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をホーム画面に追加し、そこから開いて通知を許可してください。

ログイン ログアウト 表示テーマ 標準テーマ ダークテーマ ピンクテーマ チャット 1:1 チャット グループチャット 掲示板 お知らせ ニュース掲示板 ご意見掲示板 自己紹介 メインメニュー

さあ、あなただけの人工知能を作ってみましょう。

自分でさせた を に上げて、だれでもダウンロードできるようにします。export.py で を書き出し、を書いてから push してみましょう。

単語のブロックが一列に並び、最後に空きマスがある。その上に高さのちがう棒がついた候補ブロックが3つあり、そのうち1つが選ばれて列の最後につながり、矢印が最初に戻ってまた次を選ぶ。
10

自分のモデルを公開

は を上げたりダウンロードしたりする場所で、モデルのための のようなサイトです。モデル1つが 1つです。ファイル・設定・・実行と()をいっしょに上げると、ほかの人が同じモデルを受け取ってそのまま動かせます。

手順は3つです。export.py がチェックポイントの数を ファイルに書き出し、自分でモデルカードを書き、git で Hugging Face のリポジトリに push します。 は変えません。ダウンロードした人は export.py --restore でチェックポイントを作り直し、同じ generate.py・runner.py・xchat.py で実行します。

なぜ公開するのか — モデルを分かち合う場所、Hugging Face

Hugging Face は、モデル・セット・デモを上げたりダウンロードしたりする公開の場所です。大きな会社から学生まで、だれでもモデルを上げています。概要で見た SmolLM2-135M も、ここからダウンロードします。

  • リポジトリ: モデル1つが git リポジトリ1つです。アドレスは huggingface.co/ユーザー名/モデル名 です。
  • : push のたびにが残るので、前の重みに戻れます。
  • モデルカード: リポジトリの README.md がモデルの最初の画面です。
  • 公開範囲: Public はだれでも、Private は自分と自分が許した人だけが見られます。

公開すると、ほかの人が自分の結果をそのままもう一度動かせます。これをといいます。実際の AI 開発でも、公開モデルをダウンロードして微調整し、また上げることが毎日起きています。

safetensors — 重みを入れる安全なファイル

safetensors は Hugging Face が作った重みファイルの形式です。中身は3つの部分だけです。

  • 最初の8: 後ろに続く ヘッダーの長さです(符号なし整数、)。
  • JSON ヘッダー: 層の名前ごとに (F32)・shape(行, 列)・data_offsets(本体の中の開始・終了バイト)を書きます。
  • 本体: すべての数を4バイトの としてすきまなくつなげたバイトです。

以前よく使われた の .bin ファイルは の pickle なので、ファイルを開いた瞬間に中に隠れたコードが実行されることがありました。safetensors には数と JSON しかないので、開いてもコードは実行されません。だから他人が上げたモデルをダウンロードするとき、より安全です。

の Python の数は8バイト(float64)ですが、ファイルには4バイト(float32)に縮めて書きます。0.1 が 0.10000000149011612 になるように、ごく小さな差が出ますが、基本のデータでしたモデルは生成結果がまったく同じです。1,248個 × 4バイト = 4,992バイトにヘッダーを足して、ファイルは約 5.7KB です。

自分で確かめる lab/safetensors.py
import struct
from pathlib import Path
from export import write_safetensors, read_safetensors

path = Path('lab/tiny.safetensors')
write_safetensors(path, {'w': [[0.1, 0.5], [-2.0, 3.0]]})
raw = path.read_bytes()
size = struct.unpack('<Q', raw[:8])[0]
print('file bytes:', len(raw), 'header bytes:', size)
print('header:', raw[8:8 + size].decode().strip())
print('numbers:', raw[8 + size:].hex(' ', 4))
print('read back:', read_safetensors(path)['w'])
cd ~/xslm
mkdir -p lab
micro lab/safetensors.py
python3 -m lab.safetensors

実行結果

file bytes: 128 header bytes: 104
header: {"__metadata__": {"format": "xslm"}, "w": {"dtype": "F32", "shape": [2, 2], "data_offsets": [0, 16]}}
numbers: cdcccc3d 0000003f 000000c0 00004040
read back: [[0.10000000149011612, 0.5], [-2.0, 3.0]]

いっしょに上げるファイル — 重みだけでは動かない

model.safetensors はただの数の表です。この数をもう一度使うには、受け取る人にあと3つ必要です。

  • config.json: モデルの大きさ(width・)と語彙の数、生成の初期値、学習したステップ数です。
  • tokenizer.json: 文章を番号に変える語彙とです。番号が1つ違うだけで、モデルはまちがった文字を見ます。
  • 実行コード: engine.py・model.py・tokenizer.py・generate.py・runner.py・xchat.py・export.py です。同じ数でも、同じ計算で動かしてはじめて同じ答えが出ます。

export.py はこれらのファイルをすべて hub フォルダーに集めます。(data)と train.py は上げません。モデルを使うのには必要なく、データは権利を別に確かめる必要があるからです。大きなモデルも同じです。Hugging Face のモデルリポジトリには、ふつう config.json・tokenizer.json・*.safetensors がいっしょにあります。

モデルカード — README.md に書くモデルの説明書

モデルカードはリポジトリの README.md です。上と下の2つの部分に分かれます。

  • ヘッダー(--- の2行のあいだ): (ライセンス)、language(言語)、tags(検索用のことば)、pipeline_tag(タスクの種類、ここでは text-generation)です。Hugging Face がこれを読んで、モデル一覧のフィルターや表示に使います。
  • 本文: 人が読む の説明です。

本文には少なくとも5つのことを書きます。何なのか、どんなファイルがあるのか、どう実行するのか、どんなデータで学習したのか、何ができないのか(限界)です。限界を正直に書くことが大切です。が1,248個なので答えはほとんどでたらめだと書いておけば、受け取った人がまちがった使い方をしません。

ライセンスとデータ — 公開する前に確かめること

Public リポジトリは、世界中のだれでも見てダウンロードできます。上げる前に3つのことを確かめましょう。

  • ライセンス: ほかの人がどう使ってよいかを決めます。MIT は、著作権の表示さえ残せばほぼ自由に使える短いライセンスです。ほかのものがよければ、・CC-BY-4.0 のように Hugging Face の一覧にある名前を使います。
  • 学習データの権利: 他人の文章を許可なく学習させたなら、そのモデルも公開しないでください。基本のデータは、この講座のために書いた例文です。
  • 個人情報: 名前・電話番号・住所のような情報をデータに入れたなら、モデルがその文をそのまま出してしまうことがあります。消してから学習し直し、そのあと上げます。

最初は Private で上げて確かめ、問題なければリポジトリの Settings で Public に変えてもかまいません。

大きなファイルと git-lfs — 数のファイルは別に上げる

git は、ソースコードのように行がある文章の、変わった行を記録するために作られました。重みのようなファイルには行がないので、少し変わっただけでもファイル全体がもう一度たまります。そのため Hugging Face は、バイナリファイルを git の中に直接入れた push を断ります。ファイルが小さくても同じです。

  • : ファイルの中身は別に上げ、git にはそのファイルを指す短いポインター(大きさと )だけを入れます。
  • .gitattributes: どのファイルを LFS に送るかを書いた一覧です。Hugging Face はリポジトリを作るときに *.safetensors を入れておいてくれます。
  • git-xet: Hugging Face の新しくて速い方法ですが、64bit のコンピューター専用です。このは なので git-lfs を使います。Hugging Face は git-lfs で上げたファイルもそのまま受け取って保存します。

git lfs install は git に LFS をつなぐ設定で、1回だけすれば済みます。そのあとはいつもどおり git add・commit・push するだけです。git lfs ls-files で、LFS に行ったファイルを確かめられます。

アクセストークン — パスワードの代わりに使うかぎ

Hugging Face は、git push でアカウントのパスワードを受けつけません。代わりに Settings → Access Tokens で作った(hf_ で始まる長い文字列)を、パスワードの場所に入れます。

  • : Read トークンはダウンロードだけ、Write トークンはアップロードまでできます。push には Write が必要です。
  • しまい方: トークンはパスワードと同じです。・チャット・コード・リポジトリのアドレス(https://ID:TOKEN@…)に入れないでください。
  • credential.helper : 入力したトークンを15分のあいだだけに覚えておき、git と git-lfs が2回聞かないようにします。ファイルには保存しません。
  • 消す: 全部上げ終わったら、Access Tokens でそのトークンを消してもかまいません。リポジトリとモデルはそのまま残ります。

トークンがもれたと思ったら、すぐに消して新しく作ってください。消したトークンでは何もできません。

ダウンロードしてもう一度動かす — 公開が完成した証拠

公開したモデルは、ほかの人のコンピューターで動いてはじめて意味があります。ダウンロードする人はこうします。

  • git clone https://huggingface.co/YOUR_ID/xslm-tiny でリポジトリを受け取ります。git-lfs がないと model.safetensors の代わりに短いポインターの文字だけが届くので、そのときは Web の Files タブからそのファイルをダウンロードします。
  • export.py --restore . で、safetensors・config・tokenizer から checkpoints/model.json を作り直します。
  • python3 generate.py で文章を作るか、runner.py・xchat.py で会話します。インストールするパッケージはありません。

seed と設定が同じなら、このターミナルとまったく同じ答えが出ます。これが再現です。大きなモデルも同じやり方です。受け取る側は safetensors を読み、自分の(PyTorch・・ など)で実行します。

入力して実験

まず huggingface.co に登録し、huggingface.co/new で xslm-tiny という名前の Public モデルリポジトリを作ります。Settings → Access Tokens で Write 権限のトークンも1つ作ります。そのあと下のを順に入力します。YOUR_ID は自分の Hugging Face のユーザー名に置きかえます。git push が Username を聞いたらユーザー名を、Password を聞いたらパスワードの代わりにトークンを貼りつけてください。トークンは画面に表示されません。

cd ~/xslm
micro export.py
sudo apk add git-lfs
git lfs install
git clone https://huggingface.co/YOUR_ID/xslm-tiny hub
python3 export.py
nano hub/README.md
cd hub
git config user.name "YOUR_ID"
git config user.email "you@example.com"
git config credential.helper cache
git add .
git commit -m "My first XSLM"
git push
ターミナルで実習する
export.py手入力する完全なソース

write_safetensors は数を4バイトの float32 として順に書き、前に JSON のヘッダーをつけます。read_safetensors はその逆です。export は hub フォルダーに重み・設定・トークナイザー・実行コードを集め、もう一度読んで差を見せます。--restore はダウンロードしたファイルを checkpoints/model.json に戻します。

import argparse
import json
import shutil
import struct
from pathlib import Path

SOURCES = ['engine.py', 'model.py', 'tokenizer.py', 'generate.py',
           'runner.py', 'xchat.py', 'export.py']


def write_safetensors(path, weights):
    header, body = {'__metadata__': {'format': 'xslm'}}, b''
    for name, matrix in weights.items():
        rows, cols = len(matrix), len(matrix[0])
        data = struct.pack('<%df' % (rows * cols),
                           *[v for row in matrix for v in row])
        header[name] = {'dtype': 'F32', 'shape': [rows, cols],
                        'data_offsets': [len(body), len(body) + len(data)]}
        body += data
    head = json.dumps(header).encode('utf-8')
    head += b' ' * (-len(head) % 8)
    path.write_bytes(struct.pack('<Q', len(head)) + head + body)


def read_safetensors(path):
    raw = path.read_bytes()
    size = struct.unpack('<Q', raw[:8])[0]
    header = json.loads(raw[8:8 + size])
    body, weights = raw[8 + size:], {}
    for name, info in header.items():
        if name == '__metadata__':
            continue
        assert info['dtype'] == 'F32', 'only float32'
        rows, cols = info['shape']
        start, end = info['data_offsets']
        flat = struct.unpack('<%df' % (rows * cols), body[start:end])
        weights[name] = [list(flat[r * cols:(r + 1) * cols])
                         for r in range(rows)]
    return weights


def export(folder):
    saved = json.loads(Path('checkpoints/model.json').read_text())
    folder.mkdir(exist_ok=True)
    write_safetensors(folder / 'model.safetensors', saved['weights'])
    config = {'model_type': 'xslm', 'vocab_size': len(saved['tokenizer']['vocab']),
              'step': saved['step'], 'settings': saved['settings']}
    (folder / 'config.json').write_text(json.dumps(config, indent=2))
    (folder / 'tokenizer.json').write_text(
        json.dumps(saved['tokenizer'], ensure_ascii=False), encoding='utf-8')
    for name in SOURCES:
        shutil.copy(name, folder / name)
    loaded = read_safetensors(folder / 'model.safetensors')
    gap = max(abs(a - b) for name in loaded
              for row, old in zip(loaded[name], saved['weights'][name])
              for a, b in zip(row, old))
    count = sum(len(row) for matrix in loaded.values() for row in matrix)
    print('parameters:', count, 'bytes:', (folder / 'model.safetensors').stat().st_size)
    print('largest float32 gap:', '%.1e' % gap)
    print('exported:', folder)


def restore(folder):
    config = json.loads((folder / 'config.json').read_text())
    state = {'settings': config['settings'],
             'tokenizer': json.loads((folder / 'tokenizer.json').read_text(encoding='utf-8')),
             'weights': read_safetensors(folder / 'model.safetensors')}
    Path('checkpoints').mkdir(exist_ok=True)
    Path('checkpoints/model.json').write_text(
        json.dumps(state, ensure_ascii=False), encoding='utf-8')
    print('restored: checkpoints/model.json')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--to', default='hub')
    parser.add_argument('--restore', metavar='FOLDER')
    args = parser.parse_args()
    if args.restore:
        restore(Path(args.restore))
    else:
        export(Path(args.to))
hub/README.md手入力する完全なソース

モデルカードです。いちばん上の --- の行のあいだにある YAML は Hugging Face が読む情報(ライセンス・言語・タグ・タスクの種類)で、その下は人が読む説明です。YOUR_ID を自分のユーザー名に置きかえ、データを変えたならパラメーター数と学習データの説明も自分のものに直してください。

---
license: mit
language:
- en
tags:
- xslm
- tiny
- educational
pipeline_tag: text-generation
---

# XSLM tiny

A 1,248-parameter GPT that I typed from scratch and trained
inside my web browser, following https://sonub.com/ai/build

## Files

- model.safetensors: trained weights (float32)
- config.json: size and sampling settings
- tokenizer.json: character BPE vocabulary and merge rules
- engine.py, model.py, tokenizer.py, generate.py: the model code
- runner.py, xchat.py: HTTP Runner and terminal chat
- export.py: writes these files, and turns them back into a checkpoint

## How to run

Python 3 only. Nothing to install.

    git clone https://huggingface.co/YOUR_ID/xslm-tiny
    cd xslm-tiny
    python3 export.py --restore .
    python3 generate.py

## Training data

15 short English Q/A lines written for the course
(12 for training, 3 for validation).

## Limitations

For learning only. With 1,248 parameters and a few training
steps, the answers are mostly random. Do not use it for real work.

コードを1行ずつ読み解く

export.py SOURCES — いっしょに上げる実行コード

import argparse
import json
import shutil
import struct
from pathlib import Path

SOURCES = ['engine.py', 'model.py', 'tokenizer.py', 'generate.py',
           'runner.py', 'xchat.py', 'export.py']

struct は数をバイトに変えたり戻したりするで、shutil はファイルをコピーします。SOURCES はモデルを実行するのに必要なソースファイルの一覧です。学習にしか使わない prepare.py・train.py は入れません。

export.py write_safetensors — 数をファイルに

def write_safetensors(path, weights):
    header, body = {'__metadata__': {'format': 'xslm'}}, b''
    for name, matrix in weights.items():
        rows, cols = len(matrix), len(matrix[0])
        data = struct.pack('<%df' % (rows * cols),
                           *[v for row in matrix for v in row])
        header[name] = {'dtype': 'F32', 'shape': [rows, cols],
                        'data_offsets': [len(body), len(body) + len(data)]}
        body += data
    head = json.dumps(header).encode('utf-8')
    head += b' ' * (-len(head) % 8)
    path.write_bytes(struct.pack('<Q', len(head)) + head + body)

層ごとにを1列に広げ、struct.pack でバイトに変えます。形式 <%df では、< は little-endian、f は4バイトの float32 で、%d の場所に数の個数が入ります。ヘッダーには、この層の dtype・shape と、本体の中の開始・終了位置を書きます。JSON ヘッダーの長さを8の倍数にそろえるために空白を足し、いちばん前にその長さを8バイト(<Q)で書きます。

export.py read_safetensors — ファイルを数に

def read_safetensors(path):
    raw = path.read_bytes()
    size = struct.unpack('<Q', raw[:8])[0]
    header = json.loads(raw[8:8 + size])
    body, weights = raw[8 + size:], {}
    for name, info in header.items():
        if name == '__metadata__':
            continue
        assert info['dtype'] == 'F32', 'only float32'
        rows, cols = info['shape']
        start, end = info['data_offsets']
        flat = struct.unpack('<%df' % (rows * cols), body[start:end])
        weights[name] = [list(flat[r * cols:(r + 1) * cols])
                         for r in range(rows)]
    return weights

書くときの逆です。最初の8バイトでヘッダーの長さを読み、その長さの分を JSON として読みます。__metadata__ は層ではないので飛ばします。data_offsets で本体からその層のバイトだけを切り出し、struct.unpack で数を取り出して、cols 個ずつ区切って行列に戻します。

export.py export — hub フォルダーを作る

def export(folder):
    saved = json.loads(Path('checkpoints/model.json').read_text())
    folder.mkdir(exist_ok=True)
    write_safetensors(folder / 'model.safetensors', saved['weights'])
    config = {'model_type': 'xslm', 'vocab_size': len(saved['tokenizer']['vocab']),
              'step': saved['step'], 'settings': saved['settings']}
    (folder / 'config.json').write_text(json.dumps(config, indent=2))
    (folder / 'tokenizer.json').write_text(
        json.dumps(saved['tokenizer'], ensure_ascii=False), encoding='utf-8')
    for name in SOURCES:
        shutil.copy(name, folder / name)

学習で保存した checkpoints/model.json を読みます。重みは safetensors に、大きさ・設定・学習ステップ数は config.json に、語彙とマージ規則は tokenizer.json に書きます。ensure_ascii=False なので、日本語のような文字もそのまま保存されます。最後に SOURCES を hub にコピーします。

export.py 確認 — もう一度読んで差を測る

    loaded = read_safetensors(folder / 'model.safetensors')
    gap = max(abs(a - b) for name in loaded
              for row, old in zip(loaded[name], saved['weights'][name])
              for a, b in zip(row, old))
    count = sum(len(row) for matrix in loaded.values() for row in matrix)
    print('parameters:', count, 'bytes:', (folder / 'model.safetensors').stat().st_size)
    print('largest float32 gap:', '%.1e' % gap)
    print('exported:', folder)

いま書いたファイルを read_safetensors でもう一度読み、元の数といちばん大きく違う値を探します。float32 に縮めたことによる差なので、1e-8 くらいなら正常です。パラメーター数とファイルの大きさも表示して、hub が正しくできたかを見ます。

export.py restore — ダウンロードしたファイルをチェックポイントに

def restore(folder):
    config = json.loads((folder / 'config.json').read_text())
    state = {'settings': config['settings'],
             'tokenizer': json.loads((folder / 'tokenizer.json').read_text(encoding='utf-8')),
             'weights': read_safetensors(folder / 'model.safetensors')}
    Path('checkpoints').mkdir(exist_ok=True)
    Path('checkpoints/model.json').write_text(
        json.dumps(state, ensure_ascii=False), encoding='utf-8')
    print('restored: checkpoints/model.json')

config.json の設定、tokenizer.json、safetensors の重みを集め、generate.py の load が読む形そのままで checkpoints/model.json を作ります。だから generate.py・runner.py・xchat.py を1行も直さずに、ダウンロードしたモデルを動かせます。

export.py コマンドライン — 書き出しと作り直し

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--to', default='hub')
    parser.add_argument('--restore', metavar='FOLDER')
    args = parser.parse_args()
    if args.restore:
        restore(Path(args.restore))
    else:
        export(Path(args.to))

引数がなければ hub に書き出し、--to で別のフォルダーを指定できます。--restore にフォルダーを渡すと、そのフォルダーのファイルからチェックポイントを作り直します。ダウンロードしたリポジトリの中では、python3 export.py --restore . のように点(いまのフォルダー)を渡します。

理解を確認

huggingface.co/YOUR_ID/xslm-tiny を開いてみましょう。最初の画面にモデルカードが出ていて、Files タブの model.safetensors に LFS の印がありますか? 別のフォルダーに git clone してから python3 export.py --restore . と python3 generate.py を実行し、このターミナルと同じ答えが出れば公開は完成です。

困ったとき

git push が binary files のせいで断られたら、git lfs install を飛ばしています。 hub でフォルダーを消し、git lfs install からやり直してください。 failed は、パスワードを入れたか、Read 権限だけのトークンを使ったときに出ます。ページを再読み込みすると hub の .git が消えるので、そのときも rm -rf hub のあと git clone と python3 export.py をもう一度実行します。全部上げ終わったら、Access Tokens でトークンを消してもかまいません。

よくある質問

リポジトリを非公開(Private)にしてもいいですか?

はい、できます。Private リポジトリは、自分と自分が許した人だけが見られます。上げる手順は同じで、ダウンロードするときにもトークンが必要になる点だけが違います。確かめ終わったら、リポジトリの Settings で Public に変えられます。

上げたモデルを直したり消したりするには、どうすればいいですか?

直すには、もう一度学習して python3 export.py を実行し、hub で git add・commit・push します。新しいコミットが積み重なり、前のバージョンも履歴に残ります。消すには、リポジトリの Settings のいちばん下にある削除(Delete)ボタンを押します。消したリポジトリは元に戻せません。

transformers ライブラリで読みこめますか?

そのままではできません。 は ・ のように登録された構造しか読めませんが、XSLM は層の組み立てと文字単位のトークナイザーが違います。だから実行コードもいっしょに上げ、export.py --restore で自分たちのコードで動かします。safetensors ファイルそのものは標準の形式なので、safetensors で開いて の配列として読めます。

ガイドライン

人工知能

エージェントツール

バイブコーディング

AI活用

AI資格

AI授業

IT基礎

チャット

掲示板

制作

コミュニティ

その他

用語辞典

知らない言葉を選んでみましょう。やさしい説明と関連用語が見られます。

その用語はまだありません。

用語を選ぶと説明が表示されます。