mxnet symbol 和gluon 模型加载
常规流程
使用mxnet搭建模型模型的流程:主要包括数据准备,模型构建,超级参数选择,优化器,loss评价标准
数据准备
from mxnet import gluon
from mxnet.gluon import nn
import matplotlib.pyplot as plt
from mxnet import autograd as autograd
from mxnet import nd
import mxnet as mx
from collections import namedtuple
import random
数据准备gloun提供的MNIST数据集
def transform(data,label):
return data.astype('float32')/255,label.astype('float32')
fashion_train = gluon.data.vision.FashionMNIST(root='./',train=True,transform=transform)
fashion_test = gluon.data.vision.FashionMNIST(root='./',train=True, transform=transform)
batch_size = 256
train_data = gluon.data.DataLoader(fashion_train,batch_size,shuffle=True)
test_data = gluon.data.DataLoader(fashion_test,batch_size,shuffle=True)
定义精度评价函数
即是定义模型训练的评价标准,表示是实现acc函数
和定义验证流程
def accuracy(output, label):
return nd.mean(output.argmax(axis=1)==label).asscalar()
def evaluate_accuracy(data_iterator, net):
acc = 0.
for data, label in data_iterator:
output = net(nd.transpose(data,(0,3,1,2)))
acc += accuracy(output, label)
return acc / len(data_iterator)
定义网络
Gluon模型转到Symbol下只能用HybridSequential模式,HybridSequential是静态图,会对计算有优化,不过HybridSequential和Sequential可以很方便的转换
class MyDense(nn.HybridBlock):
def __init__(self,**kwargs):
super(MyDense,self).__init__(**kwargs)
with self.name_scope():
self.dense0 = nn.Dense(256)
self.dense1 = nn.Dense(10)
def hybrid_forward(self,F,x): # 这里要使用hybrid_forward而不是forward,并且多了个参数F
return self.dense1(F.relu(self.dense0(x))) # F的作用就是替代 nd,如果是静态图,就是用 sym,否则使用 nd
使用 自定义的层构成网络
网络定义和动态图一样,只不过把Sequential替换成了HybridSequential,在最后使用hybridize()会对静态图进行优化
登录
fiercex
路漫漫其修远兮,吾将上下而求索
MxNet新前端Gluon模型转换到Symbol
1. 导入各种包
from mxnet import gluon
from mxnet.gluon import nn
import matplotlib.pyplot as plt
from mxnet import autograd as autograd
from mxnet import nd
import mxnet as mx
from collections import namedtuple
import random
2. 准备数据
使用和mnist很像的FashionMNIST数据集,使用Gluon下载
def transform(data,label):
return data.astype('float32')/255,label.astype('float32')
fashion_train = gluon.data.vision.FashionMNIST(root='./',train=True,transform=transform)
fashion_test = gluon.data.vision.FashionMNIST(root='./',train=True, transform=transform)
batch_size = 256
train_data = gluon.data.DataLoader(fashion_train,batch_size,shuffle=True)
test_data = gluon.data.DataLoader(fashion_test,batch_size,shuffle=True)
用于显示图像和标签
def show_images(images):
n = images.shape[0]
_, figs = plt.subplots(1, n, figsize=(15, 15))
for i in range(n):
figs[i].imshow(images[i].reshape((28, 28)).asnumpy())
figs[i].axes.get_xaxis().set_visible(False)
figs[i].axes.get_yaxis().set_visible(False)
plt.show()
def get_text_labels(label):
text_labels = [
't-shirt', 'trouser', 'pullover', 'dress,', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot'
]
return [text_labels[int(i)] for i in label]
看下数据集长啥样
data,label = fashion_train[5:19]
show_images(data)
print(get_text_labels(label))
['coat', 'coat', 'sandal', 'coat', 'bag', 't-shirt', 'bag', 'ankle boot', 't-shirt', 'pullover', 'pullover', 'ankle boot', 'dress,', 'dress,']
3. 精度计算函数
def accuracy(output, label):
return nd.mean(output.argmax(axis=1)==label).asscalar()
def evaluate_accuracy(data_iterator, net):
acc = 0.
for data, label in data_iterator:
output = net(nd.transpose(data,(0,3,1,2)))
acc += accuracy(output, label)
return acc / len(data_iterator)
4. 定义网络
4.1 自己定义的层
Gluon模型转到Symbol下只能用HybridSequential模式,HybridSequential是静态图,会对计算有优化,不过HybridSequential和Sequential可以很方便的转换,确切的就是一行代码的事。同样自定义的网络,要使用HybridBlock,和Block没有多大区别
class MyDense(nn.HybridBlock):
def __init__(self,**kwargs):
super(MyDense,self).__init__(**kwargs)
with self.name_scope():
self.dense0 = nn.Dense(256)
self.dense1 = nn.Dense(10)
def hybrid_forward(self,F,x): # 这里要使用hybrid_forward而不是forward,并且多了个参数F
return self.dense1(F.relu(self.dense0(x))) # F的作用就是替代 nd,如果是静态图,就是用 sym,否则使用 nd
4.2 使用自定义的层和自带的层组成完整的网络
网络定义和动态图一样,只不过把Sequential替换成了HybridSequential,在最后使用hybridize()会对静态图进行优化
net = nn.HybridSequential()
with net.name_scope():
net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation='relu'))
net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
net.add(gluon.nn.Conv2D(channels=50, kernel_size=3, activation='relu'))
net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
net.add(gluon.nn.Flatten())
net.add(MyDense())
net.initialize(init=mx.init.Xavier())
net.hybridize()
net
HybridSequential(
(0): Conv2D(20, kernel_size=(5, 5), stride=(1, 1))
(1): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
(2): Conv2D(50, kernel_size=(3, 3), stride=(1, 1))
(3): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
(4): Flatten
(5): MyDense(
(dense0): Dense(256, linear)
(dense1): Dense(10, linear)
)
)
训练
定义loss,优化器
softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'Adam', {'learning_rate': 0.008})
for epoch in range(5):
train_loss = 0.
train_acc = 0.
test_acc = 0.
for data, label in train_data:
data = nd.transpose(data,(0,3,1,2))
with autograd.record():
output = net(data)
loss = softmax_cross_entropy(output, label)
loss.backward()
trainer.step(batch_size)
train_loss += nd.mean(loss).asscalar()
train_acc += accuracy(output, label)
test_acc = evaluate_accuracy(test_data, net)
print("Epoch %d. Loss: %f, Train acc %f, Test acc %f" % (
epoch, train_loss/len(train_data), train_acc/len(train_data), test_acc))
symbol与Gluon 模型加载
symboll常保存模型为.json文件和.params文件,前者表示网络结构,后者表示该结构的参数
故symbol加载模型 并向前推断
import mxnet as mx
import numpy as np
from collections import namedtuple
net_name = 'vgg16'
img_name = 'dog.jpg'
# imagenet 图像预处理
def load_image(img_name):
img = mx.image.imread(img_name)
img = mx.image.imresize(img, 224, 224)
img = img.transpose((2,0,1)) # hwc->chw
img = img.expand_dims(axis=0) # chw->1chw
img = img.astype('float32')
return img
# 加载 mxnet symbol
sym, arg, aux = mx.model.load_checkpoint(net_name, 0) #net_name代表加载网络name,第二个参数代表Epoch num
# 设置 runtime context
ctx = mx.cpu() || ctx = mx.gpu()
mod = mx.mod.Module(symbol=sym, context=ctx)
mod.bind(for_training=False, data_shape[('data', (1, 3, 224, 224))]) # 为输入数据分配内存
mod.set_params(arg, aux) # 加载模型参数
Batch = namedtuple('Batch', ['data'])
img = load_image(img_name)
mod.forward(Batch([img])) # 做简单的inference
prob = mod.get_outputs()[0].asnumpy
如果想输出中间层特征
sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch)
print(sym)
# print(arg_params)
# print(aux_params)
# 提取中间某层输出帖子特征层作为输出
all_layers = sym.get_internals()
print(all_layers) # 打印网络层名称
sym = all_layers['fc1_output']
#选择其中某层的输出 layer+'_output'
# 重建模型
model = mx.mod.Module(symbol=sym, label_names=None)
model.bind(for_training=False, data_shapes=[('data', (1, 3, 112, 112))])
model.set_params(arg_params, aux_params)
可在后面直接定义层 fine_tune方式,重新定义
symbol 保存模型结构
checkpoint = mx.callback.do_checkpoint(model_prefix)
mod = mx.mod.Module(symbol=net)
mod.fit(train_iter, num_epoch=5, epoch_end_callback=checkpoint)
#fit 实现方式
arg_params, aux_params = self.get_params()
self.set_params(arg_params, aux_params)
if epoch_end_callback is not None:
for callback in _as_list(epoch_end_callback):
callback(epoch, self.symbol, arg_params, aux_params)
gloun加载.json文件和.params文件的方式
sym, arg_params, aux_params = mx.model.load_checkpoint("1.0.3", 40)#这里是model的名字和参数对应的epoch
layers = sym.get_internals()#得到所有的layers
outputs = layers['stage4_unit1_conv2_output']#选择输出层
inputs = layers['data']#选择输入层
net = gluon.SymbolBlock(outputs, inputs)#使用gluon的接口将其封装成一个新的net
net.load_parameters("1.0.3-0040.params", ignore_extra = True, allow_missing = True)#载入数据
修改网络后并想在后面定义新的层
class PretrainedNetwork(gluon.HybridBlock):
def __init__(self,pretrianed_layer,**kwargs):
super(PretrainedNetork,self).__init__(**kwargs)
with self.name_scope():
self.pretrained_layer =pretrained_layer
self.fc = nn.HybridSequential()
self.fc.add(
nn.Flatten(),
nn.Dense(256,activation='relu'),
nn.Dropout(rate=0.5),
nn.Dense(128)
)
self.single_fc = nn.Dense(2)
self.fusion_fc = nn.Dense(2)
def hybrid_forward(self,F,x):
x = self.pretrained_layer(x)
x = self.fc(x)
feat = x
y1 = self.single_fc(x)
feat = feat.sum(axis=1)
y2 = self.fusion_fc(feat)
return y1,y2
使用预训练模型并初始化其中一部分
net = PretrainedNetwork(pretrained_layer = net)
net.initialize(forece_reinit = False, init = init.Xavier())
先load_parameters再用其初始化PretrainedNwtwork,否则容易出现prefix不匹配的问题。
gluon保存和加载模型结构和参数
net.export('Gluon_FashionMNIST',epoch=0)
参考博客
- https://blog.csdn.net/qq_20622615/article/details/89924387
- https://www.cnblogs.com/fiercex/p/7656612.html