NLP之RNN的原理讲解(python示例)
目录
- 代码示例
- 代码解读
- 知识点介绍
代码示例
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import SimpleRNNCell
# 第t时刻要训练的数据
xt = tf.Variable(np.random.randint(2, 3, size=[1, 1]), dtype=tf.float32)
print(xt)
# https://www.cnblogs.com/Renyi-Fan/p/13722276.html
cell = SimpleRNNCell(units=1, activation=None, use_bias=True, kernel_initializer='ones', recurrent_initializer='ones',
bias_initializer=tf.keras.initializers.Constant(value=3))
cell.build(input_shape=[None, 1])
print('variables', cell.variables)
print('config:', cell.get_config())
print(tf.nn.tanh(tf.constant([-float("inf"), 6, float("inf")])))
# 第t时刻运算
ht_1 = tf.ones([1, 1])
out, ht = cell(xt, ht_1) # LSTM
print(out, ht[0])
print(id(out), id(ht[0]))
# 第t+1时刻运算
cell2 = SimpleRNNCell(units=1, activation=None, use_bias=True, kernel_initializer='ones',
recurrent_initializer=tf.keras.initializers.Constant(value=3), bias_initializer='ones')
xt2 = tf.Variable(np.random.randint(3, 4, size=[1, 1]), dtype=tf.float32)
out2, ht2 = cell2(xt2, ht)
print(out2, ht2[0])
代码解读
这段代码包含了一些使用 TensorFlow 来创建和操作循环神经网络(RNN)的基础操作。我们将一步步地解释其含义。
-
导入所需的库:
import numpy as np import tensorflow as tf from tensorflow.keras.layers import SimpleRNNCell
代码导入了NumPy库、TensorFlow库以及
SimpleRNNCell
,这是一个实现了简单的RNN单元操作的类。 -
创建训练数据:
xt = tf.Variable(np.random.randint(2, 3, size=[1, 1]), dtype=tf.float32) print(xt)
这里创建了一个
1x1
的张量,其值是2或3之间的随机整数。这代表了在时间t
的输入数据。 -
定义RNN单元:
cell = SimpleRNNCell(units=1, activation=None, use_bias=True, kernel_initializer='ones', recurrent_initializer='ones', bias_initializer=tf.keras.initializers.Constant(value=3))
使用
SimpleRNNCell
创建了一个RNN单元。这个单元有以下特性:- 只有一个神经元(
units=1
)。 - 不使用激活函数(
activation=None
)。 - 使用偏置,并初始化为3(
bias_initializer=tf.keras.initializers.Constant(value=3)
)。 - 输入权重和循环权重都初始化为1。
kernel_initializer='ones'
:- 这是一个初始化器,用于初始化RNN单元的权重(也称为内核权重)。
'ones'
表示所有的权重都被初始化为1。- 换句话说,当输入数据经过RNN单元时,它会与这些权重相乘,而这些权重的初始值都是1。
recurrent_initializer='ones'
:- 这是一个初始化器,用于初始化RNN单元的循环权重。
- 在RNN中,当前时间步的隐藏状态是基于前一个时间步的隐藏状态计算的。这个计算涉及到的权重就是循环权重。
'ones'
表示所有的循环权重都被初始化为1。
bias_initializer=tf.keras.initializers.Constant(value=3)
:- 这是一个初始化器,用于初始化RNN单元的偏置。
tf.keras.initializers.Constant(value=3)
表示所有的偏置被初始化为常数3。
- 简而言之,这些参数(kernel_initializer、recurrent_initializer、bias_initializer)确定了RNN单元在开始训练之前的权重和偏置的初始状态。这些初始值在训练过程中会被更新。选择合适的初始化器对于模型的收敛速度和性能至关重要,尽管在这个特定的例子中,这些权重和偏置被赋予了特定的常数值。
cell.build(input_shape=[None, 1])
这行代码是用来告诉RNN单元输入的形状,这样它就可以创建相应的权重和偏置张量。- 在TensorFlow和Keras中,
input_shape
是用来指定输入数据的维度的参数。具体到这里的input_shape=[None, 1]
,我们可以解读它为: [None, 1]
:这是一个形状列表,其中有两个维度。None
:- 第一个维度通常表示批处理的大小(即在一个批次中的样本数)。在许多情况下,为了使模型更加灵活,我们可能不想在定义模型时硬编码一个固定的批处理大小。
- 使用
None
作为批处理的大小意味着模型可以接受任何大小的批次。 - 例如,你可以选择在训练时使用64的批大小,在评估或推理时使用1的批大小,或者使用其他任何数字。
1
:- 第二个维度是数据的特征维度。
- 在这里,它指的是输入数据的每个样本有1个特征。
- 综上所述,
input_shape=[None, 1]
表示模型可以接受一个二维的输入,其中第一个维度是任意大小的批处理,第二个维度是1个特征。
- 只有一个神经元(
-
显示RNN单元的变量和配置:
代码打印出RNN单元的所有变量(如权重和偏置)以及配置。print('variables', cell.variables) print('config:', cell.get_config())
这两行代码是关于打印关于
cell
(这里的cell
是一个SimpleRNNCell
的实例)的相关信息。-
print('variables', cell.variables)
:cell.variables
: 这是一个属性,它返回一个列表,该列表包含cell
中的所有可训练变量(权重和偏置)。在RNN cell的上下文中,这通常包括核权重、递归权重以及偏置。print(...)
: 打印变量列表,以便于你查看和调试。通常这可以帮助你理解RNN cell中的权重如何初始化(例如,这里你已经明确地设置了初始化器)。
-
print('config:', cell.get_config())
:cell.get_config()
: 这是一个方法,它返回一个字典,该字典包含cell
的配置。这通常包括其初始化时使用的参数(例如units的数量、激活函数、是否使用偏置等)。这允许你查看或者后续再次使用这些配置信息,例如,如果你想保存模型的结构并稍后再次创建它。print(...)
: 打印配置字典,使你能够查看cell
的配置。
-
总之,这两行代码提供了关于
SimpleRNNCell
实例(cell
)的详细信息,包括它的权重(和它们的初始值)以及它的配置。这是非常有用的,特别是当你在调试或了解你的模型结构时。
-
-
计算tanh的值:
print(tf.nn.tanh(tf.constant([-float("inf"), 6, float("inf")])))
这行代码计算了
tanh
函数在-∞
、6和∞
三个点的值。tanh是RNN和其他神经网络中常用的激活函数。 -
第t时刻的计算:
这部分代码首先定义了上一个时间步的隐藏状态ht_1
,然后使用cell(xt, ht_1)
调用RNN单元来获取当前时间步的输出和隐藏状态。ht_1 = tf.ones([1, 1]) out, ht = cell(xt, ht_1) # LSTM print(out, ht[0]) print(id(out), id(ht[0]))
-
第t+1时刻的计算:
同样地,这部分代码定义了一个新的RNN单元cell2
,然后用新的输入xt2
和上一个时间步的隐藏状态ht
来获取下一个时间步的输出和隐藏状态。cell2 = SimpleRNNCell(units=1, activation=None, use_bias=True, kernel_initializer='ones', recurrent_initializer=tf.keras.initializers.Constant(value=3), bias_initializer='ones') xt2 = tf.Variable(np.random.randint(3, 4, size=[1, 1]), dtype=tf.float32) out2, ht2 = cell2(xt2, ht)
-
输出与隐藏状态的关系:
print(id(out), id(ht[0]))
这部分代码展示了在简单的RNN中,输出状态
out
和隐藏状态ht
是相同的对象。
最后,代码的主要目的是演示如何使用SimpleRNNCell
在给定的输入和隐藏状态上进行计算,并展示其结果。
知识点介绍
tf.Variable
是 TensorFlow(TF)中的一个核心概念,它用于表示在 TF 计算过程中可能会发生变化的数据。在 TF 中,计算通常是通过计算图(graph)来定义的,而 tf.Variable
允许我们将可以变化的状态添加到这些计算图中。
以下是 tf.Variable
的一些关键点:
-
可变性:与 TensorFlow 的常量(
tf.constant
)不同,tf.Variable
表示的值是可变的。这意味着在训练过程中,可以更新、修改或赋予其新值。 -
用途:
tf.Variable
通常用于表示模型的参数,例如神经网络中的权重和偏置。 -
初始化:当创建一个
tf.Variable
时,你必须为它提供一个初始值。这个初始值可以是一个固定值,也可以是其他任何 TensorFlow 计算的结果。 -
赋值:使用
assign
、assign_add
等方法,你可以修改tf.Variable
的值。 -
存储和恢复:
tf.Variable
的值可以被存储到磁盘并在之后恢复,这是通过 TensorFlow 的保存和恢复机制实现的,这样可以方便地保存和加载模型。
示例:
import tensorflow as tf
# 创建一个初始化为1的变量
v = tf.Variable(1.0)
# 使用变量
result = v * 2.0
# 修改变量的值
v.assign(2.0) # 现在 v 的值为 2.0
总之,tf.Variable
是 TensorFlow 中表示可变状态的主要方式,尤其是在模型训练中,它用于存储和更新模型的参数。