利用LSTM实现简单的情感分类任务。
Keras是一个高度模块化的神经网络第三方库,利用它可以十分便利地搭建LSTM神经网络。
在使用LSTM进行情感分类之前,我们首先需要将文本转特征。一般有两种方式,bag of words和word embedding。bag of words指的是对于一个文本,不考虑词序、语法和句法,仅仅将它看作一组词汇的集合。word embedding则是先根据文本生成词对应的词向量,然后利用词向量来表示文本。word embedding中词向量的生成可以利用gensim库中的Word2Vec来实现或者利用keras自带的Embedding层,这里介绍第一种。
import gensim
import os
class MySentences():
def __init__(self, dirPath):
self.dirPath = dirPath
def __iter__(self):
for eachList in os.walk(self.dirPath):
if eachList[2]:
for eachFile in eachList[2]:
with open(os.path.join(eachList[0], eachFile), 'r') as fp:
yield fp.read().split()
if __name__ == '__main__':
sentences = MySentences(r'C:\Users\ASUS\Desktop\unigram')
print 'Build word model...'
#size设置词向量大小,min_count设置词频限制,workers设置并行化的程度
word_model = gensim.models.Word2Vec(sentences, size = 200, min_count = 10, workers = 4)
word_model.save('word_model1_200.m')
word_model.save_word2vec_format('word_model1_200.txt', binary = False)
word_model = gensim.models.Word2Vec.load('word_model1_200.m')
word embedding在相同维度的数据上效果最好,所以当使用embedding表示文本时需要对较短的文本进行补偿或者对较长的文本进行截取以保持文本维度的一致性。
def createVec(documents, word_model):
vecs = []
labels = []
for doc in documents:
vec = [word_model[word] for word in doc.words if word in word_model]
if len(vec) == 0:
if len(vecs) == 0:
vec = [random.random() for i in range(embedding_dims)]
else:
vec = vecs[0]
labels.append(doc.polarity)
continue
elif len(vec) < maxlen:
j = 0
while len(vec) < maxlen:
vec.append(vec[j])
j += 1
else:
vec = vec[:maxlen]
vecs.append(vec)
labels.append(doc.polarity)
return vecs, labels
准备好所需要的文本格式后,我们就可以开始利用Keras搭建LSTM神经网络了。基本代码如下:
def LSTM_model(trainArray, testArray, trainLabels, testLabels):
model = Sequential()
#input_shape指的是每个文本特征化后对应的维度。
model.add(LSTM(lstm_output_dim, input_shape = (maxlen, embedding_dim)))
#激励函数有两种添加方式。
model.add(Dense(hidden_dim, activation = 'relu'))
# model.add(Activation('relu'))
#将50%的神经元disable。
model.add(Dropout(0.5))
#二元分类一般使用sigmoid作为激励函数,多元分类使用softmax。
model.add(Dense(1, activation = 'sigmoid'))
#二元分类一般使用binary_crossentropy作为损失函数,多元分类使用categorical_crossentropy,class_mode的选择也是相同的道理。
model.compile(loss = 'binary_crossentropy', optimizer = 'adam', class_mode = 'binary')
#因为我的任务是二元分类,所以类别标签本来就是0,1序列。如果是多元分类,可以使用Keras中的np_utils.to_categorical(trainLabels, nb_classes)完成类别标签的转换。其中batch_size代表每次梯度更新选择的样本数目,nb_epoch代表迭代次数,verbose代表进度显示方式,validation_data代表验证集数据。
hist = model.fit(trainArray, trainLabels, batch_size = batch_size, nb_epoch = nb_epoch, verbose = 2, validation_data = (valArray, valLabels))
#预测测试集标签
preLabels = model.predict_classes(testArray, batch_size = batch_size, verbose = 2)