テストの実行

ニューラル ネットワークについての紹介

James McCaffrey

コード サンプルのダウンロード

James McCaffrey人工神経回路網 (通称、ニューラル ネットワーク) とは、生物学上のニューロン (神経細胞) とシナプス (神経細胞接合部とその構造) を大まかにモデル化する抽象概念です。ニューラル ネットワークは何十年も研究されてきましたが、インターネット上に公開されているニューラル ネットワークの多くのコード実装は、私の考えでは、あまりうまく説明されていません。今月のコラムでは、ニューラル ネットワークについて説明し、ニューラル ネットワークを実装する C# コードを紹介します。

何をしようとしているかは、図 1図 2 をご覧ください。ニューラル ネットワークについての 1 つの見方は、ニューラル ネットワークを、ある数値入力から別の数値出力に変換するメカニズムと考えることです。図 1 のニューラル ネットワークには、x0、x1、x2 というラベルが付き、値をそれぞれ 1.0、2.0、3.0 とする入力があり、y0 と y1 というラベルが付き、値がそれぞれ 0.72 と -0.88 となる出力があります。図 1 のニューラル ネットワークは、いわゆる非表示ニューロンという 1 つの層があり、3 つの入力、2 つの出力、および 4 つの非表示ニューロンを備えた、3 層完全接続フィードフォワード ネットワークと表すことができます。残念ながら、ニューラル ネットワークには多種多様な専門用語が使われます。今回は、ニューラル ネットワークに関する優れた FAQ (bit.ly/wfikTI、英語) に記載されている用語を使用するようにしていますが、必ずではありません。

Neural Network Structure図 1 ニューラル ネットワークの構造

Neural Network Demo Program

図 2 ニューラル ネットワークのデモ プログラム

図 2 は、今回紹介するデモ プログラムからの出力です。ニューラル ネットワークはアクティブ化関数として、シグモイド関数とハイパーボリック タンジェント (tanh: 双曲線正接) 関数の両方を使用します。図 1 では、これらの関数を、ギリシャ文字のファイ (Φ) を使用した 2 つの式で示しています。ニューラル ネットワークは、数値による重みとバイアスのセットを使用して出力を生成します。今回の例では、合計 26 セット (0.10、0.20、~-5.00 と続く値) の重みとバイアスがあります。重みとバイアスをニューラル ネットワークに読み込んだら、デモ プログラムは 3 つの入力値 (1.0、2.0、3.0) を読み込み、一連の計算を実行します。この計算は、出力例の "入力ニューロンから非表示ニューロンへの合計" (input-to-hidden sums) と "非表示ニューロンから出力ニューロンへの合計" (hidden-to-output sums) というメッセージに示すような過程で行います。デモ プログラムは、2 つの出力値 (0.72、-0.88) を表示して終了します。

ここからは、図 2 に示す出力を生成したプログラムを見ていきます。今回は、プログラミングについては中級程度のスキルが必要ですが、ニューラル ネットワークの知識はなくてもかまいません。デモ プログラムは C# 言語でコーディングしていますが、Visual Basic .NET や Python など別の言語にリファクタリングしても問題はありません。ここで紹介するプログラムは、基本的に、機能を試すためのチュートリアルおよびプラットフォームです。実際の問題を直接解決するのではなく、重要な問題を解決するためにコードを拡張する方法を説明します。ここに記載する情報に興味を持ち、価値を見出したら、そのプログラミング技法をコーディング スキルのセットに加えていただければさいわいです。

ニューラル ネットワークをモデル化する

概念的には、実際の生物学上の神経回路網の動作を基に、ニューラル ネットワークをモデル化します。図 1 の青い円は処理が行われるニューロンを表し、矢印は情報の流れと重みの数値を表します。多くの状況では、入力値は重みを加えることなく入力ニューロンに直接コピーされます。また、出力ニューロンからは処理することなく直接出力されます。したがって、最初の実際のアクションは非表示層のニューロンで行われます。ここで、入力値 1.0、2.0、3.0 が入力ニューロンから取り出されるとします。図 1 を見てみると、3 つの入力ニューロンと 4 つの非表示ニューロンの間に、重みの値を表す矢印があります。1 番上の非表示ニューロンに向かっている 3 つの重みの矢印にそれぞれ、w00、w10、w20 という名前を付けます。この命名法では、1 桁目のインデックスが入力元の入力ニューロンを、2 桁目のインデックスが出力先の非表示ニューロンを表します。ニューロンの処理は 3 手順で行います。まず、重みの合計を計算します。ここでは w00 = 0.1、w10 = 0.5、w20 = 0.9 となり、1 番上の非表示ニューロンの重みの合計は、(1.0)(0.1) + (2.0)(0.5) + (3.0)(0.9) = 3.8 になります。次に、バイアス値を加算します。バイアス値が -2.0 であれば、調整後の重みの合計は 3.8 + (-2.0) = 1.8 になります。最後に、調整後の重みの合計にアクティブ化関数を適用します。アクティブ化関数が、1.0 / (1.0 * Exp(-x)) で定義されるシグモイド関数 (Exp は自然指数関数を表します) だとすると、非表示ニューロンからの出力は、1.0 / (1.0 * Exp(-1.8)) = 0.86 になります。この出力が重みの合計の一部となり、出力層の各ニューロンに入力されます。図 1 では、この 3 手順をギリシャ文字ファイを使用した式で示しています。つまり、重みの合計 (xw) を計算し、バイアス (b) を加算して、アクティブ化関数 (phi) を適用します。

すべての非表示ニューロン値を計算したら、出力層のニューロン値を同じ方法で計算します。出力ニューロン値の計算に使用するアクティブ化関数は、非表示ニューロン値の計算に使用するのと同じ関数を指定することも、異なるアクティブ化関数を使用することもできます。図 2 に実行結果を示したデモ プログラムは、ハイパーボリック タンジェント関数を、非表示ニューロンから出力ニューロンへのアクティブ化関数として使用しています。出力層のすべてのニューロン値を計算したら、大半は、これらの値に重みを加えたり、処理したりしないで、ニューラル ネットワークの最終値として出力します。

内部構造

今回紹介するニューラル ネットワークの実装を理解する鍵は、図 3 を詳しく調べることです。一見、非常に複雑に見えるかもしれません。しかし、我慢して付き合ってください。じっくり見てみるとそれほど複雑ではありません。図 3 には、合計 8 つの配列と 2 つの行列があります。this.inputs というラベルを付けた最初の配列は、ニューラル ネットワークの入力値 (この例では、1.0、2.0、3.0) を保持します。その隣は、非表示層の値の計算に使用する重み値のセットです。重みの値は、i-h weights というラベルを付けた 3 x 4 の行列に格納します。i-h は input-to-hidden (入力ニューロンから非表示ニューロンへ) を表します。図 1 のデモ ニューラル ネットワークには 4 つの非表示ニューロンがあります。i-h weights 行列では、行数が入力数、列数が非表示ニューロン数に等しくなります。


Neural Network Internal Structure
図 3 ニューラル ネットワークの内部構造

i-h sums というラベルを付けた配列は、計算に使用する初期状態の配列です。i-h sums 配列の長さは、常に、非表示ニューロン数と同じです (この例では 4)。次が、i-h biases というラベルを付けた配列です。ニューラル ネットワークのバイアスは、非表示層ニューロンと出力層ニューロンの計算に使用する重みです。i-h biases 配列の長さは、i-h sums 配列の長さと同じで、非表示ニューロン数です。

i-h outputs というラベルを付けた配列は中間結果で、次の層の入力として使用します。i-h sums 配列の長さも非表示ニューロン数に等しくなります。

次は、h-o weights というラベルを付けた行列です。h-o は hidden-to-output (非表示ニューロンから出力ニューロンへ) を表します。h-o weights 行列のサイズは 4 x 2 で、4 つの非表示ニューロンと 2 つの出力ニューロンがあることを表しています。h-o sums 配列、h-o biases 配列、および this.outputs 配列の長さはすべて、出力ニューロン数 (この例では 2) と等しくなります。

図 3 の一番下の weights というラベルを付けた配列は、input-to-hidden (入力ニューロンから非表示ニューロンへ) および hidden-to-output (非表示ニューロンから出力ニューロンへ) のすべての重みとバイアスを保持します。今回の例では、重みの配列の長さは (3 * 4) + 4 + (4 * 2) + 2 = 26 です。一般に、Ni を入力値数、Nh を非表示ニューロン数、No を出力数とすると、重みの配列の長さは Nw = (Ni * Nh) + Nh + (Nh * No) + No になります。

出力を計算する

前述の 8 つの配列と 2 つの行列を作成したら、ニューラル ネットワークはその入力、重み、およびバイアスに基づいて、出力を計算します。まず、入力値を this.inputs 配列にコピーします。次に、重みの配列に値を代入します。このデモでは、好みの重み値を使用できます。次に、重み配列の値を i-h weights 行列、i-h biases 配列、h-o weights 行列、および h-o biases 配列にコピーします。図 3 がわかれば、この関係が明確になります。

i-h sums 配列の値は、2 手順で計算します。まず、入力配列値に、i-h weights 行列の列値を乗算し、重みの合計を計算します。たとえば、非表示ニューロン [3] (ここではゼロから始まるインデックスを使用しています) の重みの合計は、各入力値と、i-h weights 行列の列 [3] の値から、(1.0)(0.4) + (2.0)(0.8) + (3.0)(1.2) = 5.6 になります。次に、i-h sum 値を計算します。この計算では、各バイアス値を、現在の i-h sum 値に加算します。たとえば、i-h biases [3] の値は -7.0 なので、i-h sums [3] の値は、5.6 + (-7.0) = -1.4 になります。

i-h sums 配列のすべての値を計算したら、それらの合計に入力ニューロンから非表示ニューロンへのアクティブ化関数を適用して、出力値を生成します。使用できるアクティブ化関数は多数あります。最もシンプルなアクティブ化関数は、ステップ関数です。この関数は、ゼロを超えるすべての入力値には 1.0 を返し、ゼロ以下のすべての入力値には 0.0 を返します。よく使用するもう 1 つのアクティブ化関数が今回使用しているシグモイド関数で、f(x) = 1.0 / (1.0 * Exp(-x)) と定義されます。図 4 に、シグモイド関数のグラフを示します。

The Sigmoid Function図 4 シグモイド関数

シグモイド関数は、0 ~ 1 の範囲で値を返すことがわかります。今回の例では、バイアス値を加算後の i-h sums [3] の値が -1.4 なので、i-h outputs [3] の値は 1.0 / (1.0 * Exp(-(-1.4))) = 0.20 になります。

入力ニューロンから非表示ニューロンに出力されるニューロン値をすべて計算したら、それらの値を非表示ニューロン層から出力ニューロン層への入力に使用します。これらの計算は、入力ニューロンから非表示ニューロンで行った計算と同じです。暫定的な重みの合計を計算し、バイアスを加算してから、アクティブ化関数を適用します。今回は、非表示ニューロンから出力ニューロンへのアクティブ化関数に、ハイパーボリック タンジェント (tanh) 関数を使用しています。tanh 関数は、シグモイド関数と密接に関係しています。tanh 関数のグラフもシグモイド関数に似た S 字型のカーブを出力しますが、tanh 関数は、0~1 の範囲ではなく、-1~1 の範囲で値を返します。

重みとバイアスを組み合わせる

インターネット上で公開されているニューラル ネットワークの実装の多くは、重みとバイアスの配列を別に管理するのではなく、重みとバイアスを weights 行列に組み合わせています。どうしてこのようなことが可能なのでしょう。入力ニューロンから非表示ニューロンへのニューロン [3] の値の計算は、(i0 * w03) + (i1 * w13) + (i2 * w23) + b3 のようになります。i0 は入力値 [0]、w03 は入力 [0] からニューロン [3] への重み、b3 は非表示ニューロン [3] のバイアス値です。ここで新たに入力 [4] を作成し、この入力に、ダミー値 1.0 と、バイアス値を保持する重み用に行を追加する場合、上記の計算は、(i0 * w03) + (i1 * w13) + (i2 * w23) + (i3 * w33) になります。i3 はダミーの 1.0 という入力値で、w33 はバイアスを表します。つまり、この手法を使用すればニューラル ネットワークのモデルが簡潔になると考えられています。私はそうは思いません。私の意見では、重みとバイアスを組み合わせると、ニューラル ネットワーク モデルが理解しにくくなり、実装時にエラーが発生しやすくなります。ただし、この意見を持っているのが私だけかもしれないので、読者ご自身でこの設計上の決定を下すことをお勧めします。

実装

ここでは、Visual Studio 2010 を使用して、図 1図 2、および図 3 に示すニューラル ネットワークを実装する、NeuralNetworks という C# コンソール アプリケーションを作成しました。ソリューション エクスプローラーで、Program.cs ファイルを右クリックして、NeuralNetworksProgram.cs という名前に変更します。これにより、テンプレートが生成するクラス名も NeuralNetworksProgram に変更されます。ほとんどの WriteLine ステートメントを取り除いた状態の、プログラム構造全体を図 5 に示します。

図 5 ニューラル ネットワークのプログラムの構造

using System;
namespace NeuralNetworks
{
  class NeuralNetworksProgram
  {
    static void Main(string[] args)
    {
      try
      {
        Console.WriteLine("\nBegin Neural Network demo\n");
        NeuralNetwork nn = new NeuralNetwork(3, 4, 2);
        double[] weights = new double[] {
          0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2,
          -2.0, -6.0, -1.0, -7.0,
          1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
          -2.5, -5.0 };
        nn.SetWeights(weights);
        double[] xValues = new double[] { 1.0, 2.0, 3.0 };
        double[] yValues = nn.ComputeOutputs(xValues);
        Helpers.ShowVector(yValues);
        Console.WriteLine("End Neural Network demo\n");
      }
      catch (Exception ex)
      {
        Console.WriteLine("Fatal: " + ex.Message);
      }
    }
  }
  class NeuralNetwork
  {
    // Class members here
    public NeuralNetwork(int numInput, int numHidden, int numOutput) { ... }
    public void SetWeights(double[] weights) { ... }
    public double[] ComputeOutputs(double[] xValues) { ... }
    private static double SigmoidFunction(double x) { ... }
    private static double HyperTanFunction(double x) { ... }
  }
  public class Helpers
  {
    public static double[][] MakeMatrix(int rows, int cols) { ... }
    public static void ShowVector(double[] vector) { ... }
    public static void ShowMatrix(double[][] matrix, int numRows) { ... }
  }
} // ns

テンプレートが生成するすべての using ステートメントを削除します (ただし、System 名前空間への参照は除きます)。Main 関数では、開始メッセージ表示後に、3 つの入力ニューロン、4 つの非表示ニューロン、および 2 つの出力ニューロンから成る、nn という NeuralNetwork オブジェクトのインスタンスを作成します。次に、26 個の任意の重みとバイアスを、weights 配列に代入します。SetWeights メソッドを使用して、weights をニューラル ネットワーク オブジェクトに読み込みます。値 1.0、2.0、3.0 を、xValues 配列に代入します。ComputeOutputs メソッドを使用して、入力値をニューラル ネットワークに読み込み、結果の出力を確定します。この結果を yValues 配列にフェッチします。このデモは、出力値を表示して終了します。

NeuralNetwork クラス

NeuralNetwork クラス定義は、次の定義から始まります。

class NeuralNetwork
{
  private int numInput;
  private int numHidden;
  private int numOutput;
...

前述のように、ニューラル ネットワークの構造は、入力値の数、非表示層ニューロンの数、および出力値の数によって決まります。クラス定義は次のように続きます。

private double[] inputs;
private double[][] ihWeights; // input-to-hidden
private double[] ihSums;
private double[] ihBiases;
private double[] ihOutputs;
private double[][] hoWeights;  // hidden-to-output
private double[] hoSums;
private double[] hoBiases;
private double[] outputs;
...

この 7 つの配列と 2 つの行列が、図 3 に示す配列と行列に対応します。入力ニューロンから非表示ニューロンへのデータには ih プレフィックス、非表示ニューロンから出力ニューロンへのデータには ho プレフィックスを使用します。ihOutputs 配列の値は、出力層の計算の入力として使用します。このため、この配列にはっきりとした名前を付けると、少し面倒です。

図 6 に、NeuralNetwork クラス コンストラクターの定義を示します。

図 6 NeuralNetwork クラス コンストラクター

public NeuralNetwork(int numInput, int numHidden, int numOutput)
{
  this.numInput = numInput;
  this.numHidden = numHidden;
  this.numOutput = numOutput;
  inputs = new double[numInput];
  ihWeights = Helpers.MakeMatrix(numInput, numHidden);
  ihSums = new double[numHidden];
  ihBiases = new double[numHidden];
  ihOutputs = new double[numHidden];
  hoWeights = Helpers.MakeMatrix(numHidden, numOutput);
  hoSums = new double[numOutput];
  hoBiases = new double[numOutput];
  outputs = new double[numOutput];
}

入力パラメーター値の numInput、numHidden、および numOutput をそれぞれのクラスのフィールドにコピーしたら、9 つの各メンバー配列と行列を前述のサイズで割り当てます。C# の多次元配列型を使用するのではなく、行列を配列の配列として実装することで、このコードを多次元配列型をサポートしない言語に簡単にリファクタリングできるようにしています。行列の各行を確保する必要があるため、MakeMatrix のようなヘルパー メソッドを使用すると便利です。

SetWeights メソッドは、重みとバイアス値の配列を受け取って、ihWeights、ihBiases、hoWeights、および hoBiases を設定します。SetWeights メソッドは次のように始めます。

public void SetWeights(double[] weights)
{
  int numWeights = (numInput * numHidden) +
    (numHidden * numOutput) + numHidden + numOutput;
  if (weights.Length != numWeights)
    throw new Exception("xxxxxx");
  int k = 0;
...

先ほど説明したように、完全接続フィードフォワード ニューラル ネットワークの重みとバイアスの合計数 (Nw) は、(Ni * Nh) + (Nh * No) + Nh + No です。weights 配列パラメーターの長さが適切かどうかを確認するために、簡単なチェックを行います。ここで、"xxxxxx" はエラーを説明するメッセージに置き換えてください。次に、インデックス変数 k を初期化して、weights 配列パラメーターの先頭を指すようにします。SetWeights メソッドは、次のように終了します。

for (int i = 0; i < numInput; ++i)
  for (int j = 0; j < numHidden; ++j)
    ihWeights[i][j] = weights[k++];
for (int i = 0; i < numHidden; ++i)
  ihBiases[i] = weights[k++];
for (int i = 0; i < numHidden; ++i)
  for (int j = 0; j < numOutput; ++j)
    hoWeights[i][j] = weights[k++];
for (int i = 0; i < numOutput; ++i)
  hoBiases[i] = weights[k++]
}

weights 配列パラメーターの各値は、ihWeights、ihBiases、hoWeights、および hoBiases に順番にコピーします。ihSums と hoSums の 2 つの初期状態の配列は計算に使用するため、ihSums または hoSums には値をコピーしません。

出力を計算する

NeuralNetwork クラスの中核となるのが、ComputeOutputs メソッドです。このメソッドは、驚くほど短くシンプルで、次のように始まります。

public double[] ComputeOutputs(double[] xValues)
{
  if (xValues.Length != numInput)
    throw new Exception("xxxxxx");
  for (int i = 0; i < numHidden; ++i)
    ihSums[i] = 0.0;
  for (int i = 0; i < numOutput; ++i)
    hoSums[i] = 0.0;
...

まず、入力の x-values 配列の長さが、NeuralNetwork オブジェクトにとって適切なサイズかどうかをチェックします。次に、ihSums 配列と hoSums 配列に 0 を設定します。ComputeOutputs が一度しか呼び出されないのであれば、このように明示的な初期化は不要ですが、複数回呼び出される場合は、ihSums や hoSums は累積値となるため、明示的な初期化が必要です。別の設計手法として、ihSums や hoSums をクラス メンバーとして宣言したり割り当てたりしないで、ComputeOutputs メソッドのローカル メンバーにする方法があります。ComputeOutputs メソッドは次のように続きます。

for (int i = 0; i < xValues.Length; ++i)
  this.inputs[i] = xValues[i];
for (int j = 0; j < numHidden; ++j)
  for (int i = 0; i < numInput; ++i)
    ihSums[j] += this.inputs[i] * ihWeights[i][j];
...

xValues 配列パラメーターの値を、inputs クラスの配列メンバーにコピーします。一部のニューラル ネットワーク シナリオでは、たとえば線形変換を実行して、入力パラメーター値を正規化し、すべての入力が-1.0 ~ +1.0 の範囲内にスケーリングされるようにしていますが、今回は正規化を実行しません。次に、ループを入れ子にして重みの合計を計算します (図 1図 3 参照)。i を行、j を列のインデックスとすると、ihWeights を標準形式でインデックス処理する場合は、j を外側のループのインデックスにします。ComputeOutputs メソッドは次のように続きます。

for (int i = 0; i < numHidden; ++i)
  ihSums[i] += ihBiases[i];
for (int i = 0; i < numHidden; ++i)
  ihOutputs[i] = SigmoidFunction(ihSums[i]);
...

各重みの合計は、適切なバイアス値を加算して補正します。この時点で、図 2 の出力を生成するために、Helpers.ShowVector メソッドを使用して、ihSums 配列内の現在値を表示します。次に、ihSums 配列内の各値にシグモイド関数を適用して、その結果を ihOutputs 配列に代入します。SigmoidFunction メソッドのコードは後で簡単に示します。ComputeOutputs メソッドは次のように続きます。

for (int j = 0; j < numOutput; ++j)
  for (int i = 0; i < numHidden; ++i)
    hoSums[j] += ihOutputs[i] * hoWeights[i][j];
for (int i = 0; i < numOutput; ++i)
  hoSums[i] += hoBiases[i];
...

ihOutputs 配列内の計算結果値と hoWeights の重みを使用して値を計算し、その値を hoSums に代入後、非表示ニューロンから出力ニューロンへの適切なバイアス値を加算します。繰り返しになりますが、図 2 の出力を生成するために、Helpers.ShowVector を呼び出します。ComputeOutputs メソッドは次のように締めくくります。

for (int i = 0; i < numOutput; ++i)
    this.outputs[i] = HyperTanFunction(hoSums[i]);
  double[] result = new double[numOutput];
  this.outputs.CopyTo(result, 0);
  return result;
}

HyperTanFunction メソッドを hoSums に適用して最終出力を生成し、クラスの配列のプライベート メンバー出力します。それらの出力をローカルの結果配列にコピーして、その配列を戻り値として使用します。設計上の別の選択肢として、戻り値なしで ComputeOutputs を実装することもできますが、その場合は、ニューラル ネットワーク オブジェクトの出力を取得できるように、GetOutputs パブリック メソッドを実装します。

アクティブ化関数とヘルパー メソッド

入力ニューロン非表示ニューロンへの出力の計算に使用するシグモイド関数のコードを次に示します。

private static double SigmoidFunction(double x)
{
  if (x < -45.0) return 0.0;
  else if (x > 45.0) return 1.0;
  else return 1.0 / (1.0 + Math.Exp(-x));
}

Math.Exp 関数の実装方法によっては演算時にオーバーフローが生じる可能性があるため、通常は、入力パラメーター値のチェックを行います。非表示ニューロンから出力ニューロンへの結果の計算に使用する tanh 関数のコードは、次のとおりです。

private static double HyperTanFunction(double x)
{
  if (x < -10.0) return -1.0;
  else if (x > 10.0) return 1.0;
  else return Math.Tanh(x);
}

ハイパーボリック タンジェント関数は、-1 ~ +1 の値を返すため、演算オーバーフローは生じません。ここでは、単にパフォーマンスを向上するために、入力値をチェックしています。

Helpers クラスの静的なユーティリティ メソッドは、コーディングの利便性のためのものです。NeuralNetwork コンストラクターでの行列割り当てに使用する MakeMatrix メソッドは、配列の配列として実装する行列の各行を割り当てます。

public static double[][] MakeMatrix(int rows, int cols)
{
  double[][] result = new double[rows][];
  for (int i = 0; i < rows; ++i)
    result[i] = new double[cols];
  return result;
}

ShowVector メソッドと ShowMatrix メソッドは、配列または行列の値をコンソールに表示します。この記事付属のダウンロード コードで、これらの 2 つのメソッドのコードを確認できます (archive.msdn.microsoft.com/mag201205TestRun (英語) で入手できます)。

次のステップ

今回紹介したコードによって、ニューラル ネットワークを理解し、調べていくための確固たる基盤を提供します。さまざまなアクティブ化関数を使用したり、入力、出力、非表示層のニューロンの数を変更したりした場合の効果を試すことをお勧めします。ニューラル ネットワークを部分接続状態にすることで、ニューラル ネットワークを変更できます。この場合は、一部のニューロンが次層のニューロンに論理的に接続されません。今回紹介したニューラル ネットワークの非表示層は 1 つですが、2 つ以上の非表示層がある、もっと複雑なニューラル ネットワークを作成できます。また、このコラムで紹介したコードを拡張して、複雑なニューラル ネットワークを実装できます。

ニューラル ネットワークは、分類の問題を含む、さまざまな実用的な問題を解決するために使用できます。そういった問題を解決するには、いくつかの課題があります。たとえば、数値以外のデータをエンコードする方法や、ニューラル ネットワークについてトレーニングを受け、重みとバイアスの最適なセットを見つける方法を知る必要があります。今後のコラムでは、分類を行うためにニューラル ネットワークを使用する例を紹介する予定です。

Dr. James McCaffrey は Volt Information Sciences Inc. に勤務し、ワシントン州レドモンドにあるマイクロソフト本社で働くソフトウェア エンジニアの技術トレーニングを管理しています。これまでに、Internet Explorer、MSN サーチなどの複数のマイクロソフト製品にも携わってきました。また、『.NET Test Automation Recipes』(Apress、2006 年) の著者でもあります。連絡先は jammc@microsoft.com (英語のみ) です。

この記事のレビューに協力してくれた技術スタッフの Dan LieblingAnne Loomis Thompson に心より感謝いたします。