Rosenblattパーセプトロンをプログラムしますか?

ローゼンブラットパーセプトロンによる挑発的な記事の後-歴史によって忘れられ、発明されたものは何ですか? ローゼンブラットパーセプトロンに問題がないことを完全に証明するもの、およびその逆もあり、いくつかの興味深い側面と可能性を示します。 実際、彼に関する信頼できる情報は、元のものを除いて、見つけることができません。 しかし、そこでも、このパーセプトロンをプログラムする方法を説明することは非常に困難です。 完全なコードをアップロードしません。 しかし、一緒にいくつかの基本を試してみましょう。



始めましょう...そうそう、私はあなたに警告します、私は古典的には言いませんが、やや近代化されます...







C#コードですが、擬似コードのように扱う方が良いと思います。 しかし、誰かが何かを理解していなかったら、尋ねてください-私は説明します。



そして、センサーから始めます。



パブリック クラス cSensor

{

パブリック イベント EventHandler ChangeState ;

private sbyte state = 0 ;

パブリック sbyte State

{

get {状態を返す ; }

セット

{

状態=値;

if ( state == 1 && ChangeState != null )

{

ChangeState ( これ 、 新しい EventArgs ( ) ) ;

}

}

}

}





ここではすべてが簡単です。 センサーの状態は0または1です。センサーがユニットを受信するとすぐに、イベントを送信します。 次にシナプスがあります。



パブリック デリゲート void BackCommunication ( sbyte Type ) ;

クラス cSinaps

{

プライベート sbyteタイプ;

プライベート BackCommunication hBackCommunication ;

パブリック cSinaps ( sbyte tType、BackCommunication tBackCommunication )

{

タイプ= tType ;

hBackCommunication = tBackCommunication ;

}

public void ChangeSensorState ( オブジェクトソース、EventArgs e )

{

hBackCommunication (タイプ) ;

}

}





タイプがあります-センサーの活動を刺激または抑制します。 センサーの変更に対する反応(ChangeSensorState)。 現在、実際のA要素は中間層にあります。



パブリック クラス cAssociation

{

// A要素のアクティベーションレベル

public int ActivationLevel = 0 ;

//このA要素に接続されたシナプス

プライベート cSinaps [ ] oSinaps ;



public cAssociation ( cSensor [ ] sensorField、 int SCount、Random RND )

{

int SinapsCount = 10 ;

oSinaps = 新しい cSinaps [ SinapsCount ] ;



int tSinapsNumber = 0 ;

int tmpSensorNumber = 0 ;

sbyte tmpSensorType = 0 ;



for ( int j = 1 ; j < SinapsCount + 1 ; j ++ )

{

tmpSensorNumber = RND。 次へ ( SCount ) ;

if ( RND。Next ( 2 ) == 0 ) tmpSensorType = 1 ; そうでない場合、 tmpSensorType = -1 ;



oSinaps [ tSinapsNumber ] = 新しい cSinaps ( tmpSensorType、AssumeSinapsSignal ) ;



sensorField [ tmpSensorNumber ] 。 ChangeState + =

新しい EventHandler ( oSinaps [ tSinapsNumber ] 。ChangeSensorState ) ;

tSinapsNumber ++ ;

}

}



void AssumeSinapsSignal ( sbyte Type )

{

ActivationLevel + =タイプ;

}

}





A要素を作成するときは、それに関連するシナプスを形成する必要があります。10にします。どのセンサーに接続するか、どのタイプのシナプス(興奮性または抑制性)になるかをランダムに決定します。 そして最も重要なことは、この時点でAssumeSinapsSignalを呼び出すためにセンサー値を変更することです。 そして、接続されているシナプスのタイプに応じて、活性化のレベルを上げたり下げたりします。



一般に、すべて、非常に複雑なものすべてが伝えられます。Rosenblattパーセプトロンの最初の「ランダム」レイヤーの役割は何ですか -実装しました。 A要素のセットには、任意の問題の線形表現が既に保証されています。



次に、第2層のエラー修正方法によるティーチングに進みましょう。 最初は、一般的なアルゴリズムは言葉なしで明確だと思います。



パブリック クラス cNeironNet

{

public cSensor [ ] SensorsField ; / *センサーフィールド* /

public cAssociation [ ] AssociationsFiled ; / *連想フィールド* /

int ACount ;

int SCount ;

public ArrayList AHConnections ;

ランダムRND = new Random ( ) ;



public cNeironNet ( int argSCount、 int argACount )

{

ACount = argACount ;

SCount = argSCount ;

SensorsField = new cSensor [ SCount ] ;

for ( int i = 0 ; i < SCount ; i ++ )

{

SensorsField [ i ] = new cSensor ( ) ;

}

AssociationsFiled = new cAssociation [ ACount ] ;

for ( int i = 0 ; i < ACount ; i ++ )

{

AssociationsFiled [ i ] = new cAssociation ( SensorsField、SCount、RND ) ;

}

}



/ *トレーニングセットの新しい例を処理に追加します* /

public ArrayList JoinStimul ( int [ ] tPerception、 int [ ] tReaction )

{

for ( int i = 1 ; i < ACount + 1 ; i ++ )

{

AssociationsFiled [ i ] 。 ActivationLevel = 0 ;

}

for ( int i = 1 ; i < SCount + 1 ; i ++ )

{

SensorsField [ i ] 。 状態 = 0 ;

}

//受信したサンプルをセンサーに投げましょう

for ( int i = 0 ; i < SCount ; i ++ )

{

SensorsField [ i ] 。 状態 = tPerception [ i ] ;

}

//この例でどのA要素がアクティブだったかを覚えておいてください

AHConnections = new ArrayList ( ) ;

for ( i = 0 ; i < ACount ; i ++ )

{

if ( AssociationsFiled [ i ] 。ActivationLevel > 0 )

{

AHConnections。 追加 ( i ) ;

}

}

//この例に対する反応を覚えておいてください

SaveReaction ( tReaction ) ;

AHConnectionsを返します。

}

/ *すべての例を追加すると、パーセプトロンが呼び出されて学習します* /

プライベート ボイドの保存( )

{

//多くの反復を行います

for ( int n = 1 ; n < 100000 + 1 ; n ++ )

{

//反復ごとに、トレーニングセットのすべての例をスクロールします

for ( int i = 1 ; i < StimulCount + 1 ; i ++ )

{

// R要素をアクティブにします。 出力を期待する

RAktivization ( i ) ;

//パーセプトロンが間違っているかどうかを確認し、間違っている場合はトレーニングに送ります

bool e = GetError ( i ) ;

if ( e )

{

LearnedStimul ( i ) ;

エラー++ ; //エラーの数。繰り返しの終わりに= 0の場合、トレーニングから飛び出します。

}

}

}

}

}




R要素のアクティブ化も簡単です。 アクティブなA要素からの重みを集計し、しきい値(= 0)を通過します。



プライベート ボイド RAktivization ( int ReactionNumber )

{

int [ ] Summa = new int [ RCount + 1 ] ;

for ( int j = 1 ; j < RCount + 1 ; j ++ )

{

for ( i = 1 ; i < AHConnections [ ReactionNumber ] 。Count + 1 ; i ++ )

{

Summa [ j ] + = Weight [ AHConnections [ ReactionNumber ] 。 値 [ i ] ] 値 [ j ] ;

}

}

for ( int i = 1 ; i < RCount + 1 ; i ++ )

{

if ( Summa [ i ] > 0 )リアクション[ i ] = 1 ;

if ( Summa [ i ] <= 0 )リアクション[ i ] = -1 ;

}

}


以下にエラーがあるかどうかを確認します。



private int GetError ( int ReactionNumber )

{

int IsError = 0 ;

for ( int i = 1 ; i < RCount + 1 ; i ++ )

{

if ( Reactions [ i ] == NecessaryReactions [ ReactionNumber ] 。Value [ i ] )

{

ReactionError [ i ] = 0 ;

}

他に

{

IsError = 1 ;

ReactionError [ i ] = NecessaryReactions [ ReactionNumber ] 。 値 [ i ] ;

}

}

IsErrorを返します。

}





ここで、現在のリアクションをチェックし、ReactionErrorが何であるかを学習するための配列を準備します。 それでは、最後の1つであるトレーニング自体について説明しましょう。



private void LearnedStimul ( int ReactionNumber )

{

for ( int j = 1 ; j < RCount + 1 ; j ++ )

{

for ( int i = 1 ; i < AHConnections [ ReactionNumber ] 。Count + 1 ; i ++ )

{

重さ[ AHConnections [ ReactionNumber ] 。 値 [ i ] ] 値 [ j ] + = ReactionError [ j ] ;

}

}

}





そして、あなた。



彼らが私に尋ねる唯一のことは、「明らかに、重みがゼロの場合、このエラー修正学習アルゴリズムはエラー逆伝播アルゴリズムのようにスタックしますか?」です。 ご覧のとおり、ここではトレーニング自体がゼロウェイトから始まります。 基本的な増分または減分などの数式はありません。 重みが0の場合、エラーが修正されると、重みは+1または-1になります。重みは、ゼロを通過した後に再び符号を変更できますが、物理的にゼロにはまりません。



更新しました。



以下のretranは、関数型プログラミングの行列とlinqを使用して、より明確なOOPモデルに従ってイベントのコードと引き換えにA要素をアクティブにすることを提案しました。



パブリック クラス Perceptron1

{

public int [ ] [ ] SAMatrix { get ; プライベートセット; }

public Perceptron1 ( int sensorCount、 int associativeElementsCount )

{

var random = new Random ( ) ;

SAMatrix = new int [ associativeElementsCount ] [ ] ;

for ( var i = 0 ; i < associativeElementsCount ; i ++ )

{

SAMatrix [ i ] = new int [ sensorCount ] ;

for ( var j = 0 ; j < 10 ; j ++ )

{

var sindex =ランダム。 次 ( sensorCount ) ;

if (ランダム。 次 ( 2 ) == 1 )

if (ランダム。 次 ( 2 ) == 1 )

SAMatrix [ i ] [ sindex ] + = 1 ;

他に

SAMatrix [ i ] [ sindex ] - = 1 ;

}

}

}

public int Activate ( int i、 int [ ]入力)

{

return ( SAMatrix [ i ] 。Zip ( inputs、 ( w、input ) => w * input ) 。Sum ( ) > 0 ? 1 : 0 ) ;

}

}





はい、もちろんコードはずっと短いです。 しかし、あまり明確ではありませんが、アクティベーションプロセスが変更された場合、変更を加えることはより困難です。 しかし、最も重要なことは、100倍以上遅くなることです。 ここでは、数学および関数型プログラミングの楽しみがあります:)



この方法でテストします(上記のコードにはいくつかのバグがありますが、誰かがこれを行うと簡単に修正できますが、そのほとんどは上記で修正および更新されます)。



ランダムランダム= new Random ( ) ;

int [ ] Input = new int [ 1000 ] ;

int [ ] AActiv = new int [ 900 ] ;



TimeSpan BeginTime = DateTime。 今 。 TimeOfDay ;

パーセプトロン1 P1 = 新しいパーセプトロン1 ( 1000、900 ) ;

for ( int i = 0 ; i < 100 ; i ++ )

{

for ( int j = 0 ; j < 1000 ; j ++ )

{

入力[ j ] =ランダム。 次へ ( 2 ) ;

}

for ( int j = 0 ; j < 900 ; j ++ )

{

AActiv [ j ] = P1。 有効化 ( j、入力) ;

}

}

TimeSpan locTime = DateTime。 今 。 TimeOfDay - BeginTime ;



// TimeSpan BeginTime = DateTime.Now.TimeOfDay;

// Perceptron2 P2 =新しいPerceptron2(1000、900);

// for(int i = 0; i <10000; i ++)

// {

// for(int j = 0; j <1000; j ++)

// {

//入力[j] = random.Next(2);

//}

// P2.JoinStimul(入力);

//}

// TimeSpan locTime = DateTime.Now.TimeOfDay-BeginTime;



コンソール WriteLine ( locTime。ToString ( ) ) ;

コンソール ReadLine ( ) ;




All Articles