Pythonで単純パーセプトロンニューラルネットワークを実装する方法

スポンサーリンク

ようこそ。

今日は、基本的なシングルパーセプトロンニューラルネットワークの作り方を取り上げます。

CNNや転移学習など、あらゆることを深く掘り下げる連載記事の第一回にしたいと思いますので、ぜひこのサイトをブックマークしてチェックしておいてください。

また、この記事には数学も含まれますので、どうぞお付き合いください。

スポンサーリンク

パーセプトロンとは

ニューラルネット(NN)の最も基本的な単位です。

複雑なNNでは、すべてのデータはこれらのいくつかを通過し、しばしば同時に、異なる役割を果たす。

しかし、それについては後で説明します。

さて、パーセプトロンとは何でしょうか?

教師あり学習では、パーセプトロンは線形分類器の一種です。

つまり、一本の直線で分けられるデータセットであれば、パーセプトロンを使って分類することができます

つまり、次のようなデータセットです。

import pandas as pd
import numpy as np
import random

最後のものは、近似的にデータベースを分けることができる一本の直線ではないので、線形分離可能とは言えません。

#Dataset
df = pd.DataFrame()
df['x'] = [random.randint(1,20) for x in range(10)]
df['y'] = [random.randint(1,20) for x in range(10)]
df.head()

Single Perceptron Neural Networkを構築する

それでは、今日最初のシングルパーセプトロンニューラルネットワークを構築してみましょう。

そのために、まずはデータを作成します。

1. データセットの作成

まず、データセットが必要です。

この例では2次元配列です。

コードエディター、Jupyterノートブック、Google Colabを開いてください。

label=[]
for i in range(df.shape[0]):
  if df.iloc[i,0] < df.iloc[i,1]:
    label.append(1)
  else:
    label.append(-1)
 
df['label'] = label
df

データを作ってみましょう。

この例では、結果を小さく簡潔にするために、20*20の平面を考えています。

#weights and bias
weights = [np.round(random.uniform(-0.99,0.99),2) for i in range(2)]

さて、これらにラベルを付ける必要があります。

そこで、線(私はy=xと考えた)を基準にフィルタリングします。

つまり、線より下の点はすべてyxという意味です。

w = weights.copy()
X = [[df.iloc[i,0],df.iloc[i,1]] for i in range(df.shape[0])]
wx = [X[i][0]*w[0]+X[i][1]*w[1] for i in range(df.shape[0])]
for i in range(df.shape[0]):
  if wx[i]<=0:
    pred = 0
  else:
    pred = 1

2. 値の重みを初期化する

さて、重みを初期化することができます

0は使えないので、一様分布のランダムな重みにします。

for i in range(df.shape[0]):
  if wx[i]<=0:
    pred = -1
  else:
    pred = 1
  if pred != df['label'][i] :
    err = df['label'][i] - pred
    w[0] = w[0] + err
    w[1] = w[1] + err

そして、重みを入力データ点と掛け合わせ、合計します。

for i in range(df.shape[0]):
  print('wx : ',wx[i])
  if wx[i]<=0:
    pred = -1
  else:
    pred = 1
  print('label=',df['label'][i])
  print('pred = ',pred)
  if pred != df['label'][i] :
    err = df['label'][i] - pred
    print('err',err)
    print('before', w[0],w[1])
    w[0] = w[0] + err
    w[1] = w[1] + err
    print('after',w[0],w[1])
  else:
    print('w_i', w[0],w[1])

これで、各ポイントの重みと入力の合計が求まりました。

これらの値を1つずつ活性化関数に代入し、出力に基づいて重みを修正する、という手順です。

3. 活性化関数の作成

さて、次は活性化関数です。

パーセプトロンは和を処理してラベルを出し、それを元のラベルと比較して正しいかどうかを判断します。

正しくない場合は誤差を求め、解が元の方向へ向くように重みを調整します。

ここではsignum関数を使用します。

wx <=0 ならば出力は0、そうでなければ出力は1です。

#Test Dataset
new_df = pd.DataFrame()
new_df['x'] = [random.randint(1,20) for x in range(100)]
new_df['y'] = [random.randint(1,20) for x in range(100)]
new_df.head()

ここで、入力はxとyの2つだけで、データフレーム全体ではないことに注意してください。

そこで、この活性化関数を拡張して、一度に1つのデータポイントを取り込み、誤差を求め、その誤差を調整することにします。

label_text = []
for i in range(new_df.shape[0]):
  if new_df.iloc[i,0] < new_df.iloc[i,1]:
    label_text.append(1)
  else:
    label_text.append(-1)
new_wX = w[0]*new_df['x']+w[1]*new_df['y']

これで完璧に動作するようになりました。

出力を明確に見るために、printステートメントをたくさん入れてみましょう。

new_df['given label'] = label_text
pred_label_text = []
 
for i in range(new_df.shape[0]):
  if new_wX[i]>=0:
    pred_label_text.append(-1)
  else:
    pred_label_text.append(1)
 
new_df['predicted labels'] = pred_label_text

そして、これを実行すると

Linearly Separable Dataset Examples
Linearly Separable Dataset Examples

単純なプリント・フォーマット文が最終的な重みを与えてくれます。

Perceptron
Perceptron

4. 別のデータベースでモデルをテストする

訓練とテストの分割と同様に、ここでは別のデータベースを使用してテストします。

Dataset With Labels For Neural Nets Perceptron Model
Dataset With Labels For Neural Nets Perceptron Model

そして、y=xの線と、weights*inputsの和からラベルを生成します。

Updating Weights Single Perceptron Neural Network
Updating Weights Single Perceptron Neural Network

これが私のものです。

Final Weights Single Perceptron Neural Network
Final Weights Single Perceptron Neural Network

さて、いよいよ活性化関数を適用して、与えられたラベルと予測されたラベルを比較します。

New Weight Sums Neural Net
New Weight Sums Neural Net
Predicted Labels For New Dataset
Predicted Labels For New Dataset

見ての通り、かなりうまくいったと思います。

まとめ

このチュートリアルを終えることができ、おめでとうございます。

パーセプトロン」についての理解を深めていただけたでしょうか。

今後のチュートリアルを読むために、私たちと連絡を取り合ってください。

タイトルとURLをコピーしました