tf中的循环神经网络(RNN)

tf中的循环神经网络(RNN)

1. 序列数据的表示方法

  • 与时间相关的数据称为时间序列(Sequence)。如股票曲线,语音,句子等
  • 序列数据转换为数值数据成为Embeding,如[b, seq_len, feature_len],其中seq_len表示Sequence中的单元数, feature_len表示序列数据转换为数值数据时特征数据的长度
  • Embeding后的batch的理解方式:以股票数据分析为例,[b, word num, word vec]表示有b组股票数据(曲线图),在曲线图上采样word num个点,每个点上的数据是word vec;[word num, b, word vec]表示在每个采样点上选取b组数据的值,每组曲线图分别得到对应点上的数据(word vec)
  • 常见的Embeding方法:Embeding应当保证语义相近的词其数值表示也有相关性,并且这个相似度(如欧氏距离)是可训练的,其中较常用的两种是Word2Vec和GloVe
  • TensorFlow中Embeding的实现:
import tensorflow as tf
from tensorflow.keras import layers
x = tf.range(5)
x = tf.random.shuffle(x)
# 其中10代表理解10个单词,4表示将一个单词表示为1x4数据
net = layers.Embedding(10, 4)  
a = net.trainable
print(a)
b = net.trainable_variables
print(b)

2. 循环神经网络(RNN)

  • RNN思想:首先设计一个memory,设定一个初始状态;将第一个单词通过全连层在加上初始状态memory;将第二个单词通过全连层(每个全连层的参数(权值)相同)在加上第一个状态的输出;以此方式循环至最后;把最后的输出作为分类预测等的判断依据(也可考虑之前所有的输出)
  • RNN相关公式推到:x为输入,y为输出,h表示每个词经过全连层(或其他层)的输出 h t = f W ( h t − 1 , x t ) h_t=f_W(h_{t-1},x_t) ht=fW(ht1,xt) W h h W_{hh} Whh表示输出与输出之间的更新参数w W x h W_{xh} Wxh表示输出与输入之间的更新参数w h t = t a n h ( W h h h t − 1 + W x h x t ) h_t = tanh(W_{hh}h_{t-1}+W_{xh}x_t) ht=tanh(Whhht1+Wxhxt) y t = W h y h t + b y_t = W_{hy}h_t+b yt=Whyht+b求导,其中E是损失函数 ∂ E t ∂ W h h = ∑ i = 0 t ∂ E t ∂ y t ∂ y t ∂ h t ∂ h t ∂ h i ∂ h i ∂ W h h \frac{\partial E_t}{\partial W_{hh}} = \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_{hh}} WhhEt=i=0tytEthtythihtWhhhi ∂ h k ∂ h 1 = ∏ i k d i a g ( f ′ ( W x h x i + W h h h i − 1 ) ) W h h \frac{\partial h_k}{\partial h_1} = \prod_i^kdiag(f\prime(W_{xh}x_i+W_{hh}h_{i-1}))W_{hh} h1hk=ikdiag(f(Wxhxi+Whhhi1))Whh

3. TensorFlow中RNN实现

  • W h h @ h t − 1 + W x h @ x t W_{hh}@h_{t-1}+W_{xh}@x_t Whh@ht1+Wxh@xt在代码中可以理解为 [ b a t c h , f e a t u r e   l e n ] @ [ f e a t u r e   l e n , h i d d e n   l e n ] + [ b a t c h , h i d d e n   l e n ] @ [ h i d d e n   l e n , h i d d e n   l e n ] [batch, feature\ len]@[feature\ len, hidden\ len]+[batch, hidden\ len]@[hidden\ len, hidden\ len] [batch,feature len]@[feature len,hidden len]+[batch,hidden len]@[hidden len,hidden len]其中 feature len为一个‘单词’的特征向量长度,hidden len为输出的维数。输出中kernel是指 W x h W_{xh} Wxh,recurrent_kernel是指 W h h W_{hh} Whh
cell = layers.SimpleCell(3)
cell.build(input_shape=(None, 4))
a0 = cell.trainable_variables
print(a0)
  • SimpleCell()函数:括号中的内容是 hidden len,SimpleCell函数需要自己说明在哪个轴展开

# 四个句子,80种单词,每种单词用长度为100的特征向量表示
x = tf.random.normal([4,80,100])
xt0 = x[:,0,:]
cell = tf.keras.layers.SimpleRNNCell(64)
# RNN的输出是ht和yt,其中yt表示当前的输出,ht表示传入到下一个网络的上一个网络的输出
# 在简单RNN网络种,yt和ht是相同的,但高级RNN中这两个量是有所不同的
out, xt1 = cell(xto, [tf.zeros([4,64])])
a1 = out.shape
a2 = xt1[10].shape
a3 = id(out)
a4 = id(xt1[0])
  • 多层RNN:有时候embeddding的结果可以经过多层网络,而不只是一层。这种情况下一般根据最高层的最后一层结果作为最后的判决依据
x = tf.random.normal([4,80,100])
xt0 = x[:,0,:]
cell = tf.keras.layers.SimpleRNNCell(64)
cell_1 = tf.keras.layers.SimpleRNNCell(64)
state = [tf.zeros([4,64])]
state1 = [tf.zeros([4,64])]
out, state = cell(xto, state)
out1, state1 = cell(out, state)
# 设置在时间轴(即)第二个维度上展开
for word in tf.unstack(x, axis=1):
    out_real0 = self.cell(word, state, training)
    out_real1 = self.cell(out_real0, state1, training)
  • SimpleRNN函数:SimpleRNN可以自动在时间轴上展开,通常搭配Sequential使用
self.rnn = keras.Sequential([
    layers.SimpleRNN(units, dropout=0.5, return_sequences=True, unroll=True)
    layers.SimpleRNN(units, dropout=0.5, unroll=True)
])
x = self.rnn(x)

4. RNN实战

  • 情感问题分类,采用两层embedding,RNN采用SimpleRNNCell函数实现,SimpleRNNCell函数需要用户自行设定在哪个轴展开
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'


# SimpleRNNCell不可以自动在时间轴上展开,需自行展开
batch_size = 128
total_words = 10000  # 只考虑10k个常用单词,其它的单词都看为一种单词
max_review_length = 80  # 设置一个句子中最多单词数量,少补多截
embedding_length = 100  # 设置一个单词embedding后的向量长度
(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# 为保持数据长度一致,对数据做padding
x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_length)
x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_length)
db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# 最后一个batch的大小可能与batch_size不同,为保证输入的维度一致,对与batch_size不同的batch截断
db_train = db_train.shuffle(1000).batch(batch_size, drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
db_test = db_test.batch(batch_size, drop_remainder=True)


class MyRNN(keras.Model):
    # units值embedding的结果经过RNN层后的维数
    def __init__(self, units):
        super(MyRNN, self).__init__()
        # 设定两个初始状态
        self.state0 = [tf.zeros([batch_size, units])]
        self.state1 = [tf.zeros([batch_size, units])]
        self.embedding = layers.Embedding(
            total_words,
            embedding_length,
            input_length=max_review_length
        )
        # 设定两个rnn层,通过dropout来减小过拟合
        self.rnn_cell0 = layers.SimpleRNNCell(units, dropout=0.5)
        self.rnn_cell1 = layers.SimpleRNNCell(units, dropout=0.5)
        self.outlayer = layers.Dense(1)  # 因为是二分类问题,所以只需要一个输出节点

    def call(self, inputs, training=None):
        x = inputs
        x = self.embedding(x)
        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, training)
        x = self.outlayer(out1)
        prob = tf.sigmoid(x)
        return prob


def main():
    units = 64
    epochs = 5
    model = MyRNN(units)
    model.compile(
        optimizer=keras.optimizers.Adam(1e-3),
        loss=tf.losses.BinaryCrossentropy(),
        metrics=['accuracy'],
        experimental_run_tf_function=False
    )
    model.fit(db_train, epochs=epochs, validation_data=db_test)
    model.evaluate(db_test)


if __name__ == '__main__':
    main()
  • 情感问题分类,采用两层embedding,RNN采用SimpleRNN函数实现,SimpleRNN自动在时间轴展开
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'


# SimpleRNN可以自动在时间轴上展开
batch_size = 128
total_words = 10000  # 只考虑10k个常用单词,其它的单词都看为一种单词
max_review_length = 80  # 设置一个句子中最多单词数量,少补多截
embedding_length = 100  # 设置一个单词embedding后的向量长度
(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# 为保持数据长度一致,对数据做padding
x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_length)
x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_length)
db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# 最后一个batch的大小可能与batch_size不同,为保证输入的维度一致,对与batch_size不同的batch截断
db_train = db_train.shuffle(1000).batch(batch_size, drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
db_test = db_test.batch(batch_size, drop_remainder=True)


class MyRNN(keras.Model):
    # units值embedding的结果经过RNN层后的维数
    def __init__(self, units):
        super(MyRNN, self).__init__()
        self.embedding = layers.Embedding(
            total_words,
            embedding_length,
            input_length=max_review_length
        )
        # 通过dropout来减小过拟合
        self.rnn = keras.Sequential([
            layers.SimpleRNN(units, dropout=0.5, return_sequences=True, unroll=True),
            layers.SimpleRNN(units, dropout=0.5, unroll=True)
        ])
        self.outlayer = layers.Dense(1)  # 因为是二分类问题,所以只需要一个输出节点

    def call(self, inputs, training=None):
        x = inputs
        x = self.embedding(x)
        x = self.rnn(x)
        x = self.outlayer(x)
        prob = tf.sigmoid(x)
        return prob


def main():
    units = 64
    epochs = 5
    model = MyRNN(units)
    model.compile(
        optimizer=keras.optimizers.Adam(1e-3),
        loss=tf.losses.BinaryCrossentropy(),
        metrics=['accuracy']
    )
    model.fit(db_train, epochs=epochs, validation_data=db_test)
    model.evaluate(db_test)


if __name__ == '__main__':
    main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值