CNN for Regression and Image Processing with Mixed-Data input: Issue with image shape

76 Views Asked by At

I am developing a neural network that use image data and a matrix of additional data (all floats) to predict a continuous value. I am new to tensorflow, so I was following a tutorial to learn how to alter my neural network to take both image and float data as input I am having an issue with the code from the tutorial. The main error at the end of the stack trace is as follows:

ValueError: Exception encountered when calling layer "lambda" (type Lambda).

Dimensions must be equal, but are 1 and 3 for '{{node lambda/BiasAdd}} = BiasAdd[T=DT_FLOAT, data_format="NHWC"](lambda/strided_slice, lambda/Const)' with input shapes: [?,999,999,1], [3].

Call arguments received by layer "lambda" (type Lambda):
  • inputs=tf.Tensor(shape=(None, 999, 999, 1), dtype=float32)
  • mask=None
  • training=None

My questions are: How do I solve this error? Is this the proper way to build a neural network with mixed input data? If not, could you please give an example of what the architecture should look like? (with VGGnet-16 architecture for image input ONLY)

The relevant code is as follows. Images are .TIF files.

def get_data(path):
    df = pd.read_csv(path)
    df['cn2_scaled'] = scale_cn2(df['bls_cn2'])
    print('df.head(): ', df.head())

    img_shape = get_img_shape(df['img_path'].iloc[0])
    print('img_shape: ', img_shape)

    return df

def scale_cn2(cn2_arr):
    scaled_cn2_arr = []
    for cn2 in cn2_arr:
        cn2_scaled = ((-1*np.log10(cn2))-12)/5
        scaled_cn2_arr.append(cn2_scaled)
    return scaled_cn2_arr

def reverse_cn2_scaling(cn2_arr):
    reverse_scaled_cn2_arr = []
    for cn2 in cn2_arr:
        reverse_scaled = 10**(-1*((cn2*5)+12))
        reverse_scaled_cn2_arr.append(reverse_scaled)
    return reverse_scaled_cn2_arr

def get_img_shape(img_path):
    img = Image.open(img_path)
    img_arr = np.array(img).astype('float32')
    img_shape = img_arr.shape
    return img_shape

def accuracy(y_true, y_pred):
    y_true = np.log(y_true)
    y_pred = np.log(y_pred)
    return np.abs((y_pred - y_true)/y_true)

def split_data(df):
    # remove unused data cols
    df.drop(['timestamp', 'bls_cn2', 'day', 'hour', 'minute', 'min_hour'], inplace=True, axis=1)
    print('df.head(): ', df.head())
    # shuffle df then split into training, test, validation sets
    shuffled_df = df.sample(frac=1) # shuffle
    first_80_percent = int(len(df)*0.8)
    next_10_percent = first_80_percent + int(len(df)*0.1)
    df_train = shuffled_df[:first_80_percent]
    df_test = shuffled_df[first_80_percent:next_10_percent]
    df_val = shuffled_df[next_10_percent:]

    return df_train, df_test, df_val

def get_X_y_from_df(df):
# separate dataframe into X data, picture data, y data
    X_pic = []
    for img in df['img_path']:
        im = load_img(img, target_size=(999, 999), color_mode='grayscale')
        im = img_to_array(im)*(1./255)
        #im = np.reshape(-1, 999, 999, 1) # not working
        X_pic.append(im)

    X_stats = []
    for i in range(0, len(df['day_sin'])):
        stats_1 = df['day_sin'].iloc[i]
        stats_2 = df['hour_sin'].iloc[i]
        stats_3 = df['Barometric Pressure (mbar)'].iloc[i]
        stats_4 = df['Air Temperature (C)'].iloc[i]
        stats_5 = df['Relative Humidity (%)'].iloc[i]
        stats_6 = df['Shortwave Downwelling Radiation (W/m^2)'].iloc[i]
        stats_7 = df['Soil Temperature (C)'].iloc[i]
        stats_8 = df['Wind Speed (m/s)'].iloc[i]
        X_stats.append([stats_1, stats_2, stats_3, stats_4, stats_5, stats_6, stats_7, stats_8])

    y = []
    for i in range(0, len(df['cn2_scaled'])):
        y_val = df['cn2_scaled'].iloc[i]
        y.append(y_val)

    X_pic, X_stats = np.array(X_pic), np.array(X_stats)
    y = np.array(y)

    return (X_pic, X_stats), y

def initiate_get_X_y(df_train, df_val, df_test):
    (X_train_pic, X_train_stats), y_train = get_X_y_from_df(df_train)
    (X_val_pic, X_val_stats), y_val = get_X_y_from_df(df_val)
    (X_test_pic, X_test_stats), y_test = get_X_y_from_df(df_test)

    return (X_train_pic, X_train_stats), y_train, (X_val_pic, X_val_stats), y_val, (X_test_pic, X_test_stats), y_test

def create_model():
    # define picture (CNN) stream
    ### change shape of inputs (to what??) ###
    input_pic = layers.Input(shape=(999, 999, 1)) # input (define shape)
    f = tf.reshape(input_pic, (-1, 999, 999, 1))
    print('shape: ', f.shape)
    x = layers.Lambda(preprocess_input)(f) # do preprocessing
    x = VGG16(input_shape=(999, 999, 1), include_top=False)(x)
    x = layers.GlobalAveragePooling2D()(x)
    x = layers.Dense(10, activation='relu')(x)
    x = Model(inputs=input_pic, outputs=x)

    # define stats (Feed-Forward) stream
    # shape: # of features/cols in stats dataframe
    input_stats = layers.Input(shape=(8,))
    y = layers.Dense(32, activation='relu')(input_stats)
    y = layers.Dense(10, activation='relu')(y)
    y = Model(inputs=input_stats, outputs=y)

    # concatinate two layers together
    combined = layers.concatenate([x.output, y.output])

    z = layers.Dense(4, activation='relu')(combined)
    z = layers.Dense(1, activation='linear')(z) # regression: output 1 node
    
    model = Model(inputs=[x.input, y.input], outputs=z)

    print(model.summary())
    return model

def train_model(model_save_path, model, X_train_pic, X_train_stats, y_train, X_val_pic, X_val_stats, y_val):
    optimizer = Adam(learning_rate=0.001)
    model.compile(loss='mse', optimizer=optimizer, metrics=['mean_absolute_error'])
    cp = ModelCheckpoint(model_save_path, save_best_only=True)
    model.fit(x=[X_train_pic, X_train_stats], y=y_train,
        validation_data=([X_val_pic, X_val_stats], y_val),
        epochs=15, callbacks=[cp])

    return model

The full stack trace is as follows:

Traceback (most recent call last):
  File "C:\Users\WPRG\Desktop\AI_ML_files\cnn_working.py", line 246, in <module>
    model = create_model()
  File "C:\Users\WPRG\Desktop\AI_ML_files\cnn_working.py", line 134, in create_model
    x = layers.Lambda(preprocess_input)(f) # do preprocessing
  File "C:\Users\WPRG\anaconda3\envs\AI_ML\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "C:\Users\WPRG\anaconda3\envs\AI_ML\lib\site-packages\keras\backend.py", line 6751, in bias_add
    return tf.nn.bias_add(x, bias, data_format="NHWC")
ValueError: Exception encountered when calling layer "lambda" (type Lambda).

Dimensions must be equal, but are 1 and 3 for '{{node lambda/BiasAdd}} = BiasAdd[T=DT_FLOAT, data_format="NHWC"](lambda/strided_slice, lambda/Const)' with input shapes: [?,999,999,1], [3].

Call arguments received by layer "lambda" (type Lambda):
  • inputs=tf.Tensor(shape=(None, 999, 999, 1), dtype=float32)
  • mask=None
  • training=None
0

There are 0 best solutions below