borch

파이썬

파이썬 길

borch_webgpu 는 borch.ts 에 파이썬 표면을 씌운 것이다. 교재에 있는 학습 코드가 탭 안 GPU 에서 돈다. 설치하는 것도, 어디로 보내는 것도 없다.

이 페이지가 왜 필요한지는 분명히 해 두는 게 좋겠다. borch 는 PyTorch 모양이고, 그 모양이 향하는 사람들은 파이썬을 읽는다. 그런데 어색한 부분을 지고 있는 쪽은 자바스크립트 표면이다 — 값을 읽을 때마다 await, 모델을 부를 때 model.call(x). 파이썬에서는 그 대부분이 없다. 닮음이 가장 진한 표면이고, 이 페이지는 그 표면의 참조 문서다 — 넘기는 원리, 비용, 멈추는 곳. 배우려면 배우기튜토리얼의 모든 블록에 파이썬 탭이 있고, 일하려면 NotebookWorkbench가 처음부터 끝까지 파이썬이다.

넘길 뿐, 다시 만들지 않는다

지원 연산 목록이 없다. 모듈의 __getattr__ 이 물어본 이름을 받아 snake_casecamelCase 로 바꾸고 그 메서드를 텐서에 부른다. borch.ts 에 없으면 두 철자를 모두 대며 AttributeError 로 멈춘다 — numpy 로 비슷하게 만들어 주지 않는다.

알아 둘 만한 결과가 하나 딸린다. 파이썬 표면이 borch.ts 를 자동으로 따라가므로 이름을 안 더해서 뒤처지는 일은 생기지 않는다. 대신 위에 얹어 조립하는 것은 가능한데, 저장소는 그 자리를 사람 눈이 아니라 검사로 센다.

torch 코드에서 무엇이 달라지나

borch 와 torch 를 가르는 것이 다섯이다. 그중 셋은 자바스크립트 사정이고, 이 표면에는 아예 없다.

torchborch.tsborch_webgpu
await init() 없음
t.item() await t.item() t.item()
model(x) model.call(x) model(x)
scope(async () => …) with torch.scope():
keepAlive(t) torch.keep_alive(t)

남는 것은 scope() 이고, 남을 수밖에 없다. 한 스텝이 중간 버퍼를 수천 개 만드는데 어느 언어의 쓰레기 수집도 GPU 메모리를 제때 안 놓는다. 같은 201 스텝에서 with 를 빼면 쥐고 있는 양이 1.0MB 에서 228.9MB 가 된다.

await 가 없는 이유

WebGPU 에는 동기 읽기가 없다. GPU 에서 수 하나를 가져오는 것이 약속이고, 자바스크립트에서는 그 약속이 await t.item() 으로 코드까지 올라온다. Pyodide 의 run_sync 가 WebAssembly 의 JSPI 위에서 파이썬 프레임을 대신 기다리게 해 주므로, loss.item() 이 다시 평범한 식이 된다.

조건이 하나 붙고, 이 사이트에서 이것이 되는 이유가 그것이다 — 페이지가 파이썬으로 비동기로 들어가야 한다. 코드가 하는 일이 아니라 페이지가 Pyodide 를 시작하는 방식의 성질이다.

무엇이 드나

이 기계에서 localhost 로, 브라우저 캐시가 빈 상태에서 잰 값이다. 첫 파이썬 실행이 여섯 파일 25.1MB 를 받았고 — Pyodide, 파이썬 표준 라이브러리, WebAssembly 빌드, numpy 휠 — 끝까지 1,066ms 걸렸다. 두 번째 실행은 2ms 였다. 실제 연결에서 달라지는 것은 25.1MB 쪽이고, 나머지 모양은 그대로 예상해도 된다.

전부 페이지와 같은 출처에서 나온다. CDN 에서 받아 오는 것도, 올려 보내는 것도 없다 — 자바스크립트 쪽이 하는 약속과 같다.

어디서 멈추나

정직한 모서리 셋이고, 전부 이 페이지를 쓰면서 확인한 것이다.

구역 밖으로는 표시한 것만 나간다. with torch.scope(): 안에서 만들고 표시를 안 하면 블록 끝에서 놓이고, 그 뒤에 쓰면 멈춘다. 표시가 둘 있는데 같은 것이 아니다. torch.keep_alive(t) 는 어떤 구역도 안 놓는다는 뜻이고 — 파라미터와 옵티마이저 상태가 원하는 것이 그것이다 — with torch.scope() as s: s.keep(t) 는 바깥 구역에 넘겨서 그쪽이 닫힐 때 같이 놓인다. 중간값에 앞의 것을 쓰면 스텝마다 쌓인다.

이 페이지는 한동안 파이썬에 둘 다 없다고 적고 있었다. 쓸 때는 사실이었고 재서 쓴 것이다. 문장을 조용히 갈아 끼우는 대신 무엇이 바뀌었는지 적어 둔다 — 결속에 구역은 있는데 문이 없었고, 그때 나오던 말은 keepAlive 가 borch.ts 에 없다고 했는데 거짓이었다. 검사하는 명제는 "텐서 메서드인가" 인데 말하는 명제는 "borch.ts 에 있는가" 였다. 둘 다 고쳐졌고, 문구도 이제 자기가 어느 쪽을 말하는지 밝힌다.

torch.cuda.is_available() 은 거짓을 답한다. 일부러 그렇다. borch 는 GPU 를 쓰지만 CUDA 가 아니고, 교재 코드는 그 이름으로 끊임없이 갈라진다. 버퍼 통은 torch.empty_cache() 로 비운다.

메모리를 묻는 질문이 둘이다. torch.memory() 는 "새는가" 를 묻고 통을 일부러 뺀다. torch.pooled() 는 "얼마나 쥐고 있는가" 를 묻는다. 앞의 것만 읽던 벤치가 269.7MB 라고 답할 때 통에는 1,699.6MB 가 있었다.

맞는지 눌러 보기

이 모든 것의 밑에 있는 주장은 두 표면이 같은 커널에 닿는다는 것이다. javascript 로 돌린 뒤 python 을 눌러 다시 돌려 보면 된다.

같은 고리가 학습 강의에도 있다. 4강이 201 스텝 선형회귀를 두 언어로 담고 있는 이유가 같다 — 밑에 커널이 한 벌뿐이라 손실이 마지막 자리까지 맞는다.