三步實現圖片智能識別與分類


1.概要****
本代碼是基於python3.6和百度飛槳paddlepaddle2.0模塊實現,現在人工智能的模塊很很多,主流的有tf,pytorch,百度飛槳等,雖然百度飛槳的流行程度不如tf和pytorch,但是百度飛槳畢竟是國人開發出來的,而且在百度的aistuio上有一些免費的課程,大家可以去看一下https://aistudio.baidu.com/aistudio/course,個人覺得挺不錯的,廢話不多說直接上代碼

2.實現
下載模塊

pip install paddlepaddle

首先是圖片預處理部分,首先大家需要自己創建一個數據集,將不同的分類的圖片保存到不同的文件夾中,例如people文件夾下放人物圖,需要出注意的一點就是,文件路徑中不能帶有中文,不然程序會找不到文件,會報錯。圖片可以通過爬蟲爬取,或者可以直接用我的https://github.com/weita1013/Photo_classification,其中分類文件夾的名稱就是圖片的類別,數據集的數量最好不要太少,一個分類200張左右就可以基本實現功能。

# 數據預處理
import os
import shutil

name_dict = {'people': 0, 'animal': 1, 'landscape': 2,
             'vehicle': 3, 'food': 4}
data_root_path = r'dataset/photo/'
# 測試集路徑
test_file_path = data_root_path + 'test.list'
# 訓練集文件路徑
train_file_path = data_root_path + 'train.list'
# 樣本匯總文件
readme_file = data_root_path + 'readme.json'
# 記錄每個類別多少張訓練圖片、測試圖片
name_data_list = {}


def save_train_test_file(path, name):
    if name not in name_data_list:
        img_list = []
        img_list.append(path)
        name_data_list[name] = img_list
    else:
        name_data_list[name].append(path)


# 遍歷目錄、將圖片路徑存入字典,再由字典寫入文件
dirs = os.listdir(data_root_path)
for d in dirs:
    full_path = data_root_path + d
    if os.path.isdir(full_path):
        imgs = os.listdir(full_path)
        for img in imgs:
            save_train_test_file(full_path + '/' + img, d)
    else:
        pass
# 圖片分配到測試集和訓練集中,
with open(test_file_path, 'w')as f:
    pass
with open(train_file_path, 'w')as f:
    pass
# 遍歷字段,分配測試集
for name, img_list in name_data_list.items():
    i = 0
    num = len(img_list)
    print('{}:{}張'.format(name, num))
    for img in img_list:
        if i % 10 == 0:
            with open(test_file_path, 'a')as f:
                line = '%s\t%d\n' % (img, name_dict[name])
                f.write(line)
        else:
            with open(train_file_path, 'a')as f:
                line = '%s\t%d\n' % (img, name_dict[name])
                f.write(line)
        i += 1

第二步就是網絡的搭建、模型的訓練與保存。這部分就與深度學習基礎有關了,這些代碼看似晦澀,其實本質上還是python基礎的代碼,只要了解paddlepaddle模塊的使用,這段代碼就會變得很簡單,神經網絡我采用了三個卷積池化層,和兩個全連接層,訓練次數大概五六十次就差不多,因為我買不起NVIDIA的顯卡,所以我選在在cpu上訓練,有條件的朋友可以將place = fluid.CPUPlace() # 在cpu上執行這段代碼改成place = fluid.CUDAPlace(0) # 在gpu上執行這樣可以省下幾十倍的訓練時間。

import paddle
import os
import paddle.fluid as fluid
import numpy
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
paddle.enable_static()


def train_mapper(sample):
    img, label = sample
    if not os.path.exists(img):
        print('圖片不存在', img)
    else:
        # 讀取圖片
        img = paddle.dataset.image.load_image(img)
        # 對圖片進行變換,修剪,輸出矩陣
        img = paddle.dataset.image.simple_transform(im=img,
                                                    resize_size=100,
                                                    crop_size=100,
                                                    is_train=True)
        # 圖像歸一化處理,將值壓縮到0~1之間
        img = img.flatten().astype('float32') / 255.0
        return img, label


# 自定義reader,從訓練集讀取數據,並交給train_mapper處理
def train_r(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(train_mapper,
                                      reader,
                                      cpu_count(),
                                      buffered_size)


# 搭建神經網絡
# 輸入層、卷積池化層dropout*3、全連接層、dropout、全連接層
def convolution_nural_network(image, type_size):
    # 第一個卷積-池化層
    conv_pool_1 = fluid.nets.simple_img_conv_pool(input=image,  # 輸入數據
                                                  filter_size=3,  # 卷積核大小
                                                  num_filters=32,  # 卷積核數量,與輸出通道數相同
                                                  pool_size=2,  # 池化層大小2*2
                                                  pool_stride=2,  # 池化層步長
                                                  act='relu')  # 激活函數)
    # dropout 丟棄學習,隨機丟棄一些神經元的輸出,防止過擬合
    drop = fluid.layers.dropout(x=conv_pool_1,  # 輸出
                                dropout_prob=0.5)  # 丟棄率
    # 第二個卷積-池化層
    conv_pool_2 = fluid.nets.simple_img_conv_pool(input=drop,  # 輸入數據
                                                  filter_size=3,  # 卷積核大小
                                                  num_filters=64,  # 卷積核數量,與輸出通道數相同
                                                  pool_size=2,  # 池化層大小2*2
                                                  pool_stride=2,  # 池化層步長
                                                  act='relu')  # 激活函數)
    drop = fluid.layers.dropout(x=conv_pool_2,  # 輸出
                                dropout_prob=0.5)  # 丟棄率
    # 第三個卷積-池化層
    conv_pool_3 = fluid.nets.simple_img_conv_pool(input=drop,  # 輸入數據
                                                  filter_size=3,  # 卷積核大小
                                                  num_filters=64,  # 卷積核數量,與輸出通道數相同
                                                  pool_size=2,  # 池化層大小2*2
                                                  pool_stride=2,  # 池化層步長
                                                  act='relu')  # 激活函數)
    drop = fluid.layers.dropout(x=conv_pool_3,  # 輸出
                                dropout_prob=0.5)  # 丟棄率
    # 全連接層
    fc = fluid.layers.fc(input=drop,
                         size=512,
                         act='relu')
    drop = fluid.layers.dropout(x=fc, dropout_prob=0.5)
    # 輸出
    predict = fluid.layers.fc(input=drop,  # 輸出層
                              size=type_size,  # 最終分類個數
                              act='softmax')  # 激活函數
    return predict


# 准備數據執行訓練
BATCH_SIZE = 32
trainer_reader = train_r(train_list=train_file_path)
train_reader = paddle.batch(paddle.reader.shuffle(reader=trainer_reader,
                                                  buf_size=1200),
                            batch_size=BATCH_SIZE)
# 訓練時輸入數據
image = fluid.layers.data(name='image',
                          shape=[3, 100, 100],  # RGB三通道彩色圖像
                          dtype='float32')
# 訓練時期望輸出值/真實類別
label = fluid.layers.data(name='label',
                          shape=[1],
                          dtype='int64')
# 調用函數,創建卷積神經網絡
predict = convolution_nural_network(image=image,  # 輸入數據
                                    type_size=5)  # 類別數量
cost = fluid.layers.cross_entropy(input=predict,  # 預測值
                                  label=label)  # 期望值
avg_cost = fluid.layers.mean(cost)  # 求損失值的平均值
# 計算預測准確率
accuracy = fluid.layers.accuracy(input=predict,  # 預測值
                                 label=label)  # 期望值
# 優化器,自適應提督下降
optimizer = fluid.optimizer.Adam(learning_rate=0.001)
optimizer.minimize(avg_cost)
# 執行器
place = fluid.CPUPlace()  # 在cpu上執行
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())  # 初始化系統參數
feeder = fluid.DataFeeder(feed_list=[image, label],
                          place=place)
for pass_id in range(60):
    train_cost = 0
    for batch_id, data in enumerate(train_reader()):
        train_cost, train_acc = exe.run(program=fluid.default_main_program(),  # 執行默認program
                                        feed=feeder.feed(data),  # 輸入數據
                                        fetch_list=[avg_cost, accuracy]  # 獲取數據
                                        )
        if batch_id % 20 == 0:
            print('pass:{}, batch:{}, cost:{}, acc:{}'.format(pass_id, batch_id, train_cost[0], train_acc[0]))
print('訓練完成')

# 保存模型
model_save_dir = r'model/photo/'
shutil.rmtree(model_save_dir, ignore_errors=True)
os.makedirs(model_save_dir)
fluid.io.save_inference_model(dirname=model_save_dir,
                              feeded_var_names=['image'],
                              target_vars=[predict],
                              executor=exe)
print('模型保存完成')

最后一步就是模型的加載,結果的預測

from PIL import Image

place = fluid.CPUPlace()
infer_exe = fluid.Executor(place)


# 讀取圖片,調整尺寸歸一化處理
def load_image(path):
    img = paddle.dataset.image.load_and_transform(
        path, 100, 100, False).astype('float32')
    img = img / 255.0
    return img


infer_imgs = []  # 圖像數據列表
test_img = '4.jpg'  # 預測圖像路徑
infer_imgs.append(load_image(test_img))  # 加載圖像數據,添加到列表
infer_imgs = numpy.array(infer_imgs)  # 轉換成array

# 加載模型
[infer_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(model_save_dir, infer_exe)
# 現顯示原始圖片
img = Image.open(test_img)  # 打開圖片
plt.imshow(img)  # 顯示原始圖片
plt.show()
# 執行預測
results = infer_exe.run(infer_program,
                        feed={feed_target_names[0]: infer_imgs},
                        fetch_list=fetch_targets)
print(results)  # result為數組,包含每個類別的概率
result = numpy.argmax(results[0])  # 獲取最大值的索引
for k, v in name_dict.items():
    if result == v:
        print('預測結果為:', k)

附上結果截圖
在這里插入圖片描述
由於我偷懶(主要是cpu上訓練是在是太慢了),我就訓練了5次,結果差強人意,還能接受。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM