一、選題背景
在學習了深度學習案例——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的版本,后續應多加練習熟悉所需的各種環境。
這次機器學習中,無論是第一次訓練模型還是增強后的模型訓練都達到了預期的效果,但是在進行機器學習設計的過程中發現自己對程序設計的思路沒有理清楚,導致花費了大量時間改正,以后在進行類似學習前應當將思路理清,再付諸行動。
