为不同的层指定相应的学习率可能会有些用处,印象中,这个在caffe里面是在定义网络时指定的,用mxnet后一直没用到过。这放一些字符,以备查。
接口
思路来自于。
但在optimizer.py
中,相应的接口为set_lr_mult(self, args_lr_mult)
。 其思路是:在 mod._optimizer 内部定义一个字典以记录每个参数的学习率乘子。 值得注意的是,从程序上来看,这个接口并不是按照层为单位进行学习率设定,而是对具体的参数进行设置(比如:conv1_weight
)。 Nov 5, 2017
试验的几次都把怀疑目标指向了这个地方,今早测试了下。问题出在set_lr_mult
传入的dictionary
上,其内容应当包括所有要调整的参数,不能使用单个多次指定的方式。
测试
# updated on Nov 5, 2017import mxnet as mxM,N=3,3num_filter=1kernel=mx.nd.array([ [1,2,3],[1,2,3],[1,2,3] ])d=mx.sym.Variable('data')conv1=mx.sym.Convolution(data=d,kernel=(3,3),num_filter=num_filter,no_bias=False,name='conv1')loss=mx.sym.MakeLoss(data=conv1)bch_kernel=kernel.reshape((1,1,M,N))arg_params={'conv1_weight': bch_kernel}mod=mx.mod.Module(symbol=loss,data_names=('data',),label_names=None)mod.bind(data_shapes=[ ('data',[1,1,M,N]),])mod.init_params() mod.init_optimizer() ################################################################### Solution I ############################################################################mod._optimizer.set_lr_mult({'conv1_weight':0}) # 单个多次指定->失败mod._optimizer.set_lr_mult({'conv1_bias':0}) mod._optimizer.sym.list_arguments()#['data', 'conv1_weight']mod._optimizer.sym.attr_dict()#{'conv1': {'no_bias': 'True', 'kernel': '(3, 3)', 'num_filter': '1'}, 'conv1_weight': {'no_bias': 'True', 'kernel': '(3, 3)', 'num_filter': '1'}}### test ###############mod.forward(mx.io.DataBatch([bch_kernel]))mod.get_outputs()[0].asnumpy()#array([[[[ 0.06028102]]]], dtype=float32)mod.backward()mod.update()mod.backward()mod.update()mod.backward()mod.update()mod.backward()mod.update()mod.forward(mx.io.DataBatch([bch_kernel]))mod.get_outputs()[0].asnumpy()#array([[[[-1.61971903]]]], dtype=float32) !test failed################################################################### Solution II ############################################################################mod._optimizer.set_lr_mult({'conv1_bias':0,'conv1_weight':0}) # 一次指定完成mod._optimizer.sym.list_arguments()#['data', 'conv1_weight']mod._optimizer.sym.attr_dict()#{'conv1': {'no_bias': 'True', 'kernel': '(3, 3)', 'num_filter': '1'}, 'conv1_weight': {'no_bias': 'True', 'kernel': '(3, 3)', 'num_filter': '1'}}### test ###############mod.forward(mx.io.DataBatch([bch_kernel]))mod.get_outputs()[0].asnumpy()#array([[[[ 0.06028102]]]], dtype=float32)mod.backward()mod.update()mod.backward()mod.update()mod.backward()mod.update()mod.backward()mod.update()mod.forward(mx.io.DataBatch([bch_kernel]))mod.get_outputs()[0].asnumpy()#array([[[[ 0.06028102]]]], dtype=float32) !test OK~
Jul 31, 2018
最近又要用到这方面的借口了,现在是gluon的江湖,一切向之看齐。 gluon推出了两个关于优化的接口,一个是固有的 optimizer,另一个是新加入的Trainer。 通常同Trainer作为训练时的接口,但这两个类都接受Opt的参数,于是要检查下之前的设置是否合适。- Trainer在step时调用optimizer中的updater,在update中,首先调用_get_lr获得Param的lr*:
# _get_lr(self, index): from optimizer.py ¦ if index in self.param_dict: ¦ ¦ lr *= self.param_dict[index].lr_mult ¦ elif index in self.lr_mult: ¦ ¦ lr *= self.lr_mult[index] ¦ elif index in self.idx2name: ¦ ¦ lr *= self.lr_mult.get(self.idx2name[index], 1.0)
所以直接在ParamDict里面设置就好:
:import mxnet as mxmodel = mx.gluon.nn.Sequential()with model.name_scope(): model.add(mx.gluon.nn.Embedding(30, 10)) ¦ model.add(mx.gluon.rnn.LSTM(20)) ¦ ¦ model.add(mx.gluon.nn.Dense(5, flatten=False))d1 = model.collect_params()model = mx.gluon.rnn.SequentialRNNCell()with model.name_scope(): model.add(mx.gluon.rnn.LSTMCell(20)) ¦ model.add(mx.gluon.rnn.LSTMCell(20))d2 = model.collect_params()d = mx.gluon.ParamDict()d1.setattr('lr_mult',.01) # 直接设置 lr_multd2.setattr('lr_mult',10)d.update(d1)d.update(d1)d['sequential0_dense0_weight'].lr_mult # 合并后无影响d['sequentialrnncell0_lstm0_i2h_weight'].lr_mult
推测mxnet一贯使用引用手法,所以直接合并几个model的ParamDict,不会影响,但合并对于使用统一的Trainer接口却是必要的(不然会需要多个Trainer对应不同的model part)。