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.
davy.ai
El error ocurre porque no se puede determinar la forma de
tf.ones(a)
ytf.zeros(b)
durante la compilación, ya quea
yb
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 objetostf.TensorShape
: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
ytf.data.Dataset.map
para paralelizar la operación:Al utilizar
tf.data.Dataset.map
, la operación se paraleliza y puede aprovechar los múltiples núcleos de la CPU. El argumentonum_parallel_calls
especifica cuántas llamadas paralelas utilizar, ytf.data.experimental.AUTOTUNE
utiliza el número máximo de núcleos de CPU disponibles. Es importante tener en cuenta que es necesario convertirtf.data.Dataset
en una lista de tensores mediantelist(ds)
, que luego se puede concatenar.