天天看点

Python 深度学习--学习笔记(十一)

使用预训练模型学习判断imdb评论正负面模型

本节的模型与上节见过的那个类似:将句子嵌入到向量序列中,然后将其展平,最后在上面训练一个 Dense 层。但此处将使用预训练的词嵌入。此外,我们将从头开始,先下载IMDB 原始文本数据,而不是使用 Keras 内置的已经预先分词的 IMDB 数据。

首先,在 http://mng.bz/0tIo ,下载原始IMDB数据集并解压。

文件夹的结构如下:

aclImdb:

├─test

│ ├─neg

│ └─pos

└─train

├─neg

└─pos

随便打开一个neg文件夹里的文本:

Python 深度学习--学习笔记(十一)

想必,这就是评论的原生数据,并没有像之前keras内置的imdb数据集那样帮我们处理好了单词->序列的转化。

  • 处理 IMDB 原始数据的标签
#导入要处理的数据
import os

imdb_dir = 'C:\\Users\\Administrator\\Desktop\\Keras_learn\\aclImdb'
train_dir = os.path.join(imdb_dir,'train')

labels = []
texts = []

for label_type in ['neg','pos']:
    dir_name = os.path.join(train_dir,label_type)
    for fname in os.listdir(dir_name):
        if fname[-4:] == '.txt':
            f = open(os.path.join(dir_name,fname), encoding='UTF-8')
            texts.append(f.read())
            f.close()
            if label_type == 'neg':
                labels.append(0)
            else:
                labels.append(1)
                
           

这里从训练集中,分别导入neg和pos文件夹里的文本信息,并在 labels 相应的索引处添加标签值,0表示负面评价,1表示正面评价。

让我们验证下导入是否成功:

print(len(texts))
print(texts[0])
           

输出:

Python 深度学习--学习笔记(十一)

正负面评价总共有25 000 条。

  • 处理数据

    keras内置了分词器(tokenizer)功能,可以在限制单词数的前提下,为需要的单词编号。

#处理数据
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import numpy as np

maxlen = 100 #在100个单词后截断评论
training_samples = 200 #200个训练样本
validation_samples = 10000  #10 000个验证样本
max_words = 10000 #只考虑数据集中前10 000 个最常见的单词

tokenizer = Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts) #将单词转化为序列

word_index = tokenizer.word_index
print('Found %s unique tokens.'% len(word_index))

data = pad_sequences(sequences,maxlen=maxlen)
#不够maxlen用 0 填补

labels = np.asarray(labels)
print('Shape of data tensor:',data.shape)
print('Shape of label tensor:',labels.shape)

#打乱顺序
indices = np.arange(data.shape[0])
indices = np.random.choice(indices,indices.shape[0])

data = data[indices]
labels = labels[indices]

x_train = data[:training_samples]
y_train = labels[:training_samples]
x_val = data[training_samples:training_samples + validation_samples]
y_val = labels[training_samples:training_samples + validation_samples]
           

输出:

Python 深度学习--学习笔记(十一)
  • 下载GloVe词嵌入

    打开https://nlp.stanford.edu/projects/glove,下载 2014 年英文维基百科的预计算嵌入。这是一个 822 MB 的压缩文件,文件名是 glove.6B.zip,里面包含 400 000 个单词(或非单词的标记)的 100 维嵌入向量。解压文件。

  • 导入模型参数

    我们用字典的方式,导入词——向量。

# 解析 GloVe 词嵌入文件
glove_dir = 'C:\\Users\\Administrator\\Desktop\\Keras_learn\\glove'
#文件里每行是一个单词,和该单词的词向量
embeddings_index = {}
f = open(os.path.join(glove_dir,'glove.6B.100d.txt'),encoding='utf-8')
#构建  词:向量  的字典
for line in f:
    values = line.split()
    word = values[0] #获得单词
    coefs = np.asarray(values[1:],dtype='float32') #获得词向量
    embeddings_index[word] = coefs #构建  词:向量  的字典
f.close()

print('Found %s word vectors.'%len(embeddings_index))
           

输出:

Python 深度学习--学习笔记(十一)
  • 准备 GloVe 词嵌入矩阵

要让参数注入模型中,必须将这个字典转为矩阵的形式。

#准备 GloVe 词嵌入矩阵
embedding_dim = 100

embedding_matrix = np.zeros((max_words,embedding_dim))
for word, i in word_index.items():
    if  i < max_words:
        embedding_vector = embeddings_index.get(word)
        if embedding_vector is not None:
            embedding_matrix[i] = embedding_vector
            #在glove中找不到的词,其嵌入向量全为0
           

这里,值得注意的是,每个单词都转为一个100维向量。

  • 模型定义
#模型定义
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense

model = Sequential()
model.add(Embedding(max_words,embedding_dim,input_length=maxlen))
#max_words==10 000, embedding_dim==100, maxlen==100
model.add(Flatten())
model.add(Dense(32,activation='relu'))
model.add(Dense(1,activation='sigmoid'))
model.summary()
           
Python 深度学习--学习笔记(十一)
  • 将预训练的词嵌入加载到 Embedding 层中
#model的第一层即为embedding
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False
           
  • 编译,训练模型
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])
history = model.fit(x_train,y_train,
                   epochs=10,
                   batch_size=32,
                   validation_data=(x_val,y_val))
model.save_weights('pre_trained_glove_model.h5')
           

输出:

Python 深度学习--学习笔记(十一)
  • 绘制结果
#绘制结果
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1,len(acc)+1)

plt.figure("acc")
plt.plot(epochs,acc,'bo',label="Training acc")
plt.plot(epochs,val_acc,'b',label="Validation acc")
plt.title("Traning and validation accuracy")
plt.legend()

plt.figure("loss")
plt.plot(epochs,loss,'bo',label="Training loss")
plt.plot(epochs,val_loss,'b',label="Validation loss")
plt.title("Traning and validation loss")
plt.legend()

plt.show()

           
Python 深度学习--学习笔记(十一)

可以明显看出,由于训练样本只有 200,会严重依赖样本,训练集接近1,而验证集的准确度只有0.56。但换个角度想想,只用了200个数据集就可以达到超过一半的准确度,也是不容易的。

继续阅读