自己使用时候总结的MXNet一些基本操作及介绍,深度学习训练框架MXNet的基本操作都在这里了
一、基础篇
NDArray介绍篇
在mxnet中,NDArray是所有运算的核心数据结构,mxnet中的所有数据均使用NDArray进行表示,NDarray有点类似于numpy中的ndarray,操作上面也与numpy很相似,但是NDArray提供了numpy.ndarray所不具备的操作,比如:GPU,CPU的切换,自动求梯度的运算等等,这也是为什么mxnet要重新封装一个NDArray的原因。
NDArray就好比盖房子的砖,砖有了自然可以盖房子了,所以利用NDArray你便可以实现所有的深度学习模型了,只是深度学习日新月异,如果每个模型都从NDArray开始写,那当然是比较麻烦的,所以MXnet或者gluon帮我们封装了一些函数可以直接使用,接下来我们都会逐一的了解,那么这一节我们先来仔细学习一下mxnet的NDArray:
特别说明:下面的操作只是NDArray的一些基本操作,
获取更多的操作还请查找MXNet文档:https://mxnet.incubator.apache.org/api/python/ndarray/ndarray.html
==当然,我希望你可以跟我一起来敲如下的代码而不是看一遍就过去了,事实证明,敲一遍的效果会好很多==
在mxnet中,使用NDArray需要引用nd包(nd是ndarray的缩写),如下:
1 | from mxnet import nd |
在引入nd包之后就可以愉快的使用NDArry了。
特别说明,下面代码中 ‘->’ 代表的是输出结果
1. 定义x为一个序列,这里与numpy一致,不同的是,这里返回的每个元素类型都是ndarray
1 | x = nd.arange(12) -> [0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.] |
2. 当然我们可以打印出ndarray的shape以及size,这里的shape和size不要混淆了
1 | x.shape -> (12 ,) |
3. 那么如果我们想要构建一个二维矩阵怎么办呢?可以考虑reshape函数
1 | x = nd.arange(12) |
4. 如果我们想初始化一个值为0或者值为1的多维矩阵该怎么做呢?
1 | zero = nd.zeros((2,3,4)) # 别忘记了是负数 |
5. 那如何建立一个随机初始化的矩阵呢?
1 | S = nd.random.normal(0,1,shape=(3,4)) # normal是高斯分布 |
6. 当然我们也可以直接利用list直接建立ndarray,如下:
1 | Y = nd.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]]) |
7. 在计算机视觉中,图像一般是3维的,但是在进行模型训练的时候,往往需要将多张图像组成一个batch,构成4维数组,ndarray当然支持,使用concat:
1 | x=nd.random.normal(shape=(2,3,4)) -> x.shape (2,3,4) |
8. ndarray天然支持常用的数学计算,==这里方法较多,可以查阅文档,里面有例子,使用会比较方便==
1 | S*Y |
9. ndarray与numpy的相互转换:
1 | # ndarray -> numpy |
10. 前面我们说了,NDArray可以自动计算梯度,那么如何使用呢?
1 | 1. 引用包 :from mxnet import autograd |
11. 关于CPU与GPU的切换
1 | x = nd.random.normal(shape=(3,4)) ## 默认在CPU内存中 |
12. 复制也是常用的操作,利用copy()可以避免浅拷贝的尴尬
1 | x = nd.array([1,2,3]) |
特别说明:之上只是NDArray的一些基本操作,
获取更多的操作还请查找MXNet文档https://mxnet.incubator.apache.org/
Symbol介绍篇
Symbol的基本函数
- Symbol.infer_type
- Symbol.infer_shape
- Symbol.list_arguments
- Symbol.list_outputs
- Symbol.list_auxiliary_states
args = 输入数据symbol + 权值参数symbol
aux = 辅助symbol,比如bn中的mean以及var
举个例子:
1 | data = mx.sym.var('data') |
1 | data= mx.sym.var('data', shape=(1,2)) |
1 | data = mx.sym.var('data') |
Module介绍篇
- Module是MXNet中集成的接口,将几乎所有的模块封装成一个可以一步完成的训练和测试接口。
- 所有的Module均继承了BaseModule
Metric 介绍篇
- Metric是衡量模型效果的接口,如下是官方的计算Accuracy的例子
1 | class Accuracy(EvalMetric): |
如何实现自己的metric函数
需要继承EvalMetric,并重写update函数,注意传入参数的类型。
更新sum_metric和num_inst的值,mxnet会调用sum_metric/num_inst来计算当前metric输出值。
二、使用篇
mxnet生成lst以及rec文件(mxnet指定的训练数据格式)
生成lst的时候,第一个参数是目标存放地址,第二个参数是图像文件目录,利用如下命令会生成train.lst以及val.lst
1 | python im2rec.py --list --recursive --train-ratio 0.95 /path/train /path/train # 前面的参数修改成 /path/lst/data 会生成 data_train.lst |
mxnet训练demo
简单的利用fit直接训练
1 |
|
mxnet的训练过程,step by step
训练模型主要包括下面几个step:
- bind : prepares environment for the computation by allocating memory
- init_params : assigns and initializes parameters
- init_optimizer : initializes optimizers defaults to sgd
- metric.create : creates evaluation metric from input metric name
- forward : forward computation
- update_metric : evaluates and accumulates evaluation metric on outputs of the last forward computation
- backward: backwoard computation
- update: upadates parameters according to the installed optimizer and the gradients computed in the previous forward-backward batch
1 | import logging |
mxnet进行finetune代码示例
1 |
|
finetune的时候,如何调整新加层的学习率
1 | weight = mx.sym.var('weight', lr_mult=5) |
mxnet进行inference代码示例
这里是我自己的代码,可能不适用所有情况,需要按需修改
1 | import mxnet as mx |
如下脚本运行上面代码
1 | python ./src/inference.py \ |
mxnet进行inference的时候多种方式读取图像(看你习惯哪一个)
1、利用mxnet的imread()函数读取图像并进行数据扩增:
1 |
|
2、另一种mxnet图像读取方式:利用数据流:
这时,data是ndarray格式的数据(imdecode进行图像解码)
1 | image_string = open('file_path', 'rb').read() |
3、采用opencv读取方式进行图像操作
1 |
|
==mxnet对于读取的图像类型有局限性,非jpe或者jpeg图像容易出现错误==
三、使用升级篇
mxnet如何获取网络参数
mxnet可以通过model.get_params() 可以得到arg_params以及aux_params
1 | import mxnet as mx |
mxnet如何获取中间层特征
1 | ## 这个主要是使用mx.symbol.Group([xxx,xxx])来多输出 |
Gluon篇
gluon调用MXNet模型(params+json)进行训练
参考链接:https://blog.csdn.net/qq_20622615/article/details/89924387
使用symbol得到的模型或者gluon的hybridize之后的模型包括一个.json文件(网络结构)和.params文件(参数),gluon可以使用net = gluon.SymbolBlock.imports(json, [‘data’], params, ctx)导入网络和参数,这样可以进行测试或者进一步训练。
但是如果只需要使用模型的其中一部分,比如只需要conv层,去掉所有fc层,或者再另外增加一些层, 这样直接导入就会比较复杂。正确的做法如下:
1 | sym, arg_params, aux_params = mx.model.load_checkpoint("1.0.3", 40)#这里是model的名字和参数对应的epoch |
如果需要在该网络的基础上再新增加一些层,如下定义:
1 | class PretrainedNetwork(gluon.HybridBlock): |
通过下面的方式,使用预训练模型初始化其中一部分:
1 | net = PretrainedNetwork(pretrained_layer = net) |
需要注意的是,要先load_parameters再用其初始化PretrainedNwtwork,否则会出现prefix不匹配的问题。
如果需要fix其中一部分参数,只训练其中一部分,可以通过观察所有layer的名字,找到需要训练的layer。
print(net.collect_params())#打印所有的参数,这样可以看到所有的layer及其参数
在Trainer的params通过正则表达式选择需要训练的参数:
1 | trainer = gluon.Trainer(params = net.collect_params("pretrained*|dense0*"), optimizer = optimizer) |
这样没有被选中的参数就会被fix,训练中不会改变。
导出Gluoncv的预训练模型
利用gluoncv的export_block导出gluoncv提供的预训练模型
1 | import gluoncv |
gluon训练
gluon主要有3个方法得到预训练模型:
- gluon自身的model_zoo
- gluoncv提供的model_zoo
- mxnet提供的预训练模型(*.params ,*.json)
下面分别就这三个方面进行介绍
1.读取gluon model_zoo提供的模型,并进行finetune
gluon提供的model主要在gluon.model_zoo.vision下,模型地址:https://mxnet.incubator.apache.org/api/python/gluon/model_zoo.html,你可以根据自己的情况查找对应的模型进行使用。model_zoo提供的模型均为features+output结构
调用方法如下:
一:只修改最终的fc层,进行finetune:
1 | from mxnet import gluon |
二:不仅仅修改最终的fc层,还可以增加几层
下面的方法,首先提取出features,然后构建增加的sequential,最后将两部分通过sequential合并在一起。
1 | from mxnet import gluon |
也可以直接修改features,达到同样的效果,不过记得初始化
1 | from mxnet import gluon |
2.读取gluoncv model_zoo提供的模型,并进行finetune(==推荐==)
gluoncv是gluon提供的比较强大的视觉库,其中提供了很多的预训练模型可以使用,链接:https://gluon-cv.mxnet.io/model_zoo/classification.html
使用gluoncv的预训练模型也很方便,跟使用gluon的model_zoo方法基本一致,不同点如下:
1 | from gluoncv.model_zoo import get_model |
其他的就跟上面的一致了。
3.直接读取mxnet模型( .params + .json)
有的时候,我们可能需要利用gluon读取mxnet模型,目前利用gluon读取mxnet模型,只能使用gluon.nn.SymbolBlock()进行读取,如下:
1 | ctx = mx.gpu(0) |
如上,我们便读取了mxnet的model,现在我们便可以对net进行操作了,如下代码构建了一个3分类的网络:
1 |
|
4.最优雅的方式,重新定义网络,实现任意的操作
这种方法最为优雅,也最灵活,你可以采用上面个各个方法读取模型,然后重写forward,实现网络的任意操作
1 | class PretrainedNetwork(gluon.HybridBlock): |
四、其他的杂七杂八
1 |
|