ValueError:没有为任何变量提供梯度 - Tensorflow 2.0

时间:2021-03-12 17:08:38

标签: python tensorflow deep-learning tensorflow2.0 generative-adversarial-network

我正在尝试从训练有素的 MNIST GAN 模型中找到 MNIST 图像的相应潜在代码。我计划做的是对定义为目标和生成样本之间的距离的损失应用梯度下降。随着生成的样本离目标越近,loss越小,对应的latent code就是我需要的。

这是我的代码:

import numpy as np
import tensorflow as tf
from tensorflow.keras import Model
from tensorflow.keras import Sequential
import tensorflow.keras.backend as K
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers
from tensorflow.keras.layers import *
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.losses import MeanSquaredError
import random

### Load MNIST data
(data_x, _), _ = mnist.load_data()
data_x = np.reshape(np.asarray(data_x), [60000, 28*28]).astype(float)
train = data_x[:1024]
test = data_x[-10:]

### GAN setting
generator = Sequential([
    Dense(7 * 7 * 64, input_shape=[100]),
    BatchNormalization(),
    LeakyReLU(),
    Reshape([7, 7, 64]),
    UpSampling2D([2, 2]),
    Conv2DTranspose(64, [3, 3], padding='same'),
    BatchNormalization(),
    LeakyReLU(),
    UpSampling2D([2, 2]),
    Conv2DTranspose(1, [3, 3], padding='same', activation='sigmoid')
])

discriminator = Sequential([
    Conv2D(64, [3, 3], padding='same', input_shape=[28, 28, 1]),
    BatchNormalization(),
    LeakyReLU(),
    MaxPool2D([2, 2]),
    Conv2D(64, [3, 3], padding='same'),
    BatchNormalization(),
    LeakyReLU(),
    MaxPool2D([2, 2]),
    Flatten(),
    Dense(128),
    BatchNormalization(),
    LeakyReLU(),
    Dense(1, activation='sigmoid')
])

x_input = Input([28, 28, 1])
g_sample_input = Input([100])

log_clip = Lambda(lambda x: K.log(x + 1e-3))

sample_score = discriminator(generator(g_sample_input))

d_loss = (
    - log_clip(discriminator(x_input)) 
    - log_clip(1.0 - sample_score)
)
fit_discriminator = Model(inputs=[x_input, g_sample_input], outputs=d_loss)
fit_discriminator.add_loss(d_loss)
generator.trainable = False
for layer in generator.layers:
    if isinstance(layer, BatchNormalization):
        layer.trainable = True
fit_discriminator.compile(optimizer=Adam(0.001))
generator.trainable = True

g_loss = (
    - log_clip(sample_score)
)
fit_generator = Model(inputs=g_sample_input, outputs=g_loss)
fit_generator.add_loss(g_loss)
discriminator.trainable = False
for layer in discriminator.layers:
    if isinstance(layer, BatchNormalization):
        layer.trainable = True
fit_generator.compile(optimizer=Adam(0.001))
discriminator.trainable = True

### GAN training
train_x = train.reshape([-1, 28, 28, 1]) / 255
batch_size = 64
for i in range(10000):
    x = train_x[random.sample(range(len(train_x)), batch_size)]
    g_sample = np.random.uniform(-1, 1, [batch_size, 100])
    fit_discriminator.fit([K.constant(x), K.constant(g_sample)])
    fit_generator.fit(g_sample)
    
### Search for latent code
target = (test[0] / 255).reshape([28, 28])
mse = MeanSquaredError()
z = np.random.uniform(-1, 1, [1, 100])
z_t = tf.Variable(z, trainable=True)
opt = SGD(learning_rate=0.1)

for _ in range(10):
    loss_fn = lambda: mse(target,
                          generator(z_t.numpy())[0].numpy().reshape([28, 28]))

    opt.minimize(loss_fn, var_list=[z_t])

我收到此错误:

<块引用>

ValueError: 没有为任何变量提供梯度:['Variable:0']。

Tensorflow 似乎无法从这种损失中计算梯度。

如果损失来自另一个模型,有没有办法计算梯度?或者有没有办法不计算梯度就达到我的目标?

1 个答案:

答案 0 :(得分:0)

我想我找到了重点。

Tensorflow 根据图形计算梯度。所以我们应该总是把每一个操作都放在图中。

我的代码的错误是由tensor-numpy转换引起的。因为一旦我们将张量转换为一个 numpy 数组,它就会被带出图形并且 Tensorflow 无法再跟踪它。

这是我的新代码,现在运行良好:

mse = MeanSquaredError()
target = (test[0] / 255).reshape([28, 28])
target_t = tf.convert_to_tensor(target)
z = np.random.uniform(-1, 1, [1, 100])
z_t = tf.Variable(z, trainable=True)
opt = SGD(learning_rate=0.1)

for _ in range(10):
    loss_fn = lambda: mse(target_t,
                          tf.reshape(tf.cast(generator(z_t), tf.float64), [28, 28]))
    opt.minimize(loss_fn, var_list=[z_t])

(这里只显示最后一段代码,其他部分保持不变。)