【cntk速成】cntk图像分类从模型自定义到测试
欢迎来到专栏《2小时玩转开源框架系列》,这是我们第七篇,前面已经说过了caffe,tensorflow,pytorch,mxnet,keras,paddlepaddle。
今天说cntk,本文所用到的数据,代码请参考我们官方git
https://github.com/longpeng2008/LongPeng_ML_Course
作者 | 言有三
编辑 | 言有三
01
CNTK是什么
地址:https://github.com/Microsoft/CNTK
CNTK是微软开源的深度学习工具包,它通过有向图将神经网络描述为一系列计算步骤。在有向图中,叶节点表示输入值或网络参数,而其他节点表示其输入上的矩阵运算。
CNTK允许用户非常轻松地实现和组合流行的模型,包括前馈DNN,卷积网络(CNN)和循环网络(RNN / LSTM)。与目前大部分框架一样,实现了自动求导,利用随机梯度下降方法进行优化。
cntk有什么特点呢?
1.1 性能较高
按照其官方的说法,比其他的开源框架性能都更高。
笔者在实际进行实验的时候,确实也发现它的训练比较快。
1.2 适合做语音
CNTK本就是微软语音团队开源的,自然是更合适做语音任务,使用RNN等模型,以及在时空尺度分别进行卷积非常容易。
当然,现在的背靠python的这些框架已经大同小异,未来实现大一统并非不可能。
02
CNTK模型训练
pip安装一条命令即可,可以选择安装cpu或者gpu版本。
pip install cntk/cntk-gpu。
接下来就是数据的准备,模型的定义,结果的保存与分析。
在此之前,我们先看官方的分类案例,直观感受一下,代码比较长。
from __future__ import print_function
import numpy as np
import cntk as C
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
from cntk.layers import Dense, Sequential
def generate_random_data(sample_size, feature_dim, num_classes):
# Create synthetic data using NumPy.
Y = np.random.randint(size=(sample_size, 1), low=0, high=num_classes)
# Make sure that the data is separable
X = (np.random.randn(sample_size, feature_dim) + 3) * (Y + 1)
X = X.astype(np.float32)
# converting class 0 into the vector "1 0 0",
# class 1 into vector "0 1 0", ...
class_ind = [Y == class_number for class_number in range(num_classes)]
Y = np.asarray(np.hstack(class_ind), dtype=np.float32)
return X, Ydef ffnet():
inputs = 2
outputs = 2
layers = 2
hidden_dimension = 50
# input variables denoting the features and label data
features = C.input_variable((inputs), np.float32)
label = C.input_variable((outputs), np.float32)
# Instantiate the feedforward classification model
my_model = Sequential ([
Dense(hidden_dimension, activation=C.sigmoid),
Dense(outputs)])
z = my_model(features)
ce = C.cross_entropy_with_softmax(z, label)
pe = C.classification_error(z, label)
# Instantiate the trainer object to drive the model training
lr_per_minibatch = C.learning_parameter_schedule(0.125)
progress_printer = ProgressPrinter(0)
trainer = C.Trainer(z, (ce, pe), [sgd(z.parameters, lr=lr_per_minibatch)], [progress_printer])
# Get minibatches of training data and perform model training
minibatch_size = 25
num_minibatches_to_train = 1024
aggregate_loss = 0.0
for i in range(num_minibatches_to_train):
train_features, labels = generate_random_data(minibatch_size, inputs, outputs)
# Specify the mapping of input variables in the model to actual minibatch data to be trained with
trainer.train_minibatch({features : train_features, label : labels})
sample_count = trainer.previous_minibatch_sample_count
aggregate_loss += trainer.previous_minibatch_loss_average * sample_count
last_avg_error = aggregate_loss / trainer.total_number_of_samples_seen
test_features, test_labels = generate_random_data(minibatch_size, inputs, outputs)
avg_error = trainer.test_minibatch({features : test_features, label : test_labels})
print(' error rate on an unseen minibatch: {}'.format(avg_error))
return last_avg_error, avg_errornp.random.seed(98052)ffnet()
上面就是一个两层的全连接神经网络,使用input_variable封装数据,使用Sequential定义模型,使用train_minibatch({features : train_features, label : labels})来feed数据,与tf,pytorch等框架都是一样的,的确是没有什么好说的。
2.1 数据读取
这里需要用到接口,io.ImageDeserializer与C.io.StreamDefs,C.io.StreamDef。
它可以直接输入如下格式的txt文件用于图像分类问题。
../../../../datas/mouth/1/182smile.jpg1
../../../../datas/mouth/1/435smile.jpg1
../../../../datas/mouth/0/40neutral.jpg0
../../../../datas/mouth/1/206smile.jpg1
注意上面采用的分隔符是'\t',这一点与MXNet相同,与caffe不同,完整的解析代码如下:
C.io.MinibatchSource(C.io.ImageDeserializer(map_file, C.io.StreamDefs(
features = C.io.StreamDef(field='image', transforms=transforms),
labels = C.io.StreamDef(field='label', shape=num_classes)
)))
在对图像数据进行封装的时候,添加了transform,所以可以在这里进行数据预处理操作。
常用的裁剪与缩放如下:
transform.crop(crop_type='randomside', side_ratio=0.8)
transform.scale(width=image_width, height=image_height, channels=num_channels, interpolations='linear')
C.io.MinibatchSource的返回就是数据指针,可以直接用于训练。
2.2 网络定义
与tensorflow和pytorch颇为相似,如下
def simpleconv3(input, out_dims):
with C.layers.default_options(init=C.glorot_uniform(), activation=C.relu):
net = C.layers.Convolution((3,3), 12, pad=True)(input)
net = C.layers.MaxPooling((3,3), strides=(2,2))(net)
net = C.layers.Convolution((3,3), 24, pad=True)(net)
net = C.layers.MaxPooling((3,3), strides=(2,2))(net)
net = C.layers.Convolution((3,3), 48, pad=True)(net)
net = C.layers.MaxPooling((3,3), strides=(2,2))(net)
net = C.layers.Dense(128)(net)
net = C.layers.Dense(out_dims, activation=None)(net)
return net
2.3 损失函数与分类错误率指标定义
如下,model_func就是上面的net,input_var_norm和label_var分别就是数据和标签。
z = model_func(input_var_norm, out_dims=2)
ce = C.cross_entropy_with_softmax(z, label_var)
pe = C.classification_error(z, label_var)
2.4 训练参数
就是学习率,优化方法,epoch等配置。
epoch_size = 900
minibatch_size = 64
lr_per_minibatch = C.learning_rate_schedule([0.01]*100 + [0.003]*100 + [0.001],
C.UnitType.minibatch, epoch_size)
m = C.momentum_schedule(0.9)
l2_reg_weight = 0.001
learner = C.momentum_sgd(z.parameters,
lr = lr_per_minibatch,
momentum = m,
l2_regularization_weight=l2_reg_weight)
progress_printer = C.logging.ProgressPrinter(tag='Training', num_epochs=max_epochs)
trainer = C.Trainer(z, (ce, pe), [learner], [progress_printer])
注意学习率的配置比较灵活,通过learning_rate_schedule接口,上面的C.learning_rate_schedule([0.01]*100 + [0.003]*100 + [0.001]意思是,在0~100 epoch,使用0.01的学习率,100~100+100 epoch,使用0.003学习率,此后使用0.001学习率。
2.5 训练与保存
使用数据指针的next_minibatch获取训练数据,trainer的train_minibatch进行训练,可以看出cntk非常强调minibatch的概念,实际上学习率和优化方法都可以针对单个样本进行设置。
for epoch in range(max_epochs):
sample_count = 0
while sample_count < epoch_size:
data = reader_train.next_minibatch(min(minibatch_size, epoch_size - sample_count), input_map=input_map)
trainer.train_minibatch(data)
模型的保存就一行代码:
z.save("simpleconv3.dnn")
2.6 可视化
需要可视化的内容不多,就是loss曲线和精度曲线,所以可以直接自己添加代码,用上面的模型训练最后的loss如下,更好参数可自己调。
03
CNTK模型测试
测试就是载入模型,做好与训练时同样的预处理操作然后forward就行了。
import ***
model_file = sys.argv[1]
image_list = sys.argv[2]
model = C.load_model(model_file)
count = 0
acc = 0
imagepaths = open(image_list,'r').readlines()
for imagepath in imagepaths:
imagepath,label = imagepath.strip().split('\t')
im = Image.open(imagepath)
print imagepath
print "im size",im.size
image_data = np.array(im,dtype=np.float32)
image_data = cv2.resize(image_data,(image_width,image_height))
image_data = np.ascontiguousarray(np.transpose(image_data, (2, 0, 1)))
output = model.eval({model.arguments[0]:[image_data]})[0]
print output
print label,np.argmax(np.squeeze(output))
if str(label) == str(np.argmax(np.squeeze(output))):
acc = acc + 1
count = count + 1
print "acc=",float(acc) / float(count)
最终模型训练集准确率91%,测试集准确率88%,大家可以自己去做更多调试。
总结
相比于tensorflow,pytorch,cntk固然是比较小众,但也不失为一个优秀的平台,尤其是对于语音任务,感兴趣大家可以自行体验,代码已经上传至https://github.com/longpeng2008/LongPeng_ML_Course。
转载文章请后台联系
侵权必究