> 原文博客:Doi技術團隊

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

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

數據集介紹


本次使用的驗證碼是方正系統,現在很多的大學的教務系統用的就是這個方正系統,剛好既然那麼普遍,我們就用它練一練手。經過觀察大量的驗證碼發現,該系統的驗證碼只有小寫的字母和數字,這樣分類就少了很多了。該系統的驗證碼如下:
|驗證碼|尺寸|說明|
|:—:|:—:|:—:|
||7227|只有數字和小寫字母|
||12
27|第一個X方向的從5開始裁剪到17,Y取全部,即從0裁剪到27|
||1227|第二個X方向的從17開始裁剪到29,Y取全部,即從0裁剪到27|
||12
27|第三個X方向的從29開始裁剪到41,Y取全部,即從0裁剪到27|
||12*27|第四個X方向的從41開始裁剪到53,Y取全部,即從0裁剪到27|
通過上面表上說明,我們就可以開始裁剪驗證碼了。在裁剪之前我們先要下載編寫一個程序,讓它來幫我們下載更多的驗證碼

下載驗證碼


編寫一個下載驗證碼的程序DownloadYanZhengMa.py,這裏我們只需要傳入保存路徑和要下載的數量就可以了。

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

class DownloadYanZhengMa:
    def __init__(self,save_path,download_max):
        self.download_sum = 0
        self.save_path = save_path
        self.download_max = download_max

    def downloadImages(self):
        try:
            pic = requests.get('http://jwsys.ctbu.edu.cn/CheckCode.aspx?', timeout=500)
            pic_name = self.save_path+'/' +str(uuid.uuid1()) + '.png'
            with open(pic_name, 'wb') as f:
                f.write(pic.content)
            self.download_sum += 1
            print '已下載完成'+str(self.download_sum)+'張驗證碼'
            if self.download_sum >= self.download_max:
                return
            else:
                return self.downloadImages()
        except  Exception, e:
            print '【錯誤】當前圖片無法下載,%s' % e
            return self.downloadImages()


if __name__ == '__main__':
    downloadYanZhenMa = DownloadYanZhengMa(save_path='images/download_yanzhengma', download_max=1000)
    downloadYanZhenMa.downloadImages()

修改驗證碼的文件名


從上一個部分可以看到下載到images/download_yanzhengma文件夾中, 待下載完成之後,需要做以下幾件事:

  1. 將每一張驗證碼命名爲其對應的驗證碼內容,這是一個龐大的工作量
  2. 將命名好的驗證碼剪切到images/src_yanzhengma/文件夾中

修改驗證碼的文件名是一個非常費時的工程,如果快速正確命名,那要發揮你們的想象力了,筆者同時也提供了數據集,這個不用擔心. 正確命名是非常重要的, 在一個部分會講到.

裁剪驗證碼


在數據集介紹的那部分,我們編寫一個CorpYanZhengMa.py程序,讓它來幫我們去裁剪所有的驗證碼,但是要注意一下幾點:

  • 驗證碼的命名一定要對於驗證碼的內容,這個非常重要
  • 裁剪的驗證碼會單獨存放在自己對應的文件夾中
# coding=utf-8
import os
import uuid
from PIL import Image

class YanZhenMaUtil():
    def __init__(self):
        pass

    def splitimage(self,src, dstpath):
        name = src.split('/')
        name1 = name[name.__len__() - 1]
        name2 = name1.split('.')[0]
        l1 = list(name2)
        img = Image.open(src)
        box1 = (5, 0, 17, 27)
        box2 = (17, 0, 29, 27)
        box3 = (29, 0, 41, 27)
        box4 = (41, 0, 53, 27)
        path1 = dstpath + '/%s' % l1[0]
        path2 = dstpath + '/%s' % l1[1]
        path3 = dstpath + '/%s' % l1[2]
        path4 = dstpath + '/%s' % l1[3]
        if not os.path.exists(path1):
            os.makedirs(path1)
        if not os.path.exists(path2):
            os.makedirs(path2)
        if not os.path.exists(path3):
            os.makedirs(path3)
        if not os.path.exists(path4):
            os.makedirs(path4)
        img.crop(box1).save(path1 + '/%s.png' % uuid.uuid1())
        img.crop(box2).save(path2 + '/%s.png' % uuid.uuid1())
        img.crop(box3).save(path3 + '/%s.png' % uuid.uuid1())
        img.crop(box4).save(path4 + '/%s.png' % uuid.uuid1())

if __name__ == '__main__':
    root_path = 'images/src_yanzhengma/'
    dstpath = 'images/dst_yanzhengma/'
    imgs = os.listdir(root_path)
    yanZhenMaUtil = YanZhenMaUtil()
    for src in imgs:
        src = root_path + src
        yanZhenMaUtil.splitimage(src=src, dstpath=dstpath)

例如經過上面裁剪,會生成這些文件夾,裁剪的圖片會放在這裏

你會發現只有33個文件夾,你應該會好奇10+26不應該是36個類別嗎.因爲驗證碼去掉了容易混淆的9,o,z,所以只剩下了33個類別.

生成圖像列表


編寫一個生成CreateDataList.py的程序,然後我們要把剛纔的驗證碼生成一個圖像列表,只有這個這裏PaddlePaddle才能讀取驗證碼數據,在自定義圖像數據集的識別這一章有介紹,如果不瞭解的話可以閱讀該文章。
這裏就用到了上一個部分裁剪後的數據集,通過傳入../images/dst_yanzhengma這個路徑,會把之前裁剪好的所有圖像都生成它的相對路徑,給之後的訓練程序使用.

# 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/dst_yanzhengma')

通過上面的程序,一共會生成trainer.listtest.listreadme.json,其中trainer.listtest.list分佈是用來訓練和測試的,readme.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
        }
}

讀取數據


因爲是使用自定義數據集,所以同樣使用到reader.py這程序,但是這次又點不一樣,這次使用的單通道的灰度圖,所以我們的參數要變一變,把is_color的參數變成False,因爲默認的是True.從官方文檔可以瞭解到這些

paddle.v2.image.simple_transformimresize_sizecrop_sizeis_trainis_color = Truemean = None 

參數:
- im(ndarray) - HWC佈局的輸入圖像。
- resize_size(int) - 調整大小的圖像的較短邊緣長度。
- crop_size(int) - 裁剪尺寸。
- is_train(bool) - 是否訓練。
- is_color(bool) - 圖像是否是彩色的。
- mean(numpy array | list) - 平均值,可以是每個通道的元素平均值或平均值。

MyReader代碼

爲了做一下區分,我把命名改成了MyReade.py,在舊版本的該程序是有bug的,如果讀者想使用這個程序,想要更新本地PaddlePaddle的版本,舊版本的bug是沒有對灰度的圖像處理,所以在做這個灰度的驗證碼時會報錯。

# coding=utf-8
from multiprocessing import cpu_count
import paddle.v2 as paddle


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

    def train_mapper(self, sample):
        img, label = sample
        # 我這裏使用的是本地的image,如果你的paddlepaddle是最新的,也可以使用padd.v2.image
        # 因爲是灰度圖,所以is_color=False
        img = paddle.image.load_image(img, is_color=False)
        img = paddle.image.simple_transform(img, 38, self.imageSize, True, is_color=False)
        return img.flatten().astype('float32'), label

    def test_mapper(self, sample):
        img, label = sample
        # 我這裏使用的是本地的image,如果你的paddlepaddle是最新的,也可以使用padd.v2.image
        # 因爲是灰度圖,所以is_color=False
        img = paddle.image.load_image(img, is_color=False)
        img = paddle.image.simple_transform(img, 38, self.imageSize, False, is_color=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)

使用PaddlePaddle開始訓練


同樣在開始訓練的前,要定義一個神經網絡vgg.py,我們這次使用的還是前面兩章使用到的VGG16的神經網絡模型,在這裏我同樣是把BN層關閉了,至於爲什麼,可以查看之前的文章

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


# ***********************定義VGG卷積神經網絡模型***************************************
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], 1)
    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

然後創建一個train.py編寫以下代碼:

導入依賴包

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

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

初始化Paddle

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

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

程序默認給出的是VGG16網絡神經模型,還記得我們在手寫數字識別使用的卷積神經網絡LeNet-5吧,這裏筆者也提供LeNet-5的神經網絡模型cnn.py

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

# 卷積神經網絡LeNet-5,獲取分類器
def convolutional_neural_network(datadim, type_size):
    image = paddle.layer.data(name="image",
                              type=paddle.data_type.dense_vector(datadim))

    # 第一個卷積--池化層
    conv_pool_1 = paddle.networks.simple_img_conv_pool(input=image,
                                                       filter_size=5,
                                                       num_filters=20,
                                                       num_channel=1,
                                                       pool_size=2,
                                                       pool_stride=2,
                                                       act=paddle.activation.Relu())
    # 第二個卷積--池化層
    conv_pool_2 = paddle.networks.simple_img_conv_pool(input=conv_pool_1,
                                                       filter_size=5,
                                                       num_filters=50,
                                                       num_channel=20,
                                                       pool_size=2,
                                                       pool_stride=2,
                                                       act=paddle.activation.Relu())
    # 以softmax爲激活函數的全連接輸出層
    out = paddle.layer.fc(input=conv_pool_2,
                          size=type_size,
                          act=paddle.activation.Softmax())
    return out

如果要使用LeNet-5,只要把

out = self.vgg_bn_drop(input=image, type_size=type_size)

改成

out = self.convolutional_neural_network(input=image, type_size=type_size)

同時要把訓練優化方法改成以下方法就可以了

optimizer = paddle.optimizer.Momentum(learning_rate=0.00001 / 128.0,
                                      momentum=0.9,
                                      regularization=paddle.optimizer.L2Regularization(rate=0.005 * 128))

要提醒的是,爲了讓網絡能夠收斂,我把學習率調了很低,所以訓練收斂會非常慢.

獲取參數

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

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 正則化,防止過擬合
    '''
    # ********************如果使用VGG網絡模型就用這個優化方法******************
    optimizer = paddle.optimizer.Momentum(
        momentum=0.9,
        regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128),
        learning_rate=0.0001 / 128,
        learning_rate_decay_a=0.1,
        learning_rate_decay_b=128000 * 35,
        learning_rate_schedule="discexp", )

    # ********************如果使用LeNet-5網絡模型就用這個優化方法******************
    # optimizer = paddle.optimizer.Momentum(learning_rate=0.00001 / 128.0,
    #                                       momentum=0.9,
    #                                       regularization=paddle.optimizer.L2Regularization(rate=0.005 * 128))

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

開始訓練

我們把圖片設置成灰度圖來處理了,所以數據集也非常小。所以相對之前訓練CIFAR數據集來說,訓練起來還算挺快的。

# ***********************開始訓練***************************************
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, %s" % (
                    event.pass_id, event.batch_id, event.cost, event.metrics)
            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, %s" % (event.pass_id, result.metrics)

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

然後在main中調用相應的函數,就可以開始訓練了

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

    # *******************************開始訓練**************************************
    myReader = MyReader(imageSize=imageSize)
    # parameters_path設置爲None就使用普通生成參數,
    trainer = paddleUtil.get_trainer(datadim=datadim, type_size=type_size, parameters_path=parameters_path)
    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 3.684595, {'classification_error_evaluator': 0.9765625}
........................................
Test with Pass 0, {'classification_error_evaluator': 0.930390477180481}

Pass 1, Batch 0, Cost 3.523515, {'classification_error_evaluator': 0.953125}
........................................
Test with Pass 1, {'classification_error_evaluator': 0.8862478733062744}

使用PaddlePaddle預測


編寫infer.py做驗證碼預測,這次預測要做的事情比較多.
因爲傳進來的是一個完整的驗證碼,所以首先要對驗證碼進行裁剪.
然後把裁剪後的數據傳該PaddlePaddle進行預測.
預測出來的是一個label值,所以還有通過label找到對應的字符

裁剪要預測的驗證碼

# *****************獲取你要預測的參數********************************
def get_TestData(path, imageSize):
    test_data = []
    img = Image.open(path)
    # 切割圖片並保存
    box1 = (5, 0, 17, 27)
    box2 = (17, 0, 29, 27)
    box3 = (29, 0, 41, 27)
    box4 = (41, 0, 53, 27)
    temp = '../images/temp'
    img.crop(box1).resize((32, 32), Image.ANTIALIAS).save(temp + '/1.png')
    img.crop(box2).resize((32, 32), Image.ANTIALIAS).save(temp + '/2.png')
    img.crop(box3).resize((32, 32), Image.ANTIALIAS).save(temp + '/3.png')
    img.crop(box4).resize((32, 32), Image.ANTIALIAS).save(temp + '/4.png')
    # 把圖像加載到預測數據中
    test_data.append((image.load_and_transform(temp + '/1.png', 38, imageSize, False, is_color=False)
                      .flatten().astype('float32'),))
    test_data.append((image.load_and_transform(temp + '/2.png', 38, imageSize, False, is_color=False)
                      .flatten().astype('float32'),))
    test_data.append((image.load_and_transform(temp + '/3.png', 38, imageSize, False, is_color=False)
                      .flatten().astype('float32'),))
    test_data.append((image.load_and_transform(temp + '/4.png', 38, imageSize, False, is_color=False)
                      .flatten().astype('float32'),))
    return test_data

使用裁剪好的圖像進行預測

def to_prediction(test_data, parameters, out, all_class_name):
    with open('../data/%s/readme.json' % all_class_name) as f:
        txt = f.read()
    # 獲得預測結果
    probs = paddle.infer(output_layer=out,
                         parameters=parameters,
                         input=test_data)
    # 處理預測結果
    lab = np.argsort(-probs)
    # 返回概率最大的值和其對應的概率值
    result = ''
    for i in range(0, lab.__len__()):
        print '第%d張預測結果爲:%d,可信度爲:%f' % (i + 1, lab[i][0], probs[i][(lab[i][0])])
        result = result + lab_to_result(lab[i][0], txt)
    return str(result)

把預測的label轉換成對應的字符

def lab_to_result(lab, json_str):
    myjson = json.loads(json_str)
    class_details = myjson['class_detail']
    for class_detail in class_details:
        if class_detail['class_label'] == lab:
            return class_detail['class_name']

然後通過以上的程序拼接,最後在main入口中調用對應的程序就可以預測驗證碼了

if __name__ == '__main__':
    # 類別總數
    type_size = 33
    # 圖片大小
    imageSize = 32
    # 總的分類名稱
    all_class_name = 'dst_yanzhengma'
    # 保存的model路徑
    parameters_path = "../model/model.tar"
    # 數據的大小
    datadim = imageSize * imageSize

    out = get_out(datadim=datadim, type_size=type_size)
    parameters = get_parameters(parameters_path=parameters_path)
    # 添加數據
    test_data = paddleUtil.get_TestData("../images/src_yanzhengma/0a13.png", imageSize=imageSize)
    result = paddleUtil.to_prediction(test_data=test_data,
                                      parameters=parameters,
                                      out=out,
                                      all_class_name=all_class_name)
    print '預測結果爲:%s' % result

預測結果輸出

第1張預測結果爲:0,可信度爲:0.966999
第2張預測結果爲:9,可信度爲:0.664706
第3張預測結果爲:1,可信度爲:0.780999
第4張預測結果爲:3,可信度爲:0.959722
預測結果爲:0a13

項目代碼


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


上一章:《我的PaddlePaddle學習之路》筆記四——自定義圖像數據集的識別
下一章:《我的PaddlePaddle學習之路》筆記六——驗證碼端到端的識別


參考資料


  1. http://paddlepaddle.org/
  2. https://www.jianshu.com/p/479dff9a599d
小夜