我目前正在使用TensorFlow 2.x分析卷积神经网络(CNN)训练过程中梯度的发展。我希望将批次中的每个梯度与整个批次的梯度进行比较。目前,我在每个训练步骤中使用以下简单代码片段:
[...]loss_object = tf.keras.losses.SparseCategoricalCrossentropy()[...]# 一个训练步骤# x_train是一个输入数据批次,y_train是对应的标签def train_step(model, optimizer, x_train, y_train): # 处理批次 with tf.GradientTape() as tape: batch_predictions = model(x_train, training=True) batch_loss = loss_object(y_train, batch_predictions) batch_grads = tape.gradient(batch_loss, model.trainable_variables) # 对整个批次的梯度做一些处理 # ... # 处理当前批次中的每个数据点 for index in range(len(x_train)): with tf.GradientTape() as single_tape: single_prediction = model(x_train[index:index+1], training=True) single_loss = loss_object(y_train[index:index+1], single_prediction) single_grad = single_tape.gradient(single_loss, model.trainable_variables) # 对单个数据输入的梯度做一些处理 # ... # 使用批次梯度更新网络权重 optimizer.apply_gradients(zip(batch_grads, model.trainable_variables)) train_loss(batch_loss) train_accuracy(y_train, batch_predictions)
我的主要问题是,当单独计算每个梯度时,计算时间会激增,尽管TensorFlow在计算批次梯度时应该已经完成了这些计算。原因是GradientTape
以及compute_gradients
总是返回单个梯度,无论是提供单个数据点还是多个数据点。因此,必须为每个数据点进行这种计算。
我知道我可以通过使用为每个数据点计算的所有单个梯度来计算批次的梯度来更新网络,但这在节省计算时间方面只起到次要作用。
有没有更有效的方法来计算单个梯度?
回答:
您可以使用梯度带的jacobian
方法来获取雅可比矩阵,这将为您提供每个单独损失值的梯度:
import tensorflow as tf# 创建一个随机线性问题tf.random.set_seed(0)# 随机输入批次,包含十个四维向量示例x = tf.random.uniform((10, 4))# 随机权重w = tf.random.uniform((4, 2))# 随机批次标签y = tf.random.uniform((10, 2))with tf.GradientTape() as tape: tape.watch(w) # 预测 p = x @ w # 损失 loss = tf.losses.mean_squared_error(y, p)# 计算雅可比矩阵j = tape.jacobian(loss, w)# 雅可比矩阵为您提供每个损失值的梯度print(j.shape)# (10, 4, 2)# 对于第一个示例,损失相对于权重的梯度tf.print(j[0])# [[0.145728424 0.0756840706]# [0.103099883 0.0535449386]# [0.267220169 0.138780832]# [0.280130595 0.145485848]]