目的
突發奇想想會認爲下面這張圖片究竟是瑪麗蓮夢露還是愛因斯坦,主要目的順便實踐練習《Python深度學習》書中的例子,只採用了很小批量的數據,也沒有深究如何提高正確率,解決過擬合的問題。詳細可以參見《python深度學習》第五章前兩節。
數據準備
從百度圖片中找到了風格各異的愛因斯坦的圖片,直接採用下載整個網頁的方式獲取圖片。選的量不多,100張作爲訓練,25張用於驗證。本來是留有測試的數據,不小心刪掉了就跳過在新數據上測試的步驟。(數據量太小也是一個嚴重的問題)
手動刪掉一些不合適的圖片,分別放到train和validation文件夾下的E,M兩個文件中。
構建網絡
建立序列模型,採用這個網絡是因爲之前在一個SAR圖像的識別中表現優異,預測準確率達到96%以上(儘管並不能說明它在區分愛因斯坦和瑪麗蓮夢露也能表現得很好)
import os
from keras import layers
from keras import models
model = models.Sequential()
model.add(layers.Conv2D(64, (3, 3), activation='relu',
input_shape=(88, 88,3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 86, 86, 64) 1792
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 43, 43, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 41, 41, 64) 36928
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 20, 20, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 18, 18, 128) 73856
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 9, 9, 128) 0
_________________________________________________________________
conv2d_4 (Conv2D) (None, 7, 7, 128) 147584
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 3, 3, 128) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 1152) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 1152) 0
_________________________________________________________________
dense_1 (Dense) (None, 512) 590336
_________________________________________________________________
dropout_2 (Dropout) (None, 512) 0
_________________________________________________________________
dense_2 (Dense) (None, 512) 262656
_________________________________________________________________
dense_3 (Dense) (None, 1) 513
=================================================================
Total params: 1,113,665
Trainable params: 1,113,665
Non-trainable params: 0
讀入圖片並訓練
base_dir = r'dir\Einstein'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'v')
from keras import optimizers
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale=1. / 255)
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(88,88),
batch_size=20,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(88, 88),
batch_size=20,
class_mode='binary')
history = model.fit_generator(train_generator,steps_per_epoch=128,epochs=20,
validation_data=validation_generator,validation_steps=50)
#保存模型
model.save('EM.h5')
訓練結果
繪製性能曲線
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
l最終結果:
oss: 0.0050 - acc: 0.9996 -
val_loss: 2.4635 - val_acc: 0.6614
結果顯然過擬合了,預測的正確率只有66%。但不妨礙用於用的預測。
預測
from keras.preprocessing import image
import matplotlib.image as mpimg
from keras import models
import numpy as np
img = image.load_img(r'dir\Einstein\EM.jpg',target_size=(88,88,3))
img = np.array(img)
img = img/255
model = models.load_model(r'dir\Einstein\EM.h5')
img = img.reshape(1,88,88,3)
pre = model.predict(img)
print('預測結果:',pre)
預測結果: [[0.00376787]]
Keras添加的標籤是E(愛因斯坦)文件夾中的爲0,M(瑪麗蓮夢露)爲1。通過網絡最後的sigmoid單元,輸出值爲0.00376787,這個神經網絡十分傾向於認爲這張圖片是愛因斯坦。
嘗試了很多種不同的結構(數據量小訓練也很快),驗證集的正確率一直在70%左右,僅有一次認爲該圖片是瑪麗蓮夢露,其餘結果都認爲這張圖片是愛因斯坦。
結論
在搭建的這樣的簡單的網絡下,更傾向於認爲這種圖片裏的人是愛因斯坦。
不足之處
- 樣本太少
- 過擬合,驗證集的識別正確率不高
參考資料
《python深度學習》