Keras Resizing层无法处理不同尺寸图像输入的问题与解决
Keras Resizing层使用问题与解决方案
我原本以为Keras的Resizing层支持输入不同尺寸的图像,但实际使用时遇到了问题,以下代码可复现报错情况:
import tensorflow as tf import tensorflow_datasets as tfds from tensorflow.keras import layers dsTrain = tfds.load('CatsVsDogs', split='train[:10%]', as_supervised=True).batch(128).prefetch(tf.data.AUTOTUNE) model = tf.keras.models.Sequential() model.add(layers.InputLayer(input_shape=(None, None, 3))) model.add(layers.Resizing(200, 200, crop_to_aspect_ratio=True)) # 问题出在这里 model.add(layers.Rescaling(1./255)) model.add(layers.Conv2D(8, (3, 3), activation='relu', kernel_initializer='random_normal', padding='same')) model.add(layers.MaxPooling2D((3,3))) model.add(layers.Dense(2)) model.compile(optimizer='rmsprop',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy']) model.fit(dsTrain,epochs=10,batch_size=128) # 报错信息: # 无法对组件0中形状不同的张量进行批处理。第一个元素形状为[262,350,3],第二个元素形状为[409,336,3]
我想掌握该层的正确用法,虽然可以提前调整图像尺寸,但还是希望了解Resizing层的规范使用方式。
编辑1
我尝试将预处理逻辑集成到模型中,代码如下:
import tensorflow as tf import tensorflow_datasets as tfds from tensorflow import keras from tensorflow.keras import layers dsTrain = tfds.load('CatsVsDogs', split='train[:10%]', as_supervised=True).batch(128).prefetch(tf.data.AUTOTUNE) IMAGE_SIZE = 100 preprocessing_model = tf.keras.models.Sequential() preprocessing_model.add(layers.InputLayer(input_shape=(None, None, 3))) preprocessing_model.add(layers.Resizing(IMAGE_SIZE, IMAGE_SIZE, crop_to_aspect_ratio=True)) preprocessing_model.add(layers.Rescaling(1./255)) training_model = tf.keras.models.Sequential() training_model.add(layers.InputLayer(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3))) training_model.add(layers.Conv2D(8, (3, 3), activation='relu', kernel_initializer='random_normal', padding='same')) training_model.add(layers.MaxPooling2D((5,5))) training_model.add(layers.Flatten()) training_model.add(layers.Dense(2)) inputs = keras.Input(shape=preprocessing_model.input_shape) outputs = training_model(preprocessing_model(inputs)) model = tf.keras.Model(inputs, outputs) model.summary() model.compile(optimizer='rmsprop',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy']) model.fit(dsTrain,epochs=3,batch_size=128)
但出现维度不兼容报错:
WARNING:tensorflow:构建模型时输入形状为(None, None, None, 3),但实际调用时输入形状为(None, None, None, None, 3),维度不兼容。 --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-82-6e99f023839a> in <module> 22 23 inputs = keras.Input(shape=preprocessing_model.input_shape) ---> 24 outputs = training_model(preprocessing_model(inputs)) 25 model = tf.keras.Model(inputs, outputs) 26 1 frames /usr/local/lib/python3.7/dist-packages/keras/preprocessing/image.py in smart_resize(x, size, interpolation) 110 if img.shape.rank < 3 or img.shape.rank > 4: 111 raise ValueError( ---> 112 '期望图像数组形状为`(高度, 宽度, 通道数)`或`(批大小, 高度, 宽度, 通道数)`,但实际输入维度不符合要求,形状为{img.shape}。') ValueError: 调用Resizing层时遇到异常: 期望图像数组形状为`(高度, 宽度, 通道数)`或`(批大小, 高度, 宽度, 通道数)`,但实际输入形状为(None, None, None, None, 3)。
编辑2
调整输入维度后,预处理层集成成功,但仍无法接收不同尺寸图像,报错如下:
import tensorflow as tf import tensorflow_datasets as tfds from tensorflow import keras from tensorflow.keras import layers IMAGE_SIZE = 100 dsTrain = tfds.load('CatsVsDogs', split='train[:10%]', as_supervised=True).batch(128).prefetch(tf.data.AUTOTUNE) preprocessing_model = tf.keras.models.Sequential() preprocessing_model.add(layers.InputLayer(input_shape=(None, None, 3))) preprocessing_model.add(layers.Resizing(IMAGE_SIZE, IMAGE_SIZE, crop_to_aspect_ratio=True)) preprocessing_model.add(layers.Rescaling(1./255)) training_model = tf.keras.models.Sequential() training_model.add(layers.InputLayer(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3))) training_model.add(layers.Conv2D(8, (3, 3), activation='relu', kernel_initializer='random_normal', padding='same')) training_model.add(layers.MaxPooling2D((5,5))) training_model.add(layers.Flatten()) training_model.add(layers.Dense(2)) inputs = keras.Input(shape=preprocessing_model.input_shape[1:]) # [1:] 为批处理添加维度 outputs = training_model(preprocessing_model(inputs)) model = tf.keras.Model(inputs, outputs) model.summary() model.compile(optimizer='rmsprop',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy']) model.fit(dsTrain,epochs=3,batch_size=128) # model.fit报错:无法对组件0中形状不同的张量进行批处理。第一个元素形状为[262,350,3],第二个元素形状为[409,336,3]
最终结论与解决方案
我终于搞懂了问题核心:训练阶段的数据必须统一尺寸(因为批处理要求张量形状一致),但训练好的包含Resizing层的模型,在推理阶段可以接收不同尺寸的图像。解决方案代码如下:
import tensorflow as tf import tensorflow_datasets as tfds from tensorflow import keras from tensorflow.keras import layers import numpy as np import matplotlib.pyplot as plt import random IMAGE_SIZE = 100 dsTrain = tfds.load('CatsVsDogs', split='train[:10%]', as_supervised=True) dsPredict = dsTrain.take(77) # 训练前统一图像尺寸,满足批处理要求 def preprocess(image, label): image = tf.image.resize(image, (100,100)) return image, label dsTrain = dsTrain.map(preprocess).shuffle(1024).batch(128).prefetch(tf.data.AUTOTUNE) # 预处理模型(包含Resizing层,推理时可处理任意尺寸图像) preprocessing_model = tf.keras.models.Sequential() preprocessing_model.add(layers.Resizing(IMAGE_SIZE, IMAGE_SIZE, crop_to_aspect_ratio=True, input_shape=(None, None, 3))) # 训练时此层冗余,但推理时有用 preprocessing_model.add(layers.Rescaling(1./255)) # 核心训练模型 training_model = tf.keras.models.Sequential() training_model.add(layers.Conv2D(8, (3, 3), activation='relu', kernel_initializer='random_normal', padding='same')) training_model.add(layers.MaxPooling2D((5,5))) training_model.add(layers.Flatten()) training_model.add(layers.Dense(2)) # 组合模型 inputs = keras.Input(shape=preprocessing_model.input_shape[1:]) outputs = training_model(preprocessing_model(inputs)) model = tf.keras.Model(inputs, outputs) model.summary() model.compile(optimizer='rmsprop',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy']) model.fit(dsTrain,epochs=1,batch_size=128) # 测试:用任意尺寸的图像推理 for image, labelId in dsPredict.skip(random.randint(0, 50)).take(1): dsImage = tf.keras.preprocessing.image.img_to_array(image) dsImage = np.expand_dims(dsImage, axis = 0) # 添加批维度 prediction = model.predict(dsImage) plt.imshow(image) plt.title(f"预测值:{prediction[0][0]}, {prediction[0][1]}") plt.show()
内容的提问来源于stack exchange,提问作者Marquo
相关产品推荐
相关产品推荐

