图像分类 ======================= 这里将介绍如何在PaddlePaddle下使用AlexNet、VGG、GoogLeNet和ResNet模型进行图像分类。图像分类问题的描述和这四种模型的介绍可以参考[PaddlePaddle book](https://github.com/PaddlePaddle/book/tree/develop/03.image_classification)。 ## 数据格式 reader.py定义了数据格式,它读取一个图像列表文件,并从中解析出图像路径和类别标签。 图像列表文件是一个文本文件,其中每一行由一个图像路径和类别标签构成,二者以跳格符(Tab)隔开。类别标签用整数表示,其最小值为0。下面给出一个图像列表文件的片段示例: ``` dataset_100/train_images/n03982430_23191.jpeg 1 dataset_100/train_images/n04461696_23653.jpeg 7 dataset_100/train_images/n02441942_3170.jpeg 8 dataset_100/train_images/n03733281_31716.jpeg 2 dataset_100/train_images/n03424325_240.jpeg 0 dataset_100/train_images/n02643566_75.jpeg 8 ``` ## 训练模型 ### 初始化 在初始化阶段需要导入所用的包,并对PaddlePaddle进行初始化。 ```python import gzip import paddle.v2 as paddle import reader import vgg import resnet import alexnet import googlenet import argparse import os # PaddlePaddle init paddle.init(use_gpu=False, trainer_count=1) ``` ### 定义参数和输入 设置算法参数(如数据维度、类别数目和batch size等参数),定义数据输入层`image`和类别标签`lbl`。 ```python DATA_DIM = 3 * 224 * 224 CLASS_DIM = 100 BATCH_SIZE = 128 image = paddle.layer.data( name="image", type=paddle.data_type.dense_vector(DATA_DIM)) lbl = paddle.layer.data( name="label", type=paddle.data_type.integer_value(CLASS_DIM)) ``` ### 获得所用模型 这里可以选择使用AlexNet、VGG、GoogLeNet和ResNet模型中的一个模型进行图像分类。通过调用相应的方法可以获得网络最后的Softmax层。 1. 使用AlexNet模型 指定输入层`image`和类别数目`CLASS_DIM`后,可以通过下面的代码得到AlexNet的Softmax层。 ```python out = alexnet.alexnet(image, class_dim=CLASS_DIM) ``` 2. 使用VGG模型 根据层数的不同,VGG分为VGG13、VGG16和VGG19。使用VGG16模型的代码如下: ```python out = vgg.vgg16(image, class_dim=CLASS_DIM) ``` 类似地,VGG13和VGG19可以分别通过`vgg.vgg13`和`vgg.vgg19`方法获得。 3. 使用GoogLeNet模型 GoogLeNet在训练阶段使用两个辅助的分类器强化梯度信息并进行额外的正则化。因此`googlenet.googlenet`共返回三个Softmax层,如下面的代码所示: ```python out, out1, out2 = googlenet.googlenet(image, class_dim=CLASS_DIM) loss1 = paddle.layer.cross_entropy_cost( input=out1, label=lbl, coeff=0.3) paddle.evaluator.classification_error(input=out1, label=lbl) loss2 = paddle.layer.cross_entropy_cost( input=out2, label=lbl, coeff=0.3) paddle.evaluator.classification_error(input=out2, label=lbl) extra_layers = [loss1, loss2] ``` 对于两个辅助的输出,这里分别对其计算损失函数并评价错误率,然后将损失作为后文SGD的extra_layers。 4. 使用ResNet模型 ResNet模型可以通过下面的代码获取: ```python out = resnet.resnet_imagenet(image, class_dim=CLASS_DIM) ``` ### 定义损失函数 ```python cost = paddle.layer.classification_cost(input=out, label=lbl) ``` ### 创建参数和优化方法 ```python # Create parameters parameters = paddle.parameters.create(cost) # Create optimizer optimizer = paddle.optimizer.Momentum( momentum=0.9, regularization=paddle.optimizer.L2Regularization(rate=0.0005 * BATCH_SIZE), learning_rate=0.001 / BATCH_SIZE, learning_rate_decay_a=0.1, learning_rate_decay_b=128000 * 35, learning_rate_schedule="discexp", ) ``` 通过 `learning_rate_decay_a` (简写$a$) 、`learning_rate_decay_b` (简写$b$) 和 `learning_rate_schedule` 指定学习率调整策略,这里采用离散指数的方式调节学习率,计算公式如下, $n$ 代表已经处理过的累计总样本数,$lr_{0}$ 即为参数里设置的 `learning_rate`。 $$ lr = lr_{0} * a^ {\lfloor \frac{n}{ b}\rfloor} $$ ### 定义数据读取方法和事件处理程序 读取数据时需要分别指定训练集和验证集的图像列表文件,这里假设这两个文件分别为`train.list`和`val.list`。 ```python train_reader = paddle.batch( paddle.reader.shuffle( reader.test_reader('train.list'), buf_size=1000), batch_size=BATCH_SIZE) test_reader = paddle.batch( reader.train_reader('val.list'), batch_size=BATCH_SIZE) # End batch and end pass event handler def event_handler(event): if isinstance(event, paddle.event.EndIteration): if event.batch_id % 1 == 0: print "\nPass %d, Batch %d, Cost %f, %s" % ( event.pass_id, event.batch_id, event.cost, event.metrics) if isinstance(event, paddle.event.EndPass): with gzip.open('params_pass_%d.tar.gz' % event.pass_id, 'w') as f: parameters.to_tar(f) result = trainer.test(reader=test_reader) print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics) ``` ### 定义训练方法 对于AlexNet、VGG和ResNet,可以按下面的代码定义训练方法: ```python # Create trainer trainer = paddle.trainer.SGD( cost=cost, parameters=parameters, update_equation=optimizer) ``` GoogLeNet有两个额外的输出层,因此需要指定`extra_layers`,如下所示: ```python # Create trainer trainer = paddle.trainer.SGD( cost=cost, parameters=parameters, update_equation=optimizer, extra_layers=extra_layers) ``` ### 开始训练 ```python trainer.train( reader=train_reader, num_passes=200, event_handler=event_handler) ```