RNN循环神经网络(Recurrent Neural Network)学习

一.RNN简介

  1.)什么是RNN?

RNN是一种特殊的神经网络结构,考虑前一时刻的输入,且赋予了网络对前面的内容的一种‘记忆‘功能.

  2.)RNN可以解决什么问题?

时间先后顺序的问题都可以使用RNN来解决,比如:音乐,翻译,造句,语音识别,视频图像预测,语言处理等等,后来经过变种甚至可以达到CNN的作用

具体例子1 Car which.............,() .........。使用RNN可以预测括号里面的内容应该为 is/was.

    2 学习莎士比亚写的诗词,然后进行模仿

    3 你想为朋友的生日创作一段爵士乐,然而,你不会任何乐器、乐理,幸运的是,你了解深度学习并将使用LSTM网络来解决这个问题

二.RNN原理

  1.)RNN单元图(上)和完整结构图(下)以及前向传播

RNN单元理解:

    上一时间t-1隐藏状态与本时刻t的输入xt 乘以权重矩阵Wa,加上一个偏置ba,再使用tanh激活函数得到本时间t得隐藏状态at

    使用本时间的隐藏状态at预测出yt

疑问1:它是如何进行“记忆”的呢?

答:我们称a^t为隐藏状态,由图可知,它是根据X^t计算得到的,也就是说它保留了上一个单元的输入信息,这就是它记忆的原理

疑问2:为什么使用tanh不使用sigmod激活函数呢?(RNN的激活函数除了双曲正切,RELU函数也用的非常多)

答:sigmod导数复杂,使用sigmod函数容易出现梯度消失,(tanh也会有此问题,lstm网络解决此问题)

,                  

  2.)反向传播和损失函数 选用交叉熵(Cross Entropy)

反向传播

pass

损失函数

t时刻的损失值

总损失值

三 RNN的升级

RNN基础版,存在着一些问题, 其中较为严重的是容易出现梯度消失或者梯度爆炸的问题. 注意: 这里的梯度消失主要指由于时间过长而造成记忆值较小的现象,例如Car 和 后面的 距离太远了,网络无法记住

  1.)长短时记忆(Long Short-Term Memory (LSTM))网络                                    参考 https://www.jianshu.com/p/95d5c461924c

我们称Ct为细胞状态

LSTM的理解

  1)第一步决定细胞状态需要丢弃哪些信息

忘记门 Γf?t??=σ(Wf?[a?t−1?,x?t?]+bf?)  使用 sigmod激活函数,向量里面的0-1值表示细胞状态中的哪些信息保留或丢弃多少。0表示不保留,1表示都保留

  2)第二步决定给细胞状态添加哪些新的信息

输入门 Γu?t?=it?=σ(Wu?[a?t−1?,x?t?]+bu?),使用sigmod激活函数,决定更新哪些信息

C~t为新的候选细胞信息(输入门决定选用细胞里面哪些信息)

  3)更新旧的细胞信息,变为新的细胞信息

  4)断输出细胞的哪些状态特征

拿语言模型来举例说明,在预测动词形式的时候,我们需要通过输入的主语是单数还是复数来推断输出门输出的预测动词是单数形式还是复数形式。

  

  2)GRU

pass

四 实例

  1)字符级语言模型 - 恐龙岛

 欢迎来到恐龙岛,恐龙生活于在6500万年前,现在研究人员在试着复活恐龙,而你的任务就是给恐龙命名,如果一只恐龙不喜欢它的名字,它可能会狂躁不安,所以你要谨慎选择。

import numpy as np
import random
import time
import utils

data = open("dinos.txt", "r").read()#读取数据
data = data.lower() #转换为小写字符,类型为 str
chars = list(set(data)) #转换为无序且不重复的元素列表[‘s‘, ‘y‘, ‘m‘.
data_size, vocab_size = len(data), len(chars) #?, 27

#‘a‘:1,‘b‘:2的字典
char_to_ix = {ch: i for i, ch in enumerate(sorted(chars))}
#‘1‘:a,‘2‘:b的字典
ix_to_char = {i: ch for i, ch in enumerate(sorted(chars))}

#梯度修剪
def clip(gradients, maxValue):
    """
    使用maxValue修剪梯度
    :param gradients: 字典类型,包含 dWaa, dWax, dWya,db ,dby
    :param maxValue:  阈值,把梯度限制在[-N,N]
    :return:修剪后的梯度
    """
    #获取参数
    dWaa, dWax, dWya, db, dby = gradients[‘dWaa‘], gradients[‘dWax‘], gradients[‘dWya‘], gradients[‘db‘], gradients[‘dby‘]
    #梯度修剪
    for gradient in  [dWaa, dWax, dWya, db, dby]:
        np.clip(gradient, -maxValue, maxValue,out=gradient)
    gradients = {‘dWaa‘: dWaa, "dWax": dWax, "dWya": dWya, "db": db, "dby": dby}

    return gradients

def text_clip():
    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])

#采样
def sample(paramters, char_to_is, seed):
    """
    根据rnn输出的概率分布序列对字符序列进行采样
    :param paramters: 包含Waa, Wax,Wya,by,b的字典
    :param char_to_is: 字符映射到所以的字典
    :param seed:
    :return: indices -- 包含采样字符索引的长度为n的列表
    """
    #从parameters中获取参数
    Waa, Wax, Wya, by, b =  paramters[‘Waa‘], paramters[‘Wax‘], paramters[‘Wya‘], paramters[‘by‘], paramters[‘b‘]
    vocab_size = by.shape[0]
    n_a = Waa.shape[1]

    #1.创建独热向量x
    x = np.zeros((vocab_size, 1))
    a_prev = np.zeros((n_a, 1))
    indices = []
    idx = -1 #检测换行符的标记,初始化为-1
    #循环遍历时间步骤t
    counter = 0
    newline_character = char_to_ix["\n"]
    while (idx != newline_character and counter < 50):
        a = np.tanh(np.dot(Wax, x) + np.dot(Waa, a_prev) + b)
        z = np.dot(Wya, a) + by
        y = utils.softmax(z)
        #上面前向传播,
        np.random.seed(counter + seed)
        #从概率分布y中抽取词汇表中字符的索引
        idx = np.random.choice(list(range(vocab_size)), p=y.ravel())
        indices.append(idx)
        x = np.zeros((vocab_size, 1))
        x[idx] = 1
        a_prev = a

        seed += 1
        counter += 1
        if(counter == 50):
            indices.append((char_to_ix["\n"]))

    return indices

def text_sample():
    np.random.seed(2)
    _, n_a = 20, 100
    Wax, Waa, Wya = np.random.randn(n_a, vocab_size), np.random.randn(n_a, n_a), np.random.randn(vocab_size, n_a)
    b, by = np.random.randn(n_a, 1), np.random.randn(vocab_size, 1)
    parameters = {"Wax": Wax, "Waa": Waa, "Wya": Wya, "b": b, "by": by}

    indices = sample(parameters, char_to_ix, 0)
    print("Sampling:")
    print("list of sampled indices:", indices)
    print("list of sampled characters:", [ix_to_char[i] for i in indices])

#优化函数
def optimize(X, Y, a_prev, parameters, learning_rate = 0.01):
    """

    :param X: 整个列表,其中每个整数映射到词汇表中的字符
    :param Y: 整数列表,与X相同,但左移动了一个索引
    :param a_prev: 上一个隐藏状态
    :param parameters: 字典,包含了一下参数:
                        Wax -- 权重矩阵乘以输入,dim=(n_a, n_x)
                        Waa -- 权重矩阵乘以隐藏状态,dim = (n_a, n_a)
                        Wya -- 隐藏状态与输出相关的权重偏置
                        b -- 偏置,dim=(n_a,1)
                        by -- 隐藏状态与输出相关的权重偏置,dim=(n_y,1)
    :param learning_rate:
    :return: loss,
             gradients -- 字典,包含了一下参数:
                            dwax:
                            dwaa:
                            dwya:
                            db:
                            dby:
             a[len(X)-1]-- 最后的隐藏状态,dim=(n_a,1)
    """
    #前向传播
    loss, cache = utils.rnn_forward(X, Y, a_prev, parameters)
    #反向传播
    gradients, a = utils.rnn_backward(X, Y, parameters, cache)
    #梯度修剪[-5,5]
    gradients = clip(gradients, 5)
    #更新参数
    parameters = utils.update_parameters(parameters, gradients, learning_rate)

    return loss, gradients, a[len(X)-1]

def text_optimize():
    np.random.seed(1)
    vocab_size, n_a = 27, 100
    a_prev = np.random.randn(n_a, 1)
    Wax, Waa, Wya = np.random.randn(n_a, vocab_size), np.random.randn(n_a, n_a), np.random.randn(vocab_size, n_a)
    b, by = np.random.randn(n_a, 1), np.random.randn(vocab_size, 1)
    parameters = {"Wax": Wax, "Waa": Waa, "Wya": Wya, "b": b, "by": by}
    X = [12, 3, 5, 11, 22, 3]
    Y = [4, 14, 11, 22, 25, 26]

    loss, gradients, a_last = optimize(X, Y, a_prev, parameters, learning_rate=0.01)
    print("Loss =", loss)
    print("gradients[\"dWaa\"][1][2] =", gradients["dWaa"][1][2])
    print("np.argmax(gradients[\"dWax\"]) =", np.argmax(gradients["dWax"]))
    print("gradients[\"dWya\"][1][2] =", gradients["dWya"][1][2])
    print("gradients[\"db\"][4] =", gradients["db"][4])
    print("gradients[\"dby\"][1] =", gradients["dby"][1])
    print("a_last[4] =", a_last[4])

def model(data, ix_to_char, char_to_ix, num_iterations=3500,
          n_a=50, dino_names=7, vocab_size=27):
    """
    下路模型并生成恐龙的名字
    :param data: 语料库
    :param ix_to_char:字符映射索引字典
    :param char_to_ix:
    :param num_iterations:迭代
    :param n_a: RNN单元数
    :param dino_names: 每次迭代中采样的数量
    :param vocab_size: 文本中的唯一字符的数量
    :return:parameters -- 学习后的参数
    """
    n_x, n_y = vocab_size, vocab_size #27? 个字母
    #初始化参数
    parameters = utils.initialize_parameters(n_a, n_x, n_y)
    #初始化损失
    loss = utils.get_initial_loss(vocab_size, dino_names)
    with open("dinos.txt") as f:
        examples = f.readlines()
    examples = [x.lower().strip() for x in examples] #转换成列表

    np.random.seed(0)
    np.random.shuffle(examples) #打乱顺序
    #初始化lstm隐藏状态
    a_prev = np.zeros((n_a, 1))
    #循环
    for j in range(num_iterations):
        index = j % len(examples) #j%1536 共1536个样本
        #print("index = ",index)
        X = [None] + [char_to_ix[ch] for ch in examples[index]]
        Y = X[1:] + [char_to_ix["\n"]] #Y=X[1:]+[0]
        #print("X={}, Y={}".format(X, Y))
        curr_loss, gradients, a_prev = optimize(X, Y, a_prev, parameters)
        loss = utils.smooth(loss, curr_loss)

        if j % 500 == 0:
            print("第" + str(j+1) + "次迭代,损失值为:" + str(loss))

            seed = 0
            for name in range(dino_names):
                #采样
                sampled_indices = sample(parameters, char_to_ix, seed)
                utils.print_sample(sampled_indices, ix_to_char)

                seed += 1
                #print("\n")
    return parameters
def text_model():
    # 开始时间
    start_time = time.perf_counter
    # 开始训练
    parameters = model(data, ix_to_char, char_to_ix, num_iterations=3500)
    # 结束时间
    end_time = time.perf_counter
    # 计算时差
    #minium = end_time - start_time

    #print("执行了:" + str(int(minium / 60)) + "分" + str(int(minium % 60)) + "秒")

text_model()

原文地址:https://www.cnblogs.com/ymzm204/p/12215240.html

时间: 2024-09-28 21:53:30

RNN循环神经网络(Recurrent Neural Network)学习的相关文章

Recurrent Neural Network 学习笔记【二】RNN-LSTM

理论上讲,只要足够大的RNN结构就能去生成任意复杂的序列结构. 但是在实际上,标准的RNN并不能有效的长期保存信息(这是由于类似HMM的结构,每次每个节点的信息如果始终经过同样的变换,那么会要么指数爆炸要么指数衰减,很快信息就会丢失).也是由于它这个“健忘”的特点,这种RNN生成的序列很容易缺乏稳定性.这样的话,如果只能依赖上几步的结果去预测下一步,而又使用预测的新结果去预测再下一步,那么一旦出现了错误,系统就会很容沿着错误的方向走下去,而很少有机会能从之前的信息中把错误改正过来. 从这个角度讲

pytorch --Rnn语言模型 -- 《Recurrent neural network based language model》

论文通过实现RNN来完成了文本分类. 论文地址:88888888 模型结构图: 原理自行参考论文,code and comment: 1 # -*- coding: utf-8 -*- 2 # @time : 2019/11/9 15:12 3 4 import numpy as np 5 import torch 6 import torch.nn as nn 7 import torch.optim as optim 8 from torch.autograd import Variable

《转》循环神经网络(RNN, Recurrent Neural Networks)学习笔记:基础理论

转自 http://blog.csdn.net/xingzhedai/article/details/53144126 更多参考:http://blog.csdn.net/mafeiyu80/article/details/51446558 http://blog.csdn.net/caimouse/article/details/70225998 http://kubicode.me/2017/05/15/Deep%20Learning/Understanding-about-RNN/ RNN

Recurrent Neural Network(循环神经网络)

Reference:   Alex Graves的[Supervised Sequence Labelling with RecurrentNeural Networks] Alex是RNN最著名变种,LSTM发明者Jürgen Schmidhuber的高徒,现加入University of Toronto,拜师Hinton. 统计语言模型与序列学习 1.1 基于频数统计的语言模型 NLP领域最著名的语言模型莫过于N-Gram. 它基于马尔可夫假设,当然,这是一个2-Gram(Bi-Gram)模

RNN循环神经网络学习——概述

循环神经网络(Recurrent Neural NetWork,RNN)是一种将节点定向连接成环的人工神经网络,其内部状态可以展示动态时序行为. 循环神经网络的主要用途是处理和预测序列数据.循环神经网络最初就是为了刻画一个序列当前的输出与之前信息的关系.从网络结构上来看,循环神经网络会记忆之前的信息,并利用之前的信息影响后面节点的输出.也就是说,循环神经网络的隐藏层之间的节点是有连接的,隐藏层的输入不仅包含输入层的输出,还包括上一时刻隐藏层的输出. 如图为典型的RNN结构示意图.RNN主体结构的

Recurrent Neural Network Language Modeling Toolkit代码学习

Recurrent Neural Network Language Modeling Toolkit  工具使用点击打开链接 按照训练的进度学习代码: trainNet()中的结构: step1. learnVocabFromTrainFile() 统计训练文件中所有的单词信息,并对统计好的信息进行整理 涉及的数据结构: vocab_word ocab_hash *int 涉及的函数: addWordToVocab() 对于一个单词w,将其信息存入vocab_word结构的数组中,其结构下标为w

Recurrent neural network (RNN) - Pytorch版

import torch import torch.nn as nn import torchvision import torchvision.transforms as transforms # 配置GPU或CPU设置 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 超参数设置 sequence_length = 28 input_size = 28 hidden_size = 128 num_l

TensorFlow框架(6)之RNN循环神经网络详解

1. RNN循环神经网络 1.1 结构 循环神经网络(recurrent neural network,RNN)源自于1982年由Saratha Sathasivam 提出的霍普菲尔德网络.RNN的主要用途是处理和预测序列数据.全连接的前馈神经网络和卷积神经网络模型中,网络结构都是从输入层到隐藏层再到输出层,层与层之间是全连接或部分连接的,但每层之间的节点是无连接的. 图 11 RNN-rolled 如图 11所示是一个典型的循环神经网络.对于循环神经网络,一个非常重要的概念就是时刻.循环神经网

Recurrent neural network language modeling toolkit 源码走读(六)

系列前言 参考文献: RNNLM - Recurrent Neural Network  Language Modeling Toolkit(点此阅读) Recurrent neural network based language model(点此阅读) EXTENSIONS OF RECURRENT NEURAL NETWORK LANGUAGE MODEL(点此阅读) Strategies for Training Large Scale Neural Network  Language

CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)

CNN(卷积神经网络).RNN(循环神经网络).DNN(深度神经网络)的内部网络结构有什么区别? DNN以神经网络为载体,重在深度,可以说是一个统称.RNN,回归型网络,用于序列数据,并且有了一定的记忆效应,辅之以lstm.CNN应该侧重空间映射,图像数据尤为贴合此场景. DNN以神经网络为载体,重在深度,可以说是一个统称.RNN,回归型网络,用于序列数据,并且有了一定的记忆效应,辅之以lstm.CNN应该侧重空间映射,图像数据尤为贴合此场景. Stanford University CS231