一、分词

1、英文分词

按照分词粒度大小:

词级就是按单词分,但是实际应用中容易出现OOV问题out of vocabulary,包括网络热词、专有名

词、复合词比如chatgpt,模型无法识别这些词,通常会把这些替换为特殊标记如<UNK>,从而导

致语义丢失,影响模型预测。

字符级就是按字母分,覆盖率极高,词表小,很难出现OOV问题,但是单个字符信息极弱,模型

必须依赖上下文推断语义,增加建模难度和训练成本。

子词级是一种介于前两者之间的一种分词方法,把词语切分成更小的单元,例如词根、前后缀或常

见词片段等,常见的子词级分词算法包括BPE,WorldPiece和Unigram Language Model,其中

BPE最广泛,原理是先做一个字符级分词,再合并,统计字符对的频率,添加到词表里。

2、中文分词

字符级分词就是按汉字分,中文的字符级更加友好,语义友好

词级分词,切分结果贴近阅读习惯

子词级分词,先切成单字,再看字符对的频率

3、分词工具

基于词典或模型,以词为单位切分,jieba,HanLP,

基于子词建模算法如BPE,自动学习高频字组合,构建词表,hugging face tokenizer,

sentencepiece,tiktoken等

jieba分词器

pip install jieba

精确模式(fault)        .cut<generator>        .lcut<list>

<generator>要遍历输出

import jieba
text = '小明毕业于北京大学计算机系'
words_generator = jieba.lcut(text)
print(words_generator)
#result:['小明', '毕业', '于', '北京大学', '计算机系']

全模式cut_all = True,输出如下:

['小', '明', '毕业', '于', '北京', '北京大学', '大学', '计算', '计算机', '计算机系', '算机', '系']

搜索引擎模式.cut_for_search

自定义词典 load_userdict(' dict.txt '),add_word(word,freq = None, tag = None),del_word(word)

二、词向量

one-hot独热简单但是无法表示语义

CBOW(Continuous Bag-of-Words)连续词袋模型,知道前后文预测中间词

Skip-gram模型,知道中间预测前后词 ,输入层是词语的独热编码,输出层是词表每个词的概率

SGNS(Skip-gram with Negative Sampling)可以理解成:SGNS 是 Skip-gram 的加速版 + 负样

本训练策略

Word2Vec原理:利用大规模原始文本作为数据源,从中自动构造训练样本,由于两种模型的输入

输出都是词语,因此首先需要对原始文本进行分词,将连续文本转换为token序列,此外,模型无

法直接处理文本符号,训练时仍需将词语转换为 one-hot 编码,以便作为模型的输入和输出进行计

算。

1、获取Word2Vec词向量

注意了W2V这个方式获得的词向量是static的,不会根据上下文的变化来改变词向量的内容,所以

这个只是一个经典的方式

pip install gensim

1)使用公开的中文词向量,可从 https://github.com/Embedding/Chinese-Word-Vectors 下载,其提

供了基于多个数据集训练得到的词向量。

我们这里用sgns的词向量库来演示

from gensim.models import KeyedVectors
model_path = 'data/sgns.weibo.word(1)/sgns.weibo.word(1)'
model = KeyedVectors.load_word2vec_format(model_path)
print(model.key_to_index)
vector = model['地铁']
print(vector)
print(vector.shape)

这里可以直接通过输入词语来查找词向量

2、计算向量的相似度

1)比对两个词similarity

model.similarity 计算的是两个词向量的余弦相似度

print(model.similarity('地铁','公交'))
#result:0.65458214

2)找出与目标词相似/不相似的词most_similar(),positive是相似negative是不相似,topn是要输出的个数,我们传相似不相似的时候要上传列表,后面这些数字是相似度

similar_words = model.most_similar(negative = ['地铁'], topn = 5)
print(similar_words)
#result:[('穆', 0.07467251271009445), ('长青', 0.06398050487041473), ('干白', 0.061115290969610214), ('挚', 0.06012710556387901), ('功劳', 0.05630827695131302)]

案例:对比填词,

result = model.most_similar(positive = ('男人','女孩'),negative = ('女人'),topn = 1)
print(result)
#result:[('男孩', 0.5668050050735474)]
3、自行训练词向量

Word2Vec 是训练词向量的模型

KeyedVectors 是存储和操作已训练词向量的工具类

这个前面的token是新加的,目的是为了去掉空的字符

import pandas as pd
import jieba
from gensim.models import Word2Vec, KeyedVectors

df = pd.read_csv('data/online_shopping_10_cats.csv').dropna()
sentences = [ [token for token in jieba.lcut(sentence) if token.strip() != ''] for sentence in df['review']]
model = Word2Vec(
    sentences = sentences, #已分词的句子序列
    window = 5,#上下文窗口大小
    sg = 1, #1表示skip-gram,0表示cbow
    vector_size = 100, #词向量维度
    min_count = 5, #最小词频
    workers = 5, #并行训练线程数
)
model_path = 'data/review.txt'
model.wv.save_word2vec_format(model_path)
kv_model = KeyedVectors.load_word2vec_format(model_path)
print(kv_model)

#result:KeyedVectors<vector_size=100, 17018 keys>
print(kv_model.similarity('地铁','公交'))
0.852923
print(kv_model['地铁'])
[ 0.19500694 -0.03965044  0.1324852   0.10620299 -0.4235677  -0.7651219
  0.35803005 -0.03432196 -0.3441585   0.01472531 -0.02551124 -0.1966812
  0.50005436  0.11777816  0.26972964 -0.39212835  0.1059521  -0.8275402
  0.09232639 -0.17036419  0.23938079 -0.6067029   0.16755275  0.18860516
 -0.22056982  0.09086072  0.12811464 -0.08946093  0.23552182 -0.35849762
  0.5508271   0.44139338 -0.01307059 -0.40379706  0.23712929 -0.32623547
  0.11192365 -0.02663203  0.17870496 -0.6673017  -0.584636    0.43865106
 -0.37505236  0.01376642  0.37338766 -0.5476329  -0.11379293  0.48873746
  0.2114909   0.19136614  0.3628646   0.15822539 -0.12155686  0.09103846
  0.09672575 -0.18193625  0.37623656 -0.05954948 -0.37473536  0.05388224
  0.33835897  0.92868674  0.02416807 -0.23636033  0.06309167  0.09657489
  0.07441811  0.30667982 -0.2695101   0.54302526  0.1245986  -0.15983255
  0.40304184  0.24169847  0.40091097 -0.07505183 -0.12165613  0.20424005
 -0.2171529  -0.5317836   0.43617678  0.02835425  0.07248473  0.10208542
 -0.21886182 -0.35131636 -0.22335248  0.48000592  0.35729057  0.03773176
  0.34011748  0.22837088 -0.03961422  0.20944718  0.34765387  0.20317239
  0.08094657 -0.02142851  0.84808177 -0.46067324]
4、词向量应用

在现代深度学习NLP模型中,大多数任务的输入第一层都是嵌入层。本质上嵌入层是一个查找表

(lookup table),这个嵌入层是要给他训好的词向量的,但是不给也可以,就是要用自己的模型

先做一个初始化然后再训。

随机初始化:略

使用预训练词向量初始化:这个意思就是我们传入已经训练好的词向量,比如上面用w2v训练好的

词向量作为初始值,这样我们用当前模型训练的时候,就不用从0开始训练了,他就已经有一些懂

词的基础了,降低了训练难度,这种方法在低资源任务中优势明显。

embedding = nn.Embedding(vocab_size, vector_dim)

这个代码的意思是:embedding变量是一个词嵌入矩阵,这个矩阵的shape是(vocab_size,

vector_dim),这个是基于随机生成的。

import torch
import torch.nn as nn
from gensim.models import KeyedVectors
wv_model = KeyedVectors.load_word2vec_format('data/review.txt')
vector_dim = wv_model.vector_size # 词表维度
word2id = wv_model.key_to_index
vocab_size = len(word2id) # 词表大小

embedding_matrix = torch.zeros(vocab_size, vector_dim)
for word, id in word2id.items():
    embedding_matrix[id] = torch.tensor(wv_model[word])
print(embedding_matrix.shape)

完整代码如下,并解决了OOV问题

这里是加了oov词汇的<unk>,其实word2id就是一个字典,id2word就是一个列表,我们unkword

默认加到列表的首位,word2id跟着枚举一下

import torch
import torch.nn as nn
import jieba
from gensim.models import KeyedVectors

wv_model = KeyedVectors.load_word2vec_format('data/word2vec.kv')

vector_dim = wv_model.vector_size
print(vector_dim)

unk_token = '<unk>'
id2word = [unk_token] + wv_model.index_to_key
word2id = {word : id for id, word in enumerate(id2word)}

vocab_size = len(word2id)
print(vocab_size)

embedding_matrix = torch.zeros(vocab_size, vector_dim)
for word,id in word2id.items():
    if word in wv_model:
        embedding_matrix[id] = torch.tensor(wv_model[word])

print(embedding_matrix.shape)

embedding = nn.Embedding.from_pretrained(embedding_matrix, freeze=False)

text = "我喜欢乘坐宇宙飞船"
tokens = jieba.lcut(text)
print(tokens)

ids = [word2id.get(word,word2id[unk_token]) for word in tokens]
print(ids)

input = torch.tensor([ids])

output = embedding(input)
print(output)
print(output.size())

wv_model是keyedvectors的一个实例对象,并加载了预训练好的“data/word2vec.kv”词向量,后面

我们添加了unk为了解决oov问题,构建了词表,对于embedding层,如果要加载预训练的嵌入矩

阵的话需要一个tensor的matrix词嵌入矩阵,所以我们用最原始的方法先构建了一个全0空矩阵,然

后利用词表填入内容并转换成tensor以便后续训练。后面是测试环节,创建一个text用结巴分词,

然后把词的列表转换成序号的列表并转换成tensor形式,把这个input丢进词嵌入层,获得的是各个

词语对应的词向量。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐