您的位置:首页 > 大数据 > 人工智能

使用mxnet的预训练模型(pretrained model)分类与特征提取

2017-02-09 21:47 591 查看
    note: 该博客代码基于mxnet 0.9.4,可能已过期

4000
    本人以前是使用tensorflow,但是tensorflow的预训练不太给力。虽然现在有tf-slim感觉还是太麻烦,网上说mxnet好的有点多,所以就看了下mxnet。只能说文档和接口都太不友好了,在这里吐下槽,当然也有很多优点,网上比较多这里不多说。下面进入正题。

安装mxnet

    本人是Ubuntu 14的系统,按照mxnet的安装手册拷贝git库,编译安装就可以了,本人用的虚拟机所以没有用gpu,gpu的问题没有遇到。可能会报cython编译的错误,解决方法是注释掉Makefile和python文件夹下关于cython的行再次编译就可以了。

模型下载

    模型有两个地方下载一个是github上面的,另一个是mxnet官网的。模型比较多,下载也比较快,这个是mxnet的优点之一。推荐先玩github上面的,因为有一些小坑。

    这里以inception-bn模型为例,下载链接  ,下载后解压,假设解压后文件路径为 /xxx/model/,model文件夹中有三个文件分别为:

        synset.txt: 类别标签和描述

        Inception-BN-symbol.json: 网络架构(符号)

        Inception-BN-0039.params: 网络参数

使用预训练模型的代码

    下面直接上代码了(基于python的)参考官网:Predict with pre-trained models

#encoding=utf-8

import mxnet as mx
import numpy as np
from PIL import Image
from collections import namedtuple

#读取类别标签和描述
def read_clazz_map(clazz_path):
id_name_map={}
index=0
with open(clazz_path) as f:
for i in f.readlines():
arr=i.strip().split(" ")
names=arr[0]+','+' '.join(arr[1:])
names=names.split(',')
id_name_map[index]=names
index+=1
return id_name_map

#读取一张本地图片
def read_one_img(img_path):
#这里注意是jpg,即3通道rgb,如果不是的话需要转换
img=Image.open(img_path)
img=img.resize((224,224),Image.BILINEAR)
#img=np.array(img)
#return np.array([[img[:,:,i] for i in xrange(3)]])
img = np.swapaxes(img, 0, 2)
img = np.swapaxes(img, 1, 2)
Batch = namedtuple('Batch', ['data'])
#这里也要吐槽,数据要封装成这样的形式才能用
one_data=Batch([mx.nd.array(np.array([img]))])
return one_data

def test():
#数据的shape,这样写有点复杂了,这里吐槽,哈哈
data_shape=[('data', (1,3,224,224))]

#读取一张图片,路径替换成你的图片路径
data=read_one_img(img_path='../9ls7h2oicwemknp1ub.jpg')

clazz_map=read_clazz_map(clazz_path='/xxx/model/synset.txt')

#装载模型,epoch为Inception-BN-0039.params的数字
prefix="/xxx/model/Inception_BN"
model=mx.module.Module.load(prefix=prefix,epoch=39,context=mx.cpu())

#这里bind后就可以直接用了,不需要再定义网络架构(这个比tensorflow简洁)
model.bind(data_shapes=data_shape)

#前馈过程
model.forward(data,is_train=False)

#获取前馈过程的输出(这个设计为何?),result类型为list([mxnet.ndarray.NDArray])
result = model.get_outputs()

#输出numpy类型的数组
result=result[0].asnumpy()

#下面取最大值作为预测值
pos=np.argmax(result)
print 'max:',np.max(result)
print 'position:',pos
print "result:",clazz_map[pos]

#获取网络结构
internals=model.symbol.get_internals()
#print '\n'.join(internals.list_outputs())

#获取从输入到flatten层的特征值层的模型
feature_net = internals["flatten_output"]
feature_model=mx.module.Module(symbol=feature_net,context=mx.cpu())
feature_model.bind(data_shapes=data_shape)

#获取模型参数
arg_params,aux_params=model.get_params()

#上面只是定义了结构,这里设置特征模型的参数为Inception_BN的
feature_model.set_params(arg_params=arg_params,
aux_params=aux_params,
allow_missing=True)

#输出特征
feature_model.forward(data,is_train=False)
feature = feature_model.get_outputs()[0].asnumpy()

print 'shape:',np.shape(feature)
print 'feature:',feature

if __name__=="__main__":
test()

这里完了,还要说一下的就是,mxnet的输入数据用的是迭代器DataIter,没有tensorflow直观。数据shape是将通道放在前面[3,224,224]而其他框架一般是[224,224,3]。模型会绑定batch_size,预测时用其他batch_size会出错,需要重新创建模型绑定数据shape。mxnet的主要问题大概就是接口设计的不够简洁和文档写的不够有条理,里面有一些坑,易用性比较差。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐