查看原文
其他

NLP.TM | Keras做基本的文本分类

机智的叉烧 CS的陋室 2022-08-08

【NLP.TM】

本人有关自然语言处理和文本挖掘方面的学习和笔记,欢迎大家关注。

往期回顾:

上次谈到了用tensorflow进行文本分类,tf其实有着比较灵活的形式,但是灵活的形式一定伴随着比较复杂的配置,因此代码,尤其是模型那块会比较多,当然地,也有比较简单的方案,那就是keras,keras在我的理解是一个外壳,可以套着tensorflow,也可以套着theano,其实都可以,套上之后同样可以做深度学习,而且代码结构写起来会比较简单,但是由于本身结构比较直接简单,所以不能很好地做一些复杂结构的网络。

CNN做文本分类是一个非常简单而又常见的任务,keras当然能轻松支持,那么在之前的基础上,我们来看看keras怎么实现吧。另外拉到最后点击阅读原文可以看到我的全套代码

这是上次发布的tensorflow做文本分类的文章,有关预备的内容在这里写清楚:

# NLP.TM | tensorflow做基础的文本分类

直接上代码

这里从拿到分词后结果的数据poscw.txt和negcw.txt之后开始进行。

数据加载

  1. # 读取文件

  2. pos_data = []

  3. with open(POS_PATH) as f:

  4. for line in f:

  5. ll = line.strip().split("\t")

  6. pos_data.append(ll)

  7. neg_data = []

  8. with open(NEG_PATH) as f:

  9. for line in f:

  10. ll = line.strip().split("\t")

  11. neg_data.append(ll)


  12. all_data = pos_data + neg_data


  13. # 数据打标签

  14. y = np.concatenate((np.ones(len(pos_data)), np.zeros(len(neg_data))))


  15. # 数据集打乱

  16. index = [i for i in range(len(all_data))]

  17. np.random.shuffle(index)

  18. x = np.array(all_data)[index]

  19. y = y[index]


  20. # 数据集划分

  21. x_train, x_test, y_train, y_test = train_test_split(

  22. x, y, test_size=0.2, random_state=10)

  23. print("data preprocessing completed")

首先通过数据流的方式加载数据,然后为数据添加标签,添加后打乱数据,并且对打乱数据做数据集划分,与之前的数据操作非常类似,但此处不再需要自己去分batch了。

w2v的有关操作

  1. # word2vec

  2. imdb_w2v = Word2Vec(size=N_DIM, min_count=MIN_COUNT)

  3. imdb_w2v.build_vocab(all_data)


  4. for sentence_idx in range(len(all_data)):

  5. for word_item_idx in range(len(all_data[sentence_idx])):

  6. if all_data[sentence_idx][word_item_idx] not in imdb_w2v.wv.vocab:

  7. all_data[sentence_idx][word_item_idx] = "unk_"


  8. imdb_w2v = Word2Vec(size=N_DIM, min_count=MIN_COUNT)

  9. imdb_w2v.build_vocab(all_data)


  10. imdb_w2v.train(all_data, total_examples=len(all_data), epochs=w2v_EPOCH)


  11. # word2vec后处理

  12. n_symbols = len(imdb_w2v.wv.vocab.keys()) + 1

  13. embedding_weights = np.zeros((n_symbols, N_DIM))

  14. idx = 1

  15. word2idx_dic = {}

  16. for w in imdb_w2v.wv.vocab.keys():

  17. embedding_weights[idx, :] = imdb_w2v[w]

  18. word2idx_dic[w] = idx

  19. idx = idx + 1

  20. # print(embedding_weights[0, :])


  21. # 文字转化为数字索引

  22. x_train = text_to_index_array(word2idx_dic, x_train)

  23. x_test = text_to_index_array(word2idx_dic, x_test)

特征这块,主要就是Word2vector的操作,非常容易理解,此处也和之前的非常类似。

  • word2vector词库构成,此处也对出现少的词汇进行了“unk_”操作

  • word2vector训练

  • word2vector整理的词典根据后续keras的embedding操作转为合适的数据结构

  • 另外要把文本转为数字索引

文字转为数字索引函数texttoindex_array的定义如下:

  1. def text_to_index_array(p_new_dic, p_sen): # 文本转为索引数字模式

  2. new_sentences = []

  3. for sen in p_sen:

  4. new_sen = []

  5. for word in sen:

  6. try:

  7. new_sen.append(p_new_dic[word]) # 单词转索引数字

  8. except:

  9. new_sen.append(0) # 索引字典里没有的词转为数字0

  10. new_sentences.append(new_sen)


  11. return np.array(new_sentences)

标签处理

  1. # y值处理为2维

  2. y_train_oh = []

  3. for idx in range(len(y_train)):

  4. item = [0, 0]

  5. item[int(y_train[idx])] = 1

  6. y_train_oh.append(item)


  7. y_test_oh = []

  8. for idx in range(len(y_test)):

  9. item = [0, 0]

  10. item[int(y_test[idx])] = 1

  11. y_test_oh.append(item)

此处标签要处理为二维,因此单独处理此块,当然大家可以把它用函数编辑。

深度学习模型与评估

  1. # 开始建立深度学习模型LSTM

  2. model = Sequential()

  3. model.add(Embedding(output_dim=N_DIM,

  4. input_dim=n_symbols,

  5. weights=[embedding_weights],

  6. input_length=MAXLEN, trainable=True))

  7. model.add(Dropout(0.2))


  8. model.add(Conv1D(50, (3)))

  9. model.add(MaxPooling1D(pool_size=2, stride=2))

  10. model.add(Activation('relu'))


  11. model.add(Conv1D(50, (4)))

  12. model.add(MaxPooling1D(pool_size=2, stride=2))

  13. model.add(Activation('relu'))


  14. model.add(Conv1D(50, (5)))

  15. model.add(MaxPooling1D(pool_size=2, stride=2))

  16. model.add(Activation('relu'))


  17. model.add(Flatten())

  18. model.add(Dense(64))


  19. model.add(Activation('relu'))

  20. model.add(Dense(2))

  21. model.add(Activation('softmax'))


  22. model.compile(loss='binary_crossentropy',

  23. optimizer='adam',

  24. metrics=['accuracy'])

  25. model.summary()


  26. model.fit(x_train, y_train_oh, batch_size=64, nb_epoch=5,

  27. validation_data=(x_test, y_test_oh))


  28. print("evaluating...")

  29. score, acc = model.evaluate(x_test, y_test_oh, batch_size=64)

  30. print('Test score: %s ' % score)

  31. 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的灵活性使得他会出现更多灵活的方案,模型的升级改造下当然是非常有用的。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存