[C#]AIの基本的な仕組み-形式ニューロンの作成-
概要
代表的なAIの考え方の1つに、形式ニューロンと呼ばれる人間の神経細胞をモデルに作り出されたものがある。
今回は、C#プログラムを用い形式ニューロンを1つ作成しAND計算を学習させた。
その結果正しくAND演算を学習することが出来た
目次
- 形式ニューロン
- 学習プログラムの作成
- 実行結果
- 補足
- まとめ
- コード
形式ニューロン
人間の脳細胞はニューロンと呼ばれる細胞の集合である。ここでニューロンの1つに着目すると複数の入力と1つの出力を持つ構造になっている(下図)。
AIにおける形式ニューロンはこれをヒントに考えられたものである。
形式ニューロンの構造は下の図のように複数の入力に重みを掛けたものにバイアス(b)を加算した結果に応じた結果に応じて0か1の出力を得る構造になっている。(式1-1)
(1-1)
学習プログラムの作成
今回は式1-1をもとにAND演算を学習するプログラムを作成した。ある入力に対する各学習段階での出力を教師データと比較することで学習を行う。
教師データの作成
今回ランダムにx1,x2を生成しそれに応じた適切な出力(y=x1 and x2)を返すクラスを作成することで、教師データの作成を行った。
ただし生成するx 1,x 2は0か1をとるものとする。
形式ニューロンの作成
形式ニューロンは教師データが生成したx1,x2を入力とし、それに応じた出力(式2-2-1)を得るように作成した。
この出力を教師データのものと比較し、その結果に応じて式1-1中の重み(w 1,w 2 )とバイアス(b)の値を調整することで学習を行う。
学習の方法は、ある入力に対し出力に影響があるパラメータを適切な出力が得られる方向に変更することで行った。
例えばx1=0の場合、式1-1より、w1を変更しても出力には影響しないため、変更する必要がない。
このように出力に影響が生じるパラメータのみを変更する規則を、パーセプトロンの学習測と言う。
実行結果
作成したプログラムを実行した結果、正しくand演算を学習していることがわかる。
同様にor演算も行ったが、これについても問題なく学習することが分かった。
今回は100回学習を行ったが、実際には30回程度で学習は完了しているようである。
補足
上記の方法でand演算とor演算を学習させることができた。
しかしこの方法には限界があり、例えばxor演算を学習することができない。
式1-1より、形式ニューロンは下図のように領域を2つに分ける機能を持っており、これにより入力に応じた出力を得ることができるようになっている。
and やor演算であれば、出力に応じ適切に領域を分けることができるが(線形分離可能 )、xorではそれができないためである。(下図)
xorを適切に学習させるためにはより複雑な領域の分割を実現する必要があり、複数のニューロンを組み合わせた方法を使う必要がある。
まとめ
今回は形式ニューロンを作成しand演算を学習させた。
上手く学習はできるようであるが、xorのように学習できないものもあり自分が当初考えていたよりは万能な方法ではなく、適切に学習させるためには工夫が必要と感じた。
コード
学習プログラム
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Machinelearning
{
public partial class BtStartLearn : Form
{
const double rate = 0.1;
double w1, w2, b;
int[,] result = new int[2,2];
public BtStartLearn()
{
InitializeComponent();
w1 = 0;
w2 = 0;
b = 0;
}
///
/// 学習を行う
///
///
///
private void button1_Click(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter("結果.txt");
sw.WriteLine("X1,X2,W1,W2,B,Ans");
teacher teacher = new teacher(); // 教師データを作成
for (int i = 0; i < 100; i++) {//100回学習
teacher.MakeData();
int answer = GetAnswer(teacher.X1,teacher.X2); // 現段階の学習で求まる結果を得る
if (teacher.Judge(answer)==false) // 教師データと比較して不正解だった場合
{
if (answer == 0) {
if (teacher.X1 == 1)
{
w1 += rate;
}
if(teacher.X2 == 1)
{
w2 += rate;
}
b += rate;
}
else
{
if (teacher.X1 == 1) {
w1-=rate;
}
if(teacher.X2 == 1)
{
w2 -= rate;
}
b -= rate;
}
}
sw.WriteLine($"{teacher.X1},{teacher.X2},{w1},{w2},{b},{answer}");
}
learningResult();
WriteText();
sw.Close();
}
void WriteText()
{
tBw1.Text = w1.ToString();
tBw2.Text = w2.ToString();
tbB.Text = b.ToString();
tBx10x20.Text = result[0,0].ToString();
tBx11x20.Text = result[1, 0].ToString();
tBx10x21.Text = result[0, 1].ToString();
tBx11x21.Text = result[1, 1].ToString();
}
int GetAnswer(int x1,int x2)
{
return ((x1 * w1) + (x2 * w2) + b > 0) ? 1 : 0;
}
void learningResult()
{
for(int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++) {
result[i,j]=GetAnswer(i,j);
}
}
}
}
}
教師データ作成プログラム
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Machinelearning
{
internal class teacher
{
int x1,x2;
int answer;
Random random;
public teacher() {
random = new Random();
}
public void MakeData()
{
x1 = random.Next(2);
x2 = random.Next(2);
answer=x1 & x2;
}
public bool Judge(int answer)
{
return answer==this.answer;
}
public int X1 { get { return x1; } }
public int X2 { get { return x2; } }
}
}