Home
戻る
ニューラルネットの基本原理と使い方
気晴らしにみょんな話だが最近得た理系知識をHPにUPするという趣味が加わった。
今回はニューラルネットと呼ばれるアルゴリズムについて簡単にまとめてみた。
1.ニューラルネットとは?
ニューラルネットは人間の知能と同程度の働きができないかと考えられた手法の一つである。これは学習と呼ばれる機能によって知能を獲得し、正しい答えを導くアルゴリズムである。
ニューラルネットは生物の神経系の特徴的な機能に着目してモデル化を行ったものである。生物の神経系は多数のニューロンによって結合されそれぞれが並列処理を行っている。各ニューロンの大まかな構造は入力端子、出力端子、本体で成り立っている。各ニューロンの入力端子はシナプスを通じて他のニューロンから電気信号を受け取り信号を受け取ったニューロンがとある一定のしきい値を超えるとニューロンが興奮、発火し出力が変化する。これをモデルで表すと(1)のような式が導き出せる。
xjはニューロンjからの信号、Wijはニューロンjからニューロンiへの重み、θiはニューロンiのしきい値をそれぞれ表している。更に1[x]はx≧0のとき1、それに達しない時0となる単位ステップ関数を表している。ただ実際にこのモデルで何らかの計算を行う場合、後のバックプロパゲーションにおいて微分計算を容易にするため、実際には(2)のようなシグモイド関数を用いることが多い。
(1)はニューロンjから伝わった信号xj(t)が重み付けられて加算されニューロンiに達
しそれがあるしきい値を超えるとニューロンiが興奮することを意味している。一言でいうと各ニューロンから伝わった電気信号の総和によって一定のしきい値に達すればそのニューロンが興奮、出力が変化するということである。この様子をモデル図で表すと図1のようになる。これを幾つも結合することでニューラルネットのモデルを作ることが可能となる。一般的には入力ユニットから出力ユニットまで全て順方向のみに結合されているニューラルネットモデル、階層構造ニューラルネットが用いられている。この方法を多層パー
セプトロンと呼んでいる。これらのニューラルネットモデルを用いることで各種予測やパターン分類が可能となる。
図1.出力計算のモデル図
2.多層パーセプトロン
多層パーセプトロンを大雑把に図で表すと図2のようになる。
図2.多層パーセプトロン
一般的には中間層の数は入力層の2倍以下の数が良いといわれている。各層同士ではそれぞれ重みを設定する必要がある。入力層に適当な入力信号を入れ、重みの値によって各層の出力が決まり、最終的に出力層の出力から予測などを行う。よって重みを如何に決めるかが重要である。
主に教師なし学習と呼ばれる方法では理想とする出力を用意し実際の出力との二乗誤差の総和が小さくなるよう重みを修正する。その総和Eは(3)式のように表せる。yi(M)はM層(出力層)の出力、diは理想出力とする。この重みを修正する基本的な方法としてバックプロパゲーションと呼ばれる方法がある。
3.バックプロパゲーション
評価関数Eの値を小さくするために重み係数に関する偏微分∂E/∂wij(m)を求める。この値が正の値をとると定性的には重みwij(m)を少し増やと誤差Eが増えることを意味し、その逆に負の値をとることはこの重みを増やすと誤差Eが現象することを意味する。従って重み係数は以下の修正式(4)で更新していく。
ここでnは学習サイクルを表すパラメータでありこれが大きい程、収束速度は速くなる。これは経験的に決める必要がある。この偏微分を具体的に計算するには式の算出過程は省くが(5)〜(10)で求めることができる。(5)〜(7)は出力層ユニットへの重みに関する偏微分の計算、(8)〜(10)は中間層ユニットへの重みに関する偏微分の計算を表す式である。中間層ユニットへの重み計算は出力層に近い中間層から入力層に向けて逆方向に計算を行う。尚、それぞれの式における重み係数の添え字i、j、kは出力層(M層)、M−1層、M−2層のユニットを代表するものと考えること。またしきい値は常に1を出力するユニットy0(m) として表現することとする。
・出力層ユニットへの重み計算
・中間層ユニットへの重み計算
重みを修正し終えたら再度入力層から出力層に向かって各ユニットの出力を出す。十分にEの値が小さくなるまで行う。
これらは学習データが単体である場合である。一般的には学習データは複数あるためその場合について考える。学習データがL組あった場合、2乗誤差の総和Eは(11)のようになる。
この時、Eの各層の重み係数に関する偏微分は次のように各学習データの組に対する偏微分の和として(12)のように求められる。
各学習データに対する偏微分を(5)〜(10)のように計算し、全学習データにわたって総和をとってから(4)を適用して重み係数を更新することでEを減少させることができる。
またこれとは別に各学習データの出力が満足する出力を得られたら次のデータに移る逐次修正法もあるが一般的には(11)、(12)を用いた一括修正法を行うことが多い。
バックプロパゲーションは大域的な最小値を見つけるのが困難であり仮に二乗誤差が下がっても正しい出力を出すのは難しいことがある。これを解決するためにランダム探索法という方法がある。
バックプロパゲーションは高速計算にも向いているがいくつかの問題点を持っている。例えば重みの初期値によってはE(W)の大域的最小値(最小値)に収束せず局所的最小値(極小値)に収束してしまう。この解決法についてはいろいろなものが考えられており、ランダム探索法を利用したニューラルネットの学習などがある。これはEX−ORの問題でもその有効性を確認できる。
4.Matyasのランダム探索法
この方法はコンパクト集合上で大域的最小値を見出すという優れた性質を持つ。その基本アイデアは現在の点を中心として乱数(一般に正規分布)を発生し、生成された点における総誤差関数(二乗誤差E(W)のこと)の値と現在の点におけるその値とを比較し、前者の方が優れていれば(E(W)が小さければ)生成された点に移る。もし改良されなければ現在の点に留まるという方法である。そのアルゴリズムは以下のように行われる。
・Matyasのランダム探索法のアルゴリズム
[1]探索回数(学習回数)Mと探索領域Wを決める。初期点(重み)W(0)をランダムに決定し、k=0(現在の学習回数)とおく。
[2]正規性ランダムベクトルξ(k)を発生する。
ならば[3]へ、
ならば[4]へ飛ぶ。
[3]
もし
ならば
もし
ならば
[4]もしk=Mならば探索を打ち切る、そうでなければk=k+1とし[2]に戻る。以下繰り返し。
Matyasのランダム探索法は大域的最小値を見出すという優れた特性を持っている反面、収束スピードはやや遅い。だが通常のバックプロパゲーションよりも容易でありかつ正しい学習を行うことができる。
5.XORの学習を行うプログラム例
ニューラルネットの簡単なプログラムとしてXORの出力が正しい解答を出すように学習を行う。そのためのプログラムをMATLABで作り以下に示した。図3のようなXORの入出力を表すのには入力列が2つ、理想出力列が1つ必要となるため入力層2、出力層1とし中間層は3で指定した。
図3.XORにおける入出力
学習プログラムはMatyasのランダム探索法を使用した。その他の条件はプログラム内で示す。
・Matyasのランダム探索法を用いたXORの学習プログラム
% 入力信号 y(k,m,j) kは入力種類の数, jは入力数, 変更可
% 期待出力 d(k,s) kは入力種類の数, sは出力数, 変更可
% 重みデータはw(m,i,j)と定義する. mは階層
% ファイルからデータを読み込む形式とする. 入力情報とするものを入力させる. risouは理想出力とする.
% XORの学習を行うため図3の内容をy1.txt y2.txt risou.txtにテキスト形式で情報を用意しておく.
date1=load('y1.txt');
date2=load('y2.txt');
risoudate=load('risou.txt');
kk=length(risoudate); % kkは学習パターン数, 学習データの数
% データ設定
ii=2; % 入力層の層の数, 変更可
ss=1; % 出力層の層の数, 変更可
mi=3; % 中間層の層の数, 変更可
mm=1; % 中間層の数, 通常1, 変更可
mm=mm+1; % 実際の重みは中間層の数分と出力層の分だけあるため一つ増やす必要がある.
jj=ii; % iiと同じ
mj=mi; % miと同じ
gaku=0; % 学習回数
zyougen=30000; % 学習回数の上限:適当に定める.
saishou=0.005; % 二乗誤差の目標最小値
for k=1:kk;
y(k,1,1)=date1(k);
y(k,1,2)=date2(k);
d(k,1)=risoudate(k);
end
% 重み(結合強度)の初期値をランダムに決定する. (-1から1)
if(gaku==0);
for i=1:mi; % 入力層
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w0(1,i)=tmp; % w0はしきい値
for j=1:jj;
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w(1,i,j)=tmp;
end
end
for m=2:(mm-1); % 中間層
for i=1:mi;
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w0(m,i)=tmp;
for j=1:mj;
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w(m,i,j)=tmp;
end
end
end
for s=1:ss; % 出力層
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w0(mm,s)=tmp;
for j=1:mj;
tmp=100;
while(tmp<(-1)||1<tmp);
tmp=randn;
end
w(mm,s,j)=tmp;
end
end
end
% 演算開始. con(k,s)が出された出力とする. 1[x]はシグモイド関数を用いる.
if(gaku==0);
E=1;
end
while(E>=saishou&&gaku<zyougen);
gaku=gaku+1;
for k=1:kk;
for i=1:mi;
tmp=0;
for j=1:jj;
tmp=tmp+w(1,i,j)*y(k,1,j);
end
tmp=tmp-w0(1,i);
y(k,2,i)=1/(1+exp(-tmp));
end
for m=2:(mm-1);
for i=1:mi;
tmp=0;
for j=1:mj;
tmp=tmp+w(m,i,j)*y(k,m,j);
end
tmp=tmp-w0(m,i);
y(k,m+1,i)=1/(1+exp(-tmp));
end
end
for s=1:ss;
tmp=0;
for j=1:mj;
tmp=tmp+w(mm,s,j)*y(k,mm,j);
end
tmp=tmp-w0(mm,s);
con(k,s)=1/(1+exp(-tmp));
end
end
% 二重誤差を算出し出力する.
tmp=0;
for k=1:kk;
for s=1:ss;
tmp=tmp+(con(k,s)-d(k,s))^2;
end
end
E=tmp/(2*kk*ss);
% ランダム探索法を実施.
if(gaku==1); % 探索領域を決める. 最大数をdomah, 最小数をdomalとする.
domah=100; % 変更可
domal=-100; % 変更可
end
% Step1:正規性ランダムベクトルra, ra0を発生. (ra0はしきい値ベクトル) 探索領域に含まれるかどうかtanhanteiから検討. 含まれれば1, 含まれなければ0.
tanhantei=1;
for i=1:mi;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra0(1,i)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra0(1,i)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w0(1,i)+ra0(1,i);
if(tmp<domal||domah<tmp);
tanhantei=0; % 探索領域を超えれば探索しない.
end
end
for j=1:jj;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra(1,i,j)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra(1,i,j)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w(1,i,j)+ra(1,i,j);
if(tmp<domal||domah<tmp);
tanhantei=0;
end
end
end
end
for m=2:(mm-1);
for i=1:mi;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra0(m,i)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra0(m,i)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w0(m,i)+ra0(m,i);
if(tmp<domal||domah<tmp);
tanhantei=0;
end
end
for j=1:mj;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra(m,i,j)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra(m,i,j)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w(m,i,j)+ra(m,i,j);
if(tmp<domal||domah<tmp);
tanhantei=0;
end
end
end
end
end
for s=1:ss;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra0(mm,s)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra0(mm,s)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w0(mm,s)+ra0(mm,s);
if(tmp<domal||domah<tmp);
tanhantei=0;
end
end
for j=1:mj;
if(tanhantei==1);
tmp1=rand;
tmp2=rand;
tmp3=rand;
if(0.5<=tmp3);
ra(mm,s,j)=sqrt(-2*log(tmp1))*sin(2*pi*tmp2);
else
ra(mm,s,j)=sqrt(-2*log(tmp1))*cos(2*pi*tmp2);
end
tmp=w(mm,s,j)+ra(mm,s,j);
if(tmp<domal||domah<tmp);
tanhantei=0;
end
end
end
end
% Step2:ra,ra0を用いてE(w+ra)とE(w)を比較する. ただし探索領域に収まってる場合のみ行う. (tanhantei==1)
if(tanhantei==1);
for k=1:kk;
for i=1:mi;
tmp=0;
for j=1:jj;
wr(1,i,j)=w(1,i,j)+ra(1,i,j);
tmp=tmp+wr(1,i,j)*y(k,1,j);
end
wr0(1,i)=w0(1,i)+ra0(1,i);
tmp=tmp-wr0(1,i);
y(k,2,i)=1/(1+exp(-tmp));
end
for m=2:(mm-1);
for i=1:mi;
tmp=0;
for j=1:mj;
wr(m,i,j)=w(m,i,j)+ra(m,i,j);
tmp=tmp+wr(m,i,j)*y(k,m,j);
end
wr0(m,i)=w0(m,i)+ra0(m,i);
tmp=tmp-wr0(m,i);
y(k,m+1,i)=1/(1+exp(-tmp));
end
end
for s=1:ss;
tmp=0;
for j=1:mj;
wr(mm,s,j)=w(mm,s,j)+ra(mm,s,j);
tmp=tmp+wr(mm,s,j)*y(k,mm,j);
end
wr0(mm,s)=w0(mm,s)+ra0(mm,s);
tmp=tmp-wr0(mm,s);
conr(k,s)=1/(1+exp(-tmp));
end
end
tmp=0;
for k=1:kk;
for s=1:ss;
tmp=tmp+(conr(k,s)-d(k,s))^2;
end
end
Er=tmp/(2*kk*ss);
if(Er<E); % ランダムに生成された点の値の方が優れていればそちらに移る.
for i=1:mi;
w0(1,i)=wr0(1,i);
for j=1:jj;
w(1,i,j)=wr(1,i,j);
end
end
for m=2:(mm-1);
for i=1:mi;
w0(m,i)=wr0(m,i);
for j=1:mj;
w(m,i,j)=wr(m,i,j);
end
end
end
for s=1:ss;
w0(mm,s)=wr0(mm,s);
for j=1:mj;
w(mm,s,j)=wr(mm,s,j);
end
end
end
end
end
% 重みデータ表示
fprintf('\n\n');
fprintf('Eの重み=\n');
fprintf('1階層\n',m);
for i=1:mi;
fprintf('%4.7f ',w0(1,i));
for j=1:jj;
fprintf('%4.7f ',w(1,i,j));
end
fprintf('\n');
end
for m=2:(mm-1);
fprintf('%d階層\n',m);
for i=1:mi;
fprintf('%4.7f ',w0(m,i));
for j=1:mj;
fprintf('%4.7f ',w(m,i,j));
end
fprintf('\n');
end
end
fprintf('出力層\n');
for s=1:ss;
fprintf('%4.7f ',w0(mm,s));
for j=1:mj;
fprintf('%4.7f ',w(mm,s,j));
end
fprintf('\n');
end
fprintf('\n');
% 出力(結果)表示
fprintf('2乗誤差の総和Eは、%4.7f\n',E);
fprintf('合計学習回数=%d\n',gaku);
fprintf('\n');
for k=1:kk;
for s=1:ss;
fprintf('実際の出力=%4.7f 期待出力=%4.7f\n',con(k,s),d(k,s));
end
end
% 終了
このプログラムによってXORの出力結果は以下のようになった。
・結果表示
Eの重み=
1階層
9.1723411 -5.7203880 2.9181035
-4.8048182 -2.7155761 -3.3608050
-1.6481548 -8.1071963 -10.5790514
出力層
3.1219371 0.3048605 6.7424577 -7.7576944
2乗誤差の総和Eは、0.0049253
合計学習回数=494
実際の出力=0.0502043 期待出力=0.0000000
実際の出力=0.9115556 期待出力=1.0000000
実際の出力=0.9461260 期待出力=1.0000000
実際の出力=0.1617308 期待出力=0.0000000
重みは1階層の1行目は、それぞれ各入力層から中間層1への重みとなっている。左の値はしきい値である。2行目は無論各入力層から中間層2への重みと順に続く。出力層の重みの見方も同様である。
結果そのものはXORの期待出力に近いものが出てきた。
XOR以外の学習を行いたいならば最初の入力情報、理想出力情報、データ設定を変更するだけで行える。
**参考文献**
八名和夫, 鈴木義武著, “ニューロ情報処理技術,” pp.42-48, 1992
馬場則夫, 小島史男, 小澤誠一著,“ニューラルネットの基礎と応用,”pp.4-19, 1994