NLP入门之 通过 四大名著 学Embedding

为什么会有embedding出现?

这里我以自己搞图像分类的理解,来代入我们的nlp的Embedding。

Word2Vec

embedding的进入很难避开Word2Vec。

Word2Vec是从大量文本语料中以无监督的方式学习语义知识的一种模型,它被大量地用在自然语言处理(NLP)中。那么它是如何帮助我们做自然语言处理呢?Word2Vec其实就是通过学习文本来用词向量的方式表征词的语义信息,即通过一个嵌入空间使得语义上相似的单词在该空间内距离很近。

Embedding其实就是一个映射,将单词从原先所属的空间映射到新的多维空间中,也就是把原先词所在空间嵌入到一个新的空间中去。

我们从直观角度上来理解一下,cat这个单词和kitten属于语义上很相近的词,而dog和kitten则不是那么相近,iphone这个单词和kitten的语义就差的更远了。通过对词汇表中单词进行这种数值表示方式的学习(也就是将单词转换为词向量),能够让我们基于这样的数值进行向量化的操作从而得到一些有趣的结论。比如说,如果我们对词向量kitten、cat以及dog执行这样的操作:kitten - cat + dog,那么最终得到的嵌入向量(embedded vector)将与puppy这个词向量十分相近。

这里不再展开讲Word2Vec的各种实现,我们侧重于深度学习常用的embedding去讲解。

其实二者的目标是一样的,都是我们为了学到词的稠密的嵌入表示。只不过学习的方式不一样。

Word2vec是无监督的学习方式,利用上下文环境来学习词的嵌入表示,因此可以学到相关词,但是只能捕捉到局部分布信息。

而在Embedding层中,权重的更新是基于标签的信息进行学习,为了达到较高的监督学习的效果,会将Embedding作为网络的一层,根据target进行学习和调整。比如LSTM中对词向量的微调。

简单来说,Word2vec一般单独提前训练好,而Embedding一般作为模型中的层随着模型一同训练。

One-hot 编码

比如:

我喜欢飞桨,我也喜欢你

是重复的,所以只需要一次记录

   我  喜 欢 飞  桨  , 也 你
我  1  0  0  0  0  0  0  0
喜  0  1  0  0  0  0  0  0
欢  0  0  1  0  0  0  0  0
飞  0  0  0  1  0  0  0  0
桨  0  0  0  0  1  0  0  0
,  0  0  0  0  0  1  0  0
也  0  0  0  0  0  0  1  0
你  0  0  0  0  0  0  0  1

则原句子的特征就是:

 1  0  0  0  0  0  0  0 0  1  0  0  0  0  0  0 0  0  1  0  0  0  0  0 0  0  0  1  0  0  0  0 0  0  0  0  1  0  0  0 0  0  0  0  0  1  0  0 0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  1

这个一个好处是特征计算简单,直接将稀疏矩阵对应位置相乘相加即可。

另外他的劣势是由于是稀疏矩阵,大部分信息都是0,浪费存储空间和计算空间,到这就推导出embeddding层的作用了

将其转换为如下的查表的形式,就是embedding的作用了。

# 来自官方的embedding  Demoimport paddle
import numpy as npx = np.array([[1, 0, 0],[0, 1, 0],[0, 0, 1]])x = paddle.to_tensor(x, stop_gradient=False)embedding = paddle.nn.Embedding(10, 4, sparse=True)w0=np.full(shape=(10, 4), fill_value=0).astype(np.float32)
embedding.weight.set_value(w0)adam = paddle.optimizer.Adam(parameters=[embedding.weight], learning_rate=0.01)
adam.clear_grad()out=embedding(x)print(out)out.backward()
adam.step()

可能这里还是看不懂,那我们以实际的例子为介绍进行展开。

我们随便找一个文章进行处理。

这里我去百度找到了四大名著的中文TXT,就以这个为例进行展示。
(侵删,请勿商用)

玩转四大名著-实例

1 读文本

# 文件路径
def readTxt(path_to_file):test_sentence = open(path_to_file, 'rb').read().decode(encoding='UTF-8')# 文本长度是指文本中的字符个数print ('{} : Length of text: {} characters'.format(path_to_file.split('.')[0] , len(test_sentence)))return test_sentence
test_sentence = []hongloumeng =  readTxt('红楼梦.txt')
sanguoyanyi =  readTxt('三国演义.txt')
xiyouji =  readTxt('西游记.txt')
shuihuzhuan =  readTxt('水浒传.txt')test_sentence = hongloumeng + sanguoyanyi + xiyouji + shuihuzhuanprint(len(test_sentence))
红楼梦 : Length of text: 932224 characters
三国演义 : Length of text: 614770 characters
西游记 : Length of text: 739496 characters
水浒传 : Length of text: 931284 characters
3217774

2 数据预处理

因为标点符号本身无实际意义,用string库中的punctuation,完成英文符号的替换。

from string import punctuation# str库的punctuation只是英文字符,我们加上中文的字符和字母、空格 因为我们是中文文集
punctuation = punctuation + ' qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM,。、  ;‘’【】』!@#э¥%……&*()'
print(punctuation)# 特殊符号全部换成空格 后续分句需要使用
process_dicts={i:'' for i in punctuation}
print(process_dicts)punc_table = str.maketrans(process_dicts)
test_sentence = test_sentence.translate(punc_table)# 去掉无关的文本以及空格后
print ('Length of text: {} characters'.format(len(test_sentence)))
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM,。、  ;‘’【】』!@#э¥%……&*()
{'!': '', '"': '', '#': '', '$': '', '%': '', '&': '', "'": '', '(': '', ')': '', '*': '', '+': '', ',': '', '-': '', '.': '', '/': '', ':': '', ';': '', '<': '', '=': '', '>': '', '?': '', '@': '', '[': '', '\\': '', ']': '', '^': '', '_': '', '`': '', '{': '', '|': '', '}': '', '~': '', ' ': '', 'q': '', 'w': '', 'e': '', 'r': '', 't': '', 'y': '', 'u': '', 'i': '', 'o': '', 'p': '', 'a': '', 's': '', 'd': '', 'f': '', 'g': '', 'h': '', 'j': '', 'k': '', 'l': '', 'z': '', 'x': '', 'c': '', 'v': '', 'b': '', 'n': '', 'm': '', 'Q': '', 'W': '', 'E': '', 'R': '', 'T': '', 'Y': '', 'U': '', 'I': '', 'O': '', 'P': '', 'A': '', 'S': '', 'D': '', 'F': '', 'G': '', 'H': '', 'J': '', 'K': '', 'L': '', 'Z': '', 'X': '', 'C': '', 'V': '', 'B': '', 'N': '', 'M': '', ',': '', '。': '', '、': '', ';': '', '‘': '', '’': '', '【': '', '】': '', '』': '', '!': '', 'э': '', '¥': '', '…': '', '(': '', ')': ''}
Length of text: 2733255 characters

由于词表的的长尾,会降低模型训练的速度与精度。

因此取词频前3000的单词作为词表,如果不在词表中的单词都用 ‘’ 替换。

下图来自百度:

与此同时,我们统计一下词频

test_sentence_list = test_sentence.lower().split()test_sentence_list[0:5]
['红楼梦','第一卷01030章第一回','甄士隐梦幻识通灵贾雨村风尘怀闺秀','此开卷第一回也作者自云因曾历过一番梦幻之后故将真事隐去而借通灵之说撰此一书也故曰甄士隐云云但书中所记何事何人自又云今风尘碌碌一事无成忽念及当日所有之女子一一细考较去觉其行止见识皆出于我之上何我堂堂须眉诚不若彼裙钗哉实愧则有余悔又无益之大无可如何之日也当此则自欲将已往所赖天恩祖德锦衣纨之时饫甘餍肥之日背父兄教育之恩负师友规谈之德以至今日一技无成半生潦倒之罪编述一集以告天下人我之罪固不免然闺阁中本自历历有人万不可因我之不肖自护己短一并使其泯灭也虽今日之茅椽蓬牖瓦灶绳床其晨夕风露阶柳庭花亦未有妨我之襟怀笔墨者虽我未学下笔无文又何妨用假语村言敷演出一段故事来亦可使闺阁昭传复可悦世之目破人愁闷不亦宜乎故曰贾雨村云云','此回中凡用梦用幻等字是提醒阅者眼目亦是此书立意本旨']
word_dict_count = {}
word_dict = []
for word in test_sentence_list:for i in word: word_dict_count[i] = word_dict_count.get(i, 0) + 1word_dict.append(i)word_list = []
# 按照值得大小排序
soted_word_list = sorted(word_dict_count.items(), key=lambda x: x[1], reverse=True)
for key in soted_word_list:word_list.append(key[0])word_list = word_list[:3000]
print(len(soted_word_list))
print(soted_word_list[0:10])
print(len(word_list))
print(word_list[0:10])print(word_dict[0:10])
5916
[('了', 42354), ('不', 39643), ('一', 34742), ('道', 33456), (':', 33285), ('来', 30995), ('“', 30758), ('”', 30619), ('人', 28750), ('的', 26417)]
3000
['了', '不', '一', '道', ':', '来', '“', '”', '人', '的']
['红', '楼', '梦', '第', '一', '卷', '0', '1', '0', '3']

3 模型训练参数设置

# 设置参数
hidden_size = 2048               # Linear层 参数
embedding_dim = 512              # embedding 维度
batch_size = 512                 # batch size 大小
context_size = 2                 # 上下文长度
vocab_size = len(word_list) + 1  # 词表大小
epochs = 10                       # 迭代轮数

4 数据加载

数据格式

将文本拆成了元组的形式,格式为((‘第一个词’, ‘第二个词’), ‘第三个词’)

其中,第三个词就是目标。

trigram = [[[word_dict[i], word_dict[i + 1]], word_dict[i + 2]]for i in range(len(word_dict) - 2)]# 对两千个字进行编号
word_to_idx = {word: i+1 for i, word in enumerate(word_list)}
word_to_idx['<pad>'] = 0
idx_to_word = {word_to_idx[word]: word for word in word_to_idx}# 看一下数据集
print(trigram[:5])
[[['红', '楼'], '梦'], [['楼', '梦'], '第'], [['梦', '第'], '一'], [['第', '一'], '卷'], [['一', '卷'], '0']]
print(word_to_idx)
{'了': 1, '不': 2, '一': 3, '道': 4, ':': 5, '来': 6, '“': 7, '”': 8, '人': 9, '的': 10, '是': 11, '我': 12, '个': 13, '那': 14, '有': 15, '他': 16, '去': 17, '说': 18, '你': 19, '大': 20, '这': 21, '上': 22, '见': 23, '之': 24, '得': 25, '里': 26, '在': 27, '下': 28, '也': 29, '子': 30, '只': 31, '着': 32, '将': 33, '出': 34, '又': 35, '便': 36, '?': 37, '军': 38, '马': 39, '儿': 40, '曰': 41, '日': 42, '头': 43, '中': 44, '此': 45, '行': 46, '三': 47, '到': 48, '时': 49, '好': 50, '如': 51, '回': 52, '两': 53, '家': 54, '二': 55, '都': 56, '知': 57, '自': 58, '小': 59, '兵': 60, '天': 61, '老': 62, '宝': 63, '看': 64, '与': 65, '们': 66, '前': 67, '玉': 68, '太': 69, '王': 70, '何': 71, '今': 72, '者': 73, '听': 74, '起': 75, '要': 76, '却': 77, '心': 78, '山': 79, '就': 80, '后': 81, '事': 82, '等': 83, '为': 84, '可': 85, '笑': 86, '无': 87, '正': 88, '么': 89, '门': 90, '面': 91, '把': 92, '十': 93, '贾': 94, '叫': 95, '过': 96, '明': 97, '众': 98, '打': 99, '江': 100, '问': 101, '身': 102, '宋': 103, '公': 104, '走': 105, '手': 106, '当': 107, '先': 108, '相': 109, '还': 110, '进': 111, '以': 112, '城': 113, '生': 114, '师': 115, '地': 116, '处': 117, '和': 118, '于': 119, '些': 120, '言': 121, '话': 122, '四': 123, '若': 124, '入': 125, '张': 126, '而': 127, '方': 128, '已': 129, '路': 130,
······ 'X': 3000,  '<pad>': 0

5 dataset类构建

import numpy as np
import paddle
from paddle.io import Dataset,DataLoaderclass TrainDataset(Dataset):def __init__(self, tuple_data):self.tuple_data = tuple_datadef __getitem__(self, idx):data = self.tuple_data[idx][0]label = self.tuple_data[idx][1]data = np.array(list(map(lambda word: word_to_idx.get(word, 0), data)),dtype=np.int64)label = np.array(word_to_idx.get(label, 0), dtype=np.int64)return data, labeldef __len__(self):return len(self.tuple_data)train_dataset = TrainDataset(trigram)# 加载数据
train_loader = DataLoader(train_dataset, return_list=True, shuffle=True, batch_size=batch_size, drop_last=True)
for i, data in enumerate(train_dataset):print("data -------------\n",data[0])print("label ------------\n",data[1])break
data -------------[335 566]
label ------------889

6 模型组网

为了构建Trigram模型,用一层 Embedding 与两层 Linear 完成构建。Embedding 层对输入的前两个字embedding,然后输入到后面的两个Linear层中,完成特征提取。

import paddle.nn.functional as Fclass NGramModel(paddle.nn.Layer):def __init__(self, vocab_size=vocab_size, embedding_dim=embedding_dim, context_size=context_size):super(NGramModel, self).__init__()self.embedding = paddle.nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)self.linear1 = paddle.nn.Linear(context_size * embedding_dim, hidden_size)self.linear2 = paddle.nn.Linear(hidden_size, vocab_size)def forward(self, x):x = self.embedding(x)x = paddle.reshape(x, [-1, context_size * embedding_dim])x = self.linear1(x)x = F.relu(x)x = self.linear2(x)x = F.relu(x)return x
epochs = 20n_gram_model = paddle.Model(NGramModel(vocab_size, embedding_dim, context_size)) # 用 Model封装 NGramModel# 模型配置
n_gram_model.prepare(optimizer=paddle.optimizer.Adam(learning_rate=0.001, parameters=n_gram_model.parameters()),loss=paddle.nn.CrossEntropyLoss())# 模型训练
n_gram_model.fit(train_loader, epochs=epochs,batch_size=batch_size,verbose=1)
The loss value printed in the log is the current step, and the metric is the average value of previous steps.
Epoch 1/20
step 5245/5245 [==============================] - loss: 6.7501 - 9ms/step
Epoch 2/20
step 5245/5245 [==============================] - loss: 6.6608 - 9ms/step
Epoch 3/20
step 5245/5245 [==============================] - loss: 6.5338 - 9ms/step
Epoch 4/20
step 5245/5245 [==============================] - loss: 6.3674 - 9ms/step
Epoch 5/20
step 5245/5245 [==============================] - loss: 6.4726 - 9ms/step
Epoch 6/20
step 5245/5245 [==============================] - loss: 6.5758 - 9ms/step
Epoch 7/20
step 5245/5245 [==============================] - loss: 6.4533 - 9ms/step
Epoch 8/20
step 5245/5245 [==============================] - loss: 6.5346 - 9ms/step
Epoch 9/20
step 5245/5245 [==============================] - loss: 6.2345 - 9ms/step
Epoch 10/20
step 5245/5245 [==============================] - loss: 6.3339 - 9ms/step
Epoch 11/20
step 5245/5245 [==============================] - loss: 6.4343 - 9ms/step
Epoch 12/20
step 5245/5245 [==============================] - loss: 6.6187 - 9ms/step
Epoch 13/20
step 5245/5245 [==============================] - loss: 6.3213 - 9ms/step
Epoch 14/20
step 5245/5245 [==============================] - loss: 6.4034 - 8ms/step
Epoch 15/20
step 5245/5245 [==============================] - loss: 6.2653 - 8ms/step
Epoch 16/20
step 5245/5245 [==============================] - loss: 6.3361 - 8ms/step
Epoch 17/20
step 5245/5245 [==============================] - loss: 6.3716 - 8ms/step
Epoch 18/20
step 5245/5245 [==============================] - loss: 6.4298 - 8ms/step
Epoch 19/20
step 5245/5245 [==============================] - loss: 6.4861 - 9ms/step
Epoch 20/20
step 5245/5245 [==============================] - loss: 6.3069 - 9ms/step
import randomdef test(model):model.eval()# 从最后1000组数据中随机选取1个idx = random.randint(len(trigram)-1000, len(trigram)-1)print('the input words is: ' + trigram[idx][0][0] + ', ' + trigram[idx][0][1])x_data = list(map(lambda word: word_to_idx.get(word, 0), trigram[idx][0]))x_data = paddle.to_tensor(np.array(x_data))predicts = model(x_data)predicts = predicts.numpy().tolist()[0]predicts = predicts.index(max(predicts))print('the predict words is: ' + idx_to_word[predicts])y_data = trigram[idx][1]print('the true words is: ' + y_data)cts.index(max(predicts))print('the predict words is: ' + idx_to_word[predicts])y_data = trigram[idx][1]print('the true words is: ' + y_data)test(model)
the input words is: 州, 蓼
the predict words is:  子
the true words is:  子

总结

这样就完成了,一整套的embedding的学习以及入门级的使用。当然,因为是自己收集的文本不够大,效果不理想也是在情理之中的,一般情况下都会去拿别人已经训练好的预训练词向量模型去跑,或者你的数据集是足够的充足也是可以的。

个人总结

全网同名:

iterhui

我在AI Studio上获得至尊等级,点亮10个徽章,来互关呀~

https://aistudio.baidu.com/aistudio/personalcenter/thirdview/643467

此文仅为搬运,原作链接:https://aistudio.baidu.com/aistudio/projectdetail/4338296

[NLP入门篇] 我用四大名著学Embedding相关推荐

  1. Hololens开发入门篇-郑洪智-专题视频课程

    Hololens开发入门篇-572人已学习 课程介绍         本课程使用Hololens模拟器,基于Unity2017.2及Visual Studio 2017开发 课程收益     学会Ho ...

  2. 单片机独立式按键c语言程序,(原创)51单片机C语言程序设计--速学教程实例(入门篇)之独立按键(查询)...

    (原创)51单片机C语言程序设计--速学教程实例(入门篇)之独立按键(查询) /************************************************************ ...

  3. 矩阵键盘逐行扫描C语言,(原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf...

    (原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf /***************************************************** ...

  4. 跟着王进老师学开发之Python篇第一季:基础入门篇-王进-专题视频课程

    跟着王进老师学开发之Python篇第一季:基础入门篇-2859人已学习 课程介绍         本季课程首先对Python简要介绍,然后演示如何搭建Python的开发环境,以及如何在IDE中调试Py ...

  5. 视频教程-跟着王进老师学开发之Python篇第一季:基础入门篇-Python

    跟着王进老师学开发之Python篇第一季:基础入门篇 教学风格独特,以学员视角出发设计课程,难易适度,重点突出,架构清晰,将实战经验融合到教学中.讲授技术同时传递方法.得到广大学员的高度认可. 王进 ...

  6. 女友问粉丝过万如何庆祝,我发万字长文《保姆级大数据入门篇》感恩粉丝们支持,学姐|学妹|学弟|小白看了就懂

    2021大数据领域优质创作博客,带你从入门到精通,该博客每天更新,逐渐完善大数据各个知识体系的文章,帮助大家更高效学习. 有对大数据感兴趣的可以关注微信公众号:三帮大数据 目录 粉丝破万了 新星计划申 ...

  7. 零基础学C++——黑马程序员课程笔记(C++基础语法入门篇)

    封面来自互联网侵删 视频地址:点击访问 (我这里开发工具选用VSstudio) 此笔记有三个系列: C++基础语法入门篇 C++核心编程篇 点击查看 C++提高编程篇 文章目录 C++初识 变量 常量 ...

  8. 女友问粉丝过万如何庆祝,我发长文《保姆级大数据入门篇》感恩粉丝们支持,学姐|学弟看了就懂

    文章目录 粉丝破万了 新星计划申请时粉丝数 新星内卷抢热榜之旅 运营整顿新星执行新规 重整旗鼓输出内容为王 女友问粉丝过万如何庆祝 保姆级大数据入门篇 一.学习重点划定 二.Java和大数据关系 三. ...

  9. 【NLP】NLP重铸篇之Fasttext

    文本分类 论文标题:Bag of Tricks for Efficient Text Classification 论文链接:https://arxiv.org/pdf/1607.01759.pdf ...

最新文章

  1. 【阿里妈妈数据科学系列】第一篇:认识在线实验
  2. setInterval只执行一次的原因
  3. 【PL/SQL】学习笔记 (1)一个简单的PL/SQL程序
  4. 滚动时间选择器recyclerview_Android自定义可循环的滚动选择器CycleWheelView
  5. 如何使用XGBoost开发随机森林集成
  6. L2-004. 这是二叉搜索树吗?
  7. linux下分析prn文件,linux专题一之文件描述符、重定向、管道符、tee命令
  8. 显示创建Mat对象的七种方式
  9. 企业安全建设-蜜标(honeytokens)
  10. mysql 口令_怎么样为用户设定口令(MYSQL)_MySQL
  11. 代写品牌故事-品牌故事的结构
  12. wordcloud python 如何不显示中文_Python词云库wordcloud中文显示问题详解
  13. 发票自动处理识别和分类
  14. POSTGRESQL 设置hugepage 可以让系统使用内存更有效率,防止OOM
  15. IPv6路由信息的序号
  16. Button控件更改背景和去掉边框
  17. 移植MT7620A+MT7610E驱动到Openwrt trunk(Linux Kernel 3.14.18)(续:MT7620A)
  18. docker部署consol 集群
  19. 服务器名称显示 n a,EXCEL技巧 怎样消除vlookup找不到目标时出现的#N/A
  20. Cocos Creator之打包设置横竖屏

热门文章

  1. 3.2 使用STC89C52控制MC20发送短信
  2. 【新番尝鲜】超越宇宙的少女——不明生物参见
  3. MyEclipse8.6 MyEclipse注册 破解
  4. 如何判断领导是在培养你,还是压榨你?
  5. Java豆瓣电影TOP250爬虫
  6. c语言已知次数的循环,C语言 循环结构总结
  7. vue组件+vue插件的创建和使用
  8. webx与springmvc框架对比?
  9. 罗小波 mysql_千金良方——MySQL性能优化金字塔法则
  10. 【C语言 strlen函数的实现】