Usar torchtitan en AWS Trainium significa usarlo como siempre lo ha hecho. TorchNeuron registra Trainium como un dispositivo PyTorch nativo, lo que permite a torchtitan usarlo a través de las interfaces PyTorch estándar. Puedes usar estas configuraciones para realizar un entrenamiento previo a partir de una inicialización aleatoria o para ajustar con precisión los pesos publicados. También puede personalizar la implementación del modelo y los núcleos para su carga de trabajo.

En esta publicación, entrenas a Qwen3 de tres maneras en un solo trn2.48xlarge.

El primer método usa Transformers v5 como backend de modelado en torchtitan. Ejecuta los modelos Hub a través de AutoModelForCausalLM y lee y escribe directamente los safetensores publicados. El segundo método cambia al Qwen3 nativo de torchtitan cambiando config.model_spec. El tercero añade núcleos mixture-of-experts (MoE) de la Interfaz de Kernel Neuron (NKI) de las recetas de torchtitan-neurona y, a continuación, utiliza el registro de anulaciones de torchtitan para adjuntar tu propio núcleo.

Las tres configuraciones usan el mismo patrón de lanzamiento y estructura de configuración de Torchrun.

Requisitos previos

Para seguir este tutorial, utilice un único trn2.48xlarge con la AMI de aprendizaje profundo de AWS para Neuron o con un contenedor de entrenamiento de Neuron PyTorch. Ambos entornos proporcionan el controlador, el tiempo de ejecución y el compilador de Neuron necesarios

para entrenar en Trainium.

Antes de instalar torchtitan-neuron, compruebe si su entorno ya lo incluye. El siguiente comando imprime la versión instalada y la ruta del paquete

:
python3 -c «importar torchtitan, torchtitan_neuron; print (torchtitan). __versión__, torchtitan_neuron. __archivo__)»

En este tutorial se utilizan las versiones de la tabla siguiente. Para reproducir los ejemplos, fije estas versiones. Los módulos de integración de Transformers v5 y de anulación específicos de Trainium pueden cambiar entre

las versiones de Torchtitan.
Componente
Versión
Instancia trn2.48xlarge, 16 aceleradores Trainium2, 128 núcleos neuronales físicos
Núcleos neuronales lógicos
64 en LNC=2
antorcha, torch_neuronx 2.14.0, 2.14.3
transformadores 5.16.0
neurona torchtitán versión 2.33 (0.2.2+neuron.1)

Cuando se instala torch_neuronx, TorchNeuron registra Trainium como dispositivo neuronal y torchtitan lo detecta al inicio. En el modo ansioso, Neuron compila las operaciones a medida que se ejecutan. Con torch.compile, Neuron compila el gráfico capturado. Este mismo patrón de lanzamiento funciona

en las tres configuraciones.

Para las versiones utilizadas en este tutorial, instala las dependencias restantes de torchtitan-neuron y torchtitan con --no-deps para conservar la versión Neuron de torch:

clon de git https://github.com/aws-neuron/torchtitan-neuron
cd torchtitan-neurona
pip install -r requirements.txt

Antes de empezar a entrenar, consigue los artefactos del modelo Qwen3 en Hugging Face Hub. Guárdalos en un directorio local que puedas pasar a la

configuración de entrenamiento:
Si descarga Qwen/Qwen3-4B-Instruct-2507\
 --local-dir «$pwd/assets/hf/Qwen3-4b-instruct-2507"

Cada configuración de entrenamiento es una función de configuración de Python. Los tres ejemplos parten de una configuración base que se actualiza para cada paso.

Entrena con cara abrazada Transformers v5

En la primera configuración, Transformers v5 construye Qwen 3 a través de AutoModelForCausalLM. La definición del modelo Hub proporciona la implementación utilizada para las pasadas hacia adelante y hacia atrás. Para seleccionar el modelo, establezca su ID de hub en la configuración.

Empieza con transformers_modeling_backend_full ().

Deja sin definir los campos que se asignan a las claves de configuración de Hugging Face, por lo que autoConfig.from_pretrained () carga la arquitectura del modelo desde el Hub.

Crea el archivo neuron_qwen3.py en la raíz del repositorio torchtitan-neuron, donde ejecutas el comando de entrenamiento. Añade las importaciones, la ruta del artefacto modelo y

la configuración base:
sistema operativo de importación
desde torchtitan.experiments.transformers_modeling_backend.config_registry import (
 transformers_modeling_backend_full,
)
desde torchtitan.experiments.transformers_modeling_backend.configs import (
 Transformers Backend Config,
)

ACTIVOS = os.path.abspath (». /assets/HF/QWEN3-4B-instruct-2507 «)

def v5_qwen3_4b () -> Configuración de backend de Transformers:
 config = transformers_modeling_backend_full ()
 config.hf_model = «Qwen/Qwen3-4B-Instruct-2507"
 config.hf_assets_path = ACTIVOS
 config.dataloader.dataset = «c4_test»
 config.training.steps = 10
 config.training.local_batch_size = 1
 config.parallelism.data_parallel_shard_degree = -1
 configuración de devolución
torchrun --nproc_per_node=64 --rdzv_backend c10d --rdzv_endpoint localhost:0\
 --local-ranks-filter 0 --rol rank --tee 3\
 -m torchtitan.train --module neuron_qwen3 --config v5_qwen3_4b

Este comando lanza 64 procesos de entrenamiento, uno para cada NeuronCore lógico. --module neuron_qwen3 importa el módulo de configuración local. --config v5_qwen3_4b selecciona la función de configuración. La configuración de datos paralelos fragmenta el modelo

en los 64 rangos.

Carga y guarda los puntos de control de Hugging Face

Para ajustar con precisión los pesos publicados, habilita la carga por puntos de control y apunta initial_load_path a ASSETS. El adaptador de diccionario estatal ajusta el modelo principal. prefija y maneja incrustaciones enlazadas. Guarda el punto de control final

como protectores Hugging Face.
def v5_qwen3_4b_finetune () -> Transformers Backend Config:
 config = v5_qwen3_4b ()
 config.checkpoint.enable = Verdadero
 config.checkpoint.folder = «checkpoint_qwen3_4b_ft»
 config.checkpoint.initial_load_path = ASSETS # se requiere una ruta absoluta
 config.checkpoint.initial_load_in_hf = Verdadero
 config.checkpoint.initial_load_model_only = Verdadero
 config.checkpoint.last_save_in_hf = Verdadero
 config.checkpoint.last_save_model_only = Verdadero
 configuración de devolución

Usa la pérdida del primer paso de entrenamiento como una forma rápida de comprobar que Torchtitan ha cargado las pesas publicadas. En el caso de Qwen/Qwen3-4B-Instruct-2507, la ejecución verificada produjo una pérdida de 6,54 en el paso 1 con respecto a los pesos publicados y de 12,43 con respecto a la

inicialización aleatoria.

Tras el entrenamiento, carga el punto de control exportado con AutoModelForCausalLM y load_state_dict. Un viaje de ida y vuelta exitoso indica que no hay claves perdidas o inesperadas, excepto lm_head.weight, que Qwen3-4B vincula con las incrustaciones de los tokens.

Esto confirma que los archivos siguen siendo un punto de control estándar de Hugging Face.
Training output showing a step 1 loss of 6.54 and the exported checkpoint loading with no missing or unexpected keys

Figura 1: El punto de control publicado comienza con una pérdida de 6,54 y los pesos exportados se cargan sin claves faltantes o inesperadas

Entrena con los modelos nativos de torchtitan

En la segunda configuración, torchtitan crea su modelo Qwen3 nativo.

Agregue la función nativa de importación y configuración de Qwen3 a neuron_qwen3.py:

Este ejemplo parte de qwen3_32b () porque la versión probada de torchtitan no proporciona un generador de configuración genérico de qwen3_4b (). La siguiente línea reemplaza la especificación del modelo 32B por la especificación 4B. Los campos restantes reproducen la ejecución probada

.
desde torchtitan.models.qwen3 importar model_registry
desde torchtitan.models.qwen3.config_registry importe qwen3_32b
desde torchtitan.trainer import Trainer

def native_qwen3_4b () -> Trainer.Config:
 config = qwen3_32b ()
 config.model_spec = model_registry («4B», attn_backend="sdpa»)
 config.hf_assets_path = ACTIVOS
 config.dataloader.dataset = «c4_test»
 config.training.steps = 10
 config.training.local_batch_size = 1
 config.training.global_batch_size = 64
 config.parallelism.data_parallel_shard_degree = -1
 configuración de devolución
torchrun --nproc_per_node=64 --rdzv_backend c10d --rdzv_endpoint localhost:0\
 --local-ranks-filter 0 --rol rank --tee 3\
 -m torchtitan.train --module neuron_qwen3 --config native_qwen3_4b

config.model_spec selecciona la clase del modelo y define cómo torchtitan fragmenta el modelo y mapea sus claves de puntos de control. Aquí, model_registry («4B», attn_backend="sdpa») selecciona la implementación Qwen3 nativa de torchtitan

con Scaled Dot Product Attention (SDPA).

Añada núcleos NKI para obtener una mezcla de expertos

En la tercera configuración, torchtitan ejecuta capas mixtas de expertos con núcleos escritos en NKI, el lenguaje del núcleo de Neuron.

Agregue las importaciones necesarias y la función de configuración MoE de Qwen3 a neuron_qwen3.py:
desde torchtitan.config importar compileConfig
desde torchtitan_neuron.models.qwen3.config_registry importe qwen3_nki_moe_config

def nki_qwen3_30b_a3b () -> Trainer.Config:
 config = qwen3_nki_moe_config (
 «30B-A3B»,
 compile_config=compileConfig (enable=false, backend="neuron»),
 n_layers=4,
 num_experts=64,
 top_k=4,
 )
 config.hf_assets_path = ACTIVOS
 devuelve la configuración
torchrun --nproc_per_node=64 --rdzv_backend c10d --rdzv_endpoint localhost:0\
 --local-ranks-filter 0 --rol rank --tee 3\
 -m torchtitan.train --module neuron_qwen3 --config nki_qwen3_30b_a3b

Esta configuración utiliza la fragmentación paralela de datos en 64 rangos con un grado de paralelo del tensor de 1. No utiliza el paralelismo experto. num_experts=64 establece el número de expertos del modelo, no el grado paralelo de expertos

.

Al configurar compileConfig (enable=false), se ejecuta este ejemplo en modo ansioso.

TorchNeuron admite operadores de NKI registrados tanto en Sager Execution como en torch.compile.

En la compilación torchtitan utilizada para este tutorial, qwen3_nki_moe_config () reemplaza el bloque MoE por la implementación de expertos agrupados de NKI. También selecciona el SDPA y la incrustación rotativa sin recolección.

Cuando habilites torch.compile, agrega «grad_clip» a CompileConfig.components para compilar el recorte de normas de gradiente. Los

núcleos NKI se entrenan como operadores de PyTorch. wrap_nki hace que un núcleo NKI sea invocable desde PyTorch, y nki_op registra el operador. register_autograd

adjunta su pasada hacia atrás utilizando los metadatos de enrutamiento guardados durante la pasada hacia adelante.

El ejemplo reduce el Qwen3-30B-A3B a 4 capas y 64 expertos, por lo que cabe en un trn2.48xlarge. Dirige cada token a 4 expertos

con top_k=4.

Adjunta tu propio núcleo de NKI

En algunos casos, es posible que desee optimizar una operación para las formas de los tensores de su modelo. Un núcleo especializado puede adaptar sus ordenamientos en teselas y el movimiento de datos a esas formas. También puede reemplazar una secuencia crítica de operaciones de PyTorch por un operador optimizado. Puede escribir el núcleo usted mismo o empezar con uno desde nkilib. Este ejemplo usa rope_hf de nkilib.core.embeddings, que espera el diseño del tensor Hugging Face y admite su propio modo de retroceso. En este ejemplo se muestra el registro del núcleo y la integración con la autogradación, pero no se trata de

una mejora del rendimiento.

Crea el archivo my_neuron_kernels.py en la raíz del repositorio, donde inicias training. torchtitan almacena la consulta y la clave como [batch, seq, heads, head_dim], mientras que rope_hf espera [batch, heads, seq, head_dim].

Convierte el diseño dentro del operador y asigna los tensores de salida con torch.empty_like ():
antorcha de importación
desde nkilib.core.embeddings.rope_hf importa rope_hf
desde torch_neuronx importa nki_op
desde torch_neuronx.nki_hop importa wrap_nki
desde torch_neuronx.utils importa get_logical_neuron_cores

LNC = (int (get_logical_neuron_cores ()),)
wrapped_rope = wrap_nki (rope_hf)

@nki_op («my_kernels: :rope_fwd»)
def rope_fwd (consulta, clave, rope_cache):
 q = query.permute (0, 2, 1, 3) .contiguous ()
 k = key.permute (0, 2, 1, 3) .contiguous ()
 cache = rope_cache.reshape (-1, rope_cache.shape [-1])
 q_out, k_out = wrapped_rope [LNC] (
 q,
 k,
 torch.empty_like (q),
 torch.empty_like (k),
 rope_cache=caché,
 )
 devolución (
 q_out.permute (0, 2, 1, 3) .contiguo (),
 k_out.permute (0, 2, 1, 3) .contiguous (),
 )

rope_hf calcula los gradientes cuando lo llamas con backward=True. Registra un segundo operador para ese modo. Guarde la memoria caché rotativa durante la pasada hacia adelante para que la pasada hacia atrás pueda reutilizarla. Devuelve None para el gradiente de la caché porque la caché no es diferenciable

.
@nki_op («my_kernels: :rope_bwd»)
def rope_bwd (grad_query, grad_key, rope_cache):
 gq = grad_query.permute (0, 2, 1, 3) .contiguous ()
 gk = grad_key.permute (0, 2, 1, 3) .contiguous ()
 caché = rope_cache.reshape (-1, rope_cache.shape [-1])
 out_q, out_k = wrapped_rope [LNC] (
 gq,
 gk,
 torch.empty_like (gq),
 torch.empty_like (gk),
 rope_cache=caché,
 Hacia atrás = verdadero,
 )
 devolución (
 out_q.permute (0, 2, 1, 3) .contiguo (),
 out_k.permute (0, 2, 1, 3) .contiguous (),
 )
def _setup_context (ctx, entradas, salida):
 ctx.save_for_backward (entradas [2])

def _backward (ctx, grad_query, grad_key):
 (rope_cache,) = ctx.saved_tensors
 grad_q, grad_k = rope_bwd (grad_query, grad_key, rope_cache)
 devuelve grad_q, grad_k, Ninguno

rope_fwd.register_autograd (_backward, setup_context=_setup_context
)

Como rope_hf requiere una longitud de secuencia compatible, valide esa restricción antes de llamar al núcleo.

Subclasifique CossInRope y llame a rope_fwd desde apply_rotary_emb:
desde clases de datos importar clase de datos
desde torchtitan.config, importar, derivar, anular
desde torchtitan.models.common.rope importa CosSinRope

clase NikRope (CossinRope):
 @dataclass (KW_ONLY=true, slots=true)
 configuración de clase (CossinRope.config):
 pase

 @staticmethod
 def apply_rotary_emb (consulta, clave, rope_cache):
 stride = 128 * LNC [0]
 si query.shape [1]% stride:
 genera ValueError ()
 «f"rope_hf requiere una longitud de secuencia que sea un múltiplo de»
 f"128 * LNC= {stride}, tiene {query.shape [1]}»
 )
 q_out, k_out = rope_fwd (consulta, clave, rope_cache)
 devuelve q_out.type_as (consulta), k_out.type_as (clave
)

Registra NKiRope como reemplazo de CosSinRope. derive () copia los campos de configuración compartidos en la configuración de reemplazo

:
@override (
 «ni_rope»,
 target = cossinrope.config,
 exacto = verdadero,
 description="El núcleo nkilib rope_hf en lugar de la rotación de PyTorch»,
)
def _nki_rope (cfg: cossinRope.config) -> nkirope.config:
 devuelva la derivación (cfg, NKirope.config)

Para cargar la anulación personalizada, pasa el nombre del módulo a --override.imports. torchtitan importa la entrada de registro antes de crear el modelo:

torchrun --nproc_per_node=64 --rdzv_backend c10d --rdzv_endpoint localhost:0\
 --local-ranks-filter 0 --rol rank --tee 3\
 -m torchtitan.train --module neuron_qwen3 --config native_qwen3_4b\
 --override.importa mis núcleos neuron_

Antes de que comience el entrenamiento, torchtitan registra cada nodo de configuración al que reemplaza la anulación. Confirme que la salida contenga una entrada nki_rope

para cada capa de Qwen3:
[Anular] nki_rope: model_spec.model.layers.0.attention.rope CossinRopeConfig -> NKirope.config
[Anular] nki_rope: model_spec.model.layers.1.attention.rope COSSINropeConfig -> NKirope.config

Establece la longitud de la secuencia en un múltiplo de 128 * LNC, que es 256 cuando LNC es 2. Cambie la forma de la caché rotativa a [seq, head_dim * 2], con valores de coseno en la primera mitad y valores de seno en la segunda. El núcleo valida estas

restricciones antes de que comience el entrenamiento.

Para ver un ejemplo completo de torchtitan, consulte torchtitan_neuron/models/gpt_oss/nki_attention.py. Conecta los núcleos nkilib flash-attention a través del mismo operador y mecanismo de anulación.

También gestiona las entradas de dTensor para el paralelismo de los tensores.

Antes de entrenar con un núcleo personalizado, compare sus resultados con la implementación a la que reemplaza. En la prueba numérica con entradas de float32, la incrustación rotativa PyTorch de rope_hf y torchtitan produjo una diferencia absoluta máxima de

0.0 tanto para la consulta como para la clave.

Cuando registre varias anulaciones, limite cada una de ellas a las instancias de módulo deseadas con fqns. Por ejemplo, fqns= ["layers.1 [0-9] .attention.rope"] tiene como objetivo la incrustación rotativa de las capas 10 a 19. torchtitan se detiene cuando dos anulaciones reclaman el mismo nodo y avisa cuando una anulación no coincide con ningún nodo.

Revisa el resultado del entrenamiento

Al inicio, confirme que torchtitan reporta 64 rangos y el modelo esperado. El primer paso incluye la compilación y lleva más tiempo que los pasos posteriores. Cada paso del entrenamiento informa sobre la pérdida, la norma de gradiente, el uso de la memoria de gran ancho de banda (HBM), el rendimiento y la utilización del modelo de FLOP (MFU). Para ejecutar el punto de control, confirme que la pérdida del primer paso es cercana a los 6,54. Para ejecutar el kernel personalizado, confirme que la anulación de nki_rope aparezca

una vez para cada capa de Qwen3.

Escale en toda la instancia

La misma configuración de paralelismo se aplica a las configuraciones del modelo nativo y de los Transformers. Un trn2.48xlarge expone 64 núcleos neuronales lógicos en un LNC=2.

Defina data_parallel_shard_degree = -1 para fragmentar los parámetros del modelo, los gradientes y el estado del optimizador en cada rango que inicie Torchrun.

Configura config.parallelism.tensor_parallel_degree para dividir los pesos de cada capa en un grupo de rangos. Cada rango calcula una porción de cada multiplicación de matrices.

Con el paralelismo de secuencias habilitado de forma predeterminada, las capas de normalización se ejecutan en las activaciones fragmentadas a lo largo de la dimensión de la secuencia. torchtitan combina el paralelismo tensorial con el paralelo de datos totalmente fragmentados (FSDP) en un DeviceMesh multidimensional.

Observe a HBM por rango a medida que aumenta el tamaño del modelo, la longitud de la secuencia o el tamaño del lote local. Estos valores determinan la cantidad de memoria que necesita cada rango

.

Limpiar

Si quieres conservar tus puntos de control, cópialos en un almacenamiento permanente antes de limpiarlos. Si planeas reutilizar la instancia, deténgala. Cuando ya no necesites la instancia, termínala.

Conclusión

AWS Trainium funciona como un dispositivo Torchtitan compatible en las tres configuraciones de este tutorial. Puedes entrenar a Qwen3 con Hugging Face Transformers v5 y cargar o guardar directamente los safetensores publicados. También puedes entrenar con la implementación nativa de Qwen3 de torchtitan configurando config.model_spec. Para modelos con una mezcla de expertos, usa las recetas de NKI de torchtitan-neurona. En el caso de los núcleos personalizados, utilice el registro de anulación para adjuntar operadores de NKI mediante el mismo flujo de lanzamiento

.

Para obtener instrucciones sobre la configuración, consulte la documentación de AWS Neuron. Para ver las fuentes actuales y las recetas de formación, consulte el repositorio torchtitan

.


Acerca de los autores

Josh Longenecker

Josh Longenecker

Josh es arquitecto de soluciones en el equipo de aceleración de aprendizaje automático de Annapurna Labs en AWS. Ayuda a los clientes a diseñar, optimizar e implementar cargas de trabajo distribuidas de entrenamiento e inferencia de IA en AWS Trainium. Sus intereses técnicos incluyen PyTorch distribuido, el entrenamiento e inferencia de modelos de lenguaje de gran tamaño y

los núcleos de NKI.
Alex Hoffman

Alex Hoffman

Alex es un ingeniero de software que trabaja en la formación distribuida en AWS Annapurna Labs. Con torchtitan-neuron, posibilita experiencias de formación integrales para los clientes de AWS Trainium

en TorchNeuron.

¿Tiene un proyecto de software o plataforma SaaS en mente?

Hable directamente con nuestros arquitectos de software en SoftAndino. Le brindamos asesoría técnica y cotización inmediata sin compromiso.