es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

tf.vectorized_map no concatena tensores de longitud variable (InvalidArgumentError: PartialTensorShape: Incompatible shapes durante la fusión).

Me encuentro con un error “InvalidArgumentError: PartialTensorShape: Incompatible shapes during merge” cuando intento concatenar dos tensores con la función tf.concat, cuyas formas dependen de la entrada de la función dentro de la función vectorizada (aunque la forma de salida es la misma para cada par de a, b). A continuación, se muestra un ejemplo de la situación:

import tensorflow como tf

def test_fn(inputs):
a, b = inputs
out = tf.concat([tf.ones(a), tf.zeros(b)], 0)
return out

a = tf.constant([5, 4, 3, 2])
b = tf.constant([5, 6, 7, 8])
x_a = tf.vectorized_map(test_fn, (a, b))

Busco una explicación de por qué se produce el error.

Nota: Me di cuenta en el código fuente el comentario “- La forma y el tipo de datos de cualquier tensor intermedio o de salida en el cálculo de fn no deben depender de la entrada a fn”, que parece ser el escenario aquí. ¿Hay una solución alternativa que aún pueda aprovechar la vectorización?

Usar x_a = tf.map_fn(test_fn, (a, b), fn_output_signature=tf.TensorSpec((10,))) funciona, pero no paraleliza.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El error ocurre porque no se puede determinar la forma de tf.ones(a) y tf.zeros(b) durante la compilación, ya que a y b dependen de la entrada de la función. Esto no está permitido en TensorFlow porque dificulta las optimizaciones que pueden realizarse durante la compilación del gráfico.

    Una solución alternativa es especificar explícitamente la forma de salida en la operación tf.concat utilizando objetos tf.TensorShape:

    import tensorflow as tf
    
    def test_fn(inputs):
        a, b = inputs
        out_shape = tf.TensorShape([a.shape[0] + b.shape[0]])
        out = tf.concat([tf.ones(a), tf.zeros(b)], 0)
        out.set_shape(out_shape)
        return out
    
    a = tf.constant([5, 4, 3, 2])
    b = tf.constant([5, 6, 7, 8])
    x_a = tf.vectorized_map(test_fn, (a, b))
    

    Al establecer la forma explícitamente, TensorFlow es capaz de determinar la forma durante la compilación y se evita el error.

    Sin embargo, esto aún puede dificultar la optimización y puede no ser tan eficiente como la paralelización. Una alternativa es usar tf.data.Dataset.from_tensor_slices y tf.data.Dataset.map para paralelizar la operación:

    import tensorflow as tf
    
    def test_fn(inputs):
        a, b = inputs
        out = tf.concat([tf.ones(a), tf.zeros(b)], 0)
        return out
    
    a = tf.constant([5, 4, 3, 2])
    b = tf.constant([5, 6, 7, 8])
    ds = tf.data.Dataset.from_tensor_slices((a, b))
    ds = ds.map(test_fn, num_parallel_calls=tf.data.experimental.AUTOTUNE)
    x_a = tf.concat(list(ds), axis=0)
    

    Al utilizar tf.data.Dataset.map, la operación se paraleliza y puede aprovechar los múltiples núcleos de la CPU. El argumento num_parallel_calls especifica cuántas llamadas paralelas utilizar, y tf.data.experimental.AUTOTUNE utiliza el número máximo de núcleos de CPU disponibles. Es importante tener en cuenta que es necesario convertir tf.data.Dataset en una lista de tensores mediante list(ds), que luego se puede concatenar.

Comments are closed.