【参考资料】
【1】《面向机器智能的tensorflow实践》
【2】Keras中文文档
【3】https://zybuluo.com/hanbingtao/note/541458
基础循环神经网络
循环神经网络(RNN)是一个由神经元和权值构成的有向图,它的当前状态与前一时刻的状态和当前输入决定,因此当前状态也被称为工作记忆。循环神经网络在时间序列上展开后如上图所示,用于解决序列化的问题,诸如语音识别、语音合成、文本生成。
例子:利用RNN写诗,本质上是在训练后得到各个词语的使用频次和关联规则,RNN可以知道在“秋”后面跟“月”“风”具有更大概率。但它并不知道它所写的含义,从这个角度将写诗其实是简单的。RNN可以做到“吟诗一首”,而做不到“此情此景,我要吟诗一首”:)
模型推导如下
当前输入 + 之前的状态
因此根据上下式不断的迭代可得到下一时刻
双向循环神经网络
在部分模型中光靠前文的推测还不够,可能还需要后文的信息反过来判断。
例如我的手机坏了,我打算___新手机。这里空格里利用新手机就很容易推测应该为买的可能性更大。
在双向循环神经网络中输出同时取决于和
模型推导如下
//差别在这里,通过后文反推
BPTT训练方法
TBD
RNN代码例子(keras,参考网上部分代码)
# -*- coding: utf-8 -*-
"""
说明:
RNN代码DEMO,对应的笔记《19.神经网络(RNN)》
作者:fredric
日期:2018-9-22
"""
from keras.layers import Dense,Activation
from keras.layers.recurrent import SimpleRNN
from keras.models import Sequential
from keras.optimizers import Adam
import numpy as np
### 加载数据
### Test.java是随便Java项目里找的一批代码合并到一个文件里
fin=open('./data/Test.java','rb')
lines=[]
for line in fin:
line=line.strip().lower()
line=line.decode('ascii','ignore')
if len(line)==0:
continue
lines.append(line)
fin.close()
text=' '.join(lines)
"""
对样本Test.java中的所有字符生成字典索引,包括:
char2index: '}': 0, 't': 1, 'k': 2 等
index2char: 0: '}', 1: 't', 2: 'k' 等
"""
chars=set([c for c in text])
nb_chars=len(chars)
char2index=dict((c,i) for i,c in enumerate(chars))
index2char=dict((i,c) for i,c in enumerate(chars))
SEQLEN=10
STEP=1
input_chars=[]
label_chars=[]
"""
不段以SEQLEN为长度,STEP为偏移生成input_chars和label_chars
举例:
以原文件代码package com.fredric为例子,生成
input_chars[0]: package co label_chars[0]: m
label_chars[1]: ackage com label_chars[0]: .
"""
for i in range(0,len(text)-SEQLEN,STEP):
input_chars.append(text[i:i+SEQLEN])
label_chars.append(text[i+SEQLEN])
"""
这里将输入向量利用char2index做了一个变换,例如:
第一个输入的label输出m,则对应字典中的 9: 'm',因此此时的y值为:
[False False False False False False False False False True False False
False False False False False False False False False False False False
False False False False False False False False False False False False
False False False False False False False False False False False False
False]
同理x的值也被做了上述的变换,重要: 相当于所有的输入被做了统一的编码
"""
X=np.zeros((len(input_chars),SEQLEN,nb_chars),dtype=np.bool)
y=np.zeros((len(input_chars),nb_chars),dtype=np.bool)
for i,input_char in enumerate(input_chars):
for j,ch in enumerate(input_char):
X[i,j,char2index[ch]]=1
y[i,char2index[label_chars[i]]]=1
### 创建RNN网络
HIDDEN_SIZE = 128
BATCH_SIZE = 128
TRAIN_STEP = 500
model=Sequential()
model.add(SimpleRNN(HIDDEN_SIZE,return_sequences=False,input_shape=(SEQLEN,nb_chars), unroll=True))
model.add(Dense(nb_chars,activation='softmax'))
adam = Adam(0.001)
model.compile(loss='categorical_crossentropy',optimizer=adam)
### 进行训练
for step in range(TRAIN_STEP):
print("current step is #: %d"%(step))
model.fit(X,y, batch_size=BATCH_SIZE, epochs=1)
### 对输入字符串进行预测
_test_input = 'public cla'
_test_chars=set([t for t in _test_input])
_test=np.zeros((1, SEQLEN, nb_chars))
for i,ch in enumerate(_test_chars):
_test[0,i,char2index[ch]]=1
pred=model.predict(_test,verbose=0)[0]
ypred=index2char[np.argmax(pred)]
## 输出结果是the test input public cla get prediction i,貌似不好
print("the test input %s get prediction %s"%(_test_input, ypred))