the nature of code を読み終えて

1年と半年かかった「the nature of code」の最後の課題が終わったところで、(正確には終わってないんですが・・最終課題の生態系プロジェクトがまだノータッチ)、
いままで書いたブログ記事へのリンク、課題を作って知って楽しかったこと・さっぱりわからなかったことなどまとめておこうと思います。

英語版はこちら

The Nature of Code

で読めます。

日本語版はこれ

Nature of Code -Processingではじめる自然現象のシミュレーション-

Nature of Code -Processingではじめる自然現象のシミュレーション-

私はどちらも読みつつやりました。

はぁ楽しい本だった! 帯に「一番簡単な世界の作り方」と書いてあるんですが、言いえて妙。
canvas(sketch)の中で自分の書いたルールが、いきいきと、動く!

そしてシフマン先生が大好きになりました。
↓シフマン先生(この動画の最初で拾い上げているのがthe nature of codeです)

次はcoding rainbowやろうかなぁ。 ・・今見たらcoding[Undefined]になってる!商標権の問題だそうな。笑ってしまった

読んでいた時の自分なりのルール

  • 本を読んで、そのあとprocessingのサンプルコードを読んで、課題はjavascriptで書く、p5.jsは使わない。

これは単に「書いたことがあるのがjavascriptしかないから」という理由なので特に大した意味はない縛りだったのですが、 おかげでprocessingは描画に特化した言語なんだと気づいたり・processingにある機能を使いたいなぁ〜と思ったら自分で書くしかなく、その結果ES2015を知ったりするきっかけになったりして振り返ると結構よかったかも。

  • わからなかったらやめる・脱線する

「高校生や大学生はお休み中にさくっとやってしまってもいいですね」的な紹介をどこかでされていたため、さくっとできるかと思ったら、 全然そんなことはなく・・・。特に序盤よくつまずき、もう軽い気持ちでやることにしました。

課題のリンクとメモ

1~4章をやっていた頃はブログを書いてなかったので課題のリンクなしです。

無生物編

物体が動くのをシュミレートできるようになる

Chapter 0 はじめに

  • アニメーションはパラパラ漫画みたいにちょっと動かして・消してを繰り返すと作れる
  • 「ちょっと動かして」のルールをどう定義するかが大事
  • random()に頼ることは有機的なデザインの解決にはならない。
  • 擬似ランダムに偏りを持たせる方法
    • 格率を高くしたい数値を多めに用意してそこから選ぶ
    • 最初に選択肢を決めるランダム値の範囲を偏りのある状態で定義しておく
    • ランダム値を2つ使う(1つ目はただのランダム値・二つ目は1つ目を使うか破棄するかの判別用)
  • 平均値付近に多く分布させたい時はガウス分布が使える
  • より自然なランダム値を生成するパーリンノイズというものがある

Chapter 1 ベクトル

  • 座標を扱うときはxとyをまとめて扱えるベクトルとして使うと楽
  • 位置 = 位置 + 速度
  • 場所の変化の割合(速度)
  • 速度 = 速度 + 加速度
  • 速度の変化の割合(加速度)
  • processingにはベクトルの計算のセットPVctorがある(javascriptにはないので自分でつくる)
  • 移動オブジェクトが持つべきデータは何か?機能はなにか?ということを考えてオブジェクトをつくる
  • processingにはstatic関数と非static関数がある。(javascriptだとES21015で使えるようになる)

    ログイン - はてな

  • static関数がわからない

  • javascriptで書こうとするとPVectorを自作しないといけない

    ログイン - はてな

Chapter 2 力

  • オブジェクトに力を適用(積算・すべての力を合計)するには 質量で割って、加速度のベクトルに力を加算する。 このときの加速度は瞬間ごとなので、フレームを次に進める前に0にする必要がある
  • 物理の公式を使ってシミュレーションしたいとき
    • 力の方向をどう計算するか?
    • 力の大きさをどう計算するか? のふたつに分けて考えてコードに書き直す。
    • 扱っている対象がベクトルなのか・スカラー浮動小数点数)なのかに注意する。
  • 2章では摩擦や抵抗や重力をやってみた
  • 重力の課題でオブジェクト間の対話についてでてくる。どっちに力を計算する機能をもたせるか?で結構迷った。
  • 割り算の記号(/)を見たら0で割ることがないように注意する

Chapter 3 振動

  • radian(孤の長さ = 半径のときの角度) = 2 * PI * (度数 / 360)
  • 角度 = 角度 + 角速度
  • 三角関数をつかってベクトルの大きさや方向などを調べたりできる
  • 極座標デカルト座標の変換は結構でてくる
  • 単振動などは三角関数を使うと簡単に再現できる
  • 波は単振動をずらしてアニメーションさせると作れる
  • 波は足すことができる

Chapter 4 粒子系

  • 粒子のような多くのものをスケッチするときには、複数のクラスや他のクラスのインスタンスのリストを保持するクラスをつくるとやりやすくなる
  • 粒子をつくるときは存続期間のプロパティをつける(粒子が増えすぎると停止しちゃうので永続させない)
  • 粒子には普通エミッター(粒子の初期速度・位置などの設定ができる発生源)がある

    パーティクル・システム - Wikipedia

  • processingではArrayListをつかって粒子のリストを管理してこれをエミッターとする。

  • processingのArrayListiteratorオブジェクトを作れる。 (反復処理中に要素を削除したり追加したりしても2回参照したりスキップしたりせずにすべての要素に処理ができる!便利!) (hasNext()で次があれば実行させることができる!便利!)
  • ES2015の配列でもiteratorオブジェクトが作れる

    ログイン - はてな

  • 粒子を管理する粒子系・粒子系を複数管理するクラス、を管理する・・・と、どんどん入れ子にして複雑にできる

  • オブジェクト指向の基本原則(継承・ポリモーフィズムカプセル化)がでてくるけれどここの部分はついていけてないのでまた絶対読み返す
  • 継承を使うと他のクラスから特性と機能を受け継ぐことができる。

    ログイン - はてな

  • ポリモーフィズムが何か全然わからない・・

Chapter 5 物理ライブラリ

・・・の途中で脱落。

あとで読む


生物編

環境に応じて動きを決められるようになる

Chapter 6 自律エージェント

複雑系のルールベースの技法を学んで、複雑な動きをつくれるようになる

  • 自律エージェント = 環境ないでどう行動するかをリーダーや全般的な計画を受けずに自分で選択すること
  • 自律エージェントの構成要素
    • 環境を認識する「限られた」能力がある
    • 環境からの情報を処理して行動を計算する
    • リーダーを持たない
  • 課題ででてくる「vehicle」は「模型は心を持ちうるか」という論文から。

模型は心を持ちうるか―人工知能・認知科学・脳生理学の焦点

模型は心を持ちうるか―人工知能・認知科学・脳生理学の焦点

  • レイノルズ(boidの人)の理想的なvehicle(仮想的な乗り物)
    • 行動選択:環境の注意を向けて環境に応じて行動を計算する
    • 操舵:行動を選択したら次の動きを計算する
    • 移動運動:これは課題ではあんまり出てこないが、行動するときの動きを決める(足を左右交互にだすとか)
  • 操舵力の式:操舵力 = 必要な速度(現在の位置から目標地点までの位置ベクトルを最大の速度などで適宜制限したもの) - 現在の速度
  • 最大速度などの変数をいろいろあてて特定の動きのシュミレートができる
  • 目標に近くなるにつれて減速させたり・・・必要な速度は自分で好きなように決めることができる

    ログイン - はてな

    ログイン - はてな

    • 前方の点から円を描いて円周上のランダムな点を目標地点にする
    • 壁の近くに来たら壁の反対方向へ最大速度ですすむ
    • 流れ場などで環境から与えられる力に沿わせる など

    ログイン - はてな

    ログイン - はてな

    ログイン - はてな

  • 経路追従の課題ではベクトル内積が活躍した

    ログイン - はてな

  • 複雑系

  • 群れ

    ログイン - はてな

  • boidを描いて、処理速度をあげるにはどうするか考えた

    ログイン - はてな

    ログイン - はてな

Chapter 7 セル・オートマトン

  • 単位を最小(ビット・0か1か)に絞って仕組みを考える
  • 時間の経過とともに状態を変化させるやり方をセルオートマトンで見てみる。 すごく単純な系であっても洗練された形状をつくることができる!

    ログイン - はてな

  • 2次元のセルオートマトンは世代をフレームで表してアニメーションにしていた

    ログイン - はてな

  • 近隣と自分のセルの組み合わせで次の世代が0か1か決めるとき、必要な3つの数字を文字列にしてくっつけて3桁の数字にして、2進数に変換するというのをやっていた、これ思いつかないなぁと思った

Chapter 8 フラクタル


知能編

生物の進化の法則を使ってオブジェクトを進化させる

Chapter 9 遺伝と進化

  • 今までの課題は初期化するときランダム性や考えた結果としてオブジェクトに特性を割り当てていたが、進化の過程にまかせてみても面白い
  • 結果がわかっているときに総当たり的なアルゴリズムを組んで解こうとするのはよくない
  • 遺伝的アルゴリズム

    • 遺伝子の型と表現を切り離してつくる
    • 適応度を評価する関数を自分で設計する
    • 評価の高い遺伝子を次の世代に拾われやすいようにする
    • でも突然変異させるのも必要

      ログイン - はてな

  • 表現と遺伝子を切り離してつくるといろいろ応用できる

    ログイン - はてな

  • 適応度関数を変化させるとこんなことも

    ログイン - はてな

  • 適応度関数の部分を人力でやってもいい(対話的選択) もっとも人気のあった作品に似た作品を次の世代に残しやすくするとか

    ログイン - はてな

Chapter 10 ニューラルネットワーク


脱線して読んだ(読むつもり)の本

形の美とは何か (NHKブックス)

形の美とは何か (NHKブックス)

自然物の美しさはフラクタルの美しさだった・・・!おまけに黄金比フラクタルの美しさ。ああフラクタル

ログイン - はてな

[普及版]ジェネラティブ・アート―Processingによる実践ガイド

[普及版]ジェネラティブ・アート―Processingによる実践ガイド

the nature of code の前に読んで、nature of code読むきっかけになった本。これはいつかメモに起こしたい

複雑系入門―知のフロンティアへの冒険

複雑系入門―知のフロンティアへの冒険

複雑系のところを読んでいて、こんなことどうやって思いつくのかなと気になって。でもまだ未読。

プログラマの数学

プログラマの数学

1章をやっているときに高校数学の記憶がきれいさっぱり消えてることに気づいてあわてて読むことにした。読み途中。

波紋と螺旋とフィボナッチ

波紋と螺旋とフィボナッチ

この本はめっちゃおもしろかった・・!
アンモナイトも、結晶の螺旋も、しましま模様も、なんでできるか解説がわかりやすく書かれててスッキリとした気持ちに。 植物の茎の先端の「中央部分の連続した拡大と周囲の相似形の構造」が黄金比の長方形そのものだ! コッホ曲線を単なる座標を再帰関数で扱う書き方からクラスを使う書き方へ変換する課題をやっていたときに、この本を思い出したりした。 あと後ろの方の自伝が胸熱。

www.google.com

私は美術館とかにいったら絵画の細部を眺めるのが好きで、 直線を描いてる部分だったらマスキングテープの剥がれる部分のちょっと絵の具が引っ張られて固まった感じとかすごく綺麗だなって見てしまうんですが、 それって8章に出てきた自己相似性のある形が好きとも言える。 このサイトはかなり高解像度の作品が収容されてるので信じられないくらい拡大できて細部が眺められる。あぁ欲が満たされる・・。

nature of code : 今日の練習「ネットワークのアニメーション」

the nature of code 10章最後の課題

これまで読んできたニューラルネットワークのさわりの部分を可視化したアニメーション

See the Pen ネットワークのアニメーション by kanaparty (@kanaparty) on CodePen.

2016年にギリギリ間に合った・・・!

nature of code : 今日の練習「ビークルの訓練」

前回作成したのは教師あり学習(正解があって、結果と正解から誤差を計算し重みを調整する)だったが
今回は簡易的な強化学習(結果から誤差を計算し、環境に対応する)を作ってみる練習。

今回のビークルにはbrainプロパティがあって、操舵力を決めるときにbrainから処理された操舵力を受け取って それに従って運動させる。

See the Pen ビークルの訓練 by kanaparty (@kanaparty) on CodePen.

環境(黄色い点)から受ける力をbrainに渡して処理してもらい、 その結果が画面の中心(灰色の点)からどれだけ離れているかをエラーとしてトレーニングしている。今回は活性化関数がない。

ビークル

//操舵力を計算
steer(target){
  var force = [];
  for (var i = 0; i < target.length; i++) {
    force[i] = this.seek(target[i]);
  }
  //ターゲットから受ける力をbrainプロパティに渡して結果をもらう
  var result = this.brain.feedfoward(force);
  this.applyForce(result);
  //トレーニング
  var error = Vector.sub(this.desired, this.position);
  this.brain.train(force, error);
}

brain内では受け取った力の分だけ重み(今回は位置なのでxとyの2つ分)を調整している。

//調整
train(forces, error){
  for (var i = 0; i < this.weightLength; i++) {
    this.weight[i] += this.c * error.x * forces[i].x;
    this.weight[i] += this.c * error.y * forces[i].y;
  }
}

1000回トレーニングを繰り返したら、点の位置を変える。
位置が切り替わった直後は前の位置のときに調整した重みに従って動くので目標がわからなくてフラフラしているように見えるが、
まただんだん調整されて画面の真ん中を目指すようになる。

the nature of codeの一番最初の課題はランダムウォークだった。
ついに動きをつける対象にbrainが〜!!すごい、私も進化してきた感がある。

nature of code : 今日の練習「選択的遺伝」

See the Pen 選択的遺伝 by kanaparty (@kanaparty) on CodePen.

9章でやり残してしまっていた課題。
自分で適応度を変更して次の世代のパターンを作る。 例は顔みたいな図形だったけど、タータンチェックのパターンで作ってみた。

nature of code : 今日の練習「単純なパーセプトロン」

ニューラルネットワークとは

脳に基づいて特定の問題を解決するための計算モデル。複雑系の一種

ニューラルネットワーク - Wikipedia

ニューロン...細胞網に存在している単一細胞で、入力を受け取り、処理し、出力を生成する。
コネクショニスト計算系...情報がネットワーク全域で集合的に並列で処理される

ニューラルネットワークの学習機能

ニューラルネットワークの主な要素の一つ。
ニューラルネットワークは単なる複雑系にあらず。内部を流れる情報に基づいて構造を変化させることができる複雑適応系
普通は重み(二つのニューロン間の信号を制御する数値)を調整することで適合させる。
ニューラルネットワークが適していない出力を使た場合はこの重みを変更して後続の結果を改善する。

いろいろな学習方法

  • 教師あり学習
    ネットワークのだした答えと、正しい答え(教師)を比較して誤差にあわせて調整する。

  • 教師なし学習
    既知の答えのデータがない場合に行う。隠されたパターンを検索するイメージ。適用例にクラスタリングがある。

  • 強化学習
    観察に基づいた方法。結果に従って判断し、環境の観察をする。ロボット工学で広く使われている。

ニューラルネットワークの代表的な使用方法

  • パターン認識(顔認識)
  • 時系列予測(明日の天気など)
  • 信号処理(補聴器のノイズの除去など・・・)
  • 制御(自動運転など)
  • ソフトセンサー(複数の個別センサーを処理して総合的に判断したり)
  • 異常検出

パーセプトロンとは

最も単純なニューラルネットワーク。単一ニューロンの計算モデル。
1つか複数の入力、プロセッサー、出力で構成される。
フィードフォワードモデル(送信、処理、出力)?

入力から出力まで

  1. 入力を受けとる
  2. 重みを入力する(特定のあたいをかける。通常は最初ランダムな0〜1の値で行う。)
  3. 入力に重みをかける
  4. 重み付けされたすべての入力を合計する
  5. 出力を生成する(活性化関数を通じて合計値を渡す。出力するかどうかをパーセプトロンに通知する。)

実装した単純なパーセプトロン

パーセプトロンを使って、単純なパターン認識をする。
与えられた座標が線より上にあるか、下にあるか判断するパーセプトロンを作る。

できたもの↓

See the Pen シンプルパーセプトロン by kanaparty (@kanaparty) on CodePen.

正しい線は背景にうっすら見える紺色の線。
点は教師。1フレームづつ教師の入力をパーセプトロンに渡して訓練させる。
紺色の点は線より上に、黄色い点は線より下にあるとパーセプトロンが判断した位置。
これが正しい線にだんだん近づけば訓練が成功している!

登場人物は2つ。

処理の流れ

  1. 答えが用意されている入力をパーセプトロンにわたす
  2. 答えを推測
  3. エラーを計算(正しいか、間違っているか)
  4. エラーに従ってすべての重みを計算する
  5. (繰り返し)

エラーの定義と重さの定義

  • エラー = 適切な出力 - 推測の出力

  • 新しい重み = 今の重み + 重みの変化量

(重みの変化量 = エラー * 入力)

  • 新しい重み = 重み + エラー * 入力

学習定数(ビークルの操舵のときに出てきたmaxSpeedのような感じで、最大力を制御する変数)を加えると答えに行き着くまでの時間を調整することができる。
学習定数が大きいと短時間で済むが微調整が難しい。小さいと時間がかかるが正確性が増す。

教師オブジェクト

線の上にあるか下にあるかは線の関数を使って調べればよい。f(x)のyよりの上にあるか、ないか。


おしまい

たしかこの章を読み始めたのは7月だったはず・・・。
私には難しくて危うく積ん読になってしまうところだった。 のこす課題はあと3つ。

それにしても教師オブジェクト2000個でも正しい斜めのラインぴったりにはなかなかならないのだなぁ。

参考にしたサイト

ニューラルネットワーク

hokuts.com

イテレータ・ジェネレータ(ついでにシンボルもちょっとだけ)覚えたことメモ

tuitui.hatenablog.com

↑昨年イテレータについて後日読もうと思っていたんですが、ようやくその「後日」が来ました。
イテレータ・ジェネレータ(ついでにシンボルもちょっとだけ)について覚えたことをメモ。
自分でIterableなオブジェクトを書いてもいいし、arrayやstringにはそもそも備わっているということで
なんだ〜となりました。もっと早くちゃんと読んでおけばよかったなと思った次第です。  

Iterationについて

繰り返し処理を行うための決まりに従った実装。
繰り返し処理を適用したときの挙動 → Iteration

IterableとIterator

Iterable = Iteratorを備えた(Symbol.iteratorプロパティにIteratorを返すメソッドを実装している)オブジェクト。Iteratorを備えているのでfor-ofで処理できる。
Iterator = next()メソッドを実装したオブジェクト。nextメソッドを呼ぶと以下2つのプロパティをもったオブジェクトを返す。

  • value 現在の値
  • done 値を出し終えたかどうか

最初からIterableな挙動が備わっているもの

はじめからSymbol.iteratorプロパティにIteratorを返すメソッドが実装されているもの

  • Array
  • String
  • NodeList
  • Generator Object
  • Array, Map, Set が持つ entries(), keys(), values()の戻り値

など。
たとえば文字列で順番にとりだしたいとき以下のように書ける

const s = 'javascript';
const sIterator =  s[Symbol.iterator]();
sIterator.next();//Object {value: "j", done: false}
sIterator.next();//Object {value: "a", done: false}
sIterator.next();//Object {value: "v", done: false}
sIterator.next();//Object {value: "a", done: false}
sIterator.next();//Object {value: "s", done: false}
sIterator.next();//Object {value: "c", done: false}
sIterator.next();//Object {value: "r", done: false}
sIterator.next();//Object {value: "i", done: false}
sIterator.next();//Object {value: "p", done: false}
sIterator.next();//Object {value: "t", done: false}
sIterator.next();//Object {value: undefined, done: true}

for-ofを使ってとりだすとき

const a = ['j','a','v','a','s','c','r','i','p','t'];
const aIterator =  a[Symbol.iterator]();
for (variable of aIterator) {
  console.log(variable);
}
//j
//a
//v
//a
//s
//c
//r
//i
//p
//t

使い方はここ qiita.com

がとてもまとまってました。ありがとうございます。

Symbolについて

オブジェクトに対して、ある状況に応答するためのインターフェースを組み込む(プロトコルを定義する)ために使う。

const sym = Symbol();

で生成できる。newをつけない。
常に別々のユニークな値として生まれる。

オブジェクトのプロパティとして使うとObject.keys()などで無視される。

GlobalSymbolRegistry

グローバルスコープを越えて共有されるSymbolの領域。 iframeなどを隔てたとしても同じSymbolを共有することができる。
Symbol.for(key)メソッドを使うと keyとして渡した値を持ったSymbolがGlobalSymbolRegistryに存在しなければ、新しく生成したSymbolを生成して返す。

Generatorについて

処理を途中で抜けられる。そのときに値を取り出すことができる。 Generatorオブジェクトはnextメソッドを呼びだすと、 yieldの後に置かれている処理を評価するところまで進み、その評価結果を返す。 返ってくるオブジェクトの中身は

  • value : yieldの後の処理
  • done : すべての値を取り出し終えたかどうか

書き方

function* generatorFunc() {
  yield 1;
  yield 2;
  return 3;
}
var g = generatorFunc();
console.log(g.next()); //Object {value: 1, done: false}
console.log(g.next()); //Object {value: 2, done: false}
console.log(g.next()); //Object {value: 3, done: true}

function* と記述すると定義できる。