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 ...
|
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
|
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.
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.