Keras 允许添加计算用户定义的 lambda 函数的层。 我不明白的是 Keras 如何知道计算这个用户定义函数的反向传播的梯度。
使用 Theano/Tensorflow 和基于它们的库的好处之一。它们可以为您提供数学函数和运算的自动梯度计算。
Keras 通过调用获取它们:
# keras/theano_backend.py
def gradients(loss, variables):
return T.grad(loss, variables)
# keras/tensorflow_backend.py
def gradients(loss, variables):
'''Returns the gradients of `variables` (list of tensor variables)
with regard to `loss`.
'''
return tf.gradients(loss, variables, colocate_gradients_with_ops=True)
依次由优化器(keras/optimizers.py)调用
grads = self.get_gradients(loss, params)
来获取梯度,用于为所有params
编写更新规则。 params
这里是各层的可训练权重。但是 Lambda 功能层创建的层没有任何可训练的权重。但它们通过前向概率影响损失函数,从而间接影响其他层可训练权重梯度的计算。
唯一需要编写新梯度计算的时候是定义新的基本数学运算/函数时。此外,当您编写自定义损失函数时,自动梯度几乎总是负责梯度计算。但是,如果您实现自定义函数的分析梯度,您可以选择优化训练(并非总是如此)。例如,softwax 函数可以用 exp、sum 和 div 表示,而 auto grad 可以处理它,但其分析/符号梯度通常在 Theano/Tensorflow 中实现。
要实施新的操作,您可以查看以下链接: http://deeplearning.net/software/theano/extending/extending_theano.html https://www.tensorflow.org/versions/r0.12/how_tos/adding_an_op/index.html
如果您将打印添加到 lambda 函数,如下所示:
import tensorflow as tf
def f(x):
print(x)
return x * 2
m = tf.keras.models.Sequential([
tf.keras.layers.Input((1,)),
tf.keras.layers.Lambda(f),
tf.keras.layers.Dense(1),
])
m.compile(loss="mse", optimizer="SGD")
m.fit(tf.convert_to_tensor([1]), tf.convert_to_tensor([2]))
您会发现在训练期间您的函数实际上从未被使用真实值调用。相反,它使用不同的“占位符”张量调用两次,没有实际值:
Tensor("Placeholder:0", shape=(None, 1), dtype=float32)
Tensor("sequential_1/ExpandDims:0", shape=(None, 1), dtype=float32)
当您对这些张量执行操作时,会生成新的“符号”占位符值,您可以看到这些张量跟踪用于生成它们的操作。
(Pdb) (x * 2)._op
<tf.Operation 'mul_26' type=Mul>
(Pdb) (x * 2)._op.inputs
(<tf.Tensor 'Placeholder:0' shape=(None, 1) dtype=float32>, <tf.Tensor 'mul_27/y:0' shape=() dtype=float32>)
张量流数学运算还专门处理这些符号张量,生成新的符号变量并跟踪它们的生成方式。
(Pdb) tf.reduce_sum(x)._op
<tf.Operation 'Sum_1' type=Sum>
一旦您的函数返回由这些数学运算产生的最终符号张量,因为它可以访问整个图,它可以将其符号化。
但是,因为您的函数只是“象征性”调用,所以您无法使用
if
、while
、for
等定义自己的控制逻辑。相反,您必须使用 tf.cond 或 tf 等函数.while_loop.
替代方案,tf.function可以读取Python代码并用可微等价物替换流程控制。