精华内容
下载资源
问答
  • 循环神经网络实现语言模型循环神经网络裁剪梯度困惑度实现 循环神经网络 目的是基于当前的输入与过去的输入序列,预测序列的下一个字符。循环神经网络中引入一个隐含层HHH,用HtH_tHt​表示HHH在时间步ttt的值。HtH_...
  • 一、时序数据 卷积神经网络是针对二维位置...对于按时间轴不停产生的信号,神经网络中,我们称其为temporal signals,而循环神经网络处理的就是拥有时序相关或者前后相关的数据类型(Sequence)。 二、embeddin...

    一、时序数据

    卷积神经网络是针对二维位置相关的图片,它采取权值共享的思想,使用一个滑动的窗口去提取每一个位置相关的信息,自然界除了位置相关的信息以外,还存在另一种跟时序相关的数据类型,例如:序列信号,语音信号。对于按时间轴不停产生的信号,神经网络中,我们称其为temporal signals,而循环神经网络处理的就是拥有时序相关或者前后相关的数据类型(Sequence)。

    二、embedding数据类型转换

    计算机是无法处理时序数据的,所以,我们必须把这些时序数据转化成数值类型,以文本为例,文字和数值之间并没有一一对应的关系,而且,文字之间还有语义关系,没有大小关系,要是我们能找到一种表示方法能很好的表达文字之间的语义关系,那么用于训练或者分类就会很有帮助,而我们把这一转化过程统称为embedding。

    在循环神经网络中,我们通常用下面的格式进行表示训练数据:

                                                                      [ b, seq_len, fearture_len ]

    b:一个批次的大小。seq_len:时序数据的长度(一句话有seq_len个单词,一段录音有seq_len时刻等)。fearture_len:对于每一个seq_len,我们用多少纬度来表示(一个单词,我们可以用长度为4的向量表示)

    例如: 

    我喜欢你  =====》[ 1, 4, 4 ]: 只有一句话,所以b=1,这句话有4个汉字,所以seq_len=4,每个汉字,我们用一个4纬的向量表示,所以,fearture_len=4。同理,对于一段长达10秒的语音信号,我们可以这样表示为 [ 1, 10, 10 ]。

    备注:在本篇博文中,我们只讨论文本处理即word embedding,对于语言序列不给予过多讨论。

    三、word embedding

    文本的转换不仅仅是逻辑上的转换,或者简单的一对一关系,其中还要包括语义上的转换。所以,word embedding需要满足一下两个条件:

    1)语义相关。

    单词在语义空间的相似度需要在数值空间表现出来(可利用位置距离或者概率表示),例如:输入king这个单词的话,那么在语义空间中和king相关的所有词都必须在数值空间中,与king的位置靠近(距离的远近代表着相关的程度)。

    2)可训练。

    下面,我们将利用layers简单的实现一次word embedding过程:

    数据:I love it   ====》[ 1, 3, 4 ]

    第一步:为三个单词设置一个编号。

    第二步:调用layers的embedding接口,创建一个embedding层,并设置这个层的纬度。

    第三步:把x输入embedding层中,embedding层就会为x随机初始化一个tensor对象

    当前的embedding结果是不符合要求的,我们会通过后续训练去优化embedding。

    四、循环神经网络

    通过word embedding,我们可以把句子中的所有单词数值化后,映射到向量空间中去,为了得到最佳的word embedding结果,我们会把数值化的单词输入全连接网络中进行训练,具体如下:

                                             

    每一个单词都输入到单独的全连接层中,得到的结果用于对情感的划分,但是,当句子过长时,其网络的层数和参数都会成直线上升,而且,当我们变换句子顺序时,其输出结果不变,即没有保留上下之间的语境信息。

    针对参数上述问题,我们提出权重共享的思想,即每一个全连接层共享同一个w和b:

                                      

    针对语义信息,由于现有网络没有全局的综合的高层的语义信息抽取过程,所以,我们需要一个全局的数据去存储整个句子的语义信息,即需要一个容器去存储从第一个单词到最后一个单词的总体语义信息,该容器被称为memory。

     

                                                            如上图所示,h0为初始memory,h1~h5是每一层输出的memory,后一层利用下面的公式会用到前一层的语境信息,

                                                                                h_2=x@w_x + h_1@w_h_h

    所以最后一层就拥有了全局的语境信息,最后,我们可以利用这个全局的语境信息去做分类。

     通过观察上图中的全连接层,我们发现每一个全连接层的结构都是一样的(都是x@w_x + h_t@w_h_h形式),所以,我们把这些全连接层折叠起来就成了RNN循环神经网络了。具体公式如下:

                                                   

    备注:在RNN中,激活函数通常用thah(),ht为t时刻的memory,yt表示RNN在循环完毕后,利用一个全连接层汇总RNN中提取的高维特征,用于最终结果的分类。

    五、RNN的可训练性

    所有神经网络结构,都需要能进行反向梯度更新,那么,RNN是怎么求解梯度的呢?首先,我们把RNN网络按时间轴进行展开:

                                                             

    RNN公式:           h_t =tanh(W_I_x +W_Rh_t_-_1)                        y_t=W_0h_t

    loss函数:            losee = MSE(y,x)

    我们对W_R进行求导:

                                                         \frac{\partial E_t}{\partial W_R} = \sum_{i=0}^{t}{\frac{\partial E_t}{\partial y_t}\frac{\partial y_t}{\partial h_t}\frac{\partial h_t}{\partial h_i}\frac{\partial h_i}{\partial W_R}}

    假设t=1,则:

                                            \frac{\partial E_1}{\partial W_R} = \frac{\partial E_1}{\partial y_1}\frac{\partial y_1}{\partial h_1}\frac{\partial h_1}{\partial h_0}\frac{\partial h_0}{\partial W_R}

    假设t=2,则:

                                          \frac{\partial E_2}{\partial W_R} =\frac{\partial E_1}{\partial y_1}\frac{\partial y_1}{\partial h_1}\frac{\partial h_1}{\partial h_0}\frac{\partial h_0}{\partial W_R} + \frac{\partial E_2}{\partial y_2}\frac{\partial y_2}{\partial h_2}\frac{\partial h_2}{\partial h_1}\frac{\partial h_1}{\partial h_0}\frac{\partial h_0}{\partial W_R}

    我们可以发现,由于\frac{\partial E_t}{\partial y_t},\frac{\partial y_t}{\partial h_t},\frac{\partial h_i}{\partial W_R}是已知的,所以可以直接求解导数,但是\frac{\partial h_t}{\partial h_i}是未知的,我们把\frac{\partial h_t}{\partial h_i}进行展开可得:

                                                               \frac{\partial h_t}{\partial h_i} = \frac{\partial h_t}{\partial h_t_{-1}}\frac{\partial h_t_{-1}}{\partial h_t_{-2}}.....\frac{\partial h_i_{+1}}{\partial h_i}=\prod ^{t-1}_{k-i}\frac{\partial h_k_{+1}}{\partial h_k}

    利用RNN公式可得:

                                                                \frac{\partial h_k_{+1}}{\partial h_k}=diag(f(W_I_{xi}+W_R_{h_i-1})) W_R

    则求1到k时刻的梯度为:

                                                                 \frac{\partial h_k}{\partial h_1} =\prod ^{k}_{i}diag(f(W_I_{xi}+W_R_{h_i-1})) W_R

    所以,\frac{\partial h_t}{\partial h_i}也是可求的,这里提示一下,k时刻会得到{W_R}的k次方,这一项会导致RNN很容易出现梯度弥散或者梯度爆炸。

    六、RNN训练时数据纬度的变化

    本小节,博主将详细叙述在一次word embedding的循环网络训练过程中,其内部数据纬度的变化。

    第一步:输入一个批次的训练数据集  [ b, seq_len, fearture_len ] = [ 128, 80, 100 ],由于seq_len是句子的长度,而一次RNN网络处理的是一个单词,所以,我们按seq_len进行展开,则数据纬度变成:[ b, fearture_len ] = [ 128, 100 ]。

    第二步:根据公式h_2=x@w_x + h_1@w_h_h可得:

                            h = [b,feature_len]@[fearture_len, hidden_len] + [b, hidden_len]@[bidden_len, hidden_len]

    则[fearture_len, hidden_len] = [ 100, 64],[b, hidden_len]=[128, 64],[bidden_len, hidden_len]=[64,64],这样我们就可以把[b, 100]纬度的数据降纬到[ b, 64 ]。

    实战部分

    七、IMDB数据集简介

     IMDB数据集包含了50000条偏向明显的电影评论,其中25000条作为训练集,25000作为测试集,其标签只有pos/neg两种,属于二分类问题,这里给出网上收集到的百度云下载链接:

    链接:https://pan.baidu.com/s/1jcAZiGy0zeo9VjUKBDLZHA    

    提取码:3aka 

    八、代码讲解

    本实战分部分主要是使用两层的SimpleRNNCell实现对IMDB数据集的训练。在下一章里,我们将使用层的方式和LSTM以及GRU方式实现对IMDB数据集的训练。之所以选择使用SimpleRNNCell来实现,主要是为了向大家讲解RNN的原理,希望能帮助到大家。

    第一行代码:利用Tensorflow提供的接口加载数据集,在加载的同时,设置网络识别单词的最大个数(num_words),因为英语单词至少有5万多个,网络不可能把所有单词都记住,而且我们日常使用的也很少,所以,当设置total_words=10000时,代表的意思是,网络只对10000个不同单词进行编码。对于超过10000的单词用同一个特殊符号表示。

    后两行代码:设置句子的长度,因为,句子的长度会直接影响到RNN的循环次数,所以,为了训练方便,我们会把句子进行截断成相同长度,例如:maxlen=80,代表着训练数据中的句子都会变成80个单词,多的舍去,少的补零。

    构建dataset对象,并设置每一个Batch的大小,drop_remainder=True的意思是当数据不足以构成一个Batch时,舍去。

     

    下面是模型构建中的代码

    由于我们使用的是两层RNN,每一层都需要一个初始memory。units表示RNN影藏层的纬度,本次实战设置为64,

    构建两层简单的Cell,并启用dropout功能。

    这是RNN循环完毕后的全连接层,输出一个结果。下面给出自定义层的完整代码

    把输入的训练数据进行一次embedding操作,并设置两个memory的初始状态。

    把seq_len纬度进行展开,把结果传入SimpleRNNCell中,得到每一层的输出值和memory。

    把循环后的结果放入全连接层中,并利用sigmoid函数进行缩放。下面给出自定义模型的完整代码

    下面给出整体代码:

    import os
    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers
    import numpy as np
    import time
    
    os.environ["TF_CPP_MIN_LOG_LEVEL"] = '2'
    
    total_words = 10000
    max_review_len = 80
    batchsz = 128
    embedding_len = 100
    
    (x_train, y_train) , (x_test, y_test) = keras.datasets.imdb.load_data(num_words = total_words)
    x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen = max_review_len)
    x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen = max_review_len)
    
    db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
    db_train = db_train.shuffle(1000).batch(batchsz, drop_remainder=True)
    db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
    db_test = db_test.shuffle(1000).batch(batchsz, drop_remainder=True)
    
    print('x_train shape:', x_train.shape, tf.reduce_max(y_train), tf.reduce_min(y_train))
    print('x test shape:', x_test.shape)
    
    class MyRnn(keras.Model):
    
        def __init__(self, units):
            super(MyRnn,self).__init__()
    
            self.state0 = [tf.zeros([batchsz, units])]
            self.state1 = [tf.zeros([batchsz, units])]
    
            self.embedding = layers.Embedding(total_words, embedding_len,
                                              input_length = max_review_len)
    
            self.rnn_cell0 = layers.SimpleRNNCell(units, dropout=0.2)
            self.rnn_cell1 = layers.SimpleRNNCell(units, dropout=0.2)
    
            self.outlayer = layers.Dense(1)
    
        def call(self, inputs, training=None):
    
            x = self.embedding(inputs)
    
            state0 = self.state0
            state1 = self.state1
            for word in tf.unstack(x, axis=1):
                out0, state0 = self.rnn_cell0(word, state0, training)
                out1, state1 = self.rnn_cell1(out0, state1)
    
            x = self.outlayer(out1)
    
            prob = tf.sigmoid(x)
    
            return prob
    
    def main():
        units = 64
        epoch = 4
        start_time = time.time()
        model = MyRnn(units)
        model.compile(optimizer= keras.optimizers.Adam(0.001),
                      loss=tf.losses.BinaryCrossentropy(),
                      metrics = ['accuracy'])
        model.fit(db_train, epochs= epoch, validation_data = db_test)
        model.evaluate(db_test)
        end_time = time.time()
        print('all time: ' ,end_time - start_time)
    if __name__ == '__main__':
        main()
    

    在下一章中,少奶奶将继续讲解RNN网络的不足和改进,依旧是理论+实战,欢迎大家观看

    开篇:开启Tensorflow 2.0时代

    第一章:Tensorflow 2.0 实现简单的线性回归模型(理论+实践)

    第二章:Tensorflow 2.0 手写全连接MNIST数据集(理论+实战)

    第三章:Tensorflow 2.0 利用高级接口实现对cifar10 数据集的全连接(理论+实战实现)

    第四章:Tensorflow 2.0 实现自定义层和自定义模型的编写并实现cifar10 的全连接网络(理论+实战)

    第五章:Tensorflow 2.0 利用十三层卷积神经网络实现cifar 100训练(理论+实战)

    第六章:优化神经网络的技巧(理论)

    第七章:Tensorflow2.0 RNN循环神经网络实现IMDB数据集训练(理论+实践)

    第八章:Tensorflow2.0 传统RNN缺陷和LSTM网络原理(理论+实战)

     

    展开全文
  • 前面几章介绍了卷积神经网络在自然语言处理中的应用,这是因为卷积神经网络便于理解并且易上手编程,大多教程(比如tensorflow的官方文档就先CNN再RNN)。但RNN的原理决定了它先天就适合做自然语言处理方向的问题...

    前面几章介绍了卷积神经网络在自然语言处理中的应用,这是因为卷积神经网络便于理解并且易上手编程,大多教程(比如tensorflow的官方文档就先CNN再RNN)。但RNN的原理决定了它先天就适合做自然语言处理方向的问题(如语言模型,语音识别,文本翻译等等)。因此接下来一段时间应该会着重研究RNN,LSTM,Attention等在NLP的应用及其tensorflow实现。

    在介绍本篇文章之前,先推荐几篇学习内容:
    语言模型部分:
    1、CS224d 第四篇notes,首先讲语言模型的问题,然后推导了RNN、biRNN和LSTM。比99%的中文博客要靠谱。
    2、language model and word2vec,前半部分是语言模型,后半部分介绍了Skip-gram等模型,并引入word2vec。
    RNN和LSTM部分:
    1、The Unreasonable Effectiveness of Recurrent Neural Networks 该文主要介绍了RNN在NLP中的应用,很直观。
    2、Understanding LSTM Networks LSTM过程中很完美的公式,相信看一遍就能记住。
    3、2的中文版 对自己英文不自信的同学可以看这个译文。

    本篇文章实现基于字符的RNN语言模型,源自于Understanding LSTM Networks,在该篇文章中也附有github的网址,不过是基于Torch实现的,在github上有人对其使用tensorflow重写,实现了基于字符的语言模型,我们今天就来介绍这个代码

    数据处理

    数据处理两个最重要的工作
    1. 将文本格式的文件转化为np格式的数组。首先构建字符或者单词的字典embedding_dic,字典的key为字符或者单词,value为该字符或单词对应的索引。其次要构造字符或者单词表embedding_w,每一行是一个字符或者单词的词向量(比如one-hot编码或者word2vec),对应的行标即为该单词的索引。
    2. 生成next_batch,这里要对训练的过程进行feed的格式进行考虑,确保与占位符声明的tensorshape一致。在将所有的训练集遍历过一次以后,需要将训练集进行重排permutation。

    源代码中将seq_length和batches都设置为50,这样不方便观察tensor的变化,因此在下面的代码中,我会将seq_length设置为100(只需要在train文件中更改配置参数即可)。因此一些主要参数为:

    tensor_size = 1115000 #实际为11153941115000为取整之后的结果
    batch_size = 50
    seq_length = 100
    num_batches = 223

    在源码中,po主将所有的字符存为vocab.pkl,将input.txt中的所有字符存为data.npy。这样如果之前已经有这两个文件,那么直接读取preprocessed的文件就行了,就可以不用再处理文本了。该源码中采用的数据集为莎士比亚作品集,是一个很小的数据集,但当数据集很大时,就可以节省很多时间了。这是可以借鉴的一个点。

    po主通过collections.Counter、zip、map等几个函数,就将文本处理的第一步工作做完,这是该段代码可以借鉴的第二个点。第二步要创建next_batch,和我们之前使用start和end两个指针不同,该段代码直接对batches进行了分割,然后使用一个pointer指针指向下一个块儿就行了。详细信息代码中已经添加了中文注释。

    # coding=utf-8
    import codecs
    import os
    import collections
    from six.moves import cPickle
    import numpy as np
    
    
    class TextLoader():
        def __init__(self, data_dir, batch_size, seq_length, encoding='utf-8'):
            self.data_dir = data_dir
            self.batch_size = batch_size
            self.seq_length = seq_length
            self.encoding = encoding
    
            input_file = os.path.join(data_dir, "input.txt")
            vocab_file = os.path.join(data_dir, "vocab.pkl")
            tensor_file = os.path.join(data_dir, "data.npy")
    
            if not (os.path.exists(vocab_file) and os.path.exists(tensor_file)):
                print("reading text file")
                self.preprocess(input_file, vocab_file, tensor_file)
            else:
                print("loading preprocessed files")
                self.load_preprocessed(vocab_file, tensor_file)
            self.create_batches()
            self.reset_batch_pointer()
    
        # 当第一次训练时执行此函数,生成data.npy和vocab.pkl
        def preprocess(self, input_file, vocab_file, tensor_file):
            with codecs.open(input_file, "r", encoding=self.encoding) as f:
                data = f.read()
            # 统计出每个字符出现多少次,统计结果总共有65个字符,所以vocab_size = 65
            counter = collections.Counter(data)
            # 按键值进行排序
            count_pairs = sorted(counter.items(), key=lambda x: -x[1])
            # 得到所有的字符
            self.chars, _ = zip(*count_pairs)
            self.vocab_size = len(self.chars)
            # 得到字符的索引,这点在文本处理的时候是值得借鉴的
            self.vocab = dict(zip(self.chars, range(len(self.chars))))
            # 将字符写入文件
            with open(vocab_file, 'wb') as f:
                cPickle.dump(self.chars, f)
            # 使用map得到input文件中1115394个字符对应的索引
            self.tensor = np.array(list(map(self.vocab.get, data)))
            np.save(tensor_file, self.tensor)
    
        # 如果不是第一次执行训练,那么载入之前的字符和input信息
        def load_preprocessed(self, vocab_file, tensor_file):
            with open(vocab_file, 'rb') as f:
                self.chars = cPickle.load(f)
            self.vocab_size = len(self.chars)
            self.vocab = dict(zip(self.chars, range(len(self.chars))))
            self.tensor = np.load(tensor_file)
            self.num_batches = int(self.tensor.size / (self.batch_size *
                                                       self.seq_length))
    
        def create_batches(self):
            # tensor_size = 1115000 batch_size = 50, seq_length = 100
            # num_batches = 223
            self.num_batches = int(self.tensor.size / (self.batch_size *
                                                       self.seq_length))
    
            # When the data (tensor) is too small,
            # let's give them a better error message
            if self.num_batches == 0:
                assert False, "Not enough data. Make seq_length and batch_size small."
    
            self.tensor = self.tensor[:self.num_batches * self.batch_size * self.seq_length]
            xdata = self.tensor
            ydata = np.copy(self.tensor)
            # ydata为xdata的左循环移位,例如x为[1,2,3,4,5],y就为[2,3,4,5,1]
            # 因为y是x的下一个字符
            ydata[:-1] = xdata[1:]
            ydata[-1] = xdata[0]
            # x_batches 的 shape 就是 223 × 50 × 100
            self.x_batches = np.split(xdata.reshape(self.batch_size, -1),
                                      self.num_batches, 1)
            self.y_batches = np.split(ydata.reshape(self.batch_size, -1),
                                      self.num_batches, 1)
    
        def next_batch(self):
            x, y = self.x_batches[self.pointer], self.y_batches[self.pointer]
            self.pointer += 1
            return x, y
    
        def reset_batch_pointer(self):
            self.pointer = 0

    模型构建

    RNN不太好理解的就是模型构建部分,几个重要的函数在下面的博客都有说明。
    1、使用TensorFlow实现RNN模型入门篇2–char-rnn语言建模模型
    2、解读tensorflow之rnn
    理解了这几个函数,我们开始看代码。占位符placeholder有两个,分别命名为self.input_data和self.targets,值得一提的是,由于我们现在要训练的模型是language model,也就是给一个字符,预测最有可能的下一个字符,因此input和output是同型的,并且output是input的左移位,这在数据处理的时候已经提到过。placeholder只存储一个batch的data,input接收的是该字符在self.vocab中对应的index(后续会将index转成word_ embedding),每次接收一个seq_length的字符,那么,input shape=[batch_size, num_steps]。
    注意:此时的num_steps,即为RNN可以回溯的步长,在该例子中,num_steps=seq_length=100。

    为了解释方便,我将模型的主要部分用下图表示。
    1. 首先看图1,input_shape为[batch_size, seq_length],通过lookup_embedding函数以后shape为[batch_size, seq_length, rnn_size]。需要注意的是,图4中的一个圈代表RNNcell,里边有很多神经元组成。
    2. 图2中的rnn_size就是图4中一个RNNcell中神经元的个数。
    3. 图2到图3的split函数,以1轴进行分割(即以seq进行分割,0轴为batch),分成图3所示一片一片的形式,再通过squeeze函数,每一片的大小变为[batch_size, rnn_size]。共有seq_length=100片。
    4. 然后将每一片送入图4中的一个num_step中,上文已经说明num_steps=seq_length=100。接下来就可以开始进行训练了。此源码中的num_layers=2,因此是一个二层的RNN网络,在图4中已经画出。
    这里写图片描述

    有了上述图片的解释,代码应该不难看懂:

    # coding=utf-8
    import tensorflow as tf
    from tensorflow.contrib import rnn
    from tensorflow.contrib import legacy_seq2seq
    
    
    class Model():
        def __init__(self, args, training=True):
            self.args = args
            if not training:
                args.batch_size = 1
                args.seq_length = 1
    
            if args.model == 'rnn':
                cell_fn = rnn.BasicRNNCell
            elif args.model == 'gru':
                cell_fn = rnn.GRUCell
            elif args.model == 'lstm':
                cell_fn = rnn.BasicLSTMCell
            elif args.model == 'nas':
                cell_fn = rnn.NASCell
            else:
                raise Exception("model type not supported: {}".format(args.model))
    
            # 二层RNN,需要将rnn_size作为参数传入到rnn_cell中
            cells = []
            for _ in range(args.num_layers):
                cell = cell_fn(args.rnn_size)
                if training and (args.output_keep_prob < 1.0 or args.input_keep_prob < 1.0):
                    cell = rnn.DropoutWrapper(cell,
                                              input_keep_prob=args.input_keep_prob,
                                              output_keep_prob=args.output_keep_prob)
                cells.append(cell)
    
            # 通过cells列表,构建多层RNN,函数具体的解释可以看官网或者上文推荐的博客
            self.cell = cell = rnn.MultiRNNCell(cells, state_is_tuple=True)
    
            # 占位符的shape,图中已经解释清楚
            self.input_data = tf.placeholder(
                tf.int32, [args.batch_size, args.seq_length])
            self.targets = tf.placeholder(
                tf.int32, [args.batch_size, args.seq_length])
            self.initial_state = cell.zero_state(args.batch_size, tf.float32)
    
            # 定义需要训练的权重和偏置,因为需要和[batch,rnn_size]大小的split片相乘,
            # 所以需要定义shape为[args.rnn_size, args.vocab_size]
            with tf.variable_scope('rnnlm'):
                softmax_w = tf.get_variable("softmax_w",
                                            [args.rnn_size, args.vocab_size])
                softmax_b = tf.get_variable("softmax_b", [args.vocab_size])
    
            # 嵌入层,随机进行初始化
            embedding = tf.get_variable("embedding", [args.vocab_size, args.rnn_size])
            inputs = tf.nn.embedding_lookup(embedding, self.input_data)
    
            # dropout beta testing: double check which one should affect next line
            if training and args.output_keep_prob:
                inputs = tf.nn.dropout(inputs, args.output_keep_prob)
    
            # split函数,将图2变至图3的很多片,方便传入RNNcell
            # 即[batch_size, seq_length, rnn_size]-->[batch_size, 1, rnn_size]
            inputs = tf.split(inputs, args.seq_length, 1)
            # squeeze函数,将大小为1的维度去掉,因此每一片的维度从[batch_size,1,rnn_size]
            # 变为[batch_size,rnn_size]
            inputs = [tf.squeeze(input_, [1]) for input_ in inputs]
    
            # loop函数连接num_steps步的rnn_cell,将h(t-1)的输出prev做变换然后传入h(t)作为输入
            def loop(prev, _):
                prev = tf.matmul(prev, softmax_w) + softmax_b
                prev_symbol = tf.stop_gradient(tf.argmax(prev, 1))
                return tf.nn.embedding_lookup(embedding, prev_symbol)
    
            """
            该函数实现了一个简单的多层rnn模型。上面的MultiRNNCell函数构造了一个时间步的多层rnn,
            本函数则实现将其循环num_steps个时间步。
            :param decoder_inputs:输入列表,是一个长度为num_steps的列表,
                                每个元素是[batch_size, input_size]的2-D维的tensor
            :param initial_state:初始化状态,2-D的tensor,shape为 [batch_size x cell.state_size].
            :param cell:RNNCell
            :param loop_function:如果不为空,则将该函数应用于第i个输出以得到第i+1个输入,
                    此时decoder_inputs变量除了第一个元素之外其他元素会被忽略。其形式定义为:loop(prev, i)=next。
                    prev是[batch_size x output_size],i是表明第i步,next是[batch_size x input_size]。
            """
            outputs, last_state = legacy_seq2seq.rnn_decoder(inputs, self.initial_state, cell, loop_function=loop if not training else None, scope='rnnlm')
            out_concat = tf.concat(outputs, 1)
            output = tf.reshape(out_concat, [-1, args.rnn_size])
    
    
            self.logits = tf.matmul(output, softmax_w) + softmax_b
            self.probs = tf.nn.softmax(self.logits)
            loss = legacy_seq2seq.sequence_loss_by_example(
                    [self.logits],
                    [tf.reshape(self.targets, [-1])],
                    [tf.ones([args.batch_size * args.seq_length])])
            self.cost = tf.reduce_sum(loss) / args.batch_size / args.seq_length
            with tf.name_scope('cost'):
                self.cost = tf.reduce_sum(loss) / args.batch_size / args.seq_length
            self.final_state = last_state
            self.lr = tf.Variable(0.0, trainable=False)
            tvars = tf.trainable_variables()
            # 梯度截断
            grads, _ = tf.clip_by_global_norm(tf.gradients(self.cost, tvars),
                    args.grad_clip)
            with tf.name_scope('optimizer'):
                optimizer = tf.train.AdamOptimizer(self.lr)
            self.train_op = optimizer.apply_gradients(zip(grads, tvars))
    
            # instrument tensorboard
            tf.summary.histogram('logits', self.logits)
            tf.summary.histogram('loss', loss)
            tf.summary.scalar('train_loss', self.cost)
    

    训练过程

    训练部分的代码也没有新的难懂的部分,也有很多冗余的部分,所以重点关注加了注释的部分吧:

    # coding=utf-8
    from __future__ import print_function
    import tensorflow as tf
    
    import argparse
    import time
    import os
    from six.moves import cPickle
    
    from utils import TextLoader
    from model import Model
    
    
    def main():
        parser = argparse.ArgumentParser(
                            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        parser.add_argument('--data_dir', type=str, default='data/tinyshakespeare',
                            help='data directory containing input.txt')
        parser.add_argument('--save_dir', type=str, default='save',
                            help='directory to store checkpointed models')
        parser.add_argument('--log_dir', type=str, default='logs',
                            help='directory to store tensorboard logs')
        parser.add_argument('--rnn_size', type=int, default=128,
                            help='size of RNN hidden state')
        parser.add_argument('--num_layers', type=int, default=2,
                            help='number of layers in the RNN')
        parser.add_argument('--model', type=str, default='lstm',
                            help='rnn, gru, lstm, or nas')
        parser.add_argument('--batch_size', type=int, default=50,
                            help='minibatch size')
        parser.add_argument('--seq_length', type=int, default=100,
                            help='RNN sequence length')
        parser.add_argument('--num_epochs', type=int, default=50,
                            help='number of epochs')
        parser.add_argument('--save_every', type=int, default=1000,
                            help='save frequency')
        parser.add_argument('--grad_clip', type=float, default=5.,
                            help='clip gradients at this value')
        parser.add_argument('--learning_rate', type=float, default=0.002,
                            help='learning rate')
        parser.add_argument('--decay_rate', type=float, default=0.97,
                            help='decay rate for rmsprop')
        parser.add_argument('--output_keep_prob', type=float, default=1.0,
                            help='probability of keeping weights in the hidden layer')
        parser.add_argument('--input_keep_prob', type=float, default=1.0,
                            help='probability of keeping weights in the input layer')
        parser.add_argument('--init_from', type=str, default=None,
                            help="""continue training from saved model at this path. Path must contain files saved by previous training process:
                                'config.pkl'        : configuration;
                                'chars_vocab.pkl'   : vocabulary definitions;
                                'checkpoint'        : paths to model file(s) (created by tf).
                                                      Note: this file contains absolute paths, be careful when moving files around;
                                'model.ckpt-*'      : file(s) with model definition (created by tf)
                            """)
        args = parser.parse_args()
        train(args)
    
    
    def train(args):
        # 读入数据
        data_loader = TextLoader(args.data_dir, args.batch_size, args.seq_length)
        args.vocab_size = data_loader.vocab_size
    
        # check compatibility if training is continued from previously saved model
        if args.init_from is not None:
            # check if all necessary files exist
            assert os.path.isdir(args.init_from)," %s must be a a path" % args.init_from
            assert os.path.isfile(os.path.join(args.init_from,"config.pkl")),"config.pkl file does not exist in path %s"%args.init_from
            assert os.path.isfile(os.path.join(args.init_from,"chars_vocab.pkl")),"chars_vocab.pkl.pkl file does not exist in path %s" % args.init_from
            ckpt = tf.train.get_checkpoint_state(args.init_from)
            assert ckpt, "No checkpoint found"
            assert ckpt.model_checkpoint_path, "No model path found in checkpoint"
    
            # open old config and check if models are compatible
            with open(os.path.join(args.init_from, 'config.pkl'), 'rb') as f:
                saved_model_args = cPickle.load(f)
            need_be_same = ["model", "rnn_size", "num_layers", "seq_length"]
            for checkme in need_be_same:
                assert vars(saved_model_args)[checkme]==vars(args)[checkme],"Command line argument and saved model disagree on '%s' "%checkme
    
            # open saved vocab/dict and check if vocabs/dicts are compatible
            with open(os.path.join(args.init_from, 'chars_vocab.pkl'), 'rb') as f:
                saved_chars, saved_vocab = cPickle.load(f)
            assert saved_chars==data_loader.chars, "Data and loaded model disagree on character set!"
            assert saved_vocab==data_loader.vocab, "Data and loaded model disagree on dictionary mappings!"
    
        if not os.path.isdir(args.save_dir):
            os.makedirs(args.save_dir)
        with open(os.path.join(args.save_dir, 'config.pkl'), 'wb') as f:
            cPickle.dump(args, f)
        with open(os.path.join(args.save_dir, 'chars_vocab.pkl'), 'wb') as f:
            cPickle.dump((data_loader.chars, data_loader.vocab), f)
    
        # 构建模型
        model = Model(args)
    
        with tf.Session() as sess:
            # instrument for tensorboard
            summaries = tf.summary.merge_all()
            writer = tf.summary.FileWriter(
                    os.path.join(args.log_dir, time.strftime("%Y-%m-%d-%H-%M-%S")))
            writer.add_graph(sess.graph)
    
            sess.run(tf.global_variables_initializer())
            saver = tf.train.Saver(tf.global_variables())
            # restore model
            if args.init_from is not None:
                saver.restore(sess, ckpt.model_checkpoint_path)
            # 开始训练
            for e in range(args.num_epochs):
                sess.run(tf.assign(model.lr,
                                   args.learning_rate * (args.decay_rate ** e)))
                data_loader.reset_batch_pointer()
                state = sess.run(model.initial_state)
                for b in range(data_loader.num_batches):
                    start = time.time()
                    x, y = data_loader.next_batch()
                    feed = {model.input_data: x, model.targets: y}
                    for i, (c, h) in enumerate(model.initial_state):
                        feed[c] = state[i].c
                        feed[h] = state[i].h
                    train_loss, state, _ = sess.run([model.cost, model.final_state, model.train_op], feed)
    
                    # instrument for tensorboard
                    summ, train_loss, state, _ = sess.run([summaries, model.cost, model.final_state, model.train_op], feed)
                    writer.add_summary(summ, e * data_loader.num_batches + b)
    
                    end = time.time()
                    print("{}/{} (epoch {}), train_loss = {:.3f}, time/batch = {:.3f}"
                          .format(e * data_loader.num_batches + b,
                                  args.num_epochs * data_loader.num_batches,
                                  e, train_loss, end - start))
                    if (e * data_loader.num_batches + b) % args.save_every == 0\
                            or (e == args.num_epochs-1 and
                                b == data_loader.num_batches-1):
                        # save for the last result
                        checkpoint_path = os.path.join(args.save_dir, 'model.ckpt')
                        saver.save(sess, checkpoint_path,
                                   global_step=e * data_loader.num_batches + b)
                        print("model saved to {}".format(checkpoint_path))
    
    
    if __name__ == '__main__':
        main()
    

    训练结果

    在cpu的电脑上训练还是很快的,经过五千多步的迭代,loss能降到1.4左右。github上的代码只展示了loss,因此在这里我们也只展示loss和graph。
    这里写图片描述
    这里写图片描述

    展开全文
  • 深度学习神经网络之循环神经网络(RNN)Matlab实现循环神经网络RNN
  • 使用循环神经网络(RNN)实现简易的二进制加法器,利用python中numpy包实现
  • 基于Python的循环神经网络(RNN)实现
  • 基于循环神经网络的语言模型,提供了从零开始的实现与简洁实现 ...本节介绍循环神经网络,下图展示了如何基于循环神经网络实现语言模型。我们的目的是基于当前的输入与过去的输入序列,预测序列的下一个字符。
  • 详细地介绍了如何使用循环神经网络实现目标跟踪和目标检测,理论和实验都很详细,非常值得一读,无论是对于刚刚对循环神经网络有了一定了解的同学还是对视觉动作感兴趣的同学
  • 本节介绍循环神经网络,下图展示了如何基于循环神经网络实现语言模型。 •裁剪梯度 循环神经网络中较容易出现梯度衰减或梯度爆炸,这会导致网络几乎无法训练。裁剪梯度(clip gradient)是一种应对梯度爆炸的方法。...
  • python实现循环神经网络RNN

    千次阅读 2019-08-02 11:18:44
    python实现循环神经网络 1 生成一些数据 2 定义激活函数 3训练Softmax线性分类器 3.1 初始化参数 3.2 计算得分 3.3 计算损失 3.4 用反向传播计算分析梯度 3.5 执行参数更新 3.6 测试训练正确率 4 训练神经...

    目录

    python实现循环神经网络

    1 生成一些数据

    2 定义激活函数

    3 训练Softmax线性分类器

    3.1 初始化参数

    3.2 计算得分

    3.3 计算损失

    3.4 用反向传播计算分析梯度

    3.5 执行参数更新

    3.6 测试训练正确率

    4 训练神经网络

    4.1 用sigmoid非线性训练网络

    4.2 用ReLU非线性训练网络

    5 完整代码


    python实现循环神经网络

    1 生成一些数据

    让我们生成一个不易线性分离的分类数据集。我们最喜欢的例子是螺旋数据集,可以按如下方式生成

    #玩具螺旋数据由三个类别(蓝色,红色,黄色)组成,这些类别不是线性可分的。

    N = 100 # number of points per class

    D = 2 # dimensionality

    K = 3 # number of classes

    X = np.zeros((N*K,D)) # data matrix (each row = single example)

    y = np.zeros(N*K, dtype='uint8') # class labels

    for j in range(K):

      ix = range(N*j,N*(j+1))

      r = np.linspace(0.0,1,N) # radius

      t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 # theta

      X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]

      y[ix] = j

    # lets visualize the data:

    plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)

    plt.show()

    2 定义激活函数

    sigmoid函数“压缩”输入位于0和1之间。不幸的是,这意味着对于sigmoid输出接近0或1的输入,相对于这些输入的梯度接近于零。这导致梯度消失的现象,其中梯度下降接近于零,并且网络不能很好地学习。

     

    另一方面,relu函数(max(0,x))不会随输入大小而饱和。

    #sigmoid函数压缩输入位于01之间。不幸的是,这意味着对于sigmoid输出接近01的输入,相对于这些输入的梯度接近于零。

    #这导致梯度消失的现象,其中梯度下降接近于零,并且网络不能很好地学习。

    def sigmoid(x):

        x = 1/(1+np.exp(-x))

        return x

     

    def sigmoid_grad(x):

        return (x)*(1-x)

     

    #relu函数(max0x))不会随输入大小而饱和

    def relu(x):

        return np.maximum(0,x)

    3 训练Softmax线性分类器

    我们构建一个非常简单的神经网络,有三层(两个隐藏层),您可以换掉ReLU / sigmoid非线性。

    定义函数:

    def three_layer_net(NONLINEARITY,X,y, model, step_size, reg):

    3.1 初始化参数

    Softmax分类器具有线性分数函数并使用交叉熵损失。线性分类器的参数由权重矩阵W和b每个类的偏置向量组成。

        #parameter initialization

        h= model['h']

        h2= model['h2']

        W1= model['W1']

        W2= model['W2']

        W3= model['W3']

        b1= model['b1']

        b2= model['b2']

        b3= model['b3']  

     

        # some hyperparameter

        # 梯度下降

        num_examples = X.shape[0]

        plot_array_1=[]

        plot_array_2=[]

    3.2 计算得分

    由于这是一个线性分类器,我们可以非常简单地与单个矩阵乘法并行计算所有类别得分:

    for i in range(50000):

            #前向传播

            if NONLINEARITY== 'RELU':

                hidden_layer = relu(np.dot(X, W1) + b1)

                hidden_layer2 = relu(np.dot(hidden_layer, W2) + b2)

                scores = np.dot(hidden_layer2, W3) + b3

     

            elif NONLINEARITY == 'SIGM':

                hidden_layer = sigmoid(np.dot(X, W1) + b1)

                hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)

                scores = np.dot(hidden_layer2, W3) + b3

    在这个例子中,我们有300个2-D点,所以在这个乘法之后,数组scores将具有[300 x 3]的大小,其中每行给出对应于3个类(蓝色,红色,黄色)的类分数。

    3.3 计算损失

    我们需要的第二个关键因素是损失函数,它是一个可微目标,可以量化我们对计算出的班级分数的不满意程度。直观地说,我们希望正确的类比其他类得分更高。在这种情况下,损失应该很低,否则损失应该很高。有很多方法可以量化这种直觉,但是在这个例子中,让我们使用与Softmax分类器相关的交叉熵损失。回想一下,如果f是单个例子的类分数数组(例如这里的3个数数组),那么Softmax分类器计算该例子的损失为:

    我们可以看到Softmax分类器将f的每个元素解释为持有这三个类的(非规范化)对数概率。我们将这些取幂得到(非标准化的)概率,然后将它们标准化得到概率。因此,log中的表达式是正确类的归一化概率。注意这个表达式的工作原理:这个量总是在0和1之间。当正确类的概率非常小(接近于0)时,损失将趋于(正)无穷大。相反,当正确的类概率趋近于1时,损失将趋近于零,因为log(1)=0。因此,当正确的类概率高时,Li的表达式值是低的,当正确的类概率低时,Li的表达式值是非常高的

     

    完整的Softmax分类器损失被定义为训练实例和正则化之间的平均交叉熵损失:

    给定我们上面计算的分数数组,我们可以计算损失。首先,得到概率的方法很简单:

    • 计算损失

    #计算损失

            #probs大小为[300 x 3] 的数组,其中每行现在包含类概率

            exp_scores = np.exp(scores)

            probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]

     

    • 我们现在有一个probs大小为[300 x 3] 的数组,其中每行现在包含类概率。特别是,因为我们已将它们标准化,现在每一行总和为一。我们现在可以在每个示例中查询分配给正确类的对数概率:

    corect_logprobs = -np.log(probs[range(num_examples),y])

    data_loss = np.sum(corect_logprobs)/num_examples

    • 该数组correct_logprobs是一维数组,仅包含为每个示例分配给正确类的概率。那么完全损失就是这些对数概率的平均值和正则化损失的和

    reg_loss = 0.5*reg*np.sum(W1*W1) + 0.5*reg*np.sum(W2*W2)+ 0.5*reg*np.sum(W3*W3)

    loss = data_loss + reg_loss

    3.4 用反向传播计算分析梯度

    我们有一种估算损失的方法,现在我们要把它最小化。我们用梯度下降法。也就是说,我们从随机参数开始,计算损失函数相对于参数的梯度,这样我们就知道应该如何改变参数来减少损失。让我们引入中间变量p,它是(标准化)概率的一个向量。

    利用链式法则求得:

    假设我们计算的概率是p =[0.2, 0.3, 0.5],正确的类是中间类(概率为0.3)。根据这个推导,得分的梯度为df =[0.2, -0.7, 0.5]. 增加的第一个和最后一个元素得分向量f(错误的分数类),会增加损失(由于积极迹象+ 0.2 + 0.5)不好,因此需增加损失损失,而增加正确的班级分数对损失有负面影响。

    # compute the gradient on scores

            dscores = probs

            dscores[range(num_examples),y] -= 1

            dscores /= num_examples

    反向传播:

    # BACKPROP HERE

            dW3 = (hidden_layer2.T).dot(dscores)

            db3 = np.sum(dscores, axis=0, keepdims=True)

     

     

            if NONLINEARITY == 'RELU':

     

                #backprop ReLU nonlinearity here

                dhidden2 = np.dot(dscores, W3.T)

                dhidden2[hidden_layer2 <= 0] = 0

                dW2 =  np.dot( hidden_layer.T, dhidden2)

                plot_array_2.append(np.sum(np.abs(dW2))/np.sum(np.abs(dW2.shape)))

                db2 = np.sum(dhidden2, axis=0)

                dhidden = np.dot(dhidden2, W2.T)

                dhidden[hidden_layer <= 0] = 0

               

            elif NONLINEARITY == 'SIGM':

     

                #backprop sigmoid nonlinearity here

                dhidden2 = dscores.dot(W3.T)*sigmoid_grad(hidden_layer2)

                dW2 = (hidden_layer.T).dot(dhidden2)

                plot_array_2.append(np.sum(np.abs(dW2))/np.sum(np.abs(dW2.shape)))

                db2 = np.sum(dhidden2, axis=0)

                dhidden = dhidden2.dot(W2.T)*sigmoid_grad(hidden_layer)

     

           

            dW1 =  np.dot(X.T, dhidden)

            plot_array_1.append(np.sum(np.abs(dW1))/np.sum(np.abs(dW1.shape)))

            db1 = np.sum(dhidden, axis=0)

     

            # add regularization

            dW3+= reg * W3

            dW2 += reg * W2

            dW1 += reg * W1

           

            #option to return loss, grads -- uncomment next comment

            grads={}

            grads['W1']=dW1

            grads['W2']=dW2

            grads['W3']=dW3

            grads['b1']=db1

            grads['b2']=db2

            grads['b3']=db3

            #return loss, grads

    3.5 执行参数更新

    现在我们已经计算了梯度我们知道了每个参数如何影响损失函数。我们现在将在负梯度方向进行参数更新,以减少损耗:

    # update

            W1 += -step_size * dW1

            b1 += -step_size * db1

            W2 += -step_size * dW2

            b2 += -step_size * db2

            W3 += -step_size * dW3

            b3 += -step_size * db3

    3.6 测试训练正确率

    # evaluate training set accuracy

        if NONLINEARITY == 'RELU':

            hidden_layer = relu(np.dot(X, W1) + b1)

            hidden_layer2 = relu(np.dot(hidden_layer, W2) + b2)

        elif NONLINEARITY == 'SIGM':

            hidden_layer = sigmoid(np.dot(X, W1) + b1)

            hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)

        scores = np.dot(hidden_layer2, W3) + b3

        predicted_class = np.argmax(scores, axis=1)

        print ('training accuracy: %.2f' % (np.mean(predicted_class == y)))

    4 训练神经网络

    4.1 用sigmoid非线性训练网络

    N = 100 # number of points per class

    D = 2 # dimensionality

    K = 3 # number of classes

    h=50

    h2=50

    num_train_examples = X.shape[0]

     

    model={}

    model['h'] = h # size of hidden layer 1

    model['h2']= h2# size of hidden layer 2

    model['W1']= 0.1 * np.random.randn(D,h)

    model['b1'] = np.zeros((1,h))

    model['W2'] = 0.1 * np.random.randn(h,h2)

    model['b2']= np.zeros((1,h2))

    model['W3'] = 0.1 * np.random.randn(h2,K)

    model['b3'] = np.zeros((1,K))

     

    (sigm_array_1, sigm_array_2, s_W1, s_W2,s_W3, s_b1, s_b2,s_b3) = three_layer_net('SIGM', X,y,model, step_size=1e-1, reg=1e-3)

    运行结果:

    iteration 0: loss 1.130914

    iteration 1000: loss 1.099443

    iteration 2000: loss 0.961015

    iteration 3000: loss 0.828722

    iteration 4000: loss 0.814054

    iteration 5000: loss 0.80992

    ...

    iteration 45000: loss 0.471655

    iteration 46000: loss 0.470753

    iteration 47000: loss 0.469861

    iteration 48000: loss 0.468986

    iteration 49000: loss 0.468135

    training accuracy: 0.96

    4.2 用ReLU非线性训练网络

    N = 100 # number of points per class

    D = 2 # dimensionality

    K = 3 # number of classes

    h=50

    h2=50

    num_train_examples = X.shape[0]

     

    model={}

    model['h'] = h # size of hidden layer 1

    model['h2']= h2# size of hidden layer 2

    model['W1']= 0.1 * np.random.randn(D,h)

    model['b1'] = np.zeros((1,h))

    model['W2'] = 0.1 * np.random.randn(h,h2)

    model['b2']= np.zeros((1,h2))

    model['W3'] = 0.1 * np.random.randn(h2,K)

    model['b3'] = np.zeros((1,K))

     

    (relu_array_1, relu_array_2, r_W1, r_W2,r_W3, r_b1, r_b2,r_b3) = three_layer_net('RELU', X,y,model, step_size=1e-1, reg=1e-3)

     

    运行结果:

    iteration 0: loss 1.115254

    iteration 1000: loss 0.341567

    iteration 2000: loss 0.154439

    iteration 3000: loss 0.134785

    iteration 4000: loss 0.129502

    iteration 5000: loss 0.126574

    ...

    iteration 45000: loss 0.112814

    iteration 46000: loss 0.112758

    iteration 47000: loss 0.112705

    iteration 48000: loss 0.112652

    iteration 49000: loss 0.112601

    training accuracy: 0.99

    5 完整代码

    #coding=utf-8
    #构建一个非常简单的神经网络,有三层(两个隐藏层)
    # Setup
    import numpy as np
    import matplotlib.pyplot as plt
    
    #sigmoid函数“压缩”输入位于0和1之间。不幸的是,这意味着对于sigmoid输出接近0或1的输入,相对于这些输入的梯度接近于零。
    #这导致梯度消失的现象,其中梯度下降接近于零,并且网络不能很好地学习。
    def sigmoid(x):
        x = 1/(1+np.exp(-x))
        return x
    
    def sigmoid_grad(x):
        return (x)*(1-x)
    
    #relu函数(max(0,x))不会随输入大小而饱和
    def relu(x):
        return np.maximum(0,x)
    
    plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
    plt.rcParams['image.interpolation'] = 'nearest'
    plt.rcParams['image.cmap'] = 'gray'
    
    # 生成一些数据
    # 让我们生成一个不易线性分离的分类数据集。我们最喜欢的例子是螺旋数据集,可以按如下方式生成:
    #玩具螺旋数据由三个类别(蓝色,红色,黄色)组成,这些类别不是线性可分的。
    N = 100 # number of points per class
    D = 2 # dimensionality
    K = 3 # number of classes
    X = np.zeros((N*K,D)) # data matrix (each row = single example)
    y = np.zeros(N*K, dtype='uint8') # class labels
    for j in range(K):
      ix = range(N*j,N*(j+1))
      r = np.linspace(0.0,1,N) # radius
      t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 # theta
      X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
      y[ix] = j
    # lets visualize the data:
    plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
    plt.show()
    
    #定义sigmoid和relu函数
    
    #我们构建一个非常简单的神经网络,有三层(两个隐藏层),您可以换掉ReLU / sigmoid非线性。
    def three_layer_net(NONLINEARITY,X,y, model, step_size, reg):
        #NONLINEARITY:表示使用哪种激活函数
        #parameter initialization
        
        h= model['h']
        h2= model['h2']
        W1= model['W1']
        W2= model['W2']
        W3= model['W3']
        b1= model['b1']
        b2= model['b2']
        b3= model['b3']   
        
        # some hyperparameters
    
        # 梯度下降
        num_examples = X.shape[0]
        plot_array_1=[]
        plot_array_2=[]
        for i in range(50000):
            #前向传播
            if NONLINEARITY== 'RELU':
                hidden_layer = relu(np.dot(X, W1) + b1)
                hidden_layer2 = relu(np.dot(hidden_layer, W2) + b2)
                scores = np.dot(hidden_layer2, W3) + b3
    
            elif NONLINEARITY == 'SIGM':
                hidden_layer = sigmoid(np.dot(X, W1) + b1)
                hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)
                scores = np.dot(hidden_layer2, W3) + b3
    
            #计算损失
            #probs大小为[300 x 3] 的数组,其中每行现在包含类概率
            exp_scores = np.exp(scores)
            probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]
    
            # compute the loss: average cross-entropy loss and regularization
            #数组correct_logprobs是一维数组,仅包含为每个示例分配给正确类的概率。那么完全损失就是这些对数概率和正则化损失的平均值
            corect_logprobs = -np.log(probs[range(num_examples),y])
            data_loss = np.sum(corect_logprobs)/num_examples
            reg_loss = 0.5*reg*np.sum(W1*W1) + 0.5*reg*np.sum(W2*W2)+ 0.5*reg*np.sum(W3*W3)
            loss = data_loss + reg_loss
            if i % 1000 == 0:
                print ("iteration %d: loss %f" % (i, loss))
    
    
            # compute the gradient on scores
            dscores = probs
            dscores[range(num_examples),y] -= 1
            dscores /= num_examples
    
     
            # BACKPROP HERE
            dW3 = (hidden_layer2.T).dot(dscores)
            db3 = np.sum(dscores, axis=0, keepdims=True)
    
    
            if NONLINEARITY == 'RELU':
    
                #backprop ReLU nonlinearity here
                dhidden2 = np.dot(dscores, W3.T)
                dhidden2[hidden_layer2 <= 0] = 0
                dW2 =  np.dot( hidden_layer.T, dhidden2)
                plot_array_2.append(np.sum(np.abs(dW2))/np.sum(np.abs(dW2.shape)))
                db2 = np.sum(dhidden2, axis=0)
                dhidden = np.dot(dhidden2, W2.T)
                dhidden[hidden_layer <= 0] = 0
                
            elif NONLINEARITY == 'SIGM':
    
                #backprop sigmoid nonlinearity here
                dhidden2 = dscores.dot(W3.T)*sigmoid_grad(hidden_layer2)
                dW2 = (hidden_layer.T).dot(dhidden2)
                plot_array_2.append(np.sum(np.abs(dW2))/np.sum(np.abs(dW2.shape)))
                db2 = np.sum(dhidden2, axis=0)
                dhidden = dhidden2.dot(W2.T)*sigmoid_grad(hidden_layer)
    
            
            dW1 =  np.dot(X.T, dhidden)
            plot_array_1.append(np.sum(np.abs(dW1))/np.sum(np.abs(dW1.shape)))
            db1 = np.sum(dhidden, axis=0)
    
            # add regularization
            dW3+= reg * W3
            dW2 += reg * W2
            dW1 += reg * W1
            
            #option to return loss, grads -- uncomment next comment
            grads={}
            grads['W1']=dW1
            grads['W2']=dW2
            grads['W3']=dW3
            grads['b1']=db1
            grads['b2']=db2
            grads['b3']=db3
            #return loss, grads
            
            
            # update
            W1 += -step_size * dW1
            b1 += -step_size * db1
            W2 += -step_size * dW2
            b2 += -step_size * db2
            W3 += -step_size * dW3
            b3 += -step_size * db3
        # evaluate training set accuracy
        if NONLINEARITY == 'RELU':
            hidden_layer = relu(np.dot(X, W1) + b1)
            hidden_layer2 = relu(np.dot(hidden_layer, W2) + b2)
        elif NONLINEARITY == 'SIGM':
            hidden_layer = sigmoid(np.dot(X, W1) + b1)
            hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)
        scores = np.dot(hidden_layer2, W3) + b3
        predicted_class = np.argmax(scores, axis=1)
        print ('training accuracy: %.2f' % (np.mean(predicted_class == y)))
        #return cost, grads
        return plot_array_1, plot_array_2, W1, W2, W3, b1, b2, b3
    
    #用sigmoid非线性训练网络
    N = 100 # number of points per class
    D = 2 # dimensionality
    K = 3 # number of classes
    h=50
    h2=50
    # num_train_examples = X.shape[0]
    # 
    # model={}
    # model['h'] = h # size of hidden layer 1
    # model['h2']= h2# size of hidden layer 2
    # model['W1']= 0.1 * np.random.randn(D,h)
    # model['b1'] = np.zeros((1,h))
    # model['W2'] = 0.1 * np.random.randn(h,h2)
    # model['b2']= np.zeros((1,h2))
    # model['W3'] = 0.1 * np.random.randn(h2,K)
    # model['b3'] = np.zeros((1,K))
    # 
    # (sigm_array_1, sigm_array_2, s_W1, s_W2,s_W3, s_b1, s_b2,s_b3) = three_layer_net('SIGM', X,y,model, step_size=1e-1, reg=1e-3)
    
    #用ReLU非线性训练网络
    #Re-initialize model, train relu net
    model={}
    model['h'] = h # size of hidden layer 1
    model['h2']= h2# size of hidden layer 2
    model['W1']= 0.1 * np.random.randn(D,h)
    model['b1'] = np.zeros((1,h))
    model['W2'] = 0.1 * np.random.randn(h,h2)
    model['b2']= np.zeros((1,h2))
    model['W3'] = 0.1 * np.random.randn(h2,K)
    model['b3'] = np.zeros((1,K))
    
    (relu_array_1, relu_array_2, r_W1, r_W2,r_W3, r_b1, r_b2,r_b3) = three_layer_net('RELU', X,y,model, step_size=1e-1, reg=1e-3)
    
    

     

    展开全文
  • 双向循环神经网络及TensorFlow实现

    千次阅读 2018-04-03 09:06:25
    前言 循环神经网络得益于其记忆功能使...所谓的单向循环神经网络其实就是常见的循环神经网络,可以看到t时刻、t-1时刻、t+1时刻,不同时刻输入对应不同的输出,而且上一时刻的隐含层会影响当前时刻的输出。这种结构...

    前言

    循环神经网络得益于其记忆功能使其擅长处理序列方面的问题,它能提取序列之间的特征,进而对序列输出进行预测。比如我说“我肚子饿了,准备去xx”,那么根据前面的序列输入来预测“xx”很可能就是“吃饭”。

    单向循环神经网络

    所谓的单向循环神经网络其实就是常见的循环神经网络,可以看到t时刻、t-1时刻、t+1时刻,不同时刻输入对应不同的输出,而且上一时刻的隐含层会影响当前时刻的输出。这种结构就是单向循环神经网络结构。

    这里写图片描述

    单向循环神经网络不足

    从单向的结构可以知道它的下一刻预测输出是根据前面多个时刻的输入来共同影响的,而有些时候预测可能需要由前面若干输入和后面若干输入共同决定,这样会更加准确。比如我说“我肚子xx,准备去吃饭”,那么如果没有后面的部分就不能很好地推断出是“饿了”,也可以是“好疼”或“胖了”之类的。

    双向循环神经网络

    鉴于单向循环神经网络某些情况下的不足,提出了双向循环神经网络。因为是需要能关联未来的数据,而单向循环神经网络属于关联历史数据,所以对于未来数据提

    展开全文
  • 文章目录循环神经网络门控循环单元(GRU)门控循环单元重置门和更新门候选隐藏状态隐藏状态输出结果长短期记忆(LSTM)输入门、遗忘门和输出门候选记忆细胞记忆细胞隐藏状态输出结果深度循环神经网络双向循环神经...
  • 循环神经网络——实现LSTM

    千次阅读 2017-03-03 15:29:57
    gitbook阅读地址:循环神经网络--实现LSTM · 超智能体 梯度消失和梯度爆炸 网络回忆:在《循环神经网络——介绍》中提到循环神经网络用相同的方式处理每个时刻的数据。 动态图: 数学公式: ...
  • pytorch实现循环神经网络实验

    千次阅读 2020-12-01 18:07:31
    实验: 手动实现循环神经网络RNN,并从至少一个数据集上进行实验,这里我选取了高速公路传感器数据PEMS04(后面的实验都是用的高速公路传感器数据),主要根据数据集的大小以及特征维度,手动实现循环神经网络,包括...
  • 主要介绍了TensorFlow实现RNN循环神经网络,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 文章目录门控循环神经网络GRU长短期记忆LSTM深度循环神经网络双向循环神经网络 门控循环神经网络GRU 该网络的提出也同样是为了应对普通RNN的梯度问题 基本原理看这一篇就能懂:转载自知乎 简单来说,GRU就是通过一个...
  • | 第5天 深度学习100例-卷积神经网络(VGG-16)识别海贼王草帽一伙 | 第6天 深度学习100例-卷积神经网络(ResNet-50)鸟类识别 | 第8天 深度学习100例-循环神经网络(RNN)股票预测 | 第9天 如果你还是一名小白,...
  • 循环神经网络

    千次阅读 2019-05-26 20:24:41
    文章目录循环神经网络循环神经网络RNN简单循环网络SRN参数学习随时间反向传播算法BPTT实时循环学习算法RTRL长期依赖问题基于门控的循环神经网络长短期记忆网络LSTM门控循环单元网络GRURNN文本分类Recurrent ...
  • 使用循环神经网络(RNN)实现影评情感分类 作为对循环神经网络的实践,我用循环神经网络做了个影评情感的分类,即判断影评的感情色彩是正面的,还是负面的。 选择使用RNN来做情感分类,主要是因为影评是一段文字,是...
  • 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_...
  • 基于python编写的RNN循环神经网络实现二进制加法
  • 作者:徐志强 ... 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 ...本篇教程的代码在Github上。...循环神经网络教程第二部分-用python,numpy,theano实现一个RNN
  • MATLAB实现RNN(循环神经网络)时间序列预测数据集
  • 循环神经网络RNN的简单框架实现

    千次阅读 2018-05-30 14:44:13
    循环神经网络RNN结构与全连接或者卷积神经网络结构相比,RNN比较复杂。通过阅读各种资料,觉得《TensorFlow:实战Google深度学习框架》中RNN讲的最通俗易懂,在这里将简单的总结一下书上的内容。 循环神经网络的...
  • 循环神经网络进阶 ⻔控循环神经⽹络(GRU) 当时间步数较⼤或者时间步较小时, 循环神经⽹络的梯度较容易出现衰减或爆炸。虽然裁剪梯度可以应对梯度爆炸,但⽆法解决梯度衰减的问题。通常由于这个原因,循环神经⽹络...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,154
精华内容 20,061
关键字:

循环神经网络实现