NLP.TM | Keras做基本的文本分类
【NLP.TM】
本人有关自然语言处理和文本挖掘方面的学习和笔记,欢迎大家关注。
往期回顾:
上次谈到了用tensorflow进行文本分类,tf其实有着比较灵活的形式,但是灵活的形式一定伴随着比较复杂的配置,因此代码,尤其是模型那块会比较多,当然地,也有比较简单的方案,那就是keras,keras在我的理解是一个外壳,可以套着tensorflow,也可以套着theano,其实都可以,套上之后同样可以做深度学习,而且代码结构写起来会比较简单,但是由于本身结构比较直接简单,所以不能很好地做一些复杂结构的网络。
CNN做文本分类是一个非常简单而又常见的任务,keras当然能轻松支持,那么在之前的基础上,我们来看看keras怎么实现吧。另外拉到最后点击阅读原文可以看到我的全套代码。
这是上次发布的tensorflow做文本分类的文章,有关预备的内容在这里写清楚:
直接上代码
这里从拿到分词后结果的数据poscw.txt和negcw.txt之后开始进行。
数据加载
# 读取文件
pos_data = []
with open(POS_PATH) as f:
for line in f:
ll = line.strip().split("\t")
pos_data.append(ll)
neg_data = []
with open(NEG_PATH) as f:
for line in f:
ll = line.strip().split("\t")
neg_data.append(ll)
all_data = pos_data + neg_data
# 数据打标签
y = np.concatenate((np.ones(len(pos_data)), np.zeros(len(neg_data))))
# 数据集打乱
index = [i for i in range(len(all_data))]
np.random.shuffle(index)
x = np.array(all_data)[index]
y = y[index]
# 数据集划分
x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size=0.2, random_state=10)
print("data preprocessing completed")
首先通过数据流的方式加载数据,然后为数据添加标签,添加后打乱数据,并且对打乱数据做数据集划分,与之前的数据操作非常类似,但此处不再需要自己去分batch了。
w2v的有关操作
# word2vec
imdb_w2v = Word2Vec(size=N_DIM, min_count=MIN_COUNT)
imdb_w2v.build_vocab(all_data)
for sentence_idx in range(len(all_data)):
for word_item_idx in range(len(all_data[sentence_idx])):
if all_data[sentence_idx][word_item_idx] not in imdb_w2v.wv.vocab:
all_data[sentence_idx][word_item_idx] = "unk_"
imdb_w2v = Word2Vec(size=N_DIM, min_count=MIN_COUNT)
imdb_w2v.build_vocab(all_data)
imdb_w2v.train(all_data, total_examples=len(all_data), epochs=w2v_EPOCH)
# word2vec后处理
n_symbols = len(imdb_w2v.wv.vocab.keys()) + 1
embedding_weights = np.zeros((n_symbols, N_DIM))
idx = 1
word2idx_dic = {}
for w in imdb_w2v.wv.vocab.keys():
embedding_weights[idx, :] = imdb_w2v[w]
word2idx_dic[w] = idx
idx = idx + 1
# print(embedding_weights[0, :])
# 文字转化为数字索引
x_train = text_to_index_array(word2idx_dic, x_train)
x_test = text_to_index_array(word2idx_dic, x_test)
特征这块,主要就是Word2vector的操作,非常容易理解,此处也和之前的非常类似。
word2vector词库构成,此处也对出现少的词汇进行了“unk_”操作
word2vector训练
word2vector整理的词典根据后续keras的embedding操作转为合适的数据结构
另外要把文本转为数字索引
文字转为数字索引函数texttoindex_array的定义如下:
def text_to_index_array(p_new_dic, p_sen): # 文本转为索引数字模式
new_sentences = []
for sen in p_sen:
new_sen = []
for word in sen:
try:
new_sen.append(p_new_dic[word]) # 单词转索引数字
except:
new_sen.append(0) # 索引字典里没有的词转为数字0
new_sentences.append(new_sen)
return np.array(new_sentences)
标签处理
# y值处理为2维
y_train_oh = []
for idx in range(len(y_train)):
item = [0, 0]
item[int(y_train[idx])] = 1
y_train_oh.append(item)
y_test_oh = []
for idx in range(len(y_test)):
item = [0, 0]
item[int(y_test[idx])] = 1
y_test_oh.append(item)
此处标签要处理为二维,因此单独处理此块,当然大家可以把它用函数编辑。
深度学习模型与评估
# 开始建立深度学习模型LSTM
model = Sequential()
model.add(Embedding(output_dim=N_DIM,
input_dim=n_symbols,
weights=[embedding_weights],
input_length=MAXLEN, trainable=True))
model.add(Dropout(0.2))
model.add(Conv1D(50, (3)))
model.add(MaxPooling1D(pool_size=2, stride=2))
model.add(Activation('relu'))
model.add(Conv1D(50, (4)))
model.add(MaxPooling1D(pool_size=2, stride=2))
model.add(Activation('relu'))
model.add(Conv1D(50, (5)))
model.add(MaxPooling1D(pool_size=2, stride=2))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dense(2))
model.add(Activation('softmax'))
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.summary()
model.fit(x_train, y_train_oh, batch_size=64, nb_epoch=5,
validation_data=(x_test, y_test_oh))
print("evaluating...")
score, acc = model.evaluate(x_test, y_test_oh, batch_size=64)
print('Test score: %s ' % score)
print('Test accuracy: %s' % acc)
根据keras模型的API(https://keras.io/),可以采用上面方式进行建模,可以看到整个模型的构建比较简单粗暴,并不冗杂。
Sequential初始化模型,后面是通过model.add的方式,逐一向后添加模型,这是一种加性的keras结构,另外还有函数式的结构,函数式其实能够容纳更丰富的分支结构,加性的其实对分支形式的网络结构支持的不好。
依次经过embedding、3个1维卷积+1维池化+relu激活的卷积神经网络、flatten、2层全连接等形式的网络结构
compile编译整理模型,summary打印模型基本结构
fit进行模型训练
evaluate进行模型评估
总结
其实看完keras,大家就会发现其实keras需要做的工作远远比tensorflow要少,这是keras独特的优势,很多人更倾向于选择这么一个简单的方案,我用着也觉得“真香”,不过个人还是觉得,tensorflow的灵活性使得他会出现更多灵活的方案,模型的升级改造下当然是非常有用的。