RNN入门
原文地址:http://blog.csdn.net/hjimce/article/details/49095371
作者:hjimce
一、相关理论
RNN(Recurrent Neural Networks)中文名又称之为:循环神经网络(原来还有一个递归神经网络,也叫RNN,搞得我有点混了,菜鸟刚入门,对不上号)。在计算机视觉里面用的比较少,我目前看过很多篇计算机视觉领域的相关深度学习的文章,除了OCR、图片标注、理解问答等这些会把CNN和RNN结合起来,其它的很少见到。RNN主要用于序列问题,如自然语言、语音音频等领域,相比于CNN来说,简单很多,CNN包含:卷积层、池化层、全连接层、特征图等概念,RNN基本上就仅仅只是三个公式就可以搞定了,因此对于RNN我们只需要知道三个公式就可以理解RNN了。说实话,一开是听到循环神经网络这个名子,感觉好难的样子,因为曾经刚开始学CNN的时候,也有很多不懂的地方。还是不啰嗦了,……开始前,我们先回顾一下,简单的MLP三层神经网络模型:
简单MLP模型
上面那个图是最简单的浅层网络模型了,x为输入,s为隐藏层神经元,o为输出层神经元。然后U、V就是我们要学习的参数了。上面的图很简单,每层神经元的个数就只有一个,我们可以得到如下公式:
(1)隐藏层神经元的激活值为:
s=f(u*x+b1)
(2)然后输出层的激活值为:
o=f(v*s+b2)
这就是最简单的三层神经网络模型的计算公式了,如果对上面的公式,还不熟悉,建议还是看看神经网络的书,打好基础先。而其实RNN网络结构图,仅仅是在上面的模型上,加了一条连接线而已,RNN结构图:
RNN结构图
看到结构图,是不是觉得RNN网络好像很简单的样子,至少没有像CNN过程那么长。从上面的结构图看,RNN网络基础结构,就只有一个输入层、隐藏层、输出层,看起来好像跟传统浅层神经网络模型差不多(只包含输出层、隐藏层、输出层),唯一的区别是:上面隐藏层多了一天连接线,像圆圈一样的东东,而那条线就是所谓的循环递归,同时那个圈圈连接线也多了个一个参数W。还是先看一下RNN的展开图,比较容易理解:
我们直接看,上面展开图中,Ot的计算流程,看到隐藏层神经元st的输入包含了两个:来时xt的输入、来自st-1的输入。于是RNN,t时刻的计算公式如下:
(1)t时刻,隐藏层神经元的激活值为:
st=f(u*xt+w*st-1+b1)
(2)t时刻,输出层的激活值为:
ot=f(v*st+b2)
是不是感觉上面的公式,跟一开始给出的MLP,公式上就差那么一点点。仅仅只是上面的st计算的时候,在函数f变量计算的时候,多个一个w*st-1。
二、源码实现
下面结合代码,了解代码层面的RNN实现:
- # -*- coding: utf-8 -*-
- """
- Created on Thu Oct 08 17:36:23 2015
- @author: Administrator
- """
- import numpy as np
- import codecs
- data = open('text.txt', 'r').read() #读取txt一整个文件的内容为字符串str类型
- chars = list(set(data))#去除重复的字符
- print chars
- #打印源文件中包含的字符个数、去重后字符个数
- data_size, vocab_size = len(data), len(chars)
- print 'data has %d characters, %d unique.' % (data_size, vocab_size)
- #创建字符的索引表
- char_to_ix = { ch:i for i,ch in enumerate(chars) }
- ix_to_char = { i:ch for i,ch in enumerate(chars) }
- print char_to_ix
- hidden_size = 100 # 隐藏层神经元个数
- seq_length = 20 #
- learning_rate = 1e-1#学习率
- #网络模型
- Wxh = np.random.randn(hidden_size, vocab_size)*0.01 # 输入层到隐藏层
- Whh = np.random.randn(hidden_size, hidden_size)*0.01 # 隐藏层与隐藏层
- Why = np.random.randn(vocab_size, hidden_size)*0.01 # 隐藏层到输出层,输出层预测的是每个字符的概率
- bh = np.zeros((hidden_size, 1)) #隐藏层偏置项
- by = np.zeros((vocab_size, 1)) #输出层偏置项
- #inputs t时刻序列,也就是相当于输入
- #targets t+1时刻序列,也就是相当于输出
- #hprev t-1时刻的隐藏层神经元激活值
- def lossFun(inputs, targets, hprev):
- xs, hs, ys, ps = {}, {}, {}, {}
- hs[-1] = np.copy(hprev)
- loss = 0
- #前向传导
- for t in xrange(len(inputs)):
- xs[t] = np.zeros((vocab_size,1)) #把输入编码成0、1格式,在input中,为0代表此字符未激活
- xs[t][inputs[t]] = 1
- hs[t] = np.tanh(np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t-1]) + bh) # RNN的隐藏层神经元激活值计算
- ys[t] = np.dot(Why, hs[t]) + by # RNN的输出
- ps[t] = np.exp(ys[t]) / np.sum(np.exp(ys[t])) # 概率归一化
- loss += -np.log(ps[t][targets[t],0]) # softmax 损失函数
- #反向传播
- dWxh, dWhh, dWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
- dbh, dby = np.zeros_like(bh), np.zeros_like(by)
- dhnext = np.zeros_like(hs[0])
- for t in reversed(xrange(len(inputs))):
- dy = np.copy(ps[t])
- dy[targets[t]] -= 1 # backprop into y
- dWhy += np.dot(dy, hs[t].T)
- dby += dy
- dh = np.dot(Why.T, dy) + dhnext # backprop into h
- dhraw = (1 - hs[t] * hs[t]) * dh # backprop through tanh nonlinearity
- dbh += dhraw
- dWxh += np.dot(dhraw, xs[t].T)
- dWhh += np.dot(dhraw, hs[t-1].T)
- dhnext = np.dot(Whh.T, dhraw)
- for dparam in [dWxh, dWhh, dWhy, dbh, dby]:
- np.clip(dparam, -5, 5, out=dparam) # clip to mitigate exploding gradients
- return loss, dWxh, dWhh, dWhy, dbh, dby, hs[len(inputs)-1]
- #预测函数,用于验证,给定seed_ix为t=0时刻的字符索引,生成预测后面的n个字符
- def sample(h, seed_ix, n):
- x = np.zeros((vocab_size, 1))
- x[seed_ix] = 1
- ixes = []
- for t in xrange(n):
- h = np.tanh(np.dot(Wxh, x) + np.dot(Whh, h) + bh)#h是递归更新的
- y = np.dot(Why, h) + by
- p = np.exp(y) / np.sum(np.exp(y))
- ix = np.random.choice(range(vocab_size), p=p.ravel())#根据概率大小挑选
- x = np.zeros((vocab_size, 1))#更新输入向量
- x[ix] = 1
- ixes.append(ix)#保存序列索引
- return ixes
- n, p = 0, 0
- mWxh, mWhh, mWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
- mbh, mby = np.zeros_like(bh), np.zeros_like(by) # memory variables for Adagrad
- smooth_loss = -np.log(1.0/vocab_size)*seq_length # loss at iteration 0
- while n<20000:
- #n表示迭代网络迭代训练次数。当输入是t=0时刻时,它前一时刻的隐藏层神经元的激活值我们设置为0
- if p+seq_length+1 >= len(data) or n == 0:
- hprev = np.zeros((hidden_size,1)) #
- p = 0 # go from start of data
- #输入与输出
- inputs = [char_to_ix[ch] for ch in data[p:p+seq_length]]
- targets = [char_to_ix[ch] for ch in data[p+1:p+seq_length+1]]
- #当迭代了1000次,
- if n % 1000 == 0:
- sample_ix = sample(hprev, inputs[0], 200)
- txt = ''.join(ix_to_char[ix] for ix in sample_ix)
- print '----\n %s \n----' % (txt, )
- # RNN前向传导与反向传播,获取梯度值
- loss, dWxh, dWhh, dWhy, dbh, dby, hprev = lossFun(inputs, targets, hprev)
- smooth_loss = smooth_loss * 0.999 + loss * 0.001
- if n % 100 == 0: print 'iter %d, loss: %f' % (n, smooth_loss) # print progress
- # 采用Adagrad自适应梯度下降法,可参看博文:http://blog.csdn.net/danieljianfeng/article/details/42931721
- for param, dparam, mem in zip([Wxh, Whh, Why, bh, by],
- [dWxh, dWhh, dWhy, dbh, dby],
- [mWxh, mWhh, mWhy, mbh, mby]):
- mem += dparam * dparam
- param += -learning_rate * dparam / np.sqrt(mem + 1e-8) #自适应梯度下降公式
- p += seq_length #批量训练
- n += 1 #记录迭代次数
参考文献:
1、http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/
2、http://blog.csdn.net/danieljianfeng/article/details/42931721
RNN入门的更多相关文章
- RNN 入门教程 Part 3 – 介绍 BPTT 算法和梯度消失问题
转载 - Recurrent Neural Networks Tutorial, Part 3 – Backpropagation Through Time and Vanishing Gradien ...
- RNN入门(一)识别MNIST数据集
RNN介绍 在读本文之前,读者应该对全连接神经网络(Fully Connected Neural Network, FCNN)和卷积神经网络( Convolutional Neural Netwo ...
- 循环神经网络-RNN入门
首先学习RNN需要一定的基础,即熟悉普通的前馈神经网络,特别是BP神经网络,最好能够手推. 所谓前馈,并不是说信号不能反向传递,而是网络在拓扑结构上不存在回路和环路. 而RNN最大的不同就是存在环路. ...
- RNN 入门学习资料整理
建议按序阅读 1. RNN的一些简单概念介绍 A guide to recurrent neural networks and backpropagation Deep learning:四十九(RN ...
- RNN 入门教程 Part 4 – 实现 RNN-LSTM 和 GRU 模型
转载 - Recurrent Neural Network Tutorial, Part 4 – Implementing a GRU/LSTM RNN with Python and Theano ...
- RNN 入门教程 Part 2 – 使用 numpy 和 theano 分别实现RNN模型
转载 - Recurrent Neural Networks Tutorial, Part 2 – Implementing a RNN with Python, Numpy and Theano 本 ...
- RNN 入门教程 Part 1 – RNN 简介
转载 - Recurrent Neural Networks Tutorial, Part 1 – Introduction to RNNs Recurrent Neural Networks (RN ...
- RNN入门(三)利用LSTM生成旅游点评
介绍 前几天,某个公众号发文质疑马蜂窝网站,认为它搬运其它网站的旅游点评,对此,马蜂窝网站迅速地做出了回应.相信大多数关注时事的群众已经了解了整个事情的经过,在这里,我们且不论这件事的是是非非,也 ...
- RNN入门(二)识别验证码
介绍 作为RNN的第二个demo,笔者将会介绍RNN模型在识别验证码方面的应用. 我们的验证码及样本数据集来自于博客: CNN大战验证码,在这篇博客中,我们已经准备好了所需的样本数据集,不需要 ...
随机推荐
- java 线程Thread 技术--方法演示生产与消费模式
利用wait 与notifyAll 方法进行演示生产与消费的模式的演示,我们两个线程负责生产,两个线程消费,只有生产了才能消费: 在effective Java 中有说过: 1. 在Java 中 ,使 ...
- Linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结(转)
本文介绍了linux下的压缩程式tar.gzip.gunzip.bzip2.bunzip2.compress .uncompress. zip. unzip.rar.unrar等程式,以及如何使用它们 ...
- Bootstrap(3) 表格与按钮
1.表格 基本格式,实现基本的表格样式 <table class="table"> <thead> <tr> <th>编号</ ...
- JFinal Web开发学习(三)前后台路由设计
效果图: 一.写控制器 1.在controller包中新建AdminController后台控制器,继承Controller,实现一个index方法,作为的处理方法. /admin 后面,这个控制器中 ...
- 9.26 H5日记
9.26 1.新的背景属性,background-position background-position有两个值,水平和垂直,单位px ❤在html和CSS当中,有三个属性可以向服务器发送请求,分别 ...
- ajax 之POST请求,参数序列化
比如,,我们在没有使用jquery的时候,没有$.post来让我们使用,那我们像下面这样直接发送: var params1 = { username: username, passwrod: pass ...
- 如何提高php应用的性能?
1. 如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍.2.$row[’id’] 的速度是$row[id]的7倍.3.echo 比 print快,并且使用echo的 ...
- 8K - 圆桌会议
HDU ACM集训队的队员在暑假集训时经常要讨论自己在做题中遇到的问题.每当面临自己解决不了的问题时,他们就会围坐在一张圆形的桌子旁进行交流,经过大家的讨论后一般没有解决不了的问题,这也只有HDU A ...
- 冒泡排序(js版)
基本思想:两两比较相邻记录的关键字,如果反序则交换,直至没有反序为止. 最初的冒泡排序(初级版): //从小到大 function BubbleSort(arr){ var i,j,temp; for ...
- 自己动手开启QUIC(转载)
源:https://www.bennythink.com/quic.html#title-0 今天在推上偶然发现 Google 在自己的服务器上启用了 QUIC,QUIC 这东西嘛(发音同 quick ...