PyTorchで学ぶ『平均』と『分散』と『BatchNormalization』
ところでBatchNormalizationってなんだっけ?
深層学習でモデル構築をしていると、よくお見かけするのがBatchNormalizationと呼ばれるもの。
・・・はい。よく見かけますよね?
・・・・・・・・・。
ところで、結局それってなんでしたっけ?
「平均を0、分散を1」という説明はよく聞きますけど、それは結局どういうことなのか?
というのが今日のお題です。
ちなみにですけど、この記事を書いてる人間は、本ブログで度々統計のことについて語っていらっしゃる統計学のスペシャリストとは別の人間です。どちらかというと統計学は素人に近い(?)ので、『え、そこから???』などと言わず、温かい目で読んでいただけたらと思います。
(使用しているのがNumpyではなくPyTorchという辺りがお察しですね・・・)
FIRフィルタを作って周波数特性を検証
適応フィルタを作ってみる では、サンプルコードを紹介しましたが、実際に動かしてみたいと思います。そこで適応フィルタの前に、まずはシンプルに固定フィルタを検証してみます。
- FIRフィルタ
- サンプルコード
- 検証用のコード
- サンプルコード
- フィルタスルーで動作確認
- ローパスフィルタを検証
FIRフィルタ
適応フィルタを作ってみる で使用したFIR【Finite Impulse Response】のサンプルコードを、まずは固定フィルタで検証してみます。
The Continuing Story of Error Correction Code 3
ハミング距離
カルノー図
カルノー図は論理式を簡略化するためなどに使用する図です。
このような論理式の簡略化を図から容易に行うことができます。
が、ここでは論理式は扱いません。ハミング距離の理解のためだけにカルノー図を使います。
ハミング距離の説明でよく超立方体が使われていますが(ハミング距離 - Wikipediaでも4次元の超立方体が使われてますね)次数が上がると図が意味不明になるし、そもそもイメージしずらいのでここではカルノー図で押し通してみましょう。
では、8変数までのカルノー図の作り方のはじまりはじまり・・・
2ビットのカルノー図
縦方向に、横方向にを割り当てて、各マスにはの3ビットの値が書き込まれており、3ビットが取り得る値の一覧表になっています。 3ビットが取り得る値はで4通りなので4種類の値となります。
2ビットのカルノー図はこれで完成です。
「で、カルノー図って一体なんなんだよ!!」
はい、そうでしたね。ではカルノー図が一体何なのかは3ビットのカルノー図で説明しましょう。
3ビットのカルノー図
縦方向に、横方向にを割り当てて、各マスにはの3ビットの値が書き込まれており、3ビットが取り得る値の一覧表になっています。 3ビットが取り得る値はで8通りなので8種類の値となります。
この表、縦方向のは→→→という順番に割り振ってありますが最後の2つ黄色の塗りつぶしの部分の順番を入れ替えて→→→としてみます。 このようにして作られた表には面白い性質があります。
からスタート、一つ下に進むとになりと比べるとだけがからに変化します。
から更に一つ下に進むとになりと比べるとだけがからに変化します。
から更に一つ下に進むとになりと比べるとだけがからに変化します。
更に一つ下に進めてみようかな、と思ったのですがもうこれ以上、下はないので先頭の行に戻るとになりと比べるとだけがからに変化します。
ここでは上下に移動しましたが、左右の移動も変化するビットは1ビットだけになっています。
最初の表ではの下はですからがから、がからに変化しているので2ビット変化していますね。
このように上下左右とは1ビットしか異ならないように値を並べた表を「カルノー図」と呼びます。
表のはじまで行ったとき反対側に移動するのが面倒なら表自体を上下左右に伸ばして更に続きがあるんだ、と考えると簡単です。 下の表は中央、青塗りつぶしのまわりに同じ表をつなげてみました。
2ビットでは隣との違いは必ず1ビットとなるのでマトリクスにすると自然とカルノー図になっているんですね。
4ビットのカルノー図
4ビットのカルノー図は横方向も2ビット割り当てます。
値の並びは縦方向と同じく隣同士が1ビット違いになるようにします。
上下左右に移動したとき変化するビットは1ビットのみになっていますね。
5ビットのカルノー図
4ビットまでのカルノー図は上記のとおり容易に作成できますが、更にビット数を増やそうとするとちと面倒なことが起こります。
縦方向は→→→→→→→と1ビットづつ変化するように配置して以下のような表ができます。
なにか、上手いことできているように見えますが黄色のセルを見てください。
となので1ビットしか変化していないのですが、隣同士ではないんです。
5ビットになると変化するビットは5個、移動方向も5個ないといけないのですが、移動方向は上下左右の4通りなのですからもう一つ、新しい移動方向を考える必要があるのです。黄色のセルはこの新しい移動方向で隣同士になる、ということになります。
新しい移動方向は
- 2行目と7行目
- 3行目と6行目
になります。
でも、なんか分かりづらいですね・・・
ということで少し考え方を変えてみましょう。上下左右の移動は2次元平面での移動ですから移動方向を増やしたければ3次元にしてやればよいのでは?
ということで、3次元バージョンの5ビットカルノー図です。
5ビットでは4ビットのカルノー図を2階建にします。移動方向は上下左右に加えて1階、2階を行き来できます。
5ビットののを1階、2階に割り当てて以下のようにしましょう。
1階
2階
先ほど、隣同士になっていなかったとも1階と2階で隣どうしになれました。これで5ビットすべて隣は1ビット違いとなりました。
6ビットのカルノー図
ここまでの流れを考えれば6ビットは簡単ですね。
そうです、4階建てにします。
1階
2階
3階
4階
7ビット、8ビットのカルノー図
最後、7ビットと8ビット。7ビットなら移動方向は7種類、8ビットなら移動方向は8種類必要になります。
上下左右に上の階、下の階と3次元の移動方向は使い果たしてしまいました。
そこで建物を増築します。1号館、2号館と2棟構成にしたのが7ビット、1号館から4号館の4棟構成にしたのが8ビットのカルノー図になります。
移動方法は・・・、空間移動です。とある部屋から別の棟の同じ位置の部屋に移動することができます。
7ビットの棟構成
1号棟
2号棟
8ビットの棟構成
1号棟
2号棟
3号棟
4号棟
ここまでくると、論理式の簡略化としての用途には使いずらくなってきます。まぁ、頑張ればできますが普通は6ビットぐらいまででしょうか。
しかし、ここではハミング距離のイメージを掴むためにカルノー図を用いるので、このワンフロア16部屋、4階建て、4棟構成のカルノー図でも十分に使うことができます(たぶん・・・)
ハミング距離はどうしたんだよ・・・
はい、おまたせしました。
やっとここからがハミング距離の説明です!!
エラー検出・訂正で使用するハミング距離とは2つの値の異なるビットの数となります。
そしてカルノー図上では異なる部屋の間の距離となります。
この距離とは一般的な距離の測り方とは少し異なります。とある部屋から1ビットしか異ならない部屋への移動を1として最短で何部屋移動するか、が距離となります。
4ビットのカルノー図で考えてみましょう。
- 黄色の部屋と緑色の部屋のハミング距離は1
- 黄色の部屋と青色の部屋のハミング距離は2
- 緑色の部屋とオレンジ色の部屋のハミング距離は1
1はすぐ隣なのでから左に行ってで1、2はから右に行って、下に行けばなので2、これはいいですね。
3はから右に行って、更に右に行って、もひとつ右に行ってだから3じゃないの・・・?と思うかもしれませんがカルノー図は左端と右端は繋がっているのでから左に行ってだから1になります。
この決まりは階の間の移動でも、棟間の移動でも同じです。
2階建ての5ビットカルノー図で試してみましょう。 黄色の部屋から緑色の部屋までの距離はから1階を右に行って、更に右に行って、下に行って、もひとつ下に行って、2階に上ってでハミング距離5となります。どのような経路を辿ってもこれより短い経路はありません。 実際にカルノー図を辿ってみてくださいね。
1階
2階
5ビットで全ビットが0だったのが全ビット1になったのだから異なるビットは5個でハミング距離は5、と見ただけでわかりますがこの後カルノー図を使ってエラー検出できる、できない、エラー訂正できる、できない、エラー検出・訂正ができるなら何ビットまでできるのか、の考察を行うので頭の中でカルノー図とハミング距離をイメージできるようにしておきましょう。
余談と次回予告
マンハッタン距離
カルノー図上でのハミング距離を数学用語で言うと『マンハッタン距離』となります。
一般の距離は『ユークリッド距離』と言って2点間を直線でつないだときの直線の長さとなります。これに対して『マンハッタン距離』は各座標軸での距離の和となります。マンハッタンの碁盤の目のような道路を進んでいったときの距離って感じですかね。斜めにショートカットすれば近いんだけどもそれはできない、碁盤の目を右に左に行った時の距離ということです。
ただ、マンハッタンの道路の右端と左端は繋がっていませんがカルノー図の右端と左端、上端と下端は繋がっているので計算するときはこれを考慮に入れる必要がありますね。
グレイコード
3ビットのカルノー図を作る際に→→→という並びを使用しました。隣同士が1ビットしか変化しない並びです。
このようなコードをグレイコードと呼びます。5ビットのカルノー図を作る際に最初に考えた→→→→→→→という並びも隣同士は1ビットしか変化しないのでグレイコードですね。
ソフトウェアではあまりお目にかかりませんがハードウェアではよく使う手法となります。
一度に複数のビットが変化すると回路を構成する部品の微妙な動作時間の違いから本来出力されるべきではないコードが一瞬みえてしまい、これが誤動作の引き金になったりします。ここでグレイコードを使うと変化するのは必ず1ビットですから部品の動作時間のバラツキに関わらず正しいコードしか出力されないことになります。
一見、複雑そうなコードの並びですが信頼性を上げる重要な手法なんですね。
超立方体
2次元の座標で正方形を考えます。頂点が4個あってそれぞれの頂点からは2本の同じ長さの辺が出ており頂点で直角に交わっています。
では3次元の座標で立方体を考えます。頂点が8個あってそれぞれの頂点からは3本の同じ長さの辺が出ており頂点で直角に交わっています。
では4次元の座標だったら?
2次元から3次元に拡張したとこと同じように3次元から4次元に拡張すると頂点が16個あってそれぞれの頂点からは4本の同じ長さの辺が出ており頂点で直角に交わっている、そんな形になりそうです。
でもこれ、3次元の座標では作ることはできないですよね。頂点から4本の辺が出ていてそれぞれが直角に交わっている、この時点で3次元では実現できません。この4次元、あるいはそれ以上の次元での立方体を超立方体といいます。
4次元なので2次元や3次元で作ることはできませんが、条件をゆるめれば図にすることはできます。たとえば頂点で各辺が直角に交わっている、各辺の長さは同じ、という条件を外して書いたのがハミング距離 - Wikipediaの図になります。
実はカルノー図を7ビットに拡張するときにも4次元をどう扱うか、という問題に直面しています。この時は隣の棟に空間移動できる、というズルをして解決しましたね。
次回予告
さて、ハミング距離もわかってきたので次回はエラー検出・訂正とハミング距離について考えてみましょう。
思考のサルベージ(その8)
各工程で心がけたい思想を掘り起こしてみる
今回は、設計工程における「過剰設計」について考えてみます。対向装置の挙動が不透明な状態で設計をすすめると、「過剰設計」になることがあります。「過剰設計」とその弊害とは一体何でしょうか。
準正常系の設計
以前にもお話させていただきましたが、規格に準拠する設計では、正常系、異常系は規格に沿った設計をしていればまず間違いありません。ただし、準正常系では、各メーカに設計がゆだねられることが多いです。 例えば、規格で以下のシーケンスが規定されていて、装置Aの設計をするとしましょう。
装置Bから装置Aに「特定のアクセスが一定回数」続いたら、
- 1.装置Aが装置Bにデータ取得指示を出す。
- 2.装置Bは装置Aにデータ取得要求を出す。
- 3.装置Aは装置Bにデータを送信する。
装置Aは装置Bがデータを取得したと認識する。
正常系の設計は明快ですね。装置A、装置Bの間でやり取りされるメッセージのプロトコル違反は異常系に落とし込めます。
では、「1」のシーケンスが動いた後、「2」のシーケンスが動かなかった場合はどうしましょう?一見すると、装置Bが規格に沿った動作をしないケースとなります。そのまま放置してもよさそうです。でも、装置Aからの取得指示が装置B届いてないケースもあり得ます。メッセージキューが詰まっていて、送信自体が出来ていないのかもしれません。
過剰設計はなぜうまれる?
ソフトウェア開発の現場では、対抗装置の挙動が不透明だったりすると、極力正常系に落とし込めるような設計にしたがる傾向があります。もちろん必要な設計である場合がほとんどでしょう。ただ、工程が進み対向装置の動作が明確になってくると、準正常系でのケアが不要だったことや、実は規格・機能の目的からい逸脱していることが発覚したりします。準正常系設計時にこそ、規格・機能の目的を把握していることが重要といえます。
過剰設計の弊害
とはいえ、準正常系を手厚くしただけ動作的には問題なさそうです。ただし、判定分、検索処理が多発することによるオーバーヘッドは確実に増加します。競合他社と処理速度を競うような装置の場合は、致命傷になりかねません。また、システムテストの立場では、あらゆるケースでの動作を反映したテストを実行しなければなりません。また、そこで不具合が発見されれば、複雑化した準正常系の処理を修正するために処理がさらに複雑化するかもしれません。対向装置に挙動が不透明ならば、「評価視点」を設計に加味してみるのもいいかもしれません。
何か掘り起こせた?
- 準正常系こそ規格、機能の意図を正確に把握することが必要。
- 評価視点を考慮した設計も必要。
過剰設計はある意味避けきれないのかもしれません。それでも、そのリスクを認識し、できうる限りシンプルな設計を目指したいですね。
おしまい
対向装置の動きが不明なまま設計を進めるなんて状況が回避できればなにも問題ないんですけどね、とか言ってもしかたあるまい。
GoでGoな非同期処理を試してみよう!
非同期処理、皆さんどうコードを書いてますか?
少し前のこと。弊社の若手(?)の方が、『非同期処理めんどくさい!』みたいなことを騒いでいたのですが、そもそも皆さんどうやって非同期処理のソースコードを書いているのだろう?とふと思ったわけです。そもそも『非同期』の定義ってなんだろうという話もでてきそうですが、ぱっと思いつくのは以下のような書き方でしょうか?
- スレッド作成してそこで実行
- async/await を使用して実行
最近の主流は async/await でしょうかね。こちらは多くの言語に実装されています。
ただ私の場合は仕事ではほとんどPythonを書いているのですが、Pythonでのasync/awaitはやや手順が面倒です。他の言語でも似たりよったりでしょうか。
非同期処理が得意なプログラミング言語、それがGo!
ところが、そんなめんどくさい非同期処理を簡単に実現してしまうプログラミング言語が存在するんです。
それは、言わずとしれたGoogle製、Goですね!
場合によっては、『Go言語』とか『GoLang』などとも呼ばれています。検索する場合はそうしないと全然別のものが引っかかってしまいそうですし。。
今回はそのGoを使用して、どのように非同期処理を書いていくかを紹介していきます。
続きを読む