-
一般情况下我们使用一个batch的数据计算出一个平均的loss,再使用这个loss反向传播求得模型参数的梯度并更新,例如:
loss = tf.reduce_mean(y - y_pred) # 文中y和y_pred的shape均为:[b, 1],其中b是batch_size.
这种情况比较好理解,loss只是一个值,其反向传播时对于每个参数也值计算出一个梯度值。
-
而如果我们没有使用
tf.reduce_mean()
等类似求平均的操作,即:loss = y - y_pred
求出的loss其shape是[b, 1]。即batch中的每一个样本都有一个对应的loss值。这个时候如果我们继续调用:
grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables))
也不会报错,不禁让人疑惑这个
tape.gradient()
是怎么处理loss不是标量值的情况的。 -
先说结论:当loss不是单值时
tape.gradient(loss, variables)
会首先针对loss中每一个单值对variables求梯度得到多套梯度。再对每套梯度对应元素求和合并为一套梯度返回。 -
验证:
-
其他补充
-
tf.keras.losses.BinaryCrossentopy
等大写字母开头的损失类在我们传入y, y_pred
时会自动对所有样本的loss求平均,其返回一个标量的loss。 -
tf.keras.losses.binary_crossentropy()
等小写字母开头的函数式接口在我们传入y, y_pred
时不会对所有样本的loss求平均,其返回一个张量形式的losses,维度为[batch, 1]。
-