TorchNeuron: running HF models on AWS Trainium is easier than ever
Summary
TorchNeuron 作为 PyTorch 的原生 Trainium 后端发布公测,Hugging Face 的 Transformers、Diffusers 等库可直接将其作为普通设备使用,显著提升了模型支持率并取代 Optimum Neuron 的复杂封装。
View Cached Full Text
Cached at: 10/20/26, 01:05 AM
TorchNeuron: running HF models on AWS Trainium is easier than ever
Source: https://huggingface.co/blog/hf-torchneuron TorchNeuron provides a new native backend for PyTorch on AWS Trainium. Transformers, Diffusers and Kernels natively support it, making it easier than ever to run models on Trainium and to share them on the HF hub.
https://huggingface.co/blog/hf-torchneuron#torchneuronTorchNeuron
TorchNeuronis a PyTorch plugin that brings a new backend for Trainium enabling support for eager mode,torch\.compileand native distributed APIs like FSDP and TP. Read the Pytorchblogto learn more about TorchNeuron.
Starting Oct. 20, 2026, TorchNeuron will be available as a public beta. Researchers and developers will be able to install it withpip install torch\-neuronx.
https://huggingface.co/blog/hf-torchneuron#new-backend-native-interface-in-hf-librariesNew backend, native interface in HF libraries
To date, the Hugging Face experience on AWS Trainium and Inferentia — AI chips designed respectively for cost-effective training and inference at scale — has been delivered throughoptimum-neuron. This library relies on the torch-neuronx package, which is based on PyTorch XLA. It was the natural choice at the time, but it meant thinking like a compiler: lazy tensors instead of eager execution, static shapes only, a recompilation for every graph break. Optimum Neuron existed to hide that complexity, and maintained custom code (modeling classes, trainers, etc) to do so.
TorchNeuron changes this. It integrates directly into PyTorch and exposesneuronas a native device, with eager execution, PyTorch’s own distributed primitives (DTensor, FSDP2) andtorch\.compile.
For the Hugging Face libraries, Trainium becomes a device like any other: Transformers, Diffusers, Accelerate, PEFT and TRL run on it directly, with the same classes and scripts you would use on any other accelerator. From now on, we recommend that Neuron users use these libraries directly instead of going through Optimum Neuron.
https://huggingface.co/blog/hf-torchneuron#transformersTransformers
https://huggingface.co/blog/hf-torchneuron#inferenceInference
Text generation is now natively supported in Transformers for a wide range of models. With TorchNeuron, 89% of the top 100 most-used text-generation model architectures are supported out of the box, compared to 46% with Optimum Neuron v0.4.5. You just need to pass thedevice\_map=neuronargument in your code and your model will be moved to the Neuron devices.
The following is an example of text-generation with tensor parallelism, which will enable to fully benefit from your Neuron instance. Note that it uses a static cache for generation as this is strongly recommended with Neuron to prevent frequent recompilations.
import os
import torch
import torch.distributed as dist
import torch_neuronx # noqa: F401
from torch.distributed import DeviceMesh
from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfig
from transformers.distributed import DistributedConfig
from transformers.generation.configuration_utils import CompileConfig
MODEL_ID = "Qwen/Qwen3.8-27B"
MAX_SEQ_LEN = 1024
PREFILL_CHUNK_SIZE = 512
dist.init_process_group(backend="neuron")
world_size = dist.get_world_size()
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
dtype=torch.bfloat16,
distributed_config=DistributedConfig(tp_size=world_size),
device_mesh=DeviceMesh("neuron", list(range(world_size))),
).eval()
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "left"
inputs = tokenizer.apply_chat_template(
[{"role": "user", "content": "The future of AI is"}],
add_generation_prompt=True,
padding=True,
tokenizer_kwargs={"pad_to_multiple_of": PREFILL_CHUNK_SIZE},
return_tensors="pt",
)
generation_config = GenerationConfig(
max_new_tokens=128,
do_sample=False,
use_cache=True,
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id,
cache_implementation="static",
max_cache_len=MAX_SEQ_LEN,
prefill_chunk_size=PREFILL_CHUNK_SIZE,
compile_config=CompileConfig(backend="neuron", fullgraph=False, dynamic=False),
)
with torch.no_grad():
output_ids = model.generate(
inputs["input_ids"],
attention_mask=inputs["attention_mask"],
generation_config=generation_config,
)
if dist.get_rank() == 0:
prompt_len = inputs["input_ids"].shape[1]
print(tokenizer.decode(output_ids[0, prompt_len:], skip_special_tokens=True))
https://huggingface.co/blog/hf-torchneuron#trainingTraining
Now that Neuron is a native PyTorch device, training on Trainium uses the same Hugging Face libraries as any other accelerator: Transformers, Accelerate, PEFT and TRL. You no longer need a dedicated trainer or a Neuron-specific fork of the model code. A standard TRL fine-tuning script runs on a Trainium instance with only a few Neuron-specific settings.
Here is a supervised fine-tuning script built on TRL’sSFTTrainer. If you have fine-tuned a model with TRL on GPUs before, it should look familiar.
import os
import torch
from datasets import load_dataset
from transformers.distributed import DistributedConfig
from trl import ModelConfig, ScriptArguments, SFTConfig, SFTTrainer, TrlParser
def main(script_args, training_args, model_args):
# The Neuron backend can't compile Dynamo's automatic dynamic shapes yet (https://github.com/huggingface/trl/issues/7660)
torch._dynamo.config.automatic_dynamic_shapes = False
training_args.model_init_kwargs = {
"revision": model_args.model_revision,
"trust_remote_code": training_args.trust_remote_code,
"attn_implementation": model_args.attn_implementation,
"dtype": model_args.dtype,
"device_map": None,
}
if int(os.environ.get("WORLD_SIZE", "1")) > 1:
# The model is sharded on the TP x FSDP grid as its weights are loaded
training_args.model_init_kwargs["distributed_config"] = DistributedConfig(
tp_size=int(os.environ.get("TP_SIZE", "1")),
fsdp_size=int(os.environ.get("FSDP_SIZE", "1")),
)
# Prepare dataset
train_dataset = load_dataset(
script_args.dataset_name,
name=script_args.dataset_config,
split=script_args.dataset_train_split,
)
# UltraChat also has a string `prompt` column, which makes TRL treat it as a prompt-completion dataset.
train_dataset = train_dataset.select_columns(["messages"])
# Training
trainer = SFTTrainer(
model=model_args.model_name_or_path,
args=training_args,
train_dataset=train_dataset,
)
trainer.train()
trainer.save_model(training_args.output_dir)
trainer.end()
if __name__ == "__main__":
parser = TrlParser((ScriptArguments, SFTConfig, ModelConfig))
script_args, training_args, model_args = parser.parse_args_and_config()
main(script_args, training_args, model_args)
Parallelism is handled natively by Transformers. You put aDistributedConfigwith the tensor-parallel (TP) and FSDP sizes inmodel\_init\_kwargs,SFTTrainerpasses it tofrom\_pretrained, and the model is sharded as its weights are loaded. The Trainer sees that the model is already distributed and does not wrap it again. You don’t need an\-\-fsdpflag or an Accelerate FSDP config.
Nothing in the script is tied to Trainium: the same code runs on any hardware. A few things are worth knowing when you run it on Trainium:
- **Static shapes.**The script disables automatic dynamic shapes in
torch\.compileand uses wrapped packing to produce sequences of up to 2048 tokens. With TRL ≥ 1.16, batches on Neuron are padded to a multiple of 128 tokens, limiting the number of input shapes. Compiled graphs are reused for subsequent steps with the same shapes. - **
torch\.compileon.**Passing\-\-torch\_compile trueis all it takes: on a Trainium instance,torch\.compiledetects the device and picks the Neuron backend automatically, with nothing else to configure. - **Async weight loading off.**The built-in asynchronous weight loading in Transformers is not supported on Neuron, so for now we disable it with
HF\_DEACTIVATE\_ASYNC\_LOAD=1.
The command below launches training withtorchrun, which starts one process per NeuronCore.TP\_SIZEandFSDP\_SIZEset the parallelism layout, and their product is the number of processes: here 4 x 8 = 32, matching\-\-nproc\_per\_node. The 32 processes form a 4 x 8 grid. Tensor parallelism splits each layer across the 4 cores of a TP group, and FSDP shards the parameters, gradients and optimizer state across the 8 TP groups.
TP_SIZE=4 FSDP_SIZE=8 HF_DEACTIVATE_ASYNC_LOAD=1 uv run torchrun --nproc_per_node=32 sft_neuron_example.py \
--model_name_or_path Qwen/Qwen3-8B \
--dataset_name HuggingFaceH4/ultrachat_200k \
--dataset_train_split train_sft \
--output_dir Qwen3-8B-sft-tp4-fsdp8 \
--dtype bfloat16 \
--max_length 2048 \
--packing true \
--packing_strategy wrapped \
--learning_rate 2e-5 \
--warmup_steps 0.03 \
--num_train_epochs 1 \
--logging_steps 2 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 4 \
--save_only_model true \
--torch_compile true
We ran it on 8 Trainium2 chips (32 NeuronCores), which is half atrn2\.48xlargeinstance.
Training runs to completion, andtrainer\.save\_modelwrites a standard Transformers checkpoint. Nothing in it is tied to Neuron: you can push it to the Hugging Face Hub as is and load it on any other hardware.
https://huggingface.co/blog/hf-torchneuron#diffusersDiffusers
https://huggingface.co/blog/hf-torchneuron#inference-1Inference
Many pipelines from the Diffusers library are compatible with TorchNeuron in eager and compiled mode. FLUX.1-dev, FLUX.2, Qwen-Image, Qwen-Image-2.1 and H3 are also compatible with tensor parallelism to make the most of your Neuron devices. The following is an example showing how you can use TP:
import torch, torch.distributed as dist, torch_neuronx # TP
from torch.distributed.device_mesh import DeviceMesh # TP
from diffusers import QwenImage21Pipeline, QwenImage21Transformer2DModel, TensorParallelConfig
# Distributed devices initialization
dist.init_process_group(backend="neuron") # TP
dev = torch.neuron.current_device()
mesh = DeviceMesh("neuron", list(range(8))) # TP=8
# Pipeline initialization
model = "Qwen/Qwen-Image-2.1"
transformer = QwenImage21Transformer2DModel.from_pretrained(
model,
subfolder="transformer",
torch_dtype=torch.bfloat16,
parallel_config=TensorParallelConfig(mesh=mesh), # TP
)
pipe = QwenImage21Pipeline.from_pretrained(
model,
transformer=transformer,
torch_dtype=torch.bfloat16,
)
pipe.vae.to(dev)
pipe.transformer.compile_repeated_blocks(backend="neuron", fullgraph=True, dynamic=False)
# Image generation
emb, mask, _ = pipe.encode_prompt(prompt="A capybara wearing a wizard hat, oil painting", device="cpu") # text encoder stays on CPU
image = pipe(
prompt_embeds=emb.to(dev),
prompt_embeds_mask=mask.to(dev) if mask is not None else None,
height=1024,
width=1024,
num_inference_steps=40,
generator=torch.Generator("cpu").manual_seed(0), # same noise on every rank
).images[0]
if dist.get_rank() == 0:
image.save("out.png")
You can run this piece of code with:NEURON\_LOGICAL\_NC\_CONFIG=2 torchrun \-\-nproc\_per\_node=8 run\.py.
More and more pipleines will be compatible with TP. If a pipeline you like is not, you can also add support for it followingthis guide.
https://huggingface.co/blog/hf-torchneuron#kernelsKernels
Make sure to check out thekernels from the Neuron teamas more and more Neuron kernels will become available on the Hub to speed up your models. Neuron kernels can be written using theNeuron Kernel Interface(NKI), which gives lower control to optimize operations. This way, users can run their own custom operations and share them on the hub.
You can use for examplethis kernelto speed up your vision transformers with up to a x2.4 speedup on Trainium!
https://huggingface.co/blog/hf-torchneuron#acknowledgmentsAcknowledgments
Special thanks to the AWS team for their work on TorchNeuron and for their reactivity to our feedback to make the HF integration as good as possible.
Similar Articles
@ajassy: Trying a new AI chip used to be a lot of work. You often had to rewrite your code, revalidate it, and sink many weeks i…
Amazon 发布 TorchNeuron,让现有 PyTorch 代码无需重写即可原生运行在 AWS Trainium 芯片上,并将于 10 月 20 日 PyTorch Conference 上开源。该工具旨在降低开发者切换 AI 硬件的成本,已有多家企业在机器人、自动驾驶、大模型等领域采用。
@PyTorch: More hardware choice for PyTorch developers: TorchNeuron registers @awscloud Trainium as a native device, built on the …
PyTorch and AWS announce TorchNeuron, an open-source native PyTorch backend for AWS Trainium chips, letting developers run existing PyTorch code with a simple `.to('neuron')` switch, supporting eager execution, torch.compile, and NKI custom kernels. It will launch as public beta under Apache 2.0 at the PyTorch Conference on Oct. 20.
Amazon is taking its biggest shot at Nvidia yet with new TorchNeuron dev tool
Amazon Web Services 发布了 TorchNeuron 开发工具,让 PyTorch 应用仅需一行配置即可迁移到其 Trainium AI 芯片上,直接挑战 Nvidia 在 AI 软件生态上的主导地位,并将相关改动贡献给 PyTorch 上游项目。
@PyTorch: Sponsor news from @awsdevelopers: PyTorch now runs natively on AWS Trainium. See it live at PyTorch Conference NA (Oct …
AWS 宣布 PyTorch 现已原生支持 AWS Trainium 芯片,并将在 PyTorch Conference North America(10月20-21日,圣何塞)由 Amazon VP Distinguished Engineer Robert Hundt 发表主题演讲、AWS Neuron Principal PM Maen Suleiman 进行现场演示。
@FakeMaidenMaker: Incredible! This open-source project can significantly speed up and save VRAM for self-hosted large model inference. It has garnered 9.2K stars on GitHub, joined the PyTorch Foundation, and NVIDIA's Dynamo has integrated it. GitHub: https://github.com/LMC…
LMCache is a KV cache management layer that accelerates large model inference and reduces VRAM consumption by caching and reusing KV cache. It has received 9.2K stars and joined the PyTorch Foundation, and is integrated by NVIDIA Dynamo.
