循环神经网络(Recurrent Neural Network, RNN)是一类以序列(sequence)数据为输入,在序列的演进方向进行递归(recursion)且所有节点(循环单元)按链式连接的递归神经网络(recursive neural network),关于RNN算法的介绍,大家可以看一下这个,讲解的特别清楚
tf.keras.layers.RNN(
cell, return_sequences=False, return_state=False, go_backwards=False,
stateful=False, unroll=False, time_major=False, **kwargs
)
'''
cell RNN单元实例或RNN单元实例列表。RNN单元是具有以下内容的类:
一种call(input_at_t, states_at_t)方法,返回 (output_at_t, states_at_t_plus_1)。单元格的调用方法也可以采用可选参数constants,请参见下面的“传递外部常量的注意事项”部分。
一个state_size属性。它可以是单个整数(单状态),在这种情况下,它是循环状态的大小。这也可以是整数的列表/元组(每个状态一个大小)。的state_size也可以是TensorShape或元组/ TensorShape的列表中,以表示高维状态。
一个output_size属性。它可以是单个整数或TensorShape,代表输出的形状。出于向后兼容的原因,如果该属性不适用于该单元格,则该值将由的第一个元素来推断 state_size。
return_sequences 布尔值(默认False)。是返回输出序列中的最后一个输出还是完整序列。
return_state 布尔值(默认False)。除输出外,是否返回最后一个状态。
go_backwards 布尔值(默认False)。如果为True,则向后处理输入序列,并返回相反的序列。
stateful 布尔值(默认False)。如果为True,则将批次中索引i的每个样本的最后状态用作下一个批次中索引i的样本的初始状态。
unroll 布尔值(默认False)。如果为True,则将展开网络,否则将使用符号循环。展开可以加快RNN的速度,尽管它往往会占用更多的内存。展开仅适用于短序列。
time_major inputs和outputs张量 的形状格式。如果为True,则输入和输出将为形状 ,而为False时,则为 。使用会更有效率,因为它避免了RNN计算开始和结束时的转置。但是,大多数TensorFlow数据都是批量生产的,因此默认情况下,此函数接受输入并以批量生产的形式发出输出。 (timesteps, batch, ...)(batch, timesteps, ...)time_major = True
'''
#有了计算公式以后,我们看一下用numpy怎么实现RNN
import numpy as np
class RNN:
def __init__(self,word_dim,hidden_dim=100,output_dim=50):
self.word_dim=word_dim
self.hidden_dim=hidden_dim
self.output_dim=output_dim
#U这个参数是要和输入数据进行矩阵运算的,所以维度为(输入维度,神经元个数)
self.U=np.random.uniform(-np.sqrt(1./word_dim),np.sqrt(1./word_dim),(word_dim,hidden_dim)) #d*h
#W这个参数是要和循环单元进行矩阵运算的,所以维度为(神经元个数,神经元个数)
self.W=np.random.uniform(-np.sqrt(1./hidden_dim),np.sqrt(1./hidden_dim),(hidden_dim,hidden_dim)) #h*h
#V是计算输出的参数,所以维度(神经元个数,输出维度)
self.V=np.random.uniform(-np.sqrt(1./hidden_dim),np.sqrt(1./hidden_dim),(hidden_dim,output_dim)) #h*q
def forward_propagation(self,x):
# train steps
T=x.shape[1]
N=x.shape[0]
# hidden states 初始化为0
s=np.zeros((N,T,self.hidden_dim))
# output zeros
o=np.zeros((N,T,self.output_dim))
# for each time in step:
for t in range(T):
#这里是计算公式的代码实现
s[:,t,:]=np.tan(x[:,t,:].dot(self.U)+s[:,t-1,:].dot(self.W)) #n*h
o[:,t,:]=self.softmax(s[:,t,:].dot(self.V)) #
return [o,s]
def softmax(self,x):
exp_x = np.exp(x)
softmax_x = exp_x / np.sum(exp_x)
return softmax_x
关于RNN的实现过程,在tf官方文档也给出了案例
#这个相比于numpy的实现要更简单一点,注意:RNN的理解难度主要是各个参数的维度以及数据的维度变化,搞清楚了这个,RNN还是很容易理解的
# First, let's define a RNN Cell, as a layer subclass.
class MinimalRNNCell(keras.layers.Layer):
def __init__(self, units, **kwargs):
self.units = units
self.state_size = units
super(MinimalRNNCell, self).__init__(**kwargs)
def build(self, input_shape):
self.kernel = self.add_weight(shape=(input_shape[-1], self.units),
initializer='uniform',
name='kernel')
self.recurrent_kernel = self.add_weight(
shape=(self.units, self.units),
initializer='uniform',
name='recurrent_kernel')
self.built = True
def call(self, inputs, states):
prev_output = states[0]
h = K.dot(inputs, self.kernel)
output = h + K.dot(prev_output, self.recurrent_kernel)
return output, [output]
# Let's use this cell in a RNN layer:
cell = MinimalRNNCell(32)
x = keras.Input((None, 5))
layer = RNN(cell)
y = layer(x)
# Here's how to use the cell to build a stacked RNN:
cells = [MinimalRNNCell(32), MinimalRNNCell(64)]
x = keras.Input((None, 5))
layer = RNN(cells)
y = layer(x)