機器學習——人臉性別識別

2022-12-21 15:00:28

一、選題背景

        臉部辨識技術是圖形識別和計算機視覺領域最富挑戰性的研究課題之一,也是近年來的研究熱點,人臉性別識別作為臉部辨識技術的重要組成部分也受到了廣泛地關注。人臉性別識別就是向計算機輸入人臉影象,經過某種方法或運算,得出其性別。這種識別對人眼來說很簡單,但對計算機卻並不是一件容易的事情。

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

        從網站中下載相關的資料集,對資料集進行整理,在python的環境中,給資料集中的檔案進行劃分,對資料進行預處理,利用keras,構建神經網路,訓練模型,匯入圖片測試模型。       

資料來源:kaggle,網址:https://www.kaggle.com/maciejgronczynski/biggest-genderface-recognition-dataset

        資料集包含27167個jpg檔案,其中17678個是男性面部照片,9489個是女性照片。

三、機器學習的實驗步驟

1.下載資料集

 

2.匯入需要用到的庫

 1 import os
 2 import random
 3 from shutil import copy
 4 from matplotlib import pyplot as plt
 5 from keras import optimizers
 6 from keras import models
 7 from keras import layers
 8 from keras.preprocessing.image import ImageDataGenerator
 9 from keras.models import load_model
10 from PIL import Image

3.資料集劃分,由總的資料集生成分別生成訓練集,測試集和驗證集

 1 # 女性圖片訓練集想儲存到的根路徑
 2 woman_train_dir = r'sex\faces\train\woman'
 3 # 女性圖片驗證集想儲存到的根路徑
 4 woman_validation_dir = r'sex\faces\validation\woman'
 5 # 女性圖片測試集想儲存到的根路徑
 6 woman_test_dir = r'sex\faces\test\woman'
 7 
 8 # 男性圖片訓練集想儲存到的根路徑
 9 man_train_dir = r'sex\faces\train\man'
10 # 男性圖片驗證集想儲存到的根路徑
11 man_validation_dir = r'sex\faces\validation\man'
12 # 男性圖片測試集想儲存到的根路徑
13 man_test_dir = r'sex\faces\test\man'
14 
15 # 建立列表,儲存上方6個路徑
16 dir_list = [woman_train_dir, woman_validation_dir, woman_test_dir,
17             man_train_dir, man_validation_dir, man_test_dir]
18 # 如果目錄不存在,則建立
19 for dir_child in dir_list:
20     if not os.path.isdir(dir_child):
21         os.makedirs(dir_child)
22 
23 # 女性圖片根路徑
24 woman_path = r'sex\faces\woman'
25 # 獲取 woman_path 下的資料夾列表
26 woman_path_list = os.listdir(woman_path)
27 # 遍歷列表,取6000張圖片加入訓練集,3000張圖片加入驗證集,其餘加入測試集
28 for i in range(len(woman_path_list)):
29     child_path = os.path.join(woman_path, woman_path_list[i])
30     if i < 6000:
31         to_path = woman_train_dir
32     elif i < 9000:
33         to_path = woman_validation_dir
34     else:
35         to_path = woman_test_dir
36     copy(child_path, to_path)
37 
38 # 男性圖片根路徑
39 man_path = r'sex\faces\man'
40 # 獲取 man_path 下的資料夾列表
41 man_path_list = os.listdir(man_path)
42 # 遍歷列表,取6000張圖片加入訓練集,3000張圖片加入驗證集,其餘加入測試集
43 for i in range(len(man_path_list)):
44     child_path = os.path.join(man_path, man_path_list[i])
45     if i < 6000:
46         to_path = man_train_dir
47     elif i < 9000:
48         to_path = man_validation_dir
49     else:
50         to_path = man_test_dir
51     copy(child_path, to_path)
52 
53 # 輸出各目錄中的檔案數目
54 train_path = "sex/faces/train/"
55 print('total training woman images:', len(os.listdir(train_path+"woman")))
56 print('total training man images:', len(os.listdir(train_path+"man")))
57 
58 valid_path = "sex/faces/validation/"
59 print('total validation woman images:', len(os.listdir(valid_path+"woman")))
60 print('total validation man images:', len(os.listdir(valid_path+"man")))
61 
62 test_path = "sex/faces/test/"
63 print('total test woman images:', len(os.listdir(test_path+"woman")))
64 print('total test man images:', len(os.listdir(test_path+"man")))

4.檢視影象以及對應標籤

 1 # 檢視影象以及對應的標籤
 2 fit, ax = plt.subplots(nrows=3, ncols=3, figsize=(10, 7))
 3 # 檢視影象的根路徑
 4 test_view_path = r'sex\faces\test\man'
 5 # 獲取 test_view_path 下的資料夾列表
 6 test_view_list = os.listdir(test_view_path)
 7 for i, a in enumerate(ax.flat):
 8     view_path = os.path.join(test_view_path, test_view_list[i])
 9     # 讀取源圖
10     a.imshow(plt.imread(view_path))
11     # 新增影象名稱
12     a.set_title(man_path_list[i])
13 plt.tight_layout()  # 自動調整子圖引數,使之填充整個影象區域
14 plt.show()

5.圖片預處理

 1 # 圖片預處理
 2 # 批次大小
 3 BATCH_SIZE = 20
 4 # 輸入圖片的大小
 5 IMG_SIZE = (150, 150)
 6 
 7 # 歸一化處理
 8 train_datagen = ImageDataGenerator(rescale=1./255)
 9 validation_datagen = ImageDataGenerator(rescale=1./255)
10 test_datagen = ImageDataGenerator(rescale=1./255)
11 
12 train_dir = 'sex/faces/train'     # 指向訓練集圖片目錄路徑
13 
14 train_generator = train_datagen.flow_from_directory(
15     train_dir,
16     target_size=IMG_SIZE,  # 輸入訓練影象尺寸
17     batch_size=BATCH_SIZE,
18     color_mode='rgb',
19     class_mode='binary')
20 
21 validation_dir = 'sex/faces/validation'  # 指向驗證集圖片目錄路徑
22 
23 validation_generator = validation_datagen.flow_from_directory(
24     validation_dir,
25     target_size=IMG_SIZE,
26     batch_size=BATCH_SIZE,
27     color_mode='rgb',
28     class_mode='binary')
29 
30 test_dir = 'sex/faces/test'  # 指向測試集圖片目錄路徑
31 
32 test_generator = test_datagen.flow_from_directory(
33     test_dir,
34     target_size=IMG_SIZE,
35     batch_size=BATCH_SIZE,
36     color_mode='rgb',
37     class_mode='binary')

6.檢視經過處理的圖片以及它的binary標籤

 1 # 檢視經過處理的圖片以及它的binary標籤
 2 fit, ax = plt.subplots(nrows=3, ncols=3, figsize=(10, 7))
 3 
 4 for i, a in enumerate(ax.flat):
 5     img, label = test_generator.next()
 6     a.imshow(img[0],)
 7     a.set_title(label[0])
 8 
 9 plt.tight_layout()
10 plt.show()

7.構建神經網路並對模型進行訓練

 1 # 構建神經網路
 2 model = models.Sequential()
 3 
 4 # 1.Conv2D層,32個過濾器。輸出圖片尺寸:150-3+1=148*148,引數數量:32*3*3*3+32=896
 5 model.add(layers.Conv2D(32, (3, 3),
 6                         activation='relu',
 7                         input_shape=(150, 150, 3)))  # 折積層1
 8 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層1。輸出圖片尺寸:148/2=74*74
 9 
10 # 2.Conv2D層,64個過濾器。輸出圖片尺寸:74-3+1=72*72,引數數量:64*3*3*32+64=18496
11 model.add(layers.Conv2D(64, (3, 3),
12                         activation='relu'))  # 折積層2
13 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層2。輸出圖片尺寸:72/2=36*36
14 
15 # 3.Conv2D層,128個過濾器。輸出圖片尺寸:36-3+1=34*34,引數數量:128*3*3*64+128=73856
16 model.add(layers.Conv2D(128, (3, 3),
17                         activation='relu'))  # 折積層3
18 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層3。輸出圖片尺寸:34/2=17*17
19 
20 # 4.Conv2D層,128個過濾器。輸出圖片尺寸:17-3+1=15*15,引數數量:128*3*3*128+128=147584
21 model.add(layers.Conv2D(128, (3, 3),
22                         activation='relu'))  # 折積層4
23 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層4。輸出圖片尺寸:15/2=7*7
24 
25 # 將輸入層的資料壓縮成1維資料,全連線層只能處理一維資料
26 model.add(layers.Flatten())
27 
28 # 全連線層
29 model.add(layers.Dense(512,
30                        activation='relu'))  # 全連線層1
31 model.add(layers.Dense(1,
32                        activation='sigmoid'))  # 全連線層2,作為輸出層。sigmoid分類,輸出是兩類別
33 
34 # 編譯模型
35 # RMSprop 優化器。因為網路最後一層是單一sigmoid單元,
36 # 所以使用二元交叉熵作為損失函數
37 model.compile(loss='binary_crossentropy',
38               optimizer=optimizers.RMSprop(lr=1e-4),
39               metrics=['acc'])
40 
41 # 看一下特徵圖的維度如何隨著每層變化
42 model.summary()


 

1 # 訓練模型50輪次
2 history_save = model.fit(
3                     train_generator,
4                     steps_per_epoch=100,
5                     epochs=50,
6                     validation_data=validation_generator,
7                     validation_steps=50)
8 # 將訓練過程產生的資料儲存為h5檔案
9 model.save('sex/faces/sex_model.h5')

8.繪製損失曲線和精度曲線圖

 1 # 繪製損失曲線和精度曲線圖
 2 accuracy = history_save.history['acc']  # 訓練集精度
 3 loss = history_save.history['loss']  # 訓練集損失
 4 val_loss = history_save.history['val_loss']  # 驗證集精度
 5 val_accuracy = history_save.history['val_acc']  # 驗證集損失
 6 plt.figure(figsize=(17, 7))
 7 
 8 # 訓練集精度和驗證集精度曲線圖圖
 9 plt.subplot(2, 2, 1)
10 plt.plot(range(50), accuracy, 'bo', label='Training Accuracy')
11 plt.plot(range(50), val_accuracy, label='Validation Accuracy')
12 plt.title('Training and Validation Accuracy')
13 plt.legend(loc='center right')
14 
15 # 訓練集損失和驗證集損失圖
16 plt.subplot(2, 2, 2)
17 plt.plot(range(50), loss, 'bo', label='Training Loss')
18 plt.plot(range(50), val_loss, label='Validation Loss')
19 plt.title('Training and Validation Loss')
20 plt.legend(loc='center right')
21 
22 # 訓練集精度和損失散點圖
23 plt.subplot(2, 2, 3)
24 plt.scatter(range(50), accuracy, label="Training Accuracy", color='b', s=25, marker="o")
25 plt.scatter(range(50), loss, label="Training Loss", color='r', s=25, marker="o")
26 plt.title('Training : Accuracy and Loss')
27 plt.legend(loc='center right')
28 
29 # 驗證集精度和損失散點圖
30 plt.subplot(2, 2, 4)
31 plt.scatter(range(50), val_accuracy, label="Validation Accuracy", color='b', s=25, marker="o")
32 plt.scatter(range(50), val_loss, label="Validation Loss", color='r', s=25, marker="o")
33 plt.title('Validation : Accuracy and Loss')
34 plt.legend(loc='center right')
35 
36 plt.show()

9.用ImageDataGenerator資料增強

 1 train_datagen = ImageDataGenerator(rescale=1./255,
 2                                    rotation_range=40,  # 將影象隨機旋轉40度
 3                                    width_shift_range=0.2,  # 在水平方向上平移比例為0.2
 4                                    height_shift_range=0.2,  # 在垂直方向上平移比例為0.2
 5                                    shear_range=0.2,  # 隨機錯切變換的角度為0.2
 6                                    zoom_range=0.2,  # 圖片隨機縮放的範圍為0.2
 7                                    horizontal_flip=True,  # 隨機將一半影象水平翻轉
 8                                    fill_mode='nearest')  # 填充建立畫素
 9 validation_datagen = ImageDataGenerator(rescale=1./255)
10 
11 train_generator = train_datagen.flow_from_directory(
12     train_dir,
13     target_size=IMG_SIZE,  # 輸入訓練影象尺寸
14     batch_size=BATCH_SIZE,
15     class_mode='binary')
16 
17 validation_generator = validation_datagen.flow_from_directory(
18     validation_dir,
19     target_size=IMG_SIZE,
20     batch_size=BATCH_SIZE,
21     class_mode='binary')

再次訓練模型,並繪製繪製損失曲線和精度曲線圖,得到結果圖

 

 

10.隨機選取測試集的圖片進行預測

 1 # 將圖片縮小到(150,150)的大小
 2 def convertjpg(jpgfile, outdir, width=150, height=150):
 3     img = Image.open(jpgfile)
 4     try:
 5         new_img = img.resize((width, height), Image.BILINEAR)
 6         new_img.save(os.path.join(outdir, os.path.basename(jpgfile)))
 7     except Exception as e:
 8         print(e)
 9 
10 # 從測試集隨機獲取一張男性圖片
11 man_test = r'sex\faces\test\man'
12 man_test_list = os.listdir(man_test)
13 key = random.randint(0, len(man_test_list))
14 img_key = man_test_list[key]
15 jpg_file = os.path.join(man_test, img_key)
16 convertjpg(jpg_file, "sex/faces/test")  # 影象大小改變到(150,150)
17 img_scale = plt.imread('sex/faces/test/' + img_key)
18 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
19 
20 # 呼叫訓練模型結果進行預測
21 model = load_model('sex/faces/sex_model.h5')
22 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
23 img_scale = img_scale/255  # 歸一化到0-1之間
24 result = model.predict(img_scale)  # 取圖片資訊
25 if result > 0.5:
26     print('該圖片是女性的概率為:', result)
27 else:
28     print('該圖片是男性的概率為:', 1-result)
29 plt.show()  # 列印尺寸改變後的影象


 

 1 # 從測試集隨機獲取一張女性圖片
 2 woman_test = r'sex\faces\test\woman'
 3 woman_test_list = os.listdir(woman_test)
 4 key = random.randint(0, len(woman_test_list))
 5 img_key = woman_test_list[key]
 6 jpg_file = os.path.join(woman_test, img_key)
 7 convertjpg(jpg_file, "sex/faces/test")  # 影象大小改變到(150,150)
 8 img_scale = plt.imread('sex/faces/test/' + img_key)
 9 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
10 
11 # 呼叫訓練模型結果進行預測
12 model = load_model('sex/faces/sex_model.h5')
13 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
14 img_scale = img_scale/255  # 歸一化到0-1之間
15 result = model.predict(img_scale)  # 取圖片資訊
16 if result > 0.5:
17     print('該圖片是女性的概率為:', result)
18 else:
19     print('該圖片是男性的概率為:', 1-result)
20 plt.show()  # 列印尺寸改變後的影象

11.自定義一張圖片進行預測

# 自定義一張男性圖片進行預測
diy_img = 'sex/faces/man.jpg'
convertjpg(diy_img, "sex")  # 影象大小改變到(150,150)
img_scale = plt.imread('sex/man.jpg')
plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小

# 呼叫資料增強後的訓練模型結果進行預測
model = load_model('sex/faces/sex_model_idg.h5')
img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
img_scale = img_scale/255  # 歸一化到0-1之間
result = model.predict(img_scale)  # 取圖片資訊
if result > 0.5:
    print('該圖片是女性的概率為:', result)
else:
    print('該圖片是男性的概率為:', 1-result)
plt.show()  # 列印尺寸改變後的影象

 


 

 1 # 自定義一張女性圖片進行預測
 2 diy_img = 'sex/faces/woman_2.jpg'
 3 convertjpg(diy_img, "sex")  # 影象大小改變到(150,150)
 4 img_scale = plt.imread('sex/woman_2.jpg')
 5 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
 6 
 7 # 呼叫資料增強後的訓練模型結果進行預測
 8 model = load_model('sex/faces/sex_model.h5')
 9 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
10 img_scale = img_scale/255  # 歸一化到0-1之間
11 result = model.predict(img_scale)  # 取圖片資訊
12 if result > 0.5:
13     print('該圖片是女性的概率為:', result)
14 else:
15     print('該圖片是男性的概率為:', 1-result)
16 plt.show()  # 列印尺寸改變後的影象

 

 

 


 

 

全部程式碼:

  1 import os
  2 import random
  3 from shutil import copy
  4 from matplotlib import pyplot as plt
  5 from keras import optimizers
  6 from keras import models
  7 from keras import layers
  8 from keras.preprocessing.image import ImageDataGenerator
  9 from keras.models import load_model
 10 from PIL import Image
 11 
 12 # 女性圖片訓練集想儲存到的根路徑
 13 woman_train_dir = r'sex\faces\train\woman'
 14 # 女性圖片驗證集想儲存到的根路徑
 15 woman_validation_dir = r'sex\faces\validation\woman'
 16 # 女性圖片測試集想儲存到的根路徑
 17 woman_test_dir = r'sex\faces\test\woman'
 18 
 19 # 男性圖片訓練集想儲存到的根路徑
 20 man_train_dir = r'sex\faces\train\man'
 21 # 男性圖片驗證集想儲存到的根路徑
 22 man_validation_dir = r'sex\faces\validation\man'
 23 # 男性圖片測試集想儲存到的根路徑
 24 man_test_dir = r'sex\faces\test\man'
 25 
 26 # 建立列表,儲存上方6個路徑
 27 dir_list = [woman_train_dir, woman_validation_dir, woman_test_dir,
 28             man_train_dir, man_validation_dir, man_test_dir]
 29 # 如果目錄不存在,則建立
 30 for dir_child in dir_list:
 31     if not os.path.isdir(dir_child):
 32         os.makedirs(dir_child)
 33 
 34 # 女性圖片根路徑
 35 woman_path = r'sex\faces\woman'
 36 # 獲取 woman_path 下的資料夾列表
 37 woman_path_list = os.listdir(woman_path)
 38 # 遍歷列表,取6000張圖片加入訓練集,3000張圖片加入驗證集,其餘加入測試集
 39 for i in range(len(woman_path_list)):
 40     child_path = os.path.join(woman_path, woman_path_list[i])
 41     if i < 6000:
 42         to_path = woman_train_dir
 43     elif i < 9000:
 44         to_path = woman_validation_dir
 45     else:
 46         to_path = woman_test_dir
 47     copy(child_path, to_path)
 48 
 49 # 男性圖片根路徑
 50 man_path = r'sex\faces\man'
 51 # 獲取 man_path 下的資料夾列表
 52 man_path_list = os.listdir(man_path)
 53 # 遍歷列表,取6000張圖片加入訓練集,3000張圖片加入驗證集,其餘加入測試集
 54 for i in range(len(man_path_list)):
 55     child_path = os.path.join(man_path, man_path_list[i])
 56     if i < 6000:
 57         to_path = man_train_dir
 58     elif i < 9000:
 59         to_path = man_validation_dir
 60     else:
 61         to_path = man_test_dir
 62     copy(child_path, to_path)
 63 
 64 # 輸出各目錄中的檔案數目
 65 train_path = "sex/faces/train/"
 66 print('total training woman images:', len(os.listdir(train_path+"woman")))
 67 print('total training man images:', len(os.listdir(train_path+"man")))
 68 
 69 valid_path = "sex/faces/validation/"
 70 print('total validation woman images:', len(os.listdir(valid_path+"woman")))
 71 print('total validation man images:', len(os.listdir(valid_path+"man")))
 72 
 73 test_path = "sex/faces/test/"
 74 print('total test woman images:', len(os.listdir(test_path+"woman")))
 75 print('total test man images:', len(os.listdir(test_path+"man")))
 76 
 77 # 檢視影象以及對應的標籤
 78 fit, ax = plt.subplots(nrows=3, ncols=3, figsize=(10, 7))
 79 # 檢視影象的根路徑
 80 test_view_path = r'sex\faces\test\man'
 81 # 獲取 test_view_path 下的資料夾列表
 82 test_view_list = os.listdir(test_view_path)
 83 for i, a in enumerate(ax.flat):
 84     view_path = os.path.join(test_view_path, test_view_list[i])
 85     # 讀取源圖
 86     a.imshow(plt.imread(view_path))
 87     # 新增影象名稱
 88     a.set_title(man_path_list[i])
 89 plt.tight_layout()  # 自動調整子圖引數,使之填充整個影象區域
 90 plt.show()
 91 
 92 # 圖片預處理
 93 # 批次大小
 94 BATCH_SIZE = 20
 95 # 輸入圖片的大小
 96 IMG_SIZE = (150, 150)
 97 
 98 # 歸一化處理
 99 train_datagen = ImageDataGenerator(rescale=1./255)
100 validation_datagen = ImageDataGenerator(rescale=1./255)
101 test_datagen = ImageDataGenerator(rescale=1./255)
102 
103 train_dir = 'sex/faces/train'     # 指向訓練集圖片目錄路徑
104 
105 train_generator = train_datagen.flow_from_directory(
106     train_dir,
107     target_size=IMG_SIZE,  # 輸入訓練影象尺寸
108     batch_size=BATCH_SIZE,
109     color_mode='rgb',
110     class_mode='binary')
111 
112 validation_dir = 'sex/faces/validation'  # 指向驗證集圖片目錄路徑
113 
114 validation_generator = validation_datagen.flow_from_directory(
115     validation_dir,
116     target_size=IMG_SIZE,
117     batch_size=BATCH_SIZE,
118     color_mode='rgb',
119     class_mode='binary')
120 
121 test_dir = 'sex/faces/test'  # 指向測試集圖片目錄路徑
122 
123 test_generator = test_datagen.flow_from_directory(
124     test_dir,
125     target_size=IMG_SIZE,
126     batch_size=BATCH_SIZE,
127     color_mode='rgb',
128     class_mode='binary')
129 
130 # 檢視經過處理的圖片以及它的binary標籤
131 fit, ax = plt.subplots(nrows=3, ncols=3, figsize=(10, 7))
132 
133 for i, a in enumerate(ax.flat):
134     img, label = test_generator.next()
135     a.imshow(img[0],)
136     a.set_title(label[0])
137 
138 plt.tight_layout()
139 plt.show()
140 
141 # 構建神經網路
142 model = models.Sequential()
143 
144 # 1.Conv2D層,32個過濾器。輸出圖片尺寸:150-3+1=148*148,引數數量:32*3*3*3+32=896
145 model.add(layers.Conv2D(32, (3, 3),
146                         activation='relu',
147                         input_shape=(150, 150, 3)))  # 折積層1
148 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層1。輸出圖片尺寸:148/2=74*74
149 
150 # 2.Conv2D層,64個過濾器。輸出圖片尺寸:74-3+1=72*72,引數數量:64*3*3*32+64=18496
151 model.add(layers.Conv2D(64, (3, 3),
152                         activation='relu'))  # 折積層2
153 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層2。輸出圖片尺寸:72/2=36*36
154 
155 # 3.Conv2D層,128個過濾器。輸出圖片尺寸:36-3+1=34*34,引數數量:128*3*3*64+128=73856
156 model.add(layers.Conv2D(128, (3, 3),
157                         activation='relu'))  # 折積層3
158 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層3。輸出圖片尺寸:34/2=17*17
159 
160 # 4.Conv2D層,128個過濾器。輸出圖片尺寸:17-3+1=15*15,引數數量:128*3*3*128+128=147584
161 model.add(layers.Conv2D(128, (3, 3),
162                         activation='relu'))  # 折積層4
163 model.add(layers.MaxPooling2D((2, 2)))  # 最大值池化層4。輸出圖片尺寸:15/2=7*7
164 
165 # 將輸入層的資料壓縮成1維資料,全連線層只能處理一維資料
166 model.add(layers.Flatten())
167 
168 # 全連線層
169 model.add(layers.Dense(512,
170                        activation='relu'))  # 全連線層1
171 model.add(layers.Dense(1,
172                        activation='sigmoid'))  # 全連線層2,作為輸出層。sigmoid分類,輸出是兩類別
173 
174 # 編譯模型
175 # RMSprop 優化器。因為網路最後一層是單一sigmoid單元,
176 # 所以使用二元交叉熵作為損失函數
177 model.compile(loss='binary_crossentropy',
178               optimizer=optimizers.RMSprop(lr=1e-4),
179               metrics=['acc'])
180 
181 # 看一下特徵圖的維度如何隨著每層變化
182 model.summary()
183 #
184 
185 train_datagen = ImageDataGenerator(rescale=1./255,
186                                    rotation_range=40,  # 將影象隨機旋轉40度
187                                    width_shift_range=0.2,  # 在水平方向上平移比例為0.2
188                                    height_shift_range=0.2,  # 在垂直方向上平移比例為0.2
189                                    shear_range=0.2,  # 隨機錯切變換的角度為0.2
190                                    zoom_range=0.2,  # 圖片隨機縮放的範圍為0.2
191                                    horizontal_flip=True,  # 隨機將一半影象水平翻轉
192                                    fill_mode='nearest')  # 填充建立畫素
193 validation_datagen = ImageDataGenerator(rescale=1./255)
194 
195 train_generator = train_datagen.flow_from_directory(
196     train_dir,
197     target_size=IMG_SIZE,  # 輸入訓練影象尺寸
198     batch_size=BATCH_SIZE,
199     class_mode='binary')
200 
201 validation_generator = validation_datagen.flow_from_directory(
202     validation_dir,
203     target_size=IMG_SIZE,
204     batch_size=BATCH_SIZE,
205     class_mode='binary')
206 #
207 # 訓練模型50輪次
208 history_save = model.fit(
209                     train_generator,
210                     steps_per_epoch=100,
211                     epochs=50,
212                     validation_data=validation_generator,
213                     validation_steps=50)
214 
215 # 將訓練過程產生的資料儲存為h5檔案
216 model.save('sex/faces/sex_model.h5')
217 # 儲存資料增強後的訓練模型
218 model.save('sex/faces/sex_model_idg.h5')
219 
220 # 繪製損失曲線和精度曲線圖
221 accuracy = history_save.history['acc']  # 訓練集精度
222 loss = history_save.history['loss']  # 訓練集損失
223 val_loss = history_save.history['val_loss']  # 驗證集精度
224 val_accuracy = history_save.history['val_acc']  # 驗證集損失
225 plt.figure(figsize=(17, 7))
226 
227 # 訓練集精度和驗證集精度曲線圖圖
228 plt.subplot(2, 2, 1)
229 plt.plot(range(50), accuracy, 'bo', label='Training Accuracy')
230 plt.plot(range(50), val_accuracy, label='Validation Accuracy')
231 plt.title('Training and Validation Accuracy')
232 plt.legend(loc='center right')
233 
234 # 訓練集損失和驗證集損失圖
235 plt.subplot(2, 2, 2)
236 plt.plot(range(50), loss, 'bo', label='Training Loss')
237 plt.plot(range(50), val_loss, label='Validation Loss')
238 plt.title('Training and Validation Loss')
239 plt.legend(loc='center right')
240 
241 # 訓練集精度和損失散點圖
242 plt.subplot(2, 2, 3)
243 plt.scatter(range(50), accuracy, label="Training Accuracy", color='b', s=25, marker="o")
244 plt.scatter(range(50), loss, label="Training Loss", color='r', s=25, marker="o")
245 plt.title('Training : Accuracy and Loss')
246 plt.legend(loc='center right')
247 
248 # 驗證集精度和損失散點圖
249 plt.subplot(2, 2, 4)
250 plt.scatter(range(50), val_accuracy, label="Validation Accuracy", color='b', s=25, marker="o")
251 plt.scatter(range(50), val_loss, label="Validation Loss", color='r', s=25, marker="o")
252 plt.title('Validation : Accuracy and Loss')
253 plt.legend(loc='center right')
254 
255 plt.show()
256 
257 # 將圖片縮小到(150,150)的大小
258 def convertjpg(jpgfile, outdir, width=150, height=150):
259     img = Image.open(jpgfile)
260     try:
261         new_img = img.resize((width, height), Image.BILINEAR)
262         new_img.save(os.path.join(outdir, os.path.basename(jpgfile)))
263     except Exception as e:
264         print(e)
265 
266 # 從測試集隨機獲取一張男性圖片
267 man_test = r'sex\faces\test\man'
268 man_test_list = os.listdir(man_test)
269 key = random.randint(0, len(man_test_list))
270 img_key = man_test_list[key]
271 jpg_file = os.path.join(man_test, img_key)
272 convertjpg(jpg_file, "sex/faces/test")  # 影象大小改變到(150,150)
273 img_scale = plt.imread('sex/faces/test/' + img_key)
274 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
275 
276 # 呼叫訓練模型結果進行預測
277 model = load_model('sex/faces/sex_model.h5')
278 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
279 img_scale = img_scale/255  # 歸一化到0-1之間
280 result = model.predict(img_scale)  # 取圖片資訊
281 if result > 0.5:
282     print('該圖片是女性的概率為:', result)
283 else:
284     print('該圖片是男性的概率為:', 1-result)
285 plt.show()  # 列印尺寸改變後的影象
286 
287 # 從測試集隨機獲取一張女性圖片
288 woman_test = r'sex\faces\test\woman'
289 woman_test_list = os.listdir(woman_test)
290 key = random.randint(0, len(woman_test_list))
291 img_key = woman_test_list[key]
292 jpg_file = os.path.join(woman_test, img_key)
293 convertjpg(jpg_file, "sex/faces/test")  # 影象大小改變到(150,150)
294 img_scale = plt.imread('sex/faces/test/' + img_key)
295 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
296 
297 # 呼叫訓練模型結果進行預測
298 model = load_model('sex/faces/sex_model.h5')
299 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
300 img_scale = img_scale/255  # 歸一化到0-1之間
301 result = model.predict(img_scale)  # 取圖片資訊
302 if result > 0.5:
303     print('該圖片是女性的概率為:', result)
304 else:
305     print('該圖片是男性的概率為:', 1-result)
306 plt.show()  # 列印尺寸改變後的影象
307 
308 # 自定義一張男性圖片進行預測
309 diy_img = 'sex/faces/man.jpg'
310 convertjpg(diy_img, "sex")  # 影象大小改變到(150,150)
311 img_scale = plt.imread('sex/man.jpg')
312 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
313 
314 # 呼叫資料增強後的訓練模型結果進行預測
315 model = load_model('sex/faces/sex_model_idg.h5')
316 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
317 img_scale = img_scale/255  # 歸一化到0-1之間
318 result = model.predict(img_scale)  # 取圖片資訊
319 if result > 0.5:
320     print('該圖片是女性的概率為:', result)
321 else:
322     print('該圖片是男性的概率為:', 1-result)
323 plt.show()  # 列印尺寸改變後的影象
324 
325 # 自定義一張女性圖片進行預測
326 diy_img = 'sex/faces/woman_2.jpg'
327 convertjpg(diy_img, "sex")  # 影象大小改變到(150,150)
328 img_scale = plt.imread('sex/woman_2.jpg')
329 plt.imshow(img_scale)  # 顯示改變影象大小後的圖片確實變到了(150,150)大小
330 
331 # 呼叫資料增強後的訓練模型結果進行預測
332 model = load_model('sex/faces/sex_model.h5')
333 img_scale = img_scale.reshape(1, 150, 150, 3).astype('float32')
334 img_scale = img_scale/255  # 歸一化到0-1之間
335 result = model.predict(img_scale)  # 取圖片資訊
336 if result > 0.5:
337     print('該圖片是女性的概率為:', result)
338 else:
339     print('該圖片是男性的概率為:', 1-result)
340 plt.show()  # 列印尺寸改變後的影象