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

加载TensorFlow循环神经网络模型报错:调用my_model层时遇异常

问题描述

使用TensorFlow与Python基于循环神经网络(RNN)生成语录,模型训练及保存过程无报错,但在另一个脚本中加载模型时触发ValueError,提示无法找到匹配的SavedModel具体调用函数。模型保存目录包含子文件夹与.pb文件,附错误信息及加载代码。

错误信息

ValueError: Exception encountered when calling layer "my_model" "                 f"(type MyModel).

Could not find matching concrete function to call loaded from the SavedModel. Got:
  Positional arguments (4 total):
    * <tf.Tensor 'inputs:0' shape=(1, None) dtype=int64>
    * None
    * True
    * False
  Keyword arguments: {}

 Expected these arguments to match one of the following 4 option(s):

Option 1:
  Positional arguments (4 total):
    * TensorSpec(shape=(None, 100), dtype=tf.int64, name='inputs')
    * None
    * False
    * False
  Keyword arguments: {}

Option 2:
  Positional arguments (4 total):
    * TensorSpec(shape=(None, 100), dtype=tf.int64, name='inputs')
    * None
    * False
    * True
  Keyword arguments: {}

Option 3:
  Positional arguments (4 total):
    * TensorSpec(shape=(None, 100), dtype=tf.int64, name='input_1')
    * None
    * False
    * False
  Keyword arguments: {}

Option 4:
  Positional arguments (4 total):
    * TensorSpec(shape=(None, 100), dtype=tf.int64, name='input_1')
    * None
    * False
    * True
  Keyword arguments: {}

Call arguments received by layer "my_model" "                 f"(type MyModel):
  • args=('tf.Tensor(shape=(1, None), dtype=int64)',)
  • kwargs={'states': 'None', 'return_state': 'True', 'training': 'False'}

加载模型代码

import tensorflow as tf
import time

path_to_file = tf.keras.utils.get_file('data.txt', 'file:///C:/Users/sebas/Desktop/quites/data.txt')
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
vocab = sorted(set(text))
ids_from_chars = tf.keras.layers.StringLookup(
    vocabulary=list(vocab), mask_token=None)
chars_from_ids = tf.keras.layers.StringLookup(
    vocabulary=ids_from_chars.get_vocabulary(), invert=True, mask_token=None)

new_model = tf.keras.models.load_model('quoteModel')
class OneStep(tf.keras.Model):
  def __init__(self, model, chars_from_ids, ids_from_chars, temperature=1.0):
    super().__init__()
    self.temperature = temperature
    self.model = model
    self.chars_from_ids = chars_from_ids
    self.ids_from_chars = ids_from_chars
    skip_ids = self.ids_from_chars(['[UNK]'])[:, None]
    sparse_mask = tf.SparseTensor(
        values=[-float('inf')]*len(skip_ids),
        indices=skip_ids,
        dense_shape=[len(ids_from_chars.get_vocabulary())])
    self.prediction_mask = tf.sparse.to_dense(sparse_mask)

  @tf.function
  def generate_one_step(self, inputs, states=None):
    input_chars = tf.strings.unicode_split(inputs, 'UTF-8')
    input_ids = self.ids_from_chars(input_chars).to_tensor()
    predicted_logits, states = self.model(inputs=input_ids, states=states,
                                          return_state=True)
    predicted_logits = predicted_logits[:, -1, :]
    predicted_logits = predicted_logits/self.temperature
    predicted_logits = predicted_logits + self.prediction_mask
    predicted_ids = tf.random.categorical(predicted_logits, num_samples=1)
    predicted_ids = tf.squeeze(predicted_ids, axis=-1)
    predicted_chars = self.chars_from_ids(predicted_ids)
    return predicted_chars, states

one_step_model = OneStep(new_model, chars_from_ids, ids_from_chars)
start = time.time()
states = None
next_char = tf.constant(['I'])
result = [next_char]

for n in range(1000):
  next_char, states = one_step_model.generate_one_step(next_char, states=states)
  result.append(next_char)

result = tf.strings.join(result)
end = time.time()
print(result[0].numpy().decode('utf-8'), '\n\n' + '_'*80)

print(one_step_model.generate_one_step("I"))

解决方案

1. 核心问题分析

错误显示模型训练时接受的输入形状是(None, 100)(固定序列长度100),但生成时传入的输入形状是(1, None)(变长序列),同时调用时指定的return_state=True在模型保存的签名中匹配逻辑异常,导致找不到可用的调用函数。

2. 具体修复方法

方法一:调整生成代码的输入形状

在generate_one_step方法中,将输入序列强制调整为训练时的固定长度100:

@tf.function
def generate_one_step(self, inputs, states=None):
    input_chars = tf.strings.unicode_split(inputs, 'UTF-8')
    input_ids = self.ids_from_chars(input_chars).to_tensor()
    # 填充或截断到固定长度100
    seq_len = tf.shape(input_ids)[1]
    if seq_len < 100:
        input_ids = tf.pad(input_ids, [[0, 0], [0, 100 - seq_len]])
    input_ids = tf.slice(input_ids, [0, 0], [-1, 100])
    # 后续逻辑不变
    predicted_logits, states = self.model(inputs=input_ids, states=states,
                                          return_state=True)
    ...

方法二:确保模型保存时包含生成所需签名

训练完成后,保存模型前先触发一次带return_state=True的调用,让TensorFlow记录该签名:

# 训练完成后执行
test_input = tf.random.uniform((1, 100), maxval=len(vocab), dtype=tf.int64)
# 触发return_state=True的调用,生成对应签名
_, _ = model(test_input, return_state=True)
# 保存模型
model.save('quoteModel')

方法三:包装加载后的模型适配输入

如果不想修改训练代码,可创建包装类统一处理输入形状:

# 加载原始模型后创建包装类
class WrappedRNNModel(tf.keras.Model):
    def __init__(self, original_model):
        super().__init__()
        self.original_model = original_model
    
    def call(self, inputs, states=None, return_state=False, training=False):
        # 调整输入到(None,100)的形状
        seq_len = tf.shape(inputs)[1]
        if seq_len < 100:
            inputs = tf.pad(inputs, [[0,0], [0, 100 - seq_len]])
        inputs = tf.slice(inputs, [0,0], [-1, 100])
        return self.original_model(inputs, states=states, return_state=return_state, training=training)

# 替换原加载逻辑
new_model = WrappedRNNModel(tf.keras.models.load_model('quoteModel'))

3. 额外检查点

  • 确认模型call方法的参数顺序为inputs, states=None, return_state=False, training=False,与调用时的关键字参数对应。
  • 若训练时计划支持可变长度输入,需将模型输入层的input_shape设置为(None,)而非固定的(100,)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:40:58