精华内容
下载资源
问答
  • RNN实现文本生成

    2018-12-21 13:03:13
    RNN实现的一个语言模型(实现的是可以自主生成歌词,用的是周杰伦的一些歌词,但由于是自己从网上下来的,前期预处理不是很好,每个人也可以用诗歌等训练,来生成诗歌)
  • RNN实现的matlab代码

    2018-10-16 20:29:48
    基于基本的RNN的Python代码,将其用Matlab实现了,且实验结果比较好
  • RNN实现源码

    2017-04-29 21:45:20
    RNN实现源码
  • 本文实例为大家分享了使用RNN进行文本分类,python代码实现,供大家参考,具体内容如下 1、本博客项目由来是oxford 的nlp 深度学习课程第三周作业,作业要求使用LSTM进行文本分类。和上一篇CNN文本分类类似,本此...
  • 网络安全作业,里面附有说明
  • Johannes 和 Felix 的 RNN 实现的门户以及为 ASR/LVCSR 目的进行的进一步修改。 这只是一个传送门!!!! (目前)该项目由 Johannes Bergmann 和 Felix Weninger 在 SourceForge 开源。 长乐 根据电话识别配方...
  • import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist=input_data.read_data_sets('mnist_data/',one_hot=True) #注意这里用了one_hot表示,标签的形状是(batch_size,num_...
  • 运用RNN网络对影评数据集进行分类

    RNN实现文本分类

    目标:运用RNN网络对影评数据集进行分类

    词向量模型 word2vec

    词向量概述

    一句话很长,由千千万万个词构成,计算机想要明白一句话,就要先认识一个个词,计算机擅长处理什么?是数字啊,所以我们就把“词”转化成一个个数字组成“向量”。我们希望得到一个 大表embedding maxtrix,每个词对应的向量都能找到。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VlfUsBSU-1587818125211)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\0词向量 大表.png)]

    这个词向量不能随便设定的吧,首先需要相近的词汇离得近一点,举个栗子,一个二维向量(a,b)代表一个词。比如“man”这个词在空间中(1,5),boy(1,4),而water(-1,-4),我们看看在坐标系下这些点。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dgLP9v0D-1587818125215)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\1.词向量空间.png)]

    很显然,man和boy离得很近,离water很远。但是二维远远不能满足对一个词的描述,通常情况下,我们用上百维的向量来描述一个词,两个词之间的关联程度用余弦距离或者欧式距离表示。还是这三个词,用更高维度标签,不同颜色代表不同数字范围,对应数字越大表示越深红。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iyZHSV6z-1587818125219)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\2.相近词向量.png)]

    圈出的部分明显可以看出,相似的词是有很大的相似程度的。但是词向量这么多维的数字人为的编造也太麻烦了,我们可以用一个神经网络来构造每个词对应的向量。

    词向量模型

    既然是神经网络,那肯定就要有输入和输出,词不可能单个的蹦出来,一定是有上下文关系的,我们就利用这一点,就可以构建词向量模型的网络啦,假设我们的词向量是一个4维向量。

    举个甜甜的表白词:You are the one I have been looking for. (你就是我一直在追寻的幸福),依次先圈出5个词(滑动窗口),找到中间的词w(t)和这个词的上下文 w(t-2), w(t-1), w(t+1), w(t+2)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HneXCt97-1587818125224)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\3.滑动窗口取词.png)]

    可以将上下文作为输入,中间词作为输出,来判断判断输出这个词是不是上下文所对应的中间词。先建立一个词向量大表embedding,里面有所有词和对应的向量(随机初始化).

    前向传播:根据输入词,找到大表中对应的向量,经过神经网络得到各种词的概率,判断输出是否为中间词。反向传播:不仅更新网络模型,也会更新词向量的大表.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hTKMT1RQ-1587818125231)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\4.词向量模型网络.png)]

    常见有两种模型,CBOW是上下文为输入,中间词的输出。而skip-gram正好相反,但是原理相近。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwNBsiLK-1587818125232)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\5.两模型对比.png)]

    这样虽然可以找到词向量,但是最后的预测概率是一个超多的分类问题,需要的参数可是太多了,那我们能不能简化一点,比较输入和输出是否相邻,那就变成一个二分类问题,是相邻的为1,不是为0,以skip-gram为例。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UgIfg9ds-1587818125236)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\6.1模型转变.png)]

    原先的输入和输出左边,右边是改进后增加target

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mIXYLYl1-1587818125239)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\6.变为标签.png)]

    这样看上去没啥大问题,但是,所有标签全为1啊,并没有0,这样神经网络还学啥,任意两个词都是相邻的了。所以,在这里,我们增加一个负采样,就是人为的创造一些与不相邻的数据,让target为0.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61X3GKwo-1587818125241)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\7.负采样.png)]

    负采样的个数,根据模型而定,滑动窗口的大小和每个窗口取几个值也是根据模型而定,大体的思路就是这样的。总结一下,三大步:

    1.初始化词向量矩阵

    词汇个数:vocabulary_size,每个向量维度vector_size,相当于一个大表,每个词对应向量,这也是最终所需要的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QUPD0Du0-1587818125244)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\8.词向量矩阵.png)]

    2.构建数据

    将文本做滑动窗口处理,找到中间词和上下文对应词向量,比如the用一个4维向量表示,you、are、his等一些词也在词向量表格找到对应4维向量。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DQpVhSBn-1587818125246)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\9.数据库建立.png)]

    3.构建网络更新参数

    通过神经网络返向传播来计算更新,此时不仅更新网络的权重参数矩阵,也会更新词向量矩阵(绿色的4维向量)。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wi9Xg30G-1587818125248)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\10.网络结构.png)]

    模型实现

    1.数据预处理

    构建语料库,根据语料库数目限制和最小词频限制,构建出 47135个词作为语料库。

    max_vocabulary_size = 50000 # 语料库最大词语数
    min_occurrence = 10 # 最小词频
    
    # 读取数据
    data_path = 'text8.zip'
    with zipfile.ZipFile(data_path) as f:
        text_words = f.read(f.namelist()[0]).lower().split()#总共17005207词,我们只选取最常见的
        
    # 创建计数器,从多到少计算词频
    # 第一个词为‘UNK’,文本中不在语料库中的词汇用这个代替
    count = [('UNK', -1)]
    # 基于词频返回max_vocabulary_size个常用词
    count.extend(collections.Counter(text_words).most_common(max_vocabulary_size - 1))
    
    # 剔除掉出现次数少于'min_occurrence'的词
    for i in range(len(count) - 1, -1, -1):
        if count[i][1] < min_occurrence:
            count.pop(i)
        else:
            break
    

    词-ID映射,语料库中每个词给出对应ID,并将文本转化为ID

    # 每个词都分配一个ID
    word2id = dict()
    for i, (word, _)in enumerate(count):
        word2id[word] = i
    
    # 所有词转换成ID
    data = list()
    unk_count = 0
    for word in text_words:
        index = word2id.get(word, 0)
        if index == 0:
            unk_count += 1
        data.append(index)
    count[0] = ('UNK', unk_count)
    # id2word是word2id反映射
    id2word = dict(zip(word2id.values(), word2id.keys()))
    

    文本text_words 根据 word2id 变成了一个个数字索引 data

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oLumluoZ-1587818125251)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\11.word2id转化后.png)]

    构建词向量矩阵,将索引转化维词向量

    embedding_size = 200 # 词向量由200维向量构成
    embedding = tf.Variable(tf.random.normal([vocabulary_size, embedding_size])) #维度:47135, 200
    
    #通过tf.nn.embedding_lookup函数将索引转换成词向量
    def get_embedding(x):
        x_embed = tf.nn.embedding_lookup(embedding, x)
        return x_embed
    

    2.滑动窗口提取数据对

    滑动窗口大小为2*skip_window + 1,即为7,中间的作为输入,左右两边随机选择 num_skips个词作为标签,构成一对数据。

    skip_window = 3 # 左右窗口大小
    num_skips = 2 # 一次制作多少个输入输出对
    batch_size = 128 #一个batch下有128组数据
    

    在一个 batch下取数据,即一次取128组数据对,每个窗口取2组,在128/2个窗口下取即可

    def next_batch(batch_size, num_skips, skip_window):
        global data_index
        assert batch_size % num_skips == 0
        assert num_skips <= 2 * skip_window
        batch = np.ndarray(shape=(batch_size), dtype=np.int32)
        labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
        # 数据窗口为7
        span = 2 * skip_window + 1 
        # 创建队列,长度为7
        buffer = collections.deque(maxlen=span)#创建一个长度为7的队列
        if data_index + span > len(data):#如果文本被滑完,从头再来
            data_index = 0
        # 比如一个队列为deque([5234, 3081, 12, 6, 195, 2, 3134], maxlen=7),数字代表词ID
        buffer.extend(data[data_index:data_index + span])
        data_index += span
        for i in range(batch_size // num_skips):
            context_words = [w for w in range(span) if w != skip_window]#上下文为[0, 1, 2, 4, 5, 6]
            words_to_use = random.sample(context_words, num_skips)#在上下文里随机选2个候选词
            for j, context_word in enumerate(words_to_use):
                batch[i * num_skips + j] = buffer[skip_window]#输入都为当前窗口的中间词,即3
                labels[i * num_skips + j, 0] = buffer[context_word]#标签为当前候选词
            # 窗口右移,如果文本读完,从头再来
            if data_index == len(data):
                buffer.extend(data[0:span])
                data_index = span
            else:
                buffer.append(data[data_index])
                data_index += 1
        data_index = (data_index + len(data) - span) % len(data)
        return batch, labels
    

    3.迭代优化

    计算损失,损失为 nce损失,同时加入负采样。先分别计算出正样本和采样出的负样本对应的输出(0到1之间数字),再通过 sigmoid交叉熵来计算损失。

    num_sampled = 64 # 负采样个数
    # nce权重和偏差
    nce_weights = tf.Variable(tf.random.normal([vocabulary_size, embedding_size]))
    nce_biases = tf.Variable(tf.zeros([vocabulary_size]))
    # 定义nce损失,x_emded为转化为词向量的中间词,y为上下文词
    def nce_loss(x_embed, y):
        with tf.device('/cpu:0'):
            y = tf.cast(y, tf.int64)
            loss = tf.reduce_mean(
                tf.nn.nce_loss(weights=nce_weights,
                               biases=nce_biases,
                               labels=y,
                               inputs=x_embed,
                               num_sampled=num_sampled,
                               num_classes=vocabulary_size))
            return loss
    

    计算梯度,更新 embeddingnce参数

    with tf.GradientTape() as g:
        x, y = next_batch(batch_size, num_skips, skip_window)
        emb = get_embedding(x)
        loss = nce_loss(emb, y)
    
    # 计算梯度
    gradients = g.gradient(loss, [embedding, nce_weights, nce_biases])
    # 更新
    optimizer = tf.optimizers.SGD(learning_rate)
    optimizer.apply_gradients(zip(gradients, [embedding, nce_weights, nce_biases]))
    

    4.验证

    找一些词,看看这个词邻近的词的8个词(计算向量余弦相似度),’‘nine’'很明显,邻近单词都是数字。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXM2NeQ9-1587818125254)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\12.词向量评估.png)]

    5.补充

    大多数情况下,词向量模型不需要我们自己训练,有网上训练好的,直接down下来,但是一些特殊任务有大量特殊词汇,需要自己训练。

    文本分类任务

    整体思路

    • 数据集:一条影评对应一个标签,标签为0/1,消极评价/积极评价
    • 词向量模型:加载训练好的词向量模型。https://nlp.stanford.edu/projects/glove/ 50维词向量
    • 序列网络模型:双向RNN模型进行识别

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3RhO9ddC-1587818125256)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\13.数据集_new.png)]

    将文本以固定长度 max_len截取,每个词转化为id,再转化为词向量,输入RNN网络进行二分类。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9abT4Eto-1587818125259)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\13.整体思路.png)]

    数据准备

    word2id语料表

    根据词频构建语料表,即训练集出现的词

    # 构建语料表,基于词频来进行统计
    counter = Counter()
    with open('./data/train.txt',encoding='utf-8') as f:
        for line in f:
            line = line.rstrip()
            label, words = line.split('\t')
            words = words.split(' ')
            counter.update(words)
    
    # <pad>用作文本补齐,长度不够填充
    words = ['<pad>'] + [w for w, freq in counter.most_common() if freq >= 10]
    print('Vocab Size:', len(words))
    
    # 保存文件
    Path('./vocab').mkdir(exist_ok=True)
    with open('./vocab/word.txt', 'w',encoding='utf-8') as f:
        for w in words:
            f.write(w+'\n')
    

    读取文件并标号得到word2id映射字典

    word2idx = {}
    with open('./vocab/word.txt',encoding='utf-8') as f:
        for i, line in enumerate(f):
            line = line.rstrip()
            word2idx[line] = i
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BCWiHyzB-1587818125262)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\14.word2id字典.png)]

    构建训练数据

    运用数据生成器data_generator生成数据和标签,并运用tf.data.Dataset.from_generator(data_generator,output_data_type,output_data_shape)不断读取

    # 定义生成器
    def data_generator(f_path, params):
        with open(f_path,encoding='utf-8') as f:
            print('Reading', f_path)
            for line in f:
                line = line.rstrip()
                # 标签和文本分别保存
                label, text = line.split('\t')
                text = text.split(' ')
                # 每个词对应id,利用word2id字典查找
                x = [params['word2idx'].get(w, len(word2idx)) for w in text]
                # 文本长度保持一致
                if len(x) >= params['max_len']:#截断操作,max_len = 1000 
                    x = x[:params['max_len']]
                else:
                    x += [0] * (params['max_len'] - len(x))#补齐操作
                y = int(label)
                yield x, y
    

    把数据放入batch中,训练数据加入 shuffle操作

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYr2m2ZD-1587818125264)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\15.训练数据生成.png)]

    词向量模型

    embedding矩阵

    下载词向量表是一个词对应50维向量,但是我们的语料表可能有一部分单词出现在下载向量的表中,没有出现记为 unknown ,找到到训练集语料表每个词索引所对应的向量,即 embedding

    #一个大表,里面有20598个词和一个‘unknown’,每个词有50维向量【20599*50】
    embedding = np.zeros((len(word2idx)+1, 50)) 
    
    with open('./data/glove.6B.50d.txt',encoding='utf-8') as f: #下载的词向量映射
        count = 0
        for i, line in enumerate(f):
            # 提取词和词向量
            line = line.rstrip()
            sp = line.split(' ')
            word, vec = sp[0], sp[1:]
            # 判断词是否出现在我们的语料表中
            if word in word2idx:
                count += 1
                embedding[word2idx[word]] = np.asarray(vec, dtype='float32') #将词转换成对应的向量
    np.save('./vocab/word.npy', embedding)
    

    embedding矩阵为一个 20599*50维度的数组,每行为语料表单词所对应的向量。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ohCdZfj-1587818125267)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\16.embedding表.png)]

    embedding_lookup

    有了embedding矩阵和文本序列的词id,利用 tf.nn.embedding_lookup 就可以将输入的序列转化为序列向量

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bUBDY3Ud-1587818125270)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\17.embedding_look_up.png)]

    词向量模型是整体网络结构中的一层,但是词向量模型不会更新参数。

    序列网络模型

    双向RNN

    RNN从前到后走一遍,得到隐层特征h,双向RNN在实现的时候,再从后到前走一遍,又得到另一组h,两组h拼接一起就是双向RNN的隐层生成

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hndxzunv-1587818125272)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\18.双向RNN.png)]

    实现很简单,只需要封装一个 Bidirectional,比如 self.rnn1 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(params['rnn_units'], return_sequences=True))。这样隐层输出会有 2*rnn_units个隐层特征。

    网络构架

    增加了三层双向RNN网络,每舱网络有200*2维隐层特征,并添加 dropout,最后全连接层。

    改进:

    RNN训练的时候速度很慢,文本长度1000,要1000长度的时间序列以词输入RNN。为了提高速度,利用 reshape,保证一次输入10长度的时间序列输入RNN,再利用 reduce_max将RNN隐层10长度的时间序列压缩维1个长度的序列,再进入下一层RNN,先 reshapereduce_max,这样可以提高运算速度。

    x = tf.reshape(x, (batch_sz*10*10, 10, 50)) #改变尺寸,只有10长度的时间序列输入RNN 
    x = self.drop1(x, training=training)
    x = self.rnn1(x)
    x = tf.reduce_max(x, 1)
    

    训练

    损失:softmax交叉熵

    学习率:学习率随着步长指数下降。decay_lr = tf.optimizers.schedules.ExponentialDecay(params['lr'], 1000, 0.95)

    评估:验证集准确率三次不下降就停止训练。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C07eZrCc-1587818125274)(E:\Tensorflow\0.我的笔记\6.RNN实现文本分类\image\20.训练结果.png)]

    uce_max`,这样可以提高运算速度。

    x = tf.reshape(x, (batch_sz*10*10, 10, 50)) #改变尺寸,只有10长度的时间序列输入RNN 
    x = self.drop1(x, training=training)
    x = self.rnn1(x)
    x = tf.reduce_max(x, 1)
    

    训练

    损失:softmax交叉熵

    学习率:学习率随着步长指数下降。decay_lr = tf.optimizers.schedules.ExponentialDecay(params['lr'], 1000, 0.95)

    评估:验证集准确率三次不下降就停止训练。

    [外链图片转存中...(img-C07eZrCc-1587818125274)]

    在这里插入图片描述

    展开全文
  • 一个简单的RNN实现

    千次阅读 2018-09-05 15:42:33
    一、RNN与CNN的区别 CNN是在空间上的共享,而RNN是在时序上的共享;RNN采用的是时序数据,输入的数据存在先后顺序关系; 二、RNN网络模型 在RNN结构中与传统的前馈神经网络不同,其存在记忆效应,这种记忆使得...

     

    一、RNN与CNN的区别

    CNN是在空间上的共享,而RNN是在时序上的共享;RNN采用的是时序数据,输入的数据存在先后顺序关系;

    二、RNN网络模型

    在RNN结构中与传统的前馈神经网络不同,其存在记忆效应,这种记忆使得神经网络可以对上下文进行分析,显示的表示其对时间的依赖性:

    这种对时间的依赖产生了混沌效应。

    RNN模型的数学表示为:

    上面形成一个简单的RNN层,将整个函数简化为:

    对于多层RNN模型,则将y继续作为输入:

    三、利用TensorFlow实现简单的RNN

    import os
    import numpy as np
    import tensorflow as tf
    
    n_inputs = 3
    n_units = 5
    batch_size = 4
    
    x0 = tf.placeholder(tf.float32,[None,n_inputs])
    x1 = tf.placeholder(tf.float32,[None,n_inputs])
    
    cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_units)
    init_state = cell.zero_state(batch_size,dtype=tf.float32)
    outputs,states = tf.nn.static_rnn(cell,[x0,x1],initial_state=init_state)
    
    h0,h1 = outputs
    
    init = tf.global_variables_initializer()
    
    x0_batch = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]) # t = 0
    x1_batch = np.array([[9, 8, 7], [0, 0, 0], [6, 5, 4], [3, 2, 1]]) # t = 1
    
    with tf.Session() as sess:
        sess.run(init)
        h0_val, h1_val = sess.run([h0, h1], feed_dict={x0: x0_batch, x1: x1_batch})
    
    
    print("the output of h0_val are")
    print(h0_val)

    对比代码:

    import os
    import numpy as np
    import tensorflow as tf
    
    # unroll RNN manually
    n_inputs = 3
    n_units = 5
    
    x0 = tf.placeholder(tf.float32, [None, n_inputs])
    x1 = tf.placeholder(tf.float32, [None, n_inputs])
    
    Wx = tf.Variable(tf.random_normal([n_inputs, n_units], dtype=tf.float32), name="Wx")
    Wh = tf.Variable(tf.random_normal([n_units, n_units], dtype=tf.float32), name="Wh")
    b = tf.Variable(tf.zeros([n_units,], dtype=tf.float32), name="b")
    
    h0 = tf.tanh(tf.matmul(x0, Wx) + b)
    h1 = tf.tanh(tf.matmul(x1, Wx) + tf.matmul(h0, Wh) + b)
    
    init = tf.global_variables_initializer()
    
    x0_batch = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]) # t = 0
    x1_batch = np.array([[9, 8, 7], [0, 0, 0], [6, 5, 4], [3, 2, 1]]) # t = 1
    
    with tf.Session() as sess:
        sess.run(init)
        h0_val, h1_val = sess.run([h0, h1], feed_dict={x0: x0_batch, x1: x1_batch})
    
    print("the output of h0_val are")
    print(h0_val)
    
    print("the output of h1_val are")
    print(h1_val)

     

    展开全文
  • 使用pytorch框架nn.RNN实现循环神经网络 首先,读取周杰伦专辑歌词数据集。 import time import math import numpy as np import torch from torch import nn, optim import torch.nn.functional as F import sys ...

    使用pytorch框架nn.RNN实现循环神经网络

    首先,读取周杰伦专辑歌词数据集。

    import time
    import math
    import numpy as np
    import torch
    from torch import nn, optim
    import torch.nn.functional as F
    
    import sys
    sys.path.append("..") 
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    def load_data_jay_lyrics():
        """加载周杰伦歌词数据集"""
        with zipfile.ZipFile('../../data/jaychou_lyrics.txt.zip') as zin:
            with zin.open('jaychou_lyrics.txt') as f:
                corpus_chars = f.read().decode('utf-8')
        corpus_chars = corpus_chars.replace('\n', ' ').replace('\r', ' ')
        corpus_chars = corpus_chars[0:10000]
        idx_to_char = list(set(corpus_chars))
        char_to_idx = dict([(char, i) for i, char in enumerate(idx_to_char)])
        vocab_size = len(char_to_idx)
        corpus_indices = [char_to_idx[char] for char in corpus_chars]
        return corpus_indices, char_to_idx, idx_to_char, vocab_size
        
    (corpus_indices, char_to_idx, idx_to_char, vocab_size) = load_data_jay_lyrics()
    

    定义模型

    PyTorch中的nn模块提供了循环神经网络的实现。下面构造一个含单隐藏层、隐藏单元个数为256的循环神经网络层rnn_layer:

    num_hiddens = 256
    # rnn_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens) # 已测试
    rnn_layer = nn.RNN(input_size=vocab_size, hidden_size=num_hiddens)
    

    这里rnn_layer的输入形状为(时间步数, 批量大小, 输入个数)。

    • 其中输入个数即one-hot向量长度(词典大小)。
    • rnn_layer作为nn.RNN实例,在前向计算后会分别返回输出和隐藏状态h
      • 其中输出指的是隐藏层在各个时间步上计算并输出的隐藏状态,它们通常作为后续输出层的输入。该“输出”本身并不涉及输出层计算,形状为(时间步数, 批量大小, 隐藏单元个数)
      • nn.RNN实例在前向计算返回的隐藏状态指的是隐藏层在最后时间步的隐藏状态:当隐藏层有多层时,每一层的隐藏状态都会记录在该变量中;
      • 对于像长短期记忆(LSTM),隐藏状态是一个元组(h, c),即hidden state和cell state。

    循环神经网络(LSTM)的输出如下:
    在这里插入图片描述
    输出形状为(时间步数, 批量大小, 隐藏单元个数),隐藏状态h的形状为(层数, 批量大小, 隐藏单元个数)。

    num_steps = 35
    batch_size = 2
    state = None
    X = torch.rand(num_steps, batch_size, vocab_size)
    Y, state_new = rnn_layer(X, state)
    print(Y.shape, len(state_new), state_new[0].shape)
    

    输出:

    torch.Size([35, 2, 256]) 1 torch.Size([2, 256])
    

    如果rnn_layer是nn.LSTM实例,继承Module类来定义一个完整的循环神经网络。

    • 它首先将输入数据使用one-hot向量表示后输入到rnn_layer中
    • 然后使用全连接输出层得到输出。
    • 输出个数等于词典大小vocab_size。
    def one_hot(x, n_class, dtype=torch.float32): 
        # X shape: (batch), output shape: (batch, n_class)
        x = x.long()
        res = torch.zeros(x.shape[0], n_class, dtype=dtype, device=x.device)
        res.scatter_(1, x.view(-1, 1), 1)
        return res
        
    def to_onehot(X, n_class):  
        # X shape: (batch, seq_len), output: seq_len elements of (batch, n_class)
        return [one_hot(X[:, i], n_class) for i in range(X.shape[1])]
        
    class RNNModel(nn.Module):
        def __init__(self, rnn_layer, vocab_size):
            super(RNNModel, self).__init__()
            self.rnn = rnn_layer
            self.hidden_size = rnn_layer.hidden_size * (2 if rnn_layer.bidirectional else 1) 
            self.vocab_size = vocab_size
            self.dense = nn.Linear(self.hidden_size, vocab_size)
            self.state = None
    	
        def forward(self, inputs, state): # inputs: (batch, seq_len)
            # 获取one-hot向量表示
            X = to_onehot(inputs, self.vocab_size) # X是个list
            Y, self.state = self.rnn(torch.stack(X), state)
            # 全连接层会首先将Y的形状变成(num_steps * batch_size, num_hiddens),它的输出
            # 形状为(num_steps * batch_size, vocab_size)
            output = self.dense(Y.view(-1, Y.shape[-1]))
            return output, self.state
    

    训练模型

    定义一个预测函数

    def predict_rnn_pytorch(prefix, num_chars, model, vocab_size, device, idx_to_char,
                          char_to_idx):
        state = None
        output = [char_to_idx[prefix[0]]] # output会记录prefix加上输出
        for t in range(num_chars + len(prefix) - 1):
            X = torch.tensor([output[-1]], device=device).view(1, 1)
            if state is not None:
                if isinstance(state, tuple): # LSTM, state:(h, c)  
                    state = (state[0].to(device), state[1].to(device))
                else:   
                    state = state.to(device)
                
            (Y, state) = model(X, state)
            if t < len(prefix) - 1:
                output.append(char_to_idx[prefix[t + 1]])
            else:
                output.append(int(Y.argmax(dim=1).item()))
        return ''.join([idx_to_char[i] for i in output])
    

    使用权重为随机值的模型来预测一次。

    model = RNNModel(rnn_layer, vocab_size).to(device)
    predict_rnn_pytorch('分开', 10, model, vocab_size, device, idx_to_char, char_to_idx)
    

    实现训练函数

    def data_iter_consecutive(corpus_indices, batch_size, num_steps, device=None):
        if device is None:
            device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        corpus_indices = torch.tensor(corpus_indices, dtype=torch.float32, device=device)
        data_len = len(corpus_indices)
        batch_len = data_len // batch_size
        indices = corpus_indices[0: batch_size*batch_len].view(batch_size, batch_len)
        epoch_size = (batch_len - 1) // num_steps
        for i in range(epoch_size):
            i = i * num_steps
            X = indices[:, i: i + num_steps]
            Y = indices[:, i + 1: i + num_steps + 1]
            yield X, Y
    
    def grad_clipping(params, theta, device):
        norm = torch.tensor([0.0], device=device)
        for param in params:
            norm += (param.grad.data ** 2).sum()
        norm = norm.sqrt().item()
        if norm > theta:
            for param in params:
                param.grad.data *= (theta / norm)
                
    def train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                    corpus_indices, idx_to_char, char_to_idx,
                                    num_epochs, num_steps, lr, clipping_theta,
                                    batch_size, pred_period, pred_len, prefixes):
        loss = nn.CrossEntropyLoss()
        optimizer = torch.optim.Adam(model.parameters(), lr=lr)
        model.to(device)
        state = None
        for epoch in range(num_epochs):
            l_sum, n, start = 0.0, 0, time.time()
            data_iter = data_iter_consecutive(corpus_indices, batch_size, num_steps, device) # 相邻采样
            for X, Y in data_iter:
                if state is not None:
                    # 使用detach函数从计算图分离隐藏状态, 这是为了
                    # 使模型参数的梯度计算只依赖一次迭代读取的小批量序列(防止梯度计算开销太大)
                    if isinstance (state, tuple): # LSTM, state:(h, c)  
                        state = (state[0].detach(), state[1].detach())
                    else:   
                        state = state.detach()
        
                (output, state) = model(X, state) # output: 形状为(num_steps * batch_size, vocab_size)
                
                # Y的形状是(batch_size, num_steps),转置后再变成长度为
                # batch * num_steps 的向量,这样跟输出的行一一对应
                y = torch.transpose(Y, 0, 1).contiguous().view(-1)
                l = loss(output, y.long())
                
                optimizer.zero_grad()
                l.backward()
                # 梯度裁剪
                grad_clipping(model.parameters(), clipping_theta, device)
                optimizer.step()
                l_sum += l.item() * y.shape[0]
                n += y.shape[0]
            
            try:
                perplexity = math.exp(l_sum / n)
            except OverflowError:
                perplexity = float('inf')
            if (epoch + 1) % pred_period == 0:
                print('epoch %d, perplexity %f, time %.2f sec' % (
                    epoch + 1, perplexity, time.time() - start))
                for prefix in prefixes:
                    print(' -', predict_rnn_pytorch(
                        prefix, pred_len, model, vocab_size, device, idx_to_char,
                        char_to_idx))
    
    num_epochs, batch_size, lr, clipping_theta = 250, 32, 1e-3, 1e-2 # 注意这里的学习率设置
    pred_period, pred_len, prefixes = 50, 50, ['分开', '不分开']
    train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
    
    展开全文
  • 循环神经网络(Recurrent Neural Network,RNN) 现实生活中,我们输入的向量往往存在着前后联系,即前一个输入和后一个输入是有关联的,比如文本,语音,视频等,因此,我们需要了解深度学习中的另一类重要的神经网络...

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

    现实生活中,我们输入的向量往往存在着前后联系,即前一个输入和后一个输入是有关联的,比如文本,语音,视频等,因此,我们需要了解深度学习中的另一类重要的神经网络,那就是循环神经网络(Recurrent Neural Network,RNN).
    循环神经网络(Recurrent Neural Network,RNN)依赖于一个重要的概念:序列(Sequence),即输入的向量是一个序列,存在着前后联系。简单RNN的结构示意图如下:
    在这里插入图片描述
    RNN的结构中有自循环部分,即W所在的圆圈,这是RNN的精华所在,它展开后的结构如下:
    在这里插入图片描述
    对于t时刻的输出向量 o t o_{t} ot,它的输出不仅仅依赖于t时刻的输入向量 x t x_{t} xt,还依赖于 t − 1 t-1 t1时刻的隐藏层向量 s t − 1 s_{t-1} st1,以下是输出向量 o t o_{t} ot的计算公式:

    s t = f ( U x t + W s t − 1 ) s_{t}=f(Ux_{t}+Ws_{t-1}) st=f(Uxt+Wst1)

    o t = g ( V s t ) o_{t}=g(Vs_{t}) ot=g(Vst)

    其中,第二个式子为输出层的计算公式,输出层为全连接层, V V V为权重矩阵, g g g为激活函数。第一个式子中, U U U是输入 x x x的权重矩阵, W W W是上一次隐藏层值 s s s的输入权重矩阵, f f f为激活函数。注意到,RNN的所有权重矩阵 U , V , W U,V,W U,V,W是共享的,这样可以减少计算量。
    接下来用TensorFlow中已经帮我们实现好的RNN基本函数tf.contrib.rnn.BasicRNNCell(), tf.nn.dynamic_rnn()来实现简单RNN,并且用该RNN来识别MNIST数据集。

    RNN识别MNIST数据集

    RNN要求输入的向量是序列,那么,如何把图片看成是序列呢?
    图片的大小为28*28,我们把每一列向量看成是某一时刻的向量,那么每张图片就是一个序列,里面含有28个向量,每个向量含有28个元素,如下:

    在这里插入图片描述

    # -*- coding: utf-8 -*-
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    
    # 获取MNIST数据
    mnist = input_data.read_data_sets(r"./MNIST_data", one_hot=True)
    
    # 设置RNN结构
    element_size = 28
    time_steps = 28
    num_classes = 10
    batch_size = 128
    hidden_layer_size = 150
    
    # 输入向量和输出向量
    _inputs = tf.placeholder(tf.float32, shape=[None, time_steps, element_size], name='inputs')
    y = tf.placeholder(tf.float32, shape=[None, num_classes], name='inputs')
    
    # 利用TensorFlow的内置函数BasicRNNCell, dynamic_rnn来构建RNN的基本模块
    rnn_cell = tf.contrib.rnn.BasicRNNCell(hidden_layer_size)
    outputs, _ = tf.nn.dynamic_rnn(rnn_cell, _inputs, dtype=tf.float32)
    Wl = tf.Variable(tf.truncated_normal([hidden_layer_size, num_classes], mean=0,stddev=.01))
    bl = tf.Variable(tf.truncated_normal([num_classes],mean=0,stddev=.01))
    
    def get_linear_layer(vector):
        return tf.matmul(vector, Wl) + bl
    
    # 取输出的向量outputs中的最后一个向量最为最终输出
    last_rnn_output = outputs[:,-1,:]
    final_output = get_linear_layer(last_rnn_output)
    
    # 定义损失函数并用RMSPropOptimizer优化
    softmax = tf.nn.softmax_cross_entropy_with_logits(logits=final_output, labels=y)
    cross_entropy = tf.reduce_mean(softmax)
    train_step = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cross_entropy)
    
    # 统计准确率
    correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(final_output,1))
    accuracy = (tf.reduce_mean(tf.cast(correct_prediction, tf.float32)))*100
    
    sess=tf.InteractiveSession()
    sess.run(tf.global_variables_initializer())
    # 测试集
    test_data = mnist.test.images[:batch_size].reshape((-1, time_steps, element_size))
    test_label = mnist.test.labels[:batch_size]
    
    # 每次训练batch_size张图片,一共训练3000次
    for i in range(3001):
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        batch_x = batch_x.reshape((batch_size, time_steps, element_size))
        sess.run(train_step, feed_dict={_inputs:batch_x, y:batch_y})
        if i % 100 == 0:
            loss = sess.run(cross_entropy, feed_dict={_inputs: batch_x, y: batch_y})
            acc = sess.run(accuracy, feed_dict={_inputs:batch_x, y: batch_y})
            print ("Iter " + str(i) + ", Minibatch Loss= " + \
                   "{:.6f}".format(loss) + ", Training Accuracy= " + \
                   "{:.5f}".format(acc))
    
    # 在测试集上的准确率
    print("Testing Accuracy:", sess.run(accuracy, feed_dict={_inputs:test_data, y:test_label}))
    

    在这里插入图片描述

    展开全文
  • ML(四)——RNN实现MNIST的识别

    千次阅读 2018-09-21 16:20:52
    什么是RNN RNN的理解相较与CNN有一定的难度,本文不做RNN原理的讲解,我贴一个写的非常好的RNN讲解的博客,有兴趣的朋友可以去这里学习了解下:https://www.zybuluo.com/hanbingtao/note/541458 有关LSTM的了解,...
  • pytorch RNN实现分类

    千次阅读 2019-07-06 15:56:34
    #将上一次迭代结果的hidden作为下一次迭代的输入实现RNN的思想 loss = criterion ( output , category_tensor ) loss . backward ( ) # Add parameters' gradients to their values, multiplied by ...
  • 循环核(记忆体):循环核具有记忆力,通过不同时刻的参数共享,实现了对时间序列的信息提取。 循环核:可以设置记忆体的个数改变记忆容量。当记忆容量、输入xt、输出yt维度被指定,周围这些待训练参数的维度也就被...
  • 这篇文章主要详细介绍的RNN的原理。由于看到CRNN这块,想着把RNN也好好看看,所以留下第五系列的坑,以后有时间再填吧。。。 目录 1、基于Python的RNN实践 2、加载数据集 3、RNN网络模型 3.1、前向传播 3.2、...
  • 一、RNN结构  这是一个标准的RNN结构图,图中每个箭头代表做一次变换,也就是说箭头连接带有权值。左侧是折叠起来的样子,右侧是展开的样子,左侧中h旁边的箭头代表此结构中的“循环“体现在隐层。  在展开结构...
  • 基于RNN实现古诗词生成模型-附件资源
  • 最近再看一些量化交易相关的材料,偶然在网上看到了一个关于用RNN实现股票预测的文章,出于好奇心把文章中介绍的代码在本地跑了一遍,发现可以work。于是就花了两个晚上的时间学习了下代码,顺便把核心的内容翻译成...
  • Pytorch 实现RNN分类.zip

    2021-01-22 15:40:18
    Pytorch 实现RNN分类
  • 1.使用单向RNN 建立输入层,RNN层和输出层 n_steps * n_inputs = 28 * 28,读取的单位是图片中的一行像素 输入数据:x=[batch_size,n_steps,n_inputs] 输出数据:y=[batch_size,n_classes] 输入层: 输入数据:x=...
  • RNN实现影评情感分析

    千次阅读 2018-08-15 13:38:19
    在这里我们将使用RNN(循环神经网络)对电影评论进行情感分析,结果为positive或negative,分别代表积极和消极的评论。至于为什么使用RNN而不是普通的前馈神经网络,是因为RNN能够存储序列单词信息,得到的结果更为...
  • [Keras深度学习浅尝]实战二·RNN实现Fashion MNIST 数据集分类 与我们上篇博文[Keras深度学习浅尝]实战一结构相同,修改的地方有,定义网络与模型训练两部分,可以对比着来看。通过使用RNN结构,预测准确率略有提升...
  • RNN实现mnist手写数字识别,使用pytorch中自带的LSTM、RNN、GRU模型进行训练,准确率最后还挺不错的,经典数据集练手,你值得一试。
  • PyTorch 使用RNN实现MNIST手写字体识别

    千次阅读 2019-01-24 23:50:36
    此处使用普通的RNN 推荐一个RNN入门资料:https://zhuanlan.zhihu.com/p/28054589 28*28的图片,每个输入序列长度(seq_len)为28,每个输入的元素维度(input_size)为28,将一张图片的分为28列,为长度28的序列,...
  • input_dim = 2 #输入数据的维度,程序是实现两个数相加的 hidden_dim = 16 #隐藏层神经元个数=16 output_dim = 1 #输出结果值是1维的 # initialize neural network weights #初始化神经网络的权重参数 synapse_0 =...
  • 基于RNN实现古诗词生成模型

    千次阅读 2018-12-11 17:19:52
    我们知道,RNN(循环神经网络)模型是基于当前的状态和当前的输入来对下一时刻做出预判。而LSTM(长短时记忆网络)模型则可以记忆距离当前位置较远的上下文信息。 在此,我们根据上述预判模型来进行 古诗词的生成...
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 ... 背景知识最近再看一些量化交易相关的材料,偶然在网上看到了一个关于用RNN实现股票预测的文章,出于好奇...
  • 官僚 基于ocropus的纯javascript lstm rnn实现

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,087
精华内容 16,034
关键字:

rnn实现