Производные n-мерной функции в Керасе - PullRequest
0 голосов
/ 26 апреля 2018

Скажем, у меня есть двумерная функция, например: z = x ^ 2 + y ^ 2. Я узнал , что на Keras я могу вычислять производные n-го порядка, используя лямбда-слои:

def bivariate_function(x, y):

    x2 = Lambda(lambda u: K.pow(u,2))(x)
    y3 = Lambda(lambda u: K.pow(u,2))(y)

    return Add()([x2,y3])

def derivative(y,x):
    return Lambda(lambda u: K.gradients(u[0],u[1]))([y,x])

f = bivariate_function(x,y)
df_dx = grad(f,x)      # 1st derivative wrt to x
df_dy = grad(f,y)      # 1st derivative wrt to y
df_dx2 = grad(df_dx,x) # 2nd derivative wrt to x
df_dy2 = grad(df_dy,y) # 2nd derivative wrt to y

Однако, как применить этот подход к производным NN-выхода по отношению к входам в функции потерь? Я не могу (?) Просто подать два входа в плотный слой (как созданные выше).

Например, пытаясь использовать в качестве убытка сумму первой производной по первой переменной и второй производной по второй переменной (т.е. d / dx + d² / dy²), используя Input(shape=(2,)), мне удалось прийти здесь:

import tensorflow as tf
from keras.models import *
from keras.layers import *
from keras import backend as K

def grad(f, x):
    return Lambda(lambda u: K.gradients(u[0], u[1]), output_shape=[2])([f, x])

def custom_loss(input_tensor,output_tensor):
    def loss(y_true, y_pred):

        df1 = grad(output_tensor,input_tensor)
        df2 = grad(df1,input_tensor)
        df = tf.add(df1[0,0],df2[0,1])      

        return df
    return loss

input_tensor = Input(shape=(2,))
hidden_layer = Dense(100, activation='relu')(input_tensor)
output_tensor = Dense(1, activation='softplus')(hidden_layer)

model = Model(input_tensor, output_tensor)
model.compile(loss=custom_loss(input_tensor,output_tensor), optimizer='sgd')

xy = np.mgrid[-3.0:3.0:0.1, -3.0:3.0:0.1].reshape(2,-1).T
model.fit(x=xy,y=xy, batch_size=10, epochs=100, verbose=2)

Но мне просто кажется, что я делаю это неправильно. Еще хуже, после первой эпохи я получаю только nan.

1 Ответ

0 голосов
/ 26 апреля 2018

Основной вопрос здесь теоретический.

Вы пытаетесь минимизировать d output_tensor / d x + d 2 output_tensor / д 2 х * +1022 *. Ваша сеть просто линейно объединяет входные данные x -s, однако, с активациями relu и softplus. Что ж, softplus добавляет немного изюминки к этому, но у этого также есть монотонно увеличивающаяся производная. Поэтому для того, чтобы производная была настолько малой, насколько это возможно, сеть будет просто увеличивать входной сигнал до максимально возможного с отрицательными весами, чтобы сделать производную как можно меньшей (то есть действительно большим отрицательным числом), в какой-то момент достигнув NaN . Я уменьшил первый слой до 5 нейронов и запустил модель для 2 эпох, и вес стал:

( 'dense_1',
[массив ([[1,0536456, -0,32706773, 0,0072904, 0,01986691, 0,9854533],
[-0,3242108, -0,56753945, 0,8098554, -0,7545874, 0,2716419]],
DTYPE = float32),
массив ([0,01207507, 0,09927677, -0,01768671, -0,12874101, 0,0210707], dtype = float32)])

( 'dense_2', [массив ([[- 0,4332278], [0,6621602], [-0,07802075], [-0,5798264], [-0,40561703]],
DTYPE = float32),
массив ([0.11167384], dtype = float32)])

Вы можете видеть, что второй слой держит отрицательный знак, где первый имеет положительный, и наоборот. (Уклоны не получают никакого градиента, потому что они не способствуют производной. Ну, не совсем верно из-за softplus, но более или менее.)

Таким образом, вам нужно придумать функцию потерь, которая не расходится в сторону экстремальных значений параметров, поскольку она не будет обучаемой, она будет просто увеличивать значения весов до тех пор, пока они NaN .

Это была версия, которую я запускал:

import tensorflow as tf
from keras.models import *
from keras.layers import *
from keras import backend as K

def grad(f, x):
    return Lambda(lambda u: K.gradients(u[0], u[1]), output_shape=[2])([f, x])

def ngrad(f, x, n):
    if 0 == n:
        return f
    else:
        return Lambda(lambda u: K.gradients(u[0], u[1]), output_shape=[2])([ngrad( f, x, n - 1 ), x])

def custom_loss(input_tensor,output_tensor):
    def loss(y_true, y_pred):

        _df1 = grad(output_tensor,input_tensor)
        df1 = tf.Print( _df1, [ _df1 ], message = "df1" )
        _df2 = grad(df1,input_tensor)
        df2 = tf.Print( _df2, [ _df2 ], message = "df2" )
        df = tf.add(df1,df2)      

        return df
    return loss

input_tensor = Input(shape=(2,))
hidden_layer = Dense(5, activation='softplus')(input_tensor)
output_tensor = Dense(1, activation='softplus')(hidden_layer)

model = Model(input_tensor, output_tensor)
model.compile(loss=custom_loss(input_tensor,output_tensor), optimizer='sgd')

xy = np.mgrid[-3.0:3.0:0.1, -3.0:3.0:0.1].reshape( 2, -1 ).T
#print( xy )
model.fit(x=xy,y=xy, batch_size=10, epochs=2, verbose=2)
for layer in model.layers: print(layer.get_config()['name'], layer.get_weights())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...