始めましょう...そうそう、私はあなたに警告します、私は古典的には言いませんが、やや近代化されます...
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 ( ) ;