SELECT 1
Entry 0222026.11.01 일
One launch a day. Picked, run, explained.

2026.11.01 일

nesformer: 언어 모델 안에서 NES 게임 실행하기

오늘의 픽: nesformer

nesformer 는 NES 게임을 언어 모델로 실행하는 프로덕트다. 제작자는 NES 의 CPU 회로를 학습 없이 Qwen3.5 모델의 가중치로 컴파일했다.

오늘의 픽으로 선정한 이유는 모델이 오차 없이 계산하는지 검증할 수 있게 하기 때문이다.

exit 0실행함작동한다. 모델이 생성한 토큰 약 70,000개가 기준 CPU 의 실행 기록과 같았다.
nesformer 로 실행한 Thwaite 의 첫 화면. 버전과 라이선스 안내, Press Start Button 이 보인다
Thwaite 의 첫 화면. 모델이 게임 코드를 실행했다. 화면은 호스트 프로그램이 그렸다. run 명령이 저장한 GIF 에서 프레임을 추출해 2배로 확대했다.
출처
Show HN
만든 방식
Python, NumPy, numba, Qwen3.5

무엇이 문제인가

언어 모델이 프로그램을 오차 없이 실행하려면, 모델이 그 프로그램과 똑같이 계산하도록 가중치를 정확히 정해야 한다.

보통 언어 모델의 가중치는 데이터로 학습해 만든다. 학습한 모델은 잘못된 결과를 낼 수 있다. 가중치를 읽어서는 모델이 어떤 계산을 하는지도 알 수 없다.

어떻게 해결했나

nesformer 는 2026년 10월 31일 Hacker News 에 Show HN 글로 올라왔다. nesformer 는 가중치를 학습하지 않고 컴파일러로 계산한다. NES닌텐도의 가정용 게임기다. 일본에서는 1983년 패미컴으로 나왔고, NES 는 1985년부터 북미에서 쓴 이름이다. CPU 는 6502 를 바탕으로 만든 칩이다. 의 CPU 와 내장 RAM 2 KB, 게임 카트리지의 프로그램 ROM 이 Qwen3.5 구조의 모델 안에 들어 있다.

게임을 실행하면 모델은 CPU 의 실행 기록을 토큰 하나씩 예측한다. 모델은 CPU 명령어 하나를 실행할 때 대개 토큰 하나를 생성한다. 게임 코드에서는 명령어 하나에 토큰이 평균 1.1~1.3개 나온다. 화면 그리기와 컨트롤러 입력, 인터럽트CPU 가 하던 일을 잠시 멈추고 정해진 코드를 먼저 실행하게 하는 신호다. NES 는 화면을 한 장 그릴 때마다 CPU 에 이 신호를 보낸다.는 별도의 호스트 프로그램이 처리한다. 호스트는 CPU 의 레지스터와 메모리에 직접 접근하지 않고, 모델이 생성한 실행 기록만 읽는다. check 명령은 같은 게임을 모델과 기준 CPU 에서 함께 실행하고, 토큰이 처음 달라지는 곳에서 멈춘다. 기준 CPU 는 NES 의 6502 CPU 를 Python 으로 구현한 프로그램이다.

무엇이 다른가

가중치를 만드는 방법이 다르다. nesformer 는 컴파일러로 CPU 의 회로를 가중치로 변환한다. 컴파일한 가중치는 Hugging Face 의 표준 Qwen3.5 모델 파일이다. README 에 따르면 별도 코드 없이 transformers 라이브러리로 불러올 수 있다. 파라미터 466,647,616개 가운데 0 이 아닌 값은 9,340,331개다. 그래서 933 MB 인 가중치 파일을 zip 으로 압축하면 3.3 MB 가 된다. Qwen3.5 의 Gated DeltaNet언어 모델 층의 한 종류다. 앞의 토큰을 모두 다시 참조하는 대신 고정된 크기의 상태 행렬에 앞의 내용을 저장하고, 이 행렬을 토큰마다 갱신한다. Qwen3.5 모델에 들어 있다. 층은 토큰마다 상태 행렬을 갱신한다. 이 행렬의 행 하나가 메모리 한 칸이 된다. 카트리지 ROM 과 RAM, 레지스터가 모두 이 행렬에 저장된다. 오픈소스 프로젝트 Qwenputer 가 이 컴파일러 chipformer 를 만들어 CHIP-8 과 RISC-V CPU 를 Qwen3.5-4B 의 가중치로 컴파일했다. nesformer 는 같은 컴파일러로 NES 의 CPU 를 층 8개짜리 Qwen3.5 모델에 컴파일했다. 트레이드오프는 실행할 수 있는 게임이 제한된다는 점이다. 프로그램 ROM 을 모델 안의 고정된 32 KB 테이블에서 읽기 때문에, 카트리지에 매퍼NES 카트리지 안에서 CPU 가 읽을 ROM 영역을 바꿔 주는 칩이다. 32 KB 보다 큰 게임은 이 칩으로 ROM 의 여러 부분을 번갈아 읽는다. 칩이 있는 큰 게임은 실행되지 않는다.

다만 실제 NES 보다 느리다. README 에 따르면 실제 NES 와 같은 속도로 실행하려면 초당 약 700,000 토큰이 필요하다. 제작자의 컴퓨터에서는 코어 하나로 초당 약 1,650 토큰을 생성했다. 게임 코드에는 화면 갱신을 기다리는 루프가 있다. README 에 따르면 호스트 프로그램은 이 루프의 반복을 건너뛰어 토큰 수를 2.6~4.2분의 1 로 줄인다. 이렇게 줄여도 실제 NES 보다 150~290배 느리다.

어떻게 만들었나

  • 저장소의 커밋은 2026년 10월 30일의 첫 공개 커밋 하나다. AI 도구와 함께 작성했다는 Co-authored-by 트레일러는 없다.
  • 제작자는 Qwenputer 의 컴파일러 chipformer 를 MIT 라이선스에 따라 저장소에 포함했고, 회로와 가중치를 만드는 코드 일부는 Qwenputer 의 코드를 수정해 작성했다.
  • 제작자는 README 에 검증을 네 단계로 기록했다. 기준 CPU 는 다른 6502 에뮬레이터와 대조하고, CPU 시험용 ROM nestest 의 공식 로그와도 대조했다. 회로와 가중치 파일은 기준 CPU 와 대조했다.

실행해 보니

README 의 명령을 따라 4코어 컴퓨터에서 GPU 없이 실행했다.

  1. 설치. 저장소에 든 nesformer-weights.zip(3.3 MB)을 풀자 가중치 파일이 933 MB 가 됐다. SHA-256 이 저장소의 값과 같았다. pip install numpy scipy numba pillow 는 14초 만에 끝났다.
  2. 대조. NES 게임 Thwaite 로 check roms/thwaite.nes --tokens 20000 을 실행했다. 가중치를 불러오는 시간을 포함해 16초 만에 끝났다. 도구가 출력한 생성 속도는 초당 1,469 토큰이었다. 모델이 생성한 토큰 20,000개와 화면 5프레임이 기준 CPU 의 결과와 같았다. nestest 로도 같은 방식으로 대조했다. 가중치를 불러오는 시간을 포함해 34초가 걸렸다. 토큰 50,001개와 화면 81프레임이 같았다.
  3. 게임. run roms/thwaite.nes --frames 120 을 실행했다. 모델은 102초 동안 토큰 175,511개를 생성했다. 초당 1,719개다. 120프레임은 NES 에서 2.0초이므로 실제 게임기보다 51배 느린 셈이다. 버튼을 누르지 않아 게임 시작 전 화면까지만 진행됐다. 프레임당 토큰은 약 1,460개였다. README 에 따르면 Thwaite 를 600프레임 실행했을 때는 프레임당 약 3,200개였다. 프레임마다 0.4~2.4초가 걸렸다.
  4. 재빌드. build 로 회로에서 가중치 파일을 다시 만드는 데 18초가 걸려, README 에 적힌 약 10초보다 길었다. 새 파일의 SHA-256 은 배포된 가중치 파일의 값과 같았다.
frame 120/120  175,511 tokens  1,719 tok/s  1.6s/frame
175,511 tokens in 102s (1,719 tok/s), 120 frames, 3,573,681 CPU cycles (2.0s of NES time)
Thwaite 의 타이틀 메뉴. 1 Player, 2 Players, Practice 가 보인다
버튼을 누르지 않아도 120프레임 안에 화면이 타이틀 메뉴로 넘어갔다. 같은 GIF 의 마지막 프레임이다.

확인하지 못한 것

  • 게임 진행. README 의 예시 명령에 있는 버튼 입력 순서로 Thwaite 를 600프레임 실행해 게임 화면까지 확인하자. README 에 따르면 600프레임에 약 25분이 필요하다.
  • 표준 transformers 실행. torch 를 설치하고 --engine hf 로 같은 가중치를 실행해 보자.

판정

작동한다. 모델이 생성한 토큰 약 70,000개가 기준 CPU 의 실행 기록과 같았다. 다만 실제 NES 에서 2초 분량을 실행하는 데 102초가 걸렸다. 언어 모델 안에서 프로그램이 오차 없이 실행되는 과정을 직접 확인하고 싶은 경우에 써 볼 만하다.

시작하기

  1. git clone https://github.com/dbreunig/nesformer && cd nesformer
  2. unzip nesformer-weights.zip
  3. pip install numpy scipy numba pillow
  4. python -m nesformer run roms/thwaite.nes --frames 120
필요한 것
Python 3.11 이상. GPU 는 필요 없다 · 디스크 약 1 GB(압축을 푼 가중치 파일이 933 MB 다)
비용
MIT, 무료.

README 에 따르면 매퍼 칩이 없는 카트리지 게임만 실행된다. 저장소에는 재배포가 허용된 ROM 세 개(nestest, Full Game, Thwaite)가 들어 있다.

실행해서 확인한 절차다.

진행

  1. 3일예정
  2. 7일예정
  3. 15일예정
  4. 30일예정
  5. 90일예정
  6. 180일예정
  7. 365일예정