Networkを実装した。conv_nn_mnistRustプログラミング言語Rustがこれからより多くの場所に使われるだろう。コンパイラが間違った(間違いそうな)コードを弾いてくれる点と、クロージャや台数データ型といったプログラミングの抽象化がスピードを犠牲にせずに利用できるという点はとても魅力的である。書いたコードはだいたいコンパイラエラーに当たる。Structや関数のsignatureに対してRustのコンパイラがエラーを出した場合、メッセージをしっかり理解してその部分を直すことでよりデータの所有権や参照のlifetimeが明瞭な安全なプログラムを書くことができる。プログラミング言語研究の成果を享受できるのでRustは好きだ。開発環境VSCode。lldbのプラグインでGUIを使ったデバッグもできる。エラーメッセージRustのエラーメッセージは時々難しい。1e-7));このコードに対して、下のエラー。D>という型がScalarOperandというtraitに合っていないということ。いって加減剰余の演算をArrayBaseに対して行えないばけではない。operationの右辺は行列ではなく行列への参照じゃないといけない。ndarrayのドキュメントにそう書いてあるdocs.rsこれを読めば、&を右辺の最初につければいいんだなとわかるのだが、RustコンパイラはこのドキュメントへのURLを表示することはできない。クロージャのTraitFnやFnMutのエラーメッセージも難しい。serverの章にもクロージャにまつわる難解なエラーメッセージの話があるように、Rustコンパイラは完璧ではない。Rustがより良くなっていってこのあたりが簡単になりますように。"best"?の中でndarrayの評判がよかったので。行列の掛け算は1次元の行列と2次元の行列とで振る舞いが異なる。into_shape()ハマったところはinto_shape()。into_shapeが使えない場合があるので自分でreshape関数を作ったが、これは常に行列をコピーすることになって失敗しない代わりにメモリが無駄になっているはず。次にpermuted_axis()とinto_shape()は混ぜて使えないところ。このlimitationは最後の最後まで気づかなかった。最初はニューラルネットワークの層を表すtraitを作ろうとして挫折した。これは層を1つ1つ実装していく中で層の中には4次元の入力を受けるものと2次元の入力を受けるものがあるからだった。今考えると入力の次元数と出力の次元数でgenericsを使ったtraitを作れる気がする。ところで、Numpyでは下のコードの様に異なる入力の型をとるlayerをまとめてリストに入れたり、その入力と出力をforループで回したりできる。xしかしRustは型に厳密なので、これができない。arrayはあるが型安全性は失われてしまう。これを解決してくれる良いデータ型はないものだろうか。different絵が書けないPythonとNumpyの組み合わせに比べるとこのRustでの実装ではグラフ描画やipythonのようなインタラクティブな操作ができない。入力データの画像を目でも見たかったのでansi_termで色をつけて表示してみたりした。Networkニューラルネットワークを計算グラフとして考えることで、損失関数の重さに関する偏微分の計算が局所的になるところがミソ。ネットワークにいくつもの層があっても、各層ごとに重さと入力の各要素の偏微分が(局所的に)合っていれば全体の計算が合う。checkを使うと実装が怪しい層を見つけることができる。自分の場合はどうしてもバグの箇所がわからない時があったので、結局上の本のgithubにあるNumpyの実装に同じ値を与えてどこの変換でバグがあるのか調べた。損失関数はsoftmaxとクロスエントロピー誤差。入力はMNISTの28x28のグレイスケール画像データ。層を何枚も重ねる「ディープラーニング」はしなかった。layerだけのネットワークよりも画像の一部の形に反応するネットワークを作ることができるらしい。AdamAdamはネットワーク内部の重みを調節するアルゴリズムの一つ。0.01掛けて引いており学習の結果は悪かった(テストデータに対して40%とかの確率)。Adamを導入したら同じ回数の学習で97%を達成。Networkを学べたので目標達成。