LabHub
시작하기
배우기 러닝패스 코스

MiniMind — 작은 언어 모델을 처음부터 끝까지 직접 학습한다

패딩이 버리는 계산을 재고, 말뭉치를 패킹한다

LabHub 에서 이어서 보기

목표

기준 토크나이저로 사전학습 말뭉치를 잘라 MiniMind 식 패딩이 계산의 몇 %를 버리는지 재고, 문서를 [bos] … [eos] 로 감싸 이어 붙인 uint16 배열(패킹)로 학습·검증 자료를 만든다. 검증 누수와 문서 경계, 학습 예산까지 숫자로 확인한다.

왜 중요한가

행렬 곱은 패딩인지 모른다. 패딩 자리는 손실에서 빠질 뿐 계산은 그대로 한다. 문서가 짧은데 최대 길이를 길게 잡으면 GPU 는 바쁜데 배우는 토큰은 적다. 패킹은 그 낭비를 없애는 대신 한 창에 여러 문서를 넣어 뒤 문서가 앞 문서를 보게 만든다 — 대부분의 사전학습이 감수하는 맞바꿈이다. 자료를 준비하는 단계에서 생기는 실수는 학습이 끝나야 드러난다. 검증 문서가 학습 쪽에 섞이면 검증 손실이 거짓말을 하고, 한 걸음의 토큰 수를 모르면 손실 곡선을 읽을 수 없다. 그래서 학습 전에 숫자로 확인해 둔다.

단계

  1. /opt/mm/ref/tokenizer.json 으로 /opt/mm/data/pretrain.jsonl 의 문서마다 토큰 수를 세어 /root/mm/data/lengths.jsondocs·mean·max·p95 로 적으세요.
  2. MiniMind PretrainDataset 처럼 문서 하나를 [bos] + 토큰(최대 126) + [eos] 로 싸서 길이 128 까지 패딩한다면 패딩이 몇 개인지 /root/mm/data/padding.jsonmax_len·rows·pad_tokens·pad_fraction·truncated_docs 로 적으세요.
  3. 학습 말뭉치를 문서마다 [bos](1) 토큰들 [eos](2) 로 감싸 이어 붙인 uint16 배열을 /root/mm/data/train.npy 로 저장하세요.
  4. 같은 방법으로 /opt/mm/data/pretrain_val.jsonl/root/mm/data/val.npy 로 저장하세요.
  5. 검증 문서 가운데 학습 말뭉치에 글자 그대로 있는 것의 수를 /root/mm/data/leak.jsonval_docs·dup_in_train 으로 적으세요.
  6. train.npy 를 128 토큰씩 겹치지 않게 자른 창에서, 창 하나의 평균 문서 수와 앞 문서를 볼 수 있는 토큰의 비율을 /root/mm/data/windows.jsonseq_len·windows·docs_per_window·cross_doc_fraction 으로 적으세요.
  7. 배치 16 · 길이 128 일 때 한 걸음의 토큰 수와 한 바퀴(에폭)의 걸음 수를 /root/mm/data/budget.jsontrain_tokens·tokens_per_step·steps_per_epoch 로 적으세요.
  8. /root/mm/data/report.md## 패딩 ## 패킹 ## 검증 분리 세 절을 쓰고, 2단계의 pad_fraction 과 6단계의 cross_doc_fraction 을 숫자로 넣으세요.

참고

문서가 몇 토큰인가

/opt/mm/ref/tokenizer.json 으로 /opt/mm/data/pretrain.jsonl 의 text 를 문서마다 잘라, 문서 수·평균·최댓값·95 백분위(numpy.percentile(길이, 95))를 /root/mm/data/lengths.jsondocs·mean·max·p95 로 적으세요.

평균과 최댓값만 봐도 패딩이 얼마나 생길지 짐작됩니다. 최대 길이를 최댓값에 맞추면 아무것도 안 잘리지만, 평균 길이 문서는 나머지를 전부 패딩으로 채웁니다.

MiniMind 식 패딩이 버리는 몫

문서 하나를 [bos] + 토큰(126개까지 자름) + [eos] 로 싸서 길이 128 까지 패딩한다고 할 때, 패딩 토큰 수와 전체(문서 수×128)에서의 비율, 잘린 문서 수를 /root/mm/data/padding.jsonmax_len·rows·pad_tokens·pad_fraction·truncated_docs 로 적으세요.

MiniMind 의 PretrainDataset.__getitem__ 이 그대로 이 계산을 합니다 — max_length - 2 로 자르고 bos·eos 를 붙인 뒤 나머지를 pad 로 채웁니다. 패딩은 손실에서 빠지지만(-100) 행렬 곱은 그 자리까지 합니다.

학습 말뭉치를 한 줄로 잇는다

스크립트 /root/mm/data/pack.py(인자: 입력 jsonl, 저장할 .npy)를 써서 /opt/mm/data/pretrain.jsonl 의 문서를 파일 순서대로 1(bos) 토큰들 2(eos) 로 감싸 이어 붙이고, uint16 배열로 /root/mm/data/train.npy 에 저장하세요.

파일 순서를 바꾸거나 섞으면 채점기가 다시 만든 배열과 달라집니다 — 섞는 일은 학습 루프가 배치를 뽑을 때 합니다. 어휘가 1024 라 uint16(최대 65535)이면 충분하고, int64 의 4분의 1 크기입니다.

검증 말뭉치도 같은 방법으로

/opt/mm/data/pretrain_val.jsonl 을 3단계와 같은 방법으로 패킹해 /root/mm/data/val.npy 에 저장하세요.

검증 자료는 학습과 같은 방식으로 만들어야 두 손실을 견줄 수 있습니다. 3단계 스크립트가 입력·출력 경로를 인자로 받게 해 두면 한 줄입니다.

검증 문서가 새지 않았나

검증 문서(pretrain_val.jsonl 의 text) 가운데 학습 말뭉치(pretrain.jsonl)에 글자 그대로 있는 것의 수를 /root/mm/data/leak.jsonval_docs·dup_in_train 으로 적으세요.

학습 쪽 text 를 집합(set)으로 만들어 두면 한 번씩만 찾아보면 됩니다. 0 이 아니면 그 문서의 검증 손실은 외운 것을 잽니다.

한 창에 문서가 몇 개, 경계를 넘는 토큰은 몇 %

train.npy 를 128 토큰씩 겹치지 않게 자르고(남는 꼬리는 버림), 창 하나의 평균 [bos] 수(docs_per_window)와 앞 문서를 볼 수 있는 토큰의 비율(cross_doc_fraction)을 /root/mm/data/windows.jsonseq_len·windows 와 함께 적으세요. 어떤 토큰이 '앞 문서를 볼 수 있다' 는 것은 창 안에서 그 토큰 자리까지(자기 포함) 문서 시작([bos])이 한 번 이상 있었다는 뜻입니다 — 단, 창의 첫 토큰이 [bos] 이면 그 문서는 창 안에서 처음 시작한 것이라 세지 않습니다.

numpy.cumsum(창 == 1, axis=1) 로 자리마다 그때까지 나온 bos 수를 구하고, 첫 자리가 bos 인 창은 1을 빼 주면 됩니다. 인과 마스크는 앞의 모든 토큰을 보게 하므로, 문서별 마스크를 따로 만들지 않는 한 이 토큰들은 앞 문서를 봅니다.

한 바퀴는 몇 걸음인가

배치 16 · 길이 128 로 학습할 때 한 걸음이 먹는 토큰 수와, train.npy 전체를 한 번 보는 데 드는 걸음 수(올림)를 /root/mm/data/budget.jsontrain_tokens·tokens_per_step·steps_per_epoch 로 적으세요.

다음 모듈에서 수백 걸음을 학습하면 말뭉치를 몇 바퀴 도는지 이 숫자로 압니다. 같은 자료를 여러 바퀴 보면 학습 손실이 검증 손실보다 빨리 내려가기 시작합니다.

자료를 준비한 근거 남기기

/root/mm/data/report.md## 패딩 ## 패킹 ## 검증 분리 세 절을 쓰고, 2단계의 pad_fraction 과 6단계의 cross_doc_fraction 을 숫자(소수 또는 백분율)로 넣으세요.

패딩과 패킹 가운데 무엇을 고르겠는지, 그 대가로 무엇을 감수하는지 한 줄씩 적으세요. 검증 분리 절에는 5단계의 결과를 넣으면 됩니다.