
[ad_1]
Warning :
- that is my first try at an autoencoder
- i’ve seen a video or 2 on autoencoders so i’d butcher this
With that out of the best way let’s pop a beer open and seize the keyboard.
What are we constructing :
We are going to snatch the world’s silliest easiest weakest most bare-bone thinnest neural internet ever , the one we constructed right here,
and we are going to try this :
wtf is that , you ask .
It is a neural internet that has some inputs , like most nets , however , the objective of the community is to recreate the inputs it acquired on the opposite finish of the “squeeze”.
Sure , you’re appropriate that is like compression , kind of .
So what are we going to ship in ?
A sequence of 20 bars !!!
How : ? :
- We are going to get the min and max value for a window of 20 bars.
- We are going to calculate the vary of that window max-min
- Then for every bar we are going to calculate this worth : (close-open)/vary producing a worth between -1.0 and 1.0
- We are going to ship these 20 values as inputs for every window
- and every 20 bar window will likely be a pattern
Cool let’s create our pattern collector actual fast , easy sh*t from the ohlc historical past of the chart.
#property model "1.00" #embrace "miniNeuralNet.mqh"; class ae_sample{ public: double min,max,vary; double bars[]; ae_sample(void){reset();} ~ae_sample(void){reset();} void reset(){ ArrayFree(bars); min=INT_MAX; max=INT_MIN; vary=0.0; } void fill(int oldest_bar,int measurement){ ArrayResize(bars,measurement,0); ArrayFill(bars,0,measurement,0.0); int co=-1; for(int i=oldest_bar;i>oldest_bar-size;i--){ co++; if(iHigh(_Symbol,_Period,i)>max){max=iHigh(_Symbol,_Period,i);} if(iLow(_Symbol,_Period,i)<min){min=iLow(_Symbol,_Period,i);} bars[co]=iClose(_Symbol,_Period,i)-iOpen(_Symbol,_Period,i); } vary=max-min; for(int i=0;i<measurement;i++){ bars[i]/=vary; bars[i]=(bars[i]+1.0)/2.0; } } };
Fundamental stuff :
- imported the little internet
- then a easy (and naive) extractor of chart knowledge for a given window which fills a pattern
- the inputs match the outputs right here for every pattern (bars[] is each of those)
We now want slightly pattern assortment , we can’t have many samples now that i consider it however its okay , nonetheless extra enjoyable than netflix. sco
struct ae_sample_collection{ ae_sample samples[]; ae_sample_collection(void){reset();} ~ae_sample_collection(void){reset();} void reset(){ ArrayFree(samples); } void add_sample(int oldest_bar,int window_size){ int ns=ArraySize(samples)+1; ArrayResize(samples,ns,0); samples[ns-1].fill(oldest_bar,window_size); } int fill(int window_size){ int barz=iBars(_Symbol,_Period); if(barz>TerminalInfoInteger(TERMINAL_MAXBARS)){barz=TerminalInfoInteger(TERMINAL_MAXBARS);} int samples_possible=barz-window_size; if(samples_possible>1000){ int co=-1; ArrayResize(samples,samples_possible,0); for(int i=barz-1;i>=(1+window_size);i--){ Remark("Filling "+i); co++; samples[co].fill(i,window_size); } ArrayResize(samples,co+1,0); } return(ArraySize(samples)); } };
Easy stuff , we would like accomplished bars solely so 1 might be the final bar in a pattern , this can be sluggish as a result of we’re not presizing , however anyway
🍰
now , chart initializes , we delete all of the objects with our tag we setup a timer , we catch the samples on timer .
ae_sample_collection COLLECTION; snn_net internet; #outline SYSTEM_TAG "AE_" bool Loaded=false; int OnInit() { COLLECTION.reset(); internet.reset(); Loaded=false; ObjectsDeleteAll(ChartID(),SYSTEM_TAG); EventSetMillisecondTimer(544); return(INIT_SUCCEEDED); } void OnTimer(){ if(!Loaded){ EventKillTimer(); if(COLLECTION.fill(20)>=1000){ Remark("Samples created "); }else{ Alert("Too little samples"); ExpertRemove(); } } else{ } } void OnDeinit(const int cause) { COLLECTION.reset(); internet.reset(); ObjectsDeleteAll(ChartID(),SYSTEM_TAG); }
Cool , if the gathering doesn’t fill , bounce … now we have to setup the community ….
Let’s strive with a 3-2-3 within the center , not anticipating a lot ,however lets begin there , so
20-3-2-3-20 , jesus
internet.add_layer().setup(20); internet.add_layer().setup(3,20); internet.add_layer().setup(2,3); internet.add_layer().setup(3,2); internet.add_layer().setup(20,3);
Okay however how will we play with this ? It has to do stuffy stuff and be taught after which we gotta have the ability to nudge the
“encoding” (the center layers) and see what they product , for enjoyable , so we’d like :
- a sign of the loss avg
- slightly customized show that may show 20 columns , you see the place that is going
- the center layer with the two nodes outputs 0.0 to 1.0 because it has sigmoid activations
so what if now we have 2 inputs that at any level we are able to regulate and they’re going to spit out - the 20 bars (properly the open to shut measurement inside a spread actually) it thinks we’re sending (however we’re not sending something actually 3:) )
- a beer
Good , the loss perform might be a sign with the remark perform ,then 2 edits and a useful resource.
Let’s begin there , a field to which we ship bar-sizes of a % to its sides measurement and we plot the “logical” sequence of them
hopefully , if we get out of bounds we’ll want to increase the “hypothetical canvas” although as a result of we have to see.
Okay much less typing extra typing :
void create_fake_chart(double &fake_bars[], uint &pixels[], int &side_size, colour bgColor, colour upColor, colour dwColor ){ ArrayFill(pixels,0,ArraySize(pixels),ColorToARGB(bgColor,255)); double tfb=((double)ArraySize(fake_bars)); double bar_size=((double)side_size)/(((tfb+1.0)/2.0)+tfb); double gap_size=bar_size/2.0; double start_x=gap_size; }
Quickly we run into our first realization :
We do not know the beginning “y” or “pretend value” of the output , we simply know its imagined to have 1.0 on prime as max and 0.0 on the underside as min
So we’ll “middle it” or one thing ? , let’s have a look at , let’s log the general min and max and begin from 1.0
double emu_max=INT_MIN,emu_min=INT_MAX; double price_now=1.0; for(int i=0;i<ArraySize(fake_bars);i++){ price_now+=fake_bars[i]; if(price_now>emu_max){emu_max=price_now;} if(price_now<emu_min){emu_min=price_now;} }
kay so we do thiiis and now we have the “emulated max” and emulated min …. now what …
hmmm , okay we have to flip the sizes to cost factors , so we should always convert to shut costs and
then we are going to normalize them into the vary 0.0 to 1.0 , which doesn’t take note of the unique vary had taken highs and lows into consideration however it is a check so , let’s simply go along with it.
So change this to “costs” , we modify the loop to this , we add open and shut value , the primary open value is 1.0
double fake_bars_open_price[],fake_bars_close_price[]; ArrayResize(fake_bars_open_price,ArraySize(fake_bars),0); ArrayResize(fake_bars_close_price,ArraySize(fake_bars),0); for(int i=0;i<ArraySize(fake_bars);i++){ fake_bars_open_price[i]=price_now; price_now+=fake_bars[i]; fake_bars_close_price[i]=price_now; if(price_now>emu_max){emu_max=price_now;} if(price_now<emu_min){emu_min=price_now;} }
Okay now , to show from 0.0 to 1.0 we get the vary , we loop into every bar (which is now a value level) , we subtract the minimal , we divide by the vary and that is it .
and we do that :
double vary=emu_max-emu_min; for(int i=0;i<ArraySize(fake_bars);i++){ fake_bars_open_price[i]=(fake_bars_open_price[i]-emu_min)/vary; fake_bars_close_price[i]=(fake_bars_close_price[i]-emu_min)/vary; }
annoying however wanted . now … we gotta draw this … %^$#!^$#$ , let’s cheat … we open the canvas
we discover the fill rectange and we steal it …. 😇 that is what it appears to be like like , let’s make it much less civilized , ship it a pixels array , width +top .sco
void ResourceFillRectangle(int x1,int y1,int x2,int y2,const uint clr,uint &m_pixels[],int m_width,int m_height) { int tmp; if(x2<x1) { tmp=x1; x1 =x2; x2 =tmp; } if(y2<y1) { tmp=y1; y1 =y2; y2 =tmp; } if(x2<0 || y2<0 || x1>=m_width || y1>=m_height) return; if(x1<0) x1=0; if(y1<0) y1=0; if(x2>=m_width) x2=m_width -1; if(y2>=m_height) y2=m_height-1; int len=(x2-x1)+1; for(; y1<=y2; y1++) ArrayFill(m_pixels,y1*m_width+x1,len,clr); }
good that annoyance is gone too , now the final one go the pretend bars to the pixels
we should be cautious right here , the pixels y axis has 0 on prime and 1.0 on the backside , so now we have to flip it!
uint upc=ColorToARGB(upColor,255); uint doc=ColorToARGB(dwColor,255); for(int i=0;i<ArraySize(fake_bars)-1;i++){ double y_open=side_size-fake_bars_open_price[i]*((double)side_size); double y_close=side_size-fake_bars_close_price[i]*((double)side_size); uint colorused=upc; if(fake_bars_open_price[i]>fake_bars_close_price[i]){colorused=doc;} int x1=(int)start_x; int x2=(int)(start_x+bar_size); int y1=(int)MathMin(y_open,y_close); int y2=(int)MathMax(y_open,y_close); ResourceFillRectangle(x1,y1,x2,y2,colorused,pixels,side_size,side_size); }
So what did we do right here :
- We multiplied the 0.0 to 1.0 open with the aspect measurement .(so a worth from 0 to aspect measurement)
- We subtracted that from the aspect measurement to flip it , so , if it grows it strikes up not down
- We did the identical for the shut value and now we had the open y and shut y
- We assign the right colour based mostly on whether or not or not it goes up or down
- and we draw it
Good , it’d work , now we have to construct our “deck” the two inputs and the output useful resource and bitmap label.
Okay we add an enter for the dimensions , a pixels array referred to as show ,we free a show useful resource on init and exit , we create a bmp label and a couple of inputs .
enter int display_size=300; uint show[]; int py=30; for(int i=0;i<2;i++){ string title=SYSTEM_TAG+"_NODE"+IntegerToString(i); ObjectCreate(ChartID(),title,OBJ_EDIT,0,0,0); ObjectSetInteger(ChartID(),title,OBJPROP_XSIZE,150); ObjectSetInteger(ChartID(),title,OBJPROP_YSIZE,20); ObjectSetInteger(ChartID(),title,OBJPROP_XDISTANCE,10); ObjectSetInteger(ChartID(),title,OBJPROP_YDISTANCE,py); ObjectSetInteger(ChartID(),title,OBJPROP_BGCOLOR,clrDarkKhaki); ObjectSetInteger(ChartID(),title,OBJPROP_BORDER_COLOR,clrGold); ObjectSetInteger(ChartID(),title,OBJPROP_COLOR,clrYellow); ObjectSetString(ChartID(),title,OBJPROP_TEXT,"(Node "+IntegerToString(i)+" output) :"); py+=20; } string title=SYSTEM_TAG+"_DISPLAY"; ObjectCreate(ChartID(),title,OBJ_BITMAP_LABEL,0,0,0); ObjectSetInteger(ChartID(),title,OBJPROP_XSIZE,display_size); ObjectSetInteger(ChartID(),title,OBJPROP_YSIZE,display_size); ObjectSetInteger(ChartID(),title,OBJPROP_XDISTANCE,10); ObjectSetInteger(ChartID(),title,OBJPROP_YDISTANCE,py); ObjectSetString(ChartID(),title,OBJPROP_BMPFILE,"::DISPLAY"); ChartRedraw();
Nice , now we are going to :
- begin a timer interval and prepare on samples each interval , then replace the person (us) on the loss
- we are going to create a pause / proceed state of affairs for the “studying” so we are able to pause the coaching and play with the node outputs
- everytime the inputs change (for the node outputs) manually we draw the end result if the coaching is paused
Which means the inputs are hidden by default and there must be a pause button above them , hopefully the final mods we do , we set the loaded indication as true we add a busy indication and we’re good to go .
So we add these 2 parameters on prime
enter bool reset_stats_after_batch=true; enter double base_learning_rate=0.001;
Then a swap to point coaching is just not paused
bool Prepare=false;
and that is what the coaching block appears to be like like :
if(!SystemBusy&&Prepare){ SystemBusy=true; int ix=0; for(int i=0;i<ArraySize(COLLECTION.samples);i++) { ix+=MathRand(); whereas(ix>=ArraySize(COLLECTION.samples)){ix-=ArraySize(COLLECTION.samples);} internet.feed_forward(COLLECTION.samples[ix].bars); internet.calculate_loss(COLLECTION.samples[ix].bars); internet.back_propagation(); } double max_loss=internet.get_max_loss_per_sample(); double cur_loss=internet.get_current_loss_per_sample(); double a=(cur_loss/max_loss)*base_learning_rate; internet.regulate(a); if(reset_stats_after_batch){internet.reset_loss();} string comm="Loss ("+cur_loss+")/("+max_loss+")"; Remark(comm); SystemBusy=false; }
Okay , now , lastly , when the pause button is hit we :
- change it to “Proceed”
- present the two node inputs
- present the show block
- set Prepare to false
We add a chart occasion block for this :
void OnChartEvent(const int id,const lengthy& lparam,const double& dparam,const string& sparam) { if(Loaded&&id==CHARTEVENT_OBJECT_CLICK){ if(sparam==SYSTEM_TAG+"_PAUSE"&&Prepare){ ObjectSetString(ChartID(),SYSTEM_TAG+"_PAUSE",OBJPROP_TEXT,"Proceed"); for(int i=0;i<middleNodes;i++){ ObjectSetInteger(ChartID(),SYSTEM_TAG+"_NODE"+IntegerToString(i),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); } ObjectSetInteger(ChartID(),SYSTEM_TAG+"_DISPLAY",OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); Prepare=false; }else if(sparam==SYSTEM_TAG+"_PAUSE"&&!Prepare){ ObjectSetString(ChartID(),SYSTEM_TAG+"_PAUSE",OBJPROP_TEXT,"Pause"); for(int i=0;i<middleNodes;i++){ ObjectSetInteger(ChartID(),SYSTEM_TAG+"_NODE"+IntegerToString(i),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); } ObjectSetInteger(ChartID(),SYSTEM_TAG+"_DISPLAY",OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); Prepare=true; } } }
aand now , once we detect a change in inputs recalculate the pixels and recreate the useful resource , and hopefully it really works.
However wait , we should embrace a perform within the community that feeds ahead from a layer onwards . Why ?
As a result of we hijack the center layer’s output and we wish to see what it spits out on the opposite finish – and plot it
That is a simple config :
void partial_feed_forward(int from_layer_ix){ for(int i=from_layer_ix;i<ArraySize(layers);i++){ layers[i].feed_forward(layers[i-1]); } }
Easy , we see that the feed ahead will begin from the layer we ship in so if we stuffed outputs for the layer the arrow is pointint as much as then we are going to begin from the following layer , so 0 , 1, 2 ,thats layer 3 .
And we are going to refill a “pretend bars” array to ship all the way down to the plotter. we do not overlook our output is between 0.0 and 1.0 and we have to flip it to -1.0 to 1.0
else if(Loaded&&id==CHARTEVENT_OBJECT_ENDEDIT){ if(StringFind(sparam,SYSTEM_TAG+"_NODE",0)!=-1){ for(int i=0;i<middleNodes;i++){ double v=(double)StringToDouble(ObjectGetString(ChartID(),SYSTEM_TAG+"_NODE"+IntegerToString(i),OBJPROP_TEXT)); if(v<0.0){v=0.0;}else if(v>1.0){v=1.0;} internet.layers[2].nodes[i].output=v; } internet.partial_feed_forward(3); double fake_bars[]; ArrayResize(fake_bars,20,0); for(int i=0;i<20;i++){fake_bars[i]=internet.get_output(i);} for(int i=0;i<20;i++){fake_bars[i]=(fake_bars[i]*2.0)-1.0;} create_fake_chart(fake_bars,show,display_size,clrBlack,clrGreen,clrCrimson); if(ResourceCreate("DISPLAY",show,display_size,display_size,0,0,display_size,COLOR_FORMAT_ARGB_NORMALIZE)){ ChartRedraw(); } } }
Then we create the useful resource , redraw the chart .However it could be handy to throw that right into a perform as a result of we might have
to name it elsewhere too so :
void calculate_fake_chart(){ for(int i=0;i<middleNodes;i++){ double v=(double)StringToDouble(ObjectGetString(ChartID(),SYSTEM_TAG+"_NODE"+IntegerToString(i),OBJPROP_TEXT)); if(v<0.0){v=0.0;}else if(v>1.0){v=1.0;} internet.layers[2].nodes[i].output=v; } internet.partial_feed_forward(3); double fake_bars[]; ArrayResize(fake_bars,20,0); for(int i=0;i<20;i++){fake_bars[i]=internet.get_output(i);} for(int i=0;i<20;i++){fake_bars[i]=(fake_bars[i]*2.0)-1.0;} create_fake_chart(fake_bars,show,display_size,clrBlack,clrGreen,clrCrimson); if(ResourceCreate("DISPLAY",show,display_size,display_size,0,0,display_size,COLOR_FORMAT_ARGB_NORMALIZE)){ ChartRedraw(); } }
and we add a name once we pause the learnign and once we replace the node values manually.neat
Nicely as anticipated , there’s a bottleneck in samples filling up
So we’ll should presize the samples within the assortment …. however , vibrant aspect we’ll get 90k samples , that is good , will likely be sluggish af however good.
So we’re altering the fill perform of the pattern collector to this :
int fill(int window_size){ int barz=iBars(_Symbol,_Period); if(barz>TerminalInfoInteger(TERMINAL_MAXBARS)){barz=TerminalInfoInteger(TERMINAL_MAXBARS);} int samples_possible=barz-window_size; if(samples_possible>1000){ int co=-1; ArrayResize(samples,samples_possible,0); for(int i=barz-1;i>=(1+window_size);i--){ Remark("Filling "+i); co++; samples[co].fill(i,window_size); } ArrayResize(samples,co+1,0); } return(ArraySize(samples)); }
Now this run into nan -nan errors at first , so , theres points within the pattern assortment , you will not see them as i will edit the code snippets.
The second run was higher , it converged sooner and had no bizarre alien numbers , and it kinda appears to be like like an actual chart once you hit pause .
And it appears to be like like value motion once we manually tune the nodes within the center
after all one can say , bruh , all the pieces that comes out of the output may very well be plotted as value motion . true.
Let’s have a look at if we are able to animate this sh*t , and perceive what the two knobs …
what the two nobs imply . That is how AIs are drawing issues btw , all you gotta do (or it) is work out what the little nodes within the center tune.
So , let’s add a button that stops coaching however begins animating subsequent to the pause , we may make this look higher however i can simply go look within the mirror 😇 (jk) sco lets end this.
we add the button ,we add the animating swap , and steps and present values for the nobs. the animator will likely be taking one step per timer entry and drawing it.
Lets see what occurs :
hmm it appears to be like value actiony
what if we begin from totally different values for the nodes ?
There are mixtures in there that may very well be describing totally different exercise , so if one figures out what the encoder parameters do then you possibly can be a synthetic coaching value feed for example that resembles usdjpy (on this instance)
Learn extra concerning the easiest neural internet right here
[ad_2]