English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

khách
1 / ?
trở lại bài học

Các Gradient cục bộ Nhân lên

Forward & Backward Kernels


Forward Pass

Forward pass của ANDREA-120M đưa input qua một chuỗi các phép toán:


x = embed(token_ids)         # nhúng token
for layer in 12_layers:
x = x + attn(LN(x))      # tầng con attention
x = x + mlp(LN(x))       # tầng con MLP
logits = LN(x) @ embed.T     # chiếu đầu ra chung
loss   = cross_entropy(logits, targets)

Mỗi hoạt động đọc các tensor đầu vào & tạo ra các tensor đầu ra. Quá trình lan truyền thuận kết thúc bằng một số vô hướng duy nhất: hàm mất mát cross-entropy cho batch này.


Quá trình Lan truyền Ngược

Việc huấn luyện cập nhật các trọng số theo hướng làm giảm mất mát. Để lấy hướng cập nhật, engine cần:


dL/dW cho mọi W có thể học được trong mô hình

Quy tắc chuỗi cho điều này. Với một chuỗi loss = f(g(h(x))):


dL/dx = (dL/df) * (df/dg) * (dg/dh) * (dh/dx)

Mỗi yếu tố là một gradient cục bộ: cách đầu ra của một phép toán thay đổi khi đầu vào của nó thay đổi một lượng nhỏ. Nhân các gradient cục bộ ngược qua đồ thị sẽ lan truyền tín hiệu mất mát đến mọi trọng số.


Phân biệt ngược (Reverse-Mode Differentiation)

Backprop tính gradient theo thứ tự ngược: bắt đầu từ dL/dlogits = 1, sau đó đi ngược qua cross-entropy, rồi projection đầu ra, rồi layer norm, rồi mười hai khối transformer, rồi embeddings. Tại mỗi bước, nhân gradient đến với Jacobian cục bộ.


Chế độ ngược hiệu quả khi đầu ra là một số vô hướng duy nhất (mất mát) & có nhiều đầu vào (các trọng số). Một lần truyền ngược tạo gradient cho mọi trọng số trong mô hình. Chế độ tiến (forward-mode) cần một lần truyền cho mỗi trọng số; với ANDREA-120M có ~120M trọng số, forward-mode là không khả thi.

Tại sao Reverse-Mode

ANDREA-120M có ~120M trọng số & tạo ra một giá trị mất mát vô hướng duy nhất cho mỗi bước huấn luyện. So sánh phân biệt tự động chế độ ngược với chế độ thuận. Nêu (1) chế độ nào tạo ra tất cả gradient trọng số trong một lần lan truyền ngược; (2) cần bao nhiêu lần lan truyền chế độ thuận để tính toán tất cả 120M gradient trọng số; (3) chế độ nào ANDREA sử dụng & tại sao.

Mỗi Phép Toán Thuận Được Ghép Với Phép Toán Ngược

Quy Tắc Ghép Đôi

microgpt_cuda.cu cung cấp hai kernel CUDA cho mọi phép toán: một kernel tính toán đầu ra thuận, một kernel tính toán gradient đầu vào dựa trên gradient đầu ra. Sự ghép đôi là một-một:


Kernel tiếnKernel lùiThao tác
k_embed_fwdk_embed_bwdTra cứu embedding token
k_layernorm_fwdk_layernorm_bwdChuẩn hóa lớp
k_attn_qkv_fwdk_attn_qkv_bwdChiếu Q, K, V
k_attn_fwdk_attn_bwdAttention scaled dot-product
k_attn_out_fwdk_attn_out_bwdChiếu đầu ra W_O
k_mlp_fwdk_mlp_bwdMLP (với GELU)
k_residual_addk_residual_add_bwdKết nối dư
k_loss_fwdk_loss_bwdHàm mất mát Cross-entropy

Tám cặp phép toán bao phủ toàn bộ transformer. Cộng thêm một vài kernel tiện ích: k_grad_norm_partial, k_grad_norm_final, k_grad_scale cho việc cắt gradient (xem hoạt động 75).


Nhiệm vụ của một Backward Kernel

Cho gradient chảy vào từ các lớp sau (grad_output), một backward kernel tính toán:


1. grad_input: gradient liên quan đến tensor đầu vào của phép toán. Nó được truyền tiếp ngược trở lại.

2. grad_weight: gradient liên quan đến các tham số có thể học được trong phép toán. Nó được đưa vào trạng thái của optimizer.


Cả hai đều được tính toán trong một lần khởi chạy kernel. Các thread CUDA hợp tác song song trên các tile của tensor gradient.


Các Tensor Đã Lưu

Phép tính ngược thường cần các giá trị từ forward pass. Ví dụ, k_layernorm_bwd cần mean & variance được tính trong forward; k_mlp_bwd cần pre-activation GELU. Engine huấn luyện lưu trữ chúng trong các buffer dành riêng trong forward, sau đó đọc chúng trong backward.


Chi phí bộ nhớ: gần giống hình dạng của đầu ra forward cho mỗi tensor được lưu. Với ANDREA-120M, batch=8, seq=1024, d_model=768, một tensor được lưu là 8 × 1024 × 768 × 4 bytes = 25 MB. Qua 12 lớp & nhiều tensor được lưu mỗi lớp, activations chiếm ưu thế VRAM trong quá trình huấn luyện (~5-10 GB trên card 24 GB).

Theo dõi Một Bước Backward

ANDREA-120M hoàn thành một forward pass qua một transformer block. Theo dõi những gì xảy ra trong backward pass qua cùng block đó (cấu trúc pre-norm: `x = x + Attention(LN(x))` rồi `x = x + MLP(LN(x))`). Nêu tên các backward kernels theo thứ tự chúng kích hoạt, & nêu kernel forward mà mỗi cái ghép đôi. Bao quát ít nhất 4 kernels.

Nơi Gradient Được Lưu Trữ Trong Bộ Nhớ

Một Tensor Gradient Cho Mỗi Tensor Trọng Số

Mỗi tensor trọng số có thể học được trong ANDREA-120M đều có một tensor gradient tương ứng với hình dạng giống hệt. Đối với mỗi block:


W_Q       [768, 768]     ↔   grad_W_Q       [768, 768]
W_K       [768, 768]     ↔   grad_W_K       [768, 768]
W_V       [768, 768]     ↔   grad_W_V       [768, 768]
W_O       [768, 768]     ↔   grad_W_O       [768, 768]
W_1       [768, 3072]    ↔   grad_W_1       [768, 3072]
W_2       [3072, 768]    ↔   grad_W_2       [3072, 768]
LN1.gamma [768]          ↔   grad_LN1.gamma [768]
LN1.beta  [768]          ↔   grad_LN1.beta  [768]
LN2.gamma [768]          ↔   grad_LN2.gamma [768]
LN2.beta  [768]          ↔   grad_LN2.beta  [768]

Cộng với token embeddings, position embeddings, & một layer norm cuối cùng. Tổng bộ nhớ buffer gradient khớp với bộ nhớ weight: ~120M floats, ~480 MB tại FP32, ~240 MB tại FP16.


Tích lũy Qua Các Microbatch

batch_size = 8 của ANDREA vừa với VRAM tại FP16. Các batch hiệu quả lớn hơn yêu cầu gradient accumulation: chạy nhiều forward+backward passes trên các batch nhỏ, cộng dồn gradients vào cùng buffer, sau đó thực hiện một bước optimizer.


for microbatch in range(n_microbatches):
forward(microbatch)
backward()           # THÊM vào bộ đệm grad, không ghi đè
scale_grads(1.0 / n_microbatches)  # tính trung bình qua các microbatches
optimizer_step()
zero_grads()             # đặt lại cho bước huấn luyện tiếp theo

Các kernel backward sử dụng ngữ nghĩa +=, không phải =. Mỗi lần gọi thêm đóng góp gradient vào bộ đệm hiện có; bộ đệm giữ tổng chạy cho đến khi zero_grads() xóa nó.


Trạng thái của Optimizer

AdamW (hoạt động 73) giữ hai buffer nữa cho mỗi trọng số: moment thứ nhất m & moment thứ hai v. Tổng bộ nhớ thời gian huấn luyện:


trọng số:    1× số lượng trọng số
gradient:  1× số lượng trọng số
Adam m:     1× số lượng trọng số
Adam v:     1× số lượng trọng số
các acts đã lưu: ~2-4× tùy thuộc vào số lớp & batch
──────────────────────────────────────────
tổng cộng:  ~6-8× số lượng trọng số

ANDREA-120M ở FP16: ~240 MB × 4 buffers (trọng số, grad, m, v) + ~5-10 GB activations = ~10-12 GB tổng cộng. Thoải mái dưới giới hạn 24 GB của RTX 4090. ANDREA-12M huấn luyện trong 1.4 GB; việc mở rộng quy mô tham số 10× mang lại ~10× bộ nhớ.

Kích thước Buffer Gradient

ANDREA-120M có khoảng 120.000.000 trọng số & sử dụng tích lũy gradient qua 4 microbatch mỗi bước huấn luyện. Tính toán: (a) kích thước bộ đệm gradient tính bằng MB ở FP16; (b) tổng bộ nhớ cho weights + gradients + Adam m + Adam v ở FP16; (c) số lượng cuộc gọi `forward()` + `backward()` riêng biệt được thực hiện mỗi bước huấn luyện. Hãy trình bày phép tính của bạn.

Kiểm soát hoàn toàn Bộ nhớ & Độ chính xác

Chi phí của các Framework chung

PyTorch & JAX làm autograd tiện lợi: viết code Python, nhận gradient tự động. Chi phí: một lớp dispatch chung giữa code của bạn & CUDA. Mọi thao tác đều qua overhead trình thông dịch Python, sổ sách framework, & chọn kernel động. Khi huấn luyện một mô hình ngôn ngữ nhỏ trên một GPU, overhead đó quan trọng.


Chi phí cụ thể mà ANDREA tránh được:


1. Độ trễ trình thông dịch Python. Mỗi phép toán PyTorch đều vượt qua ranh giới Python/C++. Với ~100 lần khởi chạy kernel mỗi bước huấn luyện, ~9 bước/phút, đó là ~900 lần vượt ranh giới mỗi phút. Phân phối ở mức C loại bỏ điều này.


2. Tính không dự đoán được của bộ cấp phát framework. Bộ cấp phát bộ nhớ đệm của PyTorch mang lại thông lượng tốt trung bình nhưng bộ nhớ đỉnh không dự đoán được. Công cụ huấn luyện của ANDREA cấp phát trước mọi bộ đệm lúc khởi động; không cấp phát lại trong quá trình huấn luyện, không phân mảnh, không OOM bất ngờ ở bước 100K.


3. Lựa chọn kernel chung chung. PyTorch chọn kernel lúc chạy qua các heuristic. ANDREA chọn kernel lúc biên dịch, được điều chỉnh cho kích thước ô tensor core RTX 4090.


4. Đường ống xử lý độ chính xác hỗn hợp. Đường dẫn cuBLAS FP16 của ANDREA-120M & các thí nghiệm tensor core FP8 E4M3 của ANDREA yêu cầu kiểm soát chính xác tensor nào sống ở độ chính xác nào. Các framework chung tiếp xúc kiểm soát này qua các API phân tầng; CUDA tùy chỉnh viết trực tiếp.


Sự đánh đổi

Chi phí CUDA tùy chỉnh: nhiều code hơn để viết, nhiều bug hơn để tìm, không có hệ sinh thái cộng đồng. microgpt_cuda.cu của ANDREA là ~6000 dòng CUDA viết tay mất hàng tháng để debug. Mỗi hoạt động mới yêu cầu viết kernel forward, kernel backward, & tests.


Những gì ANDREA đạt được:


- Tái lập hoàn toàn. Đường ống huấn luyện là một tệp nhị phân C cộng với một proxy Python. Không có sự lệch phiên bản qua các bản phát hành PyTorch, không có sự không khớp phiên bản CUDA với các wheel của framework.

- Tiếp tục chính xác từng bit. SIGTERM kích hoạt việc ghi checkpoint nắm bắt mọi tensor chính xác như GPU nhìn thấy. Tiếp tục nhặt lại cùng quỹ đạo loss mà lần chạy đang theo.

- Bộ nhớ có thể dự đoán. ANDREA-120M được huấn luyện 200K bước mà không có OOM. Bộ nhớ được tính toán ngay từ lúc khởi động engine.

- Truy cập phần cứng trực tiếp. Kích thước tile tensor core, cài đặt FP8 E4M3, sao chép bộ nhớ bất đồng bộ: tất cả đều có thể truy cập trực tiếp trong CUDA, mờ mịt trong các framework chung chung.


Tái lập Như Sứ Mệnh

Phần 9 của whitepaper ANDREA liệt kê toàn bộ stack tái lập:


**Động cơ huấn luyện:** microgpt/microgpt_cuda.cu
**Proxy huấn luyện:** microgpt/training_proxy.py
**Cấu hình thí nghiệm:** experiments/ANDREA-*-TRAIN.json
**Đường ống dữ liệu:** scripts/pull-hermes3.py, scripts/prep-megachat.py
**Bảng điều khiển:** scripts/live-loss-dashboard.html
**Thông số Bandit:** docs/FIREHOSE-BANDIT.md
**Tài liệu mô hình:** docs/ANDREA.md

Yêu cầu phần cứng: một GPU NVIDIA với ≥8 GB VRAM (RTX 3060 hoặc tốt hơn). Bất kỳ ai cũng có thể tái tạo ANDREA-12M từ các artifacts này. Đường dẫn CUDA tùy chỉnh là một phần lý do: không có phiên bản framework bị đóng băng, không có bất ngờ về dependency sau năm năm nữa.


Tín hiệu & Checkpoints

Vòng lặp huấn luyện CUDA phản hồi với hai tín hiệu POSIX:


- SIGTERM: ghi checkpoint ngay lập tức, sau đó thoát. Sử dụng khi dừng huấn luyện một cách sạch sẽ.

- SIGUSR1: ghi checkpoint ngay lập tức, tiếp tục huấn luyện. Được sử dụng trong pivot polish ở v3 để capture trạng thái mà không gián đoạn run.


Định dạng checkpoint: [int32 step][int32 n_params][n_params × float32 weights][n_params × float32 m][n_params × float32 v]. Bộ đếm step, số lượng weight, sau đó là weights theo sau bởi Adam moments. Tiếp tục bit-exactly. Proxy lưu trữ .samples.json & .state.json riêng biệt trên polish; .loss.json không bao giờ được lưu trữ (nó tích lũy toàn bộ lịch sử huấn luyện).

Tại Sao Không Dùng PyTorch

ANDREA có thể đã sử dụng autograd của PyTorch thay vì viết `microgpt_cuda.cu` bằng tay. Hãy đưa ra hai lý do kỹ thuật khác biệt tại sao ANDREA chọn CUDA tùy chỉnh. Một lý do nên đề cập đến kiểm soát bộ nhớ hoặc độ chính xác; lý do còn lại nên đề cập đến khả năng tái tạo, phụ thuộc framework, hoặc bảo trì dài hạn.