使用tf.keras.utils.Sequence时model.fit报NoneType不可调用错误
Keras Sequence加载图片报错:TypeError: 'NoneType' object is not callable
问题背景
处理1920x1088分辨率的大型图片数据集,采用tf.keras.utils.Sequence()自定义Pictures类实现批量加载,运行训练代码时持续抛出TypeError: 'NoneType' object is not callable。不使用Sequence时代码可正常运行,更换不同文件、格式后问题依旧。要求用Keras完成任务,但个人更倾向PyTorch。
自定义Pictures类代码
class Pictures(keras.utils.Sequence): def __init__(self, x_set, y_set, batch_size): self.x, self.y = x_set, y_set self.batch_size = batch_size def load_sample(self, file): image = Image.open(file) # Открываем изображение image.load() # Загружаем его return image def __len__(self): return math.ceil(len(self.x) / self.batch_size) def __getitem__(self, idx): batch_x = self.x[idx * self.batch_size:(idx + 1) * self.batch_size] batch_y = self.y[idx * self.batch_size:(idx + 1) * self.batch_size] return np.array([cv2.resize(cv2.imread(file_name), (1920, 1088)) for file_name in batch_x]).astype('float32') / 255.0, np.array([cv2.resize(cv2.imread(file_name), (1920, 1088)) for file_name in batch_y]).astype('float32') / 255.0
模型训练代码
model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate = 0.001), loss = 'mean_absolute_error', metrics = ['acc']) model.fit(Pictures(high_q, low_q, 1), epochs = 7)
问题排查与解决
核心原因分析
报错NoneType object is not callable主要来自两个方向:
keras.utils.Sequence导入不规范,导致继承的类实例化后出现方法缺失__getitem__方法中跨换行的切片存在语法隐性错误,或者cv2.imread返回None后调用cv2.resize失败(但更换文件后问题依旧,因此前者概率更高)
修正步骤
- 统一导入规范:直接使用
tensorflow.keras.utils.Sequence而非keras.utils.Sequence,避免环境中独立keras与tf.keras版本冲突 - 修正切片语法:将
__getitem__中跨换行的切片改为清晰的起始/结束索引,消除语法歧义 - 添加异常校验:逐个加载图片并校验读取结果,便于快速定位无效路径
- 移除冗余代码:删除未实际使用的
load_sample方法
修正后的代码
from tensorflow.keras.utils import Sequence import math import cv2 import numpy as np class Pictures(Sequence): def __init__(self, x_set, y_set, batch_size): self.x, self.y = x_set, y_set self.batch_size = batch_size # 提前校验输入路径数量一致性 assert len(self.x) == len(self.y), "输入的高/低清图片路径列表长度不匹配" def __len__(self): return math.ceil(len(self.x) / self.batch_size) def __getitem__(self, idx): start_idx = idx * self.batch_size end_idx = start_idx + self.batch_size batch_x = self.x[start_idx:end_idx] batch_y = self.y[start_idx:end_idx] # 逐个处理图片,捕获读取异常 x_batch = [] for path in batch_x: img = cv2.imread(path) if img is None: raise ValueError(f"无法读取图片文件: {path}") resized_img = cv2.resize(img, (1920, 1088)) x_batch.append(resized_img.astype('float32') / 255.0) y_batch = [] for path in batch_y: img = cv2.imread(path) if img is None: raise ValueError(f"无法读取图片文件: {path}") resized_img = cv2.resize(img, (1920, 1088)) y_batch.append(resized_img.astype('float32') / 255.0) return np.array(x_batch), np.array(y_batch)
额外排查点
- 检查环境中tensorflow版本,建议使用2.x以上稳定版
- Windows系统下确保图片路径使用正斜杠
/或转义反斜杠\\ - 确认图片文件无损坏、权限正常,未被其他程序占用
内容的提问来源于stack exchange,提问作者Rodion Shkokov
相关产品推荐
相关产品推荐

