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次,結果差強人意,還能接受。