当前位置:   article > 正文

【NLP】预训练模型中获取词嵌入 or Embedding层?_预训练词嵌入模型

预训练词嵌入模型

0.前言

        该博客写于投递完杭州一个中厂的NLP算法实习岗位后,面试的过程非常难受,被技术一个接一个的问题,问的很懵逼,于是痛并思痛,决定再沉淀几天再好好找工作。投递之前,没有做充足的准备,《深入浅出Embedding》是一本好书,拿到手里后,却没有怎么好好看过,写完这篇博客,我又很幸运的接到了一个公司的面试,希望这次可以准备好了再上战场。

1.项目简介

        该项目基于数据集IMDB进行情感分析,在做预测之前先对数据进行预处理,进行词嵌入操作,在项目中采用两种方法:1.利用预训练模型进行迁移学习;2.直接使用embedding层。第一种方法使用2014年英文维基百科的预计算词嵌入数据集:golve.6B.100d.txt,该文件包含了400000个单词的100维嵌入向量

        IMDB数据集:啊,这个太大了,我上传不了,有需要的请私我。

        词嵌入数据集:链接:https://pan.baidu.com/s/12v5rF_cVTm2txngVT02--w?pwd=35gr 提取码:35gr

2.读取IMDB数据集

        将下载好的IMDB数据集保存在本地,并转换成list从文件中读出来。

  1. import os
  2. imbd_dir = "D:\\973325230\\Python\\pythonProject\\word embedding\\data\\aclImdb" #你自己的文件路径
  3. train_dir = os.path.join(imbd_dir,"train") #将文件夹里的"train"文件取出来
  4. labels = [] #用于存放标签
  5. texts = [] #用于存放文本内容分
  6. for label_type in ["neg","pos"]:
  7. dir_name = os.path.join(train_dir,label_type)
  8. for fname in os.listdir(dir_name): #fname是取出的文件名
  9. if fname[-4:] == ".txt":
  10. f = open(os.path.join(dir_name,fname),encoding="utf-8")
  11. texts.append(f.read())
  12. f.close()
  13. if label_type == "neg":
  14. labels.append(0)
  15. else:
  16. labels.append(1)

3.数据基本处理

3.1分词

        在这里我们利用TensorFlow2.0提供的Tokenizer函数进行分词操作。

        首先,导入我们本次所需要的包。

  1. from tensorflow.keras.preprocessing.text import Tokenizer #用于分词操作
  2. from tensorflow.keras.preprocessing.sequence import pad_sequences #用于处理序列长度
  3. import numpy as np

         然后,我们实例化一个分词器,用于分词处理,分词后构造一个{单词:序号}样式的字典

  1. maxlen = 100 #只保留每个文本的前100个词
  2. max_words = 10000 #只考虑数据集中最常见的10000个单词
  3. #实例化一个分词器
  4. tokenizer = Tokenizer(num_words=max_words) #num_words:默认是处理所有字词,在这里处理最常见的、出现频率最高的10000个字词。
  5. tokenizer.fit_on_texts(texts) #利用tokenizer和texts构造一个字典(字典里包含了,单词与数字的映射关系)
  6. sequences = tokenizer.texts_to_sequences(texts) #将texts的文字内容转换成数字
  7. #从文本中一共抽取了88582个独一无二的单词
  8. word_index = tokenizer.word_index
  9. print("Found %s unique tokens." % len(word_index))
  10. data = pad_sequences(sequences,maxlen) #只保留文本的前maxlen个单词
  11. labels = np.asarray(labels) #将结构数据转化为ndarray,且不占用新的内存、
  12. print("shape of data tensor:", data.shape)
  13. print("shape of labels tensor:", labels.shape)

        我们可以看一下结果,现在我们的训练数据变成了一个一共有25000个样本,每个样本的文字长度为100的,25000个对应标签的数据集。

3.2训练集与验证集的划分

        我们在15000个样本上进行训练,然后在10000个样本上进行验证。

  1. training_samples = 200 #在200个样本上训练
  2. validation_samples = 10000 #对10000个样本进行验证
  3. ##将数据划分为训练集和验证集
  4. ##首先打乱数据,因为一开始数据集是排好序的,neg在前面,act在后面
  5. indices = np.arange(data.shape[0]) #shape[0] = 25000
  6. np.random.shuffle(indices) #打乱
  7. data = data[indices] #用新的编号排列data
  8. labels = labels[indices] #用新的编号排列labels
  9. x_train = data[:training_samples]
  10. y_train = labels[:training_samples]
  11. x_val = data[training_samples:training_samples+validation_samples]
  12. y_val = labels[training_samples:training_samples+validation_samples]

4.处理GloVe词嵌入数据集

        1.对golve.6B.100d.txt文件进行解析构建一个{单词:向量表示}

样式的词典(embedding_index)。

  1. ##预处理GloVe
  2. glove_dir = "D:\\973325230\\Python\\pythonProject\\word embedding\\data\\glove.6B"
  3. embedding_index = {}
  4. f = open(os.path.join(glove_dir,"glove.6B.100d.txt"),encoding="utf-8")
  5. for line in f: #将字典里的每一行取出来(就是一个单词,对应一个已经训练好的词向量)
  6. values = line.split() #按空格划分,存成list
  7. word = values[0] #每一行的第一个就是单词
  8. coefs = np.asarray(values[1:],dtype="float32") #这个单词所对应的词向量
  9. embedding_index[word] = coefs #将键值对存入词典
  10. f.close()

        我们可以打印看看这个字典的第一个样例。

  1. ##查看字典样例
  2. for key,value in embedding_index.items():
  3. print(key,value)
  4. print(value.shape)
  5. break

        2.我们上一步只是针对glove,构建好了词典,这一步,我们需要利用上一步构建好的词典,为我们的训练集文本构建一个矩阵,其形状为10000×100。(其实,我这里有一点想不清楚,我以为它会做成一个字典然后传入Embedding层,但这里似乎是一个权重矩阵,我也不太清楚它在训练的过程中该如何对应相关的词)

  1. ###利用Glove对要处理的文本重新建立一个字典,字典大小为10000
  2. embedding_dim = 100
  3. embedding_matrix = np.zeros((max_words,embedding_dim))
  4. for word,i in word_index.items():
  5. embedding_vector = embedding_index.get(word) #get()函数返回指定键的值,如果值不存在字典中,则返回默认值
  6. if i < max_words: #选取了88582中前10000个单词换成glove的词向量
  7. if embedding_vector is not None:
  8. ##embedding_index里找得到对应词嵌入就填上,找不到就是0
  9. embedding_matrix[i] = embedding_vector

5.构建模型

        我们采用Keras的序列(Sequential)构建模型,首先导入我们需要的包。

  1. from tensorflow.keras.models import Sequential
  2. from tensorflow.keras.layers import Embedding, Flatten, Dense

         我们讲第一层设为Embedding层,第二层用Faltten()进行降维处理,第三、四层是全连接层,因为是二分类问题,最后一层采用Sigmoid函数,进行归一化处理。

  1. ##构建模型
  2. model = Sequential() #建立一个容器
  3. model.add(Embedding(max_words,embedding_dim,input_length=maxlen))
  4. model.add(Flatten()) #将三维张量展平为二维
  5. model.add(Dense(32,activation="relu"))
  6. model.add(Dense(1,activation="sigmoid"))
  7. model.summary()

6.训练模型

6.1使用预训练模型的词嵌入进行训练

        在刚刚建立好的模型中,我们在第一层,也就是Embedding层加载我们刚才用GloVe建立的embedding_matrix,并将第一层冻结,不参与训练。

  1. #在模型中加载之前设定好的词嵌入,并冻结embedding layer
  2. model.layers[0].set_weights([embedding_matrix])
  3. model.layers[0].trainable = False

        这里,我们设置训练大小批次为32,一共迭代10次。 

  1. ##训练模型
  2. model.compile(optimizer="rmsprop",loss="binary_crossentropy",metrics=["acc"])
  3. history = model.fit(x_train,y_train,epochs=10,batch_size=32,validation_data=(x_val,y_val))
  4. ##保存模型权重
  5. model.save_weights("pre_trained_glove_model.h5")

6.2Embedding层进行词嵌入训练

        这里模型的建立预训练过程都跟6.1是一样的,只不过,我们不再加载GloVe词嵌入,也不再将Embedding层冻结,让其参与训练。

  1. ##构建模型
  2. model = Sequential() #建立一个容器
  3. model.add(Embedding(max_words,embedding_dim,input_length=maxlen))
  4. model.add(Flatten())
  5. model.add(Dense(32,activation="relu"))
  6. model.add(Dense(1,activation="sigmoid"))
  7. model.summary()
  8. ##训练模型
  9. model.compile(optimizer="rmsprop",loss="binary_crossentropy",metrics=["acc"])
  10. history = model.fit(x_train,y_train,epochs=10,batch_size=32,validation_data=(x_val,y_val))

7.可视化训练过程及结果

        我们对训练的过程及结果进行一个可视化处理,这里利用matplotlib进行画图。

  1. import matplotlib.pyplot as plt
  2. ##可视化训练结果
  3. plt.plot(history.history["acc"])
  4. plt.plot(history.history["val_acc"])
  5. plt.title('Model accuracy')
  6. plt.ylabel('Acc')
  7. plt.xlabel('Epoch')
  8. plt.legend(['train_accuracy', 'val_accuracy'], loc='upper left')
  9. plt.show()

        1.使用预训练的词嵌入进行训练的过程及结果。 

         我们可以看到训练的准确率与验证的准确率相差较大,不过这里只使用了较少的训练数据,并且没有进行调参,但是验证准确率基本达到60%左右。

 

        2.只使用Embedding词嵌入进行训练的过程及结果。

        由图可知,不适用预训练模型的验证集准确率只在50%左右,使用预训练词嵌入模型的性能优于未使用预训练的模型性能。

8.总结

        该项目参考于《深入浅出Embedding》第2章内容,上述实验在训练集数据增加之后,采用Embedding层的效果反而优于了引入预训练模型的词嵌入方法,希望各大读者,也包括我可以进一步探究其中的原因。

        接offer~ 接offer~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/870521
推荐阅读
相关标签
  

闽ICP备14008679号