在没有中间梯度反向传播的情况下,mxnet 模型不会为相同的输入产生相同的输出
mxnet model does not produce same output for same input with no intermediate gradient backprop
我有一些使用 Tensorflow 的经验,但使用 mxnet 的时间只有一周左右。当我在下面的函数中遇到断点时,我试图理解某些代码的行为:
def train_and_eval(lr, end_date_str, pred):
model.collect_params().initialize(mx.init.Xavier(), ctx=ctx, force_reinit=True)
mgr = ProcessMgr(2, end_date_str)
for epoch in range(args_epochs):
for i in range(2):
if i == TRAIN_MODE:
mgr.switch_to_train()
elif epoch == args_epochs - 1 and i == VALIDATE_MODE:
mgr.switch_to_validate()
else:
break
while True:
try:
data, target, eval_target, date_str = mgr.get_batch()
data = gluon.utils.split_and_load(data, ctx)
target = gluon.utils.split_and_load(target, ctx)
eval_target = gluon.utils.split_and_load(eval_target, ctx)
data = [mx.nd.swapaxes(d, 0, 1) for d in data]
with autograd.record():
losses = [loss(model(X)[-args_batch_size:], Y) for X, Y in zip(data, target)]
null_loss_vals = sum([Y.square().sum().asscalar() for Y in target])
model_loss_vals = sum([sum(l).asscalar() for l in losses])
null_loss[i] += null_loss_vals
model_loss[i] += model_loss_vals
**pdb.set_trace() ## BREAK POINT IS HERE**
if i == TRAIN_MODE:
for l in losses:
l.backward()
x = 18
grads = [i.grad(ctx) for i in model.collect_params().values() if i._grad is not None]
gluon.utils.clip_global_norm(grads, args_clip)
trainer.step(GPU_COUNT * args_batch_size)
except:
print("completed an epoch")
break
我在计算损失时得到了一些意想不到的值,所以我设置了一个断点以查看发生了什么。问题是当我通过模型 运行 相同的数据时,我每次都得到不同的输出。下面我粘贴了一些我遇到 pdb
断点时的输出,并尝试通过 model
.
获取 运行 数据
<NDArray 38400x1 @gpu(0)>
(Pdb) model(data[0])
[[ 2.9265028e-01]
[ 9.3701184e-03]
[ 4.3234527e-02]
...
[-5.0668776e-09]
[-2.7628975e-08]
[-1.9340845e-08]]
<NDArray 38400x1 @gpu(0)>
(Pdb) model(data[0])
[[ 1.5275864e-01]
[ 2.0615126e-01]
[ 4.6957955e-02]
...
[-2.6077061e-08]
[-9.2040580e-09]
[-3.2883932e-08]]
<NDArray 38400x1 @gpu(0)>
(Pdb) data[0]
[[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
...
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]]
<NDArray 128x300x2 @gpu(0)>
(Pdb) data[0]
[[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
...
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]]
<NDArray 128x300x2 @gpu(0)>
(Pdb)
我对这里发生的事情感到困惑。我确实意识到我的代码可能不完全正确,因为我没有 运行 预测或推理模型中的任何东西(计划稍后 check/tackle),但 我不不明白每次我 运行 输入模型时模型本身似乎如何变化,即使我不是 运行ning backward()
或 trainer.step()
. Any洞察力将不胜感激。为什么会这样?
我唯一的猜测是隐藏状态可能在 运行 之间保留。但我认为我没有为此编写代码(我看到了一个示例,其中完成了此操作并且必须显式保存隐藏状态并将其反馈回 RNN)。特别是,我还没有为我的 gluon.Block
实现 begin_state
方法。我不确定如何验证或反驳这个猜测。
这是我的 gluon.Block 实施情况,以防相关:
class RNNModel(gluon.Block):
def __init__(self, mode, num_inputs, num_embed, num_hidden,
num_layers, dropout=0.5, tie_weights=False, **kwargs):
super(RNNModel, self).__init__(**kwargs)
with self.name_scope():
self.drop = nn.Dropout(dropout)
self.rnn = rnn.GRU(num_hidden, num_layers, dropout=dropout,
input_size=num_inputs)
self.decoder = nn.Dense(1, in_units = num_hidden)
self.num_hidden = num_hidden
def forward(self, inputs):
output = self.rnn(inputs)
output = self.drop(output)
decoded = self.decoder(output.reshape((-1, self.num_hidden)))
return decoded
我确定在 with autograd.record()
上下文中,隐藏状态必须不断进化,因为我没有在这个上下文之外看到这种行为。因为我的模型没有提供暴露隐藏状态的变量,所以我无法明确验证这一点,但它最有意义。我还能够确认暴露的权重(通过trainer._params
)没有改变,所以它必须是隐藏状态。
我有一些使用 Tensorflow 的经验,但使用 mxnet 的时间只有一周左右。当我在下面的函数中遇到断点时,我试图理解某些代码的行为:
def train_and_eval(lr, end_date_str, pred):
model.collect_params().initialize(mx.init.Xavier(), ctx=ctx, force_reinit=True)
mgr = ProcessMgr(2, end_date_str)
for epoch in range(args_epochs):
for i in range(2):
if i == TRAIN_MODE:
mgr.switch_to_train()
elif epoch == args_epochs - 1 and i == VALIDATE_MODE:
mgr.switch_to_validate()
else:
break
while True:
try:
data, target, eval_target, date_str = mgr.get_batch()
data = gluon.utils.split_and_load(data, ctx)
target = gluon.utils.split_and_load(target, ctx)
eval_target = gluon.utils.split_and_load(eval_target, ctx)
data = [mx.nd.swapaxes(d, 0, 1) for d in data]
with autograd.record():
losses = [loss(model(X)[-args_batch_size:], Y) for X, Y in zip(data, target)]
null_loss_vals = sum([Y.square().sum().asscalar() for Y in target])
model_loss_vals = sum([sum(l).asscalar() for l in losses])
null_loss[i] += null_loss_vals
model_loss[i] += model_loss_vals
**pdb.set_trace() ## BREAK POINT IS HERE**
if i == TRAIN_MODE:
for l in losses:
l.backward()
x = 18
grads = [i.grad(ctx) for i in model.collect_params().values() if i._grad is not None]
gluon.utils.clip_global_norm(grads, args_clip)
trainer.step(GPU_COUNT * args_batch_size)
except:
print("completed an epoch")
break
我在计算损失时得到了一些意想不到的值,所以我设置了一个断点以查看发生了什么。问题是当我通过模型 运行 相同的数据时,我每次都得到不同的输出。下面我粘贴了一些我遇到 pdb
断点时的输出,并尝试通过 model
.
<NDArray 38400x1 @gpu(0)>
(Pdb) model(data[0])
[[ 2.9265028e-01]
[ 9.3701184e-03]
[ 4.3234527e-02]
...
[-5.0668776e-09]
[-2.7628975e-08]
[-1.9340845e-08]]
<NDArray 38400x1 @gpu(0)>
(Pdb) model(data[0])
[[ 1.5275864e-01]
[ 2.0615126e-01]
[ 4.6957955e-02]
...
[-2.6077061e-08]
[-9.2040580e-09]
[-3.2883932e-08]]
<NDArray 38400x1 @gpu(0)>
(Pdb) data[0]
[[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
...
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]]
<NDArray 128x300x2 @gpu(0)>
(Pdb) data[0]
[[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
[[ 0. -4.]
[ 0. -4.]
[ 0. -4.]
...
[ 0. -4.]
[ 0. -4.]
[ 0. -4.]]
...
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]
...
[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]]
<NDArray 128x300x2 @gpu(0)>
(Pdb)
我对这里发生的事情感到困惑。我确实意识到我的代码可能不完全正确,因为我没有 运行 预测或推理模型中的任何东西(计划稍后 check/tackle),但 我不不明白每次我 运行 输入模型时模型本身似乎如何变化,即使我不是 运行ning backward()
或 trainer.step()
. Any洞察力将不胜感激。为什么会这样?
我唯一的猜测是隐藏状态可能在 运行 之间保留。但我认为我没有为此编写代码(我看到了一个示例,其中完成了此操作并且必须显式保存隐藏状态并将其反馈回 RNN)。特别是,我还没有为我的 gluon.Block
实现 begin_state
方法。我不确定如何验证或反驳这个猜测。
这是我的 gluon.Block 实施情况,以防相关:
class RNNModel(gluon.Block):
def __init__(self, mode, num_inputs, num_embed, num_hidden,
num_layers, dropout=0.5, tie_weights=False, **kwargs):
super(RNNModel, self).__init__(**kwargs)
with self.name_scope():
self.drop = nn.Dropout(dropout)
self.rnn = rnn.GRU(num_hidden, num_layers, dropout=dropout,
input_size=num_inputs)
self.decoder = nn.Dense(1, in_units = num_hidden)
self.num_hidden = num_hidden
def forward(self, inputs):
output = self.rnn(inputs)
output = self.drop(output)
decoded = self.decoder(output.reshape((-1, self.num_hidden)))
return decoded
我确定在 with autograd.record()
上下文中,隐藏状态必须不断进化,因为我没有在这个上下文之外看到这种行为。因为我的模型没有提供暴露隐藏状态的变量,所以我无法明确验证这一点,但它最有意义。我还能够确认暴露的权重(通过trainer._params
)没有改变,所以它必须是隐藏状态。