Skip to main content
 首页 » 编程设计

python之急切模式下的 tensorflow 梯度返回零

2024年09月03日33fff_TT

问题:我正在从保存的检查点加载一个简单的 VGG16。我想在推理过程中生成图像的显着性。当我计算为此所需的梯度(损失 wrt 输入图像)时,我将所有梯度返回为零。非常感谢任何关于我在这里遗漏的想法!

tf版本: tensorflow-2.0alpha-gpu

型号:

import tensorflow as tf 
from tensorflow.keras.applications.vgg16 import VGG16 as KerasVGG16 
from tensorflow.keras.models import Model 
from tensorflow.keras.layers import Flatten, Dense 
 
class VGG16(Model): 
 
    def __init__(self, num_classes, use_pretrained=True): 
 
        super(VGG16, self).__init__() 
        self.num_classes = num_classes 
        self.use_pretrained = use_pretrained 
 
        if use_pretrained: 
            self.base_model = KerasVGG16(weights='imagenet', include_top=False) 
            for layer in self.base_model.layers: 
                layer.trainable = False 
        else: 
            self.base_model = KerasVGG16(include_top=False) 
 
        self.flatten1 = Flatten(name='flatten') 
        self.dense1 = Dense(4096, activation='relu', name='fc1') 
        self.dense2 = Dense(100, activation='relu', name='fc2') 
        self.dense3 = Dense(self.num_classes, activation='softmax', name='predictions') 
 
    def call(self, inputs): 
 
        x = self.base_model(tf.cast(inputs, tf.float32)) 
        x = self.flatten1(x) 
        x = self.dense1(x) 
        x = self.dense2(x) 
        x = self.dense3(x) 
        return x 

我训练这个模型并将它保存到一个检查点并通过以下方式加载它:

model = VGG16(num_classes=2, use_pretrained=False) 
checkpoint = tf.train.Checkpoint(net=model) 
        status = checkpoint.restore(tf.train.latest_checkpoint('./my_checkpoint')) 
status.assert_consumed() 

我验证重量是否正确加载。

获取测试图像

# load my image and make sure its float 
img = tf.convert_to_tensor(image, dtype=tf.float64) 
support_class = tf.convert_to_tensor(support_class, dtype=tf.float64) 

获取渐变:

with tf.GradientTape(persistent=True) as g_tape: 
    g_tape.watch(img) 
    #g_tape.watch(model.base_model.trainable_variables) 
    #g_tape.watch(model.trainable_variables) 
    loss = tf.losses.CategoricalCrossentropy()(support_class, model(img))     
    gradients_wrt_image = g_tape.gradient(loss, 
                                    img, unconnected_gradients=tf.UnconnectedGradients.NONE) 

当我检查梯度时,它们全为零!知道我错过了什么吗?提前致谢!

请您参考如下方法:

梯度不为零,尽管它们非常小:

def almost_equals(a, b, decimal=6): 
    try: 
        np.testing.assert_almost_equal(a, b, decimal=decimal) 
    except AssertionError: 
        return False 
    return True 
 
image = [abs(np.random.normal(size=(32, 32, 3))) for _ in range(20)] 
label = [[0, 1] if i % 3 == 0 else [1, 0] for i in range(20)] 
img = tf.convert_to_tensor(image, dtype=tf.float64) 
support_class = tf.convert_to_tensor(label, dtype=tf.float64) 
loss_fn = tf.losses.CategoricalCrossentropy() 
 
with tf.GradientTape(persistent=True) as tape: 
    tape.watch(img) 
    softmaxed = model(img) 
    loss = loss_fn(support_class, softmaxed) 
    grads = tape.gradient(loss, img, unconnected_gradients=tf.UnconnectedGradients.NONE) 
    # summing up all gradients with reduction over all dimension: 
    print(tf.reduce_sum(grads, axis=None).numpy()) # 0.07137820225818814 
    # comparing to zeros: 
    zeros_like_grads = np.zeros_like(grads.numpy())   
    for decimal in range(10, 0, -1): 
        print('decimal: {0}: {1}'.format(decimal, 
                                         almost_equals(zeros_like_grads, 
                                                       grads.numpy(), 
                                                       decimal=decimal))) 
# decimal: 10: False 
# decimal: 9: False 
# decimal: 8: False 
# decimal: 7: False 
# decimal: 6: False 
# decimal: 5: False 
# decimal: 4: False 
# decimal: 3: True 
# decimal: 2: True 
# decimal: 1: True 

如您所见,仅从 decimal=3 开始返回 True。