|
''' |
|
Copyright 2017 TensorFlow Authors and Kent Sommer |
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); |
|
you may not use this file except in compliance with the License. |
|
You may obtain a copy of the License at |
|
|
|
http://www.apache.org/licenses/LICENSE-2.0 |
|
|
|
Unless required by applicable law or agreed to in writing, software |
|
distributed under the License is distributed on an "AS IS" BASIS, |
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
See the License for the specific language governing permissions and |
|
limitations under the License. |
|
''' |
|
import tensorflow as tf |
|
|
|
|
|
import warnings |
|
|
|
from keras.layers import MaxPooling2D, Convolution2D, AveragePooling2D |
|
from keras.layers import Input, Dropout, Dense, Flatten, Activation |
|
from keras.layers import BatchNormalization |
|
from keras.layers import concatenate |
|
from keras import regularizers |
|
from keras import initializers |
|
from keras.models import Model |
|
|
|
from keras import backend as K |
|
|
|
from keras.utils import get_file |
|
|
|
|
|
|
|
|
|
|
|
|
|
WEIGHTS_PATH = 'https://github.com/kentsommer/keras-inceptionV4/releases/download/2.1/inception-v4_weights_tf_dim_ordering_tf_kernels.h5' |
|
WEIGHTS_PATH_NO_TOP = 'https://github.com/kentsommer/keras-inceptionV4/releases/download/2.1/inception-v4_weights_tf_dim_ordering_tf_kernels_notop.h5' |
|
|
|
|
|
def preprocess_input(x): |
|
x = tf.divide(x, 255.0) |
|
x = tf.subtract(x, 0.5) |
|
x = tf.multiply(x, 2.0) |
|
return x |
|
|
|
|
|
def conv2d_bn(x, nb_filter, num_row, num_col, |
|
padding='same', strides=(1, 1), use_bias=False): |
|
""" |
|
Utility function to apply conv + BN. |
|
(Slightly modified from https://github.com/fchollet/keras/blob/master/keras/applications/inception_v3.py) |
|
""" |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
x = Convolution2D(nb_filter, (num_row, num_col), |
|
strides=strides, |
|
padding=padding, |
|
use_bias=use_bias, |
|
kernel_regularizer=regularizers.l2(0.00004), |
|
kernel_initializer=initializers.VarianceScaling(scale=2.0, mode='fan_in', distribution='normal', seed=None))(x) |
|
x = BatchNormalization(axis=channel_axis, momentum=0.9997, scale=False)(x) |
|
x = Activation('relu')(x) |
|
return x |
|
|
|
|
|
def block_inception_a(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
branch_0 = conv2d_bn(input, 96, 1, 1) |
|
|
|
branch_1 = conv2d_bn(input, 64, 1, 1) |
|
branch_1 = conv2d_bn(branch_1, 96, 3, 3) |
|
|
|
branch_2 = conv2d_bn(input, 64, 1, 1) |
|
branch_2 = conv2d_bn(branch_2, 96, 3, 3) |
|
branch_2 = conv2d_bn(branch_2, 96, 3, 3) |
|
|
|
branch_3 = AveragePooling2D((3,3), strides=(1,1), padding='same')(input) |
|
branch_3 = conv2d_bn(branch_3, 96, 1, 1) |
|
|
|
x = concatenate([branch_0, branch_1, branch_2, branch_3], axis=channel_axis) |
|
return x |
|
|
|
|
|
def block_reduction_a(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
branch_0 = conv2d_bn(input, 384, 3, 3, strides=(2,2), padding='valid') |
|
|
|
branch_1 = conv2d_bn(input, 192, 1, 1) |
|
branch_1 = conv2d_bn(branch_1, 224, 3, 3) |
|
branch_1 = conv2d_bn(branch_1, 256, 3, 3, strides=(2,2), padding='valid') |
|
|
|
branch_2 = MaxPooling2D((3,3), strides=(2,2), padding='valid')(input) |
|
|
|
x = concatenate([branch_0, branch_1, branch_2], axis=channel_axis) |
|
return x |
|
|
|
|
|
def block_inception_b(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
branch_0 = conv2d_bn(input, 384, 1, 1) |
|
|
|
branch_1 = conv2d_bn(input, 192, 1, 1) |
|
branch_1 = conv2d_bn(branch_1, 224, 1, 7) |
|
branch_1 = conv2d_bn(branch_1, 256, 7, 1) |
|
|
|
branch_2 = conv2d_bn(input, 192, 1, 1) |
|
branch_2 = conv2d_bn(branch_2, 192, 7, 1) |
|
branch_2 = conv2d_bn(branch_2, 224, 1, 7) |
|
branch_2 = conv2d_bn(branch_2, 224, 7, 1) |
|
branch_2 = conv2d_bn(branch_2, 256, 1, 7) |
|
|
|
branch_3 = AveragePooling2D((3,3), strides=(1,1), padding='same')(input) |
|
branch_3 = conv2d_bn(branch_3, 128, 1, 1) |
|
|
|
x = concatenate([branch_0, branch_1, branch_2, branch_3], axis=channel_axis) |
|
return x |
|
|
|
|
|
def block_reduction_b(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
branch_0 = conv2d_bn(input, 192, 1, 1) |
|
branch_0 = conv2d_bn(branch_0, 192, 3, 3, strides=(2, 2), padding='valid') |
|
|
|
branch_1 = conv2d_bn(input, 256, 1, 1) |
|
branch_1 = conv2d_bn(branch_1, 256, 1, 7) |
|
branch_1 = conv2d_bn(branch_1, 320, 7, 1) |
|
branch_1 = conv2d_bn(branch_1, 320, 3, 3, strides=(2,2), padding='valid') |
|
|
|
branch_2 = MaxPooling2D((3, 3), strides=(2, 2), padding='valid')(input) |
|
|
|
x = concatenate([branch_0, branch_1, branch_2], axis=channel_axis) |
|
return x |
|
|
|
|
|
def block_inception_c(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
branch_0 = conv2d_bn(input, 256, 1, 1) |
|
|
|
branch_1 = conv2d_bn(input, 384, 1, 1) |
|
branch_10 = conv2d_bn(branch_1, 256, 1, 3) |
|
branch_11 = conv2d_bn(branch_1, 256, 3, 1) |
|
branch_1 = concatenate([branch_10, branch_11], axis=channel_axis) |
|
|
|
|
|
branch_2 = conv2d_bn(input, 384, 1, 1) |
|
branch_2 = conv2d_bn(branch_2, 448, 3, 1) |
|
branch_2 = conv2d_bn(branch_2, 512, 1, 3) |
|
branch_20 = conv2d_bn(branch_2, 256, 1, 3) |
|
branch_21 = conv2d_bn(branch_2, 256, 3, 1) |
|
branch_2 = concatenate([branch_20, branch_21], axis=channel_axis) |
|
|
|
branch_3 = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(input) |
|
branch_3 = conv2d_bn(branch_3, 256, 1, 1) |
|
|
|
x = concatenate([branch_0, branch_1, branch_2, branch_3], axis=channel_axis) |
|
return x |
|
|
|
|
|
def inception_v4_base(input): |
|
if K.image_data_format() == 'channels_first': |
|
channel_axis = 1 |
|
else: |
|
channel_axis = -1 |
|
|
|
|
|
net = conv2d_bn(input, 32, 3, 3, strides=(2,2), padding='valid') |
|
net = conv2d_bn(net, 32, 3, 3, padding='valid') |
|
net = conv2d_bn(net, 64, 3, 3) |
|
|
|
branch_0 = MaxPooling2D((3,3), strides=(2,2), padding='valid')(net) |
|
|
|
branch_1 = conv2d_bn(net, 96, 3, 3, strides=(2,2), padding='valid') |
|
|
|
net = concatenate([branch_0, branch_1], axis=channel_axis) |
|
|
|
branch_0 = conv2d_bn(net, 64, 1, 1) |
|
branch_0 = conv2d_bn(branch_0, 96, 3, 3, padding='valid') |
|
|
|
branch_1 = conv2d_bn(net, 64, 1, 1) |
|
branch_1 = conv2d_bn(branch_1, 64, 1, 7) |
|
branch_1 = conv2d_bn(branch_1, 64, 7, 1) |
|
branch_1 = conv2d_bn(branch_1, 96, 3, 3, padding='valid') |
|
|
|
net = concatenate([branch_0, branch_1], axis=channel_axis) |
|
|
|
branch_0 = conv2d_bn(net, 192, 3, 3, strides=(2,2), padding='valid') |
|
branch_1 = MaxPooling2D((3,3), strides=(2,2), padding='valid')(net) |
|
|
|
net = concatenate([branch_0, branch_1], axis=channel_axis) |
|
|
|
|
|
|
|
for idx in range(4): |
|
net = block_inception_a(net) |
|
|
|
|
|
|
|
net = block_reduction_a(net) |
|
|
|
|
|
|
|
for idx in range(7): |
|
net = block_inception_b(net) |
|
|
|
|
|
|
|
net = block_reduction_b(net) |
|
|
|
|
|
|
|
for idx in range(3): |
|
net = block_inception_c(net) |
|
|
|
return net |
|
|
|
|
|
def inception_v4(num_classes, dropout_keep_prob, weights, include_top, input_shape=(299, 299, 3)): |
|
''' |
|
Creates the inception v4 network |
|
|
|
Args: |
|
num_classes: number of classes |
|
dropout_keep_prob: float, the fraction to keep before final layer. |
|
|
|
Returns: |
|
logits: the logits outputs of the model. |
|
''' |
|
|
|
|
|
if K.image_data_format() == 'channels_first': |
|
inputs = Input((3, input_shape[1], input_shape[2])) |
|
else: |
|
inputs = Input(input_shape) |
|
|
|
|
|
x = inception_v4_base(inputs) |
|
|
|
|
|
|
|
if include_top: |
|
|
|
x = AveragePooling2D((8,8), padding='valid')(x) |
|
x = Dropout(dropout_keep_prob)(x) |
|
x = Flatten()(x) |
|
|
|
x = Dense(units=num_classes, activation='softmax')(x) |
|
|
|
model = Model(inputs, x, name='inception_v4') |
|
|
|
|
|
if weights == 'imagenet': |
|
if K.image_data_format() == 'channels_first': |
|
if K.backend() == 'tensorflow': |
|
warnings.warn('You are using the TensorFlow backend, yet you ' |
|
'are using the Theano ' |
|
'image data format convention ' |
|
'(`image_data_format="channels_first"`). ' |
|
'For best performance, set ' |
|
'`image_data_format="channels_last"` in ' |
|
'your Keras config ' |
|
'at ~/.keras/keras.json.') |
|
if include_top: |
|
weights_path = get_file( |
|
'inception-v4_weights_tf_dim_ordering_tf_kernels.h5', |
|
WEIGHTS_PATH, |
|
cache_subdir='models', |
|
md5_hash='9fe79d77f793fe874470d84ca6ba4a3b') |
|
else: |
|
weights_path = get_file( |
|
'inception-v4_weights_tf_dim_ordering_tf_kernels_notop.h5', |
|
WEIGHTS_PATH_NO_TOP, |
|
cache_subdir='models', |
|
md5_hash='9296b46b5971573064d12e4669110969') |
|
model.load_weights(weights_path) |
|
return model |
|
|
|
|
|
def InceptionV4(num_classes=1001, dropout_prob=0.2, weights=None, include_top=True, input_shape=(299, 299, 3)): |
|
return inception_v4(num_classes, dropout_prob, weights, include_top, input_shape=input_shape) |