
python 循环:序列依赖问题(学习笔记)
循环:序列依赖问题
当我们要机器识别语言时,不以字符为单位,而是以词为单位通过查词典的方式进行。以Nice to meet you
举例,通过查词典的方式我们得到它的序列并形成一个向量[6787 2845 5898 9032]
。
中文相比英文来讲多一步分词操作举例:
当然这样处理会出现一个问题,当学习到开除与开心的时候,由于二者第一个字母是一样的再进行归一化处理,这两个数值差异极小但概念不同,这样的数据就会有所偏差。
如果我们进行One-hot操作,让所有的序列都变成如下一样的矩阵,这样减少了词汇之间的关联性同样也减少了上面的问题。
但仍然不是很好的办法。
再比如下面猫狗应该是比较接近的,苹果和西瓜也是比较接近的,但这里one-hot无法识别会把它们看成四类。
这样难以训练和泛化,并且还会让输入的数据非常大。
为了解决这个问题,我们可以提取出一个物体或动物的多个特征,比如它是否是名词?是否是动物?…等;多个特征值组成一个向量。
我们给一个词添加多个特征的值,当有句子对应到相关的词时候我们进行One-hot处理,得出新的矩阵再进行铺开后得出一组向量并进行全连接神经网络的计算运行。前面W与X相乘的过程被称为嵌入层。
一般使用别人的海量数据上训练好的词向量数据,应用到自己的工程中,常见的词向量训练算法有word2vec和GloVe。
除此之外还需要注意的是:时间序列上的不一样,会导致机器学习的不正确。举例这个视频非常好看、这个视频非常不好看由于非常
和好看
的词汇导致正面评论关系比较大,但由于一个不值就会进行反转,而机器学习更需要注意的是其中的关联性。
编程实践
再此之前我们准备了一个online_shopping_10_cats.csv
的数据。
里面每行有三列不同的数据:类型,是否是正面评价(1代表是,0表不是),评论文本。
添加新的py工具文件shopping_data.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)
上代码。
import shopping_data
from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Embedding
from keras.layers import Flatten
# 获取数据
x_train, y_train, x_test, y_test = shopping_data.load_data()
# 打印向量的长度
print('x_train.shape:',x_train.shape) # 13276
print('y_train.shape:',y_train.shape) # 13276
print('x_test.shape:',x_test.shape) # 3319
print('y_test.shape:',y_test.shape) # 3319
# 打印出第一组数据
print(x_train[0])
print(y_train[0])
# 统计全体词汇
# 做one hot编码
# 使用Embedding来专门做嵌入层这件事。
# vocalen 是这个词典的词汇数量
# word_index 训练集和测试集全部语言的词典
vocalen, word_index = shopping_data.createWordIndex(x_train, x_test)
print(vocalen)
print('词典总词数:',word_index)
# 转换成向量
# 举例:x_train 今天天气不错
# # ()
# x_train_index=
x_train_index = shopping_data.word2Index(x_train, word_index)
x_test_index =shopping_data.word2Index(x_test, word_index)
maxlen = 25
# 把序列按照maxlen进行对齐
# 把长度不足25的补齐为25
x_train_index = sequence.pad_sequences(x_train_index, maxlen=maxlen)
x_test_index = sequence.pad_sequences(x_test_index, maxlen=maxlen)
# 设置训练层以及神经元数量
model = Sequential()
# 添加嵌入层
# input_dim 输入维度
# output_dim 输出维度
# input_length 序列长度
# trainable 是否在这一层训练的时候更新参数。
model.add(Embedding(trainable=False,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'))
# 加一个sigmoid函数
model.add(Dense(1, activation='sigmoid'))
# compile模型
# loss binary_crossentropy 交叉熵代价函数
# optimizer adam 动量自适应优化器 比sgd快
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
# 200回合批尺寸为512
model.fit(x_train_index, y_train, batch_size=512,epochs=200)
# 进行训练
score, acc = model.evaluate(x_test_index, y_test)
print('Test score:', score)
print('Test accuracy:', acc)
最后训练的结果为0.79不是很高,然后我们改一下嵌入层更新词汇,再次训练就会明显高很多。
model.add(Embedding(trainable=True,input_dim=vocalen,output_dim=300,input_length=maxlen))
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

