惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News | PayPal Newsroom
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
C
Cisco Blogs
SecWiki News
SecWiki News
Know Your Adversary
Know Your Adversary
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
NISL@THU
NISL@THU
WordPress大学
WordPress大学
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Threat Research - Cisco Blogs
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
Security Archives - TechRepublic
Security Archives - TechRepublic
有赞技术团队
有赞技术团队
L
LINUX DO - 热门话题
Hacker News: Ask HN
Hacker News: Ask HN
V
V2EX
G
GRAHAM CLULEY
TaoSecurity Blog
TaoSecurity Blog
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
Latest news
Latest news
The Hacker News
The Hacker News
aimingoo的专栏
aimingoo的专栏
T
Troy Hunt's Blog
S
Schneier on Security
I
Intezer
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
爱范儿
爱范儿
The Register - Security
The Register - Security
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
博客园 - 聂微东
宝玉的分享
宝玉的分享
Recent Commits to openclaw:main
Recent Commits to openclaw:main
美团技术团队
B
Blog RSS Feed

Lei Mao's Log Book

2026 FIFA World Cup 备受嘲讽的会徽 Python Debugging Via VS Code In Docker Container Vargas Plateau Regional Park 徒步 Vargas Plateau Regional Park Apex 2026 FIFA World Cup 小组赛赛程 Retaining EXIF Metadata In GIMP San Francisquito Creek Joint Powers Authority 2025 Calendar Photo 麦当劳 The FIFA World Cup 套餐 Ardenwood Historic Farm 徒步 Ardenwood Historic Farm Synchronizations With TorchRec KeyedJaggedTensor Pacific Commons Linear Park 徒步 Pacific Commons Linear Park 2026 San Jose Half Marathon 竞赛 目标 Mountain View Shoreline Park 徒步 Mountain View Shoreline Park PyTorch AOTInductor Hybrid Lowering Carquinez Strait Regional Shoreline 徒步 Carquinez Strait Regional Shoreline PyTorch Triton Kernel Transparent Tracing and Compilation 脸庞 2026 BRAIN Foundation 10K 竞赛 2026 Wild and Scenic Film Festival 参观 2026 Wild and Scenic Film Festival 系统工程程序员修 Bug FIFA 官方网站的语言 PyTorch Custom Operation 汉堡王 The Mandalorian and Grogu 套餐 Tilden Regional Parks Botanic Garden 参观 Tilden Regional Park Tilden Regional Parks Botanic Garden Tilden Regional Park 徒步 《寻秦记》电影版 ICML 2026 Area Chair Experience 2026 Foster City 5K Fun Run 竞赛 2026 年 3 月和 4 月该入手的模型手办 Docker Container GUI Display Using Wayland 马拉松破二 2026 Heart & Soles Run 5K 竞赛 How Is FARS, The Fully Automated Research System? 算计: 七天的死亡游戏 Lake Chabot Regional Park 徒步 Lake Chabot Regional Park 2023 年恐怖电影《感恩节》 2026 Airport Runway Run at San Carlos Airport 5K 竞赛 Page Table for Page-Locked Host Memory Don Edwards San Francisco Bay National Wildlife Refuge - Ravenswood 徒步 Don Edwards San Francisco Bay National Wildlife Refuge - Ravenswood 法外风云 PyTorch Graph Symbolic Integer Contra Costa Canal Regional Trail 徒步 Contra Costa Canal Regional Trail 娑婆诃 PyTorch Export 2026 Western Pacific 5K 竞赛 浮躁的科研和胡扯的自媒体 Connecting Logitech Devices On Linux 2026 Oakland Half Marathon 竞赛 Del Valle Regional Park 徒步 Del Valle Regional Park CUDA_LAUNCH_BLOCKING=1 踏切时间 Wildcat Canyon Regional Park 徒步 Wildcat Canyon Regional Park Credit Card Unauthorized Transaction While In Possession 莎拉的真伪人生 2026 Union City Superhero Fun Run 5K 竞赛 McLaughlin Eastshore State Park 徒步 McLaughlin Eastshore State Park Cloudflare Worker Proxy R2 Bucket Access Zorro 和 Batman Fix MacBook Pro Space Key Stuck Problem 2026 年 1 月和 2 月该入手的模型手办 2026 Brazen Victory 10K 竞赛 儿时的玩伴李峰 Marsh Creek Regional Trail 徒步 Marsh Creek Regional Trail Perfetto GPU Flow Artifacts 百万人推理 System Performance Optimizations QQ 幻想 2026 Brazen Bay Breeze 5K 竞赛 CUDA Shared Memory Bank Conflict-Free Vectorized Access Dota 闪电站出售 Mountain View Downtown 徒步 Mountain View Downtown C++ Latch and Barrier 2025 年跑步总结 2026 Rotary Mission Ten Half Marathon 竞赛 狗的素质等于人的素质 CUDA Rendezvous Stream Pleasanton Ridge Regional Park 徒步 Pleasanton Ridge Regional Park Xfinity Internet 多年来的使用感受 Randomized SVD Don Castro Regional Recreation Area 徒步 Don Castro Regional Recreation Area 拖车公司的大汉们
PyTorch Fake Export
Lei Mao · 2026-05-17 · via Lei Mao's Log Book

   blog 11 minutes read (About 1634 words)  visits

Introduction

PyTorch torch.export APIs produces a standardized, single-graph representation of a deep learning model designed for deployment in Python-less environments. Unlike other model export APIs and graph representations, such as torch.onnx.export APIs and ONNX, PyTorch exported program is not a pure device graph. In one PyTorch exported program, the graph can contain operators on different devices, and even explicit device transfer operators. Consequently, there is a difference between the CPU exported program and GPU exported program of the same PyTorch model.

Deep learning models are getting much larger and complex nowadays, and it is often common that a model cannot fit on a single GPU. On host, usually there is plenty of CPU memory to fit and run one large model. So a natural question is, how can the developer verify that the large model being developed can be successfully exported to a GPU exported program using torch.export APIs. Certainly, moving the model to CPU and run torch.export on CPU is an incorrect way to verify, even if the model can be run successfully on CPU, because of the difference between CPU and GPU exported programs. To address this problem, PyTorch provides a way to construct a fake model whose parameters are fake tensors on specific devices, such as CPU or GPU, that have no actual data. To verify the exportability of a large fake model, the developer can also use fake tensors as example inputs to run torch.export APIs for tracing.

In this blog post, I would like to discuss how to run PyTorch export for fake models with fake tensors for verifying the torch.export compatibility of a large model.

PyTorch Fake Export

In the following example, we define a simple MLP model with two linear layers and a GELU activation in between. The first linear layer and the activation are placed on fc1_device, and the second linear layer is placed on fc2_device. When executing the model, the output of the activation is transferred to the device of the second linear layer before being fed into it.

To instantiate a fake model, we create the model inside FakeTensorMode. To specify the device placement of the model, we can use torch.device context manager when constructing the linear layers, instead of using the PyTorch to API because the to move API would require accessing the actual data of tensors.

test_torch_fake_export.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import torch
import torch.nn as nn
from torch._subclasses.fake_tensor import FakeTensor, FakeTensorMode


class MLP(nn.Module):
"""MLP configurable across CPU, GPU, or a CPU-GPU hybrid split.

fc1 (+ GELU) is placed on *fc1_device*; fc2 is placed on *fc2_device*.
When the two devices differ the forward pass inserts an explicit device
transfer, preserved as an aten._to_copy node in the exported graph.
When they are the same the transfer is a no-op.
"""

def __init__(
self,
in_features: int,
hidden_features: int,
out_features: int,
fc1_device: torch.device = torch.device("cpu"),
fc2_device: torch.device = torch.device("cpu")
) -> None:
super().__init__()
with torch.device(fc1_device):
self.fc1 = nn.Linear(in_features, hidden_features)
self.act = nn.GELU()
with torch.device(fc2_device):
self.fc2 = nn.Linear(hidden_features, out_features)

def forward(self, x: torch.Tensor) -> torch.Tensor:
h = self.act(self.fc1(x))

h = h.to(self.fc2.weight.device)
return self.fc2(h)


def fake_export(fc1_device: torch.device,
fc2_device: torch.device) -> torch.export.ExportedProgram:
"""Export the MLP with fake tensors for the given device configuration.

Both parameters and the example input are fake tensors created inside
FakeTensorMode, so no real memory is allocated on either device.
"""
with FakeTensorMode():
model = MLP(in_features=128,
hidden_features=256,
out_features=10,
fc1_device=fc1_device,
fc2_device=fc2_device).eval()
assert all(isinstance(p, FakeTensor) for p in model.parameters(
)), "Model parameters were unexpectedly materialized (not FakeTensor)"
example_input = torch.randn(4, 128, device=fc1_device)
return torch.export.export(model, (example_input, ))


if __name__ == "__main__":

cpu_device = torch.device("cpu")
gpu_device = torch.device("cuda")


ep_cpu = fake_export(fc1_device=cpu_device, fc2_device=cpu_device)
print("MLP export (CPU) succeeded.")
print(ep_cpu)

ep_gpu = fake_export(fc1_device=gpu_device, fc2_device=gpu_device)
print("MLP export (GPU) succeeded.")
print(ep_gpu)

ep_hybrid = fake_export(fc1_device=cpu_device, fc2_device=gpu_device)
print("CPU-GPU hybrid export succeeded.")

print(ep_hybrid)

Using NVIDIA NGC Docker container nvcr.io/nvidia/pytorch:26.04-py3, we could run the above script and see the successful export of the MLP fake model for CPU, GPU, and CPU-GPU hybrid device configurations. There will be no actual data allocated for the model parameters and the example input during the export, thanks to the use of fake tensors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
$ python test_torch_fake_export.py
MLP export (CPU) succeeded.
ExportedProgram:
class GraphModule(torch.nn.Module):
def forward(self, p_fc1_weight: "f32[256, 128]", p_fc1_bias: "f32[256]", p_fc2_weight: "f32[10, 256]", p_fc2_bias: "f32[10]", x: "f32[4, 128]"):

linear: "f32[4, 256]" = torch.ops.aten.linear.default(x, p_fc1_weight, p_fc1_bias); x = p_fc1_weight = p_fc1_bias = None


gelu: "f32[4, 256]" = torch.ops.aten.gelu.default(linear); linear = None


_assert_tensor_metadata_default = torch.ops.aten._assert_tensor_metadata.default(gelu, dtype = torch.float32, device = device(type='cpu'), layout = torch.strided); _assert_tensor_metadata_default = None
to: "f32[4, 256]" = torch.ops.aten.to.dtype_layout(gelu, dtype = torch.float32, layout = torch.strided, device = device(type='cpu')); gelu = None


linear_1: "f32[4, 10]" = torch.ops.aten.linear.default(to, p_fc2_weight, p_fc2_bias); to = p_fc2_weight = p_fc2_bias = None
return (linear_1,)

Graph signature:

p_fc1_weight: PARAMETER target='fc1.weight'
p_fc1_bias: PARAMETER target='fc1.bias'
p_fc2_weight: PARAMETER target='fc2.weight'
p_fc2_bias: PARAMETER target='fc2.bias'
x: USER_INPUT


linear_1: USER_OUTPUT

Range constraints: {}

MLP export (GPU) succeeded.
ExportedProgram:
class GraphModule(torch.nn.Module):
def forward(self, p_fc1_weight: "f32[256, 128]", p_fc1_bias: "f32[256]", p_fc2_weight: "f32[10, 256]", p_fc2_bias: "f32[10]", x: "f32[4, 128]"):

linear: "f32[4, 256]" = torch.ops.aten.linear.default(x, p_fc1_weight, p_fc1_bias); x = p_fc1_weight = p_fc1_bias = None


gelu: "f32[4, 256]" = torch.ops.aten.gelu.default(linear); linear = None


_assert_tensor_metadata_default = torch.ops.aten._assert_tensor_metadata.default(gelu, dtype = torch.float32, device = device(type='cuda', index=0), layout = torch.strided); _assert_tensor_metadata_default = None
to: "f32[4, 256]" = torch.ops.aten.to.dtype_layout(gelu, dtype = torch.float32, layout = torch.strided, device = device(type='cuda', index=0)); gelu = None


linear_1: "f32[4, 10]" = torch.ops.aten.linear.default(to, p_fc2_weight, p_fc2_bias); to = p_fc2_weight = p_fc2_bias = None
return (linear_1,)

Graph signature:

p_fc1_weight: PARAMETER target='fc1.weight'
p_fc1_bias: PARAMETER target='fc1.bias'
p_fc2_weight: PARAMETER target='fc2.weight'
p_fc2_bias: PARAMETER target='fc2.bias'
x: USER_INPUT


linear_1: USER_OUTPUT

Range constraints: {}

CPU-GPU hybrid export succeeded.
ExportedProgram:
class GraphModule(torch.nn.Module):
def forward(self, p_fc1_weight: "f32[256, 128]", p_fc1_bias: "f32[256]", p_fc2_weight: "f32[10, 256]", p_fc2_bias: "f32[10]", x: "f32[4, 128]"):

linear: "f32[4, 256]" = torch.ops.aten.linear.default(x, p_fc1_weight, p_fc1_bias); x = p_fc1_weight = p_fc1_bias = None


gelu: "f32[4, 256]" = torch.ops.aten.gelu.default(linear); linear = None


_assert_tensor_metadata_default = torch.ops.aten._assert_tensor_metadata.default(gelu, dtype = torch.float32, device = device(type='cpu'), layout = torch.strided); _assert_tensor_metadata_default = None
to: "f32[4, 256]" = torch.ops.aten.to.dtype_layout(gelu, dtype = torch.float32, layout = torch.strided, device = device(type='cuda', index=0)); gelu = None


linear_1: "f32[4, 10]" = torch.ops.aten.linear.default(to, p_fc2_weight, p_fc2_bias); to = p_fc2_weight = p_fc2_bias = None
return (linear_1,)

Graph signature:

p_fc1_weight: PARAMETER target='fc1.weight'
p_fc1_bias: PARAMETER target='fc1.bias'
p_fc2_weight: PARAMETER target='fc2.weight'
p_fc2_bias: PARAMETER target='fc2.bias'
x: USER_INPUT


linear_1: USER_OUTPUT

Range constraints: {}