当前位置: 首页 > 面试题库 >

ValueError:没有为任何变量提供渐变-Tensorflow 2.0 / Keras

云欣嘉
2023-03-14
问题内容

我正在尝试使用Keras实现一个简单的序列到序列模型。但是,我一直看到以下内容ValueError

ValueError: No gradients provided for any variable: ['simple_model/time_distributed/kernel:0', 'simple_model/time_distributed/bias:0', 'simple_model/embedding/embeddings:0', 'simple_model/conv2d/kernel:0', 'simple_model/conv2d/bias:0', 'simple_model/dense_1/kernel:0', 'simple_model/dense_1/bias:0'].

像其他的问题这个还是看这个问题在Github上认为,这可能有一些做的交叉熵损失函数;
但我看不到我在做什么错。

我不认为这是问题所在,但我要提一提,tf-nightly==2.2.0.dev20200410确切地说,我是每晚构建的TensorFlow 。

以下代码是一个独立的示例,应从上面重现异常:

import random
from functools import partial

import tensorflow as tf
from tensorflow import keras
from tensorflow_datasets.core.features.text import SubwordTextEncoder

EOS = '<eos>'
PAD = '<pad>'

RESERVED_TOKENS = [EOS, PAD]
EOS_ID = RESERVED_TOKENS.index(EOS)
PAD_ID = RESERVED_TOKENS.index(PAD)

dictionary = [
    'verstehen',
    'verstanden',
    'vergessen',
    'verlegen',
    'verlernen',
    'vertun',
    'vertan',
    'verloren',
    'verlieren',
    'verlassen',
    'verhandeln',
]

dictionary = [word.lower() for word in dictionary]


class SimpleModel(keras.models.Model):

    def __init__(self, params, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.params = params
        self.out_layer = keras.layers.Dense(1, activation='softmax')

        self.model_layers = [
            keras.layers.Embedding(params['vocab_size'], params['vocab_size']),
            keras.layers.Lambda(lambda l: tf.expand_dims(l, -1)),
            keras.layers.Conv2D(1, 4),
            keras.layers.MaxPooling2D(1),
            keras.layers.Dense(1, activation='relu'),
            keras.layers.TimeDistributed(self.out_layer)
        ]

    def call(self, example, training=None, mask=None):
        x = example['inputs']
        for layer in self.model_layers:
            x = layer(x)
        return x


def sample_generator(text_encoder: SubwordTextEncoder, max_sample: int = None):
    count = 0

    while True:
        random.shuffle(dictionary)

        for word in dictionary:

            for i in range(1, len(word)):

                inputs = word[:i]
                targets = word

                example = dict(
                    inputs=text_encoder.encode(inputs) + [EOS_ID],
                    targets=text_encoder.encode(targets) + [EOS_ID],
                )
                count += 1

                yield example

                if max_sample is not None and count >= max_sample:
                    print('Reached max_samples (%d)' % max_sample)
                    return


def make_dataset(generator_fn, params, training):

    dataset = tf.data.Dataset.from_generator(
        generator_fn,
        output_types={
            'inputs': tf.int64,
            'targets': tf.int64,
        }
    ).padded_batch(
        params['batch_size'],
        padded_shapes={
            'inputs': (None,),
            'targets': (None,)
        },
    )

    if training:
        dataset = dataset.map(partial(prepare_example, params=params)).repeat()

    return dataset


def prepare_example(example: dict, params: dict):
    # Make sure targets are one-hot encoded
    example['targets'] = tf.one_hot(example['targets'], depth=params['vocab_size'])
    return example


def main():

    text_encoder = SubwordTextEncoder.build_from_corpus(
        iter(dictionary),
        target_vocab_size=1000,
        max_subword_length=6,
        reserved_tokens=RESERVED_TOKENS
    )

    generator_fn = partial(sample_generator, text_encoder=text_encoder, max_sample=10)

    params = dict(
        batch_size=20,
        vocab_size=text_encoder.vocab_size,
        hidden_size=32,
        max_input_length=30,
        max_target_length=30
    )

    model = SimpleModel(params)

    model.compile(
        optimizer='adam',
        loss='categorical_crossentropy',
    )

    train_dataset = make_dataset(generator_fn, params, training=True)
    dev_dataset = make_dataset(generator_fn, params, training=False)

    # Peek data
    for train_batch, dev_batch in zip(train_dataset, dev_dataset):
        print(train_batch)
        print(dev_batch)
        break

    model.fit(
        train_dataset,
        epochs=1000,
        steps_per_epoch=100,
        validation_data=dev_dataset,
        validation_steps=100,
    )


if __name__ == '__main__':
    main()

更新资料

  • 要点链接
  • Github问题链接

问题答案:

您的代码中存在两套不同的问题,可以分为语法问题和体系结构问题。提出的错误(即No gradients provided for any variable)与语法问题有关,我将在下面主要解决这些问题,但是在此之后,我也会尝试为您提供有关体系结构问题的一些提示。

语法问题的主要原因是有关模型的命名输入和输出。当模型具有多个输入和/或输出层时,用Keras命名的输入和输出最有用。但是,您的模型只有一个输入层和一个输出层。因此,在这里使用命名的输入和输出可能不是很有用,但是如果您是我的决定,我将解释如何正确完成它。

首先,请记住,使用Keras模型时,从任何输入管道(无论是Python生成器还是tf.data.Dataset)生成的数据都应以元组(即(input_batch, output_batch)或)的形式提供(input_batch, output_batch, sample_weights)。而且,正如我说的那样,这是Keras处理输入管道时到处都可以使用的格式,即使我们使用命名的输入和输出作为字典也是如此。

例如,如果我想使用输入/输出命名,并且我的模型有两个名为“ words”和“ importance”的输入层,还有两个名为“ output1”和“
output2”的输出层,则应采用以下格式:

({'words': words_data, 'importance': importance_data},
 {'output1': output1_data, 'output2': output2_data})

因此,如您在上面看到的,它是一个元组,其中元组的每个元素都是一个字典;第一个元素对应于模型的输入,第二个元素对应于模型的输出。现在,根据这一点,让我们看看应该对您的代码进行哪些修改:

  • 在其中,sample_generator我们应该返回一则字典,而不是一个字典。所以:

    example = tuple([
     {'inputs': text_encoder.encode(inputs) + [EOS_ID]},
     {'targets': text_encoder.encode(targets) + [EOS_ID]},
    

    ])

  • make_dataset函数中,的输入参数tf.data.Dataset应遵守此规定:

    output_types=(
    {'inputs': tf.int64},
    {'targets': tf.int64}
    

    )

    padded_shapes=(
    {‘inputs’: (None,)},
    {‘targets’: (None,)}
    )

  • 的签名prepare_example及其主体也应修改:

    def prepare_example(ex_inputs: dict, ex_outputs: dict, params: dict):
    # Make sure targets are one-hot encoded
    ex_outputs['targets'] = tf.one_hot(ex_outputs['targets'], depth=params['vocab_size'])
    return ex_inputs, ex_outputs
    
  • 最后,call子类化模型的方法:

    return {'targets': x}
    
  • 还有一件事:name构造图层时,我们还应该使用参数将这些名称放在相应的输入和输出图层上(例如Dense(..., name='output');但是,由于我们在Model此处使用子类来定义模型,因此无需这样做。

好了,这些将解决输入/输出问题,并且与梯度有关的错误将消失。但是,如果在应用以上修改后运行代码,则仍然会出现有关不兼容形状的错误。如前所述,您的模型中存在架构问题,下面将简要介绍。

正如您提到的,这应该是一个从序列到序列的模型。因此,输出是单热编码矢量的序列,其中每个矢量的长度等于(目标序列)词汇量。结果,softmax分类器应具有与词汇表大小一样多的单位(注意:注意:在任何模型或问题中,切勿使用只有一个单位的softmax层;这完全是错误的!请思考为什么是错误的!):

self.out_layer = keras.layers.Dense(params['vocab_size'], activation='softmax')

接下来要考虑的事实是,我们正在处理一维序列(即标记/单词序列)。因此,在这里使用2D卷积和2D池化层没有意义。您可以使用它们的一维对应物,也可以将其替换为RNN层之类的东西。结果,该Lambda层也应被去除。另外,如果要使用卷积和池化,则应适当调整每一层中的过滤器数量以及池大小(即,一个conv过滤器Conv1D(1,...)可能不是最佳选择,并且池大小为1毫无意义)。

此外,Dense最后一层之前只有一个单元的那一层可能会严重限制模型的表示能力(即,本质上是模型的瓶颈)。增加其单位数量,或将其删除。

另一件事是,没有理由不对开发集的标签进行一次热编码。相反,它们应该像训练集的标签一样被一键编码。因此,应该完全删除的training参数,make_generator或者,如果您有其他用例,则应使用training=True传递给make_dataset函数的参数来创建dev数据集。

最后,在完成所有这些更改之后,您的模型可能会开始工作并开始适合数据。但是经过几批之后,您可能会再次遇到形状不兼容的错误。根据需要(通过使用即那是因为你与未知维度生成输入数据,还可以使用轻松填充的方法来垫每批高达(None,)的padded_shapes)。要解决此问题,您应该确定固定的输入/输出尺寸(例如,通过考虑输入/输出序列的固定长度),然后调整模型的体系结构或超参数(例如,转换内核大小,转换填充,池大小)
,添加更多层等)以及padded_shapes相应地争论。即使您希望模型支持可变长度的输入/输出序列,也应该在模型的体系结构,超参数以及自padded_shapes变量中考虑它
。由于此解决方案取决于您脑海中的任务和所需的设计,并且没有万能的解决方案,因此,我不会对此做进一步评论,而是由您自己解决。但这是一个可行的解决方案(可能根本不是,也可能不是最优),只是为了给您一个想法:

self.out_layer = keras.layers.Dense(params['vocab_size'], activation='softmax')

self.model_layers = [
    keras.layers.Embedding(params['vocab_size'], params['vocab_size']),
    keras.layers.Conv1D(32, 4, padding='same'),
    keras.layers.TimeDistributed(self.out_layer)
]


# ...
padded_shapes=(
    {'inputs': (10,)},
    {'targets': (10,)}
)


 类似资料:
  • 我正在使用tensorflow训练“Show and tell”模型,该模型自动生成图像的字幕。我怎么会犯这个错误。 这是回溯: ValueError:没有为任何变量提供渐变,检查您的图表中不支持渐变的操作,在变量之间["tf。变量'word_embedding: 0'形状=(2943,256)dtype=float32_ref 我知道这个错误是因为在优化过程中有一个变量不能保持梯度,而这个变量又

  • 问题内容: 我已经写了一个tensorflow CNN,它已经受过训练。我希望将其还原以在几个示例上运行它,但不幸的是它吐出来了: ValueError:没有要保存的变量 我的评估代码可以在这里找到: 问题答案: 在必须创建 后 要恢复(或保存)的变量。此外,必须在与这些变量相同的图形中创建它。 假设还可以在模型中创建变量,则在此行之后添加保护程序创建应该可以: 另外,您必须将创建的新内容传递给构

  • 问题内容: 默认情况下,我的条形图始终使用渐变颜色绘制。我只想要一种 没有任何样式效果 的简单颜色。 有人可以帮忙吗? 码: 谢谢 问题答案: 问题出在您正在使用中。JFreeChart版本1.0.13的默认设置是使用,它将为条形添加金属感。如果您想要“旧”外观,解决方案是使用。 那应该做。 另外,如果要使用JFreeChart’s ,则可以在初始化渲染器之前通过调用static方法来强制其使用。

  • Another hard-to-write CSS3 feature is a gradient. You have to repeat long gradient definition multiple times with different vendor prefixes. Also, if you want to cover all gradient-supported browsers,

  • 使用渐变填充可以在要应用其他任何颜色时应用渐变颜色混和。创建渐变填色是在一个或多个对象间创建颜色平滑过渡的好方法。您可以将渐变存储为色板,从而便于将渐变应用于多个对象。 注:如果要创建颜色可以沿不同方向顺畅分布的单个多色对象,请使用网格对象。 要查看使用渐变来改进绘画的视频,请参阅 www.adobe.com/go/lrvid4017_ai_cn。有关创建渐变的教程,请参阅 “Unleash th

  • 将一个表达式提炼为一个变量,并使用变量替换原来的表达式. 操作步骤: 菜单栏: Refactor —> Extract —> Variable... 快捷键: Mac: option + Command + V