SONUB 홈 KO English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

알림을 켜는 방법

이 브라우저 또는 주소에서는 알림을 사용할 수 없습니다. 지원되는 브라우저로 보안 연결된 SONUB 사이트에 접속해 주세요.

알림이 차단되어 있으면 브라우저 설정에서 허용해 주세요.

  1. 주소 표시줄 옆의 사이트 설정 또는 브라우저의 사이트 설정을 열고, 이 사이트의 알림을 허용으로 바꾸세요.
  2. 기기 설정에서 브라우저 알림을 허용하고 방해 금지 또는 집중 모드를 확인하세요.
  3. SONUB으로 돌아와 페이지를 새로고침한 뒤 벨을 눌러 알림을 켜세요.

iPhone 또는 iPad에서는 SONUB을 홈 화면에 추가하고 거기에서 연 뒤 알림을 허용하세요.

XSML · 첫 코드부터 나만의 대화까지

자, 이제 여러분들만의 인공지능을 만들어 봅시다.

이 브라우저에서 직접 타이핑하며 언어 모델을 만듭니다. 데이터를 준비하고 작은 GPT를 학습한 뒤, 내가 만든 Runner와 XChat으로 대화합니다. 미리 학습된 가중치나 외부 AI API는 쓰지 않습니다.

6

학습·체크포인트

다음 토큰을 예측하고 가중치를 바꾼 뒤 저장 지점에서 이어 합니다.

토큰이 [a,b,c]라면 입력 [a,b]의 정답은 [b,c]입니다. 교차 엔트로피 은 정답 토큰 확률의 음수 로그입니다. 손실이 작으면 정답에 더 높은 확률을 주었다는 뜻이며 사실을 말한다는 보장은 아닙니다.

매 반복은 짧은 구간 선택 → 이전 기울기 지우기 → 순전파·역전파 → 기울기 크기 제한 → SGD 갱신 순서입니다. 한 번의 갱신을 마칠 때마다 가중치·설정·토크나이저·진행 횟수·난수 상태를 저장합니다. 처음과 끝의 은 같은 검증 자료 첫 구간을 봅니다. 작은 상태 확인용이며 전체 가 아닙니다.

직접 타이핑하며 실습하기

train.py를 작성하고 짧은 학습 명령을 실행하세요. 실제 step과 loss가 나오는지 봅니다. 이어서 5회 더 실행해 resume 값을 확인하세요. 기기마다 속도가 다르므로 작게 시작합니다. 기본 반복은 동작 확인용이고, 반복을 늘리며 변화를 실험합니다.

cd ~/xsml
nano train.py
python3 train.py --steps 20
python3 train.py --steps 5
train.py직접 작성할 전체 소스

자료 해시는 자료가 바뀐 줄 모르고 이어 학습하는 일을 막습니다. 임시 파일에 쓴 뒤 os.replace로 바꾸므로 저장 도중 중단되어도 이전 완성 체크포인트가 남습니다. SGD에는 따로 저장할 모멘텀 상태가 없습니다.

import argparse
import hashlib
import json
import math
import os
import random
from pathlib import Path
from model import GPT
from tokenizer import BPE


def main():
    cfg = json.loads(Path('settings.json').read_text())
    parser = argparse.ArgumentParser()
    parser.add_argument('--steps', type=int, default=cfg['steps'])
    args = parser.parse_args()
    assert args.steps > 0, '--steps must be positive'
    token_state = json.loads(Path('data/tokenizer.json').read_text())
    tokenizer = BPE(**token_state)
    train_text = Path('data/train.txt').read_text(encoding='utf-8')
    val_text = Path('data/val.txt').read_text(encoding='utf-8')
    fingerprint = hashlib.sha256((train_text + '\0' + val_text).encode()).hexdigest()
    train, val = tokenizer.encode(train_text), tokenizer.encode(val_text)
    model = GPT(len(tokenizer.vocab), cfg['width'], cfg['context'], cfg['seed'])
    rng, step = random.Random(cfg['seed']), 0
    checkpoint = Path('checkpoints/model.json')
    if checkpoint.exists():
        saved = json.loads(checkpoint.read_text())
        assert saved['settings'] == cfg and saved['tokenizer'] == token_state, 'changed settings/tokenizer: start a new checkpoint'
        assert saved['data_hash'] == fingerprint, 'changed data: start a new checkpoint'
        model.load(saved['weights'])
        step = saved['step']
        rng.setstate((saved['random'][0], tuple(saved['random'][1]), saved['random'][2]))
    n = model.context
    assert len(train) > n and len(val) > n, 'add more text'
    print('parameters:', len(model.parameters), 'resume:', step, flush=True)
    print('validation:', round(model.loss(val[:n], val[1:n + 1]).data, 4), flush=True)
    checkpoint.parent.mkdir(exist_ok=True)
    for _ in range(args.steps):
        start = rng.randrange(len(train) - n)
        window = train[start:start + n + 1]
        for p in model.parameters:
            p.grad = 0
        loss = model.loss(window[:-1], window[1:])
        loss.backward()
        size = math.sqrt(sum(p.grad * p.grad for p in model.parameters))
        scale = min(1.0, 1.0 / (size + 1e-8))
        for p in model.parameters:
            p.data -= cfg['learning_rate'] * p.grad * scale
        step += 1
        state = {'settings': cfg, 'tokenizer': token_state, 'data_hash': fingerprint,
                 'weights': model.state(), 'step': step, 'random': rng.getstate()}
        temporary = checkpoint.with_suffix('.tmp')
        temporary.write_text(json.dumps(state, ensure_ascii=False), encoding='utf-8')
        os.replace(temporary, checkpoint)
        print('step:', step, 'loss:', round(loss.data, 4), flush=True)
    print('validation:', round(model.loss(val[:n], val[1:n + 1]).data, 4), flush=True)
    print('saved:', checkpoint, flush=True)


if __name__ == '__main__':
    main()

여기까지 이해했나요?

checkpoints/model.json이 생겼나요? 두 번째 실행은 이전 횟수에서 이어져야 합니다. 학습 전후 validation을 비교하세요. 매번 다른 구간을 뽑으므로 loss는 오르기도 합니다. 한 번의 수치로 결론 내리지 마세요.

막혔을 때 확인하기

Ctrl+C로 멈추면 마지막으로 마친 갱신까지 남습니다. 설정·토크나이저·데이터를 바꾸면 기존 체크포인트를 일부러 거부합니다. 먼저 내보내고 model.json을 다른 이름으로 옮겨 새로 시작하세요. 이미 실행 중인 Runner는 다시 시작해야 새 가중치를 읽습니다.