初始V3微调

时间:2018-01-03 21:18:34

标签: deep-learning keras

我不是来自cs背景,我正在尝试创建一个分类器,在其中我提供包含疾病和图像而没有疾病的图像。我试图使用初始v3进行微调。不幸的是,所有用于微调的示例都是针对vgg-16完成的,并且他们停止说初始v3几乎在所有教程中都经过类似的训练。我正在使用带有tensorflow后端的keras。每个人都告诉我要截断最终的softmax图层并添加两个图层并进行微调。我不知道如何在初始阶段添加图层我还要将我的数据存储在2个文件夹中这也让我头疼因为一些教程加载了cifar数据库,而其他人使用目录,我也对此感到不舒服。任何人都可以提供一些意见吗?

train.py

import os
import sys
import glob
import argparse
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

from keras import backend as K
from keras import __version__
from keras.applications.inception_v3 import InceptionV3, preprocess_input
from keras.models import Model
from keras.layers import Dense, AveragePooling2D, GlobalAveragePooling2D, Input, Flatten, Dropout
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import SGD


IM_WIDTH, IM_HEIGHT = 299, 299 #fixed size for InceptionV3
NB_EPOCHS = 3
BAT_SIZE = 32
FC_SIZE = 1024
#NB_IV3_LAYERS_TO_FREEZE = 172


def get_nb_files(directory):
    """Get number of files by searching directory recursively"""
    if not os.path.exists(directory):
        return 0
    cnt = 0
    for r, dirs, files in os.walk(directory):
        for dr in dirs:
            cnt += len(glob.glob(os.path.join(r, dr + "/*")))
    return cnt


def setup_to_transfer_learn(model, base_model):
    """Freeze all layers and compile the model"""
    for layer in base_model.layers:
        layer.trainable = False
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])


def add_new_last_layer(base_model, nb_classes):
    """Add last layer to the convnet

    Args:
        base_model: keras model excluding top
        nb_classes: # of classes

    Returns:
        new keras model with last layer
    """
    x = base_model.output
    x = AveragePooling2D((8, 8), border_mode='valid', name='avg_pool')(x)
    x = Dropout(0.5)(x)
    x = Flatten()(x)
    predictions = Dense(2, activation='softmax')(x)
    model = Model(input=base_model.input, output=predictions)
    return model

"""
def setup_to_finetune(model):
    Freeze the bottom NB_IV3_LAYERS and retrain the remaining top layers.

    note: NB_IV3_LAYERS corresponds to the top 2 inception blocks in the inceptionv3 arch

    Args:
        model: keras model

    for layer in model.layers[:NB_IV3_LAYERS_TO_FREEZE]:
        layer.trainable = False
    for layer in model.layers[NB_IV3_LAYERS_TO_FREEZE:]:
        layer.trainable = True
    model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy'])
"""

def train(args):
    """Use transfer learning and fine-tuning to train a network on a new dataset"""
    train_img = 'training_set/' 
    validation_img = 'test_set/'
    nb_epoch = int(args.nb_epoch)
    nb_train_samples = get_nb_files(train_img)
    nb_classes = len(glob.glob(train_img + "/*"))
    # data prep
    train_datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest')

    validation_datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest')

    train_generator = train_datagen.flow_from_directory(
        train_img,
        target_size=(299, 299),
        batch_size=32,
        class_mode='categorical')
    validation_generator = validation_datagen.flow_from_directory(
        validation_img,
        target_size=(299, 299),
        batch_size=32,
        class_mode='categorical')
    if(K.image_dim_ordering() == 'th'):
        input_tensor = Input(shape=(3, 299, 299))
    else:
        input_tensor = Input(shape=(299, 299, 3))

    # setup model
    base_model = InceptionV3(input_tensor = input_tensor,weights='imagenet', include_top=False,input_shape=(IM_HEIGHT,IM_WIDTH,3)) #include_top=False excludes final FC layer
    model = add_new_last_layer(base_model, nb_classes)

    # transfer learning
    setup_to_transfer_learn(model, base_model)



    history_tl = model.fit_generator(train_generator,
                                     samples_per_epoch=320,
                                     nb_epoch=nb_epoch,
                                     validation_data=validation_generator,
                                     nb_val_samples=64) 
    model.save(args.output_model_file)
    if args.plot:
        plot_training(history_tl)


def plot_training(history):
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs = range(len(acc))

    plt.plot(epochs, acc, 'r.')
    plt.plot(epochs, val_acc, 'r')
    plt.title('Training and validation accuracy')
    plt.savefig('accuracy.png')

    plt.figure()
    plt.plot(epochs, loss, 'r.')
    plt.plot(epochs, val_loss, 'r-')
    plt.title('Training and validation loss')
    plt.savefig('loss.png')


if __name__=="__main__":            
    a = argparse.ArgumentParser()
    a.add_argument("--nb_epoch", default=NB_EPOCHS)
    a.add_argument("--batch_size", default=BAT_SIZE)
    a.add_argument("--plot", action="store_true")
    a.add_argument("--output_model_file", default="inceptionv3-ft.model")
    args = a.parse_args()

    train(args)

predictions.py

    import sys
    import argparse
    import numpy as np
    from PIL import Image
    import requests
    from io import BytesIO
    import matplotlib
    matplotlib.use('agg')
    import matplotlib.pyplot as plt

    from keras.preprocessing import image
    from keras.models import load_model
    from keras.applications.inception_v3 import preprocess_input


    target_size = (299, 299) #fixed size for InceptionV3 architecture


    def predict(model, img, target_size):
        """Run model prediction on image
        Args:
            model: keras model
            img: PIL format image
            target_size: (w,h) tuple
        Returns:
            list of predicted labels and their probabilities 
        """
        if img.size != target_size:
            img = img.resize(target_size)

        x = image.img_to_array(img)
        x = np.expand_dims(x, axis=0)
        x = preprocess_input(x)
        preds = model.predict(x)
        return preds[0]


    def plot_preds(image, preds):
        """Displays image and the top-n predicted probabilities in a bar graph
        Args:
            image: PIL image
            preds: list of predicted labels and their probabilities
        """



        plt.figure()
        labels = (" NO DR", "DR")
        plt.barh([0, 1], preds, alpha=0.5)
        plt.yticks([0, 1], labels)
        plt.xlabel('Probability')
        plt.xlim(0,1.01)
        plt.tight_layout()
        plt.savefig('out.png')


    if __name__=="__main__":
        a = argparse.ArgumentParser()
        a.add_argument("--image", help="path to image")
        a.add_argument("--image_url", help="url to image")
        a.add_argument("--model")
        args = a.parse_args()

        if args.image is None and args.image_url is None:
            a.print_help()
            sys.exit(1)

        model = load_model(args.model)
        if args.image is not None:
            img = Image.open(args.image)
            preds = predict(model, img, target_size)
            plot_preds(img, preds)

        if args.image_url is not None:
            response = requests.get(args.image_url)
            img = Image.open(BytesIO(response.content))
            preds = predict(model, img, target_size)
            plot_preds(img, preds)

最后,我将通过参数传递图像,并以PNG文件的形式获得结果。

1 个答案:

答案 0 :(得分:2)

您似乎有多个不相关的问题,但几乎所有问题都已在stackoverflow中得到解答。我会尝试编译一些信息给你一些方向:

  

我提供包含疾病和没有疾病的图像的图像[...]每个人都告诉我截断最终的softmax层开始并添加两层并进行微调

我认为在没有“顶级”密集图层(包含softmax)的情况下加载模型会更加清晰,并自己重新添加顶层:

# This will load inception without its top dense layers (there's only 2).
model = InceptionV3(..., weights='imagenet', include_top=False)
x = model.output
# Re-add the layers here, with new weights.
x = GlobalAveragePooling2D(name='avg_pool')(x)
x = Dense(2, activation='softmax', name='predictions')(x)
model = Model(inputs=model.inputs, outputs=x)

请注意,您不应同时使用GlobalAveragePooling2DFlatten,就像在火车脚本中一样。

如果您使用VGG16,架构会有所不同:

model = VGG16(..., weights='imagenet', include_top=False)
x = model.output
x = Flatten(name='flatten')(x)
x = Dense(4096, activation='relu', name='fc1')(x)
x = Dense(4096, activation='relu', name='fc2')(x)
x = Dense(2, activation='softmax', name='predictions')(x)

注意:您可能想要更改这些4096。他们似乎只有两个班级有点高。

  

我也将我的数据存储在2个文件夹中,这也让我感到头疼,因为有些教程加载了cifar数据库,而其他人使用目录,我也对此感到不舒服。

keras中的

cifar数据库是一个玩具示例。调试开始以确保其他所有内容都顺利运行。这就是它可以直接加载到主存储器中的原因 真实的数据集需要存储到磁盘中 如果它们包含在以其标签命名的子代码中,例如:

train/
  |-label_a/
  |-label_b/
  ...
  |-label_z/
valid/
  |-label_a/
  |-label_b/
  ...
  |-label_z/

然后有一个帮手可以自动加载这些图像并将它们与正确的标签相关联:

from keras.preprocessing.image import ImageDataGenerator
from keras.applications.inception_v3 import preprocess_input
# or from keras.applications.vgg16 import preprocess_input

train_dir = '/datasets/problem/train/'
valid_dir = '/datasets/problem/valid/'

g = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest',
    preprocessing_function=preprocess_input)
train = g.flow_from_directory(train_dir,
                              target_size=(256, 256),
                              batch_size=32,
                              shuffle=True)
valid = g.flow_from_directory(valid_dir,
                              target_size=(256, 256),
                              batch_size=32,
                              shuffle=True)

注意:您的火车脚本似乎就是这种情况。

如果您的数据集不是这样的,那么您需要实现一个能够为您加载数据并将其与相应标签相关联的Sequence