【mxnet速成】mxnet图像分类从模型自定义到测试
文章首發于微信公眾號《與有三學AI》
【mxnet速成】mxnet圖像分類從模型自定義到測試
這是給大家準備的mxnet速成例子
這一次我們講講mxnet,相關的代碼、數據都在我們 Git 上,希望大家 Follow 一下這個 Git 項目,后面會持續更新不同框架下的任務。
https://github.com/longpeng2008/LongPeng_ML_Course
作者&編輯 | 言有三
?
01?mxnet是什么
mxnet是amazon的官方框架,下面參考mxnet的官方簡介
https://mxnet-bing.readthedocs.io/en/latest/zh/overview.html
深度學習系統通常有兩種編程方式,一種是聲明式編程(declarative programming),用戶只需要聲明要做什么,而具體執行則由系統完成。以Caffe,TensorFlow的計算圖為代表。優點是由于在真正開始計算的時候已經拿到了整個計算圖,所以可以做一系列優化來提升性能。實現輔助函數也容易,例如對任何計算圖都提供forward和backward函數,另外也方便對計算圖進行可視化,將圖保存到硬盤和從硬盤讀取。缺點是debug很麻煩,監視一個復雜的計算圖中的某個節點的中間結果并不簡單,邏輯控制也不方便。
一種是命令式編程(imperative programming),以numpy,torch/pytorch為代表,每個語句按照原來的意思順序執行。它 的特點是語義上容易理解,靈活,可以精確控制行為。通常可以無縫地和主語言交互,方便地利用主語言的各類算法,工具包,debug和性能調試器,但是實現統一的輔助函數和提供整體優化都很困難。
MXNet嘗試將兩種模式無縫的結合起來。在命令式編程上MXNet提供張量運算,進行模型的迭代訓練和更新中的控制邏輯;在聲明式編程中MXNet支持符號表達式,用來描述神經網絡,并利用系統提供的自動求導來訓練模型。
隨著pytorch的崛起,mxnet已經掉出前三梯隊,但不影響喜歡它的人使用。相比于重量級的tensorflow,mxnet非常輕量,占用內存少,分布式訓練方便,常被用于比賽刷榜(見筆者以前用來刷榜的文)。
如何步入深度學習刷榜第一重境界
?
02?mxnet安裝配置
喜歡自定義安裝和精確控制版本的朋友,可以自行編譯,喜歡偷懶的pip安裝即可,方便快捷。
sudo pip install mxnet
不過如果你要多機多卡使用,還是源碼編譯安裝吧。
https://github.com/apache/incubator-mxnet
?
03?mxnet自定義數據
下面就開始我們的任務,跟以往項目一樣,從自定義數據和自定義網絡開始。
mxnet分類任務要求的輸入分類文件的格式與caffe不一樣,為下面的格式,其中分別是序號,標簽,路徑
01../../../../../datas/mouth/1/182smile.jpg
11../../../../../datas/mouth/1/435smile.jpg
數據的載入需要用到接口DataBatch和DataIter
https://mxnet.incubator.apache.org/api/python/io/io.html
首先我們定義一下相關的參數配置,主要用于載入訓練/測試數據集路徑data-train,data-val,rgb均值rgb-mean,類別數目num-classes與訓練樣本集大小num-examples
def add_data_args(parser):
? ? data = parser.add_argument_group('Data', 'the input images')
? ? data.add_argument('--data-train', type=str, help='the training data')
? ? data.add_argument('--data-val', type=str, help='the validation data')
? ? data.add_argument('--rgb-mean', type=str, default='123.68,116.779,103.939',help='a tuple of size 3 for the mean rgb')
? ? data.add_argument('--pad-size', type=int, default=0,
help='padding the input image')
? ? data.add_argument('--image-shape', type=str,
help='the image shape feed into the network, e.g. (3,224,224)')
? ? data.add_argument('--num-classes', type=int,help='the number of classes')
? ? data.add_argument('--num-examples', type=int, help='the number of training examples')
? ? data.add_argument('--data-nthreads', type=int, default=4,help='number of threads for data decoding')
? ? data.add_argument('--benchmark', type=int, default=0,
help='if 1, then feed the network with synthetic data')
? ? data.add_argument('--dtype', type=str, default='float32',help='data type: float32 or float16')
? ? return data
然后,使用mx.img.ImageIter來載入圖像數據
?train = mx.img.ImageIter(
? ? ? ? label_width? ? ? ? ?= 1,
? ? ? ? path_root? ? = 'data/',?
? ? ? ? path_imglist? ? ? ? ?= args.data_train,
? ? ? ? data_shape? ? ? ? ? = (3, N_pix, N_pix),
? ? ? ? batch_size? ? ? ? ? = args.batch_size,
? ? ? ? rand_crop? ? ? ? ? ?= True,
? ? ? ? rand_resize? ? ? ? ?= True,
? ? ? ? rand_mirror? ? ? ? ?= True,
? ? ? ? shuffle? ? ? ? ? ? ?= True,
? ? ? ? brightness? ? ? ? ? = 0.4,
? ? ? ? contrast? ? ? ? ? ? = 0.4,
? ? ? ? saturation? ? ? ? ? = 0.4,
? ? ? ? pca_noise? ? ? ? ? ?= 0.1,
? ? ? ? num_parts? ? ? ? ? ?= nworker,
? ? ? ? part_index? ? ? ? ? = rank)
注意到上面配置了rand_crop,rand_resize,rand_mirror,shuffle,brightness,contrast,saturation,pca_noise等選項,這些就是常見的數據增強操作了,如果不懂,可以去看看我們以前的文章
[綜述類] 一文道盡深度學習中的數據增強方法(上)
【技術綜述】深度學習中的數據增強(下)
【開源框架】一文道盡主流開源框架中的數據增強
mxnet的數據增強接口使用非常的方便,定義如下
def add_data_aug_args(parser):
? ? aug = parser.add_argument_group(
? ? ? ? 'Image augmentations', 'implemented in src/io/image_aug_default.cc')
? ? aug.add_argument('--random-crop', type=int, default=1,help='if or not randomly crop the image')
? ? aug.add_argument('--random-mirror', type=int, default=1,help='if or not randomly flip horizontally')
? ? aug.add_argument('--max-random-h', type=int, default=0,help='max change of hue, whose range is [0, 180]')
? ? aug.add_argument('--max-random-s', type=int, default=0,help='max change of saturation, whose range is [0, 255]')
? ? aug.add_argument('--max-random-l', type=int, default=0,help='max change of intensity, whose range is [0, 255]')
? ? aug.add_argument('--max-random-aspect-ratio', type=float, default=0,help='max change of aspect ratio, whose range is [0, 1]')
? ? aug.add_argument('--max-random-rotate-angle', type=int, default=0,help='max angle to rotate, whose range is [0, 360]')
? ? aug.add_argument('--max-random-shear-ratio', type=float, default=0,help='max ratio to shear, whose range is [0, 1]')
? ? aug.add_argument('--max-random-scale', type=float, default=1,help='max ratio to scale')
? ? aug.add_argument('--min-random-scale', type=float, default=1,help='min ratio to scale, should >= img_size/input_shape. otherwise use --pad-size')
? ? return aug
可以看到level >= 1,就可以使用隨機裁剪,鏡像操作,level >= 2,就可以使用對比度變換操作,level >= 3,就可以使用旋轉,縮放等操作。
def set_data_aug_level(aug, level):
? ? if level >= 1:
? ? ? ? aug.set_defaults(random_crop=1, random_mirror=1)
? ? if level >= 2:
? ? ? ? aug.set_defaults(max_random_h=36, max_random_s=50, max_random_l=50)
? ? if level >= 3:
? ? ? ? aug.set_defaults(max_random_rotate_angle=10, max_random_shear_ratio=0.1, max_random_aspect_ratio=0.25)
?
04?mxnet網絡搭建
同樣是三層卷積,兩層全連接的網絡,話不多說,直接上代碼,使用到的api是mxnet.symbol
import mxnet as mx
def get_symbol(num_classes, **kwargs):
? ?if 'use_global_stats' not in kwargs:
? ? ? ?use_global_stats = False
? ?else:
? ? ? ?use_global_stats = kwargs['use_global_stats']
? ?data = mx.symbol.Variable(name='data')
? ?conv1 = mx.symbol.Convolution(name='conv1', data=data , num_filter=12, kernel=(3,3), stride=(2,2), no_bias=True)
? ?conv1_bn = mx.symbol.BatchNorm(name='conv1_bn', data=conv1 , use_global_stats=use_global_stats, fix_gamma=False, eps=0.000100)
? ?conv1_scale = conv1_bn
? ?relu1 = mx.symbol.Activation(name='relu1', data=conv1_scale , act_type='relu')
? ?conv2 = mx.symbol.Convolution(name='conv2', data=relu1 , num_filter=24, kernel=(3,3), stride=(2,2), no_bias=True)
? ?conv2_bn = mx.symbol.BatchNorm(name='conv2_bn', data=conv2 , use_global_stats=use_global_stats, fix_gamma=False, eps=0.000100)
? ?conv2_scale = conv2_bn
? ?relu2 = mx.symbol.Activation(name='relu2', data=conv2_scale , act_type='relu')
? ?conv3 = mx.symbol.Convolution(name='conv3', data=relu2 , num_filter=48, kernel=(3,3), stride=(2,2), no_bias=True)
? ?conv3_bn = mx.symbol.BatchNorm(name='conv3_bn', data=conv3 , use_global_stats=use_global_stats, fix_gamma=False, eps=0.000100)
? ?conv3_scale = conv3_bn
? ?relu3 = mx.symbol.Activation(name='relu3', data=conv3_scale , act_type='relu')
? ?pool = mx.symbol.Pooling(name='pool', data=relu3 , pooling_convention='full', global_pool=True, kernel=(1,1), pool_type='avg')
? ?fc = mx.symbol.Convolution(name='fc', data=pool , num_filter=num_classes, pad=(0, 0), kernel=(1,1), stride=(1,1), no_bias=False)
? ?flatten = mx.symbol.Flatten(data=fc, name='flatten')
? ?softmax = mx.symbol.SoftmaxOutput(data=flatten, name='softmax')
? ?return softmax
if __name__ == "__main__":
? ?net = get_symbol(2)? ##二分類任務
? ?net.save('simpleconv3-symbol.json')
最后我們可以將其存到json文件里,net.save('simpleconv3-symbol.json'),下面是conv1的部分,詳細大家可以至git查看
? ? {
? ? ? "op": "Convolution",?
? ? ? "name": "conv1",?
? ? ? "attr": {
? ? ? ? "kernel": "(3, 3)",?
? ? ? ? "no_bias": "True",?
? ? ? ? "num_filter": "12",?
? ? ? ? "stride": "(2, 2)"
? ? ? },?
? ? ? "inputs": [[0, 0, 0], [1, 0, 0]]
? ? },
?
05?模型訓練、測試
5.1 模型訓練
準備工作都做好了,訓練代碼非常簡潔,下面就是全部的代碼
import os
import argparse
import logging
logging.basicConfig(level=logging.DEBUG)
from common import find_mxnet
from common import data, fit
import mxnet as mx
import os, urllib
if __name__ == "__main__":
? ?parser = argparse.ArgumentParser(description="simple conv3 net",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? formatter_class=argparse.ArgumentDefaultsHelpFormatter)
? ?train = fit.add_fit_args(parser)
? ?data.add_data_args(parser)
? ?aug = data.add_data_aug_args(parser)
? ?data.set_data_aug_level(parser, 1)
? ?parser.set_defaults(image_shape='3,48,48', num_epochs=200,
? ? ? ? ? ? ? ? ? ? ? ?lr=.001, wd=0)
? ?args = parser.parse_args()
? ?# define simpleconv3
? ?net = mx.sym.load('models/simple-conv3-symbol.json')
? ?print "net",net
? ?# train
? ?fit.fit(args ? ? ? ?= args,
? ? ? ? ? ?network ? ? = net,
? ? ? ? ? ?data_loader = data.get_rec_iter)
其中調用了fit接口定義優化目標和策略,我們只分析其中的核心代碼,首先是模型創建
? ?model = mx.mod.Module(
? ? ? ?context ? ? ? = devs,
? ? ? ?symbol ? ? ? ?= network
? ?)
然后是optimizer配置,默認使用adam
? ?optimizer_params = {
? ? ? ? ? ?'learning_rate': lr,
? ? ? ? ? ?'wd' : args.wd
? ?}
初始化
? ?initializer = mx.init.Xavier(rnd_type='gaussian', factor_type="in", magnitude=2.34)
最后是完整的接口
? ?model.fit(train,
? ? ? ?begin_epoch ? ? ? ?= args.load_epoch if args.load_epoch else 0,
? ? ? ?num_epoch ? ? ? ? ?= args.num_epochs,
? ? ? ?eval_data ? ? ? ? ?= val,
? ? ? ?eval_metric ? ? ? ?= eval_metrics,
? ? ? ?kvstore ? ? ? ? ? ?= kv,
? ? ? ?optimizer ? ? ? ? ?= args.optimizer,
? ? ? ?optimizer_params ? = optimizer_params,
? ? ? ?initializer ? ? ? ?= initializer,
? ? ? ?arg_params ? ? ? ? = arg_params,
? ? ? ?aux_params ? ? ? ? = aux_params,
? ? ? ?batch_end_callback = batch_end_callbacks,
? ? ? ?epoch_end_callback = checkpoint,
? ? ? ?allow_missing ? ? ?= True,
? ? ? ?monitor ? ? ? ? ? ?= monitor)
然后開始愉快的訓練吧
python train.py --gpus 0 \
? ?--data-train data/train.txt \
? ?--model-prefix 'models/simple-conv3' \
? ?--batch-size 80 --num-classes 2 --num-examples 900 2>&1 | tee log.txt
訓練模型會存為simple-conv3-epoch.params的格式。
5.2 訓練過程可視化
由于前面我們的tensorflow,pytorch,keras都使用了tensorborad進行可視化,mxnet也可以借助tensorboard進行可視化,只需要再設計一些mxnet接口即可。具體方法不再贅述,參考https://github.com/awslabs/mxboard
網絡結構的可視化則可用mx.viz.plot_network(sym).view()。
5.3 模型測試
使用mx.model.load_checkpoint載入預訓練的模型,如下
epoch = int(sys.argv[1]) #check point step
gpu_id = int(sys.argv[2]) #GPU ID for infer
prefix = sys.argv[3]
ctx = mx.gpu(gpu_id)
sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch)
arg_params, aux_params = ch_dev(arg_params, aux_params, ctx)
然后使用bind接口進行forward,具體操作如下
sym ?= mx.symbol.SoftmaxOutput(data = sym, name = 'softmax')? ? ? ?
img_full_name = os.path.join(imgdir,imgname)
img = cv2.cvtColor(cv2.imread(img_full_name), cv2.COLOR_BGR2RGB)
img = np.float32(img)
rows, cols = img.shape[:2]
resize_width = 48
resize_height = 48
img = cv2.resize(img, (resize_width, resize_height), interpolation=cv2.INTER_CUBIC)
h, w, _ = img.shape
img_crop = img[0:h,0:w] ##此處使用整圖
img_crop = np.swapaxes(img_crop, 0, 2)
img_crop = np.swapaxes(img_crop, 1, 2) ?# mxnet的訓練是rgb的順序輸入,所以需要調整為r,g,b訓練
img_crop = img_crop[np.newaxis, :]
arg_params["data"] = mx.nd.array(img_crop, ctx)
arg_params["softmax_label"] = mx.nd.empty((1,), ctx)
exe = sym.bind(ctx, arg_params ,args_grad=None, grad_req="null", aux_states=aux_params)
exe.forward(is_train=False)
probs = exe.outputs[0].asnumpy()
?
06 總結
好了,就這么多。到今天為止,主流的機器學習框架caffe,tensorflow,pytorch,paddlepaddle,keras,mxnet我們已經全部給大家提供了快速入門【文末提供了全部鏈接】。從自定義數據集,自定義網絡,到模型的訓練,可視化,測試,全套腳本都提供到了github上,歡迎star和fork。
?
同時,在我的知乎專欄也會開始同步更新這個模塊,歡迎來交流
https://zhuanlan.zhihu.com/c_151876233
注:部分圖片來自網絡
本系列完整文章:
第一篇:【caffe速成】caffe圖像分類從模型自定義到測試
第二篇:【tensorflow速成】Tensorflow圖像分類從模型自定義到測試
第三篇:【pytorch速成】Pytorch圖像分類從模型自定義到測試
第四篇:【paddlepaddle速成】paddlepaddle圖像分類從模型自定義到測試
第五篇:【Keras速成】Keras圖像分類從模型自定義到測試
第六篇:【mxnet速成】mxnet圖像分類從模型自定義到測試
第七篇:【cntk速成】cntk圖像分類從模型自定義到測試
第八篇:【chainer速成】chainer圖像分類從模型自定義到測試
第九篇:【DL4J速成】Deeplearning4j圖像分類從模型自定義到測試
第十篇:【MatConvnet速成】MatConvnet圖像分類從模型自定義到測試
第十一篇:【Lasagne速成】Lasagne/Theano圖像分類從模型自定義到測試
第十二篇:【darknet速成】Darknet圖像分類從模型自定義到測試
感謝各位看官的耐心閱讀,不足之處希望多多指教。后續內容將會不定期奉上,歡迎大家關注有三公眾號 有三AI!
?
?
?
總結
以上是生活随笔為你收集整理的【mxnet速成】mxnet图像分类从模型自定义到测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Keras速成】Keras图像分类从模
- 下一篇: 【技术综述】一文道尽softmax lo