Comment puis-je ajouter un calque de redimensionnement à
model = Sequential()
en utilisant
model.add(...)
Pour redimensionner une image de la forme (160, 320, 3) à (224,224,3)?
Normalement, vous utiliseriez la couche Reshape
pour cela:
model.add(Reshape((224,224,3), input_shape=(160,320,3))
mais comme vos dimensions cibles ne permettent pas de conserver toutes les données des dimensions d'entrée (224*224 != 160*320
), cela ne fonctionnera pas. Vous ne pouvez utiliser Reshape
que si le nombre d'éléments ne change pas.
Si vous voulez bien perdre certaines données de votre image, vous pouvez spécifier votre propre remodelage avec perte:
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))
Cela dit, ces transformations sont souvent effectuées avant d'appliquer les données au modèle, car il s'agit essentiellement de temps de calcul gaspillé si elles sont effectuées à chaque étape de la formation.
Je pense que vous devriez envisager d'utiliser la couche resize_images de tensorflow.
https://www.tensorflow.org/api_docs/python/tf/image/resize_images
Il semble que les keras n'incluent pas cela, et peut-être parce que la fonctionnalité n'existe pas dans l'ano. J'ai écrit un calque de keras personnalisé qui fait de même. C'est un hack rapide, donc cela pourrait ne pas bien fonctionner dans votre cas.
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()))
La réponse acceptée utilise la couche Remodeler , qui fonctionne comme Remodeler NumPy , qui peut être utilisée pour remodeler une matrice 4x4 en matrice 2x8, mais cela entraînera la perte de l'image informations sur la localité:
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
Au lieu de cela, les données d'image doivent être redimensionnées/"redimensionnées" en utilisant, par exemple, Tensorflows image_resize
. Mais attention au bon sage et aux bugs! Comme le montre la question connexe , cela peut être utilisé avec une couche 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
)
))
Dans votre cas, comme vous avez une image 160x320, vous devez également décider de conserver ou non le format d'image. Si vous souhaitez utiliser un réseau pré-formé, vous devez utiliser le même type de redimensionnement que le réseau a été formé.
Une modification de la réponse de @KeithWM, en ajoutant output_scale, par ex. output_scale = 2 signifie que la sortie est 2 fois la forme d'entrée :)
class ResizeImages(Layer):
"""Resize Images to a specified size
https://stackoverflow.com/questions/41903928/add-a-resizing-layer-to-a-keras-sequential-model
# 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()))