深度学习笔记(12.numpy实现RNN并生成恐龙名)

摘要

Ng深度学习课程第五部分序列化模型,第一周作业numpy实现RNN,并利用RNN生成恐龙名称实验。涉及到正向传播、反向传播公式,程序的整合,部分理论学习。代码注释添加了部分说明。
程序地址:https://github.com/ConstellationBJUT/Coursera-DL-Study-Notes

代码结构

dinos.txt:数据文件,每行是一个恐龙名称
红色框:numpy实现的rnn(rnn.py),生成名称demo(rnn_dinosaurus_name.py)
绿色框:copy课件代码。检测自己写的代码是否正确
深度学习笔记(12.numpy实现RNN并生成恐龙名)
程序查看顺序:
(1)rnn_dinosaurus_name.py的model():实验入口程序,完成数据变换,将名称转换为rnn认识的数据格式。
(2)rnn.py的optimize:rnn正向传播、损失计算、反向传播、参数更新。
(3)rnn_dinosaurus_name.py的sample():根据rnn计算得到参数,按概率生成一个恐龙名字(若干个字符)

RNN网络结构

每个方框是一个cell,展开图和变量说明如下。
深度学习笔记(12.numpy实现RNN并生成恐龙名)
用于生成名字字符串实验,各个变量含义如下:

  1. 输入X:维度(n_x, m, T_x),名字序列
    (1) n_x:每个xi维度,例如语料一共27个字符,n_x=27
    (2) m:一次输入序列个数,也就是batch_size,本实验由于每个名字长度不一样,导致每次输入T_x不同,这里m=1
    (3)T_x:序列长度,也就是cell数。
    例:名字是abc 一个输入X维度是(27, 1, 4),这里将27个字符\n,a,b,c…,映射到整数对应0,1,2,3…,每个xi是一个one_hot向量,每个位置对应一个字符。该序列如下:
    x0 = [0,0,0,0,…,0] (第一个位置添加0,因为头字符)
    x1 = [0,1,0,0,…,0]
    x2 = [0,0,1,0,…,0]
    x3 = [0,0,0,1,…,0]
  2. Y(也就是label,one_hot向量,从数据集获得):维度(n_y, m, T_x),含义和输入一样,每个xi对应一个输出yi,表示一个字符紧跟在后边的字符是啥。
    例:输入X=\nabc,输出对应Y=abc\n,相当于X左移一位,尾部加\n
    y0 = [0,1,0,0,…,0]
    y1 = [0,0,1,0,…,0]
    y2 = [0,0,0,1,…,0]
    y3 = [1,0,0,0,…,0]
  3. Y_hat:对应每个cell的softmax输出,维度同Y,每个位置表示出现各个字符的概率。

上边这一堆说明对应代码如下:rnn_dinosaurus_name.py
(1)27个字符\n和a~z映射成2个字典char_to_ix={字符: id},
ix_to_char={id:字符}
深度学习笔记(12.numpy实现RNN并生成恐龙名)
(2)将输入的名字字符串,转换为输入X和label Y,在model函数中
深度学习笔记(12.numpy实现RNN并生成恐龙名)

cell结构

正向传播、反向传播都考这个图了,所有相关程序在rnn.py
深度学习笔记(12.numpy实现RNN并生成恐龙名)

rnn算法和程序

1. 正向传播

(1) rnn_forward(),用于接收输入数据、初始化参数,调用rnn_cell_forward()来时先每个cell的计算。
深度学习笔记(12.numpy实现RNN并生成恐龙名)
(2)rnn_cell_forward(),正向传播公式,绿色框代码对应公式
深度学习笔记(12.numpy实现RNN并生成恐龙名)

2. loss计算

深度学习笔记(12.numpy实现RNN并生成恐龙名)
说明:softmax交叉熵损失函数loss=1mi=1T_xyilog(yi^)\displaystyle loss=-\frac{1}{m}\sum_{i=1}^{T\_x} y_ilog(\hat{y_i})

3.反向传播

(1)rnn_backward,初始化每次反向传播参数,然后调用rnn_cell_backward
注意:dz=y_hat - y,是softmax求导公式
深度学习笔记(12.numpy实现RNN并生成恐龙名)
(2)rnn_cell_backward
示意图如下,公式和图对应
深度学习笔记(12.numpy实现RNN并生成恐龙名)
代码和共识对应图如下
深度学习笔记(12.numpy实现RNN并生成恐龙名)
i) 绿色2行代码的小矩形,由右侧绿色椭圆公式求导得到,公式和代码一样。
ii)红色大矩形,左侧代码对应右侧公式。红色大矩形里边小粉色矩形代码,是右侧大红色矩形里边小粉色矩形替代,为了代码方便简洁。
iii)蓝色波浪线那行,da由2部分组成,本单元输出求导和下一个模块da_next

4. 梯度算法更新参数

深度学习笔记(12.numpy实现RNN并生成恐龙名)

5. 名称生成

每个输入字符x(i)计算得到和自己紧邻的字符y(i),y(i)作为下一个cell的输入x(i+1)。计算过程是根据y_hat向量每个位置的概率,随机生成一个可能的字符id,直到生成\n或者到50个字符结束。详情看程序sample()函数。
深度学习笔记(12.numpy实现RNN并生成恐龙名)

6.实验结果

Iteration: 0, Loss: 23.087336
Nkzxwtdmfqoeyhsqwasjkjvu
Kneb
Kzxwtdmfqoeyhsqwasjkjvu
Neb
Zxwtdmfqoeyhsqwasjkjvu
Eb
Xwtdmfqoeyhsqwasjkjvu

Iteration: 2000, Loss: 27.884160
Liusskeomnolxeros
Hmdaairus
Hytroligoraurus
Lecalosapaus
Xusicikoraurus
Abalpsamantisaurus
Tpraneronxeros

总结

(1)感觉把算法和从实验程序中抽离出来变得难了,没有dnn那么清晰。导致实验程序需要很多的代码适应RNN模型的输入和输出。这个还可以再改进。
(2)每个cell那个图很重要,正向和反向传播都得时刻回忆着。
(3)又看了softmax交叉熵损失函数和求导。
(4)未解决的问题,不太确定手动实现RNN错误修正方法,错了也能够运行起来。这里是用课程给的作业程序,自己完成作业后,把程序和自己实现的RNN作对比,发现错误后,单步调试,看正向和反向传播输出结果是否一致。不一致,就进到代码每一步,看输出矩阵具体数值。
(5)撸完RNN,感觉tf或者keras框架实现生成文本或者文本分类,流程变得清晰了。