查看原文
其他

【cntk速成】cntk图像分类从模型自定义到测试

言有三 有三AI 2019-12-26

欢迎来到专栏《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


转载文章请后台联系

侵权必究


更多请关注知乎专栏《有三AI学院》


往期精选

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存