Picture from Internet
現實意義在電影《九條命》中,導演毫不吝嗇的採用各種電影技巧去刻畫貓的可愛頑皮。但在幕後採訪故事中,導演表示自己其實對貓毛過敏,幾經幸苦才將 movie 拍完。喜愛貓咪但又對貓毛過敏是異常悲傷。所以導演想要養狗。某一天,他了解到一個動物市場,裡面只有兩種動物,狗,貓;主人迫於過敏,不能親自去挑選。於是他想了一個辦法,能不能用搭載了神經網絡的無人機遠程辨識出狗。
環境配置import tensorflow as tfimport tensorflow.keras as kerasimport tensorflow_datasets as tfdsimport matplotlib.pyplot as plt在本次實例中,我們採用tensoflow_datasets 第三方庫來加載數據,該庫集合了眾多著名的公開數據集,類型包括文字、圖片、語音、視頻等。本次數據集就來自於該庫中的 cats_vs_dogs 數據集。
數據集準備 —— cats_vs_dogs(train_datas, val_datas), info = tfds.load('cats_vs_dogs', split=('train[:70%]', 'train[70%:]'), as_supervised=True, with_info=True, shuffle_files=True)infotfds.core.DatasetInfo( name='cats_vs_dogs', version=4.0.0, description='A large set of images of cats and dogs.There are 1738 corrupted images that are dropped.', homepage='https://www.microsoft.com/en-us/download/details.aspx?id=54765', features=FeaturesDict({ 'image': Image(shape=(None, None, 3), dtype=tf.uint8), 'image/filename': Text(shape=(), dtype=tf.string), 'label': ClassLabel(shape=(), dtype=tf.int64, num_classes=2),}), total_num_examples=23262, splits={ 'train': 23262,}, supervised_keys=('image', 'label'), citation="""@Inproceedings (Conference){asirra-a-captcha-that-exploits-interest-aligned-manual-image-categorization, author = {Elson, Jeremy and Douceur, John (JD) and Howell, Jon and Saul, Jared}, title = {Asirra: A CAPTCHA that Exploits Interest-Aligned Manual Image Categorization}, booktitle = {Proceedings of 14th ACM Conference on Computer and Communications Security (CCS)}, year = {2007}, month = {October}, publisher = {Association for Computing Machinery, Inc.}, url = {https://www.microsoft.com/en-us/research/publication/asirra-a-captcha-that-exploits-interest-aligned-manual-image-categorization/}, edition = {Proceedings of 14th ACM Conference on Computer and Communications Security (CCS)},}""",redistribution_info=,)tfds.show_examples(train_datas, info)
從上面的信息我們可以看出來,圖片的大小不是固定的,所以我們需要對其加入一點點細節,使其高寬度統一。
def image_resize(image, label): image = tf.image.resize(image, (227, 227)) / 255.0 return image, labeltrain_datas = train_datas.map(image_resize).shuffle(1000)val_datas = val_datas.map(image_resize).shuffle(1000)def visualize_image(image): plt.figure() plt.imshow(image for image, label in train_datas.take(1): visualize_image(image) print(image.shape, label) print(image.numpy()[1] (227, 227, 3) tf.Tensor(1, shape=(), dtype=int64
自定義一個函數 image_resize(),該函數將原本不規則大小的圖像統一為(500, 500)的圖像,在除以 255.0 歸一化圖像。
train_datas.map()tf.data.Dataset().map(function) 函數能將自定義函數映射到全數據集,這樣就不用迭代改變圖像大小,大大提高效率。
自定義函數 visualize_image() 用來顯示我們測試的圖片。
圖像已被轉換成張量,萬事具備,只欠模型。
因為辨別貓狗比辨別手寫數字複雜的多,所以為了使準確度高一點, 我們使用 AlexNet,https://zhuanlan.zhihu.com/p/42914388。AlexNet運用了相當多的技巧,比如ReLu、多塊GPU並行訓練、局部響應歸一化、Overlapping池化、Dropout等。下圖為其網絡架構。我自己也嘗試過寫一些網絡層改變性能,但是效果卻不是很好。
model = keras.Sequential([ # layer_1 keras.layers.Conv2D(filters=96, kernel_size=(4, 4), strides=(4, 4), padding='valid', input_shape=(227, 227, 3), activation='relu'), keras.layers.BatchNormalization(), keras.layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid'), # layer_2 keras.layers.Conv2D(filters=256, kernel_size=(5, 5), strides=(1, 1), padding='same', activation='relu'), keras.layers.BatchNormalization(), keras.layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid'), # layer_3 keras.layers.Conv2D(filters=384, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'), keras.layers.Conv2D(filters=384, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'), keras.layers.Conv2D(filters=256, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'), keras.layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid'), # layer_4 keras.layers.Flatten(), keras.layers.Dense(units=4096, activation='relu'), keras.layers.Dropout(0.5), # layer_5 keras.layers.Dense(units=4096, activation='relu'), keras.layers.Dropout(0.5), # layer_6 keras.layers.Dense(units=1000, activation='relu'), keras.layers.Dropout(0.5), # layer_7 keras.layers.Dense(units=2, activation='softmax')]) model.summary()Model: "sequential"
模型編譯貓狗分類標籤有兩個種類,且用 1,0 表示,所以採用:SparseCategoricalCrossentropymodel.compile( optimizer=keras.optimizers.SGD(1e-3), loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'] )回調函數EarlyStopping 當被監測的數量不再提升,則停止訓練。TensorBoard TensorBoard 是由 Tensorflow 提供的一個可視化工具。可以利用該工具可視化訓練過程:callback_list = [ keras.callbacks.EarlyStopping(monitor='accuracy', patience=5,), # patience 表示 accuracy 5 次沒有提升後,就停止模型 keras.callbacks.TensorBoard(log_dir='log_1',), # log_dir-->用來保存被 TensorBoard 分析的日誌文件的文件名]訓練模型batch大小也會影響模型訓練的好壞。一開始我用的是 32 ,後改成 128 ,精確度肉眼可見的提升。 Epochs 一般情況下為 80。
訓練參數較多的,推薦用GPU,速度會快很多。
model.fit( train_datas.batch(128), validation_data=val_datas.batch(128), epochs=100, callbacks=callback_list)可視化訓練過程
%load_ext tensorboard%tensorboard --logdir='log_1'從上面可以看出,訓練集訓練過中持續變小,上昇平緩。而驗證集波動大,說明模型效果很差。但這也是不可避免的,因為網絡層層數小,訓練次數小。
解決方案,調整超參數,增加網絡層,增加訓練次數。
模型預測評價一個模型的好壞在於給他一張陌生的圖像或者文字,他正確率有多少。因為驗證機不參與模型訓練,所以我們輸入30張驗證集裡的圖片,來看看他的準確率吧!
class_name = info.features['label'].names # list ['cat', 'dog']images, labels = next(iter(val_datas.batch(30).prefetch(1)))predicted_images = model.predict(images)predicted_labels = tf.math.argmax(predicted_images, axis=-1)plt.figure(figsize=(14, 14))for i in range(30): plt.subplot(6, 5, i+1) plt.imshow(images[i]) color = 'blue' if predicted_labels[i] == labels[i] else 'red' plt.title(class_name[predicted_labels[i]].title(), color=color) plt.axis('off')
藍色標籤代表預測準確,紅色標籤代表預測失敗。圖中有兩個預測失敗,但是前面也說了,因為驗證集精準度波動極大,所以我們可能只是運氣好罷了。想要有十足的把握識別正確,就要努力提高模型精確度。
看來我們的導演可以放心的足不出戶的挑選喜愛的狗狗了。
參考資料:
https://www.kaggle.com/seanbenhur/using-tensorflow-hub-to-get-99-accuracy
撰文:塗銀江
編輯:文凌