吴恩达Coursera深度学习课程 deeplearning.ai (5-1) 循环序列模型--编程作业(二):字母级别的语言模型 - 恐龙岛

Part 2:字母级别的语言模型 - 恐龙岛

欢迎来到恐龙岛! 6500万年前,恐龙就存在了。在这项任务中他们又回来了。 现在你负责一项特殊任务。领先的生物学研究人员正在创造新的恐龙种类并将它们带到地球上,您的工作就是为这些恐龙命名。如果一只恐龙不喜欢它的名字,它可能会被人误认,所以请明智地选择!

image

幸运的是,你已经学会了一些深度学习,你会用它来拯救这一天。 你的助手收集了他们可以找到的所有恐龙名称的列表,并将它们编译成这个数据集。要创建新的恐龙名称,您将构建一个字母级级语言模型以生成新名称。 您的算法将学习不同的名称模式,并随机生成新名称。希望这个算法能够让你和你的团队免于恐龙的愤怒!

通过完成这项任务,你将学到:

  • 如何存储文本数据以便使用RNN进行处理
  • 如何合成数据,通过在每个时间步采样预测并将其传递给下一个RNN单元
  • 如何构建一个字符级文本生成递归神经网络
  • 为什么剪切梯度很重要
导包
import numpy as np
from utils import *
import random
有用的函数
import numpy as np

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

def smooth(loss, cur_loss):
    return loss * 0.999 + cur_loss * 0.001

def print_sample(sample_ix, ix_to_char):
    txt = ''.join(ix_to_char[ix] for ix in sample_ix)
    txt = txt[0].upper() + txt[1:]  # capitalize first character 
    print ('%s' % (txt, ), end='')

def get_initial_loss(vocab_size, seq_length):
    return -np.log(1.0/vocab_size)*seq_length

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

def initialize_parameters(n_a, n_x, n_y):
    """
    Initialize parameters with small random values

    Returns:
    parameters -- python dictionary containing:
                        Wax -- Weight matrix multiplying the input, numpy array of shape (n_a, n_x)
                        Waa -- Weight matrix multiplying the hidden state, numpy array of shape (n_a, n_a)
                        Wya -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a)
                        b --  Bias, numpy array of shape (n_a, 1)
                        by -- Bias relating the hidden-state to the output, numpy array of shape (n_y, 1)
    """
    np.random.seed(1)
    Wax = np.random.randn(n_a, n_x)*0.01 # input to hidden
    Waa = np.random.randn(n_a, n_a)*0.01 # hidden to hidden
    Wya = np.random.randn(n_y, n_a)*0.01 # hidden to output
    b = np.zeros((n_a, 1)) # hidden bias
    by = np.zeros((n_y, 1)) # output bias

    parameters = {
  "Wax": Wax, "Waa": Waa, "Wya": Wya, "b": b,"by": by}

    return parameters

def rnn_step_forward(parameters, a_prev, x):

    Waa, Wax, Wya, by, b = parameters['Waa'], parameters['Wax'], parameters['Wya'], parameters['by'], parameters['b']
    a_next = np.tanh(np.dot(Wax, x) + np.dot(Waa, a_prev) + b) # hidden state
    p_t = softmax(np.dot(Wya, a_next) + by) # unnormalized log probabilities for next chars # probabilities for next chars 

    return a_next, p_t

def rnn_step_backward(dy, gradients, parameters, x, a, a_prev):

    gradients['dWya'] += np.dot(dy, a.T)
    gradients['dby'] += dy
    da = np.dot(parameters['Wya'].T, dy) + gradients['da_next'] # backprop into h
    daraw = (1 - a * a) * da # backprop through tanh nonlinearity
    gradients['db'] += daraw
    gradients['dWax'] += np.dot(daraw, x.T)
    gradients['dWaa'] += np.dot(daraw, a_prev.T)
    gradients['da_next'] = np.dot(parameters['Waa'].T, daraw)
    return gradients

def update_parameters(parameters, gradients, lr):

    parameters['Wax'] += -lr * gradients['dWax']
    parameters['Waa'] += -lr * gradients['dWaa']
    parameters['Wya'] += -lr * gradients['dWya']
    parameters['b']  += -lr * gradients['db']
    parameters['by']  += -lr * gradients['dby']
    return parameters

def rnn_forward(X, Y, a0, parameters, vocab_size = 27):

    # Initialize x, a and y_hat as empty dictionaries
    x, a, y_hat = {}, {}, {}

    a[-1] = np.copy(a0)

    # initialize your loss to 0
    loss = 0

    for t in range(len(X)):

        # Set x[t] to be the one-hot vector representation of the t'th character in X.
        # if X[t] == None, we just have x[t]=0. This is used to set the input for the first timestep to the zero vector. 
        x[t] = np.zeros((vocab_size,1)) 
        if (X[t] != None):
            x[t][X[t]] = 1

        # Run one step forward of the RNN
        a[t], y_hat[t] = rnn_step_forward(parameters, a[t-1], x[t])

        # Update the loss by substracting the cross-entropy term of this time-step from it.
        loss -= np.log(y_hat[t][Y[t],0])

    cache = (y_hat, a, x)

    return loss, cache

def rnn_backward(X, Y, parameters, cache):
    # Initialize gradients as an empty dictionary
    gradients = {}

    # Retrieve from cache and parameters
    (y_hat, a, x) = cache
    Waa, Wax, Wya, by, b = parameters['Waa'], parameters['Wax'], parameters['Wya'], parameters['by'], parameters['b']

    # each one should be initialized to zeros of the same dimension as its corresponding parameter
    gradients['dWax'], gradients['dWaa'], gradients['dWya'] = np.zeros_like(Wax), np.zeros_like(Waa), np.zeros_like(Wya)
    gradients['db'], gradients['dby'] = np.zeros_like(b), np.zeros_like(by)
    gradients['da_next'] = np.zeros_like(a[0])

    ### START CODE HERE ###
    # Backpropagate through time
    for t in reversed(range(len(X))):
        dy = np.copy(y_hat[t])
        dy[Y[t]] -= 1
        gradients = rnn_step_backward(dy, gradients, parameters, x[t], a[t], a[t-1])
    ### END CODE HERE ###

    return gradients, a

问题描述

1.1 数据集和预处理

运行程序读取恐龙名称的数据集,创建唯一字符的列表(例如a-z),并计算数据集和词汇的大小。

data = open('dinos.txt', 'r').read()
data= data.lower()
chars = list(set(data))
data_size, vocab_size = len(data), len(chars)
print('There are %d total characters and %d unique characters in your data.' % (data_size, vocab_size))

# There are 19909 total characters and 27 unique characters in your data.

这些字符是a-z(26个字符)加上”\n”(换行符),换行符在这里 表示恐龙名称的结尾,而不是句子的结尾。 在下面的程序中,我们创建了一个Python字典(即哈希表),将每个字符映射到0-26的索引。 我们还创建了第二个python字典,将每个索引映射回相应的字符。 这将帮助你找出哪些索引对应于softmax图层的概率分布输出中的什么字符。 下面,char_to_ix和ix_to_char是python字典。

char_to_ix = { ch:i for i,ch in enumerate(sorted(chars)) }
ix_to_char = { i:ch for i,ch in enumerate(sorted(chars)) }
print(ix_to_char)

# {0: '\n', 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'}

1.2 模型总览

模型结构

  • 初始化参数
  • 执行最优化循环
    • 计算前向传播的损失函数
    • 计算反向传播的梯度及损失函数
    • 剪裁梯度避免梯度爆炸
    • 使用梯度更新梯度下降中的各参数
  • 返回学习到的参数

image

在每个时间步,RNN 视图通过给出的前面的字母序列来预测下一个字母。对于每个时间步t, 有 y = x

2 构建模型的各个模块

在这个部分,你讲建立模型的两个重要模块

  • 梯度剪裁:避免梯度爆炸
  • 采样:一项生成新字母的技术

之后你将利用这些模块构建模型。

2.1 在最优化循环中剪裁梯度

在本节中,您将实现clip函数一遍在优化循环中调用。 回想一下,整体循环结构通常由正向传播,损失函数计算,反向传播和参数更新组成。 在更新参数之前,在需要时执行梯度剪裁,以确保梯度不会“爆炸”,即不出现过大的值。

在下面的练习中,您将实现一个clip函数,接收一个梯度词典并在需要时返回剪裁版本的梯度词典。 有多种不同的方法来对梯度进行剪切。 我们将使用一个简单的基于元素的剪裁方式,其中梯度向量的每个元素都被裁剪到范围[-N,N]之间。 (范围外被剪成边界值)

image

练习

实现下面的函数返回剪裁后的梯度字典。 这个函数将设置一个最大剪裁阈值并返回剪裁版本的梯度字典。

### GRADED FUNCTION: clip

def clip(gradients, maxValue):
    '''
    Clips the gradients' values between minimum and maximum.

    Arguments:
    gradients -- a dictionary containing the gradients "dWaa", "dWax", "dWya", "db", "dby"
    maxValue -- everything above this number is set to this number, and everything less than -maxValue is set to -maxValue

    Returns: 
    gradients -- a dictionary with the clipped gradients.
    '''

    dWaa, dWax, dWya, db, dby = gradients['dWaa'], gradients['dWax'], gradients['dWya'], gradients['db'], gradients['dby']

    ### START CODE HERE ###
    # clip to mitigate exploding gradients, loop over [dWax, dWaa, dWya, db, dby]. (≈2 lines)
    for gradient in [dWax, dWaa, dWya, db, dby]:
        np.clip(gradient, -maxValue, maxValue, out=gradient)
    ### END CODE HERE ###

    gradients = {
  "dWaa": dWaa, "dWax": dWax, "dWya": dWya, "db": db, "dby": dby}

    return gradients

######################################################

np.random.seed(3)
dWax = np.random.randn(5,3)*10
dWaa = np.random.randn(5,5)*10
dWya = np.random.randn(2,5)*10
db = np.random.randn(5,1)*10
dby = np.random.randn(2,1)*10
gradients = {
  "dWax": dWax, "dWaa": dWaa, "dWya": dWya, "db": db, "dby": dby}
gradients = clip(gradients, 10)
print("gradients[\"dWaa\"][1][2] =", gradients["dWaa"][1][2])
print("gradients[\"dWax\"][3][1] =", gradients["dWax"][3][1])
print("gradients[\"dWya\"][1][2] =", gradients["dWya"][1][2])
print("gradients[\"db\"][4] =", gradients["db"][4])
print("gradients[\"dby\"][1] =", gradients["dby"][1])

# gradients["dWaa"][1][2] = 10.0
# gradients["dWax"][3][1] = -10.0
# gradients["dWya"][1][2] = 0.29713815361
# gradients["db"][4] = [ 10.]
# gradients["dby"][1] = [ 8.45833407]

期待的输出

key value
gradients[“dWaa”][1][2] 10.0
gradients[“dWax”][3][1] -10.0
gradients[“dWya”][1][2] 0.29713815361
gradients[“db”][4] [ 10.]
gradients[“dby”][1] [ 8.45833407]

2.2 采样

现在假设你的模型已经训练好了,你需要以此生成新的字母,过程如下:

image

练习:按照如下4步实现sample函数

1、 第一个“虚拟”输入 x1=0⃗  x ⟨ 1 ⟩ = 0 ⃗ (零向量)。 这是我们生成任何字符之前的默认输入。 我们还设置了一个 a0

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值