**MicroGPT(マイクロ GPT)**

2026/03/01 10:39

**MicroGPT(マイクロ GPT)**

RSS: https://news.ycombinator.com/rss

要約

日本語訳:

MicroGPTは、外部ライブラリを一切使用せずにトレーニングおよび実行できる、コンパクトな純粋Python実装のGPTスタイル言語モデルです。コード量は約200行で、自前の

Value
クラスに基づく自動微分システム(スカラー逆伝播用の操作記録:加算、乗算、べき乗、対数、指数、ReLUなど)、トークナイズ処理、およびトレーニングループを含みます。

モデルはGPT‑2アーキテクチャに従いますが、以下のような簡略化が施されています:RMSNorm(バイアスなし)、ReLU活性化、小規模MLP出力ヘッド。パラメータ数は約4 192で、

state_dict
に格納されます。これには埋め込みテーブル(
wte
wpe
)、注意重み(
attn_wq/k/v/wo
)、MLP重み(
mlp_fc1/2
)、および出力射影(
lm_head
)が含まれます。注意はトークンを一つずつ処理し、位置間でキー/バリューキャッシュを維持します。

トレーニングでは、GitHubからダウンロードした約32 000件の名前(1行に1件)のデータセットを使用します。各名前はBOSトークンで両端が囲まれた「文書」として扱われ、語彙数は27トークン(小文字26字+BOS)になります。トレーニングループは1 000ステップ実行されます。各ステップでは単一の文書をトークナイズし、順次モデルに渡し、位置ごとのクロスエントロピー損失を計算します。その後シーケンス全体で平均化し、

loss.backward()
で逆伝播を行い、Adam(線形学習率減衰)でパラメータ更新します。損失は毎ステップ表示され、初期値は約3.36(ランダム)からトレーニング後に約2.37まで低下し、モデルが名前のパターンを学習したことを示しています。

トレーニング完了後、推論ではBOSから開始し、ロジットを繰り返し生成し、温度スケーリング済みソフトマックスでサンプリングします。別のBOSが出るか最大長に達するまでトークンを取得し、新しい名前をサンプルします。著者は段階的に機能を追加したスクリプト(

train0.py
train5.py
)を公開しており、システムの進化を示しています。

MicroGPTは教育ツールとして、またGPUや重い依存関係なしでCPU上で変圧器メカニクスを実験するための低リソース代替手段として機能します。さらに、スケーリング、バッチング、混合精度、および専用ハードウェアが大規模言語モデルでパフォーマンス向上にどのように寄与できるかを示しています。

本文

microgpt – 純粋Pythonで実装した200行程度のシングルファイルGPT


概要

microgpt.py
には 学習推論 に必要なアルゴリズムコンポーネントがすべて収録されています。

  • データセット読み込み
  • キャラクタトークナイザー
  • スカラー自動微分 (
    Value
    )
  • 埋め込み + マルチヘッド注意機構 + MLP ブロック(RMSNorm, ReLU)
  • 線形学習率減衰付き Adam オプティマイザ
  • 交差エントロピー損失を用いたトレーニングループ
  • 温度サンプリングによる推論ループ

外部ライブラリは一切不要で、Python 標準ライブラリだけで動作します。


1. データセット

if not os.path.exists('input.txt'):
    import urllib.request
    names_url = 'https://raw.githubusercontent.com/karpathy/makemore/master/names.txt'
    urllib.request.urlretrieve(names_url, 'input.txt')

docs = [l.strip() for l in open('input.txt').read().strip().split('\n') if l.strip()]
random.shuffle(docs)
print(f"num docs: {len(docs)}")

32 k 程度の名前(1行に1つ)がデータセットです。
各名前が学習時の「ドキュメント」として扱われます。


2. トークナイザー

uchars = sorted(set(''.join(docs)))          # ユニーク文字列
BOS    = len(uchars)                         # BOS(Beginning‑of‑Sequence)トークンID
vocab_size = len(uchars) + 1                 # +1 は BOS 用
print(f"vocab size: {vocab_size}")
  • 各文字を整数 ID にマッピング
  • BOS
    はドキュメントの区切りに使われます。

3. 自動微分 (
Value
)

class Value:
    __slots__ = ('data', 'grad', '_children', '_local_grads')

    def __init__(self, data, children=(), local_grads=()):
        self.data = data; self.grad = 0
        self._children   = children
        self._local_grads = local_grads

    # 算術演算 -------------------------------------------------------------
    def __add__(self, other):
        other = other if isinstance(other, Value) else Value(other)
        return Value(self.data + other.data, (self, other), (1, 1))

    def __mul__(self, other):
        other = other if isinstance(other, Value) else Value(other)
        return Value(self.data * other.data,
                     (self, other),
                     (other.data, self.data))
    # … plus pow, log, exp, relu, neg, radd, sub など …

    def backward(self):
        topo = []; visited = set()
        def build(v):
            if v not in visited:
                visited.add(v)
                for c in v._children: build(c)
                topo.append(v)
        build(self)

        self.grad = 1
        for v in reversed(topo):
            for child, local_grad in zip(v._children, v._local_grads):
                child.grad += local_grad * v.grad

すべての演算は新しい

Value
を生成し、親ノードと局所勾配を記録します。
backward()
は逆順トップロジカルに走査して勾配を集計します。


4. パラメータ

n_embd    = 16      # 埋め込み次元
n_head    = 4       # 注意ヘッド数
n_layer   = 1       # 層数
block_size= 16      # 最大シーケンス長
head_dim  = n_embd // n_head

def matrix(nout, nin, std=0.08):
    return [[Value(random.gauss(0, std)) for _ in range(nin)]
            for _ in range(nout)]

state_dict = {
    'wte': matrix(vocab_size, n_embd),
    'wpe': matrix(block_size, n_embd),
    'lm_head': matrix(vocab_size, n_embd)
}
for i in range(n_layer):
    state_dict[f'layer{i}.attn_wq'] = matrix(n_embd, n_embd)
    state_dict[f'layer{i}.attn_wk'] = matrix(n_embd, n_embd)
    state_dict[f'layer{i}.attn_wv'] = matrix(n_embd, n_embd)
    state_dict[f'layer{i}.attn_wo'] = matrix(n_embd, n_embd)
    state_dict[f'layer{i}.mlp_fc1'] = matrix(4*n_embd, n_embd)
    state_dict[f'layer{i}.mlp_fc2'] = matrix(n_embd, 4*n_embd)

params = [p for mat in state_dict.values()
          for row in mat for p in row]
print(f"num params: {len(params)}")

総パラメータ数は約 4 192 個です。


5. ヘルパー関数

def linear(x, w):
    return [sum(wi * xi for wi, xi in zip(wo, x)) for wo in w]

def softmax(logits):
    max_val = max(v.data for v in logits)
    exps   = [(v - max_val).exp() for v in logits]
    total  = sum(exps)
    return [e / total for e in exps]

def rmsnorm(x):
    ms     = sum(v * v for v in x) / len(x)
    scale  = (ms + 1e-5)**-0.5
    return [v * scale for v in x]

6. モデル (
gpt
)

def gpt(token_id, pos_id, keys, values):
    tok_emb = state_dict['wte'][token_id]          # トークン埋め込み
    pos_emb = state_dict['wpe'][pos_id]           # 位置埋め込み
    x       = [t + p for t, p in zip(tok_emb, pos_emb)]
    x       = rmsnorm(x)

    for li in range(n_layer):
        # ---------- 注意 ----------
        x_residual = x
        x          = rmsnorm(x)
        q = linear(x, state_dict[f'layer{li}.attn_wq'])
        k = linear(x, state_dict[f'layer{li}.attn_wk'])
        v = linear(x, state_dict[f'layer{li}.attn_wv'])
        keys[li].append(k);  values[li].append(v)

        x_attn = []
        for h in range(n_head):
            hs    = h * head_dim
            q_h   = q[hs:hs+head_dim]
            k_h   = [ki[hs:hs+head_dim] for ki in keys[li]]
            v_h   = [vi[hs:hs+head_dim] for vi in values[li]]

            attn_logits = [
                sum(q_h[j]*k_h[t][j] for j in range(head_dim)) / head_dim**0.5
                for t in range(len(k_h))
            ]
            attn_weights = softmax(attn_logits)
            head_out = [sum(attn_weights[t]*v_h[t][j]
                            for t in range(len(v_h))) for j in range(head_dim)]
            x_attn.extend(head_out)

        x   = linear(x_attn, state_dict[f'layer{li}.attn_wo'])
        x   = [a + b for a, b in zip(x, x_residual)]

        # ---------- MLP ----------
        x_residual = x
        x          = rmsnorm(x)
        x          = linear(x, state_dict[f'layer{li}.mlp_fc1'])
        x          = [v.relu() for v in x]
        x          = linear(x, state_dict[f'layer{li}.mlp_fc2'])
        x          = [a + b for a, b in zip(x, x_residual)]

    logits = linear(x, state_dict['lm_head'])
    return logits

この関数は 1 トークンずつ 処理し、KV キャッシュ(

keys
,
values
)を保持して各位置が過去全てに注意できるようにしています。


7. 学習ループ

learning_rate, beta1, beta2, eps_adam = 0.01, 0.85, 0.99, 1e-8
m = [0.0] * len(params)   # 一次モーメントバッファ
v = [0.0] * len(params)   # 二次モーメントバッファ

num_steps = 1000
for step in range(num_steps):
    doc      = docs[step % len(docs)]
    tokens   = [BOS] + [uchars.index(ch) for ch in doc] + [BOS]
    n        = min(block_size, len(tokens)-1)

    keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)]
    losses      = []
    for pos_id in range(n):
        token_id, target_id = tokens[pos_id], tokens[pos_id+1]
        logits   = gpt(token_id, pos_id, keys, values)
        probs    = softmax(logits)
        loss_t   = -probs[target_id].log()
        losses.append(loss_t)

    loss = (1/n) * sum(losses)     # 平均交差エントロピー
    loss.backward()

    lr_t = learning_rate * (1 - step / num_steps)
    for i, p in enumerate(params):
        m[i] = beta1 * m[i] + (1-beta1) * p.grad
        v[i] = beta2 * v[i] + (1-beta2) * p.grad**2
        m_hat = m[i] / (1 - beta1**(step+1))
        v_hat = v[i] / (1 - beta2**(step+1))
        p.data -= lr_t * m_hat / (v_hat**0.5 + eps_adam)
        p.grad = 0

    print(f"step {step+1:4d} / {num_steps:4d} | loss {loss.data:.4f}")
  • 損失:次のトークンを予測する交差エントロピー
  • オプティマイザ:Adam + 線形学習率減衰

8. 推論(サンプリング)

temperature = 0.5          # 小さいほど決定的に近い
print("\n--- inference (new, hallucinated names) ---")
for sample_idx in range(20):
    keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)]
    token_id     = BOS
    sample       = []

    for pos_id in range(block_size):
        logits   = gpt(token_id, pos_id, keys, values)
        probs    = softmax([l / temperature for l in logits])
        token_id = random.choices(range(vocab_size),
                                  weights=[p.data for p in probs])[0]
        if token_id == BOS: break
        sample.append(uchars[token_id])

    print(f"sample {sample_idx+1:2d}: {''.join(sample)}")

BOS
から始めて次トークンをサンプルし、再度入力に戻すことで名前を生成します。
新しい
BOS
が出るかブロックサイズに達すると停止します。


9. 実行

python train.py          # ラップトップで約1分程度で学習完了

典型的な出力例:

num docs: 32033
vocab size: 27
num params: 4192
step    1 / 1000 | loss 3.3660
...
step 1000 / 1000 | loss 2.3705

--- inference (new, hallucinated names) ---
sample  1: kamon
sample  2: ann
...
sample 20: anton

10. コードベースの進化

ファイル追加内容
train0.pyバイグラムカウント(NN・勾配なし)
train1.pyMLP + 手動勾配 + SGD
train2.py自動微分 (
Value
)
train3.py位置埋め込み + 単一ヘッド注意 + RMSNorm + 残差
train4.pyマルチヘッド注意 + 層ループ(完全 GPT)
train5.pyAdam オプティマイザ – 現在の
train.py

各ステップは前段階を基に拡張され、コードは読みやすくロジックも明確です。


11. 本番 LLM と比べて欠けている点

  • データ:32 k 名 vs. 数兆トークンのウェブページ
  • トークナイザー:単文字 vs. BPE(約10万語彙)
  • 自動微分:Python のスカラー
    Value
    vs. GPU/TPU 上のテンソル演算
  • モデルサイズ:4 k パラメータ vs. 数百億パラメータ
  • 学習:1 ドキュメント / ステップ、バッチ小、混合精度なし、勾配集約なし
  • 最適化:単純 Adam vs. 大規模スケジュール・重み減衰・ウォームアップ等
  • 推論:ピュア Python ループ vs. GPU カーネル、KV キャッシュページング、スペキュレーティブデコーディング、量子化

これらのギャップがあるものの、**「次トークンを予測し、サンプルして繰り返す」**という本質は ChatGPT などと同一です。


12. よくある質問(簡潔版)

質問回答
モデルは「理解」できる?いいえ、確率分布を学習するだけです。
なぜ動くのか?勾配が損失を減らす方向へパラメータを更新し、統計的パターンを捉えるから。
ChatGPT とどう関係ある?同じ次トークンループですが、スケールとポストトレーニング(SFT/RLHF)が異なるだけです。
生成物は「幻覚」か?確率分布からサンプルするため、存在しない名前を作り出すことがあります。
なぜ遅いのか?スカラー Python 演算は GPU テンソル演算に比べ何百万倍も遅いです。
名前生成を改善できる?学習時間を伸ばす、モデルを大きくする、データセットを増やすなどで可能です。
データを変えても動くのか?はい。コードは同じままで新しいパターンを学びます。

ぜひ実験してみてください!
ハイパーパラメータを変更したり、データセットを差し替えたり、アーキテクチャを拡張したりすることで、自分だけの小さな GPT を作ることができます。すべては

microgpt.py
に自前で収められています。

同じ日のほかのニュース

一覧に戻る →

2026/02/25 5:08

**誰とでも上手に話す方法 – なぜそれが重要なのか** 1. **本物の笑顔から始める** - 温かい表情はオープンさを示し、相手に安心感を与えます。 2. **開放的な質問を投げかける** - 「いい一日だった?」ではなく「今週で特に印象に残ったことは何ですか?」と尋ねると、より深い対話が生まれます。 - 開放的な質問は会話の幅を広げます。 3. **積極的に聴く** - 頭を縦に振り、目線を合わせ、相手の言葉をパラフレーズすることで関心を示します。 4. **共通点を見つける** - 共有できる趣味や経験は瞬時に信頼感を生み出します。 5. **名前を使う** - 会話の中で相手の名前を数回繰り返すと、結び付きを強めます。 6. **身振りをリラックスさせる** - 腕を組むことは避け、少し前かがみになることで関心を示します。 7. **自分のことも少し語る** - 脆弱性を共有することで相互理解と信頼が育まれます。 8. **ポジティブに締めくくる** - 交流を明るい雰囲気で終えると、次回の接触につながります。 --- ### このスキルを習得すべき理由 - **より強固な関係を築ける** – 個人的・職業的な場面問わず、良好なコミュニケーションは絆を深めます。 - **ネットワーキングの機会が広がる** – 聴き手として真摯に関わる人は記憶に残ります。 - **自信が高まる** – 会話をスムーズに進められると、社交不安が軽減します。 - **チームワークが向上する** – 明確で敬意のある対話は協力を円滑にします。 - **影響力が拡大される** – 上手な会話術を持つ人は、説得・リーダーシップが自然と発揮できます。 誰とでも上手に話す技術を身につければ、より豊かな人間関係、広がる機会、そしてあらゆる社会的場面で自信ある存在感へとつながります。

## Japanese Translation: 記事は、日常的な公共の会話が消えつつあると主張し、その崩壊が社会的絆や個人の幸福を脅かすと警告しています。まず、70代の女性が空席の電車内で対話を始めるという鮮烈な逸話と、ソウル出身のウェイトレスがレストランで見知らぬ客と会話をするエピソードを紹介し、まだ存在する「無言のコード」がどのように人々をつなげているかを示しています。著者はテクノロジー(タッチスクリーンやリモートワーク)、パンデミックによる制限、そして強化された社会規範がこのコードを締め付け、「グローバル・レラショナル・リセッション」(Esther Perel が呼ぶ)を招いていると考察しています。 個人的な障壁としては、神経多様性、内向性、目線の不快感、小談嫌いなどが挙げられ、専門家の警告も併せて紹介されます。Dr. Jared Cooney Horvath は Gen Z の認知遅延を指摘し、Dr. Rangan Chatterjee は低自尊心と子どもの会話スキルの低下との関連性を示唆しています。ソーシャルメディアでの実験(例:「見知らぬ人と話す」動画)はパフォーマンス化し、疎外感を高めると批判されています。 研究は恐怖論に対抗します。バージニア大学の調査では、人々が見知らぬ人と話すことへの不安を過大評価していると示され、実際には短時間の交流を期待以上に楽しむケースが多いと報告されています。スタンフォード大学/Prof. Jamil Zaki の研究は、学生が「許可」と「アプローチしやすさ」のリマインダーを必要としており、疲労や失望の恐れは誇張されていることを付け加えています。 トレンドを逆転させるために記事では低リスク戦術を提案しています:人間味のある行動、社会的合図の読み取り、「ノー・ジム・フリー」カードの提供、そして日常的な小談の奨励。習慣を失うと社会分断が深まり、回復すればメンタルヘルス、職場チームワーク、コミュニティ結束が向上する可能性があります。読者に対し、衰退が不可逆的になる前に今すぐ会話を始めるよう促しています。 ## Text to translate ** The article argues that casual public conversation is vanishing—an erosion that threatens social bonds and personal well‑being. It begins with two vivid anecdotes: a woman in her 70s striking up dialogue on an empty train carriage, and a waitress from Seoul engaging a stranger at a restaurant, illustrating the everyday “unwritten code” that still allows strangers to talk. The author reflects on how technology (touchscreens, remote work), pandemic restrictions, and reinforced social norms have tightened this code, leading to what Esther Perel calls a *global relational recession*. Personal barriers are highlighted—neurodivergence, introversion, eye‑contact intolerance, and small‑talk aversion—alongside expert warnings: Dr. Jared Cooney Horvath notes Gen Z’s cognitive lag, while Dr. Rangan Chatterjee links low self‑worth to poor conversational skills in children. Social‑media experiments (e.g., “talking to strangers” videos) are critiqued for being performative and alienating. Research counters the fear narrative: a University of Virginia study shows people overestimate their anxiety about talking to strangers; most actually enjoy brief interactions more than expected. A Stanford/Prof. Jamil Zaki study adds that students need permission and reminders of approachability, and fears of exhaustion or disappointment are exaggerated. To reverse the trend, the article suggests low‑stakes tactics: humanising acts, reading social cues, giving “get‑out‑of‑jail‑free” cards, and encouraging everyday small talk. Losing this habit could deepen societal division; restoring it can improve mental health, workplace teamwork, and community cohesion. The piece urges readers to start conversations now—before the decline becomes irreversible.

2026/03/02 6:33

量子力学の謎は、解明し始めているのでしょうか?

## Japanese Translation: ## 要約 ウオイチェフ・ズレク(Wojciech Zurek)の2025年の著書『Decoherence and Quantum Darwinism』は、**環境との普遍的な絡み合いによる量子コヒーレンスの急速な喪失であるデコヒーレンスと、新たに提唱された「Quantum Darwinism」という概念が組み合わさることで、推測的な仮説や崩壊メカニズムを導入せずに、量子力学から古典的現実がどのように生まれるかを説明する**と提案している。 - **仕組み:** デコヒーレンスは極めて短い時間スケール(例:塵粒であれば \(10^{-31}\) s)で起こり、重ね合わせ状態が多数の環境自由度に拡散する。これらの重ね合わせは実質的に観測不可能になる一方で、位置や電荷といった**ポインタ状態**(pointer states)は残存し、環境へ繰り返し写像される。 - **Quantum Darwinism:** こうした安定記録の拡散は自然選択に例えられ、最も頑強なポインタ状態が客観的に実在するとみなされる。これは多様な環境断片から多数の観測者がアクセスできるためである。例えば、太陽光子が塵粒の位置をマイクロ秒単位で約 \(10^7\) 回写像する実験は、システムに関する情報のほとんどが少数のコピーから取得可能であり、急速に飽和することを確認している。 - **解釈的バランス:** ズレクの枠組みは、認識論(コペンハーゲン)と実在論(多世界)の両方を調整し、デコヒーレンス以前の状態を「エピオニック」可能性として扱い、デコヒーレンス後にのみ観測可能になるとする。著書は標準量子力学内で測定問題を再構成し、追加的な仮説や実体論的存在を導入しない。 - **批評と称賛:** サリー・シュラプネル(Sally Shrapnel)は古典的現象の説明の優雅さを賞賛するが、デコヒーレンス以前の「量子基底」の性質は未だ不明である点に触れている。レナート・レンナー(Renato Renner)はQuantum Darwinism でも観測者間で結果に合意できないシナリオが存在し、解釈上の問題が残ると指摘している。 - **未解決課題:** 任意の測定でどのように特定の結果が選択されるか、量子―古典境界が正確にどこにあるか、およびより厳密な検証を設計する方法など、依然として課題が残っている。 ズレクの総合的見解は、偶発的な崩壊メカニズムを用いずに量子確率からユニークな古典世界がどのように現れるかについて、完全で検証可能な説明を提供している。

2026/03/02 6:56

ビッグブレックファーストが食欲と腸内環境を変える

## Japanese Translation: **要約** 28日間の無作為化試験では、19名の肥満成人を対象に、高繊維(HFWL)と高タンパク質(HPWL)の2種類の朝食が体重減少と腸内環境に与える影響を調査しました。すべての食事は提供され、両方のダイエットでカロリーは朝45%、午後35%、夕方20%に分配されました。HFWLを摂取した参加者は平均-4.87 kgとHPWLよりも多く体重が減少しました(-3.87 kg)。高繊維朝食は、ビフィドバクテリア、ファーセリカチュラ・レイボルジアなどの有益な腸内細菌へシフトし、すべてブチル酸生成菌でした。一方、高タンパク質朝食は一日を通じて主観的な空腹感をより効果的に抑制しました。これらの結果は、朝食の構成がカロリー制限下での満足感と腸内微生物叢に影響を与えることを示しています

**MicroGPT(マイクロ GPT)** | そっか~ニュース