gpumode · 강의 아카이브
《GPU Mode》 L082 2025 High priority transcript · failed

Helion — PyTorch-native 한 ML 커널 DSL

Triton 의 표현력은 살리되, PyTorch 의 텐서 의미를 그대로 안에 끌어들여 “한 줄 한 줄을 GPU 위 어디로 보낼지” 고민할 필요 없이 짠다는 시도. Jason Ansel · Oguz Ulgen · Will Feng 이 PyTorch Labs 안에서 만든 Helion 의 위치, lowering 파이프라인, 그리고 기존 Triton 코드와 어떻게 다른지를 — 자막 없이 — 외부 자료와 도메인 지식으로 재구성한 학습 노트.

Helion Triton PyTorch-native DSL autotune torch.compile tile language attention
J
Speaker
Jason Ansel · Oguz Ulgen · Will Feng
Meta · PyTorch core / compiler 팀
강의 번호
L082
스피커
Ansel · Ulgen · Feng
학습 우선순위
High · 정독
자막
failed · 외부 자료
§ 01강의가 풀려는 문제· Why Helion exists

“Triton 보다 더 PyTorch 같은 DSL 이 정말 필요한가” 라는 질문에 대한 답

2024–2025 사이 PyTorch 진영의 큰 흐름 하나는 — 커널 작성을 사용자에게서 컴파일러에게로 다시 끌어오는 방향이다. Helion 은 그 흐름의 가장 새로운 한 점. Triton 이 “파이썬으로 GPU 커널을 짜자” 였다면, Helion 은 “PyTorch 코드처럼 보이는 커널 DSL” 이 출발점이다.

강의는 PyTorch Labs 의 세 사람 — torch.compile / Inductor 의 핵심을 짠 Jason Ansel, Triton 통합을 끌고 온 Oguz Ulgen, 그리고 Will Feng — 이 함께 발표한 형태다. 자막이 실패해 화면에서 직접 코드를 본 디테일은 잡히지 않지만, 외부에 공개된 Helion 의 설계 문서와 PyTorch 컴파일러 진영의 일관된 이야기 흐름에서 다음 세 줄을 읽어낼 수 있다.

  1. Triton 은 “파이썬으로 짜는 SASS” 에 가깝다 — 표현력은 강력하지만, tl.load / tl.store / BLOCK_SIZE / mask 같은 GPU-네이티브 개념을 매번 손으로 다뤄야 한다.
  2. PyTorch 사용자는 그렇게 짜고 싶지 않다 — 텐서 슬라이싱, 브로드캐스팅, 같은 indexing 의미가 커널 안에서도 그대로 작동했으면 한다.
  3. 그렇다고 torch.compile 만으로는 부족하다 — 컴파일러가 자동으로 잘 만드는 것 이상이 필요한 자리(특수한 attention 변형, 새 양자화 커널, custom fused op)는 항상 남는다.

Helion 은 이 셋 사이의 빈 자리를 메우려 한다 — “직접 커널을 짜되, PyTorch 의 의미가 그대로 살아 있고, 결국에는 Triton 으로 lowering 되어 같은 백엔드 위에서 돈다”. 새 컴파일러를 처음부터 짜는 게 아니라, Triton 위에 얹는 더 친숙한 layer 라는 위치가 핵심이다.

강의의 frame · 확인 필요

이 노트는 자막이 실패한 상태에서 Helion 의 공식 repo / PyTorch 블로그 / Jason Ansel 의 컨퍼런스 발표(PyTorch Conference, GTC 2025 트랙)를 종합해 재구성했다. 강의 안에서만 등장한 구체적 벤치마크 수치, 데모의 정확한 시퀀스는 확인 필요 표시로 남겨둔다.

“Triton 은 좋다 — 다만 사용자가 텐서 의미가 아니라 tile 의 메모리 주소를 머릿속에 들고 있어야 한다.”Helion 설계 메모 · 재구성
§ 02Triton 의 한계와 Helion 의 동기· Triton's friction surface

표현력은 충분한데, 매번 같은 보일러플레이트가 다시 등장한다

Triton 으로 커널을 한 100번 짠 사람이라면 같은 패턴이 반복된다는 걸 안다 — pid 계산, offsets 만들기, mask 처리, BLOCK_SIZE 상수 정의. 코드의 의미는 “이 텐서의 이 슬라이스를 그 텐서의 저 슬라이스에 더한다” 인데, 표현은 그것보다 한 층 아래에 머문다.

강의에서 Helion 팀이 정리한 Triton 의 친숙한 마찰점은 — 외부 발표 자료와 합쳐 보면 — 대략 다섯 갈래로 모인다.

  • indexing 의 verbosity — 같은 슬라이스를 PyTorch 에서 한 줄로 쓰던 것이 Triton 에서는 offsets + mask 의 조합이 된다.
  • shape polymorphism 의 부재 — 입력 모양이 바뀌면 launch grid 와 BLOCK 을 직접 다시 정해야 한다.
  • autotune 의 boilerplate@triton.autotune 데코레이터에 configs 를 매번 손으로 깐다.
  • PyTorch 와의 의미 차이tl.load 의 mask 와 PyTorch 의 텐서 인덱싱은 서로 다른 추상.
  • 읽기 어려움tl.where, tl.maximum, tl.exp 가 누적되면 “이 커널이 무엇을 하는 함수인지” 가 시야에서 빨리 사라진다.
FIG · Triton 코드의 마찰 표면같은 일을 짜는 다섯 위치
indexing
반복적
mask 처리
패턴화
launch shape
손맛
autotune cfg
boilerplate
코드 가독성
중간
위 막대는 Helion 팀이 발표에서 강조한 “자주 다시 등장하는 비용” 의 상대적 강도를 노트 정리용으로 재구성한 것. 실제 정량 측정은 아님.

Helion 팀의 진단 — “이 다섯이 매번 등장한다는 건 DSL 한 단계 더 위 에서 자동화될 수 있는 표시” 라는 것. 그래서 Helion 은 Triton 의 lowering 백엔드를 그대로 두되, 사용자에게 보이는 표면을 PyTorch 텐서 의미로 가져온다.

의도적으로 안 푸는 문제

Helion 은 Triton 을 대체하지 않는다. 커널 컴파일러로서의 Triton 은 그대로 산다. Helion 의 출력은 Triton 코드(또는 동등한 IR)이다. 이렇게 하면 Triton 의 빠른 진화(MLIR 백엔드, 새 PTX 생성) 를 Helion 도 그대로 받는다.

§ 03PyTorch-native API· tensor semantics inside DSL

커널 안에서도 텐서가 텐서다 — slice / broadcast / dtype 이 그대로 산다

Helion 의 가장 큰 차별점은 “DSL 안의 변수가 PyTorch 텐서의 의미를 따른다” 는 것. 같은 사용자가 같은 인덱싱을 두 군데서 다르게 외울 필요가 없다는 게 핵심.

Triton — tile-level primitives
# row-wise softmax (대략)
@triton.jit
def softmax_kernel(x_ptr, y_ptr, n_cols,
                   stride_xm, stride_ym,
                   BLOCK: tl.constexpr):
    pid    = tl.program_id(0)
    cols   = tl.arange(0, BLOCK)
    mask   = cols < n_cols
    x_row  = x_ptr + pid * stride_xm
    x      = tl.load(x_row + cols, mask=mask,
                     other=-float("inf"))
    x_max  = tl.max(x, axis=0)
    x      = x - x_max
    e      = tl.exp(x)
    z      = tl.sum(e, axis=0)
    y      = e / z
    y_row  = y_ptr + pid * stride_ym
    tl.store(y_row + cols, y, mask=mask)
Helion — PyTorch 의미 그대로 (개념적 형태)
# 강의 시연을 외부 자료로 재구성 — 확인 필요
@helion.kernel
def softmax(x: Tensor) -> Tensor:
    # tile 단위 loop — 행 분할은 컴파일러에게 맡김
    for tile_m in hl.tile(x.size(0)):
        row    = x[tile_m, :]            # PyTorch slice
        x_max  = row.amax(dim=-1, keepdim=True)
        e      = (row - x_max).exp()
        out    = e / e.sum(dim=-1, keepdim=True)
        y[tile_m, :] = out
    return y

두 코드가 같은 일을 한다 — 그러나 표현이 “다른 언어” 다. Helion 의 코드 안에서 row.amax(dim=-1) 는 PyTorch 의 그것과 같은 의미다. tl.max 와 의미가 다른 별도의 함수가 아니다. 컴파일러가 알아서 tile 안에서의 reduction 으로 lowering 한다.

이 디자인이 사용자에게 주는 효과는 두 가지로 정리된다.

“커널이라는 단어가 특수한 언어의 이름이 아니라, 같은 코드의 한 가지 실행 모드의 이름이 된다.”학습 노트 · 재구성
§ 04lowering 파이프라인· Helion → Triton → PTX

네 단계 — 그리고 그 사이에 autotune 이 박힌다

Helion 코드가 GPU 위에서 어떻게 도는지 한 번에 그려두는 게 빠르다. 자기 컴파일러를 다시 짜는 대신, 기존 인프라(Triton, Inductor, MLIR) 를 받아쓰는 형태가 일관된다.

FIG · Helion lowering 파이프라인4 stages + autotune
L0 Helion DSL@helion.kernel · PyTorch 텐서 의미 · hl.tile loop 사용자가 짜는 자리
L1 Helion IRtile 단위 dataflow + tensor 의미 그대로 보존 아직 GPU 의 모양이 박히지 않음
L2 autotune searchBLOCK · num_warps · num_stages · loop order 코드 변형 ∋ launch shape
L3 Triton 코드 생성@triton.jit kernel + launch wrapper 자동 생성 Triton 의 모든 백엔드 그대로 받음
L4 PTX / SASSarch 별 머신코드 — Triton 이 책임 실제 SM 위에서 돔
L2 의 autotune 이 핵심 — Helion 은 같은 소스에 대해 여러 Triton 코드 변형을 만들고 그중 빠른 걸 고른다. 사용자가 configs 를 손으로 깔지 않는다.

이 그림에서 짚어야 하는 디자인 결정 세 가지.

  1. L1 의 “텐서 의미 그대로” 가 가장 비싸다 — Helion IR 가 단순히 Triton AST 의 wrapper 였다면 의미가 없다. 슬라이스 / 브로드캐스트 / dtype 추론이 IR 수준에서 살아 있어야 L2 의 search 가 의미 있는 변형을 만들 수 있다.
  2. L2 가 사용자 코드에 손 안 대고 launch shape 을 결정한다 — 같은 Helion 코드가 hidden_dim=64 와 4096 에서 다른 BLOCK 으로 lowering 된다.
  3. L3 의 출력은 “읽을 수 있는 Triton” — 디버깅과 후속 최적화를 위해, Helion 이 만든 Triton 코드를 사람이 펼쳐 볼 수 있어야 한다는 디자인. TORCH_LOGS=output_code 의 사상과 같다.
Inductor 와의 위치

torch.compile 의 Inductor 도 Triton 을 출력한다. 차이는 — Inductor 는 fusion-driven 자동 컴파일러(주어진 graph 를 잘게 쪼개 fused Triton 커널을 만든다)고, Helion 은 사용자가 직접 짜는 DSL(어떤 알고리즘을 어떻게 tile 할지 사용자가 결정한다). 두 도구는 같은 lowering 인프라를 공유하지만 사용자에게 보이는 추상 레이어가 다르다.

§ 05예시: attention· tiled softmax · mask

FlashAttention-스타일 커널이 Helion 으로 어떻게 짜이는가

강의의 마지막 데모로 등장했을 가능성이 가장 높은 예시 — FlashAttention-스타일 의 tiled softmax + masked attention. Triton 진영의 거의 모든 새 DSL 이 이걸 첫 데모로 쓰는 이유는 — 충분히 복잡해서 표현력의 차이가 드러난다.

Triton FlashAttention (개념 형태)
@triton.jit
def attn_fwd(Q, K, V, O, M, ...,
             BLOCK_M: tl.constexpr,
             BLOCK_N: tl.constexpr):
    pid_m = tl.program_id(0)
    offs_m = pid_m*BLOCK_M + tl.arange(0, BLOCK_M)
    offs_n = tl.arange(0, BLOCK_N)

    q = tl.load(Q + offs_m[:,None]*sQm + ...,
                mask=...)
    m_i = tl.full([BLOCK_M], -float("inf"))
    l_i = tl.zeros([BLOCK_M])
    acc = tl.zeros([BLOCK_M, D])

    for start_n in range(0, N, BLOCK_N):
        k = tl.load(K + ..., mask=...)
        v = tl.load(V + ..., mask=...)
        s = tl.dot(q, tl.trans(k))
        m_new = tl.maximum(m_i, tl.max(s, axis=1))
        alpha = tl.exp(m_i - m_new)
        p = tl.exp(s - m_new[:,None])
        l_i = l_i*alpha + tl.sum(p, axis=1)
        acc = acc*alpha[:,None] + tl.dot(p, v)
        m_i = m_new

    o = acc / l_i[:,None]
    tl.store(O + ..., o, mask=...)
Helion FlashAttention (개념 형태 · 확인 필요)
@helion.kernel
def attn_fwd(Q, K, V):
    O = torch.empty_like(Q)
    for tile_m in hl.tile(Q.size(0)):
        q   = Q[tile_m, :]
        m_i = torch.full([q.size(0)], -inf)
        l_i = torch.zeros_like(m_i)
        acc = torch.zeros_like(q)

        for tile_n in hl.tile(K.size(0)):
            k = K[tile_n, :]
            v = V[tile_n, :]
            s = q @ k.transpose(-1, -2)

            # online softmax — PyTorch op 그대로
            m_new = torch.maximum(m_i, s.amax(-1))
            alpha = (m_i - m_new).exp()
            p     = (s - m_new[..., None]).exp()
            l_i   = l_i*alpha + p.sum(-1)
            acc   = acc*alpha[..., None] + p @ v
            m_i   = m_new

        O[tile_m, :] = acc / l_i[..., None]
    return O

두 코드가 의도하는 알고리즘은 같다 — online softmax 로 score matrix 를 통째로 들지 않으면서 attention 을 계산. 차이는 코드의 밀도다. Helion 쪽에서 tl.load/tl.store/mask 의 boilerplate 가 사라진 자리에 알고리즘 자체가 더 잘 보인다.

FlashAttention 알고리즘의 위치

Helion 이 FlashAttention 을 자동으로 만들어주는 것이 아니다. online softmax 라는 알고리즘 아이디어 자체는 사용자가 짜야 한다. Helion 이 자동화하는 건 “이 표현을 어떤 launch shape 으로 lowering 할지” 의 영역이다. 알고리즘 디자인과 launch 디자인의 분리 — 이게 Helion 이 PyTorch 사용자에게 주는 가장 큰 인지적 단순화.

“Helion 은 알고리즘을 발명해주지 않는다. 알고리즘과 launch 결정을 분리해줄 뿐이다 — 그게 충분히 큰 일이다.”학습 노트 · 재구성
§ 06autotune 통합· search space · shape

“같은 소스에서 여러 변형” 이 사용자 코드에 노출되지 않는다

Triton 의 @triton.autotune(configs=[...]) 를 한 번이라도 손으로 깔아본 사람은 안다 — configs 가 점점 길어지고, 새 모양이 등장할 때마다 다시 손을 봐야 한다. Helion 은 이 자리를 컴파일러 안으로 끌어들인다.

Helion 의 autotune 이 다루는 변수는 대략 다섯 갈래로 정리된다.

  • tile sizehl.tile 의 BLOCK 크기.
  • loop nesting / order — 같은 알고리즘에 대해 outer loop 를 m, n 중 누가 먼저 돌지.
  • num_warps / num_stages — Triton 의 launch 변수, Helion 의 search space 에 같이 들어감.
  • memory layout 변형확인 필요. transposed load, swizzle 같은 영역이 search 에 포함되는지는 현재 시점 미확정.
  • shape-conditional 분기 — 같은 소스가 입력 shape 에 따라 다른 변형으로 lowering.
FIG · autotune search 가 다루는 차원한 소스 → N 변형
tile_m
{32,64,128,256}
tile_n
{32,64,128,256}
num_warps
{2,4,8}
num_stages
{2,3,4}
loop order
{m→n,n→m}
조합 폭은 작지 않다. 핵심은 — 이 search space 가 사용자 코드에 노출되지 않는다. 같은 함수가 하드웨어와 shape 에 따라 다른 변형을 받는다.

실전 사용에서 Helion 의 autotune 이 의미를 갖는 자리는 shape 가 데이터에 따라 달라지는 워크로드다 — variable-length attention, KV cache 의 동적 크기, batch 별 다른 hidden_dim. Triton 의 정적 configs 에서 이런 워크로드가 가장 어렵게 다뤄지던 자리.

cache 의 자리

autotune 결과는 컴파일된 Triton 코드와 함께 cache 된다. 첫 호출에서만 search 가 돌고, 같은 (shape, dtype, hardware) 키에 대해서는 즉시 캐시된 변형이 쓰인다. ~/.cache/helion/ 같은 위치 — 확인 필요.

§ 07Triton 직접 짜기와 비교· side-by-side

“언제 Helion 이고, 언제 직접 Triton 인가”

L001 의 의사결정 사다리(torch → Triton → CUDA) 에 한 칸이 추가된다 — torch → Helion → Triton → CUDA. 각 칸의 trigger 가 무엇인지 정리.

Helion 이 더 적합한 곳
  • 알고리즘이 PyTorch 텐서 op 의 조합으로 표현 가능한 자리
  • 입력 shape 가 동적이고 autotune 효과가 큰 자리
  • 코드 가독성이 우선인 자리 (research / 빠른 iteration)
  • Triton 의 backend 진화를 그대로 받고 싶은 자리
  • 같은 코드를 PyTorch reference 와 numerical 비교하기 좋은 자리
직접 Triton 이 더 적합한 곳
  • 매우 비표준적인 메모리 접근 패턴 (custom swizzle, async copy 직접 제어)
  • Helion 의 IR 이 아직 표현하지 못 하는 op (확인 필요)
  • Tensor Core / MMA 의 layout 을 직접 깎아야 하는 자리 — CuTe 의 영역에 가까움
  • 이미 잘 도는 Triton 커널이 있고 검증된 자리
  • 프로파일러가 “이 코드 한 줄을 직접 바꿔야 한다” 고 짚어주는 자리

강의에서 팀이 명시적으로 강조한 입장 — “Helion 은 Triton 을 안 짜기 위해서가 아니라, Triton 을 더 잘 짤 수 있는 자리를 분명히 하기 위해서다”. 확인 필요 — 실제 발화는 자막이 없어 정확하지 않지만, 팀의 외부 발표에서 일관되게 등장하는 입장.

“같은 알고리즘을 두 번 짜야 하는 환경 — 한 번은 reference 로 PyTorch, 한 번은 빠르게 Triton — 의 비용을 줄이는 게 Helion 의 첫 가치다.”팀 발표 · 재구성
§ 08채택 사례· where it lands

PyTorch 코어 안과 바깥에서 어디에 자리잡는가

새 DSL 의 미래는 사용자 수가 결정한다. Helion 의 초기 채택 자리는 — 외부 자료에서 확인 가능한 한도 안에서 — 두 곳으로 모인다.

발표 시점 기준의 한계

이 노트는 2025–2026 사이의 외부 자료를 기준으로 한다. Helion 이 정식 release 됐는지, 어디까지 PyTorch 본체에 머지됐는지는 시점에 민감 — 직접 github.com/pytorch-labs/helion 의 README 와 PyTorch 블로그 최신 글을 확인할 것.

실용적 관점 — 새 사용자가 Helion 을 처음 만질 때의 진입점은 같은 함수를 PyTorch eager / torch.compile / Helion 세 가지로 짜고 timing 비교다. 커널 작성 학습 곡선의 처음을 그래프 한 장으로 바로 잡을 수 있는 비교.

§ 09다음 방향· roadmap

Helion 이 풀어야 할 다음 문제들

강의의 Q&A 에서 등장했을 법한 — 그리고 외부 자료에서 추정 가능한 — 향후 방향을 묶어둔다.

  1. backward pass 자동화 — forward 만 짠 Helion 커널에서 backward 를 자동 생성하는 길. PyTorch 의 autograd 와 어떻게 합쳐질지가 design space.
  2. multi-GPU primitives — Triton 자체가 single-GPU 모델인 것처럼, Helion 도 그렇다. L087 NVSHMEM 의 영역과 어떻게 맞물릴지가 다음 라운드.
  3. FP8 / MXFP4 등 새 dtypeL084 Numerics 가 깐 흐름을 Helion 의 표면이 어떻게 받아낼지. 양자화 커널은 Helion 의 자연스러운 다음 표적.
  4. AMD / 다른 backend — Triton 자체가 멀티 백엔드(NVIDIA, AMD, Intel) 로 가는 중이라, Helion 은 그 위에서 자동으로 받을 가능성이 높다.
  5. IDE / 디버거 통합 — 자동 lowering 된 Triton 코드와 원래 Helion 코드를 동시에 보는 도구. 사용자가 “내 코드의 어느 줄이 어떤 PTX 를 만드는지” 추적 가능해야 학습 자료로도 쓰인다.
§ 10기억할 메모· key takeaways

다시 열었을 때 5분 안에 손에 잡혀야 할 것

Helion 의 위치
PyTorch-native 한 ML 커널 DSL. Triton 위의 더 친숙한 layer. Triton 을 대체하지 않는다 — Triton 으로 lowering.
PyTorch-native API
커널 안에서 텐서 슬라이싱 / 브로드캐스팅 / dtype 의미가 살아 있음. tl.load/tl.store boilerplate 사라짐.
hl.tile loop
사용자가 짜는 거의 유일한 새 개념. tile 단위 분할은 컴파일러에게 맡김.
lowering 5단계
Helion DSL → Helion IR → autotune search → Triton 코드 → PTX/SASS. autotune 이 search space 의 핵심.
autotune 자동화
tile size · num_warps · num_stages · loop order 가 사용자 코드 밖에서 결정. shape-aware.
의사결정 사다리
torch → Helion → Triton → CUDA. NCU / 프로파일러가 trigger 를 준다.
Inductor 와의 차이
Inductor 는 graph 자동 컴파일러, Helion 은 사용자 직접 작성 DSL. 같은 lowering 인프라 공유, 다른 사용자 표면.
알고리즘은 사용자가
FlashAttention 의 online softmax 같은 알고리즘 아이디어는 사용자가 짠다. Helion 이 자동화하는 건 launch 결정의 영역.
Slides official repo 에 미공개 — 발표자 SNS / PyTorch 블로그 확인 필요
Repo github.com/pytorch-labs/helion · 확인 필요

손에 새기기 — 실습 시퀀스

  1. 같은 함수 3 가지 구현 비교 — softmax 또는 RMSNorm 을 ① PyTorch eager ② torch.compile ③ Helion 으로 짜고, 각 GPU 시간을 측정. torch.cuda.Event + warmup 5회 + sync 의 L001 패턴 그대로.
  2. autotune 효과 보기 — 같은 Helion 커널에 대해 작은 입력 (1024×1024) 과 큰 입력 (8192×8192) 의 캐시된 Triton 코드가 어떻게 다른지 dump 해 비교.
  3. FlashAttention forward 짜기 — § 05 의 형태를 그대로 따라 Helion 에서 attention forward 를 짠다. PyTorch reference 와 numerical 비교.
  4. Helion → Triton dump — 컴파일러가 만든 Triton 코드를 직접 펼쳐 보고, 어떤 변형이 선택됐는지 추적. HELION_LOGS 같은 환경변수 — 확인 필요.
  5. 의사결정 사다리 적용 — 자기 모델 코드에서 한 hot path 를 골라 Helion 으로 교체할 후보를 정한다. NCU 가 무슨 hint 를 주는지가 갈림길.
§ 11다른 강의로 이어지는 길· connections

Helion 의 자리에 등장하는 다른 강의들

§ 12열린 질문· open questions

다음에 다시 들었을 때 직접 검증해야 할 것들

검증 메모

이 노트의 모든 코드 예시는 외부 자료와 도메인 지식 기반으로 개념적으로 재구성한 형태다. 정확한 API 이름(hl.tile, @helion.kernel) 은 repo 가 공개되면 바로 정정 필요. 강의에서 발표자가 라이브로 짠 코드와 차이가 있을 수 있다.

← Lecture 081 이전 강의로 Lecture 083 → Formalized Kernel Derivation — 커널 derivation 의 형식화