作者:k57784506 | 来源:互联网 | 2023-06-07 03:26
API:gluon中每个Parameters或者Block都有前缀prefix,Parameters的名字由用户指定,Block的名字可以由用户指定或自动生成。from__futu
API:gluon中每个Parameters或者Block都有前缀prefix,Parameters的名字由用户指定,Block的名字可以由用户指定或自动生成。
from __future__ import print_function
import mxnet as mx
from mxnet import gluon
Naming Blocks
创建Block时可以手动施加前缀:
mydense = gluon.nn.Dense(100, prefix=‘mydense_‘)
print(mydense.prefix)
mydense_
当不给定前缀时,gluon会自动生成:
dense0 = gluon.nn.Dense(100)
print(dense0.prefix)
dense0_
当创建更多同类型的Blocks时,会自动递增前缀名以免冲突:
dense1 = gluon.nn.Dense(100)
print(dense1.prefix)
dense1_
Naming Parameters
Block中的参数将通过在参数名称前加上块的前缀来命名:
print(dense0.collect_params())
dense0_ (
Parameter dense0_weight (shape=(100, 0), dtype=‘numpy.float32‘>)
Parameter dense0_bias (shape=(100,), dtype=‘numpy.float32‘>)
)
Name scopes
要管理嵌套Block的名称,每个Block都附加一个名称范围name_scope。在名称作用域内创建的所有块的名称前都会加上其父块的前缀。
class Model(gluon.Block):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
with self.name_scope():
self.dense0 = gluon.nn.Dense(20)
self.dense1 = gluon.nn.Dense(20)
self.mydense = gluon.nn.Dense(20, prefix=‘mydense_‘)
def forward(self, x):
x = mx.nd.relu(self.dense0(x))
x = mx.nd.relu(self.dense1(x))
return mx.nd.relu(self.mydense(x))
现在验证一下:
model0 = Model()
model0.initialize()
model0(mx.nd.zeros((1, 20)))
print(model0.prefix)
print(model0.dense0.prefix)
print(model0.dense1.prefix)
print(model0.mydense.prefix)
model0_
model0_dense0_
model0_dense1_
model0_mydense_
若再次对Model进行实例化,则也会进行递增前缀以免冲突:
model1 = Model()
print(model1.prefix)
print(model1.dense0.prefix)
print(model1.dense1.prefix)
print(model1.mydense.prefix)
model1_
model1_dense0_
model1_dense1_
model1_mydense_
强烈推荐手动在最高level的Block指定前缀,例如:model=Molde(prefix=‘mymodel_’)。
以上原则适用于所有的container:
并且name_scope可以用在__init__里,或者__init__外面,像这样:
with net.name_scope():
net.add(gluon.nn.Dense(20))
net.add(gluon.nn.Dense(20))
print(net.prefix)
print(net[0].prefix)
print(net[1].prefix)
sequential0_
sequential0_dense0_
sequential0_dense1_
gluon.model_zoo
也一样:
net = gluon.nn.Sequential()
with net.name_scope():
net.add(gluon.model_zoo.vision.alexnet(pretrained=True))
net.add(gluon.model_zoo.vision.alexnet(pretrained=True))
print(net.prefix, net[0].prefix, net[1].prefix)
sequential1_ sequential1_alexnet0_ sequential1_alexnet1_
Saving and loading
由于上面定义的model0和model1前缀不同,所以其参数名字也不同:
print(model0.collect_params(), ‘\n‘)
print(model1.collect_params())
model0_ (
Parameter model0_dense0_weight (shape=(20L, 20L), dtype=‘numpy.float32‘>)
Parameter model0_dense0_bias (shape=(20L,), dtype=‘numpy.float32‘>)
Parameter model0_dense1_weight (shape=(20L, 20L), dtype=‘numpy.float32‘>)
Parameter model0_dense1_bias (shape=(20L,), dtype=‘numpy.float32‘>)
Parameter model0_mydense_weight (shape=(20L, 20L), dtype=‘numpy.float32‘>)
Parameter model0_mydense_bias (shape=(20L,), dtype=‘numpy.float32‘>)
)
model1_ (
Parameter model1_dense0_weight (shape=(20, 0), dtype=‘numpy.float32‘>)
Parameter model1_dense0_bias (shape=(20,), dtype=‘numpy.float32‘>)
Parameter model1_dense1_weight (shape=(20, 0), dtype=‘numpy.float32‘>)
Parameter model1_dense1_bias (shape=(20,), dtype=‘numpy.float32‘>)
Parameter model1_mydense_weight (shape=(20, 0), dtype=‘numpy.float32‘>)
Parameter model1_mydense_bias (shape=(20,), dtype=‘numpy.float32‘>)
)
这时如果保存了model0的参数,想load进model1,那么由于名字不匹配,就可能导致load失败:
model0.collect_params().save(‘model.params‘)
try:
model1.collect_params().load(‘model.params‘, mx.cpu())
except Exception as e:
print(e)
Parameter ‘model1_dense0_weight‘ is missing in file ‘model.params‘, which contains parameters: ‘model0_mydense_weight‘, ‘model0_dense1_bias‘, ‘model0_dense1_weight‘, ‘model0_dense0_weight‘, ‘model0_dense0_bias‘, ‘model0_mydense_bias‘. Please make sure source and target networks have the same prefix.
为此,正确的姿势是使用save_parameters
/load_parameters
而不是collect_params
和 save
/load
.
save_parameters使用的是模型结构,而不用名字来匹配。
model0.save_parameters(‘model.params‘)
model1.load_parameters(‘model.params‘)
print(mx.nd.load(‘model.params‘).keys())
[‘dense0.bias‘, ‘mydense.bias‘, ‘dense1.bias‘, ‘dense1.weight‘, ‘dense0.weight‘, ‘mydense.weight‘]
Replacing Blocks from networks and fine-tuning
将预训练模型的output为1000类,改为100类的分类层:
alexnet = gluon.model_zoo.vision.alexnet(pretrained=True)
print(alexnet.output)
print(alexnet.output.prefix)
Dense(4096 -> 1000, linear)
alexnet0_dense2_
更改分类层:
with alexnet.name_scope():
alexnet.output = gluon.nn.Dense(100)
alexnet.output.initialize()
print(alexnet.output)
print(alexnet.output.prefix)
Dense(None -> 100, linear)
alexnet0_dense3_