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는 쓰지 않습니다.

4

BPE 토크나이저

내 학습 자료에서 BPE 어휘 사전을 직접 학습합니다.

토크나이저는 글 조각마다 번호를 붙입니다. 이 문자 기반 BPE는 한 글자씩 시작해 붙어 있는 두 조각의 횟수를 세고, 가장 자주 나온 쌍을 합칩니다. 합친 순서가 중요하므로 글을 번호로 바꿀 때도 같은 순서로 규칙을 적용합니다.

이 작은 교육용 구현은 줄바꿈을 합치지 않고 모르는 글자에 0번을 씁니다. 모든 를 다루는 상용 토크나이저와는 다릅니다. tokenizer.json에 어휘와 병합 규칙을 함께 저장합니다. 특정 사전으로 학습한 모델에 다른 사전을 끼우면 번호의 뜻이 달라집니다.

직접 타이핑하며 실습하기

tokenizer.py를 직접 작성하고 실행해 JSON을 확인하세요. merge를 종이에 따라가 봅니다. 두 번호가 쌍과 맞으면 새 번호를 넣고 두 칸 전진하며, 아니면 한 칸 전진합니다. 학습 문장을 encode한 뒤 decode해 보세요.

cd ~/xsml
nano tokenizer.py
python3 tokenizer.py
python3 -m json.tool data/tokenizer.json
tokenizer.py — 직접 작성할 전체 소스

merge는 겹치지 않게 한 쌍을 합칩니다. train은 순서 있는 규칙을 배우고, encode는 그 규칙을 다시 적용합니다. decode는 조각을 이어 붙입니다. 마지막 assert는 원문 복원을 검사합니다.

import json
from collections import Counter
from pathlib import Path


def merge(ids, pair, new_id):
    result, i = [], 0
    while i < len(ids):
        if tuple(ids[i:i + 2]) == tuple(pair):
            result.append(new_id)
            i += 2
        else:
            result.append(ids[i])
            i += 1
    return result


class BPE:
    def __init__(self, vocab, merges):
        self.vocab, self.merges = vocab, merges
        self.chars = {c: i for i, c in enumerate(vocab) if len(c) == 1}

    @classmethod
    def train(cls, text, count):
        vocab = ['\ufffd'] + sorted(set(text) - {'\ufffd'})
        ids = [vocab.index(c) for c in text]
        merges = []
        for _ in range(count):
            pairs = Counter((a, b) for a, b in zip(ids, ids[1:])
                            if '\n' not in vocab[a] + vocab[b])
            if not pairs:
                break
            pair, frequency = pairs.most_common(1)[0]
            if frequency < 2:
                break
            new_id = len(vocab)
            vocab.append(vocab[pair[0]] + vocab[pair[1]])
            merges.append([list(pair), new_id])
            ids = merge(ids, pair, new_id)
        return cls(vocab, merges)

    def encode(self, text):
        ids = [self.chars.get(c, 0) for c in text]
        for pair, new_id in self.merges:
            ids = merge(ids, pair, new_id)
        return ids

    def decode(self, ids):
        return ''.join(self.vocab[i] for i in ids)

    def state(self):
        return {'vocab': self.vocab, 'merges': self.merges}


if __name__ == '__main__':
    settings = json.loads(Path('settings.json').read_text())
    text = Path('data/train.txt').read_text(encoding='utf-8')
    tokenizer = BPE.train(text, settings['merges'])
    Path('data/tokenizer.json').write_text(
        json.dumps(tokenizer.state(), ensure_ascii=False), encoding='utf-8')
    assert tokenizer.decode(tokenizer.encode(text)) == text
    print('vocab:', len(tokenizer.vocab), 'merges:', len(tokenizer.merges))
    print('roundtrip: OK', tokenizer.encode('Q: hi\nA:'))

여기까지 이해했나요?

roundtrip: OK는 전체 학습 자료를 번호로 바꿨다가 원문 그대로 되돌렸다는 뜻입니다. settings.json의 병합 횟수를 바꾸어 토큰 수를 비교하세요. 처음 보는 글자는 새로 배우지 않고 �로 바뀝니다.

막혔을 때 확인하기

되풀이되는 쌍이 없으면 병합이 없어도 정상입니다. 글이나 병합 규칙을 바꾸었다면 토크나이저와 모델 가중치를 새로 학습해야 합니다. 이전 체크포인트는 먼저 내보내 보관하세요.