Main Content

学習ベクトル量子化 (LVQ) ニューラル ネットワークの学習

アーキテクチャ

LVQ ネットワーク アーキテクチャは以下のとおりです。

Schematic of a Learning Vector Quantization network, where an input vector p is passed to a competitive layer which calculates an intermediate value a1 which is passed to a linear layer that calculates an output a2.

LVQ ネットワークには、1 つ目の競合層と 2 つ目の線形層があります。競合層は、このトピックで説明した自己組織化マップ ニューラル ネットワークによるクラスター化の競合層とほぼ同じ方法で入力ベクトルの分類を学習します。線形層は、競合層のクラスをユーザーが定義したターゲットの分類に変換します。競合層が学習したクラスを "サブクラス"、線形層のクラスを "ターゲット クラス" と呼びます。

競合層と線形層はどちらにも (サブまたはターゲット) クラスごとに 1 つのニューロンがあります。したがって、競合層は最高で S1 個のサブクラスを学習できます。次に、これらは線形層によって結合され、S2 個のターゲット クラスが形成されます (S1 は常に S2 より大きくなります)。

たとえば、競合層内のニューロン 1、2、3 のすべてが、線形層のターゲット クラス 2 に属する入力空間のサブクラスを学習するとします。その場合、競合ニューロン 1、2、3 は、線形層のニューロン n2 に対する重み LW2,1 が 1.0、その他のすべての線形ニューロンに対する重みが 0 になります。したがって、この 3 つの競合ニューロン (1、2、3) のいずれかが競合に勝って 1 を出力した場合、その線形ニューロンは 1 を生成します。このようにして、競合層のサブクラスは線形層のターゲット クラスに結合されます。

つまり、a1i 番目の行の 1 は (a1 の残りの要素は 0)、実質的に LW2,1i 番目の列をネットワーク出力として選択します。このような列には、特定のクラスに対応する 1 が 1 つ含まれます。したがって、層 1 のサブクラス 1s は、層 2 で LW2,1a1 を乗算することによってさまざまなクラスに分類されます。

層 1 のニューロンをどのくらいの割合で層 2 の各クラス出力に分類すべきかを前もって知っているので、開始時に LW2,1 の要素を指定できます。ただし、学習セットの各ベクトルに対して正しいサブクラスの出力を生成するには、学習手順を行って最初の層を取得しなければなりません。この学習については、学習で説明されています。まず、元のネットワークの作成方法を考えます。

LVQ ネットワークの作成

LVQ ネットワークは関数 lvqnet を使用して作成できます。

net = lvqnet(S1,LR,LF)

ここで、

  • S1 は最初の層の隠れニューロンの数。

  • LR は学習率 (既定は 0.01)。

  • LF は学習関数 (既定は learnlv1)。

10 個の入力ベクトルがあるとします。これらの各入力ベクトルを 4 つのサブクラスのうちの 1 つに割り当てるネットワークを作成します。したがって、最初の競合層に 4 個のニューロンがあります。これらのサブクラスは、層 2 の 2 個のニューロンによって 2 つの出力クラスのうちの 1 つに割り当てられます。入力ベクトルとターゲットは、以下で指定されます。

P = [-3 -2 -2 0 0 0 0 2 2 3; 0 1 -1 2 1 -1 -2 1 -1 0];

Tc = [1 1 1 2 2 2 2 1 1 1];

これらの 2 行のコードから得られる内容の詳細を表示すると役に立つことがあります。

P,Tc
P =
    -3    -2    -2     0     0     0     0     2     2     3
     0     1    -1     2     1    -1    -2     1    -1     0
Tc =
     1     1     1     2     2     2     2     1     1     1

入力ベクトルのプロットは以下のとおりです。

Plot of input vectors P where vectors belonging to output class one are plotted with a square marker and vectors belonging to output class 2 are plotted with a cross marker.

ご覧のように、入力ベクトルの 4 つのサブクラスがあります。ネットワークが p1p2p3p8p9p10 を分類して 1 を出力し、ベクトル p4p5p6p7 を分類して 2 を出力するようにします。この問題は線形分離が可能でないため、パーセプトロンで解くことはできませんが、LVQ ネットワークでは難しくありません。

次に、行列 Tc をターゲット ベクトルに変換します。

T = ind2vec(Tc);

こうして得られるスパース行列 T は、次を使用して全体を表示できます。

targets = full(T)

次の結果が得られます。

targets =
     1     1     1     0     0     0     0     1     1     1
     0     0     0     1     1     1     1     0     0     0

これは正しいようです。つまり、たとえば、P の最初の列を入力とした場合、targets の最初の列が出力となります。この出力は、入力がクラス 1 に正しく分類されることを示します。これで lvqnet を呼び出す準備が整いました。

lvqnet を呼び出して、4 個のニューロンを持つネットワークを作成します。

net = lvqnet(4);

関数 midpoint で、最初の層の重み行列の初期値が入力データ範囲の中央の値に初期化されるように構成して確認します。

net = configure(net,P,T);
net.IW{1}
ans =
     0     0
     0     0
     0     0
     0     0

2 番目の層の重みは、その列の 60% (Tc の 10 個のうち 6 個) は 1 行目 (クラス 1 に対応) に 1 にあり、その列の 40% は 2 行目 (クラス 2 に対応) に 1 があることを確認します。4 列しかないので、60% と 40% は実際には 50% に丸められ、各行に 1 が 2 つずつあります。

net.LW{2,1}
ans =
     1     1     0     0
     0     0     1     1

これも理に適っています。競合層が 1 番目の要素として 1 を出力する場合、入力ベクトルはクラス 1 として分類されることを示します。2 番目の要素として 1 を出力する場合はクラス 2 です。

最初の 2 つの競合ニューロンは 1 番目の線形ニューロン (重みが 1) に結合され、2 番目の 2 つの競合ニューロンは、2 番目の線形ニューロンに結合されることがわかります。競合ニューロンと線形ニューロンの間のその他の重みはすべて値が 0 になります。したがって、2 つのターゲット クラス (線形ニューロン) のそれぞれは、実際に 2 つのサブクラス (競合ニューロン) の結合になります。

sim を使用してネットワークをシミュレーションできます。元の行列 P を入力として使用して、結果を確認します。

Y = net(P);
Yc = vec2ind(Y)
Yc =
     1     1     1     1     1     1     1     1     1     1

ネットワークはすべての入力をクラス 1 に分類します。これは望ましいものではないため、良い結果を得るために、(層 1 の重みのみを調整して) ネットワークの学習を行わなければなりません。次の 2 つの節では、2 つの LVQ 学習規則と学習プロセスについて説明します。

LVQ1 学習規則 (learnlv1)

競合層における LVQ 学習は、一連の入力/ターゲットのペアを基本とします。

{p1,t1},{p2,t2},{pQ,tQ}

各ターゲット ベクトルには、1 が 1 つあります。残りの要素は 0 です。1 は関連する入力が適切に分類されたことを示します。たとえば、次の学習ペアを考えます。

{p1=[210],t1=[0010]}

ここでは、3 要素から成る入力ベクトルがあり、各入力ベクトルは 4 つのクラスのうちの 1 つに割り当てられます。ネットワークは、上記の入力ベクトルを 4 つのクラスの 3 番目に分類するよう学習します。

ネットワークに学習させるために、入力ベクトル p が与えられ、p から入力重み行列 IW1,1 の各行までの距離が関数 negdist によって計算されます。層 1 の隠れニューロンが競合します。n1 の i 番目の要素が最も大きい正の値で、ニューロン i* が競合に勝つとします。このとき、競合伝達関数は、a1 の i* 番目の要素として 1 を生成します。a1 のその他すべての要素は 0 です。

a1 に層 2 の重み LW2,1 を乗算すると、a1 の 1 つの 1 は、入力に関連するクラス k* を選択します。したがって、ネットワークは入力ベクトル p をクラス k* に割り当て、α2k* は 1 になります。もちろん、入力がクラス k* に属するかどうかによって tk* は 1 または 0 になるため、この割り当ては正しい場合もそうでない場合もあります。

IW1,1 の i* 番目の行を調整します。割り当てが正しい場合はこの行を入力ベクトル p の近くに移動し、割り当てが正しくない場合は p から行が離れるように移動します。p が正しく分類された場合、

(αk2=tk=1)

次のように IW1,1 の i* 番目の行の新しい値を計算します。

IiW1,1(q)=IiW1,1(q1)+α(p(q)IiW1,1(q1))

一方、p が正しく分類されなかった場合は、

(αk2=1tk=0)

次のように IW1,1 の i* 番目の行の新しい値を計算します。

IiW1,1(q)=IiW1,1(q1)α(p(q)IiW1,1(q1))

IW1,1 の i* 番目の行のこのような修正は、出力誤差の層 1 への逆伝播によって、IW1,1 の他の行に影響を与えずに自動的に行われるようにすることができます。

このような修正により、隠れニューロンは、サブクラスを形成するクラスに分類されるベクトルの方向に移動し、他のクラスに分類されるベクトルから離れる方向に移動します。

LVQ ネットワークの層 1 の重みのこのような変更を実装している学習関数は learnlv1 です。これは学習中に適用できます。

学習

次に、入力ベクトルの分類が正しく行われるような最初の層の重みを求めるために、ネットワークが学習する必要があります。これは、以下のコマンドを使用して train で実行します。最初に学習エポックを 150 に設定します。その後 train を使用します。

net.trainParam.epochs = 150;
net = train(net,P,T);

ここで、最初の層の重みを確認します。

net.IW{1,1}
ans =
    0.3283    0.0051
   -0.1366    0.0001
   -0.0263    0.2234
         0   -0.0685

次のプロットは、これらの重みがそれぞれの分類グループに移動したことを示しています。

Plot of the weights overlaid on the input vectors.

これらの重みによって実際に正しい分類が行われることを確認するために、行列 P を入力として使用してネットワークをシミュレーションします。その後、ネットワークがどのような分類を生成したかを確認します。

Y = net(P);
Yc = vec2ind(Y)

次の結果が得られます。

Yc =
     1     1     1     2     2     2     2     1     1     1

これは期待どおりになっています。最後の確認として、学習で使用したベクトルに近い入力を試します。

pchk1 = [0; 0.5];
Y = net(pchk1);
Yc1 = vec2ind(Y)

次の結果が得られます。

Yc1 =
     2

pchk1 は 2 に分類される他のベクトルに近いため、これは正しいようです。同様に、

pchk2 = [1; 0];
Y = net(pchk2);
Yc2 = vec2ind(Y)

により以下が得られます。

Yc2 =
     1

pchk2 は 1 に分類される他のベクトルに近いため、これも正しいようです。

サンプル プログラム学習ベクトル量子化を試してみることをお勧めします。これは上記の学習の説明に沿ったものです。

補足的な LVQ2.1 学習規則 (learnlv2)

以下の学習規則は、最初に LVQ1 を適用した "後" に適用される場合があります。これにより、最初の学習結果を改善できることがあります。この特定のバージョンの LVQ2 (参考文献 [Koho97] では LVQ2.1 と呼ばれています) は、関数 learnlv2 に組み込まれています。繰り返しになりますが、LVQ2.1 は LVQ1 の適用後にのみ使用されることに注意してください。

ここでの学習は learnlv2 と似ていますが、入力ベクトルに最も近い層 1 における 2 つのベクトルは、1 つが正しいクラスに、もう 1 つが間違ったクラスに属していて、さらに入力がこれら 2 つのベクトルの中央平面の近くの "ウィンドウ" に入る場合に更新される点が異なります。

ウィンドウは以下で定義されます

min(didj,djdi)>s

ここで、

s1w1+w

(ここで、di および dj は、それぞれ i*IW1,1 および j*IW1,1 から p までのユークリッド距離です)。w の値は 0.2 から 0.3 までの範囲から選びます。たとえば 0.25 を選択すると、s = 0.6 になります。これは、2 つの距離比率の最小値が 0.6 より大きい場合、2 つのベクトルが調整されるという意味です。つまり、入力が中央平面の近くにある場合、入力ベクトル pj*IW1,1 が同じクラスに属し、pi*IW1,1 が同じクラスに属していないという場合にも、2 つのベクトルが調整されます。

次のように調整されます。

IiW1,1(q)=IiW1,1(q1)α(p(q)IiW1,1(q1))

IjW1,1(q)=IjW1,1(q1)+α(p(q)IjW1,1(q1))

したがって、入力に最も近い 2 つのベクトルは、1 つが間違ったクラスに、もう 1 つが正しいクラスに属していて、さらに入力が中央平面ウィンドウに入る場合に調整されます。このような手順によって、LVQ1 を使用してかろうじて正しく分類されたベクトルを、より入力に近づけることができるため、結果がさらにロバストになります。

関数

説明

competlayer

競合層を作成。

learnk

Kohonen 学習規則。

selforgmap

自己組織化マップを作成。

learncon

良心的バイアス学習関数。

boxdist

2 つの位置ベクトルの間の距離。

dist

ユークリッド距離重み関数。

linkdist

リンク距離関数。

mandist

マンハッタン距離重み関数。

gridtop

グリッド層トポロジ関数。

hextop

六角形層トポロジ関数。

randtop

ランダム層トポロジ関数。

lvqnet

学習ベクトル量子化ネットワークを作成。

learnlv1

LVQ1 重み学習関数。

learnlv2

LVQ2 重み学習関数。