> 原文博客:Doi技術團隊

鏈接地址:https://blog.doiduoyi.com/authors/1584446358138
初心:記錄優秀的Doi技術團隊學習經歷

*本篇文章基於 PaddlePaddle 0.11.0、Python 2.7

數據集介紹


如果我們要訓練自己的數據集的話,就需要先建立圖像列表文件,下面的代碼是Myreader.py讀取圖像數據集的一部分,從這些代碼中可以看出,圖像列表中,圖像的路徑和標籤是以\t來分割的,所以我們在生成這個列表的時候,使用\t就可以了.

def train_reader(self,train_list, buffered_size=1024):
    def reader():
        with open(train_list, 'r') as f:
            lines = [line.strip() for line in f]
            for line in lines:
                img_path, lab = line.strip().split('\t')
                yield img_path, int(lab)

    return paddle.reader.xmap_readers(self.train_mapper, reader,
                                      cpu_count(), buffered_size)

生成的圖像列表的結構是這樣的:

../images/vegetables/lotus_root/1515827057517.jpg   2
../images/vegetables/lotus_root/1515827057582.jpg   2
../images/vegetables/lotus_root/1515827057616.jpg   2
../images/vegetables/lettuce/1515827015922.jpg  1
../images/vegetables/lettuce/1515827015983.jpg  1
../images/vegetables/lettuce/1515827016045.jpg  1
../images/vegetables/cuke/1515827008337.jpg 0
../images/vegetables/cuke/1515827008370.jpg 0
../images/vegetables/cuke/1515827008402.jpg 0

生成圖像列表


所以我們要編寫一個CreateDataList.py程序可以爲我們生成這樣的圖像列表
在這個程序中,我們只要把一個大類的文件夾路徑傳進去就可以了,該程序會把裏面的每個小類別都迭代,生成固定格式的列表.比如我們把蔬菜類別的根目錄傳進去../images/vegetables

# coding=utf-8
import os
import json

class CreateDataList:
    def __init__(self):
        pass

    def createDataList(self, data_root_path):
        # # 把生產的數據列表都放在自己的總類別文件夾中
        data_list_path = ''
        # 所有類別的信息
        class_detail = []
        # 獲取所有類別
        class_dirs = os.listdir(data_root_path)
        # 類別標籤
        class_label = 0
        # 獲取總類別的名稱
        father_paths = data_root_path.split('/')
        while True:
            if father_paths[father_paths.__len__() - 1] == '':
                del father_paths[father_paths.__len__() - 1]
            else:
                break
        father_path = father_paths[father_paths.__len__() - 1]

        all_class_images = 0
        # 讀取每個類別
        for class_dir in class_dirs:
            # 每個類別的信息
            class_detail_list = {}
            test_sum = 0
            trainer_sum = 0
            # 把生產的數據列表都放在自己的總類別文件夾中
            data_list_path = "../data/%s/" % father_path
            # 統計每個類別有多少張圖片
            class_sum = 0
            # 獲取類別路徑
            path = data_root_path + "/" + class_dir
            # 獲取所有圖片
            img_paths = os.listdir(path)
            for img_path in img_paths:
                # 每張圖片的路徑
                name_path = path + '/' + img_path
                # 如果不存在這個文件夾,就創建
                isexist = os.path.exists(data_list_path)
                if not isexist:
                    os.makedirs(data_list_path)
                # 每10張圖片取一個做測試數據
                if class_sum % 10 == 0:
                    test_sum += 1
                    with open(data_list_path + "test.list", 'a') as f:
                        f.write(name_path + "\t%d" % class_label + "\n")
                else:
                    trainer_sum += 1
                    with open(data_list_path + "trainer.list", 'a') as f:
                        f.write(name_path + "\t%d" % class_label + "\n")
                class_sum += 1
                all_class_images += 1
            class_label += 1
            # 說明的json文件的class_detail數據
            class_detail_list['class_name'] = class_dir
            class_detail_list['class_label'] = class_label
            class_detail_list['class_test_images'] = test_sum
            class_detail_list['class_trainer_images'] = trainer_sum
            class_detail.append(class_detail_list)
        # 獲取類別數量
        all_class_sum = class_dirs.__len__()
        # 說明的json文件信息
        readjson = {}
        readjson['all_class_name'] = father_path
        readjson['all_class_sum'] = all_class_sum
        readjson['all_class_images'] = all_class_images
        readjson['class_detail'] = class_detail
        jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
        with open(data_list_path + "readme.json",'w') as f:
            f.write(jsons)


if __name__ == '__main__':
    createDataList = CreateDataList()
    createDataList.createDataList('../images/vegetables')

運行這個程序之後,會生成在data文件夾中生成一個單獨的大類文件夾,比如我們這次是使用到蔬菜類,所以我生成一個vegetables文件夾,在這個文件夾下有3個文件:
|文件名|作用|
|:—:|:—:|
|trainer.list|用於訓練的圖像列表|
|test.list|用於測試的圖像列表|
|readme.json|該數據集的json格式的說明,方便以後使用|

readme.json文件的格式如下,可以很清楚看到整個數據的圖像數量,總類別名稱和類別數量,還有每個類對應的標籤,類別的名字,該類別的測試數據和訓練數據的數量:

{
    "all_class_images": 3300,
    "all_class_name": "vegetables",
    "all_class_sum": 3,
    "class_detail": [
        {
            "class_label": 1,
            "class_name": "cuke",
            "class_test_images": 110,
            "class_trainer_images": 990
        },
        {
            "class_label": 2,
            "class_name": "lettuce",
            "class_test_images": 110,
            "class_trainer_images": 990
        },
        {
            "class_label": 3,
            "class_name": "lotus_root",
            "class_test_images": 110,
            "class_trainer_images": 990
        }
    ]
}

讀取數據


通過MyReader.py這個程序可以將上一部分的圖像列表讀取,生成訓練和測試使用的reader,在生成reader前,要傳入一個圖像的大小,PaddlePaddle會幫我們按照這個大小隨機裁剪一個方形的圖像,這是種隨機裁剪也是數據增強的一種方式.

from multiprocessing import cpu_count
import paddle.v2 as paddle

class MyReader:
    def __init__(self,imageSize):
        self.imageSize = imageSize

    def train_mapper(self,sample):
        '''
        map image path to type needed by model input layer for the training set
        '''
        img, label = sample
        img = paddle.image.load_image(img)
        img = paddle.image.simple_transform(img, 70, self.imageSize, True)
        return img.flatten().astype('float32'), label

    def test_mapper(self,sample):
        '''
        map image path to type needed by model input layer for the test set
        '''
        img, label = sample
        img = paddle.image.load_image(img)
        img = paddle.image.simple_transform(img, 70, self.imageSize, False)
        return img.flatten().astype('float32'), label

    def train_reader(self,train_list, buffered_size=1024):
        def reader():
            with open(train_list, 'r') as f:
                lines = [line.strip() for line in f]
                for line in lines:
                    img_path, lab = line.strip().split('\t')
                    yield img_path, int(lab)

        return paddle.reader.xmap_readers(self.train_mapper, reader,
                                          cpu_count(), buffered_size)

    def test_reader(self,test_list, buffered_size=1024):
        def reader():
            with open(test_list, 'r') as f:
                lines = [line.strip() for line in f]
                for line in lines:
                    img_path, lab = line.strip().split('\t')
                    yield img_path, int(lab)

        return paddle.reader.xmap_readers(self.test_mapper, reader,
                                          cpu_count(), buffered_size)

定義神經網絡

編寫一個vgg.py來定義VGG神經網絡,這裏使用的是VGG神經網絡,跟上一篇文章用到的VGG又有一點不同,這裏可以看到conv_with_batchnorm=False,我是把BN關閉了,這是因爲啓用BN層的同時,也會使用Dropout層,因爲數據集比較小,再使用Dropout就更小了,導致模型無法收斂。如果讀者一定要啓動BN層的話,可以單獨關閉Dropout,把drop_rate全部設置爲0。如果數據集大的話,就可以不用這樣處理。

# coding:utf-8
import paddle.v2 as paddle

def vgg_bn_drop(datadim, type_size):
    # 獲取輸入數據模式
    image = paddle.layer.data(name="image",
                              type=paddle.data_type.dense_vector(datadim))

    def conv_block(ipt, num_filter, groups, dropouts, num_channels=None):
        return paddle.networks.img_conv_group(
            input=ipt,
            num_channels=num_channels,
            pool_size=2,
            pool_stride=2,
            conv_num_filter=[num_filter] * groups,
            conv_filter_size=3,
            conv_act=paddle.activation.Relu(),
            conv_with_batchnorm=False,
            conv_batchnorm_drop_rate=dropouts,
            pool_type=paddle.pooling.Max())

    conv1 = conv_block(image, 64, 2, [0.3, 0], 3)
    conv2 = conv_block(conv1, 128, 2, [0.4, 0])
    conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0])
    conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0])
    conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0])

    drop = paddle.layer.dropout(input=conv5, dropout_rate=0.5)
    fc1 = paddle.layer.fc(input=drop, size=512, act=paddle.activation.Linear())
    bn = paddle.layer.batch_norm(input=fc1,
                                 act=paddle.activation.Relu(),
                                 layer_attr=paddle.attr.Extra(drop_rate=0.5))
    fc2 = paddle.layer.fc(input=bn, size=512, act=paddle.activation.Linear())
    # 通過Softmax獲得分類器
    out = paddle.layer.fc(input=fc2,
                          size=type_size,
                          act=paddle.activation.Softmax())
    return out

使用PaddlePaddle開始訓練


編寫train.py文件訓練模型。

導入依賴包

首先要先導入依賴包,其中有PaddlePaddle的V2包和上面定義的Myreader.py讀取數據的程序

# coding:utf-8
import os
import sys
import paddle.v2 as paddle
from MyReader import MyReader
from vgg import vgg_bn_drop

初始化Paddle

然後我們創建一個類,再在類中創建一個初始化函數,在初始化函數中來初始化我們的PaddlePaddle

class PaddleUtil:
    def __init__(self):
        # 初始化paddpaddle,只是用CPU,把GPU關閉
        paddle.init(use_gpu=False, trainer_count=2)

獲取參數

該函數可以通過輸入是否是參數文件路徑,或者是損失函數,如果是參數文件路徑,就使用之前訓練好的參數生產參數.如果不傳入參數文件路徑,那就使用傳入的損失函數生成參數

def get_parameters(self, parameters_path=None, cost=None):
    if not parameters_path:
        # 使用cost創建parameters
        if not cost:
            raise NameError('請輸入cost參數')
        else:
            # 根據損失函數創建參數
            parameters = paddle.parameters.create(cost)
            print "cost"
            return parameters
    else:
        # 使用之前訓練好的參數
        try:
            # 使用訓練好的參數
            with open(parameters_path, 'r') as f:
                parameters = paddle.parameters.Parameters.from_tar(f)
            print "使用parameters"
            return parameters
        except Exception as e:
            raise NameError("你的參數文件錯誤,具體問題是:%s" % e)

創建訓練器

創建訓練器要3個參數,分別是損失函數,參數,優化方法.通過圖像的標籤信息和分類器生成損失函數.參數可以選擇是使用之前訓練好的參數,然後在此基礎上再進行訓練,又或者是使用損失函數生成初始化參數.然後再生成優化方法.就可以創建一個訓練器了.

# datadim 數據大小
def get_trainer(self, datadim, type_size, parameters_path):
    # 獲得圖片對於的信息標籤
    label = paddle.layer.data(name="label",
                              type=paddle.data_type.integer_value(type_size))

    # 獲取全連接層,也就是分類器
    out = vgg_bn_drop(datadim=datadim, type_size=type_size)

    # 獲得損失函數
    cost = paddle.layer.classification_cost(input=out, label=label)

    # 獲得參數
    if not parameters_path:
        parameters = self.get_parameters(cost=cost)
    else:
        parameters = self.get_parameters(parameters_path=parameters_path)

    '''
    定義優化方法
    learning_rate 迭代的速度
    momentum 跟前面動量優化的比例
    regularzation 正則化,防止過擬合
    '''
    optimizer = paddle.optimizer.Momentum(
        momentum=0.9,
        regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128),
        learning_rate=0.001 / 128,
        learning_rate_decay_a=0.1,
        learning_rate_decay_b=128000 * 35,
        learning_rate_schedule="discexp", )

    '''
    創建訓練器
    cost 分類器
    parameters 訓練參數,可以通過創建,也可以使用之前訓練好的參數
    update_equation 優化方法
    '''
    trainer = paddle.trainer.SGD(cost=cost,
                                 parameters=parameters,
                                 update_equation=optimizer)
    return trainer

開始訓練

要啓動訓練要4個參數,分別是訓練數據,訓練的輪數,訓練過程中的事件處理,輸入數據和標籤的對應關係.
訓練數據:這次的訓練數據是我們自定義的數據集.
訓練輪數:表示我們要訓練多少輪,次數越多準確率越高,最終會穩定在一個固定的準確率上.不得不說的是這個會比MNIST數據集的速度慢很多
事件處理:訓練過程中的一些事件處理,比如會在每個batch打印一次日誌,在每個pass之後保存一下參數和測試一下測試數據集的預測準確率.
輸入數據和標籤的對應關係:說明輸入數據是第0維度,標籤是第1維度

# ***********************開始訓練***************************************
def start_trainer(self, trainer, num_passes, save_parameters_name, trainer_reader, test_reader):
    # 獲得數據
    reader = paddle.batch(reader=paddle.reader.shuffle(reader=trainer_reader,
                                                       buf_size=50000),
                          batch_size=128)
    # 保證保存模型的目錄是存在的
    father_path = save_parameters_name[:save_parameters_name.rfind("/")]
    if not os.path.exists(father_path):
        os.makedirs(father_path)

    # 指定每條數據和padd.layer.data的對應關係
    feeding = {"image": 0, "label": 1}

    # 定義訓練事件
    def event_handler(event):
        if isinstance(event, paddle.event.EndIteration):
            if event.batch_id % 100 == 0:
                print "\nPass %d, Batch %d, Cost %f, Error %s" % (
                    event.pass_id, event.batch_id, event.cost, event.metrics['classification_error_evaluator'])
            else:
                sys.stdout.write('.')
                sys.stdout.flush()

        # 每一輪訓練完成之後
        if isinstance(event, paddle.event.EndPass):
            # 保存訓練好的參數
            with open(save_parameters_name, 'w') as f:
                trainer.save_parameter_to_tar(f)

            # 測試準確率
            result = trainer.test(reader=paddle.batch(reader=test_reader,
                                                      batch_size=128),
                                  feeding=feeding)
            print "\nTest with Pass %d, Classification_Error %s" % (
            event.pass_id, result.metrics['classification_error_evaluator'])

    '''
    開始訓練
    reader 訓練數據
    num_passes 訓練的輪數
    event_handler 訓練的事件,比如在訓練的時候要做一些什麼事情
    feeding 說明每條數據和padd.layer.data的對應關係
    '''
    trainer.train(reader=reader,
                  num_passes=num_passes,
                  event_handler=event_handler,
                  feeding=feeding)

然後在main中調用相應的函數,開始訓練,可以看到通過myReader.train_reader來生成一個reader

if __name__ == '__main__':
    # 類別總數
    type_size = 3
    # 圖片大小
    imageSize = 64
    # 總的分類名稱
    all_class_name = 'fruits'
    # 保存的model路徑
    parameters_path = "../model/model.tar"
    # 數據的大小
    datadim = 3 * imageSize * imageSize
    paddleUtil = PaddleUtil()
    myReader = MyReader(imageSize=imageSize)
    # parameters_path設置爲None就使用普通生成參數,
    trainer = paddleUtil.get_trainer(datadim=datadim, type_size=type_size, parameters_path=None)
    trainer_reader = myReader.train_reader(train_list="../data/%s/trainer.list" % all_class_name)
    test_reader = myReader.test_reader(test_list="../data/%s/test.list" % all_class_name)

    paddleUtil.start_trainer(trainer=trainer, num_passes=100, save_parameters_name=parameters_path,
                             trainer_reader=trainer_reader, test_reader=test_reader)

輸出日誌如下:’

Pass 0, Batch 0, Cost 1.162887, Error 0.6171875
.....................
Test with Pass 0, Classification_Error 0.353333324194

提示:如果報以下錯誤:

  File "/usr/local/lib/python2.7/dist-packages/paddle/v2/image.py", line 159, in load_image
    im = cv2.imread(file, flag)
AttributeError: 'NoneType' object has no attribute 'imread'

解決辦法如下,首先升級以下CV2:

sudo pip install opencv-python -U

然後安裝CV2的庫:

sudo apt install libopencv-dev

使用PaddlePaddle預測


編寫一個infer.py來預測我們的數據。
先定義一個獲取模型參數的函數:

def get_parameters(parameters_path):
    with open(parameters_path, 'r') as f:
        parameters = paddle.parameters.Parameters.from_tar(f)
    return parameters

定義預測函數,該函數需要輸入3個參數,
第一個是需要預測的圖像,圖像傳入之後,會經過load_image函數處理,大小會變成32*32大小,訓練是輸入數據的大小一樣.
第二個就是訓練好的參數
第三個是通過神經模型生成的分類器

def to_prediction(image_paths, parameters, out, imageSize):

    # 獲得要預測的圖片
    test_data = []
    for image_path in image_paths:
        test_data.append((paddle.image.load_and_transform(image_path, 70, imageSize, False)
                          .flatten().astype('float32'),))

    # 獲得預測結果
    probs = paddle.infer(output_layer=out,
                         parameters=parameters,
                         input=test_data)
    # 處理預測結果
    lab = np.argsort(-probs)
    # 返回概率最大的值和其對應的概率值
    all_result = []
    for i in range(0, lab.__len__()):
        all_result.append([lab[i][0], probs[i][(lab[i][0])]])
    return all_result

然後在main中調用相應的函數,開始預測,這個可以同時傳入多個數據,可以同時預測,最後別忘了在使用PaddlePaddle前初始化PaddlePaddle。

if __name__ == '__main__':
    paddle.init(use_gpu=False, trainer_count=2)
    # 類別總數
    type_size = 3
    # 圖片大小
    imageSize = 64
    # 保存的model路徑
    parameters_path = "../model/model.tar"
    # 數據的大小
    datadim = 3 * imageSize * imageSize

    # 添加數據
    image_path = []
    image_path.append("../images/vegetables/cuke/1515826971850.jpg")
    image_path.append("../images/vegetables/lettuce/1515827012863.jpg")
    image_path.append("../images/vegetables/lotus_root/1515827059200.jpg")
    out = vgg_bn_drop(datadim=datadim, type_size=type_size)
    parameters = get_parameters(parameters_path=parameters_path)
    all_result = to_prediction(image_paths=image_path, parameters=parameters,
                                          out=out, imageSize=imageSize)
    for i in range(0, all_result.__len__()):
        print '預測結果爲:%d,可信度爲:%f' % (all_result[i][0], all_result[i][1])

輸出的結果是:

預測結果爲:0,可信度爲:0.699004
預測結果爲:0,可信度爲:0.546674
預測結果爲:2,可信度爲:0.756389

所有代碼


train.py,訓練代碼:

# coding:utf-8
import os
import sys
import paddle.v2 as paddle
from MyReader import MyReader
from vgg import vgg_bn_drop


class PaddleUtil:
    # ***********************初始化操作***************************************
    def __init__(self):
        # 初始化paddpaddle,只是用CPU,把GPU關閉
        paddle.init(use_gpu=False, trainer_count=2)

    # **********************獲取參數***************************************
    def get_parameters(self, parameters_path=None, cost=None):
        if not parameters_path:
            # 使用cost創建parameters
            if not cost:
                raise NameError('請輸入cost參數')
            else:
                # 根據損失函數創建參數
                parameters = paddle.parameters.create(cost)
                print "cost"
                return parameters
        else:
            # 使用之前訓練好的參數
            try:
                # 使用訓練好的參數
                with open(parameters_path, 'r') as f:
                    parameters = paddle.parameters.Parameters.from_tar(f)
                print "使用parameters"
                return parameters
            except Exception as e:
                raise NameError("你的參數文件錯誤,具體問題是:%s" % e)

    # ***********************獲取訓練器***************************************
    # datadim 數據大小
    def get_trainer(self, datadim, type_size, parameters_path):
        # 獲得圖片對於的信息標籤
        label = paddle.layer.data(name="label",
                                  type=paddle.data_type.integer_value(type_size))

        # 獲取全連接層,也就是分類器
        out = vgg_bn_drop(datadim=datadim, type_size=type_size)

        # 獲得損失函數
        cost = paddle.layer.classification_cost(input=out, label=label)

        # 獲得參數
        if not parameters_path:
            parameters = self.get_parameters(cost=cost)
        else:
            parameters = self.get_parameters(parameters_path=parameters_path)

        '''
        定義優化方法
        learning_rate 迭代的速度
        momentum 跟前面動量優化的比例
        regularzation 正則化,防止過擬合
        '''
        optimizer = paddle.optimizer.Momentum(
            momentum=0.9,
            regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128),
            learning_rate=0.001 / 128,
            learning_rate_decay_a=0.1,
            learning_rate_decay_b=128000 * 35,
            learning_rate_schedule="discexp", )

        '''
        創建訓練器
        cost 分類器
        parameters 訓練參數,可以通過創建,也可以使用之前訓練好的參數
        update_equation 優化方法
        '''
        trainer = paddle.trainer.SGD(cost=cost,
                                     parameters=parameters,
                                     update_equation=optimizer)
        return trainer

    # ***********************開始訓練***************************************
    def start_trainer(self, trainer, num_passes, save_parameters_name, trainer_reader, test_reader):
        # 獲得數據
        reader = paddle.batch(reader=paddle.reader.shuffle(reader=trainer_reader,
                                                           buf_size=50000),
                              batch_size=128)
        # 保證保存模型的目錄是存在的
        father_path = save_parameters_name[:save_parameters_name.rfind("/")]
        if not os.path.exists(father_path):
            os.makedirs(father_path)

        # 指定每條數據和padd.layer.data的對應關係
        feeding = {"image": 0, "label": 1}

        # 定義訓練事件
        def event_handler(event):
            if isinstance(event, paddle.event.EndIteration):
                if event.batch_id % 100 == 0:
                    print "\nPass %d, Batch %d, Cost %f, Error %s" % (
                        event.pass_id, event.batch_id, event.cost, event.metrics['classification_error_evaluator'])
                else:
                    sys.stdout.write('.')
                    sys.stdout.flush()

            # 每一輪訓練完成之後
            if isinstance(event, paddle.event.EndPass):
                # 保存訓練好的參數
                with open(save_parameters_name, 'w') as f:
                    trainer.save_parameter_to_tar(f)

                # 測試準確率
                result = trainer.test(reader=paddle.batch(reader=test_reader,
                                                          batch_size=128),
                                      feeding=feeding)
                print "\nTest with Pass %d, Classification_Error %s" % (
                event.pass_id, result.metrics['classification_error_evaluator'])

        '''
        開始訓練
        reader 訓練數據
        num_passes 訓練的輪數
        event_handler 訓練的事件,比如在訓練的時候要做一些什麼事情
        feeding 說明每條數據和padd.layer.data的對應關係
        '''
        trainer.train(reader=reader,
                      num_passes=num_passes,
                      event_handler=event_handler,
                      feeding=feeding)


if __name__ == '__main__':
    # 類別總數
    type_size = 3
    # 圖片大小
    imageSize = 64
    # 總的分類名稱
    all_class_name = 'vegetables'
    # 保存的model路徑
    parameters_path = "../model/model.tar"
    # 數據的大小
    datadim = 3 * imageSize * imageSize
    paddleUtil = PaddleUtil()

    # *******************************開始訓練**************************************
    myReader = MyReader(imageSize=imageSize)
    # # parameters_path設置爲None就使用普通生成參數,
    trainer = paddleUtil.get_trainer(datadim=datadim, type_size=type_size, parameters_path=None)
    trainer_reader = myReader.train_reader(train_list="../data/%s/trainer.list" % all_class_name)
    test_reader = myReader.test_reader(test_list="../data/%s/test.list" % all_class_name)

    paddleUtil.start_trainer(trainer=trainer, num_passes=100, save_parameters_name=parameters_path,
                             trainer_reader=trainer_reader, test_reader=test_reader)

infer.py,預測代碼:

# coding:utf-8
import numpy as np
import paddle.v2 as paddle

from vgg import vgg_bn_drop


# **********************獲取參數***************************************
def get_parameters(parameters_path):
    with open(parameters_path, 'r') as f:
        parameters = paddle.parameters.Parameters.from_tar(f)
    return parameters


# ***********************使用訓練好的參數進行預測***************************************
def to_prediction(image_paths, parameters, out, imageSize):
    # 獲得要預測的圖片
    test_data = []
    for image_path in image_paths:
        test_data.append((paddle.image.load_and_transform(image_path, 70, imageSize, False)
                          .flatten().astype('float32'),))

    # 獲得預測結果
    probs = paddle.infer(output_layer=out,
                         parameters=parameters,
                         input=test_data)
    # 處理預測結果
    lab = np.argsort(-probs)
    # 返回概率最大的值和其對應的概率值
    all_result = []
    for i in range(0, lab.__len__()):
        all_result.append([lab[i][0], probs[i][(lab[i][0])]])
    return all_result


if __name__ == '__main__':
    paddle.init(use_gpu=False, trainer_count=2)
    # 類別總數
    type_size = 3
    # 圖片大小
    imageSize = 64
    # 保存的model路徑
    parameters_path = "../model/model.tar"
    # 數據的大小
    datadim = 3 * imageSize * imageSize

    # *******************************開始預測**************************************
    # 添加數據
    image_path = []
    image_path.append("../images/vegetables/cuke/1515826971850.jpg")
    image_path.append("../images/vegetables/lettuce/1515827012863.jpg")
    image_path.append("../images/vegetables/lotus_root/1515827059200.jpg")
    out = vgg_bn_drop(datadim=datadim, type_size=type_size)
    parameters = get_parameters(parameters_path=parameters_path)
    all_result = to_prediction(image_paths=image_path, parameters=parameters,
                                          out=out, imageSize=imageSize)
    for i in range(0, all_result.__len__()):
        print '預測結果爲:%d,可信度爲:%f' % (all_result[i][0], all_result[i][1])

DownloadImages.py,下載圖片的代碼:
這個程序可以從百度圖片中下載圖片,可以多個類別一起下載,還可以指定下載數量

# -*- coding:utf-8 -*-
import re
import uuid
import requests
import os


class DownloadImages:
    def __init__(self,download_max,key_word):
        self.download_sum = 0
        self.download_max = download_max
        self.key_word = key_word
        self.save_path = '../images/download/' + key_word

    def start_download(self):
        self.download_sum = 0
        gsm = 80
        str_gsm = str(gsm)
        pn = 0
        if not os.path.exists(self.save_path):
            os.makedirs(self.save_path)
        while self.download_sum < self.download_max:
            str_pn = str(self.download_sum)
            url = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&' \
                  'word=' + self.key_word + '&pn=' + str_pn + '&gsm=' + str_gsm + '&ct=&ic=0&lm=-1&width=0&height=0'
            print url
            result = requests.get(url)
            self.downloadImages(result.text)
        print '下載完成'

    def downloadImages(self,html):
        img_urls = re.findall('"objURL":"(.*?)",', html, re.S)
        print '找到關鍵詞:' + self.key_word + '的圖片,現在開始下載圖片...'
        for img_url in img_urls:
            print '正在下載第' + str(self.download_sum + 1) + '張圖片,圖片地址:' + str(img_url)
            try:
                pic = requests.get(img_url, timeout=50)
                pic_name = self.save_path + '/' + str(uuid.uuid1()) + '.' + str(img_url).split('.')[-1]
                with open(pic_name, 'wb') as f:
                    f.write(pic.content)
                self.download_sum += 1
                if self.download_sum >= self.download_max:
                    break
            except  Exception, e:
                print '【錯誤】當前圖片無法下載,%s' % e
                continue


if __name__ == '__main__':
    key_word_max = input('請輸入你要下載幾個類別:')
    key_words = []
    for sum in range(key_word_max):
        key_words.append(raw_input('請輸入第%s個關鍵字:' % str(sum+1)))
    max_sum = input('請輸入每個類別下載的數量:')
    for key_word in key_words:
        downloadImages = DownloadImages(max_sum, key_word)
        downloadImages.start_download()


上一章:《我的PaddlePaddle學習之路》筆記三——CIFAR彩色圖像識別
下一章:《我的PaddlePaddle學習之路》筆記五——驗證碼的識別


項目代碼


GitHub地址:https://github.com/yeyupiaoling/LearnPaddle

參考資料


  1. http://paddlepaddle.org/
小夜