2017-05-14 206 views
2

我已經問過類似的問題here,但現在我的問題略有不同,因此提出了新的問題。VGG16 Keras微調:精度不高

我決定使用稍微不同的方法,而不是在參考問題的答案中提出來訓練,然後微調模型。

更新:我已經換成更適合的版本在這裏提供的老問題

這裏是我的行動順序:

  1. 構建VGG16模型,跌幅居前層(電話它沒有頂級模型)
  2. 使用無頂模型生成瓶頸功能
  3. 列車爲eparate完全連接模型中使用的瓶頸功能
  4. 建立新的VGG16模型,跌幅居前層,並附加預訓練的頂級型號上的狗/貓數據

  • 列車拼接模型這裏是我使用的代碼實施上述的動作序列:

    import warnings 
    warnings.simplefilter('ignore', UserWarning) 
    warnings.simplefilter('ignore', DeprecationWarning) 
    
    from __future__ import print_function 
    from itertools import izip_longest as zip_longest 
    from pprint import pformat as pf 
    from pprint import pprint as pp 
    import os 
    
    from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img 
    from keras.layers import Conv2D, MaxPooling2D, MaxPooling2D, ZeroPadding2D 
    from keras.layers import Dropout, Flatten, Dense, InputLayer, Lambda 
    from keras.models import Sequential, Model, load_model 
    from keras.utils.data_utils import get_file 
    from keras.optimizers import SGD 
    import keras.backend as K 
    
    import numpy as np 
    
    
    RANDOM_STATE = 1 
    IMAGE_WIDTH = 224 
    IMAGE_HEIGHT = 224 
    BATCH_SIZE = 4 
    VGG_MEAN = np.array([123.68, 116.779, 103.939]).reshape((3, 1, 1)) 
    VGG16_WEIGHTS_PATH = 'http://www.platform.ai/models/vgg16.h5' 
    DATA_ROOT = os.path.join(os.path.expanduser('~'), 'data', 'dogscats') 
    TRAIN_DIR = os.path.join(DATA_ROOT, 'train') 
    VALID_DIR = os.path.join(DATA_ROOT, 'valid') 
    SAMPLES_DIR = os.path.expanduser('~/dogscats_samples') 
    
    
    np.random.seed(RANDOM_STATE) 
    K.set_image_dim_ordering('th') 
    
    
    def get_batches(dirname, gen=ImageDataGenerator(), shuffle=True, 
           batch_size=BATCH_SIZE, class_mode='categorical'): 
        return gen.flow_from_directory(
         os.path.join(SAMPLES_DIR, dirname), 
         target_size=(IMAGE_WIDTH, IMAGE_HEIGHT), 
         class_mode=class_mode, 
         shuffle=shuffle, 
         batch_size=batch_size) 
    
    def vgg_preprocess(x): 
        x = x - VGG_MEAN 
        return x[:, ::-1] 
    
    def conv_block(model, n_layers, n_filters, name='block'): 
        for i in range(n_layers): 
         model.add(ZeroPadding2D((1, 1), name='%s_padding_%s' % (name, i))) 
         model.add(Conv2D(n_filters, (3, 3), activation='relu', name='%s_conv2d_%s' % (name, i))) 
        model.add(MaxPooling2D((2, 2), strides=(2, 2), name='%s_maxpool' % name)) 
    
    def fc_block(model, name='block'): 
        model.add(Dense(4096, activation='relu', name=name + '_dense')) 
        model.add(Dropout(0.5)) 
    
    def build_vgg_16(): 
        model = Sequential() 
        input_shape = (3, IMAGE_WIDTH, IMAGE_HEIGHT) 
        model.add(InputLayer(input_shape=input_shape)) 
        model.add(Lambda(vgg_preprocess)) 
        conv_block(model, n_layers=2, n_filters=64, name='block1') 
        conv_block(model, n_layers=2, n_filters=128, name='block2') 
        conv_block(model, n_layers=3, n_filters=256, name='block3') 
        conv_block(model, n_layers=3, n_filters=512, name='block4') 
        conv_block(model, n_layers=3, n_filters=512, name='block5') 
        model.add(Flatten()) 
        fc_block(model) 
        fc_block(model) 
        model.add(Dense(1000, activation='softmax')) 
        return model 
    
    def train_finetuned_model(): 
        file_path = get_file('vgg16.h5', VGG16_WEIGHTS_PATH, cache_subdir='models') 
        print('Building VGG16 (no-top) model to generate bottleneck features') 
        vgg16_notop = build_vgg_16() 
        vgg16_notop.load_weights(file_path) 
        for _ in range(6): 
         vgg16_notop.pop() 
        vgg16_notop.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) 
    
        train_batches = get_batches('train', shuffle=False, class_mode=None) 
        train_labels = np.array([0]*1000 + [1]*1000) 
        bottleneck_train = vgg16_notop.predict_generator(train_batches, steps=2000 // BATCH_SIZE) 
    
        valid_batches = get_batches('valid', shuffle=False, class_mode=None) 
        valid_labels = np.array([0]*400 + [1]*400) 
        bottleneck_valid = vgg16_notop.predict_generator(valid_batches, steps=800 // BATCH_SIZE) 
    
        print('Training top model on bottleneck features') 
        top_model = Sequential() 
        top_model.add(Flatten(input_shape=bottleneck_train.shape[1:])) 
        top_model.add(Dense(256, activation='relu')) 
        top_model.add(Dropout(0.5)) 
        top_model.add(Dense(1, activation='sigmoid')) 
        top_model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy']) 
        top_model.fit(bottleneck_train, train_labels, 
            batch_size=32, epochs=50, 
            validation_data=(bottleneck_valid, valid_labels)) 
    
        print('Concatenate new VGG16 (without top layer) with pretrained top model') 
        vgg16_fine = build_vgg_16()  
        vgg16_fine.load_weights(file_path) 
        for _ in range(6): 
         vgg16_fine.pop() 
        vgg16_fine.add(Flatten(name='top_flatten'))  
        vgg16_fine.add(Dense(256, activation='relu', name='top_dense')) 
        vgg16_fine.add(Dropout(0.5, name='top_dropout')) 
        vgg16_fine.add(Dense(1, activation='sigmoid', name='top_sigmoid')) 
        for i, layer in enumerate(reversed(top_model.layers), 1): 
         pretrained_weights = layer.get_weights() 
         vgg16_fine.layers[-i].set_weights(pretrained_weights) 
        for layer in vgg16_fine.layers[:26]: 
         layer.trainable = False 
        vgg16_fine.compile(optimizer=SGD(lr=1e-4, momentum=0.9), 
             loss='binary_crossentropy', 
             metrics=['accuracy']) 
    
        print('Train concatenated model on dogs/cats dataset sample') 
        train_datagen = ImageDataGenerator(rescale=1./255, 
                 shear_range=0.2, 
                 zoom_range=0.2, 
                 horizontal_flip=True) 
        test_datagen = ImageDataGenerator(rescale=1./255) 
        train_batches = get_batches('train', gen=train_datagen, class_mode='binary') 
        valid_batches = get_batches('valid', gen=test_datagen, class_mode='binary') 
        vgg16_fine.fit_generator(train_batches, 
              steps_per_epoch=2000 // BATCH_SIZE, 
              epochs=50, 
              validation_data=valid_batches, 
              validation_steps=800 // BATCH_SIZE) 
        return vgg16_fine 
    
    
    final_model = train_finetuned_model() 
    

    但問題是模型的準確性急劇下降。經過50個時代後,其準確度在50%左右。因此,可能我做錯了什麼。

    參數可能有問題,例如學習率,批量大小等等?

  • 回答

    0

    好了,不知道這是否是一個正確的解決方案,但我可以用這個代碼(可能是主要的原因是降低學習速度和更高的時期)提高精確度至少達70%:

    def train_finetuned_model(lr=1e-5, verbose=True): 
        file_path = get_file('vgg16.h5', VGG16_WEIGHTS_PATH, cache_subdir='models') 
        if verbose: 
         print('Building VGG16 (no-top) model to generate bottleneck features.') 
    
        vgg16_notop = build_vgg_16() 
        vgg16_notop.load_weights(file_path) 
        for _ in range(6): 
         vgg16_notop.pop() 
        vgg16_notop.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy'])  
    
        if verbose: 
         print('Bottleneck features generation.') 
    
        train_batches = get_batches('train', shuffle=False, class_mode=None, batch_size=BATCH_SIZE) 
        train_labels = np.array([0]*1000 + [1]*1000) 
        train_bottleneck = vgg16_notop.predict_generator(train_batches, steps=2000 // BATCH_SIZE) 
        valid_batches = get_batches('valid', shuffle=False, class_mode=None, batch_size=BATCH_SIZE) 
        valid_labels = np.array([0]*400 + [1]*400) 
        valid_bottleneck = vgg16_notop.predict_generator(valid_batches, steps=800 // BATCH_SIZE) 
    
        if verbose: 
         print('Training top model on bottleneck features.') 
    
        top_model = Sequential() 
        top_model.add(Flatten(input_shape=train_bottleneck.shape[1:])) 
        top_model.add(Dense(4096, activation='relu')) 
        top_model.add(Dropout(0.5)) 
        top_model.add(Dense(4096, activation='relu')) 
        top_model.add(Dropout(0.5)) 
        top_model.add(Dense(2, activation='softmax')) 
        top_model.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) 
        top_model.fit(train_bottleneck, to_categorical(train_labels), 
            batch_size=32, epochs=10, 
            validation_data=(valid_bottleneck, to_categorical(valid_labels))) 
    
        if verbose: 
         print('Concatenate new VGG16 (without top layer) with pretrained top model.') 
    
        vgg16_fine = build_vgg_16() 
        vgg16_fine.load_weights(file_path) 
        for _ in range(6): 
         vgg16_fine.pop() 
        vgg16_fine.add(Flatten(name='top_flatten'))  
        vgg16_fine.add(Dense(4096, activation='relu')) 
        vgg16_fine.add(Dropout(0.5)) 
        vgg16_fine.add(Dense(4096, activation='relu')) 
        vgg16_fine.add(Dropout(0.5)) 
        vgg16_fine.add(Dense(2, activation='softmax')) 
        vgg16_fine.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) 
    
        if verbose: 
         print('Loading pre-trained weights into concatenated model') 
    
        for i, layer in enumerate(reversed(top_model.layers), 1): 
         pretrained_weights = layer.get_weights() 
         vgg16_fine.layers[-i].set_weights(pretrained_weights) 
    
        for layer in vgg16_fine.layers[:26]: 
         layer.trainable = False 
    
        if verbose: 
         print('Layers training status:') 
         for layer in vgg16_fine.layers: 
          print('[%6s] %s' % ('' if layer.trainable else 'FROZEN', layer.name))   
    
        vgg16_fine.compile(optimizer=RMSprop(lr=1e-6), loss='binary_crossentropy', metrics=['accuracy']) 
    
        if verbose: 
         print('Train concatenated model on dogs/cats dataset sample.') 
    
        train_datagen = ImageDataGenerator(rescale=1./255, 
                 shear_range=0.2, 
                 zoom_range=0.2, 
                 horizontal_flip=True) 
        test_datagen = ImageDataGenerator(rescale=1./255) 
        train_batches = get_batches('train', gen=train_datagen, class_mode='categorical', batch_size=BATCH_SIZE) 
        valid_batches = get_batches('valid', gen=test_datagen, class_mode='categorical', batch_size=BATCH_SIZE) 
        vgg16_fine.fit_generator(train_batches, epochs=100, 
              steps_per_epoch=2000 // BATCH_SIZE, 
              validation_data=valid_batches, 
              validation_steps=800 // BATCH_SIZE) 
        return vgg16_fine  
    

    我想有一種方法可以通過微調(高達98%)來獲得更好的結果,但我無法通過提供的代碼實現它。

    1

    您完全連接的圖層看起來完全不同於原始的VGG架構。

    # yours 
    Flatten() 
    Dense(256, activation='relu') 
    Dense(1, activation='sigmoid') 
    
    # original 
    Flatten() 
    Dense(4096, activation='relu') 
    Dense(4096, activation='relu') 
    Dense(2, activation='softmax') 
    

    兩點。

    1. 最後一層應該是2-class-softmax而不是sigmoid。我猜想,如果你使用sigmoid,那麼計算出的 精度就不如你所期望的那樣。

    2. 複雜性(神經元和層數)似乎太低。

    +0

    好吧,我明白了。我會嘗試併發布結果。 – devforfu