ホーム >  C# >  【C#】ニューラルネットワークのライブラリを作る その1【機械学習】

投稿日:   |  最終更新日:

【C#】ニューラルネットワークのライブラリを作る その1【機械学習】

C#Visual Studio機械学習

C#で、ニューラルネットワークのライブラリを作成します。

ニューラルネットワークのライブラリを作る

前回 機会学習の人工ニューロンについて解説しましたが、ニューラルネットワークは人工ニューロンを応用した考え方です。ニューラルネットワークとは、脳細胞を模した物で、古くからありました。また、2012年ごろからニューラルネットワークの応用である「ディープラーニング」が登場し、再び脚光を浴びました。

ニューラルネットワークの概念図

「入力」を受ける「入力層」、「出力値」を出力する「出力層」、そしてその中間にある「中間層」(隠れ層)で構成されます。隠れ層がない場合や2層以上ある場合もあります。

ノード(ニューロン)

各層は丸で表されたノードで構成されています。

ノードは細かく見ると、上記のような構成になっています。他の層のノードとは「エッジ」で接続され、各エッジにはそれぞれ重みがついています。重みを踏まえた入力値の合計を「活性化関数」に与えた結果が、そのノードの出力値になります。出力値は出力側にあるエッジを通して、次の層のノードに送られます。

活性化関数

入力値の合計を受け取り、合計がある値を超えたら大きな値を、超えなければゼロまたは小さな値を出力します。これは、一定以上の力を加えなければONにならないスイッチの動きに似ています。活性化関数は、計算のしやすさや扱うデータの種類に合わせて色々なものが考案されています。その中で今回は定番の一つである「シグモイド関数」を使います。

\[
f(x) =
\frac{1}{1+e^{-x}}
\]

入力が一定値を超えると、出力(縦軸)が一気に大きくなるという形です。まだ、入力がどのような値でも出力が0〜1の範囲に治ります。

入力層、出力層のノード数

入力層のノード数はデータの性質から、出力層のノード数は解決したい問題の性質から決まります。

例えば、数字の手書きの文字認識では、学習データの解像度が入力層のノードの個数になります。解像度が28×28ピクセルであれば、28×28=784個のノードを入力層に用意します。

出力層のノード数は、数字の種類である「0」〜「9」の10個になります。

中間層のノード数

中間層のノードはある程度自由に設計できます。一般的に、中間層・隠れ層のノード数が多いほど認識率は上がりますが、その分処理に必要な時間が長くなります。


準備

①Macに「Visual Studio Community 2019 for Mac」をインストールします。

【C# for Mac】Visual StudioをMacにインストールする。【環境構築/開発】

②人工ニューロンについてざっくり解説します。

高校生でもわかる!ディープラーニングの人工ニューロンの話

環境

PC MacBook Air (Retina, 13-inch, 2019)
CPU 1.6 GHz デュアルコアIntel Core i5
メモリ 16 GB 2133 MHz LPDDR3
OS Catalina 10.15.7
XCODE Version 12.3
Visual Studio Community 2019 for Mac Version 8.7.4 (build 38)


各要素のクラスを定義する

オブジェクト指向で以下のクラスを定義します。

  • ノードの「Node」クラス
  • エッジの「Edge」クラス
  • 層の「Layer」クラス

これらのクラスを組み合わせてニューラルネットワークの「NeuralNetwork」クラスを定義します。

Edgeクラスの定義

1つのエッジは、2つのノードにつながります。後ほど定義するNodeクラスのオブジェクトを参照する変数を2個持たせます。ニューラルネットワークでは、信号が左から右へ流れるものとして、左側に繋がるノードを「Left」で、右側に繋がるノードを「Right」で参照します。

重みの「weight」もEdgeクラスに持たせます。

public class Edge
{
    public Node left;
    public Node right;
    public double weight; //重み
}

左側のノードの出力値に重みを掛けた値が右側のノードの入力値となります。

Nodeクラスを定義

Nodeクラスには入力値の合計である「inValue」と、出力値の「value」が必要です。入力と出力のEdgeは、それぞれC#のListとして持つことで柔軟に増減できるようにしておきます。

また、活性化関数のシグモイド関数は、Nodeに実装します。

public class Node
{
    public List<Edge> inputs = new List<Edge>();
    public List<Edge> outputs = new List<Edge>();
    public double inValue; // 入力値の合計
    public double value;   // 出力値
    public double error;   // 誤差
    static Random random = new Random();

    // 活性化関数
    public double Activation(double val)
    {
        return 1.0 / (1.0 + Math.Exp(-val));
    }

    //隣のノードと接続する関数

    // 出力値を計算する関数
    public void CalcForward()
    {
        if (inputs.Count == 0) return;

        inValue = 0.0;
        foreach (Edge edge in inputs)
        {
            inValue += edge.left.value * edge.weight;
        }
        value = Activation(inValue);
    }
}

「CalcForward関数」はノードの入力値(edge.left.value)と重み(edge.weight)、活性化関数を使って出力値を計算する関数です。

Layerクラスを定義

Layerクラスでは、入力層、隠れ層、出力層を表現します。各層には複数のノードがあり、Nodeクラスのオブジェクトを複数保持できるようにします。層によってNodeの数が異なるので、ここでもC#のListを使ってNodeのオブジェクトを扱います。

public class Layer
{
    public List<Node> nodes = new List<Node>();
    //コンストラクタ
    public Layer(int numNodes) {
        for (int i=0; i < numNodes; i++) {
            Node node = new Node();
            nodes.Add(node);
        }
    }
}

Layer関数はコンストラクタ(初期化)で使用します。引数numNodesでノードの数を指定して必要なだけノードを生成するようにします。

NeuralNetworkクラスを定義

暫定的にEdge、Node、Layersを定義したので、ニューラルネットワーク全体を表すNueralNetworkクラスを定義します。NeuralNetworkの各層は、変数「Layers」で扱います。

using System;
using System.Collections.Generic;

public class NeuralNetwork {
    public List<Layer> layers = new List<Layer>();
}


次回

学習データの定番MNISTをダウンロードして中身をみてみます。


トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター、フロントエンドエンジニア 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 20

最近の投稿
人気記事
カテゴリー
広告