Chuyển đến nội dung chính
Hướng dẫn AI

Chạy game NES bên trong mô hình Qwen3.5 đã biên dịch bằng nesformer

Hướng dẫn này giải thích cách nesformer biên dịch CPU 6502 của NES, bộ nhớ và ROM hộp game thành một checkpoint Qwen3.5 tiêu chuẩn. Bạn sẽ cài đặt CLI, chạy các game tương thích, tự động hóa thao tác tay cầm, xuất ảnh động, so sánh quá trình thực thi với CPU tham chiếu và khám phá các engine thay thế.

Chạy game NES trong mô hình Qwen3.5 đã biên dịch bằng nesformer

nesformer là gì?

nesformer là một runtime NES thử nghiệm, trong đó CPU 6502 của máy chơi game, 2 KB RAM làm việc và ROM chương trình của băng game hoạt động bên trong các trọng số và trạng thái của một checkpoint Qwen3_5ForCausalLM tiêu chuẩn. Các trọng số không được huấn luyện. Thay vào đó, một trình biên dịch đã tính toán chúng để triển khai mạch CPU.

Trong khi chơi game, mô hình dự đoán nhật ký thực thi CPU từng token một. Một chương trình máy chủ Python cung cấp các thành phần còn lại của máy chơi game: kết xuất đồ họa, đọc dữ liệu tay cầm, xử lý thời gian, trả lời các lần đọc I/O và đưa ngắt NMI khi bắt đầu khoảng trống dọc vào.

Dự án được xây dựng dựa trên Qwenputer và tái sử dụng trình biên dịch cùng kỹ thuật bộ nhớ trung tâm của dự án này. Mỗi đầu Gated DeltaNet duy trì một ma trận trạng thái. Các khóa và truy vấn one-hot cho phép các hàng trong ma trận hoạt động như các ô nhớ, lưu giữ thanh ghi, RAM và dữ liệu băng game.

Tính năng chính

  • Biên dịch thay vì huấn luyện: mọi trọng số khác 0 đều được tạo từ đặc tả mạch.
  • Định dạng checkpoint tiêu chuẩn: checkpoint là một thư mục Hugging Face thông thường và có thể được tải bằng Qwen3_5ForCausalLM.from_pretrained mà không cần mã mô hình tùy chỉnh.
  • Bộ lệnh 6502 chính thức hoàn chỉnh: mạch triển khai toàn bộ 151 opcode chính thức, các chế độ định địa chỉ, cờ, thao tác ngăn xếp, BRK và việc vào NMI.
  • Hỗ trợ NROM có thể tái sử dụng: cùng một bộ trọng số có thể chạy các ROM iNES mapper 0 khác nhau vì băng game được chọn được ghi vào trạng thái mô hình khi khởi động.
  • các lần nhấn nút có thể được lên lịch theo từng khung hình từ dòng lệnh.
  • Xuất hình ảnh: quá trình chạy có thể được hiển thị trong terminal tương thích và lưu thành các khung hình GIF hoặc PNG.
  • Xác minh thực thi: lệnh check so sánh đầu ra của mô hình với CPU tham chiếu đi kèm và dừng ở khác biệt đầu tiên.
  • Nhiều engine thực thi: nesformer cung cấp engine numba nhanh, engine NumPy thuần và engine Transformers tiêu chuẩn.

Tìm hiểu những gì chạy bên trong mô hình

Checkpoint chứa lõi 6502, các thanh ghi và cờ CPU, 2 KB RAM làm việc và một bảng ROM chương trình cố định 32 KB. Nó cũng xử lý việc lấy lệnh, đọc dữ liệu, thao tác ngăn xếp và đọc OAM DMA.

Máy chủ vẫn chịu trách nhiệm về bộ kết xuất PPU, bảng màu, tay cầm, thời điểm NMI vblank, đếm chu kỳ và xử lý các thanh ghi APU. Âm thanh chưa được triển khai. Máy chủ đưa các giá trị cho các lần đọc I/O và sự kiện NMI vào luồng token, nhưng không trực tiếp kiểm tra các thanh ghi hoặc RAM của mô hình bên ngoài trace được phát ra.

nesformer mô phỏng CPU thông qua suy luận mô hình, nhưng không phải là một NES hoàn chỉnh được triển khai hoàn toàn bên trong các trọng số.

Yêu cầu và thiết lập thư mục

Bạn cần Python 3.11 trở lên, kho lưu trữ mã nguồn nesformer và kho lưu trữ trọng số riêng. Giải nén cả hai kho lưu trữ vào cùng một thư mục cấp cao nhất. Thư mục weights phải nằm cạnh gói Python, không nằm bên trong gói.

nesformer/
├── nesformer/
├── chipformer/
├── roms/
├── examples/
├── tests/
├── pyproject.toml
└── weights/
    ├── config.json
    ├── generation_config.json
    ├── model.safetensors
    ├── nesformer.json
    └── SHA256SUMS

Chạy mọi lệnh từ thư mục cấp cao nhất như trên. Theo mặc định, CLI tìm weights/ bên cạnh gói nesformer/.

Xác minh trọng số đã tải xuống

Sử dụng tệp checksum đi kèm để xác nhận trọng số đã được giải nén chính xác:

shasum -a 256 -c weights/SHA256SUMS

Nếu lưu checkpoint ở nơi khác, hãy truyền vị trí của nó bằng --weights /path/to/weights khi sử dụng run, check hoặc trace. Lệnh info nhận trực tiếp đường dẫn checkpoint.

Cài đặt nesformer

Tạo và kích hoạt môi trường ảo, sau đó cài đặt các gói số học và xử lý hình ảnh cần thiết:

python3 -m venv .venv
source .venv/bin/activate
pip install numpy scipy numba pillow

Trên Windows, kích hoạt môi trường bằng:

.venv\Scripts\activate

Engine fast mặc định sử dụng numba. Trong lần chạy đầu tiên, engine mất khoảng 20 giây để biên dịch. Các lần chạy sau sẽ tái sử dụng phần biên dịch này.

Chạy game đầu tiên

Kho mã nguồn bao gồm các ROM thử nghiệm được cấp phép tự do. Lệnh sau chạy Thwaite trong 600 khung hình, hiển thị các khung hình trong terminal và cung cấp một chuỗi nhấn nút Start và A theo kịch bản:

python -m nesformer run roms/thwaite.nes --frames 600 --show \
  --buttons "start@90-95+200-205,a@230-233+250-253+270-273+290-293+310-313+330-333+350-353+370-373+390-393+410-413+430-433+450-453+470-473+490-493+510-513+530-533+550-553+570-573+590-593"

Tùy chọn --show vẽ từng khung hình được tạo trong terminal hỗ trợ màu 24 bit, chẳng hạn iTerm2 hoặc Windows Terminal. Khi quá trình thực thi kết thúc, CLI lưu một GIF động có tên theo ROM, chẳng hạn thwaite.gif.

Hiệu năng chậm hơn nhiều so với NES vật lý. Sau lần biên dịch đầu tiên, mỗi khung hình thường mất khoảng một đến sáu giây. Một lần chạy 600 khung hình tương đương 10 giây thời gian NES và có thể mất khoảng 25 phút.

Chạy ROM tương thích của bạn

Đặt ROM bạn có quyền sử dụng hợp pháp vào thư mục roms/ hoặc cung cấp một đường dẫn khác. ROM phải sử dụng bo mạch NROM, được xác định là iNES mapper 0. Các ví dụ tương thích gồm Super Mario Bros., Donkey Kong và Excitebike, mặc dù các ROM thương mại này không được bao gồm.

Ví dụ này khởi động Super Mario Bros., giữ nút Right và lên lịch cho nhiều lần nhảy:

python -m nesformer run roms/smb.nes --frames 600 --show \
  --buttons "start@60-65,right@200-600,a@250-265+300-315+360-375+420-435+480-495+540-555"

ROM được nạp vào trạng thái DeltaNet của mô hình khi khởi động. Bạn không cần xây dựng lại checkpoint cho từng trò chơi tương thích.

Lập trình đầu vào bộ điều khiển

Tùy chọn --buttons chấp nhận các mục được phân tách bằng dấu phẩy. Mỗi mục gồm một hoặc nhiều tên nút, ký hiệu @ và một hoặc nhiều khoảng khung hình.

start@60-65
right@200-600
a@250-265+300-315
right+b@200-600
  • start@60-65 nhấn Start từ khung hình 60 đến khung hình 65.
  • right@200-600 giữ Right trong khoảng thời gian được chỉ định.
  • a@250-265+300-315 lên lịch hai lần nhấn nút A.
  • right+b@200-600 giữ đồng thời Right và B.

Các tên khả dụng là a, b, select, start, up, down, left và right. Khung hình bắt đầu từ lúc bật nguồn và tăng với tốc độ 60 khung hình mỗi giây. Do đó, khung hình 600 tương ứng với 10 giây theo thời gian của NES.

Thông thường, bắt đầu nhấn sớm hơn một chút là an toàn vì trò chơi sẽ bỏ qua thao tác điều khiển trên những màn hình không cho phép di chuyển. Thời lượng nhấn có thể quan trọng; chẳng hạn, nhấn A lâu hơn sẽ tạo ra cú nhảy cao hơn trong Super Mario Bros.

Kiểm soát đầu ra theo khung hình

Theo mặc định, run thực thi 120 khung hình và ghi một GIF có tên theo ROM. Sử dụng các tùy chọn đầu ra để tùy chỉnh kết quả:

python -m nesformer run roms/thwaite.nes \
  --frames 300 \
  --every 2 \
  --scale 3 \
  --gif output/thwaite.gif
  • --frames N dừng sau N khung hình.
  • --gif PATH chọn nơi lưu GIF động.
  • --png DIR lưu các khung hình được giữ lại thành từng tệp PNG.
  • --every N giữ lại mỗi khung hình thứ N.
  • --scale N phóng to các khung hình đã lưu theo hệ số nguyên.
  • --show hiển thị các khung hình được tạo trong terminal.

Tự sử dụng --png sẽ tắt đầu ra GIF. Thêm tùy chọn --gif cụ thể khi bạn muốn có cả các khung hình PNG và ảnh động.

python -m nesformer run roms/thwaite.nes \
  --frames 120 \
  --png frames \
  --gif thwaite.gif

Kiểm tra và xác minh quá trình thực thi

So sánh với CPU tham chiếu

Lệnh check chạy checkpoint và CPU tham chiếu 6502 thông thường của dự án song song. Lệnh dừng ở khác biệt token đầu tiên:

python -m nesformer check roms/thwaite.nes --tokens 50000

Độ dài so sánh mặc định là 50,000 token. Bạn có thể truyền cùng các tùy chọn --buttons, --weights, --engine và --no-skip được các lệnh thực thi khác chấp nhận.

In chuỗi token của mô hình

Sử dụng trace để kiểm tra các bản ghi CPU do mô hình phát ra:

python -m nesformer trace roms/thwaite.nes --tokens 100

Độ dài trace mặc định là 40 token. Hầu hết lệnh CPU cần một token, trong khi các lệnh liên quan đến I/O, đọc con trỏ, thao tác ngăn xếp hoặc DMA có thể tạo ra các bản ghi nhiều token.

Lưu ID token trong quá trình chạy

Lệnh run có thể ghi các ID token được tạo vào một tệp để phân tích sau:

python -m nesformer run roms/thwaite.nes \
  --frames 60 \
  --trace trace.txt

Bạn cũng có thể sử dụng --max-tokens N để dừng thực thi sau một số lượng token được tạo cố định thay vì chỉ dựa vào giới hạn khung hình.

Chọn engine thực thi

nesformer cung cấp ba engine với hiệu năng và yêu cầu phụ thuộc khác nhau:

  • fast: triển khai numba mặc định. README báo cáo khoảng 1,650 token mỗi giây trên một lõi CPU của máy phát triển.
  • numpy: triển khai NumPy đơn giản hơn, đạt khoảng 210 token mỗi giây theo báo cáo.
  • hf: Hugging Face Transformers nguyên bản, đạt khoảng 10 token mỗi giây theo báo cáo.

Chọn engine bằng --engine:

python -m nesformer run roms/thwaite.nes --frames 3 --engine numpy

Sử dụng Transformers nguyên bản

Cài đặt các phụ thuộc bổ sung trước khi chọn engine Hugging Face:

pip install "torch>=2.6" "transformers>=5.22"
python -m nesformer run roms/thwaite.nes --frames 3 --engine hf

Checkpoint không cần triển khai mô hình tùy chỉnh. Bên trong, nesformer nạp checkpoint, giải mã một token đệm, ghi trạng thái máy ban đầu vào các trạng thái DeltaNet của bộ nhớ đệm, rồi lần lượt đưa các token được tạo trở lại vào mô hình.

Mẹo nâng cao

Đặt trọng số bên ngoài kho lưu trữ

Sử dụng --weights khi checkpoint được lưu ở vị trí khác:

python -m nesformer run roms/thwaite.nes \
  --weights /path/to/weights \
  --frames 120

Kiểm tra siêu dữ liệu checkpoint

Sử dụng lệnh thông tin để mô tả checkpoint:

python -m nesformer info

Nếu trọng số không nằm trong thư mục mặc định, hãy cung cấp đường dẫn của chúng cho info.

Xây dựng lại checkpoint

Kho lưu trữ bao gồm trình biên dịch cần thiết để tạo lại checkpoint mạch. Một lần xây dựng thông thường ghi vào weights/ và mất khoảng 10 giây theo README:

python -m nesformer build

Chọn thư mục đầu ra khác bằng:

python -m nesformer build --out compiled-weights

Tìm hiểu cơ chế bỏ qua vòng lặp nhàn rỗi

Các trò chơi NES thường chờ vblank trong các vòng lặp chặt. Khi máy chủ phát hiện một vòng lặp lặp lại chính xác, không ghi vào RAM hoặc I/O, nó sẽ tiến đồng hồ đến gần sự kiện PPU tiếp theo rồi chạy các lần lặp còn lại. Tối ưu hóa này làm giảm đáng kể số token cần tạo mà vẫn giữ nguyên các khung hình hiển thị và thời điểm I/O.

Truyền --no-skip để thực thi mọi lần lặp của vòng lặp chờ. Cách này chậm hơn, nhưng hữu ích khi nghiên cứu toàn bộ chuỗi token:

python -m nesformer trace roms/thwaite.nes --tokens 100 --no-skip

Chạy bộ kiểm thử

Cài đặt các phụ thuộc kiểm thử rồi chạy pytest:

pip install pytest py65
python -m pytest -q tests

Các bài kiểm thử mất vài phút. Chúng so sánh CPU tham chiếu với nhật ký nestest, kiểm tra mạch đã biên dịch so với bản tham chiếu, xác minh các trọng số chạy tự do và kiểm thử tối ưu hóa vòng lặp chờ.

Các giới hạn quan trọng

  • Chỉ NROM: trò chơi phải sử dụng mapper iNES 0. Các mapper chuyển đổi ngân hàng như MMC1 và MMC3 không được hỗ trợ.
  • Chỉ opcode chính thức: khi gặp opcode 6502 không chính thức, hệ thống phát ra HALT.
  • Thực thi từ ROM: mã phải được thực thi từ ROM của hộp băng; việc nhảy vào RAM sẽ phát ra HALT.
  • Không hỗ trợ IRQ: BRK và NMI hoạt động, nhưng IRQ khung hình của APU và IRQ DMC thì không.
  • Hành vi I/O hạn chế: các lệnh đọc-sửa-ghi trên thanh ghi I/O không tạo ra thao tác ghi I/O, và các địa chỉ từ $4020 đến $7FFF được đọc là số không.
  • Chi tiết đồ họa xấp xỉ: việc kết xuất diễn ra từng scanline, các hiệu ứng giữa scanline không được tái hiện, còn va chạm sprite-0 và tràn sprite chỉ mang tính xấp xỉ.
  • Không có âm thanh: các thao tác ghi vào thanh ghi APU được chấp nhận nhưng không phát sinh âm thanh.
  • Thực thi chậm: ngay cả khi bỏ qua vòng lặp chờ, dự án vẫn chạy chậm hơn khoảng 150 đến 290 lần so với máy console thật.

Kết luận

nesformer cho thấy một checkpoint transformer có thể hoạt động như một máy tính được biên dịch chính xác, thay vì một mô hình ngôn ngữ được huấn luyện. Khi mã nguồn và các trọng số được sắp xếp đúng cách, bạn có thể chạy các trò chơi NROM tương thích, tự động hóa đầu vào bộ điều khiển, xuất khung hình, kiểm tra token CPU và so sánh quá trình thực thi với CPU 6502 tham chiếu. Những giới hạn về mapper, đồ họa, âm thanh và tốc độ khiến đây là một hệ thống thử nghiệm, nhưng checkpoint Qwen3.5 tiêu chuẩn cùng các công cụ xác minh cung cấp một cách thực tế để nghiên cứu phép tính được mã hóa trực tiếp trong trọng số mô hình và trạng thái DeltaNet.