假设我有一个双变量函数,例如:z = x ^ 2 + y ^ 2。 I learned在Keras上我可以使用Lambda图层计算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输出的导数以及损失函数中的输入?我不能(?)只是简单地将两个输入馈送到密集层(如上面创建的那样)。
例如,尝试使用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)
作为第一个变量和第二个导数wrt到第二个变量(即d / dx +d²/dy²)的总和,我管理到达这里:
nan
但感觉就像我没有以正确的方式做到这一点。更糟糕的是,在第一个时代之后我才刚刚获得<?php
function () {
}
。
答案 0 :(得分:1)
这里的主要问题是理论上的。
您正在尝试最小化d output_tensor / d x + d 2 的 output_tensor 强> / d 2 的 X 即可。您的网络只是线性地组合输入 x -s,但是,relu
和softplus
激活。嗯,softplus给它带来了一点点扭曲,但它也有一个单调增加的衍生物。因此,为了使导数尽可能小,网络将只使用负权重尽可能地扩大输入,以使导数尽可能小(即,一个非常大的负数),在某些时候达到的 NaN的即可。我已经将第一层减少到5个神经元并将模型运行了2个时期,并且权重变为:
( 'dense_1',
[array([[1.0536456,-0.32706773,0.0072904,0.01986691,0.9854533],
[-0.3242108,-0.56753945,0.8098554,-0.7545874,0.2716419]],
D型= FLOAT32),
阵列([0.01207507,0.09927677,-0.01768671,-0.12874101,0.0210707], dtype = float32)])( 'dense_2', [array([[ - 0.4332278],[0.6621602],[ - 0.080802075],[ - 0.5798264],[ - 0.40561703]],
D型= 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())