You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TensorFlow 1.10自定义Model子类调用fit_generator报错求解决

解决TensorFlow 1.10中子类化Model使用fit_generator的问题

这个报错的核心原因是:在TensorFlow 1.10版本中,继承tf.keras.Model的子类化模型(也就是你自定义call方法的这种)还未支持fit_generator。这类模型属于"未构建"状态,只有在第一次接收输入时才会初始化权重和计算图,而旧版本的fit_generator没有处理这个预构建逻辑,因此抛出了NotImplementedError。

下面给你三种可行的解决方案,你可以根据自己的需求选择:

方案一:手动触发模型构建(最简单的修改)

在调用compile之前,先传入一个符合输入形状的张量调用模型,让模型提前完成构建。这样fit_generator就能正常识别模型的结构了。同时注意:fit_generator需要传入生成器实例,你原来的代码里写的generate是函数本身,要改成generate()。

修改后的主函数代码:

if __name__ == "__main__":
    test_net = TestNet(class_count=5)
    # 手动构建模型:传入带batch维度的dummy输入(模型输入要求是(batch_size, seq_len, features))
    dummy_input = np.zeros(shape=(1, 100, 3))
    test_net(dummy_input)
    
    optimizer = tf.keras.optimizers.Adam()
    test_net.compile(optimizer, loss=segmentation_loss)
    # 注意这里要调用generate()得到生成器实例
    history = test_net.fit_generator(generate(), steps_per_epoch=1000, epochs=10)

方案二:改用函数式API定义模型

如果不想手动处理模型构建,可以改用Keras的函数式API来定义模型。函数式API的模型在定义时就已经完成了构建,天然支持fit_generator,代码结构也很清晰:

import tensorflow as tf
import numpy as np

# 用函数式API重定义模型
def TestNet(class_count):
    inputs = tf.keras.Input(shape=(None, 3))
    conv_output = tf.keras.layers.Conv1D(class_count, kernel_size=1)(inputs)
    return tf.keras.Model(inputs=inputs, outputs=conv_output)

# 损失函数和生成器保持不变
def segmentation_loss(labels, logits):
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=labels, logits=logits)
    return tf.reduce_mean(cross_entropy)

def generate():
    while True:
        yield (np.zeros(shape=(100,3)), np.zeros(shape=(100)))

if __name__ == "__main__":
    test_net = TestNet(class_count=5)
    optimizer = tf.keras.optimizers.Adam()
    test_net.compile(optimizer, loss=segmentation_loss)
    history = test_net.fit_generator(generate(), steps_per_epoch=1000, epochs=10)

方案三:手动实现训练循环(完全自定义)

如果需要更灵活的训练逻辑,可以放弃fit_generator,自己写循环迭代生成器,用train_on_batch或者手动计算梯度更新。这种方式完全避开了旧版本的API限制:

if __name__ == "__main__":
    test_net = TestNet(class_count=5)
    optimizer = tf.keras.optimizers.Adam()
    
    # 先手动构建模型
    dummy_input = np.zeros(shape=(1, 100, 3))
    test_net(dummy_input)
    
    epochs = 10
    steps_per_epoch = 1000
    
    for epoch in range(epochs):
        print(f"Epoch {epoch+1}/{epochs}")
        total_loss = 0.0
        
        for step in range(steps_per_epoch):
            # 从生成器获取单样本,添加batch维度(模型要求输入带batch轴)
            x, y = next(generate())
            x_batch = np.expand_dims(x, axis=0)
            y_batch = np.expand_dims(y, axis=0)
            
            # 使用train_on_batch执行一次梯度更新
            loss = test_net.train_on_batch(x_batch, y_batch)
            total_loss += loss
            
            # 每100步打印一次损失
            if step % 100 == 0:
                print(f"Step {step:4d} | Loss: {loss:.4f}")
        
        avg_loss = total_loss / steps_per_epoch
        print(f"Epoch {epoch+1} | Average Loss: {avg_loss:.4f}\n")

额外注意点

你原来的生成器返回的样本是(100,3)和(100),没有batch维度,而Keras模型的输入默认需要带batch轴(形状为(batch_size, seq_len, features)),所以在喂给模型时一定要用np.expand_dims添加batch维度,否则会报形状不匹配的错误。

内容的提问来源于stack exchange,提问作者Miiller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:01:56