Embedding层 在 TensorFlow
中,可以通过 layers.Embedding(𝑁_vocab,𝑛)
来定义一个 Word Embedding
层,其中𝑁_vocab
参数指定词汇数量, 𝑛
指定embedding
后的单词向量的长度
1 2 3 4 5 6 7 x=tf.range (10 ) x=tf.random.shuffle(x) print (x)net=tf.keras.layers.Embedding(10 ,4 ) out=net(x)
tf.Tensor([1 0 8 9 3 4 5 6 2 7], shape=(10,), dtype=int32)
(10,4)
是一个句子的单词个数和embedding
后的向量长度,若有NUM
个句子,则shape
变为(NUM,10,4)
<tf.Variable 'embedding_10/embeddings:0' shape=(10, 4) dtype=float32, numpy=
array([[-0.04157337, 0.00370337, -0.04709859, -0.02110542],
[-0.012863 , -0.0340884 , 0.01296239, -0.02337525],
[-0.017204 , 0.02752179, 0.03275616, 0.04036881],
[ 0.01910862, 0.02488795, 0.04844334, -0.00992166],
[ 0.04279174, -0.01695721, 0.04229338, -0.01208165],
[ 0.04743797, -0.04877844, 0.03140882, -0.0335933 ],
[-0.03579624, 0.03655416, -0.0206341 , 0.00822543],
[ 0.0418619 , 0.00207099, -0.04340398, -0.00929434],
[ 0.00421256, -0.00119591, 0.04572577, 0.02811921],
[-0.01074129, -0.02198823, 0.00441085, -0.0223695 ]],
dtype=float32)>
<tf.Tensor: shape=(10, 4), dtype=float32, numpy=
array([[-0.012863 , -0.0340884 , 0.01296239, -0.02337525],
[-0.04157337, 0.00370337, -0.04709859, -0.02110542],
[ 0.00421256, -0.00119591, 0.04572577, 0.02811921],
[-0.01074129, -0.02198823, 0.00441085, -0.0223695 ],
[ 0.01910862, 0.02488795, 0.04844334, -0.00992166],
[ 0.04279174, -0.01695721, 0.04229338, -0.01208165],
[ 0.04743797, -0.04877844, 0.03140882, -0.0335933 ],
[-0.03579624, 0.03655416, -0.0206341 , 0.00822543],
[-0.017204 , 0.02752179, 0.03275616, 0.04036881],
[ 0.0418619 , 0.00207099, -0.04340398, -0.00929434]],
dtype=float32)>
1 net.embeddings.trainable
True
SimpleRNNCell 一层SimpleRNNCell网络 仅仅是完成了一个时间戳的前向运算
1 2 cell=tf.keras.layers.SimpleRNNCell(3 )
1 2 cell.build(input_shape=(None ,4 ))
1 cell.trainable_variables
[<tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
array([[-0.12730736, 0.49879634, -0.12697208],
[ 0.62330437, 0.8244791 , -0.45662448],
[ 0.89570665, -0.20918423, -0.8737987 ],
[-0.54977036, -0.05649453, -0.00607061]], dtype=float32)>,
<tf.Variable 'recurrent_kernel:0' shape=(3, 3) dtype=float32, numpy=
array([[-0.22971189, 0.9539083 , 0.19310963],
[-0.36177534, 0.10050881, -0.9268314 ],
[-0.90352154, -0.2827664 , 0.32201245]], dtype=float32)>,
<tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]
kernel
变量即𝑾 _xh
张量, recurrent_kernel
变量即𝑾 _hh
张量, bias
变量即偏置𝒃
向量
但是 RNN
的 Memory
向量 h
并不由SimpleRNNCell
维护,需要用户自行初始化向量h0
并记录每个时间戳上的 𝒕。
1 2 3 4 5 6 7 8 h0 = [tf.zeros([4 , 64 ])] x = tf.random.normal([4 , 80 , 100 ]) xt = x[:,0 ,:] cell = tf.keras.layers.SimpleRNNCell(64 ) out, h1 = cell(xt, h0) print (out.shape,h1[0 ].shape)
(4, 64) (4, 64)
1 2 print (id (out),id (h1[0 ]))
3078969475672 3078969475672
以上仅仅做了一个时间戳的前向运算,对于长度为s的序列来说,需要循环通过Cell
类𝑠
次才算完成一次网络层的前向运算
1 2 3 4 5 6 h = h0 for xt in tf.unstack(x, axis=1 ): out,h = cell(xt, h) out = out
<tf.Tensor: shape=(64,), dtype=float32, numpy=
array([-0.25621325, 0.51310164, -0.8620935 , -0.91738695, 0.23226644,
-0.66992235, -0.63344294, -0.9089617 , 0.72135305, -0.7318457 ,
-0.99582106, -0.9522287 , -0.6830161 , -0.7123331 , 0.95459735,
-0.5337273 , 0.2837275 , 0.972833 , 0.99199206, 0.9326225 ,
0.92419845, 0.9897123 , 0.98730296, -0.8111788 , 0.18107522,
0.6471946 , 0.95291704, 0.9300036 , -0.69558764, 0.758556 ,
0.21924002, -0.86336696, -0.2925538 , -0.53042555, 0.61276007,
0.31824008, 0.50052625, -0.609673 , 0.91918457, 0.31857985,
0.4469507 , 0.13685822, -0.03755331, 0.4636307 , 0.9822013 ,
-0.71981126, -0.9569911 , 0.9512179 , 0.86438775, 0.01853882,
-0.86230564, 0.86030304, -0.19372608, -0.99768096, 0.9988538 ,
0.77483326, 0.9892455 , 0.01369001, 0.9266391 , -0.9306773 ,
0.00980736, 0.29978752, 0.24117659, -0.45769033], dtype=float32)>
多层 SimpleRNNCell 网络 和卷积神经网络一样,循环神经网络虽然在时间轴上面展开了多次, 但只能算一个网络层
以两层的循环神经网络为例,介绍利用Cell
方式构建多层 RNN
网络。
1 2 3 4 5 6 7 8 x = tf.random.normal([4 ,80 ,100 ]) xt = x[:,0 ,:] cell0 = tf.keras.layers.SimpleRNNCell(64 ) cell1 = tf.keras.layers.SimpleRNNCell(64 ) h0 = [tf.zeros([4 ,64 ])] h1 = [tf.zeros([4 ,64 ])]
前向计算有两种方式:
方法1 :在时间轴上面循环计算多次来实现整个网络的前向运算,每个时间戳上的输入 xt
首先通过第一层,得到输出 out0
,再通过第二层,得到输出 out1
1 2 3 4 5 for xt in tf.unstack(x, axis=1 ): out0,h0 = cell0(xt,h0) out1,h1 = cell1(out0,h1)
上述方式先完成一个时间戳上的输入在所有层上的传播, 再循环计算完所有时间戳上的输 入
方法2 :先完成输入在第一层上所有时间戳的计算, 并保存第一层在所有时间戳上的输出列表,再计算第二层、第三层等的传播。代码如
1 2 3 4 5 6 7 8 9 middle_sequences = [] for xt in tf.unstack(x, axis=1 ): out0, h0 = cell0(xt, h0) middle_sequences.append(out0) for xt in middle_sequences: out1,h1=cell1(xt,h1)
一般来说,最末层Cell
的状态有可能保存了高层的全局语义特征, 因此一般使用最末层的输出作为后续任务网络的输入。
SimpleRNN 层 更高层的接口,可以省略之前手动参与的内部计算过程,比如每一层的 状态向量的初始化,以及每一层在时间轴上展开的运算
单层SimpleRNN 网络的前向运算 1 2 3 layer=tf.keras.layers.SimpleRNN(64 ) x = tf.random.normal([4 , 80 , 100 ]) out=layer(x)
TensorShape([4, 64])
通过SimpleRNN
可以仅需一行代码即可完成整个前向运算过程, 它默认返回最 后一个时间戳上的输出。
如果希望返回所有时间戳上的输出列表,可以设置 return_sequences=True
参数
1 2 3 4 layer = tf.keras.layers.SimpleRNN(64 ,return_sequences=True ) out = layer(x) out
<tf.Tensor: shape=(4, 80, 64), dtype=float32, numpy=
array([[[ 0.7579574 , 0.5203536 , -0.13247532, ..., -0.97075224,
-0.5602517 , 0.1896142 ],
[ 0.70799 , 0.8877379 , 0.8039977 , ..., -0.9796105 ,
-0.90698063, 0.92094153],
[-0.98230916, 0.38763395, -0.24368586, ..., -0.23982975,
-0.5587594 , 0.8005439 ],
...,
[ 0.9696948 , -0.56924766, 0.99460095, ..., 0.86883426,
0.7421469 , -0.16692714],
[ 0.98573875, -0.866003 , -0.8699877 , ..., -0.70909184,
0.79517734, 0.21344577],
[-0.4993558 , 0.9063643 , 0.90756595, ..., 0.63874185,
0.3061087 , 0.94876754]],
[[-0.953717 , 0.5357896 , -0.24438739, ..., -0.9902813 ,
0.65611756, 0.52405304],
[-0.945761 , 0.92643136, 0.93036115, ..., -0.9637114 ,
0.86534184, -0.19020523],
[-0.11487287, -0.8078128 , 0.95136124, ..., 0.79756886,
0.7799482 , 0.208571 ],
...,
[-0.92995924, -0.49086258, -0.49593148, ..., -0.50804 ,
0.5525898 , -0.92352575],
[ 0.87116635, -0.3758928 , 0.2159305 , ..., -0.6538404 ,
0.0528454 , 0.971082 ],
[-0.37672698, -0.9683858 , -0.9913551 , ..., 0.8241966 ,
0.99546564, -0.9172934 ]],
[[ 0.44561443, -0.72680014, -0.98325783, ..., -0.30991045,
0.7665605 , 0.0668956 ],
[ 0.9603438 , 0.9961231 , 0.43043685, ..., -0.3882459 ,
-0.53074616, 0.04012485],
[ 0.6547422 , 0.001742 , -0.18013465, ..., 0.72801995,
0.5303095 , -0.3371497 ],
...,
[ 0.71766 , -0.52994007, -0.03237867, ..., 0.2299321 ,
0.9955149 , 0.9458545 ],
[ 0.9850791 , 0.90992504, -0.44711468, ..., -0.9919823 ,
-0.16220197, 0.5074431 ],
[ 0.0717535 , 0.8818335 , -0.6376899 , ..., -0.86398774,
0.91119236, 0.99637604]],
[[-0.6396239 , -0.9482835 , 0.48356768, ..., 0.1447552 ,
0.24843507, 0.85139376],
[-0.9784054 , -0.60325694, -0.54072136, ..., 0.5444716 ,
-0.20786293, -0.9302095 ],
[ 0.92882097, 0.24866687, -0.02795087, ..., -0.8263675 ,
-0.23303777, 0.55453205],
...,
[ 0.6856851 , 0.18871786, 0.11841806, ..., -0.9009302 ,
0.9300211 , 0.311716 ],
[ 0.7124896 , 0.9189299 , -0.2578693 , ..., -0.4982193 ,
-0.98169625, 0.3771086 ],
[-0.96602875, 0.2520068 , 0.8261244 , ..., -0.7265942 ,
0.5231435 , -0.8301581 ]]], dtype=float32)>
返回的输出张量 shape
为[4,80,64]
,中间维度的 80
即为时间戳维度
多层SimpleRNN 网络的前向运算 1 2 3 4 5 6 7 8 net=tf.keras.Sequential([ tf.keras.layers.SimpleRNN(64 ,return_sequences=True ), tf.keras.layers.SimpleRNN(64 ), ]) out=net(x)
TensorShape([4, 64])
LSTMCell LSTMCell
的用法和SimpleRNNCell
基本一致, 区别在于LSTM
的状态变量 List
有两个, 即[ h𝑡, 𝒄𝑡]
, 需要分别初始化,其中List
第一个元素为 h𝑡
,第二个元素为𝒄𝑡
。
1 2 3 4 x=tf.random.normal([2 ,80 ,100 ]) xt=x[:,0 ,:] cell=tf.keras.layers.LSTMCell(64 )
1 2 3 4 state=[tf.zeros([2 ,64 ]),tf.zeros([2 ,64 ])] out,state=cell(xt,state)
1 id (out),id (state[0 ]),id (state[1 ])
(3078980607848, 3078980607848, 3078978869912)
返回的输出 out
和List
的第一个元素 h𝑡
的 id
是相同的,这与基础的RNN
初衷一致,都是为了格式的统一
通过在时间戳上展开循环运算,即可完成一次层的前向传播
1 2 3 for xt in tf.unstack(x,axis=1 ): out,state=cell(xt,state)
TensorShape([2, 64])
LSTM 层 一层LSTM层 1 2 3 4 layer=tf.keras.layers.LSTM(64 ) out = layer(x)
TensorShape([2, 64])
经过 LSTM
层前向传播后,默认只会返回最后一个时间戳的输出, 如果需要返回每个时间 戳上面的输出, 需要设置return_sequences=True
标志。
1 2 3 4 layer = tf.keras.layers.LSTM(64 , return_sequences=True ) out = layer(x)
TensorShape([2, 80, 64])
多层LSTM层 对于多层神经网络, 可以通过 Sequential
容器包裹多层 LSTM
层,并设置所有非末层网络 return_sequences=True
,这是因为非末层的 LSTM
层需要上一层在所有时间戳的输出 作为输入。
1 2 3 4 5 6 net = tf.keras.Sequential([ tf.keras.layers.LSTM(64 , return_sequences=True ), tf.keras.layers.LSTM(64 ) ]) out = net(x)
TensorShape([2, 64])
GRUCell 1 2 3 4 5 6 7 8 9 x=tf.random.normal([2 ,80 ,100 ]) h = [tf.zeros([2 ,64 ])] cell = tf.keras.layers.GRUCell(64 ) for xt in tf.unstack(x, axis=1 ): out, h = cell(xt, h) out.shape
TensorShape([2, 64])
GRU层 单层GRU 1 2 3 4 5 6 layer=tf.keras.layers.GRU(64 ) out = layer(x) out.shape
TensorShape([2, 64])
多层GRU 通过 layers.GRU
类可以方便创建一层 GRU
网络层,通过 Sequential
容器可以堆叠多 层 GRU
层的网络
1 2 3 4 5 6 net = tf.keras.Sequential([ tf.keras.layers.GRU(64 , return_sequences=True ), tf.keras.layers.GRU(64 ) ]) out = net(x) out.shape
TensorShape([2, 64])