在gihub上: https://github.com/torch/tutorials/blob/master/2_supervised/4_train.lua 我们有一个定义训练过程的脚本示例。我对这个脚本中feval函数的构造很感兴趣。
-- create closure to evaluate f(X) and df/dX
local feval = function(x)
-- get new parameters
if x ~= parameters then
parameters:copy(x)
end
-- reset gradients
gradParameters:zero()
-- f is the average of all criterions
local f = 0
-- evaluate function for complete mini batch
for i = 1,#inputs do
-- estimate f
local output = model:forward(inputs[i])
local err = criterion:forward(output, targets[i])
f = f + err
-- estimate df/dW
local df_do = criterion:backward(output, targets[i])
model:backward(inputs[i], df_do)
-- update confusion
confusion:add(output, targets[i])
end
-- normalize gradients and f(X)
gradParameters:div(#inputs)
f = f/#inputs
-- return f and df/dX
return f,gradParameters
end
我尝试通过抑制循环来修改此函数: 对于i = 1,#输入做... 因此,不是通过输入(输入[i])进行前向和后向输入,而是为整个小批量(输入)执行此操作。这真的加快了这个过程。这是修改脚本:
-- create closure to evaluate f(X) and df/dX
local feval = function(x)
-- get new parameters
if x ~= parameters then
parameters:copy(x)
end
-- reset gradients
gradParameters:zero()
-- f is the average of all criterions
local f = 0
-- evaluate function for complete mini batch
-- estimate f
local output = model:forward(inputs)
local f = criterion:forward(output, targets)
-- estimate df/dW
local df_do = criterion:backward(output, targets)
-- update weight
model:backward(inputs, df_do)
-- update confusion
confusion:batchAdd(output, targets)
-- return f and df/dX
return f,gradParameters
end
但是当我详细检查给定迷你批次的feval(f,gradParameters)的返回时,我们在循环和没有循环的情况下没有相同的结果。
所以我的问题是: 1 - 为什么我们有这个循环? 2 - 没有这个循环可以获得相同的结果吗?
此致 萨姆
注意:我是Torch7的初学者
答案 0 :(得分:0)
我确定你注意到第二种工作方式需要的不仅仅是改变feval。 在第二个示例中,输入需要是4D张量,而不是3D张量表(除非自上次更新以来发生了某些变化)。根据所使用的损耗标准/模型,这些张量具有不同的尺寸。实施该示例的人必须认为循环是一种更容易的方式。此外,ClassNLLCriterion似乎不喜欢批处理(人们通常会使用CrossEntropy标准来解决这个问题)。
除此之外,这两种方法应该给出相同的结果。唯一的细微差别是第一个示例使用平均误差/渐变,第二个示例使用总和,如下所示:
gradParameters:div(inputs:size(1))
f = f/inputs:size(1)
在第二种情况下,f和gradParameters应该与opt.batchSize因子中的第一个不同。出于优化目的,这些在数学上是等效的。