序贯模型
实现一个简单的与门神经网络。
这段代码为方便读者理解如何处理多分类问题,将二分类问题也作为多分类问题处理。
#coding:utf-8
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
import scipy.io as sio
import numpy as np
import keras
model = Sequential()
model.add(Dense(input_dim=2, units=2))
model.add(Activation('sigmoid'))
model.compile(loss='mean_squared_error', optimizer='sgd', metrics=['accuracy'])
trainDa = np.mat([[1,1],[1,0],[0,1],[0,0]])
trainBl = np.mat([[1],[0],[0],[0]])
testDa = np.mat([[1,1],[1,0],[0,1],[0,0]])
testBl = np.mat([[1],[0],[0],[0]])
one_hot_labels=keras.utils.to_categorical(trainBl,num_classes=2)
print(one_hot_labels)
model.fit(trainDa, one_hot_labels, nb_epoch=1, batch_size=1)
print (model.evaluate(testDa, one_hot_labels,batch_size=1))
#print(model.predict_classes(testDa))
print (model.predict_classes(testDa))
print (model.predict(testDa))
print ('真实标签:\n')
print (testBl)
建立一个序贯模型
model = Sequential()
建立一层神经元
model.add(Dense(input_dim=2, units=2))
其中input_dim指输入的个数,units指这一层神经元的个数
增加激活函数
model.add(Activation('sigmoid'))
对神经网络模型进行编译
model.compile(loss='mean_squared_error', optimizer='sgd', metrics=['accuracy'])
loss指损失函数,optimizer指优化器,metrics指每次迭代打印出相应的准确率
loss函数binary_crossentropy只能用于二分类输出
loss函数categorical_crossentropy只能用于多分类输出
之前因为在情感五元分类中使用binary_crossentropy,结果用model.evaluate函数计算得到的准确率是错的
trainDa = np.mat([[1,1],[1,0],[0,1],[0,0]])
构造训练集中的数据集.
trainBl = np.mat([[1],[0],[0],[0]])
构造训练集的指标集(类别)
这里面有几个坑.
1. 数据集和指标集必须是numpy库中的数据结构,不能是python中的list数据结构.可以用np.mat和np.array将list数据结构转化为numpy中的数据结构
2. 数据集的shape必须是[samples,data],指标集的shape必须是[samples,labels],也就是指标集是一个二维数据,而不是一维的
one_hot_labels=keras.utils.to_categorical(trainBl,num_classes=2)
如果指标集中有多个类别,比方说有n个类别.那么需要将类别编码成one_hot编码.
假设有5个类,one_hot编码指
0编码成1 0 0 0 0
1编码成0 1 0 0 0
2编码成0 0 1 0 0
3编码成0 0 0 1 0
4编码成0 0 0 0 1
所以使用keras.utils.to_categorical的话,如果有n个类,那么trainBl中的类必须已经编码成0,1,2,…n-1;然后通过keras.utils.to_categorical编码成one_hot
除此之外,因为有五个类别,因此神经元的输出个数必须要设置为5.
因为与门有两个类别,所以有两个输出神经元
model.add(Dense(input_dim=2, units=2))
这段代码主要给读者演示如何解决多类别的输出问题。实际上与门是二分类问题,可以直接用一个输出神经元。与门完全可以用
#coding:utf-8
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
import scipy.io as sio
import numpy as np
import keras
model = Sequential()
model.add(Dense(input_dim=2, units=1))
model.add(Activation('sigmoid'))
model.compile(loss='mean_squared_error', optimizer='sgd', metrics=['accuracy'])
trainDa = np.mat([[1,1],[1,0],[0,1],[0,0]])
trainBl = np.mat([[1],[0],[0],[0]])
testDa = np.mat([[1,1],[1,0],[0,1],[0,0]])
testBl = np.mat([[1],[0],[0],[0]])
model.fit(trainDa, trainBl, nb_epoch=1, batch_size=1)
print (model.evaluate(testDa, testBl,batch_size=1))
print (model.predict(testDa))
print (model.predict_classes(testDa))
print ('真实标签:\n')
print (testBl)
即一个神经元输出来解决,但是为了演示多分类是怎么用程序编写的,所以这段代码仍然设置了两个输出。下面是用一个神经元输出的情况。
model.fit(trainDa, one_hot_labels, nb_epoch=1, batch_size=1)
model.fit是训练函数,其中参数 trainDa指训练的数据集;one_hot_labels为one_hot编码过的指标集,nb_epoch指迭代次数
batch_size指小批量梯度下降中每次迭代的批量
print (model.evaluate(testDa, one_hot_labels,batch_size=1))
model.evaluate函数是用来评价测试集的正确率。其中参数testDa指测试集的数据集,one_hot_labels指测试集中经过one_hot编码的指标集
会返回[*,accuracy],accuracy指正确率
print (model.predict_classes(testDa))
model.predict_classes函数用于多分类的对测试集中的数据集的预测。这个函数与keras.utils.to_categorical是配套的
print (model.predict(testDa))
model.predict会返回神经网络中的最后输出。比如本段代码中返回
[[ 0.6909377 0.58852398]
[ 0.47659436 0.53545755]
[ 0.71092319 0.55301178]
[ 0.50041854 0.49926224]]
情感五元分类,lstm
下面的代码用LSTM实现了情感五元分类
其中glove.6b.50d.txt为50维的词向量。也可以用google的word2vector
train_x.txt_temp文件为训练集的数据集
部分内容为:
films about loss , grief and recovery are pretty valuable these days .
a must see for all sides of the political spectrum
it is sentimental but feels free to offend , is analytical and then surrenders to the illogic of its characters , is about grief and yet permits laughter .
train_y.txt_temp文件为训练集中的指标集
部分内容为
4
5
5
其中1,2,3,4,5表示5类情感
下面是完整实现的代码
from keras.models import Sequential
from keras.layers import Dense,Dropout
from keras.layers import LSTM
from keras.layers import Masking
from keras.models import load_model
import keras
import numpy as np
def load_glove():
glove_dict={}
f=open('glove.6B.50d.txt','r')
for line in f:
values=line.split()
word=values[0]
coefs=np.asarray(values[1:],dtype='float32')
glove_dict[word]=coefs
f.close()
print('Found %s word vectors.' % len(glove_dict))
return glove_dict
def load_train(glove_dict):
f=open('train_x.txt_temp','r')
lines=f.readlines()
train_x=[]
max_len=0
for line in lines:
line=line.strip()
line=line.split(' ')
temp=len(line)
if temp>max_len:
max_len=temp
print("最大长度",max_len)
#max_len=100
sentence_num=0
for line in lines:
sentence_num+=1
line=line.strip()
line=line.split(' ')
vector_bag=[]
cur_len=0
for word in line:
cur_len+=1
glove_vector=glove_dict.get(word)
if glove_vector is not None:
vector_bag.append(glove_vector)
else:
vector_bag.append(np.zeros(50))
for i in range(max_len-cur_len):
vector_bag.append(np.zeros(50))
train_x.append(vector_bag)
#print(len(vector_bag))
f.close()
train_y=[]
f=open('train_y.txt_temp','r')
lines=f.readlines()
for line in lines:
line=line.strip()
train_y.append([int(line)-1])
f.close()
return np.array(train_x),np.array(train_y),max_len
train_x,train_y,max_len=load_train(load_glove())
encoding_train_y=keras.utils.to_categorical(train_y,num_classes=5)
#建立神经网络
model=Sequential()
model.add(Masking(mask_value=0,input_shape=(max_len,50)))
model.add(LSTM(100,dropout_W=0.2,dropout_U=0.2,input_shape=(max_len,50)))
model.add(Dense(5,activation='sigmoid'))
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])
#用上面的loss和optimizer会有问题,evaluate是错的,模型训练也是错的
#binary_crossentropy只能用于二分类,categorical_crossentropy只能用于多分类
model.fit(train_x,encoding_train_y,batch_size=16,epochs=50)
'''
score=model.evaluate(train_x,encoding_train_y,batch_size=1)
print(score)
#多分类预测
label=model.predict_classes(train_x,batch_size=3)
#打印多类输出
print(model.predict(train_x,batch_size=3))
print(label)
print(train_y)
'''
#保存模型
model.save('my_model.h5')
分析:
1. LSTM神经网络的输入形式
LSTM神经网络中,输入的训练集data的shape是
[samples,sentence_length,word_vector_length]
也就是说,LSTM的输入的形式是[sentence_length,word_vector_length]
sentence_length指一句话中词的个数
word_vector_length指词的表示的向量的长度
比如说句子 I love you
I单词的向量为[0.5 0.5]
love单词的向量为[0.1 0.8]
you单词的向量为[0.2 0.7]
则[[0.5 0.5],[0.1 0.8],[0.2 0.7]]构成句子I love you的numpy数组形式.其中shape为[sentence_length,word_vector_length]
2. 五类输出的编码形式
因为是五元情感分类。所以有五类
首先将类别1到5编码为0,1,2,3,4
然后用
encoding_train_y=keras.utils.to_categorical(train_y,num_classes=5)
编码成one_hot形式
注意神经网络中要有5个输出神经元
model.add(Dense(5,activation='sigmoid'))
3. loss函数
loss函数binary_crossentropy只能用于二分类输出
loss函数categorical_crossentropy只能用于多分类输出
之前因为在情感五元分类中使用binary_crossentropy,结果用model.evaluate函数计算得到的准确率是错的
4. LSTM如何处理变长(不定长)的输入
每个句子的长度可能完全不一样。LSTM本身可以接受变长的输入。但是在设计神经元的时候输入神经元的个数显然要一致。
所以首先要把每个句子的长度变得一样。用0补齐。比如
发现训练集中最长的句子长度为4
句子I love you的句数组
[[0.5 0.5],[0.1 0.8],[0.2 0.7]]
变成[[0.5 0.5],[0.1 0.8],[0.2 0.7],[0,0,0,0]]
这样句子的长度就一样了
然后在LSTM网络面前加入一层Masking层
model.add(Masking(mask_value=0,input_shape=(max_len,50)))
mask_value指过滤的输入,input_shape指输入的shape,也就是[sentence_length,word_vector_length]
通过设置mask_value可以把0的输入过滤掉
然后再连接上LSTM,就可以实现变长的LSTM输入
model.add(LSTM(100,dropout_W=0.2,dropout_U=0.2,input_shape=(max_len,50)))
embedding层详解
见 http://blog.csdn.net/jiangpeng59/article/details/77533309
参考
keras中文文档
http://keras-cn.readthedocs.io/en/latest/
一个非常棒的在线中文keras教程
https://cnbeining.github.io/deep-learning-with-python-cn/
Keras 实现 LSTM
http://www.jianshu.com/p/795a5e2cd10c
Keras学习之一:文本与序列预处理
http://blog.csdn.net/zzulp/article/details/76146947