비트 단위 재현으로 학습 전 과정을 감사 가능하게 만든 Open-1B
OPEN-1B: A Fully Auditable Training Run
무엇인가
이 논문이 푸는 문제는 오픈소스 언어모델의 검증 불가능성이다. 저자들은 투명성을 폐쇄형 모델, 오픈 웨이트 모델, 오픈 소스 모델의 세 단계로 나눈 뒤, OLMo나 Pythia처럼 가중치와 데이터, 레시피를 모두 공개한 오픈 소스 모델조차 완전히 재현되지는 않는다고 지적한다. 원인은 부동소수점 연산의 비결합성이다. (a⊕b)⊕c는 일반적으로 a⊕(b⊕c)와 다르기 때문에, 같은 레시피를 그대로 따라도 하드웨어가 다르면 마지막 비트가 달라진다. 프레임워크의 결정적 실행 모드는 같은 기계에서의 반복만 보장할 뿐, CPU와 GPU, 서로 다른 GPU 모델 사이의 일치를 보장하지 않는다. 저자들은 이를 구분해 전자를 결정성, 후자를 비트 단위 재현성(BR)이라 부르고, proof-of-learning이나 proof-of-training-data 같은 기존 기법은 확률적 검증에 그쳐 소량의 데이터로도 삽입 가능한 백도어를 걸러내지 못한다고 본다. 그래서 네 번째 투명성 계층으로 완전 감사 가능(fully auditable)을 제안한다.
어떻게 동작하나
방법의 첫 축은 Gensyn이 만든 재현 가능 연산 라이브러리 RepOps다. 모든 하드웨어에서 리덕션 순서를 고정해 반올림 시퀀스를 동일하게 만들고, a×b+c 패턴에서 컴파일러가 임의로 융합 여부를 정하지 못하도록 CPU 빌드에서는 융합을 끄고 GPU에서는 명시적으로 비융합 곱셈-덧셈을 쓴다. 서브노멀은 백엔드마다 처리가 갈리는데(Apple GPU는 FTZ/DAZ로 0 처리, CPU와 NVIDIA GPU는 기본적으로 보존), 가장 덜 관대한 백엔드에 맞춰 모두 0으로 플러시한다. 난수는 시드만으로는 플랫폼 간 일치가 안 되므로, 시드와 고정된 논리적 위치 i의 순수 함수로 값을 계산하는 카운터 기반 생성기(Philox)를 쓴다. 이렇게 하면 텐서 크기나 레인 분할 방식, 실행 GPU와 무관하게 동일한 스트림이 나온다.
무엇과 다른가
두 번째 축은 위상 불변 데이터 스트림이다. 학습 데이터를 월드 크기나 랭크, 노드 수와 무관한 단일 정규 스트림으로 정의하고, 소스 인터리빙(학습 시드만으로 시드되는 전역 mix RNG), 샤드 순서(seed, SHA-256(source), epoch로 시드), 문서 순서(seed, SHA-256(source), epoch, shard로 시드)의 세 의사난수 생성기로 완전히 결정한다. 소스 이름을 Python의 프로세스별 랜덤 해시가 아니라 SHA-256으로 해싱하는 것이 프로세스·기계·인터프리터 버전 간 동일성을 보장하는 핵심이다. 선택된 문서는 구분자 토큰과 함께 평탄한 토큰 버퍼로 이어 붙이고, 앞에서부터 4,097 토큰(입력+레이블) 단위로 윈도를 잘라낸다. 데이터 병렬성은 스트림을 정의한 뒤에 적용하며, R-way 데이터 병렬 작업의 랭크 r은 m mod R = r인 윈도 W_m을 소유한다. GPU 수를 바꾸면 어느 랭크가 어떤 윈도를 로드하는지만 바뀐다. 다만 전역 배치 크기와 그래디언트 누적을 (M mod R) = 0이 되도록 잡아야 유휴 워커가 생기지 않는다. 재개 상태는 소스별 소비 문서 수, 에포크 카운터, mix RNG의 비트 상태, 패킹 버퍼에 남은 부분 윈도를 담은 랭크 독립 레코드로 저장된다.
어떻게 쓰나
모델 자체는 1.61B 파라미터(비임베딩 1.08B)의 디코더 전용 트랜스포머로, Llama 3·OLMo 2·Gemma에서 착안하되 저정밀 학습의 안정성과 재현성을 위해 조정했다. 바이어스 없음, SwiGLU(게이트와 업 프로젝션을 하나의 융합 GEMM으로 계산), θ=500,000인 RoPE, 16개 쿼리 헤드가 4개 KV 헤드를 공유하는 GQA, 바이어스 없는 RMSNorm 프리노름, 학습 가능한 게인을 제거한 QK-norm(게인 곱이 무한한 어텐션 온도로 작동해 어텐션 엔트로피 붕괴를 일으킨다고 관측), 첫 트랜스포머 블록 앞 임베딩에 추가한 RMSNorm, 512 토큰 슬라이딩 윈도 어텐션(5번째마다와 마지막 층은 완전 인과), 가중치 10^-4의 z-loss, 언타이드 임베딩을 쓴다. 모든 어텐션·피드포워드 선형층은 LSQ 기반 int8 양자화 인지 학습으로 8비트 가중치와 활성값을 쓰고, 가중치 스케일은 매 옵티마이저 스텝마다 2·mean(|w|)/√q_max로 다시 고정한다. 플래시 어텐션 내부의 P·V 곱도 int8 텐서 코어에서 계산하되 QK^T 로짓과 소프트맥스는 고정밀로 유지하고, 어텐션 역전파는 ∇Q를 64비트 고정소수점으로 누적해 재현성을 확보한다. 임베딩과 LM 헤드, 정규화, RoPE 테이블, 손실 계산은 양자화에서 제외된다.
전제와 한계
학습 레시피는 4,096 시퀀스 길이로 400B 토큰, 48대 H100에서 수행했다. AdamW(β1=0.9, β2=0.95, ε=10^-8), 디커플드 가중치 감쇠 0.1(입력 임베딩·정규화 가중치·RoPE 테이블 제외), 그래디언트 전역 L2 노름 1.0 클리핑을 쓴다. GPU당 마이크로배치는 4 시퀀스 16,384 토큰이고, 전역 배치는 그래디언트 누적 깊이를 세 단계로 올려 램프한다. 학습률은 워밍업 단계 배치로 667 스텝(약 2.1B 토큰) 동안 선형으로 4.5·10^-4까지 올린 뒤 400B 토큰 예산에서 피크의 10%(4.5·10^-5)까지 단일 코사인 감쇠를 따른다. 스케줄은 스텝 수가 아니라 소비 토큰에 고정되어 배치 램프와 어긋나지 않는다. 전역 시드는 42 하나이고, 드롭아웃이나 확률적 깊이, 레이블 스무딩 같은 확률적 정규화는 전혀 쓰지 않는다. 사전학습 데이터는 Open-1B Mix 0626이라 부르는 약 450B 토큰으로, 80%가량이 웹 데이터다. DCLM-Baseline, FineWeb-Edu, The Stack v2의 허용 라이선스 부분집합, 그리고 arXiv·OpenWebMath·Algebraic Stack을 29:15:11로 합친 Proof-Pile-2를 결합했고, 업스트림 품질 파이프라인을 그대로 신뢰하며 인제스트 단계에서 세 가지 필터만 추가 적용한다.
감사는 세 단계 리덕션을 단일 디바이스에서 순차 재생하는 방식으로 이루어진다. 단일 디바이스의 마이크로배치 그래디언트 누적, 노드 내 샤드에 대한 reduce-scatter, 노드 간 레플리카에 대한 all-reduce가 그것이다. reduce-scatter는 메시 순서(레플리카 우선, 샤드 후순)로 가상 랭크를 도는 단일 루프에서 누적 합으로 실현되어 한 번에 하나의 부분 그래디언트만 메모리에 상주한다. 레플리카 간 all-reduce는 클러스터의 재귀적 배증 all-reduce와 같은 짝짓기 순서로 부분값을 결합하는 TreeFold로 처리한다. 전체 학습 실행을 한 기계에서 재생하는 것은 불가능하므로, 다수의 독립 감사자가 각자 개별 스텝을 인증해 전체 실행을 함께 커버하는 집합적 검증 방식을 쓴다. 감사 하네스는 NVIDIA GPU, x86 CPU, ARM CPU, Apple Silicon(Metal)을 지원한다.
결과 수치는 상당히 솔직하다. int8 재현 런타임과 PyTorch bf16 구현을 같은 레시피로 비교했을 때, 400B 토큰 후 교차엔트로피 손실이 약 0.2 nats 벌어졌고 z-loss는 int8에서 더 크게 벌어졌다(int8의 균일한 간격 때문에 z-loss가 더 높은 값에서 포화되는 양자화의 자연스러운 결과다). 비용 면에서 Open-1B는 GCP의 a3-megagpu-8g 노드 6대로 총 29.5일의 실시간을 썼고, 그중 27.8일이 실제 사전학습이다. GPU당 약 485W, 평균 전력 사용률 약 50%(최대 70%)에 MFU는 5% 근처로, 최적화된 비재현 커널 대비 한 자릿수 낮다. 강한 스케일링 실험에서 전역 배치를 288 마이크로배치(스텝당 4,718,592 토큰)로 고정하고 1~6 노드로 확장했을 때, 매 스텝 해싱을 켜면 처리량이 40.0k 토큰/s에서 169.4k로 늘어 71% 효율을 보였고, 해싱을 끄면 217.4k(86%)에 도달했다. 순전파+역전파는 99.7% 효율이므로 손실은 스텝당 약 6.0초가 일정하게 드는 상태 해시와 6노드에서 2.6초인 노드 간 레플리카 리덕션에서 온다. 런타임 오버헤드 비교에서는 단일 노드에서 비트 재현 bf16 커널이 MFU 3.3%로 스톡 PyTorch의 40.5% 대비 12.2배 느렸고, int8 QAT 레시피가 이를 완화해 repop의 bf16 경로보다 약 1.8배 빠르면서 스톡 PyTorch보다는 6.8배 느렸다. 6노드로 확장하면 격차가 약 5.0배로 좁혀진다(repop 계열 91%/86% 대 PyTorch 66%).
저자들이 밝힌 한계는 분명하다. 비트 재현성을 강제하는 대가로 텐서 코어 GEMM이 스톡 PyTorch bf16 베이스라인보다 수 배 느리고, 그 오버헤드와 자원 제약 때문에 OLMo 2 1B의 4T 토큰 예산보다 한 자릿수 적은 토큰으로 학습해 다운스트림 벤치마크에서 뒤진다. 상태 해싱이 호스트에서 구현되어 디바이스-호스트 메모리 전송 오버헤드를 유발하며, 향후 온디바이스 해싱으로 전환해 스텝당 약 6초 비용을 거의 없애는 것이 목표다. 또한 감사는 모델의 편향을 제거하지 않는다. 다만 어떤 편향이 존재할 수 있는지 감사자가 절대적으로 확신할 수 있게 해줄 뿐이다. 부수적으로 int8 사전학습에서 LSQ 스텝 크기가 발산해 양자화 레벨이 붕괴하는 불안정성을 발견했고, 이를 스텝 크기를 학습하지 않고 매 스텝 가중치로부터 재계산하는 방식으로 해결했다(스텝 시간의 약 2% 비용, 양자화를 끄는 대안은 약 70%). 확률적 라운딩은 비트 재현성과 양립하지 않아 해법으로 채택되지 않았다.
개발자 관점에서 이 논문의 실용적 의미는 두 가지다. 첫째, 재현성을 주장하려면 결정적 실행 모드로는 부족하고 리덕션 순서, FMA 융합 정책, 서브노멀 처리, 난수 생성 방식까지 명시적으로 고정해야 한다는 체크리스트를 제공한다. 둘째, 학습 실행의 무결성을 제3자가 검증해야 하는 상황(규제, 감사, 모델 출처 증명)에서 스텝 단위 해시와 단일 디바이스 재생 하네스가 어떤 형태로 구현되는지 참조할 수 있다. 다만 처리량을 5배가량 포기하는 비용이 따르므로, 재현성이 실제로 요구되는 구간에만 선택적으로 적용하는 판단이 필요하다.