Torch 7入門続編(八)---終結編---Torchブログはもう書かない、どうせつらい
21809 ワード
これは最終編で、いくつかの穴や間違い点などを記録しましょう.以前も少し記録していました.Torchコードを書くときに遭遇する可能性のあるいくつかの問題に注意すべき点があり、ゆっくりとここに加えて参考にします.初回更新:2017-4-20 第2回更新:2017-4-21 第3更新:2017-4-24:mask操作を追加する3次元例 第4回更新:2017-10-31:「attempt to index field‘THNN’(a nil value)」を追加して解決.
1.カスタムレイヤーはreturn selfでなければなりません.义齿gradInput形式.
しゅつりょく
したがって、直接return tmpまたはreturn gradOutputは使用できません.そうでなければ、ネットワークの出力は実際には0です.updateGradInputでgradOutputに直接戻るもupdateOutputでinputを直接出力もselfに変換する必要がある.gradInputとself.output.なお、戻り値は複数であってもよい.たとえば
2.luaの三元演算子
luaのデフォルトパラメータはもちろん簡単です
でも時々君は
これが三元演算子で、Cのk=aに似ていますか?b : c
時々tensorのいくつかの位置で抽出することを望んで、これらの位置は矩形であることを要求しないで、任意の形状であることができます.普通はmaskを1つ譲るのです.このmaskは
些細な点
Tensor構造の場合、「代入操作」は最後にしたほうがよい
このときoutput 2の値はまたランダムになります
正しい書き方:
ネットワークの階層の情報を取得
実はmoduleクラスには2つの状態変数があります:
また,この階層の重み情報もある.
attempt to index field ‘THNN’ (a nil value)
何も言いたくない.の実は君が加えるのを忘れたんだ
ネットワークが重み値を更新する方法についてもう一度お話しします
一般的な関数
カスタムレイヤは、一般に、
各レイヤは、主な3つの機能ではないことは明らかです.「更新」出力(updateOutput)、「更新」入力の勾配(updateGradInput)、「計算」このレイヤのパラメータ勾配(accGradParameters).実は英語で翻訳するのが一番正確な意味です.カスタムレイヤにパラメータがない場合や、既存のレイヤの組み合わせで簡単に形成されている場合、特別な要求がない場合は、
updateParameters(learningRate)
しかし、一般的には
また、
要約:updateParametersを呼び出すと、ウェイト値が更新されます.backwardを呼び出すのは、各層のgradInputと各層のパラメータの勾配を計算するだけで、もちろん今ではoptimパッケージが使われているので、
回答:–なぜbackwardではなくupdateGradInputを使っているのかと聞かれるかもしれません.
これは,ここでGが生成したダミーパターンの勾配は,Dにできるだけダミーパターンが真図であると思わせることによってGを更新するためである.これはD対Gの一種の役割である.しかし、backwardを呼び出すとupdateGradInputだけでなくaccGradParametersも呼び出され、Dの制約が変更され、問題が発生します.だからupdateGradInputだけでもっと合います.
1.カスタムレイヤーはreturn selfでなければなりません.义齿gradInput形式.
function CustomizedLayer:updateOutput(input)
print('updateGradInput'..self.cls)
-- other code and get tmp
self.output = tmp
return self.output
end
function CustomizedLayer:updateGradInput(input, gradOutput)
print('updateGradInput'..self.cls)
self.gradInput = gradOutput
return self.gradInput
end
しゅつりょく
updateOutput..output 208554.015625
# net:forward(input) ,
..latent after customizedLayer: 0
したがって、直接return tmpまたはreturn gradOutputは使用できません.そうでなければ、ネットワークの出力は実際には0です.updateGradInputでgradOutputに直接戻るもupdateOutputでinputを直接出力もselfに変換する必要がある.gradInputとself.output.なお、戻り値は複数であってもよい.たとえば
...
function cLayer:updateOutput(input)
...
return self.ouput, self.k
end
2.luaの三元演算子
luaのデフォルトパラメータはもちろん簡単です
function myFun(a)
p = a or 1 -- or
end
でも時々君は
k = a and b or c
これが三元演算子で、Cのk=aに似ていますか?b : c
a = 1
b = a == 1 and 2 or 0 -- 2
a = 3
b = a == 1 and 2 or 0 -- 0
[]
でTensor取値補充を行うa = torch.Tensor(6,3,4,5)
-- 4
b = a[{{1},{1,3},{1,4},{1,5}] -- 1*3*4*5
b = a[{{1},{},{},{}] -- 1*3*4*5
b = a[1] -- 3*4*5
[ByteTensor]
でmask操作を行います時々tensorのいくつかの位置で抽出することを望んで、これらの位置は矩形であることを要求しないで、任意の形状であることができます.普通はmaskを1つ譲るのです.このmaskは
0 1
を充填するByteTensorタイプでなければならない.maskのある位置が1であると、maskのtensorの対応する位置の値がカスタム数字となる.-- bernoulli() 0 1 tensor
-- b = torch.ByteTensor(3,4):bernoulli()
b = torch.Tensor(3,4):apply(function()
if i > 0 then
i = i - 1
else
i = i + 1
end
return i
end)
--[[
b
1 0 1 0
1 0 1 0
1 0 1 0
[torch.DoubleTensor of size 3x4]
]]
b = b:byte()
a = torch.Tensor(2,3,4)
-- [b] mask
a[1][b] = 3
--[[
th>a
(1,.,.) =
3.0000e+00 6.9521e-310 3.0000e+00 0.0000e+00
3.0000e+00 7.8762e-114 3.0000e+00 3.6017e+227
3.0000e+00 4.6197e+281 3.0000e+00 8.2678e+140
(2,.,.) =
7.0981e+194 7.4861e-114 4.0622e-66 7.5656e-307
1.2946e+214 1.0740e-152 9.0870e+223 2.1724e-153
1.3085e+180 2.2462e-57 2.1724e-153 1.3085e+180
[torch.DoubleTensor of size 2x3x4]
]]
--
a = torch.rand(2,3,4):mul(4):floor():int()
th> a
(1,.,.) =
0 0 3 3
3 2 2 0
3 0 3 2
(2,.,.) =
1 2 3 3
3 3 3 3
0 3 2 3
[torch.IntTensor of size 2x3x4]
mask = torch.Tensor(2,3,4):bernoulli():byte()
th> mask
(1,.,.) =
0 1 0 1
1 0 1 1
0 0 1 1
(2,.,.) =
0 1 0 1
0 1 0 1
0 0 1 1
[torch.ByteTensor of size 2x3x4]
th> a[mask] = 0 -- 0
[0.0000s]
th> a
(1,.,.) =
0 0 3 0
0 2 0 0
3 0 0 0
(2,.,.) =
1 0 3 0
3 0 3 0
0 3 0 0
[torch.DoubleTensor of size 2x3x4]
些細な点
Tensor構造の場合、「代入操作」は最後にしたほうがよい
local input = torch.Tensor(3,4)
local output2 = torch.Tensor():zero():typeAs(input):resizeAs(input)
このときoutput 2の値はまたランダムになります
output2
6.9316e-310 6.9316e-310 0.0000e+00 0.0000e+00
0.0000e+00 2.1724e-153 5.4104e-67 8.0109e-307
8.4880e-314 1.0748e+160 2.1724e-153 9.5896e-308
[torch.DoubleTensor of size 3x4]
正しい書き方:
local input = torch.Tensor(3,4)
local output2 = torch.Tensor():typeAs(input):resizeAs(input):zero()
ネットワークの階層の情報を取得
実はmoduleクラスには2つの状態変数があります:
output
とgradInput
です.net.modules[i].output
net.modules[i].gradInput
また,この階層の重み情報もある.
net.modules[i].weight
net.modules[i].bias
net.modules[i].gradWeight
net.modules[i].gradBias
attempt to index field ‘THNN’ (a nil value)
何も言いたくない.の実は君が加えるのを忘れたんだ
require 'cunn'
ネットワークが重み値を更新する方法についてもう一度お話しします
一般的な関数
カスタムレイヤは、一般に、
__init__
、updateOuput
、およびupdateGradInput
の3つをリロードする.ネットワークforward関数が呼び出されると、各レイヤのupdateOutput
関数が自動的に呼び出されます.ネットワークbackward関数を呼び出すと、各レイヤのupdateGradInput(input,gradOutput)
およびaccGradParameters(input,gradOuput,scale)
も自動的に呼び出されます.function Module:backward(input, gradOutput, scale)
scale = scale or 1
self:updateGradInput(input, gradOutput)
self:accGradParameters(input, gradOutput, scale)
return self.gradInput
end
各レイヤは、主な3つの機能ではないことは明らかです.「更新」出力(updateOutput)、「更新」入力の勾配(updateGradInput)、「計算」このレイヤのパラメータ勾配(accGradParameters).実は英語で翻訳するのが一番正確な意味です.カスタムレイヤにパラメータがない場合や、既存のレイヤの組み合わせで簡単に形成されている場合、特別な要求がない場合は、
accGradParameters
を必要とせず、内部のこの関数を自動的に呼び出して計算を実現します.updateParameters(learningRate)
accGradParameters
勾配を計算した後、このレイヤのパラメータを更新する必要があります.updateParameters(learningRate)
を呼び出せばいいです.updateParameters(learningRate)は、parameters()
で内部のパラメータおよびパラメータの勾配を先に取得することを示す.その後、各パラメータを更新します.function Module:updateParameters(learningRate)
local params, gradParams = self:parameters()
if params then
for i=1,#params do
params[i]:add(-learningRate, gradParams[i])
end
end
end
しかし、一般的には
getParameters
を使用し、扁平なパラメータを返します.function Module:getParameters()
-- get parameters
local parameters,gradParameters = self:parameters()
local p, g = Module.flatten(parameters), Module.flatten(gradParameters)
assert(p:nElement() == g:nElement(),
'check that you are sharing parameters and gradParameters')
if parameters then
for i=1,#parameters do
assert(parameters[i]:storageOffset() == gradParameters[i]:storageOffset(),
'misaligned parameter at ' .. tostring(i))
end
end
return p, g
end
また、
zeroGradParameters()
は、パラメータの勾配をゼロにすることができる.function Module:zeroGradParameters()
local _,gradParams = self:parameters()
if gradParams then
for i=1,#gradParams do
gradParams[i]:zero()
end
end
end
要約:updateParametersを呼び出すと、ウェイト値が更新されます.backwardを呼び出すのは、各層のgradInputと各層のパラメータの勾配を計算するだけで、もちろん今ではoptimパッケージが使われているので、
updateParameters
を手動で呼び出すことは一般的ではありません.optimパッケージの使用方法については、http://blog.csdn.net/hungryof/article/details/66970563backwardは、各層のupdateGradInputおよびaccGradParametersを呼び出すだけで、重みパラメータは更新されず、パラメータの勾配を計算し、各層の入力の勾配を更新します.local fDx = function(x)
netD:apply(function(m) if torch.type(m):find('Convolution') then m.bias:zero() end end)
netG:apply(function(m) if torch.type(m):find('Convolution') then m.bias:zero() end end)
gradParametersD:zero()
-- Real
-- train netD with (real, real_label)
local output = netD:forward(real_AB)
local label = torch.FloatTensor(output:size()):fill(real_label)
if opt.gpu>0 then
label = label:cuda()
end
local errD_real = criterion:forward(output, label)
local df_do = criterion:backward(output, label)
-- real , netD , 。
netD:backward(real_AB, df_do)
-- Fake
-- train netD with (fake_AB, fake_label)
local output = netD:forward(fake_AB)
label:fill(fake_label)
local errD_fake = criterion:forward(output, label)
local df_do = criterion:backward(output, label)
-- netD 0, !
-- netD real fake , “ ” ,
-- gradParametersD 。
netD:backward(fake_AB, df_do)
errD = (errD_real + errD_fake)/2
return errD, gradParametersD
end
local fGx = function(x)
netD:apply(function(m) if torch.type(m):find('Convolution') then m.bias:zero() end end)
netG:apply(function(m) if torch.type(m):find('Convolution') then m.bias:zero() end end)
gradParametersG:zero()
-- GAN loss
local df_dg = torch.zeros(fake_B:size())
if opt.gpu>0 then
df_dg = df_dg:cuda();
end
if opt.use_GAN==1 then
local output = netD.output -- netD:forward{input_A,input_B} was already executed in fDx, so save computation
local label = torch.FloatTensor(output:size()):fill(real_label) -- fake labels are real for generator cost
if opt.gpu>0 then
label = label:cuda();
end
errG = criterion:forward(output, label)
local df_do = criterion:backward(output, label)
-- , updateGradInput backward ?
df_dg = netD:updateGradInput(fake_AB, df_do):narrow(2,fake_AB:size(2)-output_nc+1, output_nc)
else
errG = 0
end
-- unary loss
local df_do_AE = torch.zeros(fake_B:size())
if opt.gpu>0 then
df_do_AE = df_do_AE:cuda();
end
if opt.use_L1==1 then
errL1 = criterionAE:forward(fake_B, real_B)
df_do_AE = criterionAE:backward(fake_B, real_B)
else
errL1 = 0
end
netG:backward(real_A, df_dg + df_do_AE:mul(opt.lambda))
return errG, gradParametersG
end
回答:–なぜbackwardではなくupdateGradInputを使っているのかと聞かれるかもしれません.
これは,ここでGが生成したダミーパターンの勾配は,Dにできるだけダミーパターンが真図であると思わせることによってGを更新するためである.これはD対Gの一種の役割である.しかし、backwardを呼び出すとupdateGradInputだけでなくaccGradParametersも呼び出され、Dの制約が変更され、問題が発生します.だからupdateGradInputだけでもっと合います.