我发现计算的梯度取决于 tf.function 装饰器的相互作用,如下所示。
首先,我为二元分类创建一些合成数据
tf.random.set_seed(42)
np.random.seed(42)
x=tf.random.normal((2,1))
y=tf.constant(np.random.choice([0,1],2))
Run Code Online (Sandbox Code Playgroud)
然后我定义两个仅在 tf.function 装饰器中不同的损失函数
weights=tf.constant([1.,.1])[tf.newaxis,...]
def customloss1(y_true,y_pred,sample_weight=None):
y_true_one_hot=tf.one_hot(tf.cast(y_true,tf.uint8),2)
y_true_scale=tf.multiply(weights,y_true_one_hot)
return tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true_scale,y_pred))
@tf.function
def customloss2(y_true,y_pred,sample_weight=None):
y_true_one_hot=tf.one_hot(tf.cast(y_true,tf.uint8),2)
y_true_scale=tf.multiply(weights,y_true_one_hot)
return tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true_scale,y_pred))
Run Code Online (Sandbox Code Playgroud)
然后我制作了一个非常简单的逻辑回归模型,删除了所有花哨的东西以保持简单
tf.random.set_seed(42)
np.random.seed(42)
model=tf.keras.Sequential([
tf.keras.layers.Dense(2,use_bias=False,activation='softmax',input_shape=[1,])
])
Run Code Online (Sandbox Code Playgroud)
最后定义两个函数来计算上述损失函数的梯度,一个被tf.function修饰,另一个不被tf.function修饰
def get_gradients1(x,y):
with tf.GradientTape() as tape1:
p1=model(x)
l1=customloss1(y,p1)
with tf.GradientTape() as tape2:
p2=model(x)
l2=customloss2(y,p2)
gradients1=tape1.gradient(l1,model.trainable_variables)
gradients2=tape2.gradient(l2,model.trainable_variables)
return gradients1, gradients2
@tf.function
def get_gradients2(x,y):
with tf.GradientTape() as tape1:
p1=model(x)
l1=customloss1(y,p1)
with tf.GradientTape() as tape2:
p2=model(x)
l2=customloss2(y,p2)
gradients1=tape1.gradient(l1,model.trainable_variables)
gradients2=tape2.gradient(l2,model.trainable_variables)
return gradients1, gradients2
Run Code Online (Sandbox Code Playgroud)
现在当我跑步时
get_gradients1(x,y)
Run Code Online (Sandbox Code Playgroud)
我明白了
([<tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[ 0.11473544, …Run Code Online (Sandbox Code Playgroud)