TensorFlow2自定义图像类设置IMAGE_SIZE无效问题排查
问题产生原因
- 核心诱因是历史pickle缓存未更新且缓存读写逻辑存在缺陷:
你写的load_dataset方法会优先读取固定路径..\\SeekThermal\\下的缓存文件,只有当该路径下缓存完全不存在时才会重新执行预处理。你此前曾使用IMAGE_SIZE=100的参数运行过代码,在该路径下生成了尺寸为(4732, 100, 100, 3)的旧缓存。后续修改传入的IMAGE_SIZE参数时,代码直接读取旧缓存返回,根本没有执行新参数对应的resize、归一化等预处理流程,因此无论怎么调整传入的尺寸参数,输出始终是旧缓存里的100×100规格。 - 代码中存在的其他问题会进一步导致该现象难以排查:
- 缓存读写路径不一致:写入pickle时文件存在当前工作目录,读取时却去上级目录的SeekThermal文件夹下找,极易出现读到远古旧缓存、新生成的缓存完全不生效的问题。
- 裸异常捕获吞掉所有报错:所有代码块都用无参数的
except:包裹,哪怕预处理、reshape流程出错也不会抛出明确提示,只会静默走异常分支,开发者根本感知不到代码实际执行逻辑。 - 打乱逻辑效率极低:在遍历单张图片的循环内反复执行
random.shuffle(self.image_data),每加一张图就打乱一次整个数据集,完全没必要,还会拖慢加载速度。 - 无效代码引发隐式报错:多处写了
print(self.X_data),但类中从未定义self.X_data属性,只有局部变量X_Data,这些打印语句执行时本就会触发属性错误,只是被裸except捕获没有暴露。
修复方法
- 第一步:清除旧缓存
找到..\\SeekThermal\\路径,删除路径下的X_Data、Y_Data两个旧pickle文件,强制代码首次运行时走新参数的预处理流程。 - 第二步:修正缓存读写逻辑
统一缓存读写路径,并且将缓存文件名和当前使用的IMAGE_SIZE参数绑定,避免不同尺寸的缓存互相覆盖,替换原有pickle_image、load_dataset方法即可:
import os def pickle_image(self): """ 生成数据集并序列化存储为pickle缓存 :return: 处理好的特征张量X_Data、标签张量Y_Data """ X_Data,Y_Data = self.process_image() # 缓存文件名绑定尺寸参数,避免不同规格缓存冲突 x_cache_name = f'X_Data_{self.IMAGE_SIZE}' y_cache_name = f'Y_Data_{self.IMAGE_SIZE}' # 统一缓存存储路径,存在数据集目录下的cache文件夹中,自动创建不存在的目录 cache_dir = os.path.join(self.PATH, 'cache') os.makedirs(cache_dir, exist_ok=True) # 写入特征缓存 with open(os.path.join(cache_dir, x_cache_name), 'wb') as pickle_out: pickle.dump(X_Data, pickle_out) # 写入标签缓存 with open(os.path.join(cache_dir, y_cache_name), 'wb') as pickle_out: pickle.dump(Y_Data, pickle_out) print("Pickled Image Successfully ") return X_Data,Y_Data def load_dataset(self): # 按照当前尺寸参数匹配对应缓存,读写路径和写入逻辑完全一致 cache_dir = os.path.join(self.PATH, 'cache') x_cache_path = os.path.join(cache_dir, f'X_Data_{self.IMAGE_SIZE}') y_cache_path = os.path.join(cache_dir, f'Y_Data_{self.IMAGE_SIZE}') # 匹配到对应尺寸的缓存才读取 if os.path.exists(x_cache_path) and os.path.exists(y_cache_path): with open(x_cache_path, 'rb') as X_Temp: X_Data = pickle.load(X_Temp) with open(y_cache_path, 'rb') as Y_Temp: Y_Data = pickle.load(Y_Temp) print(f'Reading Dataset from Pickle Object, image size {self.IMAGE_SIZE}') return X_Data,Y_Data # 没有匹配缓存则重新预处理生成 print('Could not Found Matching Pickle File ') print('Loading File and Dataset ..........') X_Data,Y_Data = self.pickle_image() return X_Data,Y_Data
- 第三步:修正预处理逻辑的问题
把循环内的shuffle移到所有图片加载完成后执行,删除无效的self.X_data打印语句,增加图片读取失败的判断,不要裸吞异常,替换原有process_image方法即可:
import cv2 import random import numpy as np def process_image(self): """ 遍历路径读取图像并做预处理 :return: 归一化后的特征张量X_Data、标签张量Y_Data """ self.CATEGORIES = self.get_categories() self.image_data = [] for categories in self.CATEGORIES: train_folder_path = os.path.join(self.PATH, categories) class_index = self.CATEGORIES.index(categories) for img in os.listdir(train_folder_path): new_path = os.path.join(train_folder_path, img) try: image_data_temp = cv2.imread(new_path) # 跳过读取失败的损坏图片 if image_data_temp is None: continue image_temp_resize = cv2.resize(image_data_temp, (self.IMAGE_SIZE, self.IMAGE_SIZE)) self.image_data.append([image_temp_resize, class_index]) except Exception as e: # 打印具体错误信息方便排查,不要静默吞掉异常 print(f"Process image {new_path} failed: {str(e)}") continue # 所有图片加载完成后统一打乱一次即可 random.shuffle(self.image_data) self.x_data = [] self.y_data = [] for x in self.image_data: self.x_data.append(x[0]) self.y_data.append(x[1]) X_Data = np.asarray(self.x_data) / 255.0 Y_Data = np.asarray(self.y_data) print(f"Compiled X_data shape: {X_Data.shape}") return X_Data, Y_Data
修改完成后,传入不同的IMAGE_SIZE参数时,代码会自动匹配对应尺寸的缓存,没有缓存就重新生成对应尺寸的数据集,不会再出现尺寸锁死在100×100的问题。
内容的提问来源于stack exchange,提问作者Bluetail
相关产品推荐
相关产品推荐

