前馈神经网络只能单独处理一个个的输入,前一个输入与后一个输入之间没有任何关系,若是碰到须要处理输入之间关系的数据,它们将没法正确的预测输入值,好比下列样例:算法
球的轨迹(移动过程点的集合)数据库
天然语言处理数组
我吃苹果
,想要预测它的语义,那么它会被拆成一个个词输入模型苹果吃我
、苹我吃果
和我吃苹果
是彻底不一样的语义针对上述须要须要按照顺序处理的数据,在原有全链接神经网络的基础上添加了一个时间轴的概念,即诞生了循环神经网络(RNN)网络
循环神经网络(RNN)是一类用于处理序列数据的神经网络。RNN拥有记忆模块,能够获取以及计算过的信息,记住执行的顺序。即便是一样的输入,若是输入的顺序不一样也会产生不一样的输出。架构
神经网络的结构分为输入层、隐藏层、输出层。输入与输出层是处理数据的输入输出的;而隐藏层则对数据进行计算、预测处理。前馈网络与循环网络(RNN)的主要区别就是在隐藏层。 app
前馈网络的隐藏层,若是只有一个神经元,则直接处理;若是有多个神经元,每一个神经元都单独运行,互不相关,没有任何顺序、引用、传值的关系。 机器学习
而RNN的结构则是在前馈网络隐藏层上添加了时间轴的概念,让每个单元都按照输入的顺序进行处理,上一个处理的输出做为下一个处理的输入与当前的输入一块儿计算,综合前几个输入的计算结果与当前输入一块儿进行预测。 函数
这种形式一是只在序列开始把输入信息输入模型计算(左);二是把输入信息做为每一个阶段的输入(右),这种结构能够处理如: 输入图像的特征,输出y的序列是一段句子或者从别的类别生成语音;输入一个类别,输出一段描述文字这类问题。 学习
输入的是一个序列,输出的是一个单独的值。这种结构经常使用于处理分类问题,如:输入一段文字判断类别、输入句子判断感情倾向、输入图片判断类别。 测试
输入和输出序列是等长的。这种能够做为简单的Char RNN能够用来生成文章,诗歌,甚至是代码。
这种结构又称Encoder-Decoder、Seq2Seq模型,它会将输入数据编码成一个上下文向量c,以后经过c输出预测序列。它普遍应用于机器翻译、文本摘要、阅读理解、对话生成等领域。
实现RNN的第一步须要准备数据集,下列是对图像进行分类的数据处理格式
(x_train, y_train) = dealImage()
# 处理数据格式,将图片数据x转化到-1到1之间(除以像素点最大值255),提升精确度
x_train = x_train.reshape(x_train.shape[0], 56, -1).astype('float') / 255.0
# 转换labels为one hot格式
y_train = np_utils.to_categorical(y_train, num_classes=num_classes)
# 一样的方法加载测试数据
(x_test, y_test) = dealTestImage()
复制代码
# deal.py 处理图片分类时的数据预处理,读取图片数据和对应类别
def dealImage():
result = [(src, label)....] # 路径和类别的对应关系能够保存到本地文件或者数据库中,须要使用的时候在读取
images = []
labels = []
for row in result:
imsrc = cv2.imread(row[0], 0)
im = cv2.resize(imsrc, (56, 56), interpolation=cv2.INTER_AREA) # 转换数据格式(按本身须要的格式转换)
imgData = np.array(im) # numpy array化
images.append(imgData)
labels.append(row[1])
images = np.array(images)
labels = np.array(labels)
return (images, labels)
复制代码
根据前向传播算法的理论,搭建RNN神经网络,选择恰当的神经网络的层数、神经元数目
# 建立模型,当前模型比较简单无复杂的结构,使用顺序模型便可
model = Sequential()
cell_size = 300
复制代码
SimpleRNN
之间必须设置return_sequences=True
(默认是False
)softmax
、Softplus
、Relu
、tanh
、sigmod
、hard_sigmoid
、linear
SimpleRNN
适合使用tanh
函数,输出Dense
层适合采用softmax
进行分类# 循环神经网络
model.add(SimpleRNN(
units=cell_size, # 输出数据的维度(当前层神经元的数目)
activation='tanh', # 激活函数,默认即tanh
return_sequences=True,
input_shape=(56, 56) # 输入数据的维度(shape)
))
model.add(SimpleRNN(units=cell_size, return_sequences=True))
model.add(SimpleRNN(units=cell_size, return_sequences=True))
# 每层SimpleRNN之间必须设置return_sequences=True(默认是False)
# return_sequences 是返回输出序列的最后一个输出(False),仍是返回所有序列(True)
# return_sequences=True 表示咱们须要完整的编码序列,而不只仅是最终总结状态
# return_sequences=True 返回的是个多维数组,若是下一层没法接收该种多维数组,则层须要设置为return_sequences=True或者不设置取默认值
model.add(SimpleRNN(units=cell_size))
# 添加全链接层做为输出层
model.add(Dense(num_classes, activation='softmax'))
复制代码
使用反向传播算法迭代训练模型,根据每次训练结果优化参数后再次训练直到获得能尽量好的预测结果的模型
反向传播算法tensorflow与keras都有封装,直接调用方法便可
SGD
、Adagrad
、RMSprop
、Adam
Adam
算法mse
、mae
、mape
、msle
、hinge
、categorical_crossentropy
等等categorical_crossentropy
函数# 初始化优化器
adam = Adam(lr=1e-4)
# 定义优化器,loss function,训练过程当中计算准确率
model.compile(
optimizer=adam, # 优化器
loss='categorical_crossentropy', # 损失函数 mse 均方差 categorical_crossentropy 交叉熵(多分类)
metrics=['accuracy'] # 训练和测试期间的模型评估标准
)
复制代码
# 开始训练模型,调用model.fit()方法,方法采用时序后向传播算法训练模型
# 以给的数目的轮次训练模型,到第epochs轮结束训练,每轮多个批次,每批次大小batch_size
model.fit(x_train, y_train, batch_size=32, epochs=20)
# 预测模型的损失值和准确率
loss, accuracy = model.evaluate(x_test, y_test)
# 保存模型,以便使用时加载
model.save('myfile/rnn.hdf5')
复制代码
训练结果
加载已保存的模型,输入待预测的,输出最可能的结果
# 加载模型
model = load_model('myfile/rnn.hdf5')
# 使用模型预测结果
pred = model.predict(data) # data 是numpy的array格式
# 取出可能性最大的值做为预测结果
print([final.argmax() for final in pred])
复制代码
在处理序列信息时,有时咱们不只须要以前的信息,还须要以后的信息,好比:预测我__苹果
这句话所缺失的词是什么,咱们就须要根据上下文的词汇一块儿去预测。而Bi-RNN能很好的解决这个问题,它是一个由两个RNN上下叠加在一块儿组成的相对较简单的RNN。所以,它的输出由前向RNN和后向RNN共同决定,它当前时刻输出(第t步的输出)不只仅与以前序列有关,还与以后序列有关。
SRNN是在全链接的单层循环神经网络的基础上堆叠造成的深度算法。该网络具备更强大的表达与学习能力,可是复杂性也随之提升,同时须要更多的训练数据。
RNN在处理长期依赖(时间序列上距离较远的节点)时会遇到巨大的困难,由于计算距离较远的节点之间的联系时会涉及雅可比矩阵的屡次相乘,会形成梯度消失或者梯度膨胀的现象。 LSTM就是一种为了解决长期依赖问题而提出的特殊RNN,所以,记住长时间的信息是它的基本功能
GRU能够当作是LSTM的变种,GRU把LSTM中的遗忘门和输入们用更新门来替代。 把cell state和隐状态ht进行合并,在计算当前时刻新信息的方法和LSTM有所不一样。GRU的构造更简单,在训练数据大的状况下能节省更多时间