Show HN:Microcrad - Micrograd の C ライブラリでの再実装

2026/06/17 22:34

Show HN:Microcrad - Micrograd の C ライブラリでの再実装

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

要約

Japanese Translation:

Microcrad は、神経ネットワークが基本的なレベルでどのように機能するかを教えるための自動微分用の教育用 C エンジンです。Andrej Karpathy の有名な

micrograd
プロジェクトの再実装であり、ベクトルや GPU を使用せずスカラー
double
値のみを取り扱うことで、パフォーマンスよりも可読性を最優先としています。その主たる強みは、計算グラフや誤差逆伝播といった基本概念を、背後にある数学を隠さずに教えることにあります。

このエンジンは、

Value
構造体上の参照カウントによってメモリを直接管理します。各
Value
は単一の数をラップし、ポインタ (
prev
) を介して演算子を保存することでグラフのトポロジを定義し、操作コード(例:
add
,
mul
,
relu
など)と勾配を累積するためのフィールド (
grad
) を持っています。モデルを学習させるためには、チェーン規則を適用する必要があり、そのために深さ優先のトポロジカルソートに続いて逆向きのウォークを行います。重要な点として、新しいデータバッチごとにトレーニング可能のパラメータに対して勾配蓄積器を手動でリセット(0.0 に設定)しなければならず、計算エラーを防ぐ必要があります。神経ネットワークのアーキテクチャは
Neuron
Layer
、および
MLP
構造体から構成されており、特に出力層を含めすべてのニューロンが ReLU アクティベーションを適用するため、出力は常に非負となります。

今後の利用としては、特定のテストスイート(例:

test_value
,
test_mlp
)を実行し、単純な回帰例から MNIST データセットのデモのようなより複雑なタスクへと進んでいきます。そのアーキテクチャを学ぶことで、開発者は黒箱ツールによってしばしば隠蔽されがちなフラットな重みリスト上の勾配降下のメカニズム、グラフのトラベル、ならびにメモリ管理(
value_retain
/
value_release
)について透明性の高い理解を得ることができます。

本文

microcrad: スカラー自動微分エンジンとニューラルネットワークの実装

microcrad は、C 言語向けの小さなスカラー値を扱う自動微分エンジンであり、その上に構築された軽量なニューラルネットワークの実装を備えています。これは Andrej Karpathy 氏の「micrograd」の C 言語への再実装です。Python のオリジナルと同様に、テンソルではなくスカラーに基づいて動作します。

計算に携わるすべての数はグラフ上のノードとして扱われ、各操作が生成方法を記録(計算グラフ)します。その後方伝播パスでは、単一のパスで逆方向にグラフを走行し、出力に関する各入力への微分係数を計算します。ベクトル化や GPU は一切使用せず、スカラー単位で連鎖律を適用するだけです。

このエンジンの上には多層感知器(MLP)が構築されており、C 言語だけでネットワークの構築・順伝播・後方伝播・勾配降下法を実現できます。本リポジトリは主に教育目的の実装であり、生産環境向けの最適化や大規模データセットへの対応を最優先していません。


基本的な設計概念

全体は以下の二つの概念を中心に構築されています:

  • Value:計算グラフ上の単一のノードを表します。
  • 参照カウント(Reference counting)
    Value
    のグラフから完全に外れたタイミングを知るための仕組みです。リソース解放を管理するために利用されます。

Value の仕組みについて

基本型は

Value
です。「葉(leaf)」の
Value
(入力、重み、定数)では
n_prevs == 0
で、オペランドを持たない一方、演算によって生成された
Value
では依存するオペランドへのポインタを持つ
prev
アレイを有します。

Value の構造体定義

typedef struct Value {
    uint32_t ref_count;   /* この Value を参照するポインターの数 */
    uint32_t n_prevs;     /* この Value を生成したオペランドの数 */
    double data;          /* このノードが保持するスカラー値 */
    double extra_data;    /* 演算のパラメータ(例:pow の指数)*/
    struct Value **prev;  /* オペランド(グラフ上の前のノード群)*/
    int32_t op_code;      /* この Value を生成した演算の種類 */
    uint32_t magic;       /* デバッグ用キャニワリ(無効ポインタ検出のため)*/
    double grad;          /* dLoss/dThisValue(backward で埋め込む値)*/
} Value;

これにより、計算グラフ(有向非巡回グラフ:DAG)が形成されます。何かを計算しその勾配を求める最小限の microcrad プログラムは以下の通りです:

Value *a = value_create_leaf(2.0);
Value *b = value_create_leaf(3.0);
Value *c = value_mul(a, b);   /* c = a * b = 6 */

value_backward(c);            /* 成功なら 0 を返すか、全ての grad フィールドを埋める */

printf("c    = %f\n", c->data);   /* 6.000000 */
printf("dc/da= %f\n", a->grad);   /* 3.000000  (== b) */
printf("dc/db= %f\n", b->grad);   /* 2.000000  (== a) */

value_release(c);             /* c を解放;a と b に対する保持も解放 */
value_release(a);             /* a を解放(もう一つの参照はあなたのものでした)*/
value_release(b);             /* b を解放                                     */

Value の作成方法

主要なコンストラクターは以下の通りです:

  • Value *value_create(double data, int32_t n_prevs, Value **prev);
  • Value *value_create_leaf(double data);

value_create_leaf
は、入力、重み、バイアス、定数である「葉」ノードのための簡易コンストラクターです。ユーザーコードは基本的にこちらを呼び出し、演算自体への接続作業を関数に任せるのが望ましいでしょう。

新規作成された

Value
は参照カウントが 1 で始まります(戻されるポインター自体が一つの参照)。これを解放するのはあなたの責任となります。

演算子(Operations)

以下の関数は新しい

Value
を返し、その
data
は演算結果、
prev
アレイはオペランドを指します。

関数説明
value_add(v1, v2)
v1 + v2
value_mul(v1, v2)
v1 * v2
value_pow(b, e)
b ** e
(定数の指数のみサポート)
value_exp(v)
e ** v
value_log(v)
\ln(v)
value_relu(v)
\max(0, v)

※引数は非 NULL ポインターを期待します。堅牢性よりも学習パスの明確さを優先しています。

参照カウントに関する注意点: 演算関数はオペランドの参照カウントを増やし、結果ノードが必要とする間オペランドを維持します。しかし、呼び出し前にはもともと保持していた参照をあなたが依然として保有し、解放する責任があります(共有所有関係)。

Value *a = value_create_leaf(2.0);   /* a: ref_count 1 (あなたの所有) */
Value *b = value_create_leaf(3.0);   /* b: ref_count 1 (あなたの所有) */
Value *c = value_add(a, b);            /* a,b は現在 ref_count 2; c は ref_count 1 */

/* ... c を使用する間 ... */

value_release(c);   /* c を解放;a と b に対する保持も解放 */
value_release(a);   /* a を解放(もう一つの参照はあなたの所有でした)    */
value_release(b);   /* b を解放                                     */

※注記:引き算や除算は独立した演算ではありません。それぞれ符号反转された加算または逆数との乗算として実装されます。


後方伝播(Backpropagation)

int value_backward(Value *v);

value_backward
は、引数
v
が依存するすべてのノードに対するその勾配を計算し、それぞれの結果をノードの
grad
フィールドに格納します。動作は以下の 2 ステップです:

  1. グラフ全体(
    v
    を根として)に対して、**深さ優先順序(Topological Sort)**を実行します。共有ノードを二度訪問しないように注意しています。
  2. v->grad = 1
    で種付けを行い、ソートされたリストを逆順に歩き回り、各ノードについて連鎖律に従って勾配をオペランドへ伝播させます。

成功時は 0 を、失敗時は -1 を返します。

重要な前提条件

  • v
    は非 NULL で、有効な計算グラフのルートであることを指さしている必要があります。
  • ループ内で学習を行う場合は、呼び出す前に蓄積させたくない勾配をゼロ化する必要があります。
  • 勾配はオペランドに対して**累加(
    +=
    )**されるため、複数の場所で使用された
    Value
    は各パスからの勾配を正しく受けます。
// 学習ループ内の処理例
for (size_t i = 0; i < parameters->size; i++)
    vector_get(parameters, i)->grad = 0.0;   /* 勾配をゼロにする */

value_backward(loss);                        /* 新しいものを蓄積する */

for (size_t i = 0; i < parameters->size; i++) {
    Value *p = vector_get(parameters, i);
    p->data -= learning_rate * p->grad;      /* 勾配降下法のステップ */
}

メモリ管理:参照カウント

C ランタイムにはガベージコレクターがないため、計算グラフの解放は共有ポインターの複雑な絡み合いです。参照カウントがこれを解決します。

  • value_retain(Value *v)
    : リファレンスを取得(ref_count++)。新しい誰かが
    Value
    を保持していることを記録します。
  • value_release(Value *v)
    : リファレンスを解放(ref_count--)。カウントがゼロに達した時、
    Value
    は解放され、まず自身のオペランドを解放して再帰的にグラフを下へと伝播させます。

ルール

  1. 全ての
    Value
    は参照カウント 1 で生まれます。
  2. グラフのルート(損失や順伝播の出力)を解放すれば、参照カウントは下流へとカスケード状に伝わり、他の何もしない節点を正確に解放します。

value_release
は NULL に対して安全に呼び出せるため、NULL チェック不要です:

value_release(maybe_null);   /* maybe_null が NULL なら何も起きない */

magic フィールド

Value
には定数値として設定されたマーカー(magic marker)があります。
value_retain
value_release
はこれをチェックし、再帰的に節点を解放する前に毒をかけます。これにより、無効または陳腐な
Value *
の使用を実験中に検出できます。


この設計の利点と欠点

参照カウントは正しさと構文能力(composability)をもたらしますが、コストを伴います。

欠点

  1. 手動のバランス:各参照を明示的に管理する必要があります。一つ忘れればメモリリークに陥り、一つ多すぎると不要な解放となります。
  2. 共有所有関係
    Value *c = value_add(a, b)
    の後、
    a
    b
    c
    によって保持され続けます。個別の Value のライフタイムを個別に議論せず、全体としてのグラフ Lifecycle を考える必要があります。

利点

  1. 自動クリーンアップ:ルートだけを解放すれば、他に参照されていないサブグラフ全体が消滅します。
  2. 共有が無料:重みや中間値は適切なタイミングで解放されます。
    value_backward
    が共有ノードを超えて適切に勾配を蓄積できるためです。

ニューラルネットワークの実装

自動微分エンジンの上に、順伝播(feed-forward)ネットワークに必要な三つの要素が提供されています。

Neuron *neuron_create(uint32_t nin);
Value  *neuron_forward(Neuron *n, Value **x);

Layer  *layer_create(uint32_t nin, uint32_t nout);
Value **layer_forward(Layer *l, Value **x);

MLP    *mlp_create(uint32_t nin, uint32_t *nouts, uint32_t n_layers);
Value **mlp_forward(MLP *m, Value **x);
  • Neuron:
    nin
    個の重みの
    Value
    とバイアスを保持し、
    relu(w·x + b)
    を計算して一つの出力
    Value
    を返します。
  • Layer: 同じ入力を受ける
    nout
    個のニューロンからなるアレイで、
    nout
    個の出力
    Value
    のアレイを返します。
  • MLP: 複数の層を連結し、各層の出力を次の層の入力として供給します。

※すべてのニューロン(出力層を含む)が ReLU を適用することに注意してください。これはエンジンを最小限に保つための意図的な簡略化です(結果:出力は常に非負)。

トレーニングするには、ネットワーク内のすべての重みとバイアスの平たいリストが必要です:

Vector *neuron_parameters(Neuron *n);
Vector *layer_parameters(Layer *l);
Vector *mlp_parameters(MLP *m);  // 全てのトレーニング可能なスカラーを含む Vector

統合方法(トレーニングステップ)

完全なトレーニングステップの形状は以下の通りです:

uint32_t nouts[] = {8, 1};
MLP *model = mlp_create(2, nouts, 2);     /* 2 -> 8 -> 1 のネットワーク       */
Vector *params = mlp_parameters(model);   /* すべての重みの平たいリスト         */

/* forward: グラフを構築する */
Value *inputs[] = { value_create_leaf(x1), value_create_leaf(x2) };
Value **out = mlp_forward(model, inputs);

/* ... out[...] から損失の Value を構築 ... */

/* backward + update */
for (size_t i = 0; i < params->size; i++) vector_get(params, i)->grad = 0.0;
value_backward(loss);
for (size_t i = 0; i < params->size; i++) {
    Value *p = vector_get(params, i);
    p->data -= learning_rate * p->grad;
}

/* cleanup */
value_release(loss);
/* ... out, inputs を解放 ... */
vector_free(params);
mlp_free(model);

examples/
内の二つの例(
toy_regression
mnist
)は、このトレーニングループとデータ読み込みを具体化しています。特に
examples/toy_regression/train_on_toy_regression.c
を読むことをお勧めします。


サポートするデータ構造

通常は直接操作しませんが、以下の二つの自己完結型のデータ構造を利用しています:

  • Vector (
    vector.h
    )
    :
    Value
    ポインターからなる動的アレイです。
    vector_append
    は格納する
    Value
    を保持し、
    vector_free
    は解放します。
  • SimpleSet (
    simpleset.h
    )
    : メモリアドレス(ポインタ同値)をキーとする最小限のセットです。挿入とメンバーシップテストしかサポートしておらず、
    value_backward
    の幅優先順序で共有ノードを二度訪問しないために必要な機能です。

ビルドとテスト

ビルドには C コンパイラ、C 標準ライブラリ、および

libm
(数学関数)が必要です。すべては Makefile を通じて駆動されます。

テストスイートの実行

make test_value
make test_mlp

例プログラムの実行

# タINY な合成回帰分析(外部データ不要、推奨)
make example_toy_regression  

# MNIST データセットを利用した概念的なデモ
make example_mnist 

example_mnist
は最初に
examples/mnist/download_data.sh
を通じてデータをフェッチします。

クリーンアップ

make clean   /* ビルドディレクトリを削除 */

次のステップ

  • 最小限の完全なトレーニングプログラム:
    examples/toy_regression/train_on_toy_regression.c
  • 構造的デモンストレーション(実際のデータセット接続):
    examples/mnist/train_on_mnist.c
    • 注意:これは最適化や数値的に慎重な意図を持っていません。スカラーベースであり、ReLU 専用です。
  • 関数の呼び出し方法及び保証:
    test/
    ディレクトリ内のテストコードを参照してください。
  • ソースコード:
    src/value.c
    は短い注釈付きであり、順伝播演算と逆伝播ルールの各ケースが段階的に記述されています。

クレジット

microcrad は Andrej Karpathy 氏の

micrograd
の C 言語実装です。自動微分の設計、スカラー
Value
アブストラクション、および幅優先順序による後方伝播パスはすべて元のものに従っています。参照カウント付きのメモリ管理と C データ構造は、これらのアイデアをガベージコレクターなしで機能させるためにこのポートが追加した部分です。

同じ日のほかのニュース

一覧に戻る →

2026/06/21 7:36

2022 年以前の書籍

## Japanese Translation: 著者は 2022 年以降に出版された書籍、特に未知の作家によるものに過小評価する個人的な無意識のバイアスを認め、すべての文字が人間によって入力され、編集され、校正されたためにより重みがあると信じる古いタイトルの作品を好むと告白している。大規模言語モデルは効果的なコーディングツールのことを認める一方で、このバイアスに不安を感じながらも、それが社会に対して新しい技術の悪影響や特定の業界の更新事項に関連すると見なすわけではない。その作品では、執筆、印刷、新聞、ラジオ、テレビ、インターネットといった歴史的なメディア形式に触れているが、これらを技術的出来事と結びつけてはいない。検証の主張や IT ニュースは提示されていない。著者はこの傾向に対する既知の解決策がないこと述べており、それを不要かもしれないとして結論づけ、その省察を広範な技術導入やビジネスへの影響に対する批判ではなく、個人の読書習慣についての評論として位置づけている。 ## Text to translate: The original summary is strong and accurate; only a minor adjustment to phrasing can make it slightly more direct. Here is an improved version: The author admits a personal subconscious bias that undervalues books published after 2022, especially by unknown writers, preferring older titles on the belief they carry more weight because every word was typed, edited, and proofread by humans. While acknowledging that large language models are effective coding tools, the writer feels uneasy about this bias but does not equate it with concerns that society is being negatively affected by new technology or tie it to specific industry updates. The piece references historical media forms—writing, printing, newspapers, radio, television, and the Internet—without linking them to technical events. No verification claims or IT news are presented. The author states there is no known solution to this inclination and concludes it may not need one, framing the reflection as a commentary on individual reading habits rather than a critique of broader technological adoption or business impacts.

2026/06/21 5:30

愛の物語

## Japanese Translation: このテキストは、「カップルが出会い、ともに生き抜く方法」調査(2017 年、2020 年、2022 年)のデータが表示されている方法を明確にし、誤解を防ぐことを目的としています。主なメッセージは、アイコンチャートは三つの波浪すべてに登場した参加者のみを表示し、各参加者は 1 つのアイコンで表されることです。これらの視覚化は個人を表しているものの、基礎となる分析は人口全体に基づいて行われ、統計的な正確さを確保するために人口特性に基づく加重されたサブセットを使用します。したがって、チャート内の正確な数は加重分析の合計数と一致しない場合があります。個々のアイコンは純粋に視覚化のための目的であり、視覚化は特定の人口統計ではなく一般的な結果を反映しています。より深い方法論的洞察や将来の更新については、Alvin のニュースレターへの購読を推奨します。このデータセットは Stanford University Libraries(https://data.stanford.edu/hcmst2017 でアクセス可能)を通じて Rosenfeld, Thomas, Hausen(2023)から取得されており、視覚化に使用された粘土アニメーションアイコンの作成に際し Amanda Sakuma 氏に特別感謝いたします。

2026/06/21 2:01

SMPTEが標準をフリーアクセス可能に

## Japanese Translation: 以下のものは、日付、場所、ドキュメントの完全な範囲、特定のリーダーの名前、そして企業サポーターの文脈など、欠落していた具体的な詳細を統合しつつ、読みにくさを保ちながら改訂されたバージョンです。 ## サマリー(改訂版) **ニューヨーク州、ホワイトプレインズ、2026 年 6 月 17 日** — SMPTE は、アクセシビリティにおける歴史的な転換を発表しました。同社全体の標準カタログ(発効済み標準、推奨プラクティス、エンジニアリングガイドライン、登録開示文書(RDD)、および今後のリリースをすべて含む)は、今やグローバルなメディアテクノロジーコミュニティ全体に対して無料で利用可能となりました。SMPTE 社長のリッチ・ウェルシュ氏は、この決断が 110 年にわたる進化の後に、将来の相互運用性を確保するために不可欠であると述べました。この戦略的措置は、AI の真正性、コンテンツの出所、IP ベースのワークフローなど、業界全体を変革する課題に直接対処しています。本イニシアチブは、GitHub ベースのワークフローを採用し、構造化された HTML 制作への移行を行うという広範な近代化プロジェクトの一部です。SMPTE 標準副本代表のレイモンド・ヨン氏によると、これらの障壁を取り除くことで透明性が支えられ、業界のニーズに応えるスピードが向上します。一方、ディレクターのスティーブ・LLAMB は、アクセシビリティの向上が誤情報の削減に寄与し、主要テクノロジー大手全体で一貫した実装を可能になると強調しました。このオープンアクセス図書館は、ダイヤモンドレベルの企業会員(Amazon AWS、Apple、Blackmagic Design、CBS/Paramount Global、Disney、Dolby、Fox、Google、Ross Video、Sony、Telstra)によって支えられています。この進化を持続させ、さらなるイノベーションを育成するため、SMPTE は創設者支援者認識プログラムを開始しました。2026 年 12 月 31 日までに 1 万ドル以上の寄付を行う団体は、「創設者支援者」として公的に認定されます。すべてのドキュメントは、次世代メディアエコシステムにおける透明性を推進するために、SMPTE スタンダードズライブラリを通じてアクセス可能です。 # チェックポイント検証 - **主要なキーポイントはすべて反映されていますか?** はい(日付/場所を追加し、ドキュメントの完全な範囲を記載、名前を特定されたリーダーが引用され、ダイヤモンドメンバーの完全リストが含まれています)。 - **テキストに含まれていない推測を含んでいますか?** いいえ、提供された事実に基づいて物語を展開しています。 - **メインメッセージは明確ですか?** はい、閉鎖からオープンへのアクセシビリティ転換が中心的なテーマとなっています。 - **曖昧な表現がありますか?** 「ダイヤモンドレベル」「特定のドキュメント種類」などの具体的な定義を追加することで軽減されました。