一步一步创建RNN模型

序列化模型(rnn)对于自然语言处理和一些序列化的任务是非常有作用的,因为他们是存在“记忆”功能的
说明:
上标[l]:表示与第 l 层相关联的对象
上标(i):表示与第 i 个示例关联的对象
上标<t>:表示第 t 时间步处的对象
下标 i : 表示向量的第 i 项

导入我们所需的包

import numpy as np
from rnn_utils import *

1. 基本RNN的前向传播

RNN基本结构(本例Tx=Ty):


实现步骤

  1. 实现RNN的一个时间步骤所需的计算。
  2. 在Tx时间步上实现一个循环,一次处理一个输入值。

1.1 实现一个rnn单元

循环(递归)神经网络可以看作是单个细胞的重复。首先要实现一个时间步的计算。


实现步骤

  1. 计算隐藏状态的值a<t>
  2. 根据a<t>,计算预测值yhat<t>
  3. 将(a<t>, a<t-1>, x<t>, parameters)存储到cache中
  4. 返回值a<t>, y<t> and cache

我们将矢量化m个例子,x<t>尺寸(nx, m),a<t>尺寸(na, m)

def rnn_cell_forward(xt, a_prev, parameters):
    """
    Arguments:
                     xt  shape: (n_x, m).
                     a_prev  shape: (n_a, m)
    parameters -- python dictionary containing:
                        Wax --  shape (n_a, n_x)
                        Waa --  shape (n_a, n_a)
                        Wya --  shape (n_    y, n_a)
                        ba --   shape (n_a, 1)
                        by --  shape (n_y, 1)
    Returns:
    a_next -- shape (n_a, m)
    yt_pred -- shape (n_y, m)
    cache -- 元组,包含向后传递所需的值 (a_next, a_prev, xt, parameters)
    """
    # 从"parameters"中检索参数
    Wax = parameters["Wax"]
    Waa = parameters["Waa"]
    Wya = parameters["Wya"]
    ba = parameters["ba"]
    by = parameters["by"]
     
    a_next = np.tanh(np.add(np.add(np.matmul(Wax,xt),np.matmul(Waa,a_prev)),ba))
 
    yt_pred = softmax(np.add(np.matmul(Wya,a_next),by))
    
    # store values you need for backward propagation in cache
    cache = (a_next, a_prev, xt, parameters)
    
    return a_next, yt_pred, cache

1.2 rnn向前传播

rnn可以看作将前面的rnn细胞进行重复,如果输入的数据序列经过10个时间步,那将复制rnn单元10次,每个单元都将前一个单元的隐藏状态a<t-1>和当前时间步的输入数据x<t>作为输入,它输出该时间步的隐藏状态a<t>和预测y<t>
实现步骤

  1. 创建一个零向量(a),它将存储由RNN计算的所有隐藏状态。
  2. 初始化隐藏状态a_next = a0
  3. 开始循环每个时间步,增量索引为t:
  • 通过运行rnn_cell_forward更新下一个隐藏状态和缓存
  • 存储隐藏状态到 a
  • 存储预测值到 y
  • 添加cache到caches
  1. 返回a, y 和 caches
def rnn_forward(x, a0, parameters):
    """
    说明:
    x -- 输入,shape (n_x, m, T_x).
    a0 -- 初始隐藏状态,shape (n_a, m)
    parameters -- python字典包含:
                        Waa -- shape (n_a, n_a)
                        Wax -- shape (n_a, n_x)
                        Wya -- shape (n_y, n_a)
                        ba --   shape (n_a, 1)
                        by --  shape (n_y, 1)
    Returns:
    a -- shape (n_a, m, T_x)
    y_pred -- shape (n_y, m, T_x)
    caches --元组,包含向后传递所需的值 (list of caches, x)
    """    
    # 初始化,包含caches列表
    caches = []   
    n_x, m, T_x = x.shape
    n_y, n_a = parameters["Wya"].shape
    # 初始化
    a = np.zeros([n_a, m,T_x])
    y_pred = np.zeros([n_y, m, T_x])
    # 初始化a_next 为a0
    a_next = a0
    
    # 循环time-steps
    for t in range(T_x):
        a_next, yt_pred, cache = rnn_cell_forward(x[:,:,t], a_next, parameters)
        a[:,:,t] = a_next
        y_pred[:,:,t] = yt_pred
        caches.append(cache)
       
    # store values needed for backward propagation in cache
    caches = (caches, x)
    
    return a, y_pred, caches

2.长短期记忆(LSTM)

LSTM基本结构:


关于门

  • 遗忘门


  • 更新门


  • 更新单元



    新状态为:


  • 输出门


2.1 LSTM单元

实现步骤

  1. 将a<t-1>和x<t>上下连接起来,组成矩阵concat
  2. 计算前面的公式
  3. 计算预测值y<t>
def lstm_cell_forward(xt, a_prev, c_prev, parameters):
    """
    Arguments:
    xt -- shape (n_x, m).
    a_prev --  shape (n_a, m)
    c_prev --  shape (n_a, m)
    parameters -- python 字典:
                        Wf --  shape (n_a, n_a + n_x)
                        bf -- shape (n_a, 1)

                        Wi --  shape (n_a, n_a + n_x)
                        bi -- shape (n_a, 1)

                        Wc -- shape (n_a, n_a + n_x)
                        bc --  shape (n_a, 1)

                        Wo -- shape (n_a, n_a + n_x)
                        bo --   shape (n_a, 1)

                        Wy -- shape (n_y, n_a)
                        by -- shape (n_y, 1)
                        
    Returns:
    a_next -- shape (n_a, m)
    c_next --  shape (n_a, m)
    yt_pred --  shape (n_y, m)
    cache --元组,包含向后传递所需的值(a_next, c_next, a_prev, c_prev, xt, parameters)
    
    注意: ft / it / ot 代表 遗忘门、更新门、输出门
    cct :代表候选值 (c tilda),
    c :代表记忆值
    """
    # 检索参数
    Wf = parameters["Wf"]
    bf = parameters["bf"]
    Wi = parameters["Wi"]
    bi = parameters["bi"]
    Wc = parameters["Wc"]
    bc = parameters["bc"]
    Wo = parameters["Wo"]
    bo = parameters["bo"]
    Wy = parameters["Wy"]
    by = parameters["by"]
    
    n_x, m = xt.shape
    n_y, n_a = Wy.shape

    # 连接 a_prev 和 xt 在一个矩阵中
    concat = np.zeros([n_x+n_a,m])
    concat[: n_a, :] = a_prev
    concat[n_a :, :] = xt

    # 计算 ft, it, cct, c_next, ot, a_next 用下面的公式:
    ft = sigmoid(np.dot(Wf,concat) + bf)
    it = sigmoid(np.dot(Wi,concat) + bi)
    cct = np.tanh(np.dot(Wc,concat) + bc)

    c_next = ft*c_prev + it*cct
    ot = sigmoid(np.dot(Wo,concat) + bo)
    a_next = ot * np.tanh(c_next)
    
    # 计算预测值
    yt_pred = softmax(np.dot(Wy,a_next) + by)
  
    # 存储反向传播需要的值到 cache
    cache = (a_next, c_next, a_prev, c_prev, ft, it, cct, ot, xt, parameters)

    return a_next, c_next, yt_pred, cache

2.2 LSTM向前传播

现在您已经实现了LSTM的一个步骤,现在可以使用for循环来处理一系列Tx输入。

def lstm_forward(x, a0, parameters):
    """
       Arguments:
     x --  shape (n_x, m, T_x).
    a0 --  shape (n_a, m)
    parameters -- python 字典:
                        Wf --  shape (n_a, n_a + n_x)
                        bf -- shape (n_a, 1)

                        Wi --  shape (n_a, n_a + n_x)
                        bi --  shape (n_a, 1)

                        Wc -- shape (n_a, n_a + n_x)
                        bc --  shape (n_a, 1)

                        Wo --   shape (n_a, n_a + n_x)
                        bo --  shape (n_a, 1)

                        Wy --   shape (n_y, n_a)
                        by --   shape (n_y, 1)
                        
    Returns:
    a --  shape (n_a, m, T_x)
    y --  shape (n_y, m, T_x)
    caches -- 元组,包含向后传递所需的值 (list of all the caches, x)
    """
    caches = []
  
    n_x, m, T_x = x.shape
    n_y, n_a = parameters["Wy"].shape
    
    # initialize "a", "c" and "y" with zeros (≈3 lines)
    a = np.zeros((n_a, m, T_x))
    c = np.zeros((n_a, m, T_x))
    y = np.zeros((n_y, m, T_x))
    
   # 初始化a_next and c_next 
    a_next = a0
    c_next = np.zeros((n_a, m))
    
    # 循环 time-steps
    for t in range(T_x):
        a_next, c_next, yt, cache = lstm_cell_forward(x[:,:,t], a_next, c_next, parameters)
        a[:,:,t] = a_next
        y[:,:,t] = yt
        c[:,:,t]  = c_next
        caches.append(cache)
        
     caches = (caches, x)

    return a, y, c, caches

3. 反向传播

用框架实现。。。

备注
文件rnn_utils代码如下:

import numpy as np

def softmax(x):
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0)


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def initialize_adam(parameters) :
    """
    Initializes v and s as two python dictionaries with:
                - keys: "dW1", "db1", ..., "dWL", "dbL" 
                - values: numpy arrays of zeros of the same shape as the corresponding gradients/parameters.
    
    Arguments:
    parameters -- python dictionary containing your parameters.
                    parameters["W" + str(l)] = Wl
                    parameters["b" + str(l)] = bl
    
    Returns: 
    v -- python dictionary that will contain the exponentially weighted average of the gradient.
                    v["dW" + str(l)] = ...
                    v["db" + str(l)] = ...
    s -- python dictionary that will contain the exponentially weighted average of the squared gradient.
                    s["dW" + str(l)] = ...
                    s["db" + str(l)] = ...

    """
    
    L = len(parameters) // 2 # number of layers in the neural networks
    v = {}
    s = {}
    
    # Initialize v, s. Input: "parameters". Outputs: "v, s".
    for l in range(L):
    ### START CODE HERE ### (approx. 4 lines)
        v["dW" + str(l+1)] = np.zeros(parameters["W" + str(l+1)].shape)
        v["db" + str(l+1)] = np.zeros(parameters["b" + str(l+1)].shape)
        s["dW" + str(l+1)] = np.zeros(parameters["W" + str(l+1)].shape)
        s["db" + str(l+1)] = np.zeros(parameters["b" + str(l+1)].shape)
    ### END CODE HERE ###
    
    return v, s


def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01,
                                beta1 = 0.9, beta2 = 0.999,  epsilon = 1e-8):
    """
    Update parameters using Adam
    
    Arguments:
    parameters -- python dictionary containing your parameters:
                    parameters['W' + str(l)] = Wl
                    parameters['b' + str(l)] = bl
    grads -- python dictionary containing your gradients for each parameters:
                    grads['dW' + str(l)] = dWl
                    grads['db' + str(l)] = dbl
    v -- Adam variable, moving average of the first gradient, python dictionary
    s -- Adam variable, moving average of the squared gradient, python dictionary
    learning_rate -- the learning rate, scalar.
    beta1 -- Exponential decay hyperparameter for the first moment estimates 
    beta2 -- Exponential decay hyperparameter for the second moment estimates 
    epsilon -- hyperparameter preventing division by zero in Adam updates

    Returns:
    parameters -- python dictionary containing your updated parameters 
    v -- Adam variable, moving average of the first gradient, python dictionary
    s -- Adam variable, moving average of the squared gradient, python dictionary
    """
    
    L = len(parameters) // 2                 # number of layers in the neural networks
    v_corrected = {}                         # Initializing first moment estimate, python dictionary
    s_corrected = {}                         # Initializing second moment estimate, python dictionary
    
    # Perform Adam update on all parameters
    for l in range(L):
        # Moving average of the gradients. Inputs: "v, grads, beta1". Output: "v".
        ### START CODE HERE ### (approx. 2 lines)
        v["dW" + str(l+1)] = beta1 * v["dW" + str(l+1)] + (1 - beta1) * grads["dW" + str(l+1)] 
        v["db" + str(l+1)] = beta1 * v["db" + str(l+1)] + (1 - beta1) * grads["db" + str(l+1)] 
        ### END CODE HERE ###

        # Compute bias-corrected first moment estimate. Inputs: "v, beta1, t". Output: "v_corrected".
        ### START CODE HERE ### (approx. 2 lines)
        v_corrected["dW" + str(l+1)] = v["dW" + str(l+1)] / (1 - beta1**t)
        v_corrected["db" + str(l+1)] = v["db" + str(l+1)] / (1 - beta1**t)
        ### END CODE HERE ###

        # Moving average of the squared gradients. Inputs: "s, grads, beta2". Output: "s".
        ### START CODE HERE ### (approx. 2 lines)
        s["dW" + str(l+1)] = beta2 * s["dW" + str(l+1)] + (1 - beta2) * (grads["dW" + str(l+1)] ** 2)
        s["db" + str(l+1)] = beta2 * s["db" + str(l+1)] + (1 - beta2) * (grads["db" + str(l+1)] ** 2)
        ### END CODE HERE ###

        # Compute bias-corrected second raw moment estimate. Inputs: "s, beta2, t". Output: "s_corrected".
        ### START CODE HERE ### (approx. 2 lines)
        s_corrected["dW" + str(l+1)] = s["dW" + str(l+1)] / (1 - beta2 ** t)
        s_corrected["db" + str(l+1)] = s["db" + str(l+1)] / (1 - beta2 ** t)
        ### END CODE HERE ###

        # Update parameters. Inputs: "parameters, learning_rate, v_corrected, s_corrected, epsilon". Output: "parameters".
        ### START CODE HERE ### (approx. 2 lines)
        parameters["W" + str(l+1)] = parameters["W" + str(l+1)] - learning_rate * v_corrected["dW" + str(l+1)] / np.sqrt(s_corrected["dW" + str(l+1)] + epsilon)
        parameters["b" + str(l+1)] = parameters["b" + str(l+1)] - learning_rate * v_corrected["db" + str(l+1)] / np.sqrt(s_corrected["db" + str(l+1)] + epsilon)
        ### END CODE HERE ###

    return parameters, v, s
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355