kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Diskretisierung der sigmoiden Funktion, um sie als Lookup-Table auf einen FPGA zu übertragen

(EN google-translate)

(PL google-translate)

Die gebräuchlichste sigmoide Funktion bei neuronalen Netzen hat folgende Form:


$ o\left(u\right) = \frac {1}{1+e^{-du}\right)} $

Formel 0-1: Sigmoiden Funktion



Dabei ist ...

  • o der Ausgang des Neurons (output),
  • u die Summe der gewichteten Eingänge,
  • d ein positiver reell wertiger Faktor, der für die Steilheit der Kurve verantwortlich ist.
Beispielplot der sigmoiden Funktion für d=1, d=0,1 und d=0,01 mit Scilab.

Bild 0-1: Beispielplot der sigmoiden Funktion für d=1, d=0,1 und d=0,01 mit Scilab.

clear;
u = -100:0.1:100;
o_rot   = 1./(1+exp(-1.*u)); 
o_gruen = 1./(1+exp(-0.1.*u)); 
o_blau  = 1./(1+exp(-0.01.*u)); 
plot(u,o_rot,'r',u,o_gruen,'g',u,o_blau,'b');
a = gca();
a.x_label.text = 'u';
a.y_label.text = 'o(u)';
a.title.text = 'Sigmoide Funktion o(u)=1/(1+exp(-du))';
hl=legend(['d=1';'d=0.1';'d=0.01']);

Code 0-1: Scilabscript zum Plot.

Vorüberlegungen

  • Bei der Übertragung auf den FPGA muß der Wertebereich genau definiert sein.
  • Überläufe dürfen bei den Summationen und Produktbildungen nicht auftreten.
  • Die sigmoide Funktion muß sensitiv gegenüber dem Eingang sind.
  • Dies ist nur durch Strecken des Ausgangs möglich, d.h. Hinzufügen eines Faktors.
  • Außerdem sollte die Steilheit d im Hinblick auf die Sensitivität sinnvoll angepaßt werden.
  • Ansatz für sinnvolle Anpassung von d: Jeder mögliche diskrete Ausgangswert taucht auch mindestens einmal auf. So wird der mögliche Zahlenbereich wirklich ausgenutzt.
  • Das Programm, das den Lookuptable repräsentiert sollte automatisch generiert werden (als Quelltext) und nicht von Hand getippt werden müssen.

Umsetzung

$ o\left(u\right) = 128 \cdot \frac {1}{1+e^{-du}\right)} $

Formel 0-2: gestreckte sigmoiden Funktion auf einen Wertebereich von maximal 0..127.



Warum wird nicht 127 als Faktor verwendet?


Processing-Sketch (Java), das ein d findet, bei dem alle möglichen Ausgangswerte o(u) auch für einen diskreten Eingangswert mindestens einmal auftauchen (Näherung von unten). d ist hier also maximal steil bei gleichzeitigem Einhalten der Bedingung, dass alle Werte einmal auftauchen.

Als Testinput-Zahlenbereich für u wird derjenige genommen, der sich für eine 4-Byte-Integer-Zahl ergibt, also -32768 bis 32767. Dies würde gleichzeitig dem Bereich des Java-Datentyps short entsprechen.

SigmoidDiskret005.zip -- Sketch zum Download.
public void setup()
{
     double d = 1.0;
     int[] alle = new int[128];
     int anzBest=0; //für Kontrollausgabe
     int durchlauf = 0;
     while(true)
     {
         for(int u=-32768;u<=32767;u++)
         {
              double out = 128.0 / ( 1.0 + Math.exp(-d*(double)u) );
              int oint = (int)Math.floor(out); //Nachkommstellen abschneiden, d.h. für 
              // >0 nach unten, für <0 nach oben hin runden.
              // gewährleistet einen Wertebereich von maximal +/-127 INKLUSIVE.
              if(oint>127) oint=127;
              if(oint<0)   oint=0;
              alle[oint]=1;
         }
       
         int anz = 0;
         for(int k=0;k<alle.length;k++)
             anz+=alle[k];
             
         if(anz>anzBest)
         {
              println("Nr."+durchlauf+": d="+d+" "+anz+"/"+alle.length);
              anzBest = anz;
         }
         
         if(anz==alle.length-1)
             break;
       

       
         for(int k=0;k<alle.length;k++)
            alle[k]=0;
         d*=0.999;
         durchlauf++;
     }
     
     int ovor = -1;
     String umdrehen = "";
     println("public int sigmoid(int u)");
     println("{");
     println("    int out = 0;");
     for(int u=-32768;u<=32767;u++)
     {
              double out = 128.0 / ( 1.0 + Math.exp(-d*(double)u) );
              int oint = (int)Math.floor(out); //Nachkommstellen abschneiden, d.h. für 
              // >0 nach unten, für <0 nach oben hin runden.
              // gewährleistet einen Wertebereich von maximal +/-127 INKLUSIVE.
              if(oint>127) oint=127;
              if(oint<0)   oint=0;
              //alle[oint]=1;
              if(oint!=ovor)
              {
                    if(u==143)//"Hack!"
                       umdrehen = "    if(u>="+u+") out="+oint+";\n"+umdrehen;
                    else if(u>=-142)
                       umdrehen = "    else if(u>="+u+") out="+oint+";\n"+umdrehen;
                    ovor=oint;
              }
     }
     println(umdrehen);
     println("    return out;");
     println("}");
     
}

Code 0-2: Java-Sketch zur Generierung des Quelltextes der gewünschten Java-Funktion (Lookup-Table der gewünschten sigmoiden Funktion), gefundenes d=0.033991405429909555.

Nr.0: d=1.0 11/128
Nr.32: d=0.9684914751650402 13/128
Nr.214: d=0.8072641721084362 15/128
Nr.371: d=0.6899191635698992 17/128
Nr.525: d=0.5914039992761899 19/128
Nr.658: d=0.5177199916537337 21/128
Nr.776: d=0.46006924962422124 23/128
Nr.881: d=0.4141904279539273 25/128
Nr.986: d=0.3728867137909789 27/128
Nr.1082: d=0.3387383099784249 29/128
Nr.1169: d=0.31050048224601523 31/128
Nr.1251: d=0.28604395388381393 33/128
Nr.1331: d=0.26404155293258547 35/128
Nr.1405: d=0.24519907146849695 37/128
Nr.1475: d=0.22861429815057077 39/128
Nr.1544: d=0.21336464753089512 41/128
Nr.1608: d=0.20013086261725366 43/128
Nr.1670: d=0.18809388829767848 45/128
Nr.1730: d=0.17713497228194314 47/128
Nr.1787: d=0.16731599545123407 49/128
Nr.1843: d=0.15819950333179325 51/128
Nr.1897: d=0.14987934349983564 53/128
Nr.1948: d=0.14242360262202694 55/128
Nr.1999: d=0.1353387472227571 57/128
Nr.2048: d=0.12886392328920743 59/128
Nr.2095: d=0.12294462852471602 61/128
Nr.2142: d=0.11729723337040716 63/128
Nr.2187: d=0.11213340004667421 65/128
Nr.2231: d=0.10730419949433023 67/128
Nr.2274: d=0.10278576046681966 69/128
Nr.2317: d=0.09845758697729866 71/128
Nr.2358: d=0.09450057140500139 73/128
Nr.2399: d=0.09070258849560102 75/128
Nr.2439: d=0.08714438998609117 77/128
Nr.2478: d=0.08380958559855975 79/128
Nr.2517: d=0.08060239608451443 81/128
Nr.2555: d=0.07759553246580189 83/128
Nr.2592: d=0.07477561421883774 85/128
Nr.2629: d=0.0720581753114292 87/128
Nr.2666: d=0.06943949151680232 89/128
Nr.2702: d=0.06698295604488617 91/128
Nr.2738: d=0.06461332452910457 93/128
Nr.2774: d=0.062327522600013965 95/128
Nr.2809: d=0.060182766640824836 97/128
Nr.2844: d=0.05811181400210453 99/128
Nr.2879: d=0.05611212503355444 101/128
Nr.2914: d=0.05418124747692819 103/128
Nr.2949: d=0.05231681345877875 105/128
Nr.2984: d=0.05051653658668826 107/128
Nr.3019: d=0.04877820914541962 109/128
Nr.3054: d=0.047099699389551504 111/128
Nr.3090: d=0.04543347056587089 113/128
Nr.3126: d=0.04382618730933501 115/128
Nr.3163: d=0.04223348910415249 117/128
Nr.3201: d=0.04065797338690987 119/128
Nr.3241: d=0.03906298979598391 121/128
Nr.3283: d=0.03745555362867339 123/128
Nr.3328: d=0.03580662951998757 125/128
Nr.3380: d=0.033991405429909555 127/128

public int sigmoid(int u)
{
    int out = 0;
    if(u>=143) out=127;
    else if(u>=122) out=126;
    else if(u>=110) out=125;
    else if(u>=102) out=124;
    else if(u>=95) out=123;
    else if(u>=89) out=122;
    else if(u>=84) out=121;
    else if(u>=80) out=120;
    else if(u>=76) out=119;
    else if(u>=73) out=118;
    else if(u>=70) out=117;
    else if(u>=67) out=116;
    else if(u>=65) out=115;
    else if(u>=62) out=114;
    else if(u>=60) out=113;
    else if(u>=58) out=112;
    else if(u>=56) out=111;
    else if(u>=54) out=110;
    else if(u>=52) out=109;
    else if(u>=50) out=108;
    else if(u>=48) out=107;
    else if(u>=47) out=106;
    else if(u>=45) out=105;
    else if(u>=44) out=104;
    else if(u>=42) out=103;
    else if(u>=41) out=102;
    else if(u>=39) out=101;
    else if(u>=38) out=100;
    else if(u>=37) out=99;
    else if(u>=35) out=98;
    else if(u>=34) out=97;
    else if(u>=33) out=96;
    else if(u>=32) out=95;
    else if(u>=30) out=94;
    else if(u>=29) out=93;
    else if(u>=28) out=92;
    else if(u>=27) out=91;
    else if(u>=26) out=90;
    else if(u>=25) out=89;
    else if(u>=24) out=88;
    else if(u>=23) out=87;
    else if(u>=22) out=86;
    else if(u>=21) out=85;
    else if(u>=20) out=84;
    else if(u>=19) out=83;
    else if(u>=18) out=82;
    else if(u>=17) out=81;
    else if(u>=16) out=80;
    else if(u>=15) out=79;
    else if(u>=14) out=78;
    else if(u>=13) out=77;
    else if(u>=12) out=76;
    else if(u>=11) out=75;
    else if(u>=10) out=74;
    else if(u>=9) out=73;
    else if(u>=8) out=72;
    else if(u>=7) out=71;
    else if(u>=6) out=70;
    else if(u>=5) out=69;
    else if(u>=4) out=68;
    else if(u>=3) out=67;
    else if(u>=2) out=66;
    else if(u>=1) out=65;
    else if(u>=0) out=64;
    else if(u>=-1) out=62;
    else if(u>=-2) out=61;
    else if(u>=-3) out=60;
    else if(u>=-4) out=59;
    else if(u>=-5) out=58;
    else if(u>=-6) out=57;
    else if(u>=-7) out=56;
    else if(u>=-8) out=55;
    else if(u>=-9) out=54;
    else if(u>=-10) out=53;
    else if(u>=-11) out=52;
    else if(u>=-12) out=51;
    else if(u>=-13) out=50;
    else if(u>=-14) out=49;
    else if(u>=-15) out=48;
    else if(u>=-16) out=47;
    else if(u>=-17) out=46;
    else if(u>=-18) out=45;
    else if(u>=-19) out=44;
    else if(u>=-20) out=43;
    else if(u>=-21) out=42;
    else if(u>=-22) out=41;
    else if(u>=-23) out=40;
    else if(u>=-24) out=39;
    else if(u>=-25) out=38;
    else if(u>=-26) out=37;
    else if(u>=-27) out=36;
    else if(u>=-28) out=35;
    else if(u>=-29) out=34;
    else if(u>=-31) out=33;
    else if(u>=-32) out=32;
    else if(u>=-33) out=31;
    else if(u>=-34) out=30;
    else if(u>=-36) out=29;
    else if(u>=-37) out=28;
    else if(u>=-38) out=27;
    else if(u>=-40) out=26;
    else if(u>=-41) out=25;
    else if(u>=-43) out=24;
    else if(u>=-44) out=23;
    else if(u>=-46) out=22;
    else if(u>=-47) out=21;
    else if(u>=-49) out=20;
    else if(u>=-51) out=19;
    else if(u>=-53) out=18;
    else if(u>=-55) out=17;
    else if(u>=-57) out=16;
    else if(u>=-59) out=15;
    else if(u>=-61) out=14;
    else if(u>=-64) out=13;
    else if(u>=-66) out=12;
    else if(u>=-69) out=11;
    else if(u>=-72) out=10;
    else if(u>=-75) out=9;
    else if(u>=-79) out=8;
    else if(u>=-83) out=7;
    else if(u>=-88) out=6;
    else if(u>=-94) out=5;
    else if(u>=-101) out=4;
    else if(u>=-109) out=3;
    else if(u>=-121) out=2;
    else if(u>=-142) out=1;

    return out;
}


Code 0-3: Ausgabe des Programms.