Saltar al contenido
Buscar
Ver todo el radar
PyTorch 2.14Lo cubre Sage

PyTorch 2.14: varios cambios que rompen compatibilidad

Esta versión trae kernels nuevos y soporte distribuido ampliado, pero lo que más te va a afectar en el día a día son los cambios incompatibles en autograd, distributed y linalg.

Qué trae de nuevo (sin bajar al código)

Las notas mencionan NVGEMM para Inductor con kernels CUTLASS generados por CuTeDSL, un torch.switch que generaliza torch.cond a ramificación múltiple, y torch.while_loop capturable en CUDA graph. También aparece un esquema declarativo de shapes dinámicos con @dynamic_spec compartido entre torch.compile, torch.export y make_fx, soporte experimental de torch.compile para tensores complejos, un backend nccl2 para PyTorch Distributed, y mejoras de álgebra lineal nativa en Apple Silicon. El release no trae ejemplos de código para estos ítems, así que no hay más detalle para dar sin especular.

Autograd: cambia el subgradiente en clamp y min/max

Si usás clamp, clamp_min, clamp_max, fmin o fmax con un límite que es un Tensor, el gradiente en un empate ya no se asigna entero al input: ahora se reparte por igual entre el input y el límite. Con un límite escalar fijo, el gradiente en el borde pasa de 1 a 0, siguiendo el subgradiente de norma mínima. Si tu código depende del comportamiento viejo, tenés que expresarlo explícitamente con torch.where.

python
# Version 2.13
import torch
​
x = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(x, 0.0).backward()
print(x.grad) # tensor(1.)
​
value = torch.tensor(0.0, requires_grad=True)
bound = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(value, bound).backward()
print(value.grad, bound.grad) # tensor(1.) tensor(0.)
​
# Version 2.14
import torch
​
x = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(x, 0.0).backward()
print(x.grad) # tensor(0.)
​
value = torch.tensor(0.0, requires_grad=True)
bound = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(value, bound).backward()
print(value.grad, bound.grad) # tensor(0.5000) tensor(0.5000)

Distributed: tres cambios que pueden romper tu código

Si implementaste un process group custom con new_group(), ahora tenés que aceptar el keyword backend o vas a recibir un TypeError. Si usás register_mem_pool con symm=True, los segmentos nuevos ya no se promueven solos a ventanas simétricas: tenés que deregistrar y volver a registrar el pool después de crecerlo, porque la promoción automática podía colgar el proceso. Y si usás split_group() y comparabas el resultado con None para detectar ranks sin grupo, ahora tenés que comparar contra GroupMember.NON_GROUP_MEMBER.

python
# new_group con backend obligatorio
class MyProcessGroup(...):
def new_group(
self, ranks, *, timeout=None, backend=None, pg_options=None,
group_name=None, group_desc=None
):
...
​
# split_group ya no devuelve None
group = torch.distributed.split_group(
split_ranks=[[0, 1], [2, 3]]
)
if group == torch.distributed.GroupMember.NON_GROUP_MEMBER:
return

Linalg: cholesky() y qr() dejan de existir

torch.cholesky() y torch.qr(), junto con sus métodos Tensor equivalentes, fueron eliminados y ahora tiran RuntimeError. Tenés que migrar a torch.linalg.cholesky() y torch.linalg.qr(), y ajustar los argumentos: upper=True se reemplaza tomando la transpuesta conjugada con .mH, y el booleano some se reemplaza por mode="reduced" o mode="complete".

python
# Version 2.13
lower = torch.cholesky(a)
upper = torch.cholesky(a, upper=True)
​
q, r = torch.qr(a)
q_full, r_full = torch.qr(a, some=False)
​
# Version 2.14
lower = torch.linalg.cholesky(a)
upper = torch.linalg.cholesky(a).mH
​
q, r = torch.linalg.qr(a, mode="reduced")
q_full, r_full = torch.linalg.qr(a, mode="complete")

Profiler y backend tvm: APIs viejas fuera

El argumento use_cuda desapareció de torch.profiler.profile y torch.autograd.profiler.profile; ahora tenés que usar activities o use_device="cuda" según el caso. Aparte, el backend tvm de torch.compile dejó atrás el frontend relay: si tenés opciones scheduler o trials, o importás tvm_meta_schedule/tvm_auto_scheduler, eso ya no existe y necesitás pasar un pipeline de tvm.relax.

python
# Profiler, Version 2.14
with torch.profiler.profile(
activities=[
torch.profiler.ProfilerActivity.CPU,
torch.profiler.ProfilerActivity.CUDA,
]
) as prof:
run_workload()
​
with torch.autograd.profiler.profile(use_device="cuda") as prof:
run_workload()
​
# Backend tvm, Version 2.14
import tvm
​
pipeline = tvm.relax.get_pipeline("static_shape_tuning", target="llvm", total_trials=2000)
opt = torch.compile(model, backend="tvm", options={"pipeline": pipeline})

Qué te llevas

  • Si usás clamp/min/max con límites de tipo Tensor, revisá tus tests de gradiente: el reparto en los empates cambió.

  • Cualquier process group custom o código que dependa de register_mem_pool o split_group necesita actualizarse antes de migrar.

  • torch.cholesky() y torch.qr() ya no compilan: pasate a torch.linalg ahora, no después.

  • Si usabas use_cuda en el profiler o el backend tvm con relay, tu código no va a andar tal cual en 2.14.

Este resumen lo escribimos a partir de las notas oficiales del release. Lo que no estaba ahí, no está acá.

Anuncio original de PyTorch

¿Quieres una clase de esto?

Si varias personas lo piden, entra al programa. No hace falta dejar mail ni nombre.