Search code examples
pythontensorflowkerastime-seriesmetrics

Custom metric in keras with three parameters


Hi everyone I'm building a deepNN using keras for forecasting time series, to be more specific I'm using a Conv1D so inputs are tensors with this kind of shape:

[samples, window_size, 1]
input_2  = Input(shape=(window_size, 1),name= "input_CNN")

My problem is that I'd like to have a custom metric that needs to recieve 3 parameters instead of the 2 standar y_pred and y_true. This because my metric needs to be safely computed as it does not rely on divisions with values that could be equal to zero (e.g. as done in percentage errors when 𝑌𝑡 = 0).The complete formula of my metric is showed below: enter image description here

How can I pass the y_true_N and have a metric function like that?

def rmsse(y_true, y_pred, y_true_N):  
   
    N = len(y_true)
    numerator   = K.mean(K.square(y_true - y_pred))
    denominator = K.mean(K.square(y_true_N[1:N]-y_true_N[0:N-1]))
    return K.sqrt(numerator/denominator)

where the y_true_N correspond to all the target values in the training while y_true and y_pred correspond to the target in the validation. I hope I've been clear, if anyone has an example can please show me how to get it? Thanks in advance


Solution

  • Considering that your denominator is a fixed quantity defined as you reported, I think there is no problem to define the third input in your loss function outside

    here a code example:

    def rmsse(y_true, y_pred):  
    
        numerator   = K.mean(K.square(y_true - y_pred))
        denominator = K.mean(K.square(y_true_N[1:N]-y_true_N[0:N-1]))
        return K.sqrt(numerator/denominator)
    
    N = 1900
    X = np.random.uniform(0,100, (N+100, 30)).astype('float32')
    y = np.random.uniform(0,100, N+100).astype('float32')
    y_true_N = y[:N].astype('float32')
    
    
    inp = Input((30))
    x = Dense(50)(inp)
    x = Dense(1)(x)
    model = Model(inp, x)
    model.compile('adam', loss=rmsse)
    
    model.fit(X[:N], y[:N], epochs=3, validation_data=(X[N:], y[N:]))