【问题标题】:TF 2.0 Error: Gradients does not exist for variables during training using gradienttapeTF 2.0 错误:使用梯度带训练期间变量不存在梯度
【发布时间】:2019-07-27 20:42:50
【问题描述】:

我尝试使用 tf 2.0 中的批处理标准化层创建一个类,但是它给了我一个错误,即变量不存在梯度。我尝试直接使用批处理标准化,但它也给了我同样的错误。似乎它没有训练与批量标准化步骤相关的变量。

我尝试使用 model.trainable_variables 而不是 model.variables,但也没有用。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.utils import to_categorical
import numpy as np
import matplotlib.pyplot as plt
import os
from scipy import ndimage

learning_rate = 0.001
training_epochs = 15
batch_size = 100

tf.random.set_seed(777)

cur_dir = os.getcwd()
ckpt_dir_name = 'checkpoints'
model_dir_name = 'minst_cnn_best'

checkpoint_dir = os.path.join(cur_dir, ckpt_dir_name, model_dir_name)
os.makedirs(checkpoint_dir, exist_ok=True)

checkpoint_prefix = os.path.join(checkpoint_dir, model_dir_name)



mnist = tf.keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_images = train_images.astype(np.float32) /255.
test_images = test_images.astype(np.float32) /255.
print(train_images.shape, test_images.shape)
train_images = np.expand_dims(train_images, axis = -1)
test_images = np.expand_dims(test_images, axis = -1)
print(train_images.shape, test_images.shape)

train_labels = to_categorical(train_labels, 10)
test_labels = to_categorical(test_labels, 10)

train_dataset = tf.data.Dataset.from_tensor_slices((train_images, 
                                                    train_labels)).shuffle(buffer_size = 100000).batch(batch_size)
test_dataset = tf.data.Dataset.from_tensor_slices((test_images, 
                                                    test_labels)).batch(batch_size)

class ConvBNRelu(tf.keras.Model):
    def __init__(self, filters, kernel_size=3, strides=1, padding='SAME'):
        super(ConvBNRelu, self).__init__()
        self.conv = keras.layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides, 
                                        padding=padding, kernel_initializer='glorot_normal')
        self.batchnorm = tf.keras.layers.BatchNormalization()
    def call(self, inputs, training=False):
        layer = self.conv(inputs)
        layer = self.batchnorm(layer)
        layer = tf.nn.relu(layer)
        return layer    

class DenseBNRelu(tf.keras.Model):
    def __init__(self, units):
        super(DenseBNRelu, self).__init__()
        self.dense = keras.layers.Dense(units=units, kernel_initializer='glorot_normal')
        self.batchnorm = tf.keras.layers.BatchNormalization()
    def call(self, inputs, training=False):
        layer = self.dense(inputs)
        layer = self.batchnorm(layer)
        layer = tf.nn.relu(layer)
        return layer

class MNISTModel(tf.keras.Model):
    def __init__(self):
        super(MNISTModel, self).__init__()
        self.conv1 = ConvBNRelu(filters=32, kernel_size=[3, 3], padding='SAME')        
        self.pool1 = keras.layers.MaxPool2D(padding='SAME')
        self.conv2 = ConvBNRelu(filters=64, kernel_size=[3, 3], padding='SAME')
        self.pool2 = keras.layers.MaxPool2D(padding='SAME')
        self.conv3 = ConvBNRelu(filters=128, kernel_size=[3, 3], padding='SAME')
        self.pool3 = keras.layers.MaxPool2D(padding='SAME')
        self.pool3_flat = keras.layers.Flatten()
        self.dense4 = DenseBNRelu(units=256)
        self.drop4 = keras.layers.Dropout(rate=0.4)
        self.dense5 = keras.layers.Dense(units=10, kernel_initializer='glorot_normal')
    def call(self, inputs, training=False):
        net = self.conv1(inputs)        
        net = self.pool1(net)
        net = self.conv2(net)
        net = self.pool2(net)
        net = self.conv3(net)
        net = self.pool3(net)
        net = self.pool3_flat(net)
        net = self.dense4(net)
        net = self.drop4(net)
        net = self.dense5(net)
        return net

models = []
num_models = 5
for m in range(num_models):
    models.append(MNISTModel())

def loss_fn(model, images, labels):
    logits = model(images, training=True)
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,
                                                               labels=labels))
    return loss   

def grad(model, images, labels):
    with tf.GradientTape() as tape:
        loss = loss_fn(model, images, labels)
    return tape.gradient(loss, model.variables)

def evaluate(models, images, labels):
    predictions = np.zeros_like(labels)
    for model in models:
        logits = model(images, training=False)
        predictions += logits
    correct_prediction = tf.equal(tf.argmax(predictions, 1), tf.argmax(labels, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    return accuracy

optimizer = keras.optimizers.Adam(learning_rate = learning_rate)


checkpoints = []
for m in range(num_models):
    checkpoints.append(tf.train.Checkpoint(cnn=models[m]))


for epoch in range(training_epochs):
    avg_loss = 0.
    avg_train_acc = 0.
    avg_test_acc = 0.
    train_step = 0
    test_step = 0    

    for images, labels in train_dataset:
        for model in models:
            grads = grad(model, images, labels)                
            optimizer.apply_gradients(zip(grads, model.variables))            
            loss = loss_fn(model, images, labels)
            avg_loss += loss / num_models
        acc = evaluate(models, images, labels)
        avg_train_acc += acc
        train_step += 1
    avg_loss = avg_loss / train_step
    avg_train_acc = avg_train_acc / train_step

    for images, labels in test_dataset:        
        acc = evaluate(models, images, labels)        
        avg_test_acc += acc
        test_step += 1    
    avg_test_acc = avg_test_acc / test_step    

    print('Epoch:', '{}'.format(epoch + 1), 'loss =', '{:.8f}'.format(avg_loss), 
          'train accuracy = ', '{:.4f}'.format(avg_train_acc), 
          'test accuracy = ', '{:.4f}'.format(avg_test_acc))


    for idx, checkpoint in enumerate(checkpoints):
        checkpoint.save(file_prefix=checkpoint_prefix+'-{}'.format(idx))

print('Learning Finished!')

W0727 20:27:05.344142 140332288718656 optimizer_v2.py:982] 变量不存在梯度 ['mnist_model/conv_bn_relu/batch_normalization/moving_mean:0', 'mnist_model/conv_bn_relu/batch_normalization/moving_variance:0', 'mnist_model conv_bn_relu_1/batch_normalization_1/moving_mean:0', 'mnist_model/conv_bn_relu_1/batch_normalization_1/moving_variance:0', 'mnist_model/conv_bn_relu_2/batch_normalization_2/moving_mean:0', 'mnist_model/conv_bn_relu_2/batch_normalization_2/moving_variance:0',model batch_normalization_3/moving_mean:0', 'mnist_model/dense_bn_relu/batch_normalization_3/moving_variance:0'] 最小化损失时。 W0727 20:27:05.407717 140332288718656 deprecation.py:323] 来自 /usr/local/lib/python3.6/dist-packages/tensorflow_core/python/keras/optimizer_v2/optimizer_v2.py:460:BaseResourceVariable.constraint(来自 tensorflow. python.ops.resource_variable_ops) 已弃用,将在未来版本中删除。 更新说明: 在优化器更新步骤之后手动应用约束。 W0727 20:27:05.499249 140332288718656 optimizer_v2.py:982]渐变不存在变量[ 'mnist_model_1 / conv_bn_relu_3 / batch_normalization_4 / moving_mean:0', 'mnist_model_1 / conv_bn_relu_3 / batch_normalization_4 / moving_variance:0',“mnist_model_1 / conv_bn_relu_4 / batch_normalization_5 /moving_mean:0'、'mnist_model_1/conv_bn_relu_4/batch_normalization_5/moving_variance:0'、'mnist_model_1/conv_bn_relu_5/batch_normalization_6/moving_mean:0'、'mnist_model_1/conv_bn_relu_5/batch_normalization_6/moving_variance:0'、'mnist_model_1/meanatch_normalization_bnense_7_moving_1/meanatch_normalization_bnense_moving_1/meanatch_normalization_bnense :0', 'mnist_model_1/dense_bn_relu_1/batch_normalization_7/moving_variance:0'] 最小化损失时。 ...

【问题讨论】:

标签: python-3.x tensorflow tensorflow2.0


【解决方案1】:

您正在计算相对于 model.variables 的损失梯度:此集合不仅包含可训练变量(模型权重),还包含不可训练变量,例如批量计算的移动均值和方差归一化层。

您必须计算相对于trainable_variables 的梯度。总之换行

 return tape.gradient(loss, model.variables)

optimizer.apply_gradients(zip(grads, model.variables)) 

 return tape.gradient(loss, model.trainable_variables)

optimizer.apply_gradients(zip(grads, model.trainable_variables)) 

【讨论】:

  • 这些参数不能仅在评估模式下训练。在训练期间,他们需要能够接受训练,除非他们被冻结。我在这里错过了什么吗?
  • 是的,你错过了一些东西 :) 在训练阶段,这些变量(移动均值、移动方差)需要更新(不可训练!),但没有梯度流过它们。这些变量没有使用梯度下降更新,它们只是接收到一个新值的更新(但这不是训练,这只是一个通常的变量更新)
  • 当然可以,但是在模型中我们同时拥有:gamma、beta、moving_mean 和moving_variane。在 model.trainable_variables 集合中,您有 beta 和 gamma 变量,但是您在训练期间收集的移动均值和移动方差存储在 model.variables 集合中 - 这些是您仅在每次训练时更新的不可训练参数使用移动均值/方差公式。
  • import tensorflow as tf model = tf.keras.Sequential( [tf.keras.layers.Input((100)), tf.keras.layers.BatchNormalization()] ) print("所有模型变量") print(model.variables) print("仅可训练变量") print(model.trainable_variables)
  • 哦,我真傻!我现在明白了,我完全错过了你对移动平均线的强调!
猜你喜欢
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-06-02
  • 2016-11-09
  • 2020-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多