LLM+本地知识库?简单又没那么简单

最近在研究如何将大语言模型结合本地知识库进行问答,虽然网上已经有很多教程,但大部分都是基于LangChain进行文本分割,然后调用模型向量化的API。这种方式的确很简单,但有这么几个前提:

  1. 大模型不使用ChatGPT的话,其实效果很差
  2. 尽管有多重切分方式,但还是很容易把文档中的一些语义撕裂。

由于众所周知的原因,使用ChatGPT的embedding的API很麻烦,因此自己想玩LLM以及本地知识库其实很多时候用的是自己搭建的模型,那么对于文档预处理的步骤就更加重要了,看了网上很多资料,还在学习中,本文就先把最近学习到的一些东西做个总结,也不太确定是否正确,若有错误,可以评论或私信,本人还是个刚开始学习AI的小白,还请多多指教。

构建本地知识库的前提

在构建本地知识库问答系统的时候,第一步要对本地的知识文档进行处理,因为希望更傻瓜式的去使用它,因此不太希望有人力参与对文档进行处理,比如分段、摘要等等。但如果不做任何处理,直接使用文档喂给大模型肯定是会超出tokeni限制。因此第一步会将文档的知识转成向量存储到向量数据库中,在进行知识问答的时候,先将问题在向量数据库中进行匹配,将匹配到的结果提供给LLM让其针对结果进行整理和回答。常见的也是最简单的知识库问答实现就是使用Langchain来进行文档预处理。

将一个文档转成向量数据库中的数据往往可以分成两个大的步骤,tokenizerembedding

  • Tokenizer负责将文本拆分成词元(token)。它将一个字符序列转换成一个词元序列。常见的tokenizer有基于空格、标点符号的简单tokenizer,还有更复杂的基于字典的tokenizer等。
  • Embedding则是将词元转换成词向量的表示。它为每个词元映射到一个稠密的向量空间,使得语义相关的词元之间的向量更加相近。Embedding可以通过事先训练好的词向量表获得,也可以在神经网络中进行学习。

我们最终将词汇或者语句转成向量是通过embedding得到的,但一般来说,我们不太可能将一整篇文档转换成向量。因为文档的长度往往都是比较长,会超过绝大部分模型的token限制;此外我们进行知识搜索的时候也不是要搜到整篇文档,而是文档中相关联的知识。那么tokenizer的第一步就是将文档拆分成合适的片段。

使用Langchain的方式进行文档拆分是非常简单的,具体实现细节可以参考Langchain的官方文档,这里只给出一个简单的demo:

# 导入文本  
loader = UnstructuredFileLoader(file_path)  
# 将文本转成 Document 对象  
document = loader.load()  # 初始化文本分割器  
text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=20)  # 切分文本  
split_documents = text_splitter.split_documents(document)

前两行不用解释太多,就是将文档加载进来,主要是第三步,文本分割器,Langchain提供了多种文本分割器的实现,比如字符文本分割器、Markdown文本分割器、上面demo中的递归字符文本分割器等等。使用Langchain的分割器非常方便,几乎几行代码就可以将文本切分成规定的样子,切分后的文本再送入tokenizer中处理,得到的结果再进行embedding,一个简单的本地知识库就做好了。

那么这种方式有什么问题呢?

  1. 虽然Langchain提供了多种分割器,但每一种都有着极强的局限性。对于一整篇文档而言,是存在上下文关联的,如果分割的时候正好撕开了上下文的关系,会导致向量搜索的结果很差,自然LLM的问答效果也会很差。
  2. 分割器在垂直领域的文档中的表现容易变差,因为不理解文档内容,可能会导致拆分一些专业词汇或语句。

因此文本分割的方式对于构建知识库来说是非常重要的,LLM无法直接理解自然语言,有效的分词确保语言的细微差别得以准确捕捉,尤其是在面对多样化或特定领域文本时。

虽然 tokenizer 更偏重的是文本处理,embedding 才是处理语义,但如果文本被分割的稀碎那后面的步骤全部都是基于一堆碎片做处理自然不会有什么价值,因此文本分割以及分词是非常重要的。

最近感兴趣的几个方案

目前先只考虑纯文本类型的文档,但可以是word,PDF、txt或者Markdown。如果穿插图表在其中的话暂时还没放在考虑范围内。

层级摘要

绝大部分文本文档都是有着段落层级关系,就像是Markdown或者word等,有着明显的层级关系。就想Langchain的Markdown分割器就可以很好的进行Markdown文件的切割。一般来说,一个段落的核心内容不会割裂太多,那么最简单粗暴的就是分割成段落,然后tokenizer分词,在标准的Markdown的文件上表现一般不会太差。但也要考虑一个问题,段落的长度也是不确定的,对于长段落,很多tokenizer可能无法处理。那么对于段落还要进行拆分,一般默认是限制最大长度然后割裂开,这种自然也会存在语句的断裂导致语义破坏。

针对这种情况,我们可以使用现有的一些模型对文档的长段落进行摘要,生成一个包含主要信息的较短版本。然后将这些摘要作为输入,使用能够处理长序列的模型(如Longformer或BigBird)进行向量化。这些模型的设计允许处理较长的文档,并且它们的稀疏注意力机制有助于维持段落间的上下文联系。

下面是一段伪码的示例,简单的展示了如何利用层级摘要来进行长文档处理。

from transformers import LongformerTokenizer, LongformerModel
from transformers import BartForConditionalGeneration, BartTokenizer
import torch# 假设我们有一篇很长的文档,已经分成了多个段落
document_paragraphs = ["First long paragraph ...","Second long paragraph ...","Third long paragraph ...",# Assume there are more paragraphs
]# 初始化BART分词器和模型用于摘要
summary_model_name = 'facebook/bart-large-cnn'
summary_tokenizer = BartTokenizer.from_pretrained(summary_model_name)
summary_model = BartForConditionalGeneration.from_pretrained(summary_model_name)# 初始化Longformer分词器和模型用于处理长文档
longformer_tokenizer = LongformerTokenizer.from_pretrained('allenai/longformer-base-4096')
longformer_model = LongformerModel.from_pretrained('allenai/longformer-base-4096')# 函数来摘要每个段落
def summarize_paragraphs(paragraphs):summarized_paragraphs = []for paragraph in paragraphs:inputs = summary_tokenizer(paragraph, return_tensors="pt", max_length=1024, truncation=True)summary_ids = summary_model.generate(inputs['input_ids'], num_beams=4, max_length=200, early_stopping=True)summary = summary_tokenizer.decode(summary_ids[0], skip_special_tokens=True)summarized_paragraphs.append(summary)return summarized_paragraphs# 函数来编码文档的各个段落
def encode_paragraphs_with_longformer(paragraphs):# 使用Longformer分词器将所有段落编码为一个大的输入序列inputs = longformer_tokenizer(paragraphs, return_tensors="pt", padding=True, truncation=True)# 获取模型的输出outputs = longformer_model(**inputs)return outputs.last_hidden_state# 首先对每个段落进行摘要
summarized_paragraphs = summarize_paragraphs(document_paragraphs)# 然后使用Longformer编码摘要后的段落
document_encoding = encode_paragraphs_with_longformer(summarized_paragraphs)# 'document_encoding' 现在包含了整个文档的编码表示

这种方式的优缺点也很明显: 优点

  • 高效处理长文档:通过摘要减少了处理的文本长度,使长文档更易于管理。
  • 保持关键信息:摘要过程提取关键信息,有助于减少信息丢失。
  • 语义连贯性:长文档模型如Longformer保持了文档的整体语义结构。

缺点

  • 摘要的准确性:自动摘要可能会丢失一些重要细节,特别是在复杂的文档中。
  • 资源消耗:运行高级深度学习模型需要相对较多的计算资源。
  • 依赖模型质量:这种方案的效果依赖于摘要和长文档模型的质量。

这个方法我试了一下,emmm。。这个就像缺点中说的,摘要很重要,如果摘要的内容出的不好,对整个向量化的效果影响非常巨大,很考验模型本身的能力,所以需要选择合适的模型来做摘要和向量化。

滑动窗口

这个方案应该是最简单的方式,也是目前应该算是比较好实现的一种算法。其实就是对于每个长段落,使用滑动窗口技术进行分块处理,确保窗口之间有重叠部分,这样每个窗口都会包含来自相邻窗口的上下文信息。在Langchain的分割器中,往往也会设置一个overlap的值,这个其实就是重叠部分的设置,而且滑动窗口的步长是可以自己控制,可以多尝试几次找到相对比较合适的步长和重叠的大小。

处理完所有窗口后,我们获得了每个窗口的向量表示。这些向量表示包含了各自窗口的语义信息以及通过全局注意力机制获得的相关上下文信息。

最后,我们可以将这些向量合成一个连贯的段落或文档向量表示。这可以通过多种方法实现,如简单的向量平均、最大池化(max pooling)或者更复杂的融合技术。合成的向量表示旨在捕捉整个文档的核心语义,同时保持段落之间的流畅过渡。

为什么将这些向量还要合成起来?有这么几个好处:

  1. 保持文档完整性:尽管文档被切分成多个窗口以便处理,但最终目标是理解和表示整个文档的内容和语义。合成一个向量表示有助于捕捉整个文档的综合信息,而不仅仅是片段信息。
  2. 提高检索效率:在知识问答系统中,检索过程往往需要与整个文档的向量表示进行匹配。单一的文档向量表示可以显著提高检索效率,避免了与文档中的每个小片段逐一比较的需要。
  3. 减少信息丢失:在处理长文档时,单个窗口可能无法完全捕捉文档的所有关键信息。通过合成一个全面的向量表示,可以最大程度地减少由于窗口化处理带来的信息丢失。
  4. 增强上下文理解:合成的向量可以更好地反映不同窗口之间的上下文关系,特别是对于跨越多个窗口的主题或概念。这对于理解文档的整体结构和流程至关重要。
  5. 适应系统架构:许多知识问答和信息检索系统的架构设计是基于处理单一的文档向量,而不是处理多个分散的向量。因此,将窗口向量合成单一向量有助于这些系统更有效地处理和检索信息。

常见的合成方法有

  1. 简单平均:计算所有窗口向量的平均值。这种方法假设每个窗口的重要性相同。
  2. 加权平均:在某些情况下,不同窗口的重要性可能不同。加权平均方法允许根据窗口的相关性或其他标准对其进行加权。
  3. 最大池化:在这种方法中,从每个窗口向量中选择最大值作为最终向量的相应元素。这种方法有助于捕捉文档中最显著的特征。
  4. 串联:将所有窗口的向量串联起来形成一个长向量。这种方法可以保留更多的原始信息,但会导致维度非常高。
  5. 注意力机制:更复杂的方法可能包括使用注意力机制,以动态确定各个窗口的重要性,并据此合成向量。 在选择合适的合成方法时,需要考虑文档的特点、处理的目的以及计算资源等因素。例如,对于信息密度较高的文档,使用加权平均或注意力机制可能更为合适;而对于信息较为均匀分布的文档,简单平均或最大池化可能就足够有效。
import torch
from transformers import BertTokenizer, BertModel
import numpy as np
import osdef sliding_window_split(text, window_size, step):"""滑动窗口分割"""chunks = []start = 0text = text.strip()while start < len(text):end = start + window_sizechunks.append(text[start:end])start += step# Ensure we don't miss the end part of the textif end >= len(text) and start < len(text):chunks.append(text[start:])breakreturn chunkstokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')def vectorize(chunk):"""对一个chunk进行向量化"""inputs = tokenizer(chunk, return_tensors='pt', max_length=512, truncation=True, padding='max_length')outputs = model(**inputs)chunk_vector = outputs.last_hidden_state.mean(dim=1)return chunk_vectordef vectorize_chunks(chunks):"""对一个list的chunk进行向量化"""vectors = []for chunk in chunks:chunk_vector = vectorize(chunk)vectors.append(chunk_vector)return vectorsdef aggregate_vectors(vectors):return torch.mean(torch.stack(vectors), dim=0)dir_path = 'dir_path'
texts = {}
# 遍历文件夹
files = os.listdir(dir_path)
for file in files:file_path = os.path.join(dir_path, file)with open(file_path, 'r') as f:text = f.read()texts[file] = text# 遍历每个文件,进行向量化
# 每个文件对应的片段向量化之后的数组
file_vectors = {}
file_vectors_aggr = {}
file_chunks = {}
for file, text in texts.items():print(file)# 分割文档chunks = sliding_window_split(text, 1024, 555)file_chunks[file] = chunks# 分割后的向量数组vectors = vectorize_chunks(chunks)file_vectors[file] = vectorsaggregated_vector = aggregate_vectors(vectors)file_vectors_aggr[file] = aggregated_vectorquestion = '什么是MVCC'
# 向量化问题,并移除梯度
q_vec = vectorize(question).detach()# 计算相似度
for file, vector in file_vectors_aggr.items():# 转换为NumPy数组vector_np = vector.detach().numpy().flatten()  # 将向量转换为一维数组q_vec_np = q_vec.numpy().flatten()    # 同样将问题向量转换为一维数组# 计算余弦相似度similarity = np.dot(q_vec_np, vector_np) / (np.linalg.norm(q_vec_np) * np.linalg.norm(vector_np))# print(file, similarity)if (similarity > 0.48):file_vecs = file_vectors[file]for index, vec in enumerate(file_vecs):# 转换为NumPy数组vec_np = vec.detach().numpy().flatten()  # 将向量转换为一维数组q_vec_np = q_vec.numpy().flatten()    # 同样将问题向量转换为一维数组# 计算余弦相似度similarity = np.dot(q_vec_np, vec_np) / (np.linalg.norm(q_vec_np) * np.linalg.norm(vec_np))if similarity > 0.8:print(file, similarity)print(file_chunks[file][index])

我自己试了一下这个方法,但暂时体验也不是很好,可能得原因有很多,比如窗口大小和步长设置不合理、向量聚合方式不合理、模型本身能力不合适等。我这里由于硬件的限制无法测验更多的场景,只能说这个方法虽然简单,但体验还是有很大提升空间的。

自定义稀疏注意力机制

最后再说一个听起来比较高大上的方式,但复杂是真的复杂,这个也是我跟ChatGPT聊天得到的一个建议,反正我是实现不了。通常需要深入了解Transformer模型的工作原理,特别是它的注意力机制。Transformer模型通过注意力机制处理输入序列,但是传统的全连接(full attention)模式在处理长序列时计算量非常大。因此,为了处理更长的文档,需要实现一种计算上更高效的稀疏注意力模式。

在稀疏注意力模式中,模型并不是计算序列中每个元素与其他所有元素之间的注意力,而是只计算与每个元素相关联的一小部分元素的注意力。这可以通过多种方式实现,例如滑动窗口、固定模式或自定义模式。以下是实现自定义稀疏注意力的大致步骤:

  1. 定义稀疏结构:你需要定义一种模式或者结构来确定哪些token之间应该计算注意力。例如,可以设计一个模式,使得每个token只与其前后的k个token以及特定的全局token(如句首token)计算注意力。如果基于现有模型,比如BERT去做的话,需要深入理解BERT或类似模型的内部结构,特别是其注意力层的工作原理。这包括对输入进行查询(query)、键(key)和值(value)的转换,以及如何计算和应用注意力权重。
  2. 修改注意力计算:接下来需要修改自注意力层的实现,使其根据定义的稀疏结构计算注意力。这可能涉及改变softmax函数前的注意力得分计算,或在计算这些得分之前应用某种形式的掩码或过滤机制。这样做可以让模型的注意力更加集中于重要的输入部分。 在进行这些修改时,通常保留模型的其余部分不变。这意味着,除了注意力层之外,模型的其他层(如嵌入层、前馈网络等)和它们的预训练权重将保持不变。
  3. 优化内存和计算:由于稀疏结构可能会导致不规则的内存访问模式和计算,可能需要进一步优化,例如使用特殊的数据结构或并行计算策略来提高效率
  4. 训练模型:使用自定义的稀疏注意力模式,你需要重新训练你的模型,或者至少对现有模型进行fine-tuning,以适应新的注意力结构。

优点

  • 优化的性能:能够有效处理长文档,同时减少计算资源的消耗。
  • 定制的处理:可以根据具体需求调整注意力机制,更准确地捕捉文档的关键部分。
  • 维护上下文:即使在长文档中也能保持良好的上下文连贯性。

缺点

  • 技术复杂度高:需要深入的技术知识来定制和调整模型。
  • 实施难度:修改现有模型的注意力机制可能在实现上较为复杂。
  • 调优成本:可能需要大量时间进行实验和调优来达到最佳效果。
  • 性能测试:任何对模型的修改都需要经过彻底的测试,以确保改进实际上提高了模型的性能,并没有引入意外的副作用。

对于这种方式,需要深入研究模型内部结构,感觉可能更适合研究人员去玩,对于我这种可能刚开始学习的小白而言,走微调的路子可能更适合,比如使用LoRA也可以拿来试试:假设基于BERT进行微调:

import torch
import torch.nn as nn
from transformers import BertModel, BertConfigclass LoRA_BERT(nn.Module):def __init__(self, bert_model_name, rank):super(LoRA_BERT, self).__init__()self.bert = BertModel.from_pretrained(bert_model_name)self.rank = rankself.lora_adjustments = nn.ModuleDict()# 为BERT的每个注意力层添加LoRA调整for i, layer in enumerate(self.bert.encoder.layer):self.lora_adjustments[f"layer_{i}"] = LoRAAdjustment(layer.attention.self.query, rank)def forward(self, input_ids, attention_mask):outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)sequence_output = outputs.last_hidden_statereturn sequence_outputclass LoRAAdjustment(nn.Module):def __init__(self, query_layer, rank):super(LoRAAdjustment, self).__init__()self.query_layer = query_layerself.rank = rankhidden_size = query_layer.out_features# 初始化LoRA参数self.delta_W = nn.Parameter(torch.randn(hidden_size, rank))self.delta_b = nn.Parameter(torch.randn(hidden_size))def forward(self, x):# 动态计算调整后的权重和偏置adjusted_weight = self.query_layer.weight + self.delta_W @ self.delta_W.t()adjusted_bias = self.query_layer.bias + self.delta_breturn torch.nn.functional.linear(x, adjusted_weight, adjusted_bias)bert_model_name = 'bert-base-uncased'
model = LoRA_BERT(bert_model_name, rank=4)

这个demo里面,

  • LoRA_BERT 类集成了预训练的BERT模型,并为其每个注意力层添加了LoRA调整。
  • LoRAAdjustment 类是一个自定义的模块,它为给定的层添加低秩权重和偏差调整。
  • 在这个简化的例子中,只对BERT的query层进行了调整。在实际应用中,可能还需要对key和value层也进行类似的调整。 上面代码是用GPT生产的一个简单DEMO,最佳的rank值,以及如何最有效地应用LoRA调整都是需要在实际实验过程中进行调整的。

总结

其实通过几种方法的尝试,除非对大模型本身能力进行优化,不然每一种方式都会存在很大的限制。不考虑硬件成本和技术开发成本的话, 训练或调优出一个特定的模型才是最优解,当然如果基座模型的确足够强大,直接LangChain进行文档分割就足够了,相信使用ChatGPT进行embedding过的同学们应该能感受到,这种方法可能会引入一定程度的误差,但仍可以在多数情况下提供有效的结果,尝试不同的分割器和不同的参数是能找到相对较好的方案的。如果有条件的话,比如有一定的数据量且有硬件资源,可以对开源模型进行调优,让他能更好的适配本地文库的知识,比如构建的是公司内部文档的知识库,那新增一些新的公司文档,对于调优后的模型而言,也会有较好的表现。

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3226331.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

07-04 周四 关于vLLM(LLMs_inference)源码安装过程问题与解决

07-04 周四 关于LLMs_inference源码安装过程问题与解决 时间版本修改人描述2024年7月4日09:48:09V0.1宋全恒新建文档 简介 由于最近需要向vLLM上集成功能&#xff0c;因此&#xff0c;需要能够调试自己的仓库LLMs_Inference&#xff0c;该文档记录了源码编译的完整的过程。 参…

对比:9款最佳个人项目管理软件盘点

文章介绍了9款个人项目管理软件&#xff1a;PingCode、Worktile、Flowus、Todoist、Trello、Teambition、有道云笔记、Notion、Microsoft To Do。 在管理个人项目时&#xff0c;是否常感到信息零散、进度难以把控&#xff1f;选择合适的项目管理软件&#xff0c;可以有效解决这…

【密码学】从有限状态自动机到密钥流生成器

本文是对流密码内容的拓展&#xff0c;在流密码中种子密钥通过一个伪随机数生成器产生一个与明文等长的伪随机密钥流。而本文的内容就是在回答这样两个问题&#xff1a; 伪随机密钥流是如何生成的&#xff1f;流密码、流密钥生成器和有限状态自动机之间是什么关系&#xff1f;…

Defensor 4.5:构建数据资产为中心的安全运营体系

5月31日“向星力”未来数据技术峰会上&#xff0c;星环科技重磅发布数据安全管理平台 Defensor 4.5版本。新版本引入了以数据资产为中心的数据安全运营体系&#xff0c;通过智能化大模型技术&#xff0c;帮助企业快速、精准地识别核心重要资产&#xff1b;建设全局的数据安全策…

拥抱应用创新,拒绝无谓的模型竞争

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

怎么判断自己是否适合学习PMP?

判断自己是否适合学习PMP项目管理专业人士认证&#xff0c;可以从以下几个方面进行考量&#xff1a; 1、职业发展需求&#xff1a; 如果您在项目管理领域工作&#xff0c;或计划未来从事相关工作&#xff0c;PMP认证能显著提升您的竞争力。 对于项目经理、产品经理、技术领导…

充电桩运营平台的技术方案 53页

充电桩运营平台的技术方案 53页&#xff0c;全套解决方案 内容太多&#xff0c;复制图片丢失&#xff0c;需要完整的私信我。

一次性语音芯片——智能家居的新兴技术

一次性语音芯片&#xff0c;作为现代智能家居技术&#xff0c;正以其魅力和性能&#xff0c;逐渐渗透到我们日常生活的每一个角落。这些小巧而强大的芯片&#xff0c;不仅为智能家居设备赋予了“说话”的能力&#xff0c;更在提升用户体验、增强设备交互性方面发挥了举足轻重的…

数据库db文件损坏修复方法(sqlite3:database disk image is malformed)

参考博客&#xff1a; https://www.cnblogs.com/liuyangQAQ/p/18037546 sqlite3数据库提示database disk image is malformed 解决办法-CSDN博客 【SQL】sqlite数据库损坏报错&#xff1a;database disk image is malformed&#xff08;已解决&#xff09;-CSDN博客 一、第…

Yarn标签调度--HDP测试

hadoop版本从2.7.2版本开始 新增标签调度功能。 标签调度功能&#xff1a;可以给节点设置标签 让作业任务调度到这个设置的标签节点。 列入&#xff1a; 某个任务需要用到gpu资源&#xff0c;而gpu并非在每个节点上都有&#xff0c;通过对节点设置标签&#xff0c;可以使作业…

imx6ull/linux应用编程学习(15) 移植MQTT客户端库/测试

1. 准备开发环境 确保你的Ubuntu系统已经安装了必要的工具和依赖项。打开终端并运行以下命令&#xff1a; sudo apt update sudo apt install build-essential cmake git2. 获取MQTT库 git clone https://github.com/eclipse/paho.mqtt.c.git cd paho.mqtt.c3. 编译MQTT库 mk…

苹果开发者取消自动续费

文档&#xff1a;https://support.apple.com/zh-cn/118428 如果没有找到订阅&#xff0c;那就是账号不对 取消订阅后&#xff0c;就不会自动续费了&#xff0c;如果不放心&#xff0c;可以把付款绑定的方式也取消

TQZC706开发板教程:在ZC706+ADRV9009硬件平台运行ADI Linux

本教程使用2024-06-18的ADI镜像文件&#xff0c;创建ZC706ADRV9009的linux工程进行测试。 首先需要下载ADI的镜像文件下载地址如所示&#xff1a; https://wiki.analog.com/resources/tools-software/linux-software/adi-kuiper_images/release_notes#r2_patch_1 烧写完成后若…

50斤的东西寄什么快递最便宜?邮寄物品最便宜的方法分享

作为一个电商创业者&#xff0c;我经常需要寄送大量商品。寄送50斤左右的东西时&#xff0c;选择哪个快递公司最便宜成了我们关注的重点。今天&#xff0c;我将分享一些实用的寄快递省钱技巧和打包建议&#xff0c;帮助大家在快递费用上省下一大笔。云木寄快递 首先&#xff0…

小红书矩阵源码(多账号发布+批量剪辑视频+一键分发)

在数字化时代&#xff0c;社交媒体已成为品牌推广和个人表达的重要渠道。小红书作为国内领先的生活分享社区&#xff0c;其矩阵源码的出现&#xff0c;为多账号运营提供了前所未有的便利。本文将深入探讨小红书矩阵源码如何通过多账号发布、批量剪辑视频、一键分发以及持续迭代…

windows10设置环境变量Path步骤

1、鼠标右键“我的电脑”&#xff0c;点击“属性”&#xff0c;打开控制面板窗口&#xff0c;如图&#xff1a; 2、点击“高级系统设置”&#xff0c;弹出设置窗口&#xff0c;如图&#xff1a; 3、点击底部的“环境变量”&#xff0c;弹出环境变量窗口&#xff0c;如图&#x…

[CTF]-PWN:House of Cat堆题型综合解析

原理&#xff1a; 调用顺序&#xff1a; exit->_IO_wfile_jumps->_IO_wfile_seekoff->_IO_switch_to_wget_mode _IO_wfile_seekoff源码&#xff1a; off64_t _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) {off64_t result;off64_t delta, new…

android13 cat /proc/cupinfo没有Serial问题

1.前言 我们有些客户是使用cpuinfo节点去获取系统的cpuid的,如下: cat /proc/cupinfo processor : 0 BogoMIPS : 48.00 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU impleme…

tensorflow之欠拟合与过拟合,正则化缓解

过拟合泛化性弱 欠拟合解决方法&#xff1a; 增加输入特征项 增加网络参数 减少正则化参数 过拟合的解决方法&#xff1a; 数据清洗 增大训练集 采用正则化 增大正则化参数 正则化缓解过拟合 正则化在损失函数中引入模型复杂度指标&#xff0c;利用给w增加权重&#xff0c;…

滥用云服务进行传播的恶意软件越来越多

由于云服务提供了传统方式所不具备的可扩展性、匿名性和容错性&#xff0c;攻击者越来越多地开始利用云服务来存储、分发和建立 C&C 信道&#xff0c;例如 VCRUM 存储在 AWS 上或 SYK Cryptor 通过 DriveHQ 进行分发。 过去的一个月内&#xff0c;研究人员一直在监控使用这…