1
$\begingroup$

I've lately ran into an interesting problem, trying to teach a dense network a seemingly simple monotonous function- to regress a logarithmic function;

When this function was centered around 0 it seemed to be able to find decent solutions converging at ~0 error, but if this target function was shifted horizontally, the network doesn't seem to find a solution and after an initial learning phase converges to a high error level (so it doesn't seem to be just an input normalization (i.e. zero mean) issue per se, which is expected to slow down convergence but not prevent it altogether)

Below is a minimal code example to reproduce the problem, with the variable is_zero_centered controlling the two running regimes. attached are also images of results with the two states of this variable and their learning curves (which sometimes jump but this seems unrelated) zero centered 1 learning curve zero centered 1 response zero centered 0 learning curve zero centered 0 response.

Any insights or solutions will be greatly appreciated!!

PS The real problem this is a schema of is more complex and prohibits simply shifting the inputs to around 0- so the challenge is finding a solution with the training procedure or model itself

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
            
ratio_min_log10 = -6
ratio_max_log10 = 0

model_fcn_width = 16#64
model_fcn_layers = 2

TRAIN_BATCH_SIZE = 8192

numepochs = 5000

is_zero_centered = 1 #0

def make_toy(sizer,ratiorange):
    rati_log = ratiorange[0]+np.random.rand(sizer)*np.diff(ratiorange)[0]
    rati = 10**rati_log
    rati.shape=(sizer,1,1)
    
    # input transformation- 
    batchy =  (1*(1-is_zero_centered)-rati)*0.7

    da_ds_y = -rati_log 
    da_ds_x = batchy

    return((da_ds_x,da_ds_y)) 

class toysynth(tf.keras.utils.Sequence):
    def __init__(self, batch_size,lenny,interi=(ratio_min_log10,ratio_max_log10)):
        self.batch_size = batch_size
        self.lenny = lenny
        self.interi = interi

    def __len__(self):
        return self.lenny//self.batch_size

    def __getitem__(self, idx):
        return make_toy(self.batch_size,self.interi)

def plot_loss(history_orig,n=0,titlee=''):
    
    histi = history_orig

    plt.plot(histi['loss'][n:], label='loss')
    plt.plot(histi['val_loss'][n:], label='val_loss')
    #plt.ylim([0, 1])
    plt.xlabel('Epoch')
    plt.ylabel('MSE')
    plt.legend()
    plt.title(titlee)
    plt.grid(True)
    
def main():           
    # model definition:
    inputs = tf.keras.Input((1, 1))
    x = tf.keras.layers.Flatten(name='flatten')(inputs)
    for ii in range(model_fcn_layers):
        x = tf.keras.layers.Dense(model_fcn_width,activation='relu')(x) 
    outputs = tf.keras.layers.Dense(1, activation='linear')(x)
            
    model = tf.keras.Model(inputs, outputs)
        
    model.compile(
        optimizer=tf.keras.optimizers.Adam(learning_rate=4e-3),
        loss='mse',
        metrics=tf.keras.metrics.MeanSquaredError())

    train_generator = toysynth(TRAIN_BATCH_SIZE,TRAIN_BATCH_SIZE*4)
    test_generator = toysynth(TRAIN_BATCH_SIZE,TRAIN_BATCH_SIZE)

    histi = model.fit(train_generator, epochs=numepochs,validation_data=test_generator,verbose=1)
  
    test_generator = toysynth(TRAIN_BATCH_SIZE,TRAIN_BATCH_SIZE)

    yyy=[]
    zib=[]
    
    for batch_now in test_generator:

        zib_batch=model.predict(batch_now[0],batch_size=TRAIN_BATCH_SIZE);

        [yyy.append(yyyy) for yyyy in batch_now[1]]
        [zib.append(ziby) for ziby in zib_batch]

    #plt.figure()
    plt.scatter(yyy,zib)
    plt.axis('square')
    plt.xlim(-1, 6.5)
    plt.ylim(-1, 6.5)
    plt.xlabel('true -log10(ratio)')
    plt.ylabel('predicted')
    plt.title('validation is_zero_centered: ' + str(is_zero_centered))
    plt.grid()
    plt.savefig('toyfig7' +str(is_zero_centered) +'.png')
    plt.close()

    plt.figure()
    plot_loss(histi.history)
    plt.ylim(0, 3)
    plt.title('is_zero_centered: ' + str(is_zero_centered))
    plt.savefig('toyfig6'+str(is_zero_centered)+'.png')
    plt.close()

if __name__ == '__main__':
    main()
$\endgroup$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.