之前的LeNet-5卷积神经网络模型体现了数据在空间上的关联性,但除此之外,数据也有可能在时间上有关联性,比如气温数据,股票数据等。当然,最典型的还是人类的语言。面对这样在时间上有关联的数据,神经网络该如何去识别和处理呢?
我们一般把词作为自然语言处理的基本单位,这样就可以利用“词典”用一个数字来代表一个词,这个数字就是索引值。这样,由词组成的一句话就会转化为一个由数字组成的向量,自然就可以送入神经网络进行识别了。
如果有些词在词典中由于种种原因数据接近,但是含义却相差甚远,这时候如果再进行归一化操作,计算机就很可能错误的识别到完全相反的意思。这样的数据就会给预测模型带来不必要的麻烦。所以我们可以使用one-hot的编码方式对词汇进行编码。通过one-hot编码后每个词都完全不一样。
但是这样进行严格区分的话,又丢失了词汇的关联性。我们可以提取出一个词汇的多个特征值形成一个词向量,即NLP中的词嵌入。
最后我们结合一下one-hot和词向量。让词向量组成的矩阵(字典)点乘按词语组成句子的one-hot编码形成的矩阵,这样就可以提取出句子中每一个词的词向量,这样就可以送入神经网络进行学习了。
明白了原理,我们就来实现一个简单的文本情感分类模型
首先在网上找到了一个别人爬的网购评论的csv文件,然后封装一个shoppingdata.py用来读取和处理这些数据。
import os import keras import numpy as np import keras.preprocessing.text as text import re import jieba import random def load_data(): xs = [] ys = [] with open(os.path.dirname(os.path.abspath(__file__))+'/online_shopping_10_cats.csv','r',encoding='utf-8') as f: line=f.readline()#escape first line"label review" while line: line=f.readline() if not line: break contents = line.split(',') # if contents[0]=="书籍": # continue label = int(contents[1]) review = contents[2] if len(review)>20: continue xs.append(review) ys.append(label) xs = np.array(xs) ys = np.array(ys) #打乱数据集 indies = [i for i in range(len(xs))] random.seed(666) random.shuffle(indies) xs = xs[indies] ys = ys[indies] m = len(xs) cutpoint = int(m*4/5) x_train = xs[:cutpoint] y_train = ys[:cutpoint] x_test = xs[cutpoint:] y_test = ys[cutpoint:] print('总样本数量:%d' % (len(xs))) print('训练集数量:%d' % (len(x_train))) print('测试集数量:%d' % (len(x_test))) return x_train,y_train,x_test,y_test def createWordIndex(x_train,x_test): x_all = np.concatenate((x_train,x_test),axis=0) #建立词索引 tokenizer = text.Tokenizer() #create word index word_dic = {} voca = [] for sentence in x_all: # 去掉标点 sentence = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "", sentence) # 结巴分词 cut = jieba.cut(sentence) #cut_list = [ i for i in cut ] for word in cut: if not (word in word_dic): word_dic[word]=0 else: word_dic[word] +=1 voca.append(word) word_dic = sorted(word_dic.items(), key = lambda kv:kv[1],reverse=True) voca = [v[0] for v in word_dic] tokenizer.fit_on_texts(voca) print("voca:"+str(len(voca))) return len(voca),tokenizer.word_index def word2Index(words,word_index): vecs = [] for sentence in words: # 去掉标点 sentence = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "", sentence) # 结巴分词 cut = jieba.cut(sentence) #cut_list = [ i for i in cut ] index=[] for word in cut: if word in word_index: index.append(float(word_index[word])) # if len(index)>25: # index = index[0:25] vecs.append(np.array(index)) return np.array(vecs)
首先得到数据的索引表示:
x_train_index = shopping_data.word2Index(x_train, word_index) x_test_index = shopping_data.word2Index(x_test, word_index)
因为每句话长短不同,我们需要利用keras.preprocessing中的sequence进行一个对齐操作
maxlen = 25 x_train_index = sequence.pad_sequences(x_train_index, maxlen=maxlen) x_test_index = sequence.pad_sequences(x_test_index, maxlen=maxlen)
首先创造一个Sequential模型,堆叠Embedding层,然后利用Flatten把数据平铺开,再送入一个256-256-256的神经网络中进行训练,最后利用sigmoid函数进行输出。
model = Sequential() model.add(Embedding(trainable=Ture, input_dim=vocalen, output_dim=300, input_length=maxlen)) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(1, activation='sigmoid'))
然后使用交叉熵代价函数和adam优化器,训练200回合,批尺寸为512。
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(x_train_index, y_train, batch_size=512, epochs=200)
然后开始训练。得到评估结果。
86%的准确度。
本文作者:Ch1nfo
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!