摘要

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

代码结构

dinos.txt:数据文件,每行是一个恐龙名称

红色框:numpy实现的rnn(rnn.py),生成名称demo(rnn_dinosaurus_name.py)

绿色框:copy课件代码。检测自己写的代码是否正确

python rnn模型实例 rnn numpy_文本生成


程序查看顺序:

(1)rnn_dinosaurus_name.py的model():实验入口程序,完成数据变换,将名称转换为rnn认识的数据格式。

(2)rnn.py的optimize:rnn正向传播、损失计算、反向传播、参数更新。

(3)rnn_dinosaurus_name.py的sample():根据rnn计算得到参数,按概率生成一个恐龙名字(若干个字符)

RNN网络结构

每个方框是一个cell,展开图和变量说明如下。

python rnn模型实例 rnn numpy_python rnn模型实例_02


用于生成名字字符串实验,各个变量含义如下:

  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:字符}

python rnn模型实例 rnn numpy_反向传播_03


(2)将输入的名字字符串,转换为输入X和label Y,在model函数中

python rnn模型实例 rnn numpy_python rnn模型实例_04

cell结构

正向传播、反向传播都考这个图了,所有相关程序在rnn.py

python rnn模型实例 rnn numpy_深度学习_05

rnn算法和程序

1. 正向传播

(1) rnn_forward(),用于接收输入数据、初始化参数,调用rnn_cell_forward()来时先每个cell的计算。

python rnn模型实例 rnn numpy_文本生成_06


(2)rnn_cell_forward(),正向传播公式,绿色框代码对应公式

python rnn模型实例 rnn numpy_文本生成_07

2. loss计算

python rnn模型实例 rnn numpy_文本生成_08


说明:softmax交叉熵损失函数python rnn模型实例 rnn numpy_深度学习_09

3.反向传播

(1)rnn_backward,初始化每次反向传播参数,然后调用rnn_cell_backward

注意:dz=y_hat - y,是softmax求导公式

python rnn模型实例 rnn numpy_RNN_10


(2)rnn_cell_backward

示意图如下,公式和图对应

python rnn模型实例 rnn numpy_RNN_11


代码和共识对应图如下

python rnn模型实例 rnn numpy_RNN_12


i) 绿色2行代码的小矩形,由右侧绿色椭圆公式求导得到,公式和代码一样。

ii)红色大矩形,左侧代码对应右侧公式。红色大矩形里边小粉色矩形代码,是右侧大红色矩形里边小粉色矩形替代,为了代码方便简洁。

iii)蓝色波浪线那行,da由2部分组成,本单元输出求导和下一个模块da_next

4. 梯度算法更新参数

python rnn模型实例 rnn numpy_RNN_13

5. 名称生成

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

python rnn模型实例 rnn numpy_反向传播_14

6.实验结果
Iteration: 0, Loss: 23.087336
 Nkzxwtdmfqoeyhsqwasjkjvu
 Kneb
 Kzxwtdmfqoeyhsqwasjkjvu
 Neb
 Zxwtdmfqoeyhsqwasjkjvu
 Eb
 XwtdmfqoeyhsqwasjkjvuIteration: 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框架实现生成文本或者文本分类,流程变得清晰了。