计算机视觉应用

    本章结合图像分类任务,介绍MindSpore如何应用于计算机视觉场景。

    图像分类是最基础的计算机视觉应用,属于有监督学习类别。给定一张数字图像,判断图像所属的类别,如猫、狗、飞机、汽车等等。用函数来表示这个过程如下:

    选择合适的model是关键。这里的model一般指的是深度卷积神经网络,如AlexNet、VGG、GoogLeNet、ResNet等等。

    MindSpore预置了典型的卷积神经网络,开发者可以直接使用,如LeNet,使用方式如下:

    1. Copyfrom mindspore.model_zoo.lenet import LeNet5
    2. network = LeNet(num_classes)

    MindSpore当前支持的图像分类网络包括:典型网络LeNet、AlexNet、ResNet。

    图1:CIFAR-10数据集[1]

    如图1所示,CIFAR-10数据集共包含10类、共60000张图片。其中,每类图片6000张,50000张是训练集,10000张是测试集。每张图片大小为32*32。

    图像分类的训练指标通常是精度(Accuracy),即正确预测的样本数占总预测样本数的比值。

    接下来我们介绍利用MindSpore解决图片分类任务,整体流程如下:

    • 下载CIFAR-10数据集

    • 数据加载和预处理

    • 定义损失函数和优化器

    • 调用高阶API进行训练和保存模型文件

    • 加载保存的模型进行推理

    下面对任务流程中各个环节及代码关键片段进行解释说明。

    先从CIFAR-10数据集官网上下载CIFAR-10数据集。本例中采用binary格式的数据,Linux环境可以通过下面的命令下载:

      接下来需要解压数据集,解压命令如下:

      • 加载数据集

      数据加载可以通过内置数据集格式Cifar10Dataset接口完成。

      Cifar10Dataset,读取类型为随机读取,内置CIFAR-10数据集,包含图像和标签,图像格式默认为uint8,标签数据格式默认为uint32。更多说明请查看API中Cifar10Dataset接口说明。

      数据加载代码如下,其中data_home为数据存储位置:

      1. Copycifar_ds = ds.Cifar10Dataset(data_home)
      • 数据增强

      数据增强主要是对数据进行归一化和丰富数据样本数量。常见的数据增强方式包括裁剪、翻转、色彩变化等等。MindSpore通过调用map方法在图片上执行增强操作:

      1. Copyresize_height = 224
      2. resize_width = 224
      3. rescale = 1.0 / 255.0
      4. shift = 0.0
      5.  
      6. # define map operations
      7. random_crop_op = C.RandomCrop((32, 32), (4, 4, 4, 4)) # padding_mode default CONSTANT
      8. random_horizontal_op = C.RandomHorizontalFlip()
      9. resize_op = C.Resize((resize_height, resize_width)) # interpolation default BILINEAR
      10. rescale_op = C.Rescale(rescale, shift)
      11. normalize_op = C.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
      12. changeswap_op = C.HWC2CHW()
      13. type_cast_op = C2.TypeCast(mstype.int32)
      14.  
      15. c_trans = []
      16. c_trans = [random_crop_op, random_horizontal_op]
      17. c_trans += [resize_op, rescale_op, normalize_op, changeswap_op]
      18.  
      19. # apply map operations on images
      20. cifar_ds = cifar_ds.map(input_columns="label", operations=type_cast_op)
      21. cifar_ds = cifar_ds.map(input_columns="image", operations=c_trans)
      • 数据混洗和批处理

      最后通过数据混洗(shuffle)随机打乱数据的顺序,并按batch读取数据,进行模型训练:

      ResNet通常是较好的选择。首先,它足够深,常见的有34层,50层,101层。通常层次越深,表征能力越强,分类准确率越高。其次,可学习,采用了残差结构,通过shortcut连接把低层直接跟高层相连,解决了反向传播过程中因为网络太深造成的梯度消失问题。此外,ResNet网络的性能很好,既表现为识别的准确率,也包括它本身模型的大小和参数量。

      MindSpore Model Zoo中已经内置了ResNet模型,可以采用ResNet-50网络,调用方法如下:

      1. Copyfrom mindspore.model_zoo.resnet import resnet50
      2. network = resnet50(class_num=10)

      更多ResNet的介绍请参考:

      接下来需要定义损失函数(Loss)和优化器(Optimizer)。损失函数是深度学习的训练目标,也叫目标函数,可以理解为神经网络的输出(Logits)和标签(Labels)之间的距离,是一个标量数据。

      常见的损失函数包括均方误差、L2损失、Hinge损失、交叉熵等等。图像分类应用通常采用交叉熵损失(CrossEntropy)。

      优化器用于神经网络求解(训练)。由于神经网络参数规模庞大,无法直接求解,因而深度学习中采用随机梯度下降算法(SGD)及其改进算法进行求解。MindSpore封装了常见的优化器,如SGDADAM、等等。本例采用Momentum优化器,通常需要设定两个参数,动量(moment)和权重衰减项(weight decay)。

      MindSpore中定义损失函数和优化器的代码样例如下:

      1. Copy# loss function definition
      2. ls = SoftmaxCrossEntropyWithLogits(sparse=True, is_grad=False, reduction="mean")
      3.  
      4. # optimization definition
      5. opt = Momentum(filter(lambda x: x.requires_grad, net.get_parameters()), 0.01, 0.9)

      完成数据预处理、网络定义、损失函数和优化器定义之后,就可以进行模型训练了。模型训练包含两层迭代,数据集的多轮迭代(epoch)和一轮数据集内按分组(batch)大小进行的单步迭代。其中,单步迭代指的是按分组从数据集中抽取数据,输入到网络中计算得到损失函数,然后通过优化器计算和更新训练参数的梯度。

      为了简化训练过程,MindSpore封装了Model高阶接口。用户输入网络、损失函数和优化器完成Model的初始化,然后调用train接口进行训练,train接口参数包括迭代次数()和数据集(dataset)。

      模型保存是对训练参数进行持久化的过程。Model类中通过回调函数(callback)的方式进行模型保存,如下面代码所示。用户通过CheckpointConfig设置回调函数的参数,其中,save_checkpoint_steps指每经过固定的单步迭代次数保存一次模型,keep_checkpoint_max指最多保存的模型个数。

      训练得到的模型文件(如resnet.ckpt)可以用来预测新图像的类别。首先通过load_checkpoint加载模型文件。然后调用Model的接口预测新图像类别。

      1. Copyparam_dict = load_checkpoint(args_opt.checkpoint_path)
      2. load_param_into_net(net, param_dict)
      3. eval_dataset = create_dataset(1, training=False)
      4. res = model.eval(eval_dataset)

      [1] https://www.cs.toronto.edu/~kriz/cifar.html