1. 程式人生 > >利用resnet 做kaggle貓狗大戰影象識別,秒上98準確率

利用resnet 做kaggle貓狗大戰影象識別,秒上98準確率

1、資料介紹

這份資料集來源於Kaggle,資料集有12500只貓和12500只狗。在這裡簡單介紹下整體思路
1、1從圖片中直接訓練一個小網路(作為基準方法),也就是普通的cnn方法
2、2後面我會用到最新的預訓練好的resnet等方法進行訓練

2 資料提升與cnn

為了儘量利用我們有限的訓練資料,我們將通過一系列隨機變換堆資料進行提升,這樣我們的模型將看不到任何兩張完全相同的圖片,這有利於我們抑制過擬合,使得模型的泛化能力更好。
在Keras中,這個步驟可以通過keras.preprocessing.image.ImageGenerator來實現,這個類使你可以:
在訓練過程中,設定要施行的隨機變換
通過.flow或.flow_from_directory(directory)方法例項化一個針對影象batch的生成器,這些生成器可以被用作keras模型相關方法的輸入,如fit_generator,evaluate_generator和predict_generator
2、1 程式碼與解釋

import os  # 處理字串路徑
import glob  # 查詢檔案
from keras.models import Sequential  # 匯入Sequential模型
from keras.layers.core import Flatten, Dense, Dropout
from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras.optimizers import SGD
import numpy as np
from pandas import
Series, DataFrame from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation, Flatten from keras.layers.advanced_activations import PReLU from keras.layers.convolutional import Convolution2D, MaxPooling2D from
keras.optimizers import SGD, Adadelta, Adagrad from keras.utils import np_utils, generic_utils from six.moves import range #載入資料 model = Sequential() #第一個卷積層,4個卷積核,每個卷積核大小5*5。1表示輸入的圖片的通道,灰度圖為1通道。 #啟用函式用relu #你還可以在model.add(Activation('relu'))後加上dropout的技巧,防止過擬合 model.add(Dropout(0.5)) model.add(Convolution2D(4, 5, 5,input_shape=(224, 224,3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #第二個卷積層,8個卷積核,每個卷積核大小3*3。4表示輸入的特徵圖個數,等於上一層的卷積核個數 #啟用函式用relu #採用maxpooling,poolsize為(2,2) model.add(Convolution2D(8, 3, 3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #第三個卷積層,16個卷積核,每個卷積核大小3*3 #啟用函式用relu #採用maxpooling,poolsize為(2,2) model.add(Convolution2D(16, 3, 3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #全連線層,先將前一層輸出的二維特徵圖flatten為一維的。 #全連線有128個神經元節點,初始化方式為normal model.add(Flatten()) model.add(Dense(128)) model.add(Activation('relu')) model.add(Dropout(0.5)) #sigmoid分類,輸出是2類別 model.add(Dense(1)) model.add(Activation('sigmoid')) model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) # this is the augmentation configuration we will use for testing: # only rescaling test_datagen = ImageDataGenerator(rescale=1./255) # this is a generator that will read pictures found in # subfolers of 'data/train', and indefinitely generate # batches of augmented image data train_generator = train_datagen.flow_from_directory( 'd:/train2', # this is the target directory target_size=(224, 224), # all images will be resized to 150x150 batch_size=32, class_mode='binary') # since we use binary_crossentropy loss, we need binary labels # this is a similar generator, for validation data validation_generator = test_datagen.flow_from_directory( 'd:/validation', target_size=(224, 224), batch_size=32, class_mode='binary') model.fit_generator( train_generator, samples_per_epoch=2000, nb_epoch=50, validation_data=validation_generator, nb_val_samples=800) from keras.utils import plot_model plot_model(model, to_file='d:/model.png')

3、resnet及其他方法融合

從知乎看到的一種方法,在這裡介紹給大家,通過已訓練好的imagenet權重對我們的資料進行特徵提取,然後再用提取的特徵做一個簡單的全連線。程式碼如下:

from keras.models import *
from keras.layers import *
from keras.applications import *
from keras.preprocessing.image import *

import h5py

def write_gap(MODEL, image_size, lambda_func=None):
    width = image_size[0]
    height = image_size[1]
    input_tensor = Input((height, width, 3))
    x = input_tensor
    if lambda_func:
        x = Lambda(lambda_func)(x)

    base_model = MODEL(input_tensor=x, weights='imagenet', include_top=False)
    model = Model(base_model.input, GlobalAveragePooling2D()(base_model.output))

    gen = ImageDataGenerator()
    train_generator = gen.flow_from_directory("d:/train2", image_size, shuffle=False,
                                              batch_size=16)
    test_generator = gen.flow_from_directory("d:/test2", image_size, shuffle=False,
                                             batch_size=16, class_mode=None)

    train = model.predict_generator(train_generator, train_generator.nb_sample)
    test = model.predict_generator(test_generator, test_generator.nb_sample)
    with h5py.File("d:/mymodel/gap_%s.h5"%MODEL.func_name) as h:
        h.create_dataset("train", data=train)
        h.create_dataset("test", data=test)
        h.create_dataset("label", data=train_generator.classes)

write_gap(ResNet50, (224, 224))
write_gap(InceptionV3, (299, 299), inception_v3.preprocess_input)
write_gap(Xception, (299, 299), xception.preprocess_input)



import h5py
import numpy as np
from sklearn.utils import shuffle
np.random.seed(2017)

X_train = []
X_test = []

for filename in ["gap_ResNet50.h5", "gap_Xception.h5", "gap_InceptionV3.h5"]:
    with h5py.File(filename, 'r') as h:
        X_train.append(np.array(h['train']))
        X_test.append(np.array(h['test']))
        y_train = np.array(h['label'])

X_train = np.concatenate(X_train, axis=1)
X_test = np.concatenate(X_test, axis=1)

X_train, y_train = shuffle(X_train, y_train)





from keras.models import *
from keras.layers import *

np.random.seed(2017)

input_tensor = Input(X_train.shape[1:])
x = Dropout(0.5)(input_tensor)
x = Dense(1, activation='sigmoid')(x)
model = Model(input_tensor, x)

model.compile(optimizer='adadelta',
              loss='binary_crossentropy',
              metrics=['accuracy'])



model.fit(X_train, y_train, batch_size=128, nb_epoch=8, validation_split=0.2)

y_pred = model.predict(X_test, verbose=1)
y_pred = y_pred.clip(min=0.005, max=0.995)

import pandas as pd
from keras.preprocessing.image import *

df = pd.read_csv("sample_submission.csv")

gen = ImageDataGenerator()
test_generator = gen.flow_from_directory("test2", (224, 224), shuffle=False,
                                         batch_size=16, class_mode=None)

for i, fname in enumerate(test_generator.filenames):
    index = int(fname[fname.rfind('/')+1:fname.rfind('.')])
    df.set_value(index-1, 'label', y_pred[i])

df.to_csv('pred.csv', index=None)
df.head(10)

4、參考文獻