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 ;

Source: https://habr.com/ru/post/J140495/


All Articles