当前位置: 首页 > news >正文

NLP开端:Tokenizer-文本向量化

Tokenizer

问题背景

An was a algorithm engineer   

如上所示,在自然语言处理任务中,通常输入处理的数据是原始文本。但是算法模型自能处理数值类型,因此需要找到一种方法,将原始的文本数据转换为数值类型的数据。这就是分词器所解决的问题,分词器的目标是找到文本最有意义的、最小的表示方法

分词器(Tokenizer)是 NLP 管道的核心组件之一。它们有一个目的:将文本转换为模型可以处理的数据。模型只能处理数字,因此分词器(Tokenizer)需要将我们的文本输入转换为数字数据。

Tokenizer处理流程

  1. Input text data: An was a algorithm engineer

  2. String Tokenizer: 切分以上文本数据;

  3. Output: An was a algorithm engineer

以上过程称为Tokenization

分词方法分类

  • Word-based:

  • 按单词划分(tokenize on word)

  • 按标点符号划分(tokenize on punctuation)

  • 按空格划分(tokenize on white spaces)。

  • Character-based

  • Subword tokenization

  • Byte-level BPE, 用于 GPT-2

  • WordPiece, 用于 BERT

  • SentencePiece or Unigram, 用于多个多语言模型

基于词的(Word-based)

最简单直接的分词器是基于词的(word-based)分词方法。它简单易用,只需几条规则,并且通常会产生不错的结果。例如,将以下内容进行tokenize:

I'm an algorithm engineer, and my skills are awesome.   

有多种拆分文本的方法。

仅基于单词空格的方法(Tokenize on whit spaces)

可以通过应用Python的split()函数,使用空格将文本标记为单词:

ttokenized_text = "I'm an algorithm engineer, and my skills are awesome.".split()
print("Tokenize on whit spaces:",tokenized_text)
  • output
Tokenize on whit spaces: `I'm ` `an` `algorithm` `engineer,` `and` `my` `skills` `are` `awesome.`

按标点符号划分(tokenize on punctuation)

还有一些单词分词器的变体,它们具有额外的标点符号规则。 例如:

  • Tokenize on punctuation: I ' m is an algorithm engineer , and my skills are awesome .使用这种分词器,我们最终可以得到一些非常大的“词汇表”,其中词汇表由我们在语料库中拥有的独立标记的总数定义。

  • Tokenize on word: I 'm is an algorithm engineer , and my skills are awesome .

以上的分词方法虽然有一些微小的差别,但是区别都不大,属于传统经典的分词方法。但是不同的分词方法会有不同的分词结果。

word-base tokenizer方法分析

每个单词都分配了一个 ID,从 0 开始一直到词汇表vocabularies的大小。该模型使用这些 ID 来识别每个单词。

如果用基于单词的分词器(tokenizer)完全覆盖一种语言,需要为语言中的每个单词都有一个标识符,这将生成大量的tokens。例如:

  • 英语中有超过 500,000 个单词,因此要构建从每个单词到输入 ID 的映射,需要跟踪这么多 ID。

  • 此外,诸如英文单词中的多种形态:像“dog”与“dogs”、"look"衍生出的"looks", "looking", "looked、old, older, oldest 之间的关系到 smart, smarter, smartest…,这样的词,虽然表示方式不同,但其有一定的相互关系。

  • 但是word-base tokenizer方法会将这些形态相似的词组识别为不相关。

  • 最后,对于unknown token需要自定义一个token来表示不在词汇表中的单词,被称为“未知”标记(token)。通常表示为“[UNK]”或”“。如果分词器产生了很多这样的token,表明它无法检索到一个词的合理表示,并且在这个过程中丢失信息。制作词汇表时的目标是将未知token标记的尽可能少。

因此 word-base tokenizer方法的缺点是:

  • 对于未在词表中出现的词(Out Of Vocabulary, OOV),模型将无法处理(未知符号标记为 [UNK])。

  • 词表中的低频词/稀疏词在模型训无法得到训练(因为词表大小有限,太大的话会影响效率)。

  • 很多语言难以用空格进行分词,例如英语单词的多形态,“look"衍生出的"looks”, “looking”, “looked”,其实都是一个意思,但是在词表中却被当作不同的词处理,模型也无法通过 old, older, oldest 之间的关系学到 smart, smarter, smartest 之间的关系。

  • 这一方面增加了训练冗余

  • 另一方面也造成了大词汇量问题。

减少未知标记数量的一种方法是使用更深一层的分词器(tokenizer),即基于字符的(character-based)分词器(tokenizer)。

基于字符(Character-based)

基于字符的分词器(tokenizer)将文本拆分为字符和特殊符号,而不是单词。例如:将文本I'm an algorithm engineer, and my skills are awesome.内容进行tokenize:

  • Add special sapce symbol"/":I m / a n / a l g o r i t h m / e n g i n e e r , / a n d / m y / s k i l l s / a r e / a w e s o m e .

  • Ignore some symbols: I m a n a l g o r i t h m e n g i n e e r a n d m y s k i l l s a r e a w e s o m e .

  • Ignore some symbols: I ' m a n a l g o r i t h m e n g i n e e r , a n d m y s k i l l s a r e a w e s o m e .

因此Character_based方法同时能解决能解决 OOV 问题,也避免了大词汇量问题,即:

  • 词汇量要小得多。

  • 词汇外(未知)标记(token)要少得多,因为每个单词都可以从字符构建。

这种方法缺点很明显:粒度太细,训练花费的成本太高。由于现在表示是基于字符而不是单词,因此有人会说:“从直觉上讲,它的意义不大:每个字符本身并没有多大意义,而单词就是这种情况。” 然而,这又因语言而异;例如,在中文中,每个字符比拉丁语言中的字符包含更多的信息。

另一件要考虑的事情是,模型会处理大量的tokens:虽然使用基于单词的分词器(tokenizer),单词只会是单个标记,但当转换为字符时,它很容易变成 10 个或更多的tokens。

为了两全其美,可以使用结合word-basedcharacter-based两种方法的第三种技术:子词标记化(subword tokenization)。

子词标记化(subword tokenization)

子词分词算法的原则是不应将常用词拆分为更小的子词,而应将稀有词分解为有意义的子词。目的是通过一个有限的词表来解决所有单词的分词问题,同时尽可能将结果中 token 的数目降到最低

例如

  • “annoyingly”可能被认为是一个罕见的词,可以分解为annoying ly。这两者都可能作为独立的子词出现得更频繁,同时“annoyingly”的含义由“annoying”和“ly”的复合含义保持。

  • “unfortunately” = un + for + tun + ate + ly

由此可见,subword有点类似英语中的词根词缀拼词法,其中的这些小片段又可以用来构造其他词。可见这样做,既可以降低词表的大小,同时对相近词也能更好地处理。

再比如:子词标记化算法如何标记序列Let’s do tokenization!Let's do token ization !

这些子词最终提供了很多语义含义:例如,在上面的示例中,“tokenization”被拆分为“token”和“ization”,这两个具有语义意义同时节省空间的词符(token)(只需要两个标记(token)代表一个长词)。这使我们能够对较小的词汇表进行相对较好的覆盖,并且几乎没有未知的标记

这种方法在土耳其语等粘着型语言(agglutinative languages)中特别有用,您可以通过将子词串在一起来形成(几乎)任意长的复杂词。

  • subword的基本切分原则是:

  • 高频词依旧切分成完整的整词

  • 低频词被切分成有意义的子词,例如 dogs => [dog, ##s]

  • 基于subword的切分可以实现:

  • 词表规模适中,解码效率较高

  • 不存在UNK,信息不丢失

  • 能学习到词缀之间的关系

基于subword的切分包括三种分词模型:

  1. BPE及Byte-level BPE, 用于 GPT-2

  2. WordPiece

  3. SentencePiece or Unigram, 用于多个多语言模型Unigram

字节对编码(BPE, Byte Pair Encoding)

字节对编码(BPE, Byte Pair Encoder),又称 digram coding 双字母组合编码,是一种数据压缩算法,用来在固定大小的词表中实现可变⻓度的子词。该算法简单有效,因而目前是最广泛采用的subword分词器。

BPE 首先将词分成单个字符,然后依次用另一个字符替换频率最高的一对字符 ,直到循环次数结束。

BPE 在分词中的算法过程:

  1. 算法过程准备语料库,确定期望的 subword 词表大小等参数

  2. 通常在每个单词末尾添加后缀 </w>,统计每个单词出现的频率,例如,low 的频率为 5,那么我们将其改写为 l o w </ w>:5

    注:停止符 </w> 的意义在于标明 subword 是词后缀。举例来说:st 不加 </w> 可以出现在词首,如 st ar;加了 </w> 表明该子词位于词尾,如 we st</w>,二者意义截然不同

  3. 将语料库中所有单词拆分为单个字符,用所有单个字符建立最初的词典,并统计每个字符的频率,本阶段的 subword 的粒度是字符

  4. 挑出频次最高的符号对,比如说 th 组成的 th,将新字符加入词表,然后将语料中所有该字符对融合(merge),即所有 th 都变为 th

    注:新字符依然可以参与后续的 merge,有点类似哈夫曼树,BPE 实际上就是一种贪心算法 。

  5. 重复遍历 23 操作,直到词表中单词数达到设定量 或下一个最高频数为 1,如果已经达到设定量,其余的词汇直接丢弃注:看似我们要维护两张表,一个词表,一个字符表,实际上只有一张,词表只是为了我们方便理解。

  • 训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表

  • 编码方法:将文本切分成字符,再应用训练阶段获得的合并规则

  • 经典模型:GPT, GPT-2, RoBERTa, BART, LLaMA, ChatGLM等

例如
  1. 获取语料库,这样一段话为例:“ FloydHub is the fastest way to build, train and deploy deep learning models. Build deep learning models in the cloud. Train deep learning models. ”

  2. 拆分,加后缀,统计词频:

WORDFREQUENCYWORDFREQUENCY
d e e p </w>3b u i l d </w>1
l e a r n i n g </w>3t r a i n </w>`
t h e </w>2a n d </w>1
m o d e l s </w>2d e p l o y </w>1
F l o y d h u b </w>1
B u i l d </w>
i s </w>1m o d e l s </w>1
f a s t e s t </w>1i n </w>1
w a y </w>1c l o u d </w>1
t o </w>1T r a i n </w>1
  1. 建立词表,统计字符频率,并排序:
NUMBERTOKENFREQUENCYNUMBERTOKENFREQUENCY
1</w>2415g3
2e1616m3
3d1217.3
4l1118b2
5n1019h2
6i920F1
7a821H1
8o22f1
9s23w1
10t24,1
11r25B1
12u26c1
13p27T1
14y
  1. 以第一次迭代为例,将字符频率最高的 de 替换为 de,后面依次迭代:
NUMBERTOKENFREQUENCYNUMBERTOKENFREQUENCY
1</w>2416g3
2e16-7=917m3
3d12-7=518.3
4l1119b2
5n1020h2
6i921F1
7a822H1
8o23f1
9de724w1
10s25,1
11t26B1
12r27c1
13u28T1
14p
15y
  1. 更新词汇表
WORDFREQUENCYWORDFREQUENCY
de e p </w>3b u i l d </w>1
l e a r n i n g </w>3t r a i n </w>`
t h e </w>2a n d </w>1
m o de l s </w>2de p l o y </w>1
F l o y d h u b </w>1
B u i l d </w>
i s </w>1m o de l s </w>1
f a s t e s t </w>1i n </w>1
w a y </w>1c l o u d </w>1
t o </w>1T r a i n </w>1

继续迭代直到达到预设的 subwords 词表大小或下一个最高频的字节对出现频率为 1。

如果将词表大小设置为 10,最终的结果为:

d e
r n
rn i
rni n
rnin g</w>
o de
ode l
m odel
l o
l e

这样就得到了更加合适的词表,这个词表可能会出现一些不是单词的组合,但是其本身有意义的一种形式

BPE 的优点

上面例子中的语料库很小,知识为了方便理解 BPE 的过程,但实际中语料库往往非常非常大,无法给每个词(token)都放在词表中。BPE 的优点就在于,可以很有效地平衡词典大小和编码步骤数(将语料编码所需要的 token 数量)。

随着合并的次数增加,词表大小通常先增加后减小。迭代次数太小,大部分还是字母,没什么意义;迭代次数多,又重新变回了原来那几个词。所以词表大小要取一个中间值。

BPE 的缺点
  • 对于同一个句子, 可能会有不同的 Subword 序列。

  • 例如 Hello world,如图所示,。不同的 Subword 序列会产生完全不同的 id 序列表示,这种歧义可能在解码阶段无法解决。在翻译任务中,不同的 id 序列可能翻译出不同的句子,这显然是错误的。

  • 在训练任务中,如果能对不同的 Subword 进行训练的话,将增加模型的健壮性,能够容忍更多的噪声,而 BPE 的贪心算法无法对随机分布进行学习。

针对所有自学遇到困难的同学们,我帮大家系统梳理大模型学习脉络,将这份 LLM大模型资料 分享出来:包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程等, 😝有需要的小伙伴,可以 扫描下方二维码领取🆓↓↓↓

👉[CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]()👈

BPE 的适用范围

BPE 一般适用在欧美语言拉丁语系中,因为欧美语言大多是字符形式,涉及前缀、后缀的单词比较多。

而中文的汉字一般不用 BPE 进行编码,因为中文是字无法进行拆分。对中文的处理通常只有分词和分字两种:

  • 理论上分词效果更好,更好的区别语义。

  • 分字效率高、简洁,因为常用的字不过 3000 字,词表更加简短。

BPE实现
import re, collectionsdef get_vocab(filename):vocab = collections.defaultdict(int)with open(filename, 'r', encoding='utf-8') as fhand:for line in fhand:words = line.strip().split()for word in words:vocab[' '.join(list(word)) + ' </w>'] += 1return vocabdef get_stats(vocab):pairs = collections.defaultdict(int)for word, freq in vocab.items():symbols = word.split()for i in range(len(symbols)-1):pairs[symbols[i],symbols[i+1]] += freqreturn pairsdef merge_vocab(pair, v_in):v_out = {}bigram = re.escape(' '.join(pair))p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')for word in v_in:w_out = p.sub(''.join(pair), word)v_out[w_out] = v_in[word]return v_outdef get_tokens(vocab):tokens = collections.defaultdict(int)for word, freq in vocab.items():word_tokens = word.split()for token in word_tokens:tokens[token] += freqreturn tokensif __name__=="__main__":vocab = {'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3}print('==========')print('Tokens Before BPE')tokens = get_tokens(vocab)print('Tokens: {}'.format(tokens))print('Number of tokens: {}'.format(len(tokens)))print('==========')num_merges = 5for i in range(num_merges):pairs = get_stats(vocab)if not pairs:breakbest = max(pairs, key=pairs.get)vocab = merge_vocab(best, vocab)print('Iter: {}'.format(i))print('Best pair: {}'.format(best))tokens = get_tokens(vocab)print('Tokens: {}'.format(tokens))print('Number of tokens: {}'.format(len(token)))

Byte-level BPE

BPE的一个问题是,如果遇到了unicode,基本字符集可能会很大。Byte-level BPE是以一个字节为一种“字符”,不管实际字符集用了几个字节来表示一个字符。这样的话,基础字符集的大小就锁定在了256。 例如,像GPT-2的词汇表大小为50257 = 256 + <EOS> + 50000 mergers,<EOS>是句子结尾的特殊标记。

2019年提出的Byte-level BPE (BBPE)算法是上面BPE算法的进一步升级。具体参见:Neural Machine Translation with Byte-Level Subwords。 核心思想是用byte来构建最基础的词表而不是字符。首先将文本按照UTF-8进行编码,每个字符在UTF-8的表示中占据1-4个byte。 在byte序列上再使用BPE算法,进行byte level的相邻合并。编码形式如下图所示:

通过这种方式可以更好的处理跨语言和不常见字符的特殊问题(例如,颜文字),相比传统的BPE更节省词表空间(同等词表大小效果更好),每个token也能获得更充分的训练。

但是在解码阶段,一个byte序列可能解码后不是一个合法的字符序列,这里需要采用动态规划的算法进行解码,使其能解码出尽可能多的合法字符。具体算法如下: 算法如下:对于给定的字节序列,从中恢复的最大字符数表示为。则 具有最优的子结构,可以通过动态规划求解有最优的子结构:

其中 如果, 则 对应于有效字符,否则为,。当 递归计算时,还记录每个位置 的选择,以便我们可以通过回溯来恢复解决方案。UTF-8 编码的设计确保了此恢复过程的唯一性:对于使用多个字节编码的字符 UTF-8,其尾随字节不会成为有效的 UTF-8 编码字符。那么Eq 1 中的最佳选择是唯一的,最终解决方案也是如此。

WordPiece

WordPiece分词与BPE非常类似,只是在训练阶段合并pair的策略不是pair的频率而是互信息。

这里的动机是一个pair的频率很高,但是其中pair的一部分的频率更高,这时候不一定需要进行该pair的合并。 而如果一个pair的频率很高,并且这个pair的两个部分都是只出现在这个pair中,就说明这个pair很值得合并。

  • 训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表

  • 编码方法:将文本切分成词,对每个词在词表中进行最大前向匹配

  • 经典模型:BERT及其系列DistilBERT,MobileBERT等

Unigram

Unigram分词与BPE和WordPiece不同,是基于一个大词表逐步裁剪成一个小词表。 通过Unigram语言模型计算删除不同subword造成的损失来衡量subword的重要性,保留重要性较高的子词。

  • 训练方法:从包含字符和全部子词的大词表出发,逐步裁剪出一个小词表,并且每个词都有自己的分数。

  • 编码方法:将文本切分成词,对每个词基于Viterbi算法求解出最佳解码路径。

  • 经典模型:AlBERT, T5, mBART, Big Bird, XLNet

SentencePiece

SentencePiece是Google出的一个分词工具:

  • 内置BPE,Unigram,char和word的分词方法

  • 无需预分词,以unicode方式直接编码整个句子,空格会被特殊编码为▁

  • 相比传统实现进行优化,分词速度速度更快

transformers中使用Tokenizer类

Loading and saving

加载和保存分词器(tokenizer)就像使用模型一样简单。两种方法: from_pretrained()save_pretrained() ,将加载或保存分词器(tokenizer)使用的算法(有点像model的architecture)以及它的词汇(有点像model的weights)。

加载使用与 BERT 相同的检查点训练的 BERT 分词器(tokenizer)与加载模型的方式相似,使用 BertTokenizer 类:

from transformers import BertTokenizertokenizer = BertTokenizer.from_pretrained("bert-base-cased")

如同 AutoModelAutoTokenizer 类将根据检查点名称在库中获取正确的分词器(tokenizer)类,并且可以直接与任何检查点一起使用:

from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

使用分词器(tokenizer):

tokenizer("Using a Transformer network is simple")
{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

保存分词器(tokenizer)与保存模型相同:

tokenizer.save_pretrained("directory_on_my_computer")

我们在Chapter 3中将更多地谈论token_type_ids,稍后我们将解释 attention_mask 键。首先,让我们看看 input_ids 如何生成。为此,我们需要查看分词器(tokenizer)的中间方法。

Encoding

将文本翻译成数字被称为编码(encoding).编码分两步完成:标记化然后转换为输入 ID

  • 第一步是将文本拆分为单词(或单词的一部分、标点符号等),称为token。有多个规则可以执行该过程,如BPE、WordPiece、SentencePiece or Unigram,这就是为什么我们需要使用模型名称来实例化分词器(tokenizer),以确保我们使用模型预训练时使用的相同规则。

  • 第二步是将这些token转换为数字,就可以用它们构建一个张量并输入给模型。为此,分词器(tokenizer)有一个**词汇表(vocabulary)**,这是在实例化from_pretrained()时下载的。同样,需要使用模型预训练时使用的相同vocabulary。

Tokenization

标记化过程由分词器(tokenizer)的tokenize() 方法实现:

from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)print(tokens)

此方法的输出是一个字符串列表或标记(token):

['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']

这个分词器(tokenizer)是一个subword tokenizer:它对词进行拆分,直到获得可以用其词汇表表示的tokentransformer 就是这种情况,它分为两个标记:transform##er

从tokens到输入 ID

输入 ID 的转换由分词器(tokenizer)的convert_tokens_to_ids()方法实现:

ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)

Output:

[7993, 170, 11303, 1200, 2443, 1110, 3014]   

这些输出一旦转换为适当的框架张量,就可以用作模型的输入。

Decode

解码过程比较简单,如果相邻子词间没有中止符,则将两子词直接拼接,否则两子词之间添加分隔符。 如果仍然有子字符串没被替换但所有 token 都已迭代完毕,则将剩余的子词替换为特殊 token,如 <unk>解码(Decoding):从词汇索引中,想要得到一个字符串。这可以通过 decode() 方法实现,如下:

decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
'Using a Transformer network is simple'

请注意, decode 方法不仅将索引转换回标记(token),还将属于相同单词的标记(token)组合在一起以生成可读的句子。当我们使用预测新文本的模型(根据提示生成的文本,或序列到序列问题(如翻译或摘要))时,这种行为将非常有用。

到现在为止,您应该了解分词器(tokenizer)可以处理的原子操作:标记化、转换为 ID 以及将 ID 转换回字符串。

参考

  • https://zhuanlan.zhihu.com/p/448147465

  • https://huggingface.co/learn/nlp-course/en/chapter2/4#tokenization

读者福利:如果大家对大模型感兴趣,这套大模型学习资料一定对你有用

对于0基础小白入门:

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。

包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓
在这里插入图片描述

👉AI大模型学习路线汇总👈

大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)

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

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

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

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

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

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

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

👉大模型实战案例👈

光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉大模型视频和PDF合集👈

观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈

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

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

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

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

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓
在这里插入图片描述

相关文章:

NLP开端:Tokenizer-文本向量化

Tokenizer 问题背景 An was a algorithm engineer 如上所示&#xff0c;在自然语言处理任务中&#xff0c;通常输入处理的数据是原始文本。但是算法模型自能处理数值类型&#xff0c;因此需要找到一种方法&#xff0c;将原始的文本数据转换为数值类型的数据。这就是分词器所…...

STM32 MCU学习资源

STM32 MCU学习资源 文档下载需要注册登录账号 ST公司官方文档 STM32 MCU开发者资源 STM32F446 相关PDF文档 ST中文论坛 中文译文资料 ST MCU中文官网 其他学习资源 野火STM32库开发实战指南 零基础快速上手STM32开发&#xff08;手把手保姆级教程&#xff09; 直接使…...

Python知识点:Python内存管理与优化

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; Python内存管理与优化指南 Python是一种动态类型的解释型语言&#xff0c;它提…...

SpringBoot Kafka发送消息与接收消息实例

前言 Kafka的基本工作原理 我们将消息的发布&#xff08;publish&#xff09;称作 producer(生产者)&#xff0c;将消息的订阅&#xff08;subscribe&#xff09;表述为 consumer&#xff08;消费者&#xff09;&#xff0c;将中间的存储阵列称作 broker(代理)&#xff0c;这…...

【资料分析】刷题日记2

第一套 √ 2013-2016一共有13&#xff0c;14&#xff0c;15&#xff0c;16四年&#xff0c;亦即16 - 13 1 4年 √ 是多少倍 ③vs④&#xff1a;都是只给出了年均增速&#xff0c;③求的是其中一年的&#xff0c;无法确定&#xff1b;④求的是这个时段总共的&#xff0c;可…...

Aigtek功率放大器怎么选择型号

功率放大器在各个领域中都扮演着重要的角色&#xff0c;用于增强信号的幅度&#xff0c;以满足特定的需求。在选择功率放大器型号时&#xff0c;需要综合考虑多个因素&#xff0c;如应用领域、功率要求、频率范围、输入输出特性等。下面安泰电子官网将从这些方面详细介绍功率放…...

【RabbitMQ】重试机制、TTL

重试机制 在消息从Broker到消费者的传递过程中&#xff0c;可能会遇到各种问题&#xff0c;如网络故障、服务不可用、资源不足等&#xff0c;这些问题都可能导致消息处理失败。为了解决这些问题&#xff0c;RabbitMQ提供了重试机制&#xff0c;允许消息在处理失败之后重新发送…...

Linux用户及用户组操作命令笔记

1.用户概念及作用 用户&#xff1a;指的是Linux操作系统中用于管理系统或者服务的人 Linux下一切皆文件&#xff0c;所以用户管理的是相应的文件 基本上分为两种&#xff1a; 基本管理&#xff1a;文件的创建、删除、复制、查找、打包压缩等&#xff1b;文件的权限增加、减…...

threejs加载高度图渲染点云,不支持tiff

问题点 使用的point来渲染高度图点云&#xff0c;大数据图片无效渲染点多&#xff08;可以通过八叉树过滤掉无效点增加效率&#xff0c;这个太复杂&#xff09;&#xff0c;但是胜在简单能用 效果图 code 代码可运行&#xff0c;无需npm <!DOCTYPE html> <html la…...

MySQL面试题——第二篇

1. MySQL的优化手段有哪些&#xff1f; MySQL的常见的优化手段有以下五种 1. 查询优化 避免select * ,只查询需要的字段。小表驱动大表&#xff0c;即小的数据集驱动大的数据集&#xff0c;比如当B表的数据集小于A表时&#xff0c;用in优化exist。两表执行顺序是先查B表&#x…...

Unity Transform 组件

在 Unity 中&#xff0c;Transform 是一个非常重要的组件&#xff0c;它定义了物体的位置、旋转和缩放&#xff0c;几乎每个 GameObject 都包含一个 Transform 组件。Transform 组件的主要属性如下&#xff1a; 1. position 表示物体在世界空间中的位置。可以通过 transf…...

LeeCode 3. 无重复字符的最长子串

经典方法滑动窗口:(两个指针) 针对这个题我们首先假定两个指针 left 和 right 分别指在数组最左端. 然后两个变量记录长度length和maxlength. 并且因为不能有重复的字符,我们使用HashSet结构来当收集结果的表. 随着右指针不断往右移,左指针和右指针之间的就为截取的字符,而这…...

使用canal.deployer-1.1.7和canal.adapter-1.1.7实现mysql数据同步

1、下载地址 --查看是否开启bin_log日志&#xff0c;value on表示开启 SHOW VARIABLES LIKE log_bin; -- 查看bin_log日志文件 SHOW BINARY LOGS; --查看bin_log写入状态 SHOW MASTER STATUS; --查看bin_log存储格式 row SHOW VARIABLES LIKE binlog_format; --查看数据库服…...

VMware Workstation Pro 17下载及安装教程

下载 好消息&#xff01;从VMware Workstation Pro 17开始&#xff0c;个人可以免费使用了&#xff0c;再也不需要找破解激活码啥的了。 但是坏处却不小&#xff1a;其下载变得异常复杂。首先需要注册账号&#xff0c;外网非常慢很可能注册不上&#xff1b;其次根本找不到下载…...

集采良药:从“天价神药”到低价良药,伊马替尼的真实世界研究!

在医疗科技日新月异的今天&#xff0c;有一种药物以其卓越的疗效和深远的影响力&#xff0c;成为了众多患者心中的“精准武器”——伊马替尼。这款药物不仅在慢性髓细胞白血病&#xff08;CML&#xff09;的治疗上屡创佳绩&#xff0c;更是胃肠道间质瘤&#xff08;GIST&#x…...

00898 互联网软件应用与开发自考复习题

资料来自互联网软件应用与开发大纲 南京航空航天大学 高纲4295和JSP 应用与开发技术(第 3 版) 马建红、李学相 清华大学出版社2019年 第一章 一、选择题 通过Internet发送请求消息和响应消息使用&#xff08;&#xff09;网络协议。 FTP B. TCP/IP C. HTTP D. DNS Web应…...

linux 进程间通信之pthread(条件变量共享和互斥锁共享)

0,互斥锁共享 初始化和销毁mutex互斥锁 int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); 进程共享属性有两种值: 1、PTHREAD_PROCESS_PRIVATE,这个是默认值(1),同一个进程中的多个线程访问同一个…...

数据结构-2.7.单链表的查找与长度计算

注&#xff1a;本文只探讨"带头结点"的情况(查找思路类似循环找到第i-1 个结点的代码) 一.按位查找&#xff1a; 1.代码演示&#xff1a; 版本一&#xff1a; #include<stdio.h> #include<stdlib.h> ​ ​ //定义单链表结点类型 typedef struct LNo…...

iotop 命令:磁盘IO监控和诊断

一、命令简介 ​iotop​命令用于监视磁盘I/O&#xff0c;实时显示每个进程或线程的读写速率等信息。非常适合用于诊断系统中的I/O瓶颈。 ‍ ​​ ‍ 安装 iotop 在大多数Linux发行版中&#xff0c;iotop​可能不是预装的。可以使用包管理器来安装它。 例如&#xff0c;在…...

解锁编程新境界:GitHub Copilot 让效率翻倍

Number.1&#xff1a;工具介绍 功能特点&#xff1a; 智能代码生成与补全&#xff1a;通过学习大量代码库和开发者的编码风格&#xff0c;能根据上下文自动推断可能的代码补全选项&#xff0c;甚至可以自动完成函数定义、循环结构等复杂代码片段。例如&#xff0c;当编写一个算…...

爱普生相机SD卡格式化后数据恢复指南

我借了朋友的‌爱普生相机&#xff0c;想查看一下内存&#xff0c;哎呀&#xff0c;一不小心按错了&#xff0c;竟然执行了格式化操作&#xff0c;这可真是太让人郁闷了&#xff0c;这还有机会挽救数据吗&#xff1f;心塞&#xff0c;求帮助&#xff01; 随着数码摄影的普及&am…...

【数据结构】排序算法---基数排序

文章目录 1. 定义2. 算法步骤2.1 MSD基数排序2.2 LSD基数排序 3. LSD 基数排序动图演示4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 结语 ⚠本节要介绍的不是计数排序 1. 定义 基数排序&#xff08;英语&#xff1a;Radix sort&#xff09;是一种非比较型的排序算法&…...

二叉树(下)

目录 判断树是否相同 判断树是不是另一棵树的子树 二叉树翻转 判断平衡二叉树 二叉树层序遍历 这篇主要提供一些关于二叉树例题的讲解&#xff0c;如果对二叉树及其基本操作有疑问的可以转至&#xff1a; 二叉树&#xff08;上&#xff09;-CSDN博客二叉树&#xff08;中&…...

计算机网络33——文件系统

1、chmod 2、chown 需要有root权限 3、link 链接 4、unlink 创建临时文件&#xff0c;用于非正常退出 5、vi vi可以打开文件夹 ../是向外一个文件夹 6、ls ls 可以加很多路径&#xff0c;路径可以是文件夹&#xff0c;也可以是文件 ---------------------------------…...

算法:76.最小覆盖子串

题目 链接&#xff1a;leetcode链接 思路分析&#xff08;滑动窗口&#xff09; 还是老样子&#xff0c;连续问题&#xff0c;滑动窗口哈希表 令t用的hash表为hash1&#xff0c;s用的hash表为hash2 利用hash表统计窗口内的个字符出现的个数&#xff0c;与hash1进行比较 选…...

DNS服务

一.DNS介绍 DNS应用层协议 Domain Name System 域名系统 作用&#xff1a;实现域名解析&#xff0c;解析主机名所对应的IP地址&#xff0c; 在网络环境中设备与设备之间要想相互通信只能依赖IP地址&#xff0c;DNS服务器的作用是实现域名解析。 如上图所示&#xff0c;DNS存…...

STM32 HAL freertos零基础(九)任务通知

1、任务通知 任务通知用于任务之间同步和通信。任务通知允许一个任务向另一个任务发送一个32位的值,并可以选择是否唤醒正在等待通知的任务。这使得任务之间的同步更加简单和灵活。 任务通知功能: 发送通知:一个任务可以向另一个任务发送一个32位的值。 接收通知:接收任…...

Qt+FFmpeg开发视频播放器笔记(三):音视频流解析封装

音频解析 音频解码是指将压缩的音频数据转换为可以再生的PCM(脉冲编码调制)数据的过程。 FFmpeg音频解码的基本步骤如下: 初始化FFmpeg解码器(4.0版本后可省略): 调用av_register_all()初始化编解码器。 调用avcodec_register_all()注册所有编解码器。 打开输入的音频流:…...

从黎巴嫩电子通信设备爆炸看如何防范网络电子袭击

引言&#xff1a; 在当今数字化时代&#xff0c;电子通信设备已成为我们日常生活中不可或缺的一部分。然而&#xff0c;近期黎巴嫩发生的电子设备爆炸事件提醒我们&#xff0c;这些设备也可能成为危险的武器。本文将深入探讨电子袭击的原理、防范措施&#xff0c;以及网络智能…...

【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL16

使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器 描述 ②请使用2片该优先编码器Ⅰ及必要的逻辑电路实现16线-4线优先编码器。优先编码器Ⅰ的真值表和代码已给出。 可将优先编码器Ⅰ的代码添加到本题答案中&#xff0c;并例化。 优先编码器Ⅰ的代码如下&#xff1a; module…...