PaddlePaddle實現手寫藏文識別

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

前言

中央民族大學創業團隊巨神人工智能科技在科賽網公開了一個TibetanMNIST正是形體藏文中的數字數據集,TibetanMNIST數據集的原圖片中,圖片的大小是350*350的黑白圖片,圖片文件名稱的第一個數字就是圖片的標籤,如0_10_398.jpg這張圖片代表的就是藏文的數字0。在本項目中我們結合第四章所學的卷積神經網絡,來完成TibetanMNIST數據集的分類識別。

導入所需的包

主要是使用到PaddlePaddle的fluid和paddle依賴庫,cpu_count庫是獲取當前CPU的數量的,matplotlib用於展示圖片。

import paddle.fluid as fluid
import paddle
import numpy as np
from PIL import Image
import os
from multiprocessing import cpu_count
import matplotlib.pyplot as plt

生成圖像列表

因爲TibetanMNIST數據集已經在科賽網發佈了,所以我們創建項目之前還需要在科賽網中把數據集下載下來,數據集標題爲【首發活動】TibetanMNIST藏文手寫數字數據集,下載之後解答會得到一個TibetanMnist(350x350)文件夾,這個文件就是存放原圖像文件的,我們把這個文件壓縮爲zip格式並上傳到AI Studio平臺作爲個人數據集,然後在創建項目的時候掛載這個數據集就可以了。

掛載數據集之後,執行解壓命令,就可以得到一個目錄TibetanMnist(350x350),原圖像文件存放在這個目錄,我們可以在這個目錄讀取全部的圖片文件。

!unzip -q /home/aistudio/data/data2134/TibetanMnist(350x350).zip
data_path = './TibetanMnist(350x350)'
data_imgs = os.listdir(data_path)

獲取全部的圖片路徑之後,我們就生成一個圖像列表,這個列表文件包括圖片的絕對路徑和圖片對於的label,中間用製表符分開。格式如下,其中有一個lable.txt的文本文件,我們要忽略它,否則在讀取的時候就報錯。

/home/kesci/input/TibetanMNIST5610/TibetanMNIST/TibetanMNIST/8_2_1.jpg	8
/home/kesci/input/TibetanMNIST5610/TibetanMNIST/TibetanMNIST/0_11_264.jpg	0
/home/kesci/input/TibetanMNIST5610/TibetanMNIST/TibetanMNIST/0_13_320.jpg	0
/home/kesci/input/TibetanMNIST5610/TibetanMNIST/TibetanMNIST/3_16_193.jpg	3
with open('./train_data.list', 'w') as f_train:
    with open('./test_data.list', 'w') as f_test:
        for i in range(len(data_imgs)):
            if data_imgs[i] == 'lable.txt':
                continue
            if i % 10 == 0:
                f_test.write(os.path.join(data_path, data_imgs[i]) + "\t" + data_imgs[i][0:1] + '\n')
            else:
                f_train.write(os.path.join(data_path, data_imgs[i]) + "\t" + data_imgs[i][0:1] + '\n')
        print('圖像列表已生成。')

定義讀取數據

PaddlePaddle讀取訓練和測試數據都是通過reader來讀取的,所以我們要自定義一個reader。首先我們定義一個train_mapper()函數,這個函數是對圖片進行預處理的,比如通過paddle.dataset.image.simple_transform接口對圖片進行壓縮然後裁剪,和灰度化,當參數is_train爲True時就會隨機裁剪,否則爲中心裁剪,一般測試和預測都是中心裁剪。train_r()函數是從上一部分生成的圖像列表中讀取圖片路徑和標籤,然後把圖片路徑傳遞給train_mapper()函數進行預處理。同樣的測試數據也是相同的操作。

def train_mapper(sample):
    img, label = sample
    img = paddle.dataset.image.load_image(file=img, is_color=False)
    img = paddle.dataset.image.simple_transform(im=img, resize_size=32, crop_size=28, is_color=False, is_train=True)
    img = img.flatten().astype('float32') / 255.0
    return img, label
    
def train_r(train_list_path):
    def reader():
        with open(train_list_path, 'r') as f:
            lines = f.readlines()
            del lines[len(lines)-1]
            for line in lines:
                img, label = line.split('\t')
                yield img, int(label)
    return paddle.reader.xmap_readers(train_mapper, reader, cpu_count(), 1024)

def test_mapper(sample):
    img, label = sample
    img = paddle.dataset.image.load_image(file=img, is_color=False)
    img = paddle.dataset.image.simple_transform(im=img, resize_size=32, crop_size=28, is_color=False, is_train=False)
    img = img.flatten().astype('float32') / 255.0
    return img, label
    
def test_r(test_list_path):
    def reader():
        with open(test_list_path, 'r') as f:
            lines = f.readlines()
            for line in lines:
                img, label = line.split('\t')
                yield img, int(label)
    return paddle.reader.xmap_readers(test_mapper, reader, cpu_count(), 1024)

定義卷積神經網絡

這裏定義了一個卷積神經網絡,讀者可用根據自己的情況修改或更換其他卷積神經網絡。

def cnn(ipt):
    conv1 = fluid.layers.conv2d(input=ipt, 
                                num_filters=32, 
                                filter_size=3, 
                                padding=1, 
                                stride=1, 
                                name='conv1', 
                                act='relu')
    
    pool1 = fluid.layers.pool2d(input=conv1, 
                                pool_size=2, 
                                pool_stride=2, 
                                pool_type='max', 
                                name='pool1')
    
    bn1 = fluid.layers.batch_norm(input=pool1, name='bn1')
    
    conv2 = fluid.layers.conv2d(input=bn1, 
                                num_filters=64, 
                                filter_size=3, 
                                padding=1, 
                                stride=1, 
                                name='conv2', 
                                act='relu')
    
    pool2 = fluid.layers.pool2d(input=conv2, 
                                pool_size=2, 
                                pool_stride=2,
                                pool_type='max', 
                                name='pool2')
    
    bn2 = fluid.layers.batch_norm(input=pool2, name='bn2')
    
    fc1 = fluid.layers.fc(input=bn2, size=1024, act='relu', name='fc1')
    
    fc2 = fluid.layers.fc(input=fc1, size=10, act='softmax', name='fc2')
    
    return fc2

獲取網絡

通過上面定義的卷積神經網絡獲取一個分類器,網絡的輸入層是通過fluid.layers.data接口定義的,輸入的形狀爲[1, 28, 28],表示爲單通道,寬度和高度都是28的灰度圖。

image = fluid.layers.data(name='image', shape=[1, 28, 28], dtype='float32')
net = cnn(image)

定義損失函數

這裏使用了交叉熵損失函數fluid.layers.cross_entropy,還使用了fluid.layers.accuracy接口,方便在訓練和測試的是輸出平均值。

label = fluid.layers.data(name='label', shape=[1], dtype='int64')
cost = fluid.layers.cross_entropy(input=net, label=label)
avg_cost = fluid.layers.mean(x=cost)
acc = fluid.layers.accuracy(input=net, label=label, k=1)

克隆測試程序

在定義損失之後和定義優化方法之前從主程序中克隆一個測試程序。

test_program = fluid.default_main_program().clone(for_test=True)

定義優化方法

接着是定義優化方法,這裏使用的是Adam優化方法,讀取也可用使用其他的優化方法。

optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.001)
opt = optimizer.minimize(avg_cost)

創建執行器

這裏是創建執行器,並指定使用CPU執行訓練。

place = fluid.CPUPlace()
exe = fluid.Executor(place=place)
exe.run(program=fluid.default_startup_program())

把圖片數據生成reader

把上面定義的reader按照設置的大小得到每一個batch的reader。

train_reader = paddle.batch(reader=paddle.reader.shuffle(reader=train_r('./train_data.list'), buf_size=3000), batch_size=128)
test_reader = paddle.batch(reader=test_r('./test_data.list'), batch_size=128)

定義輸入數據的維度

定義輸入數據的維度,第一個是圖片數據,第二個是圖片對應的標籤。

feeder = fluid.DataFeeder(place=place, feed_list=[image, label])

開始訓練

開始執行訓練,這裏只是訓練10個Pass,讀者可以隨意設置。我們在每一個Pass訓練完成之後,都進行使用測試數據集測試模型的準確率和報錯一次預測模型。

for pass_id in range(2):
    for batch_id, data in enumerate(train_reader()):
        train_cost, train_acc = exe.run(program=fluid.default_main_program(), 
                                        feed=feeder.feed(data), 
                                        fetch_list=[avg_cost, acc])
        if batch_id % 100 == 0:
            print('\nPass:%d, Batch:%d, Cost:%f, Accuracy:%f' % (pass_id, batch_id, train_cost[0], train_acc[0]))
        else:
            print('.', end="")
    
    test_costs = []
    test_accs = []
    for batch_id, data in enumerate(test_reader()):
        test_cost, test_acc = exe.run(program=test_program, 
                                      feed=feeder.feed(data),
                                      fetch_list=[avg_cost, acc])
        test_costs.append(test_cost[0])
        test_accs.append(test_acc[0])
    test_cost = sum(test_costs) / len(test_costs)
    test_acc = sum(test_accs) / len(test_accs)
    print('\nTest:%d, Cost:%f, Accuracy:%f' % (pass_id, test_cost, test_acc))
    
    fluid.io.save_inference_model(dirname='./model', feeded_var_names=['image'], target_vars=[net], executor=exe)

輸出的信息:

Pass:0, Batch:0, Cost:2.971555, Accuracy:0.101562
...................................................................................................
Pass:0, Batch:100, Cost:0.509201, Accuracy:0.859375
........................
Test:0, Cost:0.255964, Accuracy:0.928092

Pass:1, Batch:0, Cost:0.383406, Accuracy:0.882812
...................................................................................................
Pass:1, Batch:100, Cost:0.262583, Accuracy:0.906250
........................
Test:1, Cost:0.210227, Accuracy:0.942152

Pass:2, Batch:0, Cost:0.248821, Accuracy:0.921875
...................................................................................................
Pass:2, Batch:100, Cost:0.121569, Accuracy:0.953125
........................
Test:2, Cost:0.147000, Accuracy:0.959041

Pass:3, Batch:0, Cost:0.219034, Accuracy:0.914062
...................................................................................................
Pass:3, Batch:100, Cost:0.149375, Accuracy:0.929688
........................
Test:3, Cost:0.135075, Accuracy:0.967970

Pass:4, Batch:0, Cost:0.097395, Accuracy:0.960938
...................................................................................................
Pass:4, Batch:100, Cost:0.088472, Accuracy:0.976562
........................
Test:4, Cost:0.130905, Accuracy:0.965254

Pass:5, Batch:0, Cost:0.115069, Accuracy:0.960938
...................................................................................................
Pass:5, Batch:100, Cost:0.132130, Accuracy:0.953125
........................
Test:5, Cost:0.123031, Accuracy:0.969086

Pass:6, Batch:0, Cost:0.083716, Accuracy:0.984375
...................................................................................................
Pass:6, Batch:100, Cost:0.093365, Accuracy:0.968750
........................
Test:6, Cost:0.113957, Accuracy:0.970686

Pass:7, Batch:0, Cost:0.062250, Accuracy:0.976562
...................................................................................................
Pass:7, Batch:100, Cost:0.095572, Accuracy:0.968750
........................
Test:7, Cost:0.097893, Accuracy:0.974182

Pass:8, Batch:0, Cost:0.122696, Accuracy:0.960938
...................................................................................................
Pass:8, Batch:100, Cost:0.154212, Accuracy:0.976562
........................
Test:8, Cost:0.095770, Accuracy:0.969570

Pass:9, Batch:0, Cost:0.105826, Accuracy:0.960938
...................................................................................................
Pass:9, Batch:100, Cost:0.125963, Accuracy:0.976562
........................
Test:9, Cost:0.078607, Accuracy:0.973550

獲取預測程序

通過上面保存的預測模型,我們可用生成預測程序,並用於圖片預測。

[infer_program, feeded_var_names, target_vars] = fluid.io.load_inference_model(dirname='./model', executor=exe)

進行數據預處理

在對圖片進行預測之前,還需要對圖片進行預處理。

def load_image(path):
    img = paddle.dataset.image.load_image(file=path, is_color=False)
    img = paddle.dataset.image.simple_transform(im=img, resize_size=32, crop_size=28, is_color=False, is_train=False)
    img = img.astype('float32')
    img = img[np.newaxis, ] / 255.0
    return img

獲取預測圖片

然後把與處理後的圖片加入到列表中,可用多張圖片一起預測的。然後轉換成numpy的類型。

infer_imgs = []
infer_imgs.append(load_image('./TibetanMnist(350x350)/0_10_398.jpg'))
infer_imgs = np.array(infer_imgs)
infer_imgs.shape

執行預測

最後執行預測,輸入的數據通過feed參數傳入,得到一個預測結果,這個結果是每個類別的概率。

result = exe.run(program=infer_program, 
                 feed={feeded_var_names[0]:infer_imgs}, 
                 fetch_list=target_vars)

解析結果,獲取概率最大的label

我們對輸出的結果轉換一下,把概率最大的label輸出,同時輸出當前預測的圖片。

lab = np.argsort(result)
im = Image.open('./TibetanMnist(350x350)/0_10_398.jpg')
plt.imshow(im)
plt.show()

print('預測結果爲:%d' % lab[0][0][-1])

在這裏插入圖片描述

參考資料

  1. https://www.kesci.com/home/dataset/5bfe734a954d6e0010683839
  2. https://blog.csdn.net/qq_33200967/article/details/83506694
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章