Search code examples
tensorflowkerasregressionconv-neural-networknon-linear-regression

Regressing on an image to predict a scalar


Given 256x256 rgb input images, I'm trying to regress to predict a point on the X axis of the image (0-48000)

Initially, I tried [mobile_net -> GlobalAveragePooling2D -> several Dense layers]. I didn't realize Pooling was discarding the spatial information.

Last night, I trained on a simpler net, the loss decreased all night, but it's predicting negative values.

How can I modify this architecture to predict a 0-48000 scalar?

    model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(64, kernel_size=3, activation='relu', input_shape=(256,256,3)),
    tf.keras.layers.Dropout(0.5),      
    tf.keras.layers.Conv2D(32, kernel_size=3, activation='relu'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(1,   kernel_initializer='normal'),
])
model.compile(loss='mse', optimizer='adam', metrics=['mse', 'mae', 'mape']) #

EDIT:

Inferring from my netwrok, I'm getting vastly different outputs, each run, for the SAME file. How is that possible?

Infer outputs, running multiple times on the same file:

-312864.9444580078
762.7029418945312
193352.7603149414

Here is the inference fn:

def infer(checkpoint_path):
    png_file  = ['3023_28338_26_m.png', '3023_28338_26_m.png'][1]
    test_file = data_root + png_file
    onset     = png_file.strip('_m.png.').split('_')[1]
    img       = load_and_preprocess_from_path_label(test_file, 0)
    tst       = np.expand_dims(img[0], axis=0)
    model     = load_model_and_checkpoint(checkpoint_path)
    val       = model.predict(tst)[0][0] * 48000

Here is the final epoch of training.

2019-05-26 11:11:56.698907: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:150] Shuffle buffer filled.
94/95 [============================>.] - ETA: 0s - loss: 0.0063 - mse: 0.0063 - mae: 0.0627 - mape: 93.2817   
Epoch 00100: saving model to /media/caseybasichis/sp_data/sp_data/datasets/one_sec_onset_01/model7.ckpt
95/95 [==============================] - 47s 500ms/step - loss: 0.0063 - mse: 0.0063 - mae: 0.0626 - mape: 93.2076

Here is the latest network.

mobile_net = tf.keras.applications.ResNet50(input_shape=(256, 256, 3), include_top=False, weights='imagenet')
mobile_net.trainable=False

model = tf.keras.Sequential([
    mobile_net,
    tf.keras.layers.Dropout(0.25),  
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, kernel_initializer='normal', activation='relu'),
    tf.keras.layers.BatchNormalization(axis=chanDim),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(1,  kernel_initializer='normal', activation='linear'), # activation='sigmoid'
])
model.compile(loss='mse', optimizer='adam', metrics=['mse', 'mae', 'mape']) # mean_squared_logarithmic_error

Solution

  • You can simply use Sigmoid activation on the last layer and multiply the output by the scale (in a Lambda layer or preferably just scale the output out side the network)

    model.add(Activation('sigmoid'))
    model.add(Lambda(lambda x: 48000*x))
    

    or

    model.add(Activation('sigmoid'))
    ...
    model.fit(x_train, y_train/48000.0)