Skip to main content

pytorch, tensores y torch.Tensor

Todo el procesamiento numérico central en Comfy lo hace pytorch. Si tus nodos personalizados van a meterse en las entrañas de Stable Diffusion, necesitarás familiarizarte con esta librería, algo que queda muy fuera del alcance de esta introducción. Sin embargo, muchos nodos personalizados tendrán que manipular imágenes, latents y máscaras, y cada uno de ellos se representa internamente como torch.Tensor, así que te conviene guardar en marcadores la documentación de torch.Tensor.

¿Qué es un tensor?

torch.Tensor representa un tensor, que es la generalización matemática de un vector o una matriz a cualquier número de dimensiones. El rango de un tensor es el número de dimensiones que tiene (así, un vector tiene rango 1 y una matriz rango 2); su forma describe el tamaño de cada dimensión. Así, una imagen RGB (de alto H y ancho W) podría concebirse como tres arreglos (uno por cada canal de color), cada uno de H x W, que se podría representar como un tensor con forma [H,W,3]. En Comfy las imágenes casi siempre vienen en un lote (aunque el lote solo contenga una imagen). torch siempre coloca la dimensión del lote primero, así que las imágenes de Comfy tienen forma [B,H,W,3], generalmente escrita como [B,H,W,C], donde C significa Canales.

squeeze, unsqueeze y reshape

Si un tensor tiene una dimensión de tamaño 1 (conocida como dimensión colapsada), equivale al mismo tensor con esa dimensión eliminada (un lote con 1 imagen es simplemente una imagen). Eliminar esa dimensión colapsada se conoce como squeeze, e insertar una se conoce como unsqueeze.
Parte del código de torch, y algunos autores de nodos personalizados, devolverán un tensor con la dimensión comprimida cuando una dimensión está colapsada, como cuando un lote tiene un solo miembro. ¡Esta es una causa común de errores!
Representar los mismos datos con una forma diferente se conoce como reshape. A menudo esto requiere que conozcas la estructura de datos subyacente, así que ¡manipúlalo con cuidado!

Notación importante

torch.Tensor admite la mayor parte de la notación de slicing de Python, la iteración y otras operaciones comunes similares a listas. Un tensor también tiene un atributo .shape que devuelve su tamaño como un torch.Size (que es una subclase de tuple y se puede tratar como tal). Hay otras piezas de notación importantes que verás a menudo (varias son notación estándar de Python menos común, que se ve mucho más cuando se trabaja con tensores)
  • torch.Tensor admite el uso de None en la notación de slicing para indicar la inserción de una dimensión de tamaño 1.
  • : se usa con frecuencia al hacer slicing de un tensor; simplemente significa “mantener toda la dimensión”. Es como usar a[start:end] en Python, pero omitiendo el punto inicial y el punto final.
  • ... representa “la totalidad de un número no especificado de dimensiones”. Así, a[0, ...] extraería el primer elemento de un lote sin importar el número de dimensiones.
  • en los métodos que requieren que se pase una forma, esta suele pasarse como una tuple de las dimensiones, en la cual a una sola dimensión se le puede dar el tamaño -1, lo que indica que el tamaño de esa dimensión debe calcularse a partir del tamaño total de los datos.

Operaciones elemento a elemento

Muchas operaciones binarias en torch.Tensor (incluidos ’+’, ’-’, ’*’, ’/’ y ’==’) se aplican elemento a elemento (se aplican de forma independiente a cada elemento). Los operandos deben ser o bien dos tensores de la misma forma, o bien un tensor y un escalar. Así:

Veracidad de un tensor

El valor de “veracidad” de un tensor no es el mismo que el de las listas de Python.
Quizá conozcas el valor de verdad de una lista de Python: True para cualquier lista no vacía y False para None o []. En cambio, un torch.Tensor (con más de un elemento) no tiene un valor de verdad definido. En su lugar necesitas usar .all() o .any() para combinar los valores de verdad elemento a elemento:
Esto también significa que debes usar if a is not None: y no if a: para determinar si una variable de tensor ha sido asignada.