将下载的原始数据进行转码,然后给文本标类别的标签,然后制作训练与测试数据,然后控制文本长度,分词,去标点符号
哎,坑多,费事,比较麻烦
首先,搜狗实验室提供的数据下载下来是 xml 格式,并且是 GBK (万恶之源)编码,需要转成 UTF8,并整理成 json 方便处理。原始数据长这个样:
用序号1~11表示
深度学习用的 keras 工具,操作简单易懂,模型上手飞快,居家旅行必备。keras 后端用的 Tensorflow,虽然用什么都一样
不使用预训练 word2vec 模型的 CNN:
首先一些先设定一些会用到的参数
MAX_SEQUENCE_LENGTH = 100 # 每条新闻最大长度
EMBEDDING_DIM = 200 # 词向量空间维度
VALIDATION_SPLIT = 0.16 # 验证集比例
TEST_SPLIT = 0.2 # 测试集比例
第一步先把训练与测试数据放在一起提取特征,使用 keras 的 Tokenizer 来实现,将新闻文档处理成单词索引序列,单词与序号之间的对应关系靠单词的索引表 word_index 来记录,这里从所有新闻中提取到 65604 个单词,比如 [苟,国家,生死] 就变成了 [1024, 666, 233] ;然后将长度不足 100 的新闻用 0 填充(在前端填充),用 keras 的 pad_sequences 实现;最后将标签处理成 one-hot 向量,比如 6 变成了 [0,0,0,0,0,0,1,0,0,0,0,0,0],用 keras 的 to_categorical 实现
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.utils import to_categorical
import numpy as np
tokenizer = Tokenizer()
tokenizer.fit_on_texts(all_texts)
sequences = tokenizer.texts_to_sequences(all_texts)
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
labels = to_categorical(np.asarray(all_labels))
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)
再将处理后的新闻数据按 6.4:1.6:2 分为训练集,验证集,测试集
p1 = int(len(data)*(1-VALIDATION_SPLIT-TEST_SPLIT))
p2 = int(len(data)*(1-TEST_SPLIT))
x_train = data[:p1]
y_train = labels[:p1]
x_val = data[p1:p2]
y_val = labels[p1:p2]
x_test = data[p2:]
y_test = labels[p2:]
print 'train docs: '+str(len(x_train))
print 'val docs: '+str(len(x_val))
print 'test docs: '+str(len(x_test))
然后就是搭建模型,首先是一个将文本处理成向量的 embedding 层,这样每个新闻文档被处理成一个 100 x 200 的二维向量,100 是每条新闻的固定长度,每一行的长度为 200 的行向量代表这个单词在空间中的词向量。下面通过 1 层卷积层与池化层来缩小向量长度,再加一层 Flatten 层将 2 维向量压缩到 1 维,最后通过两层 Dense(全连接层)将向量长度收缩到 12 上,对应新闻分类的 12 个类(其实只有 11 个类,标签 0 没有用到)。搭完收工,最后,训练模型,测试模型,一鼓作气,攻下高地。
from keras.layers import Dense, Input, Flatten, Dropout
from keras.layers import Conv1D, MaxPooling1D, Embedding
from keras.models import Sequential
model = Sequential()
model.add(Embedding(len(word_index) + 1, EMBEDDING_DIM, input_length=MAX_SEQUENCE_LENGTH))
model.add(Dropout(0.2))
model.add(Conv1D(250, 3, padding='valid', activation='relu', strides=1))
model.add(MaxPooling1D(3))
model.add(Flatten())
model.add(Dense(EMBEDDING_DIM, activation='relu'))
model.add(Dense(labels.shape[1], activation='softmax'))
model.summary()
正常的深度学习训练,比如上面的 CNN 模型,第一层(除去 Input 层)是一个将文本处理成向量的 embedding 层。这里为了使用预训练的 word2vec 来代替这个 embedding 层,就需要将 embedding 层的 1312 万个参数用 word2vec 模型中的词向量替换。替换后的 embedding 矩阵形状为 65604 x 200,65604 行代表 65604 个单词,每一行的这长度 200 的行向量对应这个词在 word2vec 空间中的 200 维向量。最后,设定 embedding 层的参数固定,不参加训练,这样就把预训练的 word2vec 嵌入到了深度学习的模型之中
VECTOR_DIR = 'wiki.zh.vector.bin' # 词向量模型文件
from keras.utils import plot_model
from keras.layers import Embedding
import gensim
w2v_model = gensim.models.KeyedVectors.load_word2vec_format(VECTOR_DIR, binary=True)
embedding_matrix = np.zeros((len(word_index) + 1, EMBEDDING_DIM))
for word, i in word_index.items():
if unicode(word) in w2v_model:
embedding_matrix[i] = np.asarray(w2v_model[unicode(word)],
dtype='float32')
embedding_layer = Embedding(len(word_index) + 1,
EMBEDDING_DIM,
weights=[embedding_matrix],
input_length=MAX_SEQUENCE_LENGTH,
trainable=False)
from keras.layers import Dense, Input, Flatten, Dropout
from keras.layers import Conv1D, MaxPooling1D, Embedding
from keras.models import Sequential
model = Sequential()
model.add(embedding_layer)
model.add(Dropout(0.2))
model.add(Conv1D(250, 3, padding='valid', activation='relu', strides=1))
model.add(MaxPooling1D(3))
model.add(Flatten())
model.add(Dense(EMBEDDING_DIM, activation='relu'))
model.add(Dense(labels.shape[1], activation='softmax'))
model.summary()
#plot_model(model, to_file='model.png',show_shapes=True)
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['acc'])
model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=2, batch_size=128)
model.save('word_vector_cnn.h5')
print model.evaluate(x_test, y_test)
# -*- coding:utf-8 -*-
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.models import load_model
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import jieba
MAX_SEQUENCE_LENGTH = 100
model = load_model('word_vector_cnn.h5')
'''text = open('test.txt', 'r', encoding = 'utf-8').read()
result = jieba.cut(text)
rtext=""
for i in result:
rtext += i
rtext += ' '
print (rtext)'''
stopwords=[]
for word in open('stopword.txt','r',encoding='utf-8', errors='ignore').read():
stopwords.append(word.strip())
# print(word)
article=open('test.txt','r',encoding='utf-8', errors='ignore').read()
print(stopwords)
words=jieba.cut(article,cut_all=False)
rtext=""
for word in words:
print(word)
if word not in stopwords:
rtext+=word+" "
print (rtext)
tokenizer = Tokenizer()
tokenizer.fit_on_texts(rtext)
print(tokenizer.fit_on_texts(rtext))
sequences = tokenizer.texts_to_sequences(rtext)
print(len(sequences))
print(sequences)
sequence=[]
for i in range(len(sequences)):
#print(sequences[i])
if sequences[i]:
sequence.append(sequences[i][0])
print(sequence)
seq = []
seq.append(sequence)
word_index = tokenizer.word_index
print(word_index)
data = pad_sequences(seq, maxlen=MAX_SEQUENCE_LENGTH)
print(data)
output = model.predict(data)
print (output)