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.
# Version 2.13import torchx = 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.14import torchx = 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.
# new_group con backend obligatorioclass MyProcessGroup(...): def new_group( self, ranks, *, timeout=None, backend=None, pg_options=None, group_name=None, group_desc=None ): ...# split_group ya no devuelve Nonegroup = torch.distributed.split_group( split_ranks=[[0, 1], [2, 3]])if group == torch.distributed.GroupMember.NON_GROUP_MEMBER: returnLinalg: 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".
# Version 2.13lower = 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.14lower = torch.linalg.cholesky(a)upper = torch.linalg.cholesky(a).mHq, 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.
# Profiler, Version 2.14with 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.14import tvmpipeline = 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.
¿Quieres una clase de esto?
Si varias personas lo piden, entra al programa. No hace falta dejar mail ni nombre.