train_cnn.py 4.34 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
Train on images split into directories. This assumes we've split
our videos into frames and moved them to their respective folders.

Based on:
https://keras.io/preprocessing/image/
and
https://keras.io/applications/
"""
from keras.applications.inception_v3 import InceptionV3
from keras.optimizers import SGD
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Model
from keras.layers import Dense, GlobalAveragePooling2D
from keras.callbacks import ModelCheckpoint, TensorBoard, EarlyStopping
from data import DataSet
Matt Harvey's avatar
Matt Harvey committed
17
import os.path
18
19
20
21
22

data = DataSet()

# Helper: Save the model.
checkpointer = ModelCheckpoint(
Matt Harvey's avatar
Matt Harvey committed
23
    filepath=os.path.join('data', 'checkpoints', 'inception.{epoch:03d}-{val_loss:.2f}.hdf5',)
24
25
26
27
28
29
30
    verbose=1,
    save_best_only=True)

# Helper: Stop when we stop learning.
early_stopper = EarlyStopping(patience=10)

# Helper: TensorBoard
Matt Harvey's avatar
Matt Harvey committed
31
tensorboard = TensorBoard(log_dir=os.path.join('data', 'logs'))
32
33
34
35
36
37
38
39
40
41
42
43
44

def get_generators():
    train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        horizontal_flip=True,
        rotation_range=10.,
        width_shift_range=0.2,
        height_shift_range=0.2)

    test_datagen = ImageDataGenerator(rescale=1./255)

    train_generator = train_datagen.flow_from_directory(
Matt Harvey's avatar
Matt Harvey committed
45
        os.path.join('data', 'train'),
46
47
48
49
50
51
        target_size=(299, 299),
        batch_size=32,
        classes=data.classes,
        class_mode='categorical')

    validation_generator = test_datagen.flow_from_directory(
Matt Harvey's avatar
Matt Harvey committed
52
        os.path.join('data', 'test'),
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        target_size=(299, 299),
        batch_size=32,
        classes=data.classes,
        class_mode='categorical')

    return train_generator, validation_generator

def get_model(weights='imagenet'):
    # create the base pre-trained model
    base_model = InceptionV3(weights=weights, include_top=False)

    # add a global spatial average pooling layer
    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    # let's add a fully-connected layer
    x = Dense(1024, activation='relu')(x)
69
    # and a logistic layer
70
71
72
    predictions = Dense(len(data.classes), activation='softmax')(x)

    # this is the model we will train
Matt Harvey's avatar
Matt Harvey committed
73
    model = Model(inputs=base_model.input, outputs=predictions)
74
75
    return model

76
def freeze_all_but_top(model):
77
78
79
    """Used to train just the top layers of the model."""
    # first: train only the top layers (which were randomly initialized)
    # i.e. freeze all convolutional InceptionV3 layers
80
    for layer in model.layers[:-2]:
81
82
83
        layer.trainable = False

    # compile the model (should be done *after* setting layers to non-trainable)
84
    model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
85

86
    return model
87

88
def freeze_all_but_mid_and_top(model):
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    """After we fine-tune the dense layers, train deeper."""
    # we chose to train the top 2 inception blocks, i.e. we will freeze
    # the first 172 layers and unfreeze the rest:
    for layer in model.layers[:172]:
        layer.trainable = False
    for layer in model.layers[172:]:
        layer.trainable = True

    # we need to recompile the model for these modifications to take effect
    # we use SGD with a low learning rate
    model.compile(
        optimizer=SGD(lr=0.0001, momentum=0.9),
        loss='categorical_crossentropy',
        metrics=['accuracy', 'top_k_categorical_accuracy'])

    return model

def train_model(model, nb_epoch, generators, callbacks=[]):
    train_generator, validation_generator = generators
    model.fit_generator(
        train_generator,
Matt Harvey's avatar
Matt Harvey committed
110
        steps_per_epoch=100,
111
        validation_data=validation_generator,
Matt Harvey's avatar
Matt Harvey committed
112
113
        validation_steps=10,
        epochs=nb_epoch,
114
115
116
117
118
119
120
121
122
123
        callbacks=callbacks)
    return model

def main(weights_file):
    model = get_model()
    generators = get_generators()

    if weights_file is None:
        print("Loading network from ImageNet weights.")
        # Get and train the top layers.
124
        model = freeze_all_but_top(model)
125
126
127
128
129
130
        model = train_model(model, 10, generators)
    else:
        print("Loading saved model: %s." % weights_file)
        model.load_weights(weights_file)

    # Get and train the mid layers.
131
    model = freeze_all_but_mid_and_top(model)
132
133
134
135
136
137
    model = train_model(model, 1000, generators,
                        [checkpointer, early_stopper, tensorboard])

if __name__ == '__main__':
    weights_file = None
    main(weights_file)