将调整大小层添加到 keras 顺序模型
Add a resizing layer to a keras sequential model
如何向
添加调整图层
model = Sequential()
使用
model.add(...)
要将图像的大小从形状 (160, 320, 3) 调整为 (224,224,3)?
通常您会为此使用 Reshape
层:
model.add(Reshape((224,224,3), input_shape=(160,320,3))
但是由于您的目标维度不允许保存来自输入维度 (224*224 != 160*320
) 的所有数据,因此这将不起作用。如果元素数量不变,则只能使用 Reshape
。
如果您不介意丢失图像中的一些数据,您可以指定自己的有损整形:
model.add(Reshape(-1,3), input_shape=(160,320,3))
model.add(Lambda(lambda x: x[:50176])) # throw away some, so that #data = 224^2
model.add(Reshape(224,224,3))
也就是说,通常这些转换是在将数据应用到模型之前完成的,因为如果在每个训练步骤中都完成这实际上是在浪费计算时间。
我认为你应该考虑使用 tensorflow 的 resize_images 层。
https://www.tensorflow.org/api_docs/python/tf/image/resize_images
keras 似乎没有包含这个,也许是因为 theano 中不存在该功能。我已经编写了一个执行相同操作的自定义 keras 层。这是一个快速的 hack,因此它可能不适用于您的情况。
import keras
import keras.backend as K
from keras.utils import conv_utils
from keras.engine import InputSpec
from keras.engine import Layer
from tensorflow import image as tfi
class ResizeImages(Layer):
"""Resize Images to a specified size
# Arguments
output_size: Size of output layer width and height
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
# Input shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, rows, cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, rows, cols)`
# Output shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, pooled_rows, pooled_cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, pooled_rows, pooled_cols)`
"""
def __init__(self, output_dim=(1, 1), data_format=None, **kwargs):
super(ResizeImages, self).__init__(**kwargs)
data_format = conv_utils.normalize_data_format(data_format)
self.output_dim = conv_utils.normalize_tuple(output_dim, 2, 'output_dim')
self.data_format = conv_utils.normalize_data_format(data_format)
self.input_spec = InputSpec(ndim=4)
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
return (input_shape[0], input_shape[1], self.output_dim[0], self.output_dim[1])
elif self.data_format == 'channels_last':
return (input_shape[0], self.output_dim[0], self.output_dim[1], input_shape[3])
def _resize_fun(self, inputs, data_format):
try:
assert keras.backend.backend() == 'tensorflow'
assert self.data_format == 'channels_last'
except AssertionError:
print "Only tensorflow backend is supported for the resize layer and accordingly 'channels_last' ordering"
output = tfi.resize_images(inputs, self.output_dim)
return output
def call(self, inputs):
output = self._resize_fun(inputs=inputs, data_format=self.data_format)
return output
def get_config(self):
config = {'output_dim': self.output_dim,
'padding': self.padding,
'data_format': self.data_format}
base_config = super(ResizeImages, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
接受的答案使用Reshape layer, which works like NumPy's reshape,可用于将 4x4 矩阵重塑为 2x8 矩阵,但这会导致图像丢失局部信息:
0 0 0 0
1 1 1 1 -> 0 0 0 0 1 1 1 1
2 2 2 2 2 2 2 2 3 3 3 3
3 3 3 3
相反,图像数据应该重新缩放/"resized" 使用,例如,Tensorflows image_resize
。
但要注意正确的 usage 和错误!
如 所示,这可以与 lambda 层一起使用:
model.add( keras.layers.Lambda(
lambda image: tf.image.resize_images(
image,
(224, 224),
method = tf.image.ResizeMethod.BICUBIC,
align_corners = True, # possibly important
preserve_aspect_ratio = True
)
))
在您的情况下,由于您有一张 160x320 的图片,您还必须决定是否保持纵横比。如果您想使用预训练的网络,那么您应该使用与训练网络相同的调整大小。
修改@KeithWM 的答案,添加output_scale,例如output_scale=2表示输出是输入形状的2倍:)
class ResizeImages(Layer):
"""Resize Images to a specified size
# Arguments
output_dim: Size of output layer width and height
output_scale: scale compared with input
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
# Input shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, rows, cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, rows, cols)`
# Output shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, pooled_rows, pooled_cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, pooled_rows, pooled_cols)`
"""
def __init__(self, output_dim=(1, 1), output_scale=None, data_format=None, **kwargs):
super(ResizeImages, self).__init__(**kwargs)
data_format = normalize_data_format(data_format) # does not have
self.naive_output_dim = conv_utils.normalize_tuple(output_dim,
2, 'output_dim')
self.naive_output_scale = output_scale
self.data_format = normalize_data_format(data_format)
self.input_spec = InputSpec(ndim=4)
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
if self.naive_output_scale is not None:
if self.data_format == 'channels_first':
self.output_dim = (self.naive_output_scale * input_shape[2],
self.naive_output_scale * input_shape[3])
elif self.data_format == 'channels_last':
self.output_dim = (self.naive_output_scale * input_shape[1],
self.naive_output_scale * input_shape[2])
else:
self.output_dim = self.naive_output_dim
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
return (input_shape[0], input_shape[1], self.output_dim[0], self.output_dim[1])
elif self.data_format == 'channels_last':
return (input_shape[0], self.output_dim[0], self.output_dim[1], input_shape[3])
def _resize_fun(self, inputs, data_format):
try:
assert keras.backend.backend() == 'tensorflow'
assert self.data_format == 'channels_last'
except AssertionError:
print("Only tensorflow backend is supported for the resize layer and accordingly 'channels_last' ordering")
output = tf.image.resize_images(inputs, self.output_dim)
return output
def call(self, inputs):
output = self._resize_fun(inputs=inputs, data_format=self.data_format)
return output
def get_config(self):
config = {'output_dim': self.output_dim,
'padding': self.padding,
'data_format': self.data_format}
base_config = super(ResizeImages, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
将给定的输入图像调整为目标大小(在本例中为 224x224x3):
在常规 Keras 中使用 Lambda 层:
from keras.backend import tf as ktf
inp = Input(shape=(None, None, 3))
[参考:https://www.tensorflow.org/api_docs/python/tf/keras/backend/resize_images]:
我想我应该 post 一个更新的答案,因为接受的答案是错误的,而且最近的 Keras 版本中有一些重大更新。
添加调整层,根据documentation:
tf.keras.layers.experimental.preprocessing.Resizing(height, width, interpolation="bilinear", crop_to_aspect_ratio=False, **kwargs)
对你来说,应该是:
from tensorflow.keras.layers.experimental.preprocessing import Resizing
model = Sequential()
model.add(Resizing(224,224))
如何向
添加调整图层model = Sequential()
使用
model.add(...)
要将图像的大小从形状 (160, 320, 3) 调整为 (224,224,3)?
通常您会为此使用 Reshape
层:
model.add(Reshape((224,224,3), input_shape=(160,320,3))
但是由于您的目标维度不允许保存来自输入维度 (224*224 != 160*320
) 的所有数据,因此这将不起作用。如果元素数量不变,则只能使用 Reshape
。
如果您不介意丢失图像中的一些数据,您可以指定自己的有损整形:
model.add(Reshape(-1,3), input_shape=(160,320,3))
model.add(Lambda(lambda x: x[:50176])) # throw away some, so that #data = 224^2
model.add(Reshape(224,224,3))
也就是说,通常这些转换是在将数据应用到模型之前完成的,因为如果在每个训练步骤中都完成这实际上是在浪费计算时间。
我认为你应该考虑使用 tensorflow 的 resize_images 层。
https://www.tensorflow.org/api_docs/python/tf/image/resize_images
keras 似乎没有包含这个,也许是因为 theano 中不存在该功能。我已经编写了一个执行相同操作的自定义 keras 层。这是一个快速的 hack,因此它可能不适用于您的情况。
import keras
import keras.backend as K
from keras.utils import conv_utils
from keras.engine import InputSpec
from keras.engine import Layer
from tensorflow import image as tfi
class ResizeImages(Layer):
"""Resize Images to a specified size
# Arguments
output_size: Size of output layer width and height
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
# Input shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, rows, cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, rows, cols)`
# Output shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, pooled_rows, pooled_cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, pooled_rows, pooled_cols)`
"""
def __init__(self, output_dim=(1, 1), data_format=None, **kwargs):
super(ResizeImages, self).__init__(**kwargs)
data_format = conv_utils.normalize_data_format(data_format)
self.output_dim = conv_utils.normalize_tuple(output_dim, 2, 'output_dim')
self.data_format = conv_utils.normalize_data_format(data_format)
self.input_spec = InputSpec(ndim=4)
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
return (input_shape[0], input_shape[1], self.output_dim[0], self.output_dim[1])
elif self.data_format == 'channels_last':
return (input_shape[0], self.output_dim[0], self.output_dim[1], input_shape[3])
def _resize_fun(self, inputs, data_format):
try:
assert keras.backend.backend() == 'tensorflow'
assert self.data_format == 'channels_last'
except AssertionError:
print "Only tensorflow backend is supported for the resize layer and accordingly 'channels_last' ordering"
output = tfi.resize_images(inputs, self.output_dim)
return output
def call(self, inputs):
output = self._resize_fun(inputs=inputs, data_format=self.data_format)
return output
def get_config(self):
config = {'output_dim': self.output_dim,
'padding': self.padding,
'data_format': self.data_format}
base_config = super(ResizeImages, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
接受的答案使用Reshape layer, which works like NumPy's reshape,可用于将 4x4 矩阵重塑为 2x8 矩阵,但这会导致图像丢失局部信息:
0 0 0 0
1 1 1 1 -> 0 0 0 0 1 1 1 1
2 2 2 2 2 2 2 2 3 3 3 3
3 3 3 3
相反,图像数据应该重新缩放/"resized" 使用,例如,Tensorflows image_resize
。
但要注意正确的 usage 和错误!
如
model.add( keras.layers.Lambda(
lambda image: tf.image.resize_images(
image,
(224, 224),
method = tf.image.ResizeMethod.BICUBIC,
align_corners = True, # possibly important
preserve_aspect_ratio = True
)
))
在您的情况下,由于您有一张 160x320 的图片,您还必须决定是否保持纵横比。如果您想使用预训练的网络,那么您应该使用与训练网络相同的调整大小。
修改@KeithWM 的答案,添加output_scale,例如output_scale=2表示输出是输入形状的2倍:)
class ResizeImages(Layer):
"""Resize Images to a specified size
# Arguments
output_dim: Size of output layer width and height
output_scale: scale compared with input
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
# Input shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, rows, cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, rows, cols)`
# Output shape
- If `data_format='channels_last'`:
4D tensor with shape:
`(batch_size, pooled_rows, pooled_cols, channels)`
- If `data_format='channels_first'`:
4D tensor with shape:
`(batch_size, channels, pooled_rows, pooled_cols)`
"""
def __init__(self, output_dim=(1, 1), output_scale=None, data_format=None, **kwargs):
super(ResizeImages, self).__init__(**kwargs)
data_format = normalize_data_format(data_format) # does not have
self.naive_output_dim = conv_utils.normalize_tuple(output_dim,
2, 'output_dim')
self.naive_output_scale = output_scale
self.data_format = normalize_data_format(data_format)
self.input_spec = InputSpec(ndim=4)
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
if self.naive_output_scale is not None:
if self.data_format == 'channels_first':
self.output_dim = (self.naive_output_scale * input_shape[2],
self.naive_output_scale * input_shape[3])
elif self.data_format == 'channels_last':
self.output_dim = (self.naive_output_scale * input_shape[1],
self.naive_output_scale * input_shape[2])
else:
self.output_dim = self.naive_output_dim
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
return (input_shape[0], input_shape[1], self.output_dim[0], self.output_dim[1])
elif self.data_format == 'channels_last':
return (input_shape[0], self.output_dim[0], self.output_dim[1], input_shape[3])
def _resize_fun(self, inputs, data_format):
try:
assert keras.backend.backend() == 'tensorflow'
assert self.data_format == 'channels_last'
except AssertionError:
print("Only tensorflow backend is supported for the resize layer and accordingly 'channels_last' ordering")
output = tf.image.resize_images(inputs, self.output_dim)
return output
def call(self, inputs):
output = self._resize_fun(inputs=inputs, data_format=self.data_format)
return output
def get_config(self):
config = {'output_dim': self.output_dim,
'padding': self.padding,
'data_format': self.data_format}
base_config = super(ResizeImages, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
将给定的输入图像调整为目标大小(在本例中为 224x224x3):
在常规 Keras 中使用 Lambda 层:
from keras.backend import tf as ktf
inp = Input(shape=(None, None, 3))
[参考:https://www.tensorflow.org/api_docs/python/tf/keras/backend/resize_images]:
我想我应该 post 一个更新的答案,因为接受的答案是错误的,而且最近的 Keras 版本中有一些重大更新。
添加调整层,根据documentation:
tf.keras.layers.experimental.preprocessing.Resizing(height, width, interpolation="bilinear", crop_to_aspect_ratio=False, **kwargs)
对你来说,应该是:
from tensorflow.keras.layers.experimental.preprocessing import Resizing
model = Sequential()
model.add(Resizing(224,224))