SONUB ホーム JA 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辞書を学習します。

文字から始め、隣り合う頻出ペアを順に合併します。encodeも同じ順序で規則を適用します。

改行は合併せず未知文字はID 0です。完全な単位実装ではありません。辞書と規則を一緒に保存し、学習後に別の辞書へ交換しません。

入力して実験

tokenizer.pyを入力・実行し、JSONを調べます。mergeで一致時は2位置、その他は1位置進む様子を追います。

cd ~/xsml
nano tokenizer.py
python3 tokenizer.py
python3 -m json.tool data/tokenizer.json
tokenizer.py手入力する完全なソース

mergeで合併し、trainで順序を学び、encodeで再適用、decodeで復元します。

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と原文復元を確認。未知文字は�になります。

困ったとき

頻出ペアがなければ合併ゼロでも正常です。辞書変更後は重みも新しく学習します。