我是 Tensorflow 的新手,想了解 keras LSTM layer所以我写了这个 测试程序以辨别 stateful 选项的行为。
#Tensorflow 1.x version
import tensorflow as tf
import numpy as np
NUM_UNITS=1
NUM_TIME_STEPS=5
NUM_FEATURES=1
BATCH_SIZE=4
STATEFUL=True
STATEFUL_BETWEEN_BATCHES=True
lstm = tf.keras.layers.LSTM(units=NUM_UNITS, stateful=STATEFUL,
return_state=True, return_sequences=True,
batch_input_shape=(BATCH_SIZE, NUM_TIME_STEPS, NUM_FEATURES),
kernel_initializer='ones', bias_initializer='ones',
recurrent_initializer='ones')
x = tf.keras.Input((NUM_TIME_STEPS,NUM_FEATURES),batch_size=BATCH_SIZE)
result = lstm(x)
I = tf.compat.v1.global_variables_initializer()
sess = tf.compat.v1.Session()
sess.run(I)
X_input = np.array([[[3.14*(0.01)] for t in range(NUM_TIME_STEPS)] for b in range(BATCH_SIZE)])
feed_dict={x: X_input}
def matprint(run, mat):
print('Batch = ', run)
for b in range(mat.shape[0]):
print('Batch Sample:', b, ', per-timestep output')
print(mat[b].squeeze())
print('BATCH_SIZE = ', BATCH_SIZE, ', T = ', NUM_TIME_STEPS, ', stateful =', STATEFUL)
if STATEFUL:
print('STATEFUL_BETWEEN_BATCHES = ', STATEFUL_BETWEEN_BATCHES)
for r in range(2):
feed_dict={x: X_input}
OUTPUT_NEXTSTATES = sess.run({'result': result}, feed_dict=feed_dict)
OUTPUT = OUTPUT_NEXTSTATES['result'][0]
NEXT_STATES=OUTPUT_NEXTSTATES['result'][1:]
matprint(r,OUTPUT)
if STATEFUL:
if STATEFUL_BETWEEN_BATCHES:
#For TF version 1.x manually re-assigning states from
#the last batch IS required for some reason ...
#seems like a bug
sess.run(lstm.states[0].assign(NEXT_STATES[0]))
sess.run(lstm.states[1].assign(NEXT_STATES[1]))
else:
lstm.reset_states()
请注意,LSTM 的权重设置为全 1,并且输入是恒定的以保持一致性。
正如预期的那样,当 statueful=False 没有样本、时间或批间时的脚本输出 依赖:
BATCH_SIZE = 4 , T = 5 , stateful = False
Batch = 0
Batch Sample: 0 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 1 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 2 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 3 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch = 1
Batch Sample: 0 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 1 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 2 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 3 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
在设置 stateful=True 后,我期望每个批处理中的样本产生不同的输出( 大概是因为 TF 图在批处理样本之间保持状态)。然而,情况并非如此:
BATCH_SIZE = 4 , T = 5 , stateful = True
STATEFUL_BETWEEN_BATCHES = True
Batch = 0
Batch Sample: 0 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 1 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 2 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 3 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch = 1
Batch Sample: 0 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 1 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 2 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 3 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
特别注意同一批处理的前两个样本的输出是相同的。
编辑:OverlordGoldDragon 通知了我 这种行为是预料之中的,而我的困惑在于 Batch 之间的区别——一组 (samples, timesteps, features) -- 和 Sample 批处理(或批处理的单个“行”)。 用下图表示:
因此,这提出了给定批处理的各个样本之间的依赖性(如果有的话)的问题。来自 根据我脚本的输出,我相信 每个 样本都被馈送到(逻辑上)单独的 LSTM block - 并且 差异样本的 LSTM 状态是独立的。我在这里画了这个:
我的理解正确吗?
顺便说一句,stateful=True 在 TensorFlow 1.x 中似乎被破坏了,因为如果我删除显式 分配上一批的状态:
sess.run(lstm.states[0].assign(NEXT_STATES[0]))
sess.run(lstm.states[1].assign(NEXT_STATES[1]))
它停止工作,即第二批的输出与第一批相同。
我用 Tensorflow 2.0 语法重写了上面的脚本,行为符合我的预期 (无需在批处理之间手动转移 LSTM 状态):
#Tensorflow 2.0 implementation
import tensorflow as tf
import numpy as np
NUM_UNITS=1
NUM_TIME_STEPS=5
NUM_FEATURES=1
BATCH_SIZE=4
STATEFUL=True
STATEFUL_BETWEEN_BATCHES=True
lstm = tf.keras.layers.LSTM(units=NUM_UNITS, stateful=STATEFUL,
return_state=True, return_sequences=True,
batch_input_shape=(BATCH_SIZE, NUM_TIME_STEPS, NUM_FEATURES),
kernel_initializer='ones', bias_initializer='ones',
recurrent_initializer='ones')
X_input = np.array([[[3.14*(0.01)]
for t in range(NUM_TIME_STEPS)]
for b in range(BATCH_SIZE)])
@tf.function
def forward(x):
return lstm(x)
def matprint(run, mat):
print('Batch = ', run)
for b in range(mat.shape[0]):
print('Batch Sample:', b, ', per-timestep output')
print(mat[b].squeeze())
print('BATCH_SIZE = ', BATCH_SIZE, ', T = ', NUM_TIME_STEPS, ', stateful =', STATEFUL)
if STATEFUL:
print('STATEFUL_BETWEEN_BATCHES = ', STATEFUL_BETWEEN_BATCHES)
for r in range(2):
OUTPUT_NEXTSTATES = forward(X_input)
OUTPUT = OUTPUT_NEXTSTATES[0].numpy()
NEXT_STATES=OUTPUT_NEXTSTATES[1:]
matprint(r,OUTPUT)
if STATEFUL:
if STATEFUL_BETWEEN_BATCHES:
pass
#Explicitly re-assigning states from the last batch isn't
# required as the model maintains inter-batch history.
#This is NOT the same behavior for TF.version < 2.0
#lstm.states[0].assign(NEXT_STATES[0].numpy())
#lstm.states[1].assign(NEXT_STATES[1].numpy())
else:
lstm.reset_states()
这是输出:
BATCH_SIZE = 4 , T = 5 , stateful = True
STATEFUL_BETWEEN_BATCHES = True
Batch = 0
Batch Sample: 0 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 1 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 2 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch Sample: 3 , per-timestep output
[0.38041887 0.663519 0.79821336 0.84627265 0.8617684 ]
Batch = 1
Batch Sample: 0 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 1 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 2 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
Batch Sample: 3 , per-timestep output
[0.86686385 0.8686781 0.8693927 0.8697042 0.869853 ]
请您参考如下方法:
一切似乎都按预期工作 - 但代码需要大量修改:
Batch: 0应该是Sample: 0;您的batch_shape=(4, 5, 1),包含 4 个样本、5 个时间步 和 1 个特征/ channel 。I在你的例子中是实际的批标记- 每个样本都被视为一个独立序列,所以它就像先喂样本 1,然后喂样本 2 - 除了在学习期间,批量样本损失被平均以计算梯度
- 您的每个样本都是相同 - 因此为每个批处理获得相同的输出是明智的;运行
print(X_input)来验证 - Stateful 按预期工作:给定相同 输入,
stateful=False产生相同 输出(因为没有维护内部状态)- 而stateful=True为不同的I产生不同的输出,即使输入是相同的(由于内存) - 照原样,您的
lstm不是学习,所以权重是相同的 - 所有stateful=False输出都将是相同的输入相同 - 强烈建议不要将所有权重初始化为相同的值 - 相反,请使用 random seed
