循环神经网络与LSTM网络

循环神经网络RNN

循环神经网络广泛地应用在序列数据上面,如自然语言,语音和其他的序列数据上。序列数据是有很强的次序关系,比如自然语言。通过深度学习关于序列数据的算法要比两年前的算法有了很大的提升。由此诞生了很多有趣的应用,比如语音识别,音乐合成,聊天机器人,机器翻译,自然语言理解和其他的一些应用。

符号说明:

上标[l]: 表示第层,例如,例如是第四层的激活元。和是层参数

上标(i):表示第i个样本,例如表示第训练样本输入

上标<t>:表示第个时间戳,例如是输入x在第的时间戳。是样本i

个时间戳

下标i:表示向量中的第项。例如表示激活元在l层中的第项

循环神经网络的基本结构如下:

简单的说明,x就是我们输入的序列数据,如果让每一个表示一个字符的话,单词hello,就会有四个输入,分别表示h,e,l,l,o。y是我们的输出数据,我们希望通过获得的下一个字符。在这个例子中是hello的第一个字符h,的下一个字符为e,因此我们希望为e。

循环神经网络的输入:(h,e,l,l,o)

循环神经网络的输出:(根据实际的输出情况)

输出正确的标签:(e,l,l,o, )

其中为隐变量记录之前的状态信息用来计算下一个,以及

图中的每个RNN-cell结构都是相同的(所有的参数也一样)。因此上图中的循环神经网络也可以表示成如下的形式

该模型有点像隐马尔可夫模型,每一个预测结果只依赖与前一个节点的信息,而与无关。

对于每一个RNN-cell的内容如下:

这是基本的RNN单元,通过当前的输入和(之前的隐藏状态包含了过去的信息)进行计算获得预测的下一个字符以及来给下一层RNN单元计算。

代价函数的计算

要对整个前向传播中产生的预测结果y都要用来计算代价代价函数。代价函数可以使用上次提到的交叉熵来计算。将预测结果与输出的正确标签做交叉熵。

由于给出了RNN-cell的结果因此循环神经网络可以进行前向传播了。由于现在的深度学习框架比如tensorflow等很方便,只要定义好前向传播的过程,以及代价函数,框架就会帮你进行反向传播计算。

如果不用tensorflow框架进行神经网络搭建这里还是给出了循环神经网络的反向传播计算公式(注:如果求导过于复杂可以通过Calculus软件进行求导的计算,该软件会给出具体的求导过程)

对于训练好的模型进行采样

还是以上面的例子为例,在采样的过程中用户输入第一个字符='h',循环神经网络根据'h'预测'h'的下一个字符最大概率为'e',把预测的字符'e'作为下一个输入以此循环递归。关于何时结束,我们可以指定定长的字符生成后结束。注意:在大样本的训练中,为了保证结果的多样性,我们一般不直接选择预测最大的字符作为下一个输入字符,而是在预测的结果序列进行概率采样,或者随机采样。

LSTM(长短时记忆网络)

上文中已经提到了可以对序列模型进行训练,以及采样。但是由于循环神经网络层数过多,存在梯度消失的问题。该问题直接导致的效果如下。假设有下面两个句子用来训练

"The cat, which already ate……,was full"

"The cats, which already ate……,were full"

逗号表示由很多个单词。

我们需要学习当出现cat的时候需要使用was,当出现cats的时候需要使用were。由于梯度消失的问题,理论上循环神经网络是无法学习这种具有长时间依赖关系的词性变化。由此引入了LSTM(长短时记忆网络)。

LSTM的整体结构和RNN很像都是循环递归的,只是将RNN-cell替换成LSTM-cell。LSTM-cell的表示如下

:Forget gate(忘记门),在这个例子中让我们假设每次的输入都是一个单词,我们希望LSTM保持语法结构,例如主语是单数还是复数。如果主语从单数变为复数,我们需要找到一种方法来避免之前存储的关于单数和复数的状态。在LSTM中,Forget gate让我们做这件事情。

上面式子的计算结果在0到1之间。Forget gate向量会和之前cell的状态相乘,如果值为0(或者接近0)那么它意味着LSTM应该移除之前的状态信息(例如,主语是单数),如果是1,那么应该保持该信息。

:Update gate(更新门),一旦我们忘记了主语是单数,我们需要一种方式来说更新它来反应新的主语是复数。下面是更新门的表达式:

更新门会和相乘,来计算

为了计算新的主语,我们需要创建一个新的向量可以用来增加先前的cell状态。表达式如下:

最后信息的cell状态如下:

:Outputs gate(输出门),用来控制输出结果

将每一个LSTM-cell连接起来就构成了LSTM的前向传播了

在tensorflow中根据该网络结构就可以构造出前向传播的算法,进行计算了。下面会给出LSTM的代码。

如果不用tensorflow进行计算,这里简单的给出LSTM的反向传播公式:

gate derivatives

Parameter derivatives

previous hidden state, previous memory state, and input

#导入相应的包
from __future__ import print_function
import os
import numpy as np
import random
import string
import tensorflow as tf
import zipfile
from six.moves import range
from six.moves.urllib.request import urlretrieve #读取莎士比亚的文本文件
path = "./shakespeare" #文件夹目录
files= os.listdir(path) #得到文件夹下的所有文件名称
text =""
for file in files: #遍历文件夹
if not os.path.isdir(file): #判断是否是文件夹,不是文件夹才打开
f = open(path+"/"+file,'r'); #打开文件
iter_f = iter(f); #创建迭代器
str = ""
for line in iter_f: #遍历文件,一行行遍历,读取文本
str = str + line
text+=str #每个文件的文本存到list中 print('Data size %d' % len(text)) #将莎士比亚文本中出现的所有字符做成字典并编号
vocab = set(text) vocab_to_int = {c: i for i, c in enumerate(vocab)}
int_to_vocab = dict(enumerate(vocab)) #构造测试集和训练集
valid_size = 1000
valid_text = text[:valid_size]
train_text = text[valid_size:]
train_size = len(train_text)
print(train_size, train_text[:64])
print(valid_size, valid_text[:64]) vocabulary_size =len(set(text)) batch_size = 64
num_unrollings = 10 #训练用的Batch生成器
class BatchGenerator(object):
def __init__(self, text, batch_size, num_unrollings):
self._text = text
self._text_size = len(text)
self._batch_size = batch_size
self._num_unrollings = num_unrollings
segment = self._text_size // batch_size
self._cursor = [offset * segment for offset in range(batch_size)]
self._last_batch = self._next_batch() def _next_batch(self):
"""Generate a single batch from the current cursor position in the data."""
batch = np.zeros(shape=(self._batch_size, vocabulary_size), dtype=np.float)
for b in range(self._batch_size):
#batch[b, char2id(self._text[self._cursor[b]])] = 1.0
batch[b, vocab_to_int[self._text[self._cursor[b]]]] = 1.0
self._cursor[b] = (self._cursor[b] + 1) % self._text_size
return batch def next(self):
"""Generate the next array of batches from the data. The array consists of
the last batch of the previous array, followed by num_unrollings new ones.
"""
batches = [self._last_batch]
for step in range(self._num_unrollings):
batches.append(self._next_batch())
self._last_batch = batches[-1]
return batches #将概率分布转化为1-hot形式
def characters(probabilities):
"""Turn a 1-hot encoding or a probability distribution over the possible
characters back into its (most likely) character representation."""
#return [id2char(c) for c in np.argmax(probabilities, 1)]
temp=np.argmax(probabilities,1)
return [int_to_vocab[c] for c in np.argmax(probabilities, 1)] #将batches转化成字符串
def batches2string(batches):
"""Convert a sequence of batches back into their (most likely) string
representation."""
s = [''] * batches[0].shape[0]
for b in batches:
s = [''.join(x) for x in zip(s, characters(b))]
return s train_batches = BatchGenerator(train_text, batch_size, num_unrollings)
valid_batches = BatchGenerator(valid_text, 1, 1) print(batches2string(train_batches.next()))
print(batches2string(train_batches.next()))
print(batches2string(valid_batches.next()))
print(batches2string(valid_batches.next())) def logprob(predictions, labels):
"""Log-probability of the true labels in a predicted batch."""
predictions[predictions < 1e-10] = 1e-10
return np.sum(np.multiply(labels, -np.log(predictions))) / labels.shape[0] #采样相关的函数,用于字符的生成
def sample_distribution(distribution):
"""Sample one element from a distribution assumed to be an array of normalized
probabilities.
"""
r = random.uniform(0, 1)
s = 0
for i in range(len(distribution)):
s += distribution[i]
if s >= r:
return i
return len(distribution) - 1 def sample(prediction):
"""Turn a (column) prediction into 1-hot encoded samples."""
p = np.zeros(shape=[1, vocabulary_size], dtype=np.float)
p[0, sample_distribution(prediction[0])] = 1.0
return p def random_distribution():
"""Generate a random column of probabilities."""
b = np.random.uniform(0.0, 1.0, size=[1, vocabulary_size])
tmp=np.sum(b,1)
tmp1=np.sum(b,1)[:None]
return b/np.sum(b, 1)[:,None] num_nodes = 64
#构造LSTM
graph = tf.Graph()
with graph.as_default():
# Parameters:
# Input gate: input, previous output, and bias.
ix = tf.Variable(tf.truncated_normal([vocabulary_size, num_nodes], -0.1, 0.1))
im = tf.Variable(tf.truncated_normal([num_nodes, num_nodes], -0.1, 0.1))
ib = tf.Variable(tf.zeros([1, num_nodes]))
# Forget gate: input, previous output, and bias.
fx = tf.Variable(tf.truncated_normal([vocabulary_size, num_nodes], -0.1, 0.1))
fm = tf.Variable(tf.truncated_normal([num_nodes, num_nodes], -0.1, 0.1))
fb = tf.Variable(tf.zeros([1, num_nodes]))
# Memory cell: input, state and bias.
cx = tf.Variable(tf.truncated_normal([vocabulary_size, num_nodes], -0.1, 0.1))
cm = tf.Variable(tf.truncated_normal([num_nodes, num_nodes], -0.1, 0.1))
cb = tf.Variable(tf.zeros([1, num_nodes]))
# Output gate: input, previous output, and bias.
ox = tf.Variable(tf.truncated_normal([vocabulary_size, num_nodes], -0.1, 0.1))
om = tf.Variable(tf.truncated_normal([num_nodes, num_nodes], -0.1, 0.1))
ob = tf.Variable(tf.zeros([1, num_nodes]))
# Variables saving state across unrollings.
saved_output = tf.Variable(tf.zeros([batch_size, num_nodes]), trainable=False)
saved_state = tf.Variable(tf.zeros([batch_size, num_nodes]), trainable=False)
# Classifier weights and biases.
w = tf.Variable(tf.truncated_normal([num_nodes, vocabulary_size], -0.1, 0.1))
b = tf.Variable(tf.zeros([vocabulary_size])) # Definition of the cell computation.
def lstm_cell(i, o, state):
"""Create a LSTM cell. See e.g.: http://arxiv.org/pdf/1402.1128v1.pdf
Note that in this formulation, we omit the various connections between the
previous state and the gates."""
input_gate = tf.sigmoid(tf.matmul(i, ix) + tf.matmul(o, im) + ib)
forget_gate = tf.sigmoid(tf.matmul(i, fx) + tf.matmul(o, fm) + fb)
update = tf.matmul(i, cx) + tf.matmul(o, cm) + cb
state = forget_gate * state + input_gate * tf.tanh(update)
output_gate = tf.sigmoid(tf.matmul(i, ox) + tf.matmul(o, om) + ob)
return output_gate * tf.tanh(state), state # Input data.
train_data = list()
for _ in range(num_unrollings + 1):
train_data.append(
tf.placeholder(tf.float32, shape=[batch_size, vocabulary_size]))
train_inputs = train_data[:num_unrollings]
train_labels = train_data[1:] # labels are inputs shifted by one time step. # Unrolled LSTM loop.
outputs = list()
output = saved_output
state = saved_state
for i in train_inputs:
output, state = lstm_cell(i, output, state)
outputs.append(output) # State saving across unrollings.
with tf.control_dependencies([saved_output.assign(output),
saved_state.assign(state)]):
# Classifier.
# The Classifier will only run after saved_output and saved_state were assigned.
logits = tf.nn.xw_plus_b(tf.concat(outputs, 0), w, b)
loss = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(
logits=logits, labels=tf.concat(train_labels, 0))) # Optimizer.
global_step = tf.Variable(0)
learning_rate = tf.train.exponential_decay(
10.0, global_step, 5000, 0.1, staircase=True)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
gradients, v = zip(*optimizer.compute_gradients(loss))
gradients, _ = tf.clip_by_global_norm(gradients, 1.25)
optimizer = optimizer.apply_gradients(
zip(gradients, v), global_step=global_step) # Predictions.
train_prediction = tf.nn.softmax(logits) # Sampling and validation eval: batch 1, no unrolling.
sample_input = tf.placeholder(tf.float32, shape=[1, vocabulary_size])
saved_sample_output = tf.Variable(tf.zeros([1, num_nodes]))
saved_sample_state = tf.Variable(tf.zeros([1, num_nodes]))
reset_sample_state = tf.group(
saved_sample_output.assign(tf.zeros([1, num_nodes])),
saved_sample_state.assign(tf.zeros([1, num_nodes])))
sample_output, sample_state = lstm_cell(
sample_input, saved_sample_output, saved_sample_state)
with tf.control_dependencies([saved_sample_output.assign(sample_output),
saved_sample_state.assign(sample_state)]):
sample_prediction = tf.nn.softmax(tf.nn.xw_plus_b(sample_output, w, b))
saver = tf.train.Saver() num_steps = 37001
summary_frequency = 100 #saver = tf.train.Saver(var_list=[ib])
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
print('Initialized')
mean_loss = 0
for step in range(num_steps):
batches = train_batches.next()
feed_dict = dict()
# Add training data from batches to corresponding train_data position in the feed_dict
for i in range(num_unrollings + 1):
feed_dict[train_data[i]] = batches[i]
# Train the model
_, l, predictions, lr = session.run(
[optimizer, loss, train_prediction, learning_rate], feed_dict=feed_dict)
mean_loss += l if step % summary_frequency == 0:
if step > 0:
mean_loss = mean_loss / summary_frequency
# The mean loss is an estimate of the loss over the last few batches.
print(
'Average loss at step %d: %f learning rate: %f' % (step, mean_loss, lr))
mean_loss = 0
labels = np.concatenate(list(batches)[1:])
print('Minibatch perplexity: %.2f' % float(
np.exp(logprob(predictions, labels))))
if step % (summary_frequency * 10) == 0:
# Generate some samples.
print('=' * 80)
for _ in range(5):
feed = sample(random_distribution())
tmp=characters(feed)
sentence = characters(feed)[0]
reset_sample_state.run()
for _ in range(1379):
prediction = sample_prediction.eval({sample_input: feed})
feed = sample(prediction)
#feed = np.zeros(shape=[1, vocabulary_size], dtype=np.float)
#feed[0, vocab_to_int[characters(prediction)[0]]] = 1.0
sentence += characters(prediction)[0]
print(sentence)
# Measure validation set perplexity.
reset_sample_state.run()
valid_logprob = 0
for _ in range(valid_size):
b = valid_batches.next()
predictions = sample_prediction.eval({sample_input: b[0]})
valid_logprob = valid_logprob + logprob(predictions, b[1])
print('Validation set perplexity: %.2f' % float(np.exp(
valid_logprob / valid_size)))

实验结果:

在阿里云中的服务器中跑1h的结果为

Iivind to  sh te  no sh bnt if tete t segsunsed mrovd  of teauty sormw And ttmdi n,

Aut teatme

Tr whene tn toer tone tf tftwaas srmtoundsng miser  and to e stnce whrks  anl the r sfer s  aar thoarered

Tnd tore toaet oned

Th thol'nte miye thle theu h the seert

And stael soar,

Then trewgd then sirt  thauld ttyle oegg, trwroun hhe weaath

Ahve tou  sere nles thet ts teailesTour noy th mtye Autt  ther ihere ore tavh trr h st tavh tyes

And tese,tove a dot su g,sart,

可以看出来它已经学会了部分单词,以及分段了

在阿里云中的服务器中跑3h的结果为:

L

Thosethet tn the sime tirte orove , Ao tolb tn the srlt shen t antrtn,

wo myst n st

Aut tune eye ds tocjenedtitl be tot ing mh trne

7

To ivesi soi teat uent temieeksand tvteem,oolrh  oeintitn the sear frel d snd mfe

Tided itml r tnpge taovang snuie tor trrg r ios morld ty  Ay ledd, o sii e thi ift tfrerlewe  aow that toar f beathed wea

Tnd tincle silh tuape the saerher of   atne tor mhes ht

Thet teve sn tour siic m'hle teseishne  tn ty hlay ahat tldyn t coture tor my sene,

它已经初步知道可以给段落打标签了,如上面出现的7

[Tā yǐjīng chūbù zhīdào kěyǐ gěi duànluò dǎ biāoqiānle, rú shàngmiàn chūxiàn de]

It has initially known that it can label paragraphs, as shown above.

 
 
 
 
 
 

循环神经网络与LSTM网络的更多相关文章

  1. 循环神经网络之LSTM和GRU

    看了一些LSTM的博客,都推荐看colah写的博客<Understanding LSTM Networks> 来学习LSTM,我也找来看了,写得还是比较好懂的,它把LSTM的工作流程从输入 ...

  2. 循环神经网络(LSTM和GRU)(1)

    循环神经网络的简单实现: import tensorflow as tf x=[1,2] state=[0.0,0.0] w_cell_state=np.array([[0.1,0.2],[0.3,0 ...

  3. 【神经网络】LSTM 网络

      Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息.LSTM 由Hochreiter & Schmidhuber (199 ...

  4. 循环神经网络(LSTM和GRU)(2)

    1.tf.nn.dynamic_rnn()函数 参考:http://www.360doc.com/content/17/0321/10/10408243_638692495.shtml 参考:http ...

  5. 通过keras例子理解LSTM 循环神经网络(RNN)

    博文的翻译和实践: Understanding Stateful LSTM Recurrent Neural Networks in Python with Keras 正文 一个强大而流行的循环神经 ...

  6. 十 | 门控循环神经网络LSTM与GRU(附python演练)

    欢迎大家关注我们的网站和系列教程:http://panchuang.net/ ,学习更多的机器学习.深度学习的知识! 目录: 门控循环神经网络简介 长短期记忆网络(LSTM) 门控制循环单元(GRU) ...

  7. Recurrent Neural Network系列1--RNN(循环神经网络)概述

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...

  8. Recurrent Neural Networks(RNN) 循环神经网络初探

    1. 针对机器学习/深度神经网络“记忆能力”的讨论 0x1:数据规律的本质是能代表此类数据的通用模式 - 数据挖掘的本质是在进行模式提取 数据的本质是存储信息的介质,而模式(pattern)是信息的一 ...

  9. 【学习笔记】循环神经网络(RNN)

    前言 多方寻找视频于博客.学习笔记,依然不能完全熟悉RNN,因此决定还是回到书本(<神经网络与深度学习>第六章),一点点把啃下来,因为这一章对于整个NLP学习十分重要,我想打好基础. 当然 ...

随机推荐

  1. CSS3在hover下的几种效果

    CSS3在hover下的几种效果代码分享,CSS3在鼠标经过时的几种效果集锦 效果一:360°旋转 修改rotate(旋转度数) * { transition:All 0.4s ease-in-out ...

  2. VUE注意事项(建项目)

    1>删除空格影响的:删除掉框中的代码 2>不需要新建,直接打开APP.vue,在此文件上进行修改,(注意:index.html最好不要进行修改) 3>修改APP.vue为自己需要的页 ...

  3. hihocoder1822 战舰日常任务

    思路: 使用堆即可. 实现: #include <iostream> #include <map> #include <vector> #include <c ...

  4. IOS自动化测试之UIAutomation

    通过Xcode工具编写运行测试脚本 1.当你有了一个应用的源代码之后,在Xcode工具中,首先选中被测应用,然后点击菜单栏中的“Product-Profile”,则会弹出Instruments工具,在 ...

  5. Ubuntu下Postgres安装与配置

    postgres8.4安装配置:1.安装postgres8.4~$ sudo apt-get install postgresql 2.修改超级管理员postgres密码:以系统用户运行psql~$ ...

  6. 洛谷 2299 Mzc和体委的争夺战

    题目背景 mzc与djn第四弹. 题目描述 mzc家很有钱(开玩笑),他家有n个男家丁(做过前三弹的都知道).但如此之多的男家丁吸引来了我们的体委(矮胖小伙),他要来与mzc争夺男家丁. mzc很生气 ...

  7. JavaScript中valueOf函数与toString方法

    基本上,所有JS数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下   JavaScrip ...

  8. 将回车键转换为Tab键

    实现效果: 知识运用: KeyEventArgs类的KeyValue属性 public int KeyValue {get;} //获取KeyDown或KeyUp事件的键盘值 SendKeys类的Se ...

  9. 79 最长公共子串 (lintcode)

    f[i][j]表示的是以第i个结尾和第j个结尾 class Solution { public: /* * @param A: A string * @param B: A string * @ret ...

  10. 四、绘图可视化之Seaborn

    Seaborn-Powerful Matplotlib Extension seaborn实现直方图和密度图 import numpy as np import pandas as pd import ...