Python機器學習設計——果蔬識別


一、選題背景

在學習了深度學習案例——MNIST手寫數字識別和基於keras框架的貓狗圖像識別,為了進一步熟悉tensorflow和keras的基本用法和網絡框架,試想着實現對水果和蔬菜的種類進行識別。

二、機器學習案例設計方案

1.數據集來源

水果蔬菜數據集:

數據集來源於kaggle,因數據集作者為了構建一個應用程序,該應用程序可以從捕獲的照片中識別食品,並為用戶提供可以使用食品制作的不同食譜從必應圖像搜索中抓取的,共包含4291張圖像,36個種類,分為train(每個種類100張),test(每個種類10張),validation(每個種類10張)三個文件夾,上述每個文件夾都包含不同水果和蔬菜的子文件夾,其中存在相應食品的圖像,包含水果10種,蔬菜26種,共36種。

2.采用的機器學習框架描述

卷積神經網絡(Convolutional Neural Network, CNN):卷積神經網絡是一類包含卷積計算且具有深度結構的前饋神經網絡,是深度學習技術中極具代表的網絡結構之一,在圖像處理領域取得了很大的成功,在國際標准的 ImageNet 數據集上,許多成功的模型都是基於 CNN 的。

Tensorflow:TensorFlow是谷歌基於DistBelief進行研發的第二代人工智能學習系統,其命名來源於本身的運行原理。Tensor(張量)意味着N維數組,Flow(流)意味着基於數據流圖的計算,TensorFlow為張量從流圖的一端流動到另一端計算過程。TensorFlow是將復雜的數據結構傳輸至人工智能神經網中進行分析和處理過程的系統,可被用於語音識別或圖像識別等多項機器學習和深度學習領域。

Keras:Keras是一個模型級( model-level)的庫,為開發深度學習模型提供了高層次的構建模塊。它不處理張量操作、求微積分等基礎的運算,而是依賴--個專門的、高度優化的張量庫來完成這些運算。這個張量庫就是Keras的后端引擎(backend engine),如TensorFlow等。

3.涉及到的技術難點和解決思路

一些第三方庫沒有此模塊的問題  解決思路:降版本或者使用功能相同的新模塊

三、機器學習的實現步驟

果蔬識別

1.對原有數據集進行分類

1)將數據集train,test,和validation分類成fruit和vegetable兩類

 1 import os
 2 
 3 import shutil
 4 
 5 #訓練集數據處理
 6 def train(file_path):
 7     d=[]
 8     s=[]
 9     for root, dirs , files in os.walk(file_path): #讀取文件並提取出文件路徑和類名    
10         d.append(root)#文件路徑
11         s.append(dirs)#類名
12         for i in s:
13             if i!=s[0]:
14                 s.remove(i)
15         b = [ i for item in s for i in item]        
16     d.pop(0)
17     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
18     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
19                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
20                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
21                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
22     #用for循環對水果和蔬菜進行分類
23     #訓練集數據處理
24     #水果
25     for i in b:
26         for j in fruit:
27             if i==j:
28                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/train",i),
29                             "C:/Users/linyicheng/Desktop/fruit/train")
30     #蔬菜
31     for i in b:
32         for j in vegetables:
33             if i==j:
34                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/train",i),
35                             "C:/Users/linyicheng/Desktop/vegetable/train")
36 
37 train("C:/Users/linyicheng/Desktop/train")
 1 #驗證集數據處理
 2 def validation(file_path):
 3     d=[]
 4     s=[]
 5     for root, dirs , files in os.walk(file_path):     
 6         d.append(root)
 7         s.append(dirs)
 8         for i in s:
 9             if i!=s[0]:
10                 s.remove(i)
11         b = [ i for item in s for i in item]        
12     d.pop(0)
13     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
14     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
15                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
16                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
17                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
18     #訓練集數據處理
19     #水果
20     for i in b:
21         for j in fruit:
22             if i==j:
23                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/validation",i),
24                             "C:/Users/linyicheng/Desktop/fruit/validation")
25     #蔬菜
26     for i in b:
27         for j in vegetables:
28             if i==j:
29                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/validation",i),
30                             "C:/Users/linyicheng/Desktop/vegetable/validation")
31 
32 validation("C:/Users/linyicheng/Desktop/validation")
 1 #測試集數據處理
 2 def test(file_path):
 3     d=[]
 4     s=[]
 5     for root, dirs , files in os.walk(file_path):     
 6         d.append(root)
 7         s.append(dirs)
 8         for i in s:
 9             if i!=s[0]:
10                 s.remove(i)
11         b = [ i for item in s for i in item]        
12     d.pop(0)
13     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
14     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
15                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
16                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
17                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
18     #訓練集數據處理
19     #水果
20     for i in b:
21         for j in fruit:
22             if i==j:
23                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/test",i),
24                             "C:/Users/linyicheng/Desktop/fruit/test")
25     #蔬菜
26     for i in b:
27         for j in vegetables:
28             if i==j:
29                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/test",i),
30                             "C:/Users/linyicheng/Desktop/vegetable/test")
31 
32 test("C:/Users/linyicheng/Desktop/test")

2.對數據集進行預處理,模仿貓狗識別建立數據集目錄

1)對fruit,vegetable里的train,test,validation進行重命名

 1 #水果
 2 outer_path ="C:/Users/linyicheng/Desktop/fruit/test"
 3 folderlist = os.listdir(outer_path)          #列舉文件夾
 4  
 5 for folder in folderlist:     
 6     inner_path = os.path.join(outer_path, folder)
 7     total_num_folder = len(folderlist)       #文件夾的總數
 8        #打印文件夾的總數
 9     filelist = os.listdir(inner_path)        #列舉圖片
10     i = 0
11     for item in filelist:
12         total_num_file = len(filelist)       #單個文件夾內圖片的總數
13         if item.endswith('.jpg'):
14             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
15             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
16             try:
17                 os.rename(src, dst)        
18                 i += 1
19             except:
20                 continue
 1 outer_path ="C:/Users/linyicheng/Desktop/fruit/train"
 2 folderlist = os.listdir(outer_path)          #列舉文件夾
 3  
 4 for folder in folderlist:     
 5     inner_path = os.path.join(outer_path, folder)
 6     total_num_folder = len(folderlist)       #文件夾的總數
 7        #打印文件夾的總數
 8  
 9     filelist = os.listdir(inner_path)        #列舉圖片
10     i = 0
11     for item in filelist:
12         total_num_file = len(filelist)       #單個文件夾內圖片的總數
13         if item.endswith('.jpg'):
14             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
15             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
16             try:
17                 os.rename(src, dst)
18                 
19                 i += 1
20             except:
21                 continue
 1 #驗證集
 2 outer_path ="C:/Users/linyicheng/Desktop/fruit/validation"
 3 folderlist = os.listdir(outer_path)          #列舉文件夾
 4  
 5 for folder in folderlist:     
 6     inner_path = os.path.join(outer_path, folder)
 7     total_num_folder = len(folderlist)       #文件夾的總數
 8        #打印文件夾的總數
 9  
10     filelist = os.listdir(inner_path)        #列舉圖片
11     i = 0
12     for item in filelist:
13         total_num_file = len(filelist)       #單個文件夾內圖片的總數
14         if item.endswith('.jpg'):
15             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
16             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
17             try:
18                 os.rename(src, dst)
19                 
20                 i += 1
21             except:
22                 continue
 1 #蔬菜
 2 outer_path ="C:/Users/linyicheng/Desktop/vegetable/test"
 3 folderlist = os.listdir(outer_path)          #列舉文件夾
 4  
 5 for folder in folderlist:     
 6     inner_path = os.path.join(outer_path, folder)
 7     total_num_folder = len(folderlist)       #文件夾的總數
 8        #打印文件夾的總數
 9     filelist = os.listdir(inner_path)        #列舉圖片
10     i = 0
11     for item in filelist:
12         total_num_file = len(filelist)       #單個文件夾內圖片的總數
13         if item.endswith('.jpg'):
14             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
15             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
16             try:
17                 os.rename(src, dst)        
18                 i += 1
19             except:
20                 continue
 1 outer_path ="C:/Users/linyicheng/Desktop/vegetable/train"
 2 folderlist = os.listdir(outer_path)          #列舉文件夾
 3  
 4 for folder in folderlist:     
 5     inner_path = os.path.join(outer_path, folder)
 6     total_num_folder = len(folderlist)       #文件夾的總數
 7        #打印文件夾的總數
 8  
 9     filelist = os.listdir(inner_path)        #列舉圖片
10     i = 0
11     for item in filelist:
12         total_num_file = len(filelist)       #單個文件夾內圖片的總數
13         if item.endswith('.jpg'):
14             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
15             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
16             try:
17                 os.rename(src, dst)
18                 
19                 i += 1
20             except:
21                 continue
 1 outer_path ="C:/Users/linyicheng/Desktop/vegetable/validation"
 2 folderlist = os.listdir(outer_path)          #列舉文件夾
 3  
 4 for folder in folderlist:     
 5     inner_path = os.path.join(outer_path, folder)
 6     total_num_folder = len(folderlist)       #文件夾的總數
 7        #打印文件夾的總數
 8  
 9     filelist = os.listdir(inner_path)        #列舉圖片
10     i = 0
11     for item in filelist:
12         total_num_file = len(filelist)       #單個文件夾內圖片的總數
13         if item.endswith('.jpg'):
14             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
15             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
16             try:
17                 os.rename(src, dst)
18                 
19                 i += 1
20             except:
21                 continue

2)將文件移到base目錄中,構建數據集目錄結構

 1 #目標文件夾,此處為相對路徑,也可以改為絕對路徑
 2 import shutil
 3 determination = "C:/Users/linyicheng/Desktop/base/test/fruit"#目標
 4 if not os.path.exists(determination):
 5     os.makedirs(determination)
 6 
 7 #源文件夾路徑
 8 path = "C:/Users/linyicheng/Desktop/fruit/test"
 9 folders = os.listdir(path)
10 for folder in folders:
11     dir = path + '/' + str(folder)
12     files = os.listdir(dir)
13     for file in files:
14         source = dir + '/' + str(file)
15         deter = determination + '/' + str(file)
16         shutil.copyfile(source, deter)
 1 determination = "C:/Users/linyicheng/Desktop/base/train/fruit"
 2 if not os.path.exists(determination):
 3     os.makedirs(determination)
 4 path = "C:/Users/linyicheng/Desktop/fruit/train"
 5 folders = os.listdir(path)
 6 for folder in folders:
 7     dir = path + '/' + str(folder)
 8     files = os.listdir(dir)
 9     for file in files:
10         source = dir + '/' + str(file)
11         deter = determination + '/' + str(file)
12         shutil.copyfile(source, deter)
 1 determination = "C:/Users/linyicheng/Desktop/base/validation/fruit"
 2 if not os.path.exists(determination):
 3     os.makedirs(determination)
 4 path = "C:/Users/linyicheng/Desktop/fruit/validation"
 5 folders = os.listdir(path)
 6 for folder in folders:
 7     dir = path + '/' + str(folder)
 8     files = os.listdir(dir)
 9     for file in files:
10         source = dir + '/' + str(file)
11         deter = determination + '/' + str(file)
12         shutil.copyfile(source, deter)
 1 import shutil
 2 determination = "C:/Users/linyicheng/Desktop/base/test/vegetable"#目標
 3 if not os.path.exists(determination):
 4     os.makedirs(determination)
 5 
 6 #源文件夾路徑
 7 path = "C:/Users/linyicheng/Desktop/vegetable/test"
 8 folders = os.listdir(path)
 9 for folder in folders:
10     dir = path + '/' + str(folder)
11     files = os.listdir(dir)
12     for file in files:
13         source = dir + '/' + str(file)
14         deter = determination + '/' + str(file)
15         shutil.copyfile(source, deter)
 1 determination = "C:/Users/linyicheng/Desktop/base/train/vegetable"
 2 if not os.path.exists(determination):
 3     os.makedirs(determination)
 4 path = "C:/Users/linyicheng/Desktop/vegetable/train"
 5 folders = os.listdir(path)
 6 for folder in folders:
 7     dir = path + '/' + str(folder)
 8     files = os.listdir(dir)
 9     for file in files:
10         source = dir + '/' + str(file)
11         deter = determination + '/' + str(file)
12         shutil.copyfile(source, deter)
 1 determination = "C:/Users/linyicheng/Desktop/base/validation/vegetable"
 2 if not os.path.exists(determination):
 3     os.makedirs(determination)
 4 path = "C:/Users/linyicheng/Desktop/vegetable/validation"
 5 folders = os.listdir(path)
 6 for folder in folders:
 7     dir = path + '/' + str(folder)
 8     files = os.listdir(dir)
 9     for file in files:
10         source = dir + '/' + str(file)
11         deter = determination + '/' + str(file)
12         shutil.copyfile(source, deter)

3.設置路徑

1 base_dir="C:/Users/linyicheng/Desktop/base/"
2 train_data_dir="C:/Users/linyicheng/Desktop/base/train/"
3 test_data_dir="C:/Users/linyicheng/Desktop/base/test/"
4 val_data_dir="C:/Users/linyicheng/Desktop/base/validation/"
5 train_fruit_data="C:/Users/linyicheng/Desktop/base/train/fruit/"
6 test_fruit_data="C:/Users/linyicheng/Desktop/base/test/fruit/"
7 test_vegetable_data="C:/Users/linyicheng/Desktop/base/test/vegetable/"

4.搭建卷積神經網絡

 1 #搭建卷積神經網絡
 2 from keras import layers
 3 from keras import models
 4 model=models.Sequential()
 5 """
 6 Output shape計算公式:(輸入尺寸-卷積核尺寸/步長+1
 7 對CNN模型,Param的計算方法如下:
 8 卷積核長度*卷積核寬度*通道數+1)*卷積核個數
 9 輸出圖片尺寸:150-3+1=148*148
10 參數數量:32*3*3*3+32=896
11 """
12 model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))#卷積層1
13 model.add(layers.MaxPooling2D(2,2))#最大池化層1
14 # 輸出圖片尺寸:148/2=74*74 
15 # 輸出圖片尺寸:74-3+1=72*72,參數數量:64*3*3*32+64=18496
16 #32是第1個卷積層的輸出的通道數
17 model.add(layers.Conv2D(64, (3, 3), activation='relu'))#卷積層2
18 model.add(layers.MaxPooling2D((2, 2)))#最大池化層2
19 # 輸出圖片尺寸:72/2=36*36
20  
21 #Output Shape的輸出為36
22 # 輸出圖片尺寸:36-3+1=34*34,參數數量:128*3*3*64+128=73856
23 model.add(layers.Conv2D(128, (3, 3), activation='relu'))#卷積層3
24 model.add(layers.MaxPooling2D((2, 2)))#最大池化層3
25 # 輸出圖片尺寸:34/2=17*17
26 # 輸出圖片尺寸:17-3+1=15*15,參數數量:128*3*3*128+128=147584
27 model.add(layers.Conv2D(128, (3, 3), activation='relu'))# 輸出圖片尺寸:15/2=7*7
28 model.add(layers.MaxPooling2D((2, 2)))
29 model.add(layers.Flatten())
30 model.add(layers.Dense(512, activation='relu'))   #全連接層1
31 model.add(layers.Dense(1, activation='sigmoid'))#全連接層2,作為輸出層

 從輸出看出,卷積神經網絡dense_1 (Dense)的參數總數達到300多萬

1 model.summary() 

 5.編譯模型

1 # 編譯模型
2 # RMSprop 優化器。因為網絡最后一層是單一sigmoid單元
3 from keras import optimizers
4 model.compile(loss='binary_crossentropy',
5               optimizer=optimizers.RMSprop(lr=1e-4),
6                metrics=['acc'])

6.使用 ImageDataGenerator 從目錄中讀取樣本數據

 1 from keras.preprocessing.image import ImageDataGenerator
 2 #歸一化
 3 
 4 train_datagen = ImageDataGenerator(rescale=1./255)
 5 validation_datagen=ImageDataGenerator(rescale=1./255)
 6 test_datagen = ImageDataGenerator(rescale=1./255)
 7 # 數據集加載函數,指明數據集的位置並統一處理為imgheight*imgwidth的大小,同時設置batch
 8     # 加載訓練集
 9 train_ds = train_datagen.flow_from_directory (
10         #文件目錄位置
11         train_data_dir,
12 #輸入訓練圖像尺寸,所有圖片的size必須是150x150
13         class_mode='binary',
14         target_size=(150, 150),
15         batch_size=20)
16     #加載測試集
17 test_ds = test_datagen.flow_from_directory(
18         test_data_dir,
19         class_mode='binary',
20         target_size=(150, 150),
21         batch_size=20)
22     # 加載驗證集
23 val_ds =test_datagen.flow_from_directory(
24         val_data_dir,
25         class_mode='binary',
26         target_size=(150, 150),
27         batch_size=20)

1 for data_batch, labels_batch in train_ds:
2     print('data batch shape:', data_batch.shape)
3     print('labels batch shape:', labels_batch.shape)
4     break

 

 7.訓練模型(30次)

1 #訓練模型30輪次,可以修改epochs的值
2 history = model.fit_generator(
3        train_ds,
4        steps_per_epoch=100,
5        epochs=30,
6        validation_data=val_ds,
7        validation_steps=50)

可以看出訓練集精度(acc):0.9130 和驗證集精度(val_acc):0.9803

模型較為成功,接下來通過數據增強來提升精度

 1 #將訓練過程產生的數據保存為h5文件

2 model.save('fruit_and_vegetable_30epoch.h5') 

8.繪制訓練過程中的損失曲線和精度曲線

 1 import matplotlib.pyplot as plt
 2  
 3 acc = history.history['acc']
 4 val_acc = history.history['val_acc']
 5 loss = history.history['loss']
 6 val_loss = history.history['val_loss']
 7 
 8 epochs = range(1, len(acc) + 1)
 9 
10 plt.plot(epochs, acc, 'bo', label='Training acc')
11 plt.plot(epochs, val_acc, 'b', label='Validation acc')
12 plt.title('Training and validation accuracy')
13 plt.legend()
14 plt.figure() 
15 plt.plot(epochs, loss, 'bo', label='Training loss')
16 plt.plot(epochs, val_loss, 'b', label='Validation loss')
17 plt.title('Training and validation loss')
18 plt.legend()
19  
20 plt.show()

由圖可知訓練精度隨着時間線性增加,直到接近100%

9.單張圖片進行判斷圖片是水果還是蔬菜

 1 from PIL import Image
 2 from keras.preprocessing import image
 3 from keras.models import load_model
 4 import numpy as np
 5 #加載模型
 6 model=load_model('fruit_and_vegetable_30epoch.h5')
 7 #本地圖片路徑
 8 img_path=("C:/Users/linyicheng/Desktop/base/train/fruit/apple_41.jpg")
 9 img = image.load_img(img_path,target_size=(150,150))
10 # 將其轉換為具有形狀的Numpy數組(150、150、3)
11 img_tensor = image.img_to_array(img)/255
12 # 將其形態變為(150,150,150,3)的形狀
13 img_tensor = np.expand_dims(img_tensor, axis=0)
14 #取圖片信息
15 prediction =model.predict(img_tensor)
16 #輸出識別率
17 print(prediction)
18 if prediction>0.5:
19     print('水果')
20 else:
21     print('蔬菜')
22 plt.imshow(img)

10. 數據增強訓練,利用ImageDataGenerator實現數據增強

 1 from keras.preprocessing.image import ImageDataGenerator
 2 from keras.models import load_model
 3 from tensorflow.python.keras.preprocessing import image
 4 from tensorflow.python.keras.preprocessing.image import ImageDataGenerator,array_to_img,img_to_array,load_img
 5 
 6 import os
 7 from keras.preprocessing.image import load_img
 8 import matplotlib.pyplot as plt
 9 figure,ax = plt.subplots(nrows=1, ncols=4, sharex=True, 
10                          sharey=True,figsize=(16,10))
11 
12 datagen=ImageDataGenerator(
13     rotation_range=40,      #圖像隨機旋轉角度范圍
14     width_shift_range=0.2,  #圖片在水平方向上平移的比例
15     height_shift_range=0.2, #圖片在垂直方向上平移的比例
16     shear_range=0.2,        #隨機錯切變換的角度
17     zoom_range=0.2,         #圖像隨機縮放的范圍
18     horizontal_flip=True,   #隨機將一半圖像水平翻轉
19       
20     fill_mode='nearest')
21 #填充創建像素的一種方法
22 fnames=[os.path.join(train_fruit_data,fname)for fname in os.listdir(train_fruit_data)]
23 img_path=fnames[6]
24 img=image.load_img(img_path,target_size=(150,150))
25 x = image.img_to_array(img)/255
26 x = x.reshape((1,) + x.shape)
27 i = 0
28 for batch in datagen.flow(x, batch_size=1):
29     ax = ax.flatten()   # 將子圖從多維變成一維
30     plt.figure(i)
31     imgplot = ax[i-1].imshow(image.array_to_img(batch[0]), cmap='Greys', interpolation='nearest')
32     i += 1
33     if i % 4 == 0:
34         break
35 plt.show() #繪制增強后的圖像
36 '''
37 雖然使用了數據增強技術,但是從輸出的圖像來看,圖片之間還是有很大的相似度,
38 因為它們均來自同一張原始圖片,並沒有提供新的信息。
39 為了盡可能消除過擬合,可以在模型中增加一個DDropout層,添加到密集連接分類
40 器前
41 '''

11. 在緊密連接的分類器之前為模型添加一個Dropout層

 1 #在緊密連接的分類器之前為模型添加一個Dropout層
 2 model = models.Sequential()
 3 model.add(layers.Conv2D(32, (3, 3), activation='relu',
 4                         input_shape=(150, 150, 3)))
 5 model.add(layers.MaxPooling2D((2, 2)))
 6 model.add(layers.Conv2D(64, (3, 3), activation='relu'))
 7 model.add(layers.MaxPooling2D((2, 2)))
 8 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
 9 model.add(layers.MaxPooling2D((2, 2)))
10 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
11 model.add(layers.MaxPooling2D((2, 2)))
12 model.add(layers.Flatten())
13 model.add(layers.Dropout(0.5))
14 model.add(layers.Dense(512, activation='relu'))
15 model.add(layers.Dense(1, activation='sigmoid'))

12.編譯模型

1 from keras import optimizers
2 model.compile(loss='binary_crossentropy',
3               optimizer=optimizers.RMSprop(lr=1e-4),
4                metrics=['acc'])

13.使用數據增強和dropout來訓練我們的網絡

 1 #使用數據增強和dropout來訓練我們的網絡
 2 #歸一化
 3 train_datagen = ImageDataGenerator(
 4      rescale=1./255,
 5      rotation_range=40,
 6      width_shift_range=0.2,
 7      height_shift_range=0.2,
 8      shear_range=0.2,
 9      zoom_range=0.2,
10      horizontal_flip=True)
11 test_datagen = ImageDataGenerator(rescale=1./255)
12 train_generator = train_datagen.flow_from_directory(
13      train_data_dir,
14      #輸入訓練圖像尺寸,所有圖片的size必須是150x150
15      target_size=(150, 150),
16      batch_size=32,
17      #因為我們使用二元交叉熵損失,我們需要二元標簽
18      class_mode='binary')
19 validation_generator = test_datagen.flow_from_directory(
20      val_data_dir,
21      target_size=(150, 150),
22      batch_size=32,
23      class_mode='binary')

 14.訓練模型(100次)

1 history = model.fit_generator(
2        train_generator,
3        steps_per_epoch=100,
4        epochs=100,
5        validation_data=validation_generator,
6        validation_steps=50)

 1 model.save('fruit_and_vegetable_100epoch.h5')  

15.繪制訓練過程中的損失曲線和精度曲線

 1 import matplotlib.pyplot as plt
 2  
 3 acc = history.history['acc']
 4 val_acc = history.history['val_acc']
 5 loss = history.history['loss']
 6 val_loss = history.history['val_loss']
 7 
 8 epochs = range(1, len(acc) + 1)
 9 
10 plt.plot(epochs, acc, 'bo', label='Training acc')
11 plt.plot(epochs, val_acc, 'b', label='Validation acc')
12 plt.title('Training and validation accuracy')
13 plt.legend()
14 plt.figure() 
15 plt.plot(epochs, loss, 'bo', label='Training loss')
16 plt.plot(epochs, val_loss, 'b', label='Validation loss')
17 plt.title('Training and validation loss')
18 plt.legend()
19  
20 plt.show()

 16.使用新的訓練模型進行識別

 1 from keras.preprocessing import image
 2 
 3 from keras.models import load_model
 4 import numpy as np
 5 #加載模型
 6 model=load_model('fruit_and_vegetable_100epoch.h5')
 7 #本地圖片路徑
 8 img_path=("C:/Users/linyicheng/Desktop/base/train/fruit/apple_42.jpg")
 9 img = image.load_img(img_path,target_size=(150,150))
10 # 將其轉換為具有形狀的Numpy數組(150、150、3)
11 img_tensor = image.img_to_array(img)/255
12 # 將其形態變為(150,150,150,3)的形狀
13 img_tensor = np.expand_dims(img_tensor, axis=0)
14 #取圖片信息
15 prediction =model.predict(img_tensor)
16 #輸出識別率
17 print(prediction)
18 if prediction>0.5:
19     print('水果')
20 else:
21     print('蔬菜')
22 plt.imshow(img)

17.多張圖片進行識別判斷

 

 1 from PIL import Image
 2 from keras.preprocessing import image
 3 import matplotlib.pyplot as plt
 4 from keras.models import load_model
 5 plt.rcParams['font.family'] = ['SimHei']
 6 figure,ax = plt.subplots(nrows=2, ncols=4, sharex=True, sharey=True,figsize=(24,10))
 7 def convertjpg(jpgfile):
 8     #將圖片縮小到(150,150)的大小
 9     img=Image.open(jpgfile)
10     try:
11         new_img=img.resize((150,150),Image.BILINEAR)
12         return new_img
13     except Exception as e:
14         print(e)
15 snames=[os.path.join(test_vegetable_data,sname)for sname in os.listdir(test_vegetable_data)]
16 j=0
17 for i in snames[0:8] :
18     j+=1
19     img_show=convertjpg(i)
20     img_scale = image.img_to_array(img_show)
21     img_scale = img_scale.reshape(1,150,150,3) # 將形狀轉化為(1,150,150,3)
22     img_scale = img_scale.astype('float32')/255
23     result = model.predict(img_scale)# 預測函數-
24     if result>0.5:
25         title = '蔬菜'
26         label = '正確識別率為:'+str(result)
27     else:
28         title = '水果'
29         label = '正確識別率為:'+str(1-result)
30          
31     ax = ax.flatten()   # 將子圖從多維變成一維
32     ax[j-1].imshow(img_show, cmap='Greys', interpolation='nearest')
33      # 子圖標題
34     ax[j-1].set_title(title,fontsize=24)
35      # 子圖X軸標簽
36     ax[j-1].set_xlabel(label,fontsize=24)
37      # 去掉刻度
38     ax[0].set_xticks([])
39     ax[0].set_yticks([]) 
40 plt.show()
41 
42 figure,ax = plt.subplots(nrows=2, ncols=4, sharex=True, sharey=True,figsize=(24,10))
43 
44 fnames=[os.path.join(test_fruit_data,fname)for fname in os.listdir(test_fruit_data)]
45 j=0
46 for i in fnames[0:8]: 
47     j+=1
48     img_show=convertjpg(i)
49     img_scale = image.img_to_array(img_show)
50     img_scale = img_scale.reshape(1,150,150,3) # 將形狀轉化為(1,150,150,3)
51     img_scale = img_scale.astype('float32')/255
52     result = model.predict(img_scale)# 預測函數-
53     if result>0.5:
54         title = '蔬菜'
55         label = '正確識別率為:'+ str(result)
56     else:
57         title = '水果'
58         label = '正確識別率為:'+str(1-result)         
59     ax = ax.flatten()   # 將子圖從多維變成一維
60     ax[j-1].imshow(img_show, cmap='Greys', interpolation='nearest')
61      # 子圖標題
62     ax[j-1].set_title(title,fontsize=24)
63      # 子圖X軸標簽
64     ax[j-1].set_xlabel(label,fontsize=24)
65     # 去掉刻度
66     ax[0].set_xticks([])
67     ax[0].set_yticks([])

 全代碼附上

  1 import os
  2 
  3 import shutil
  4 
  5 #訓練集數據處理
  6 def train(file_path):
  7     d=[]
  8     s=[]
  9     for root, dirs , files in os.walk(file_path): #讀取文件並提取出文件路徑和類名    
 10         d.append(root)#文件路徑
 11         s.append(dirs)#類名
 12         for i in s:
 13             if i!=s[0]:
 14                 s.remove(i)
 15         b = [ i for item in s for i in item]        
 16     d.pop(0)
 17     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
 18     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
 19                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
 20                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
 21                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
 22     #用for循環對水果和蔬菜進行分類
 23     #訓練集數據處理
 24     #水果
 25     for i in b:
 26         for j in fruit:
 27             if i==j:
 28                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/train",i),
 29                             "C:/Users/linyicheng/Desktop/fruit/train")
 30     #蔬菜
 31     for i in b:
 32         for j in vegetables:
 33             if i==j:
 34                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/train",i),
 35                             "C:/Users/linyicheng/Desktop/vegetable/train")
 36 
 37 train("C:/Users/linyicheng/Desktop/train")
 38 #驗證集數據處理
 39 def validation(file_path):
 40     d=[]
 41     s=[]
 42     for root, dirs , files in os.walk(file_path):     
 43         d.append(root)
 44         s.append(dirs)
 45         for i in s:
 46             if i!=s[0]:
 47                 s.remove(i)
 48         b = [ i for item in s for i in item]        
 49     d.pop(0)
 50     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
 51     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
 52                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
 53                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
 54                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
 55     #訓練集數據處理
 56     #水果
 57     for i in b:
 58         for j in fruit:
 59             if i==j:
 60                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/validation",i),
 61                             "C:/Users/linyicheng/Desktop/fruit/validation")
 62     #蔬菜
 63     for i in b:
 64         for j in vegetables:
 65             if i==j:
 66                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/validation",i),
 67                             "C:/Users/linyicheng/Desktop/vegetable/validation")
 68 
 69 validation("C:/Users/linyicheng/Desktop/validation")
 70 #測試集數據處理
 71 def test(file_path):
 72     d=[]
 73     s=[]
 74     for root, dirs , files in os.walk(file_path):     
 75         d.append(root)
 76         s.append(dirs)
 77         for i in s:
 78             if i!=s[0]:
 79                 s.remove(i)
 80         b = [ i for item in s for i in item]        
 81     d.pop(0)
 82     fruit=[ 'banana', 'apple', 'pear', 'grapes', 'orange','kiwi','watermelon', 'pomegranate', 'pineapple', 'mango']
 83     vegetables=['cucumber', 'carrot', 'capsicum', 'onion', 'potato', 'lemon', 'tomato', 
 84                 'raddish', 'beetroot', 'cabbage', 'lettuce', 'spinach', 'soy beans', 
 85                 'cauliflower', 'bell pepper', 'chilli pepper', 'turnip', 'corn', 'sweetcorn',
 86                 'sweetpotato', 'paprika', 'jalepeno', 'ginger', 'garlic', 'peas', 'eggplant']
 87     #訓練集數據處理
 88     #水果
 89     for i in b:
 90         for j in fruit:
 91             if i==j:
 92                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/test",i),
 93                             "C:/Users/linyicheng/Desktop/fruit/test")
 94     #蔬菜
 95     for i in b:
 96         for j in vegetables:
 97             if i==j:
 98                 shutil.move(os.path.join("C:/Users/linyicheng/Desktop/test",i),
 99                             "C:/Users/linyicheng/Desktop/vegetable/test")
100 
101 test("C:/Users/linyicheng/Desktop/test")
102 #水果
103 outer_path ="C:/Users/linyicheng/Desktop/fruit/test"
104 folderlist = os.listdir(outer_path)          #列舉文件夾
105  
106 for folder in folderlist:     
107     inner_path = os.path.join(outer_path, folder)
108     total_num_folder = len(folderlist)       #文件夾的總數
109        #打印文件夾的總數
110     filelist = os.listdir(inner_path)        #列舉圖片
111     i = 0
112     for item in filelist:
113         total_num_file = len(filelist)       #單個文件夾內圖片的總數
114         if item.endswith('.jpg'):
115             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
116             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
117             try:
118                 os.rename(src, dst)        
119                 i += 1
120             except:
121                 continue
122 outer_path ="C:/Users/linyicheng/Desktop/fruit/train"
123 folderlist = os.listdir(outer_path)          #列舉文件夾
124  
125 for folder in folderlist:     
126     inner_path = os.path.join(outer_path, folder)
127     total_num_folder = len(folderlist)       #文件夾的總數
128        #打印文件夾的總數
129  
130     filelist = os.listdir(inner_path)        #列舉圖片
131     i = 0
132     for item in filelist:
133         total_num_file = len(filelist)       #單個文件夾內圖片的總數
134         if item.endswith('.jpg'):
135             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
136             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
137             try:
138                 os.rename(src, dst)
139                 
140                 i += 1
141             except:
142                 continue
143 outer_path ="C:/Users/linyicheng/Desktop/fruit/validation"
144 folderlist = os.listdir(outer_path)          #列舉文件夾
145  
146 for folder in folderlist:     
147     inner_path = os.path.join(outer_path, folder)
148     total_num_folder = len(folderlist)       #文件夾的總數
149        #打印文件夾的總數
150  
151     filelist = os.listdir(inner_path)        #列舉圖片
152     i = 0
153     for item in filelist:
154         total_num_file = len(filelist)       #單個文件夾內圖片的總數
155         if item.endswith('.jpg'):
156             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
157             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
158             try:
159                 os.rename(src, dst)
160                 
161                 i += 1
162             except:
163                 continue
164 #蔬菜
165 outer_path ="C:/Users/linyicheng/Desktop/vegetable/test"
166 folderlist = os.listdir(outer_path)          #列舉文件夾
167  
168 for folder in folderlist:     
169     inner_path = os.path.join(outer_path, folder)
170     total_num_folder = len(folderlist)       #文件夾的總數
171        #打印文件夾的總數
172     filelist = os.listdir(inner_path)        #列舉圖片
173     i = 0
174     for item in filelist:
175         total_num_file = len(filelist)       #單個文件夾內圖片的總數
176         if item.endswith('.jpg'):
177             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
178             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
179             try:
180                 os.rename(src, dst)        
181                 i += 1
182             except:
183                 continue
184 outer_path ="C:/Users/linyicheng/Desktop/vegetable/train"
185 folderlist = os.listdir(outer_path)          #列舉文件夾
186  
187 for folder in folderlist:     
188     inner_path = os.path.join(outer_path, folder)
189     total_num_folder = len(folderlist)       #文件夾的總數
190        #打印文件夾的總數
191  
192     filelist = os.listdir(inner_path)        #列舉圖片
193     i = 0
194     for item in filelist:
195         total_num_file = len(filelist)       #單個文件夾內圖片的總數
196         if item.endswith('.jpg'):
197             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
198             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
199             try:
200                 os.rename(src, dst)
201                 
202                 i += 1
203             except:
204                 continue
205 outer_path ="C:/Users/linyicheng/Desktop/vegetable/validation"
206 folderlist = os.listdir(outer_path)          #列舉文件夾
207  
208 for folder in folderlist:     
209     inner_path = os.path.join(outer_path, folder)
210     total_num_folder = len(folderlist)       #文件夾的總數
211        #打印文件夾的總數
212  
213     filelist = os.listdir(inner_path)        #列舉圖片
214     i = 0
215     for item in filelist:
216         total_num_file = len(filelist)       #單個文件夾內圖片的總數
217         if item.endswith('.jpg'):
218             src = os.path.join(os.path.abspath(inner_path), item)           #原圖的地址
219             dst = os.path.join(os.path.abspath(inner_path), str(folder) + '_' + str(i) + '.jpg')        #新圖的地址(這里可以把str(folder) + '_' + str(i) + '.jpg'改成你想改的名稱)
220             try:
221                 os.rename(src, dst)
222                 
223                 i += 1
224             except:
225                 continue
226 #目標文件夾,此處為相對路徑,也可以改為絕對路徑
227 import shutil
228 determination = "C:/Users/linyicheng/Desktop/base/test/fruit"#目標
229 if not os.path.exists(determination):
230     os.makedirs(determination)
231 
232 #源文件夾路徑
233 path = "C:/Users/linyicheng/Desktop/fruit/test"
234 folders = os.listdir(path)
235 for folder in folders:
236     dir = path + '/' + str(folder)
237     files = os.listdir(dir)
238     for file in files:
239         source = dir + '/' + str(file)
240         deter = determination + '/' + str(file)
241         shutil.copyfile(source, deter)
242 determination = "C:/Users/linyicheng/Desktop/base/train/fruit"
243 if not os.path.exists(determination):
244     os.makedirs(determination)
245 path = "C:/Users/linyicheng/Desktop/fruit/train"
246 folders = os.listdir(path)
247 for folder in folders:
248     dir = path + '/' + str(folder)
249     files = os.listdir(dir)
250     for file in files:
251         source = dir + '/' + str(file)
252         deter = determination + '/' + str(file)
253         shutil.copyfile(source, deter)
254 determination = "C:/Users/linyicheng/Desktop/base/validation/fruit"
255 if not os.path.exists(determination):
256     os.makedirs(determination)
257 path = "C:/Users/linyicheng/Desktop/fruit/validation"
258 folders = os.listdir(path)
259 for folder in folders:
260     dir = path + '/' + str(folder)
261     files = os.listdir(dir)
262     for file in files:
263         source = dir + '/' + str(file)
264         deter = determination + '/' + str(file)
265         shutil.copyfile(source, deter)
266 import shutil
267 determination = "C:/Users/linyicheng/Desktop/base/test/vegetable"#目標
268 if not os.path.exists(determination):
269     os.makedirs(determination)
270 
271 #源文件夾路徑
272 path = "C:/Users/linyicheng/Desktop/vegetable/test"
273 folders = os.listdir(path)
274 for folder in folders:
275     dir = path + '/' + str(folder)
276     files = os.listdir(dir)
277     for file in files:
278         source = dir + '/' + str(file)
279         deter = determination + '/' + str(file)
280         shutil.copyfile(source, deter)
281 determination = "C:/Users/linyicheng/Desktop/base/train/vegetable"
282 if not os.path.exists(determination):
283     os.makedirs(determination)
284 path = "C:/Users/linyicheng/Desktop/vegetable/train"
285 folders = os.listdir(path)
286 for folder in folders:
287     dir = path + '/' + str(folder)
288     files = os.listdir(dir)
289     for file in files:
290         source = dir + '/' + str(file)
291         deter = determination + '/' + str(file)
292         shutil.copyfile(source, deter)
293 determination = "C:/Users/linyicheng/Desktop/base/validation/vegetable"
294 if not os.path.exists(determination):
295     os.makedirs(determination)
296 path = "C:/Users/linyicheng/Desktop/vegetable/validation"
297 folders = os.listdir(path)
298 for folder in folders:
299     dir = path + '/' + str(folder)
300     files = os.listdir(dir)
301     for file in files:
302         source = dir + '/' + str(file)
303         deter = determination + '/' + str(file)
304         shutil.copyfile(source, deter)
305 
306 base_dir="C:/Users/linyicheng/Desktop/base/"
307 train_data_dir="C:/Users/linyicheng/Desktop/base/train/"
308 test_data_dir="C:/Users/linyicheng/Desktop/base/test/"
309 val_data_dir="C:/Users/linyicheng/Desktop/base/validation/"
310 train_fruit_data="C:/Users/linyicheng/Desktop/base/train/fruit/"
311 test_fruit_data="C:/Users/linyicheng/Desktop/base/test/fruit/"
312 test_vegetable_data="C:/Users/linyicheng/Desktop/base/test/vegetable/"
313 
314 #搭建卷積神經網絡
315 from keras import layers
316 from keras import models
317 model=models.Sequential()
318 """
319 Output shape計算公式:(輸入尺寸-卷積核尺寸/步長+1
320 對CNN模型,Param的計算方法如下:
321 卷積核長度*卷積核寬度*通道數+1)*卷積核個數
322 輸出圖片尺寸:150-3+1=148*148
323 參數數量:32*3*3*3+32=896
324 """
325 model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))#卷積層1
326 model.add(layers.MaxPooling2D(2,2))#最大池化層1
327 # 輸出圖片尺寸:148/2=74*74 
328 # 輸出圖片尺寸:74-3+1=72*72,參數數量:64*3*3*32+64=18496
329 #32是第1個卷積層的輸出的通道數
330 model.add(layers.Conv2D(64, (3, 3), activation='relu'))#卷積層2
331 model.add(layers.MaxPooling2D((2, 2)))#最大池化層2
332 # 輸出圖片尺寸:72/2=36*36
333  
334 #Output Shape的輸出為36
335 # 輸出圖片尺寸:36-3+1=34*34,參數數量:128*3*3*64+128=73856
336 model.add(layers.Conv2D(128, (3, 3), activation='relu'))#卷積層3
337 model.add(layers.MaxPooling2D((2, 2)))#最大池化層3
338 # 輸出圖片尺寸:34/2=17*17
339 # 輸出圖片尺寸:17-3+1=15*15,參數數量:128*3*3*128+128=147584
340 model.add(layers.Conv2D(128, (3, 3), activation='relu'))# 輸出圖片尺寸:15/2=7*7
341 model.add(layers.MaxPooling2D((2, 2)))
342 model.add(layers.Flatten())
343 model.add(layers.Dense(512, activation='relu'))   #全連接層1
344 model.add(layers.Dense(1, activation='sigmoid'))#全連接層2,作為輸出層
345 model.summary()
346 
347 from keras import optimizers
348 model.compile(loss='binary_crossentropy',
349               optimizer=optimizers.RMSprop(lr=1e-4),
350                metrics=['acc'])
351 
352 from keras.preprocessing.image import ImageDataGenerator
353 #歸一化
354 
355 train_datagen = ImageDataGenerator(rescale=1./255)
356 validation_datagen=ImageDataGenerator(rescale=1./255)
357 test_datagen = ImageDataGenerator(rescale=1./255)
358 # 數據集加載函數,指明數據集的位置並統一處理為imgheight*imgwidth的大小,同時設置batch
359     # 加載訓練集
360 train_ds = train_datagen.flow_from_directory (
361         train_data_dir,
362         class_mode='binary',
363         target_size=(150, 150),
364         batch_size=20)
365     #加載測試集
366 test_ds = test_datagen.flow_from_directory(
367         test_data_dir,
368         class_mode='binary',
369         target_size=(150, 150),
370         batch_size=20)
371     # 加載驗證集
372 val_ds =test_datagen.flow_from_directory(
373         val_data_dir,
374         class_mode='binary',
375         target_size=(150, 150),
376         batch_size=20)
377 
378 for data_batch, labels_batch in train_ds:
379     print('data batch shape:', data_batch.shape)
380     print('labels batch shape:', labels_batch.shape)
381     break
382 
383 #訓練模型30輪次,可以修改epochs的值
384 history = model.fit_generator(
385        train_ds,
386        steps_per_epoch=100,
387        epochs=30,
388        validation_data=val_ds,
389        validation_steps=50)
390 
391  #將訓練過程產生的數據保存為h5文件
392 model.save('fruit_and_vegetable_30epoch.h5')
393 
394 import matplotlib.pyplot as plt
395  
396 acc = history.history['acc']
397 val_acc = history.history['val_acc']
398 loss = history.history['loss']
399 val_loss = history.history['val_loss']
400 
401 epochs = range(1, len(acc) + 1)
402 
403 plt.plot(epochs, acc, 'bo', label='Training acc')
404 plt.plot(epochs, val_acc, 'b', label='Validation acc')
405 plt.title('Training and validation accuracy')
406 plt.legend()
407 plt.figure() 
408 plt.plot(epochs, loss, 'bo', label='Training loss')
409 plt.plot(epochs, val_loss, 'b', label='Validation loss')
410 plt.title('Training and validation loss')
411 plt.legend()
412  
413 plt.show()
414 
415 from PIL import Image
416 from keras.preprocessing import image
417 from keras.models import load_model
418 import numpy as np
419 #加載模型
420 model=load_model('fruit_and_vegetable_30epoch.h5')
421 #本地圖片路徑
422 img_path=("C:/Users/linyicheng/Desktop/base/train/fruit/apple_41.jpg")
423 img = image.load_img(img_path,target_size=(150,150))
424 # 將其轉換為具有形狀的Numpy數組(150、150、3)
425 img_tensor = image.img_to_array(img)/255
426 # 將其形態變為(150,150,150,3)的形狀
427 img_tensor = np.expand_dims(img_tensor, axis=0)
428 #取圖片信息
429 prediction =model.predict(img_tensor)
430 #輸出識別率
431 print(prediction)
432 if prediction>0.5:
433     print('水果')
434 else:
435     print('蔬菜')
436 plt.imshow(img)
437 
438 from keras.preprocessing.image import ImageDataGenerator
439 from keras.models import load_model
440 from tensorflow.python.keras.preprocessing import image
441 from tensorflow.python.keras.preprocessing.image import ImageDataGenerator,array_to_img,img_to_array,load_img
442 
443 import os
444 from keras.preprocessing.image import load_img
445 import matplotlib.pyplot as plt
446 figure,ax = plt.subplots(nrows=1, ncols=4, sharex=True, 
447                          sharey=True,figsize=(16,10))
448 
449 datagen=ImageDataGenerator(
450     rotation_range=40,      #圖像隨機旋轉角度范圍
451     width_shift_range=0.2,  #圖片在水平方向上平移的比例
452     height_shift_range=0.2, #圖片在垂直方向上平移的比例
453     shear_range=0.2,        #隨機錯切變換的角度
454     zoom_range=0.2,         #圖像隨機縮放的范圍
455     horizontal_flip=True,   #隨機將一半圖像水平翻轉
456       
457     fill_mode='nearest')
458 #填充創建像素的一種方法
459 fnames=[os.path.join(train_fruit_data,fname)for fname in os.listdir(train_fruit_data)]
460 img_path=fnames[6]
461 img=image.load_img(img_path,target_size=(150,150))
462 x = image.img_to_array(img)/255
463 x = x.reshape((1,) + x.shape)
464 i = 0
465 for batch in datagen.flow(x, batch_size=1):
466     ax = ax.flatten()   # 將子圖從多維變成一維
467     plt.figure(i)
468     imgplot = ax[i-1].imshow(image.array_to_img(batch[0]), cmap='Greys', interpolation='nearest')
469     i += 1
470     if i % 4 == 0:
471         break
472 plt.show() #繪制增強后的圖像
473 '''
474 雖然使用了數據增強技術,但是從輸出的圖像來看,圖片之間還是有很大的相似度,
475 因為它們均來自同一張原始圖片,並沒有提供新的信息。
476 為了盡可能消除過擬合,可以在模型中增加一個DDropout層,添加到密集連接分類
477 器前
478 '''
479 #在緊密連接的分類器之前為模型添加一個Dropout層
480 model = models.Sequential()
481 model.add(layers.Conv2D(32, (3, 3), activation='relu',
482                         input_shape=(150, 150, 3)))
483 model.add(layers.MaxPooling2D((2, 2)))
484 model.add(layers.Conv2D(64, (3, 3), activation='relu'))
485 model.add(layers.MaxPooling2D((2, 2)))
486 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
487 model.add(layers.MaxPooling2D((2, 2)))
488 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
489 model.add(layers.MaxPooling2D((2, 2)))
490 model.add(layers.Flatten())
491 model.add(layers.Dropout(0.5))
492 model.add(layers.Dense(512, activation='relu'))
493 model.add(layers.Dense(1, activation='sigmoid'))
494 
495 from keras import optimizers
496 model.compile(loss='binary_crossentropy',
497               optimizer=optimizers.RMSprop(lr=1e-4),
498                metrics=['acc'])
499 
500 #使用數據增強和dropout來訓練我們的網絡
501 #歸一化
502 train_datagen = ImageDataGenerator(
503      rescale=1./255,
504      rotation_range=40,
505      width_shift_range=0.2,
506      height_shift_range=0.2,
507      shear_range=0.2,
508      zoom_range=0.2,
509      horizontal_flip=True)
510 test_datagen = ImageDataGenerator(rescale=1./255)
511 train_generator = train_datagen.flow_from_directory(
512      train_data_dir,
513      #輸入訓練圖像尺寸,所有圖片的size必須是150x150
514      target_size=(150, 150),
515      batch_size=32,
516      #因為我們使用二元交叉熵損失,我們需要二元標簽
517      class_mode='binary')
518 validation_generator = test_datagen.flow_from_directory(
519      val_data_dir,
520      target_size=(150, 150),
521      batch_size=32,
522      class_mode='binary')
523 
524 history = model.fit_generator(
525        train_generator,
526        steps_per_epoch=100,
527        epochs=100,
528        validation_data=validation_generator,
529        validation_steps=50)
530 
531 model.save('fruit_and_vegetable_100epoch.h5')
532 
533 import matplotlib.pyplot as plt
534  
535 acc = history.history['acc']
536 val_acc = history.history['val_acc']
537 loss = history.history['loss']
538 val_loss = history.history['val_loss']
539 
540 epochs = range(1, len(acc) + 1)
541 
542 plt.plot(epochs, acc, 'bo', label='Training acc')
543 plt.plot(epochs, val_acc, 'b', label='Validation acc')
544 plt.title('Training and validation accuracy')
545 plt.legend()
546 plt.figure() 
547 plt.plot(epochs, loss, 'bo', label='Training loss')
548 plt.plot(epochs, val_loss, 'b', label='Validation loss')
549 plt.title('Training and validation loss')
550 plt.legend()
551  
552 plt.show()
553 
554 from keras.preprocessing import image
555 
556 from keras.models import load_model
557 import numpy as np
558 #加載模型
559 model=load_model('fruit_and_vegetable_100epoch.h5')
560 #本地圖片路徑
561 img_path=("C:/Users/linyicheng/Desktop/base/train/fruit/apple_42.jpg")
562 img = image.load_img(img_path,target_size=(150,150))
563 # 將其轉換為具有形狀的Numpy數組(150、150、3)
564 img_tensor = image.img_to_array(img)/255
565 # 將其形態變為(150,150,150,3)的形狀
566 img_tensor = np.expand_dims(img_tensor, axis=0)
567 #取圖片信息
568 prediction =model.predict(img_tensor)
569 #輸出識別率
570 print(prediction)
571 if prediction>0.5:
572     print('水果')
573 else:
574     print('蔬菜')
575 plt.imshow(img)
576 
577 from PIL import Image
578 from keras.preprocessing import image
579 import matplotlib.pyplot as plt
580 from keras.models import load_model
581 plt.rcParams['font.family'] = ['SimHei']
582 figure,ax = plt.subplots(nrows=2, ncols=4, sharex=True, sharey=True,figsize=(24,10))
583 def convertjpg(jpgfile):
584     #將圖片縮小到(150,150)的大小
585     img=Image.open(jpgfile)
586     try:
587         new_img=img.resize((150,150),Image.BILINEAR)
588         return new_img
589     except Exception as e:
590         print(e)
591 snames=[os.path.join(test_vegetable_data,sname)for sname in os.listdir(test_vegetable_data)]
592 j=0
593 for i in snames[0:8] :
594     j+=1
595     img_show=convertjpg(i)
596     img_scale = image.img_to_array(img_show)
597     img_scale = img_scale.reshape(1,150,150,3) # 將形狀轉化為(1,150,150,3)
598     img_scale = img_scale.astype('float32')/255
599     result = model.predict(img_scale)# 預測函數-
600     if result>0.5:
601         title = '蔬菜'
602         label = '正確識別率為:'+str(result)
603     else:
604         title = '水果'
605         label = '正確識別率為:'+str(1-result)
606          
607     ax = ax.flatten()   # 將子圖從多維變成一維
608     ax[j-1].imshow(img_show, cmap='Greys', interpolation='nearest')
609      # 子圖標題
610     ax[j-1].set_title(title,fontsize=24)
611      # 子圖X軸標簽
612     ax[j-1].set_xlabel(label,fontsize=24)
613      # 去掉刻度
614     ax[0].set_xticks([])
615     ax[0].set_yticks([]) 
616 plt.show()
617 
618 figure,ax = plt.subplots(nrows=2, ncols=4, sharex=True, sharey=True,figsize=(24,10))
619 
620 fnames=[os.path.join(test_fruit_data,fname)for fname in os.listdir(test_fruit_data)]
621 j=0
622 for i in fnames[0:8]: 
623     j+=1
624     img_show=convertjpg(i)
625     img_scale = image.img_to_array(img_show)
626     img_scale = img_scale.reshape(1,150,150,3) # 將形狀轉化為(1,150,150,3)
627     img_scale = img_scale.astype('float32')/255
628     result = model.predict(img_scale)# 預測函數-
629     if result>0.5:
630         title = '蔬菜'
631         label = '正確識別率為:'+ str(result)
632     else:
633         title = '水果'
634         label = '正確識別率為:'+str(1-result)         
635     ax = ax.flatten()   # 將子圖從多維變成一維
636     ax[j-1].imshow(img_show, cmap='Greys', interpolation='nearest')
637      # 子圖標題
638     ax[j-1].set_title(title,fontsize=24)
639      # 子圖X軸標簽
640     ax[j-1].set_xlabel(label,fontsize=24)
641     # 去掉刻度
642     ax[0].set_xticks([])
643     ax[0].set_yticks([])

四、總結

此次機器學習過程中參考了minist案例和貓狗識別案例,在數據處理構建數據集目錄是出現一些問題,開始思路沒有構建好,導致數據處理花費太多時間,以及代碼太過冗長,還有就是在導入一些必要的數據庫是出現問題如PIL,在網上查明原因說需要更新pillow和PIL的版本,后續應多加練習熟悉所需的各種環境。

這次機器學習中,無論是第一次訓練模型還是增強后的模型訓練都達到了預期的效果,但是在進行機器學習設計的過程中發現自己對程序設計的思路沒有理清楚,導致花費了大量時間改正,以后在進行類似學習前應當將思路理清,再付諸行動。


免責聲明!

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



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