1 前言
ResNet 是一種經典的影像識別領域模型,在 2015 年影像識別領域多個競賽中排行第一,并且性能上相較第二有大幅提升,在這篇文章里,我們就站在巨人們的肩膀上,搭建一個基于 ResNet 識別花卉圖片(Oxford 102 Flowers)的神經網路吧,
2 ResNet 簡介
在 ResNet 以前,由于存在梯度消失和梯度爆炸的問題,神經網路層數越深,網路越難以訓練,導致深層網路的準確度出現下降,
ResNet 通過引入殘差塊(Residual block),將 a[l]添加到第二個 ReLU 程序中,直接建立 a[l]與 a[l+2]之間的隔層聯系,運算式如下:
論文[1]作者推測模型對殘差的擬合優化會比對隨機權重的擬合更加容易(因為baseline就是恒等映射),所以在極端狀況下,殘差塊的中間層沒有激活,即W≈0,b≈0,則有:

殘差塊示例
所以這種構造方式保證了深層的網路比淺層包含了更多(至少恒等)的影像資訊,多個殘差塊推擠在一起,便形成了一個殘差網路,

殘差網路和普通深度神經網路對比
3 用 ResNet 構造分類模型
在下列 demo 中,我們使用 keras 已有的 ResNet50預訓練模型,對 Oxford 102 Flowers 資料集中的 10 種花卉圖片進行多分類任務模型的構造,在工程上我們只需要修改 ResNet50 頂部的全連接層,對輸入的圖片資料進行裁剪,旋轉,放大等資料增強,訓練所有模型引數即可,代碼如下:
import os
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Model, load_model
from keras.applications import ResNet50
from keras.optimizers import Adam
from keras.layers import Flatten, Dense, Dropout, Input
from keras.callbacks import EarlyStopping, ModelCheckpoint
import numpy as np
import math
def fc_block(X,units,dropout,stage):
fc_name = 'fc' + str(stage)
X = Dense(units,activation ='elu',name = fc_name)(X)
X = Dropout(dropout)(X)
return X
def ResNet50_transfer():
#call base_model
base_model = ResNet50(
include_top=False,
weights="imagenet",
input_tensor= Input(shape=img_size + (3,))
)
# freeze resnet layers' params
for layer in base_model.layers:
layer.trainable = False
# top architecture
X = base_model.output
X = Flatten()(X)
X = Dropout(0.4)(X)
X = fc_block(X,fc_layer_units[0],dropout = 0.4,stage = 1)
X = fc_block(X,fc_layer_units[1],dropout = 0.4,stage = 2)
# output layer
X = Dense(len(classes),activation='softmax',name = 'fc3_output')(X)
# create model
model = Model(inputs = base_model.input,outputs = X, name = 'ResNet50_transfer')
return model
def generate_data(train_path,valid_path):
# generate & augment training data
train_datagen = ImageDataGenerator(rotation_range=30., shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
train_datagen.mean = np.array([123.675, 116.28 , 103.53], dtype=np.float32).reshape((3, 1, 1))
train_data = train_datagen.flow_from_directory(train_path, target_size=img_size, classes=None)
# generate training data
valid_datagen = ImageDataGenerator()
valid_datagen.mean = np.array([123.675, 116.28 , 103.53], dtype=np.float32).reshape((3, 1, 1))
valid_data = train_datagen.flow_from_directory(valid_path, target_size=img_size, classes=None)
return train_data, valid_data
def call_back():
early_stopping = EarlyStopping(verbose=1, patience=10, monitor='val_loss')
model_checkpoint = ModelCheckpoint(filepath='102flowersmodel.h5', verbose=1, save_best_only=True, monitor='val_loss')
callbacks = [early_stopping, model_checkpoint]
return callbacks
# path_to_img: 'dataset/flower_data_10/train/1//image_06734.jpg'
train_path = 'dataset/flower_data_10/train'
valid_path = 'dataset/flower_data_10/valid'
nb_epoch = 20
batch_size = 32
img_size = (224,224)
# output classes
classes = list(map(str,[1,2,3,4,5,6,7,8,9,10]))
rgb_mean = [123.68, 116.779, 103.939]
fc_layer_units = [512,64]
model = ResNet50_transfer()
model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=1e-5), metrics=['accuracy'])
train_data, valid_data = generate_data(train_path,valid_path)
callbacks = call_back()
model.fit_generator(train_data, steps_per_epoch= math.ceil(train_data.samples / batch_size), epochs=nb_epoch,
validation_data=valid_data, validation_steps=math.ceil(valid_data.samples / batch_size),
callbacks=callbacks)
經過 20 個 epoch 的訓練后,驗證集的準確度已經達到了 0.8837,
4 小結
本文章簡單地介紹了 ResNet 的特點,以及提供了搭建圖片分類模型的代碼模板,顯卡配置較高的同學可以嘗試搭建不同規模的 ResNet 網路觀察網路深度對模型性能的影響;對于影像識別模型感興趣的同學推薦細讀 ResNet 論文: Deep Residual Learning for Image Recognition,
參考資料
[1] Deep Residual Learning for Image Recognition: https://arxiv.org/abs/1512.03385
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/357217.html
標籤:其他
上一篇:opencv圖片處理
下一篇:JavaCV調整影像陰影
