<まくら>
一時期はニューロやファジーが大ブームで、 白物家電にまでニューロファジーがついていました。 私は、冒頭で触れるようにこの時期に研究者人生を始めました [1]。 既にニューラルネットワークの研究を離れて久しいのですが、 今回は機会をいただきましたので、簡単な紹介をしたいと思います。
</まくら>
私が初めて卒業研究なるものを行ったのは、 奈良高専の5年生(1990年)のことでした。 当時ニューラルネットワーク(NN)は第2次のブームが華やかな頃でした。 この時期は、元々別の専門分野を持っている人が、 それなりに使える一手法としてNNを利用していた時期にあたります。 関西圏では千里中央でSYNAPSEというイベントがあり、 大物のNN研究者たちを招いての発表も行われていました。
私の高専での卒業論文の題目は 「時系列パターンを識別する自己組織化神経回路網に関する研究」です。 ここでは、リカレント型と呼ばれるネットワークを利用していました。 応用としては、主に音声認識を考えていましたが、 私はSENNと呼ばれるネットワークのインパルス応答などを調べていました [2]。
大学に入り、学部4回生もNN関係の研究室に配属になりました。 ここではKohnenの提案した自己組織化神経回路網(SOM)を用いて、 肝臓疾患の診断システムを構築するという課題が与えられました (「自己組織化神経回路網の医療データへの適用」)。 入力としては主成分であると言われているGPT,ChE,AlPという検査データを入力し、 疾患名だけや、疾患名と(アルコール性やウイルス性などの)病因を診断する システムを構築しました。 また、先輩が提案した時系列データを学習する拡張を用いて、 診断性能を上げる工夫なども行いました。 ここでは、Kohnenらのグループが用意しているSOM pack [3] を主な道具として、 UNIXをToolkitアプローチで利用しながら、仕事を進めていました。
修士1年では別のテーマを与えられて、またNNを利用しました。 問題は、 微分方程式を計算してコストのかかる計算を行うべきところを、 NNで高速に計算しようというものです。 ここでは、 一般的なバックプロバゲーションを用いた多層ネットワークを利用したですが、 微分方程式を解くのであればリカレント型のネットワークが有効だろうと考え、 これとの比較などを行いました。 この当時は、PlaNetという グラフィカルなUIを持ったアプリケーションをバッジ的に利用しながら、 研究を進めていました。 リカレントネットワークに関しては、 自作のC言語のプログラムで計算を行いました。
これ以降はNNに直接は関わっていなかったのですが、 たまにNNの応用で面白そうなものを見るとチェックしたりはしていました。 特に、SOMの応用は興味深く見ていました。
私が行ってきた研究は全てSunOSの上でやったもので FreeBSDとは関係ありませんが、 現状のFreeBSD 5.1Rで動作可能なNNのソフトウエアを紹介したいと思います。
ここでは、ニューラルネットワーク(NN)について非常に簡単に説明しておきます。 詳細に関しては様々な本が出ていますので、 自分にあった適切なものを参照してください。 特にWebでの情報に関しては、 Webページ[1]が参考になるでしょう。 私が学生時代に輪講で利用していた本は 参考文献[2]です。 詳細な証明がありますので、詳しく知りたい人にはお勧めできます。 なお、各アルゴリズムに特化した参考文献は適宜説明部分で紹介します。
簡単に歴史を振り返っておきます。 第一次のNNブームはAI華やかなりしころと重なっています。 この時、知能を作るには人間と同じ構造が必要であるとする コネクショニストが、パーセプトロンという入力層と出力層だけの2層構造の ネットワークで様々な研究を行っていました。 しばらくして、 パーセプトロンでは線形分離可能な問題だけしか学習できないことが証明されました。 中間層を持ったネットワークを学習するためには、 出力層では簡単に計算できる出力結果の誤差を、 どのようにして中間層に与えてやるのかが問題になりました。 これによって、第一次のNNブームは終焉を迎えます。 第二次ニューラルネットワークブームは、 後述するバックプロバゲーションによる多層ネットワークの学習則の提案、 Hopfiledネットワークの提案、 SOMの学習法の提案などが同じような時期におこり、 このころから始まりました。
ここでは、各種アルゴリズムの概略に関してのみ説明します。
NNでは、一般には人間の神経回路網をモデル化した単純なもので計算を行いますが、 詳細は各ネットワークの説明部分で述べます。
学習アルゴリズムの分類で大きな要素となるものに、 「教師」の有無があげられます。 「教師」とは、ある入力に対して望ましい出力のことです。
また、ネットワークの結合に関してみると、 入力から出力へと一方向にしか結合を持たないフィードフォワワード型と、 自分と同じ層やもっと手前の層に結合を持つリカレント型があります。 リカレント型のネットワークは入力が与えられた後も、 出力が時間の経過に伴って変化します。 リカレントネットワークの構成方法や入力によっては、 最終的に出力が定常状態で安定するものもあります。
バックプロパゲーションは、 おおざっぱに言うと誤差をネットワークを逆向きに伝搬してやることで、 中間層でも誤差に相当する値を計算できるように改良した 学習アルゴリズムです。 このようなアルゴリズムでは、 ネットワークは学習データ群での誤差を減らす方向に更新されていきます。 丁度、ボールが谷を転がっていくよう [4]に、 その場所でのもっとも誤差を減らせる方向、 つまり一番坂のきつい方向を目指してネットワークの誤差が減っていきます。 この時、高さは誤差の大きさを表し、 小さいほど学習データ群に対する誤差が少ないことになります。
誤差の逆伝搬を計算するためには、 出力関数f(x)が微分可能なことが要求されるため、 出力関数には以下のようなシグモイド関数が使われます (図0)。
1 f(x)=--------- 1+exp(-x)
バックプロパゲーションなどの多層ネットワークでは、 入力で与えられた値(ai)に 重み(wi)という値を掛けた値が入力として、 ユニットjに与えられます(図. 図0)。 ユニットjではそれらの値を全て足しあわせます。 その後、出力関数を適用した値を出力Outjとします。
Outj=f(Σai*wij)
先ほど、坂の急な方向を下るという話をしましたが、 坂の急な方向を下っても、浅い谷と深い谷がある場合は、 必ずしも最適解に相当する深い谷に降りれるとは限りません。 これを解消するために、 慣性項というボールが転がる勢いを付加する方法などの 様々な工夫が考えられています。
バックプロバゲーションでは、 入力層、出力層、中間層2層の4層構成で 中間層の数が自由に選べる場合、 任意の学習データの学習が可能であることが証明されています。
Hopfieldによるホップフィールドネットワークは、 1層のリカレント型ネットワークです。 はじめに、問題が解けたときに最小になるような方程式(エネルギー方程式) を立てます。 全ての制約条件はこの式に盛り込まなければなりません。 この式から、重みを決定するための標準的な形に変形をしていきます。 ここで決まった重みは、2つのユニットi,jに対して対称(同じ値)になります (wij=wji)。
このネットワークに入力を与えると、 リカレント型となっているため出力が時間変化をしたあとで、 エネルギー方程式で最小となる値に遷移します。
学習というイメージとは少し違いますが、 巡回セールスマン問題(Traveling Salesman Problem,TSP)などを 解くことができます。
Kohonenの自己組織化マップ(Self Organizing Map,SOM)は、 多次元ベクトルを入力として取り、 そのベクトルとの距離がもっとも近いユニットが勝者となるネットワークです。 各ユニットは入力データと同じ次元のベクトルを持ち、 距離は数学的な距離をそのまま利用することができます。 出力ユニットは1次元や2次元などに並べられ、 こちらもユニット間で近傍関係が定義されています。 SOMの概念図を図0図3に示します。
SOMにおける学習の詳細は SOM packのドキュメント(2 The principle of SOM)や SNNSのドキュメント(9.14.1 SOM fundamentals)を参照して下さい。 日本語では参考文献[3]が 良いでしょう。 学習に関しての証明などの詳しく知りたい場合は、 Kohonen自らが書いた本が邦訳されています[4] ので、こちらを参照してください。 ここでは、SNNSのドキュメントにしたがって、概略だけを紹介します。
各出力ユニットの持つ n次元ベクトル(Wjまたは、wij)を 正規化した上で、ランダムに初期化します。 図0図3の状態が初期状態と考えてください。
以下の学習サイクルを全ての学習データに対して、 必要な回数繰り返します。 学習回数をtで表します。
学習用のデータを入力します。 各ユニットjの出力Netj(t)は、 ベクトルが正規化されている場合、 内積計算で以下のように求まります。
Netj(t)= X・Wj=Σi=1nxi(t)wijこの時、もっとも学習データに近い出力ユニットcが勝者として選ばれます。 これは以下の式で与えられます。
Netc(t)= maxj{Netj(t)}=X・Wc
勝者として選ばれた出力ユニットcと その近傍の出力ユニットの持つ内部ベクトルを、 入力として与えられた教師データのベクトルに近づけます。
Δwij = ej(t)・(xi(t)-wij(t) for j in Nc Δwij = 0 not in Ncただし、
ej(t)=h(t)exp(-dj/r(t))2 (ガウシアン関数) dj: 勝者出力ユニットWcと出力ユニットWjとの間の、ユニット空間での距離。 h(t): 学習データXに適応させる度合い。0<=h(t)<=1で、時間の経過とともに大きい値から減らされていきます。 r(t): 学習対称とする出力ユニット空間での近傍の大きさ(半径)。これも時間の経過とともに減らされていきます。ej(t)の中身を良く見ると分かりますが、 学習初期には、h(t)とr(t)を大きくしておくことで、 ほとんど全てのユニットが学習ベクトルXに近づけられます。 これで大まかな配列が決まったあと、 この値が減少していくことで、 必要な場所だけを詳細に学習することになります。
FreeBSD portsには、NN関係のソフトウエアは5つしか入っていません。 全ては、ports/mathカテゴリに分類されています。
このうち、SNNSファミリー [5] (math/{snn,javasnn}) は、汎用のシミュレータになっています。
Perlモジュールには、math/p5-AI-*という名前で、 3つ入っています。 これらの内容の概略は以下の通りです。 今回はこれらについては説明しません。 詳細はマニュアルを参照してください。
math/p5-AI-Perceptron: パーセプトロンを実現するためのモジュールです。
パーセプトロンには致命的な限界がありますので、 利用することはほとんどないでしょう。
p5-AI-NeuralNet-BackProp: バックプロパゲーションを実現するためのモジュールです。
文字列をそのまま学習パターンにできるなど、 面白い機能が実装されています。
手元で実験したのですが、 3000程度の学習でデータでも膨大なメモリを要求する実装となっているようで、 あまり実用的とは思えませんでした。
math/p5-AI-NeuralNet-Mesh: ニューラルネットワークのメッシュを実現するためのモジュールです。 p5-AI-NeuralNet-BackPropと作者がおなじため、 インタフェースは似ています。
こちらも手元で実験したのですが、 マニュアルに書いてある通りに実装しても非線形分離が必須な XORが学習できなかったりでした。 これは、私が十分に利用方法を理解できていないせいも大きいと思います。
いずれにせよ、portsやpackagesからインストールするだけで準備は終わります。
今回は、C版のSNNSを利用することにします。 詳細なドキュメントがWebページから入手可能ですので、 これを入手してください。 手元にあるのはVersion4.2用ですが、345ページもあります。 まずは、Chapter 4を読みながら利用方法を確認してください。 例題は、FreeBSD port/packageでは、 /usr/local/snns/examples/に インストールされています。
今回はSOMを用いた学習の例題をやってみましょう。 これは、3次元のキューブの頂点を2次元にマップする例題です。 まず、例題のあるディレクトリでSNNSを起動します。
% cd /usr/local/snns/examples/ % snns画面にCopyrightを表示するバナーと管理パネル(図0図4)が表示されます。 前者はマウスで左クリックすることで、消去できます。
管理パネルから[FILE]を押し、 ファイルブラウザパネルを表示します (図0図5)。 ここから[NET]を押し、 ネットワーク定義ファイルsom_cube.netを選択します。 拡張子は表示されないので注意してください。 更に、[PAT]を押し、 som_cube.patを読み込みます。 ネットワークや設定などの保存もここから行えます。 不要になったら[DONE]を押して消すこともできます。
管理パネルで、[DISPLAY]を押すと、 作成したネットワークが表示されます(図0図6)。
管理パネルから[CONTROL]を選び、 制御パネルを表示します(図0図7)。 学習やテストなどは、全てこのパネルから制御されます。
まず、ネットワークをランダムに初期化するために 制御パネルの[INIT]を押します。
試しに読み込んだパターンをテストするためには、 制御パネルの[TEST]を押してください。 PATTERN部分の数字がインクリメントされていき、 次々にネットワークの状態を観察できます。 はじめに読み込んだネットワークデータは既に学習が行われていますが、 初期化したためネットワークの活性部分はランダムに分布しています (図0図6)。
学習のためのパラメータを設定します。 これは、制御パネルのLEARN部分に与えます。 それぞれ、 h(0),r(0), hの減衰定数Δh(h(t+1)=Δh×h(t)),rの減衰定数Δr(r(t+1)=Δh×r(t)), ネットワークのx方向の大きさです。 更に、学習回数をCYCLEに与えます。 ここでは、図0図7のように与えました。
学習は[ALL]を押します。 [CYCLES]が1の場合は一度だけ学習が行われ、 学習パラメータのh(t),r(t)が更新されていきます。 ここが0になった場合は学習が行われません。
学習されたネットワークは図0図8のようになります。 少し分かりにくいですが、3次元のキューブの頂点を全て覆うように、 2次元の出力ユニットが広がっているのが分かります。
ニューラルネットワークは、問題解決の一手法として試してみる価値のある方法です。 しかし、統計学習などが使え、 環境も不変の場合などはそちらを使った方がいいかも知れません。 また、遺伝的アルゴリズムや強化学習などの手法もありますので、 自分に適した技法を利用することが重要です。
神戸大学の小澤 誠一先生@神戸大学大学院自然科学研究科/工学部電気電子工学科には、 最近利用されている汎用ツールとして、 PDP++(http://www.cnbc.cmu.edu/Resources/PDP++/PDP++.html)と Lens(http://www.cs.cmu.edu/~dr/Lens)をご紹介いただきました。 今回、記事にできなかったのは私の怠惰によるもので、申し訳ありませんでした。
[1] 私のブックマーク:ニューラルネットワーク (http://www.ai-gakkai.or.jp/jsai/journal/mybookmark/17-2.html , 村田 昇, 人工知能学会誌, vol.17, no.2, (2002).
[1] | ちなみに、今は既にリタイア状態です(;-;) |
[2] | というより、3Dグラフ作成プログラムに熱中していました;-) このあたりの詳しい話は、FreeBSD Press No.8の「私とBSD」を参照下さい。 |
[3] | |
[4] | これは、現実には慣性が存在するので厳密ではありません。 瞬間瞬間で速度が0に戻される状態を想定してください。 |
[5] |