English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Reti neurali di terza generazione: Reti profonde

Reti neurali di terza generazione: Reti profonde

MetaTrader 5Indicatori | 12 gennaio 2022, 11:35
448 0
Vladimir Perervenko
Vladimir Perervenko

Contenuto

  1. Reti neurali di seconda generazione
  2. Apprendimento profondo
  3. Esperimenti pratici
  4. L'implementazione (Indicatore ed Expert Advisor)

Introduzione

Questo articolo prenderà in considerazione le idee principali di questo argomento come l’Apprendimento Profondo (Deep Learning) e Reti Profonde (Deep Network) senza calcoli complessi.

Gli esperimenti con dati reali confermano (o no) i vantaggi teorici delle reti neurali profonde rispetto a quelle poco profonde per definizione metrica e per confronto. Il compito in mano c'è la classificazione. Creeremo un indicatore e un Expert Advisor basati su un modello di rete neurale profonda, lavoreremo in congiunzione secondo lo schema client/ server e poi li testeremo.

Si presume che il lettore abbia una buona conoscenza dei concetti di base utilizzati nelle reti neurali.


1. Reti neurali di seconda generazione

Le reti neurali sono progettate per affrontare una vasta gamma di problemi legati all'elaborazione delle immagini.

Di seguito è riportato un elenco di problemi tipicamente risolti dalle reti neurali:

  • Approssimazione delle funzioni per un insieme di punti (regressione);
  • Classificazione dei dati in base all'insieme di classi specificato;
  • Clustering di dati con identificazione di classi prototipo precedentemente sconosciute;
  • Compressione delle informazioni;
  • Ripristino dei dati persi;
  • Memoria associativa;
  • Ottimizzazione, controllo ottimale ecc.

Dall'elenco sopra solo "Classificazione" sarà discusso in questo articolo.


1.1. L'architettura delle connessioni

Il modo di elaborazione delle informazioni è fortemente influenzato dall'assenza o dalla presenza di cicli di feedback nella rete. Se non ci sono cicli di feedback tra i neuroni (cioè la rete ha una struttura di strati sequenziali in cui ogni neurone riceve informazioni solo dal livello precedente), l'elaborazione delle informazioni nella rete è unidirezionale. Un segnale di ingresso viene elaborato da una sequenza di strati e la risposta viene ricevuta nel numero di tatti pari al numero di strati.

La presenza di cicli di feedback può rendere imprevedibile la dinamica di una rete neurale (in questo caso chiamata ricorrente). In realtà, una rete può entrare in infiniti loop ( loop forever) e non produrre mai una risposta. Allo stesso tempo, secondo Turing, non esiste un algoritmo per una rete ricorrente e arbitraria per identificare se i suoi elementi stanno per entrare in equilibrio (il problema dell'arresto).

In generale, il fatto che i neuroni nelle reti ricorrenti partecipino all'elaborazione delle informazioni molte volte, consente a tali reti di elaborare le informazioni a un livello più profondo in modi diversi. In questo caso dovrebbero essere prese misure speciali in modo che la rete non entri in loop per sempre. Ad esempio, utilizza connessioni simmetriche, come in una rete Hopfield o limita forzatamente il numero di iterazioni.


Tipo di allenamento

Tipo di connessione
Con un "supervisore"Senza un "supervisore"
Senza cicli di feedbackPercettroni multistrato (approssimazione delle funzioni, classificazione)

Rete competitiva, mappe auto-organizzate (compressione dei dati, separazione delle funzionalità)
Con cicli di feedbackPercettrone ricorrente (previsione di serie temporali, formazione on-line)

Rete di Hopfield (memoria associativa, cluster di dati, ottimizzazione)

Tabella Classificazione della rete neurale per tipo di connessione e tipo di addestramento


1.2. Principali tipi di reti neurali

Avendo iniziato con il percettrone, le reti neurali si sono evolute moltissimo. Oggi viene utilizzato un gran numero di reti neurali che variano nella struttura e nei metodi di allenamento.

Le più famose sono:

1.2.1. Multilayer Fully Connected Feedforward Networks MLP (Multilayer Perceptron)

Fig. 1. Struttura di una rete neurale multistrato

Fig. 1. Struttura di una rete neurale multistrato

1.2.2. Le reti di Jordan sono reti parzialmente ricorrenti e simili alle reti di Elman.

Possono essere trattate come reti feedforward con neuroni di contesto aggiuntivi nel livello di input.

Questi neuroni di contesto sono alimentati da soli (feedback diretto) e dai neuroni di input. I neuroni di contesto preservano lo stato attuale della rete. In una rete Jordan il numero di neuroni di contesto e di input deve essere lo stesso.

Fig. 2. Struttura di una rete di Jordan

Fig. 2. Struttura di una rete di Jordan

1.2.3. Le reti di Elman sono reti parzialmente ricorrenti e simili alle reti Jordan. La differenza tra le reti di Elman e Jordan è che in un contesto di rete di Elman i neuroni non sono alimentati da neuroni di uscita, ma da quelli nascosti. Inoltre, non c'è un feedback diretto nei neuroni di contesto.

In una rete di Elman il numero di neuroni di contesto e nascosti deve essere lo stesso. Il vantaggio principale delle reti di Elman è che il numero di neuroni di contesto è definito non dal numero di uscite come nella rete Jordan, ma dal numero di neuroni nascosti, il che rende la rete più flessibile. I neuroni nascosti possono essere facilmente aggiunti o portati via a differenza del numero di output.


Fig. 3. Struttura di una rete di Elman

Fig. 3. Struttura di una rete di Elman

1.2.4. Radial Basis Function Network (RBF) - è una rete neurale feed-forward che contiene uno strato intermedio (nascosto) di neuroni radialmente simmetrici. Tale neurone converte la distanza da un vettore di input specificato al suo centro corrispondente da una legge non lineare comunemente considerata gaussiana.

Le reti RBF presentano molti vantaggi rispetto alle reti feed forward multilivello. Prima di tutto, emulano (non sono sicuro della parola) una funzione arbitraria non lineare con un solo livello intermedio, il che risparmia allo sviluppatore la necessità di decidere il numero di livelli. Quindi, i parametri nella combinazione lineare nel livello di output possono essere ottimizzati con l'aiuto di metodi ampiamente noti di ottimizzazione lineare. Questi ultimi lavorano velocemente e non hanno difficoltà con i minimi locali che interferiscono notevolmente nella retropropagazione. Questo è il motivo per cui la rete RBF impara molto più velocemente rispetto a quando si utilizza la backpropagation.

Svantaggi di RBF: queste reti hanno caratteristiche di estrapolazione deboli e risultano essere ingombranti quando il vettore di input è grande.

Fig. 4. Struttura di unRBF

Fig. 4. Struttura di un RBF

1.2.5. Dynamic Learning Vector Quantization, DLVQ Networks sono molto simili alle mappe auto-organizzate (SOM). A differenza di SOM, DLVO sono in grado di apprendimento supervisionato e mancano di una relazione di vicinato tra i prototipi. La quantizzazione vettoriale ha un uso più ampio del clustering.

1.2.6. La rete di Hopfield è una rete completamente connessa con una matrice di connessione simmetrica. Durante il funzionamento, la dinamica di tali reti converge in uno degli stati di equilibrio. Questi stati di equilibrio sono minimi locali di funzionalità noti come energia della rete. Tale rete può essere utilizzata come sistema di memoria associativa indirizzabile al contenuto, come filtro e per affrontare alcune sfide di ottimizzazione.

A differenza di molte reti neurali che lavorano fino a quando non ricevono una risposta in un certo numero di tatti, le reti Hopfield funzionano fino a raggiungere lo stato di equilibrio, cioè quando lo stato successivo di una rete è esattamente lo stesso del precedente. In questo caso lo stato iniziale è un modello di input, mentre nello stato di equilibrio viene ricevuta l'immagine di output. La formazione di una rete Hopfield richiede un modello di addestramento da presentare contemporaneamente a livello di input e output.

Fig. 5. Struttura di una rete di Hopfield con tre neuroni

Fig. 5. Struttura di una rete di Hopfield con tre neuroni

Nonostante le caratteristiche accattivanti, una rete Hopfield classica è ben lungi dall'essere perfetta. Ha una memoria limitata, circa il 15% del numero di neuroni nella rete N, mentre i sistemi di memoria indirizzata possono memorizzare fino a 2N di immagini diverse, utilizzando N bit.

Inoltre, le reti Hopfield non sono in grado di riconoscere se l'immagine è spostata o girata in relazione alla sua posizione iniziale memorizzata. Questi e altri inconvenienti definiscono la percezione di una rete Hopfield come un modello teorico conveniente per lo studio piuttosto che uno strumento pratico per l'uso quotidiano.

Molti altri (rete ricorrente di Hemming, rete di Grossberg, reti di teoria della risonanza adattiva (ART-1, ART-2) ecc.) non sono stati menzionati in questo articolo in quanto sono al di fuori dell'ambito del nostro interesse.


1.3. Metodi di allenamento

La capacità di imparare cose nuove è la caratteristica principale di un cervello umano. Nel caso delle reti neurali artificiali, l'apprendimento è un processo di configurazione dell'architettura di rete (la struttura delle connessioni tra i neuroni) e dei pesi dei collegamenti sinaptici (che influenzano i segnali dei coefficienti) per ottenere una soluzione efficace per il compito in corso. Di solito l'addestramento di una rete neurale viene eseguito su un campione di dati. Un processo di addestramento segue un certo algoritmo e man mano che va avanti, la reazione della rete ai segnali di ingresso dovrebbe migliorare.

Esistono tre principali paradigmi di apprendimento: supervisionato,non supervisionato e combinato. Nel primo caso le risposte giuste per ogni esempio di input sono note e i pesi stanno cercando di minimizzare l'errore. L'apprendimento non supervisionato consente di classificare i campioni attraverso la spiegazione della struttura interna e della natura dei dati. Nella formazione combinata vengono utilizzati entrambi gli approcci di cui sopra.

1.3.1. Regole principali dell'apprendimento delle reti neurali

Ci sono quattro regole di apprendimento principali basate sull'architettura di rete ad esse collegata: correzione degli errori, legge di Boltzmann, regola di Hebb e apprendimento competitivo.

1.3.1.1. Correzione degli errori

Ogni esempio di input ha un valore di output desiderato specificato (valore target), che potrebbe non corrispondere a un valore reale (previsione). La regola di apprendimento della correzione degli errori utilizza la differenza tra il target e i valori di previsione per la regolazione diretta dei pesi al fine di ridurre l'errore. La formazione viene effettuata solo in caso di esito errato. Questa regola di apprendimento ha numerose modificazioni.

1.3.1.2. Regola di Boltzmann

La regola di Boltzmann è una regola di apprendimento stocastico per analogia con i principi termodinamici. Ciò si traduce nella regolazione dei coefficienti di peso dei neuroni in base alla distribuzione probabilistica desiderata. L'apprendimento della regola di Boltzmann può essere considerato come un caso isolato di correzione da un errore in cui un errore significa una discrepanza di correlazione degli stati in due modi.

1.3.1.3. Regola di Hebb

La regola di Hebb è l'algoritmo più famoso di apprendimento delle reti neurali. L'idea di questo metodo è che se i neuroni su entrambi i lati di una sinapsi si attivano simultaneamente e regolarmente, aumenta la forza della connessione sinaptica. Una particolarità importante qui è che il cambiamento di peso sinaptico dipende solo dall'attività dei neuroni collegati a questa sinapsi. Ci sono molte varianti di questa regola che differiscono nelle peculiarità nella modifica del peso sinaptico.

1.3.1.4. Apprendimento competitivo

A differenza della regola di apprendimento di Hebb, in cui un certo numero di neuroni di uscita può attivarsi contemporaneamente, qui i neuroni di uscita competono l'uno contro l'altro. Un neurone di uscita con valore massimo di somma pesata è il "vincitore" e "il vincitore prende tutto". Le uscite di altri neuroni di uscita sono impostate su inattive. Durante l'apprendimento, solo i pesi del "vincitore" vengono modificati mirando aumentando la vicinanza all'istanza di input corrente.

Ci sono molti algoritmi di apprendimento che affrontano diversi problemi. La backpropagation, uno degli algoritmi moderni più efficienti, è uno di questi. Il principio alla base è che il cambiamento di peso sinaptico avviene tenendo conto del gradiente locale della funzione di errore.

La differenza tra le risposte reali e corrette di una rete neurale valutata a livello di output viene riprodotta - verso il flusso di segnali (Fig.5). In questo modo ogni neurone può definire il contributo del suo peso in rapporto all'errore cumulativo della rete. La regola di apprendimento più semplice è il metodo di discesa più ripido, cioè la variazione del peso sinaptico proporzionale al suo contributo all'errore cumulativo.

Fig. 6. Il modello di diffusione dei dati e degli errori in una rete durante l'apprendimento attraverso la retropropagazione

Fig. 6. Il modello di diffusione dei dati e degli errori in una rete durante l'apprendimento attraverso la retropropagazione

Sicuramente, questo tipo di apprendimento della rete neurale non garantisce il miglior risultato di apprendimento in quanto c'è sempre la possibilità che l'algoritmo sia entrato in un minimo locale. Esistono tecniche speciali che consentono di eliminare la soluzione trovata da un punto estremo locale. Se dopo alcune applicazioni di questa tecnica la rete neurale ha la stessa decisione, allora si può concludere che la soluzione trovata ha maggiori probabilità di essere ottimale.

1.4. Svantaggi

  • La principale difficoltà nell'utilizzo delle reti neurali è la cosiddetta "maledizione della dimensionalità". Quando le dimensioni di input e il numero di livelli vengono aumentati, la complessità di una rete e il tempo di apprendimento crescono in modo esponenziale e il risultato ricevuto non è sempre ottimale.
  • Un'altra difficoltà nell'utilizzo delle reti neurali è che le reti neurali tradizionali non sono in grado di spiegare il modo in cui risolvono i compiti. In alcuni campi di applicazione come la medicina questa spiegazione è più importante del risultato stesso. La rappresentazione interna dei risultati è spesso così complessa che è impossibile analizzarla tranne i casi più semplici che di solito non interessano.

2. Apprendimento profondo

Oggi la teoria e la pratica del machine learning sta attraversando una "rivoluzione profonda", causata dal successo dell’implementazione dei metodi di deep learning, che rappresentano le reti neurali di terza generazione. A differenza delle classiche reti di seconda generazione utilizzate negli anni '80-'90 del secolo scorso, i nuovi paradigmi di apprendimento risolvono una serie di problemi che limitano l'espansione e l'implementazione delle reti neurali tradizionali.

Le reti addestrate con algoritmi di deep learning non hanno semplicemente eccelso i migliori metodi alternativi in termini di accuratezza, ma in alcuni casi hanno rivelato rudimenti di comprensione del senso delle informazioni di input. Il riconoscimento delle immagini e l'analisi delle informazioni di testo sono gli esempi più brillanti.

Oggi i metodi industriali più avanzati di visione artificiale e riconoscimento vocale si basano su reti profonde. Giganti del settore IT come Apple, Google, Facebook stanno impiegando ricercatori che sviluppano reti neurali profonde.


2.1. Background

Un team di studenti laureati che studiano all'Università di Toronto guidati dal professor Geoffrey E. Hinton ha vinto il primo premio in un concorso sponsorizzato da Merck. Utilizzando un set di dati limitato, che descrive la struttura chimica di 15 molecole, il gruppo di G. Hinton è riuscito a creare e applicare uno speciale sistema di programmi che definiva quale di quelle molecole aveva maggiori probabilità di essere una medicina efficace.

La particolarità di quel lavoro era che gli sviluppatori utilizzavano una rete neurale artificiale basata sul deep learning. Di conseguenza, quel sistema è riuscito a eseguire calcoli e ricerche basati su un insieme molto limitato di dati sorgente, mentre l'addestramento di una rete neurale richiede normalmente una quantità significativa di informazioni inserite nel sistema.

Il risultato della squadra di Hinton è stato particolarmente impressionante perché la squadra ha deciso di partecipare al concorso all'ultimo minuto. Inoltre, il sistema di deep learning è stato sviluppato senza conoscenze specifiche su come le molecole si legano ai loro obiettivi. L'implementazione di successo del deep learning è stata un altro risultato nello sviluppo dell'intelligenza artificiale del movimentato 2012.

Così nell'estate 2012, Jeff Dean e Andrew Y. Ng di Google hanno presentato un nuovo sistema di riconoscimento delle immagini con un tasso di precisione del 15,8%, dove per addestrare un sistema cluster di 16.000 nodi hanno utilizzato la rete ImageNet contenente una libreria di 14 milioni di immagini di 20.000 oggetti diversi. L'anno scorso un programma creato da scienziati svizzeri ha superato un essere umano nel riconoscere le immagini dei segnali stradali. Il programma vincitore ha identificato con precisione il 99,46% delle immagini in un set di 50.000; il punteggio più alto in un gruppo di 32 partecipanti umani era del 99,22% e la media per gli umani era del 98,84%. Nell'ottobre 2012, Richard F. Rashid, coordinatore dei programmi scientifici Microsoft, ha presentato a una conferenza a Tianjin, in Cina, una tecnologia di traduzione simultanea dall'inglese al mandarino accompagnata da una simulazione della propria voce.

Tutte queste tecnologie che dimostrano una svolta nel campo dell'intelligenza artificiale si basano sul metodo del deep learning in una certa misura. Il principale contributo alla teoria del deep learning è stato dato dal professor Hinton, pronipote di George Boole, uno scienziato inglese, fondatore dell'algebra di Boole alla base dei computer contemporanei.

La teoria del deep learning integra i metodi ordinari di apprendimento automatico con algoritmi speciali per l'analisi delle informazioni di input a diversi livelli di presentazione. La particolarità del nuovo approccio è che il deep learning studia il soggetto fino a trovare abbastanza livelli di presentazione informativa per tenere conto di tutti i fattori che possono influenzare i parametri dell'oggetto in questione.

In questo modo, una rete neurale basata su un tale approccio richiede meno informazioni di input per l'apprendimento e una rete addestrata è in grado di analizzare le informazioni con un livello di precisione più elevato rispetto alle normali reti neurali. Il professor Hinton e i suoi colleghi affermano che la loro tecnologia è particolarmente utile per la ricerca di peculiarità in array di informazioni multidimensionali e ben strutturati.

Le tecnologie di intelligenza artificiale (AI), in particolare il deep learning, sono ampiamente utilizzate in diversi sistemi, tra cui l'assistente personale intelligente Apple Siri basato sulle tecnologie Nuance Communications e il riconoscimento degli indirizzi in Google Street View. Tuttavia, gli scienziati stanno stimando il successo in questa sfera con molta attenzione poiché la storia della creazione di un'intelligenza artificiale è piena di promesse e delusioni.

Nel 1960, gli scienziati credevano che ci sarebbero voluti solo 10 anni per creare un'intelligenza artificiale completa. Poi, nel 1980, c'è stata un'ondata di giovani aziende che offrivano una "intelligenza artificiale già pronta" seguita dall'"era glaciale" in questa sfera, che è durata fino a poco tempo fa. Oggi le ampie capacità computazionali disponibili nei servizi cloud forniscono un nuovo livello di potente implementazione della rete neurale utilizzando nuove basi teoriche e algoritmiche.

Va notato che le reti neurali, anche quelle di terza generazione come le reti neurali convoluzionali, gli autoassociatori, le macchine di Boltzmann, hanno in comune con i neuroni biologici solo il nome.

Il nuovo paradigma di apprendimento implementa l'idea di apprendimento in due fasi. Nella prima fase, le informazioni sulla struttura interna dei dati di input vengono estratte da una vasta gamma di dati non formattati con l'autoassociatore attraverso una formazione non supervisionata strato per strato. Quindi, utilizzando queste informazioni in una rete neurale multistrato, queste passano attraverso un addestramento supervisionato da metodi noti che utilizzano dati formattati. Allo stesso tempo, la quantità di dati non formattati dovrebbe essere la più grande possibile. I dati formattati possono essere di dimensioni molto più piccole. Nel nostro caso non è di importanza immediata.


2.2. Autoencodificatori (autoencoder). Autoencodificatore e Restricted Boltzmann Machine. Differenze e peculiarità

2.2.1. Autoencoder

Il primo autoassociatore (АА) fu un neocognitrone di Fukushima.

La sua struttura è presentata in Fig.7.

Fig. 7. Il neocognitrone di Fukushima

Fig. 7. Il neocognitrone di Fukushima

Lo scopo di un autoassociatore (АА) è quello di ricevere all'uscita l'immagine dell’ingresso la piu precisa possibile.

Esistono due tipi di АА: generativo e sintetizzatore. Una macchina Boltzmann con restrizioni appartiene al primo tipo e un autoencoder rappresenta il secondo tipo.

Un autoencoder è una rete neurale con un livello aperto. Utilizzando l'algoritmo di apprendimento non supervisionato e la back propagation, imposta un valore target uguale al vettore di input, ovvero y = x.

Un esempio di autoencoder è presentato in Fig.8.

Fig. 8. Una struttura autoencoder

Fig. 8. Una struttura di autoencoder

Autoencoder sta tentando di costruire la funzione h(x)=x. In altre parole sta cercando di trovare un'approssimazione di una funzione che garantisca che un feedback della rete neurale sia approssimativamente uguale ai valori dei parametri di input. Affinché la soluzione del problema non sia banale, il numero di neuroni nello strato aperto deve essere inferiore alla dimensione dei dati di input (come nell'immagine).

Questo permette di comprimere i dati quando il segnale di ingresso viene passato all'uscita di rete. Ad esempio, se il vettore di input è l’insieme di livelli di luminosità di un'immagine di dimensioni 10х10 pixel (100 caratteristiche), il numero di neuroni dello strato nascosto è 50, la rete è costretta a imparare a comprimere l'immagine. Il requisito h(x)=x significa che in base ai livelli di attivazione di cinquanta neuroni dello strato nascosto, il livello di output è quello di ripristinare 100 pixel dell'immagine iniziale. Tale compressione è possibile se ci sono interconnessioninascoste, correlazione caratteristica o qualsiasi struttura. In questo modo un'operazione di autoencoder ricorda il metodo di analisi dei componenti principali (PCA) nel senso che i dati di input vengono ridotti.

Sorprendentemente, gli esperimenti condotti da Bengio et al. (2007), hanno dimostrato che durante l'allenamento con la discesa del gradiente stocastico, le reti di autocodifica non lineare con il numero di neuroni nascosti maggiore del numero di ingressi (chiamati anche "sovrabbondanti") avevano una presentazione utile alla luce dell'errore di conformità della rete che ha preso quella presentazione dall'input.

Più tardi, quando apparve l'idea della sparsità, un autoencoder sparso fu ampiamente utilizzato.

Un autoencoder sparso è un autoencoder che ha un numero di neuroni nascosti significativamente maggiore della dimensione di input, ma hanno un'attivazione sparsa. Un'attivazione sparsa è quando il numero di neuroni inattivi nello strato nascosto è significativamente maggiore del numero di quelli attivi. Se descriviamo la sparsità in modo informale, allora un neurone può essere considerato attivo se il valore della sua funzione è vicino a 1. Se è in uso una funzione sigmoide, allora per il neurone inattivo il suo valore deve essere vicino a 0 (per la funzione di tangente iperbolica il valore dovrebbe essere vicino a -1).

Esiste una variante di un autoencoder chiamato autoencoder denoising (Vincent et al., 2008). Questo è lo stesso autoencoder ma la sua formazione ha alcune peculiarità. Durante il training di questa rete, vengono inseriti dati "danneggiati" (alcuni valori vengono sostituiti con 0). Allo stesso tempo, ci sono dati "corretti" da confrontare con i dati di output. In questo modo un autoencoder può ripristinare i dati danneggiati.


2.2.2. Macchina Boltzmann ristretta, RBM.

Non ci concentreremo sulla storia della macchina di Boltzmann ristretta (RBM). Tutto quello che dobbiamo sapere è che tutto è iniziato con reti neurali ricorrenti con feedback che erano molto difficili da addestrare. A causa di questa difficoltà di apprendimento, sono apparsi modelli ricorrenti più ristretti in modo da poter applicare algoritmi di apprendimento più semplici. La rete neurale di Hopfield era uno di questi modelli. John Hopfield è stata la persona che ha introdotto il concetto di energia di rete dopo aver messo a confronto le dinamiche delle reti neurali con la termodinamica.

Il passo successivo per un RBM erano le normali macchine Boltzmann. Differiscono da una rete di Hopfield per avere natura stocastica e i suoi neuroni sono divisi in due gruppi che descrivono stati visibili e nascosti (simili a un modello di Markov nascosto). Una macchina di Boltzmann ristretta è diversa da una normale in assenza di connessioni tra i neuroni di uno strato.

La Fig. 9 rappresenta una struttura RBM.

Fig. 9. Una struttura RBM

Fig. 9. Una struttura RBM

La particolarità di questo modello è che negli stati attuali dei neuroni di un gruppo, gli stati dei neuroni di un altro gruppo saranno indipendenti l'uno dall'altro. Ora possiamo passare a qualche teoria in cui questa proprietà ha il ruolo chiave.

Interpretazione e obiettivo

Un RBM viene interpretato in modo simile a un modello di Markov nascosto. Abbiamo un certo numero di stati che possiamo osservare (neuroni visibili) e un certo numero di stati nascosti che non possiamo vedere direttamente (neuroni nascosti). Possiamo arrivare a una conclusione basata sulla probabilità sugli stati nascosti basandoci sugli stati che possiamo osservare. Dopo che un tale modello è stato addestrato, abbiamo l'opportunità di trarre conclusioni sugli stati visibili sapendo che quelli nascosti stanno seguendo il teorema di Bayes. Ciò consente di generare dati dalla distribuzione di probabilità utilizzata per il training del modello.

In questo modo possiamo formulare l'obiettivo del training di un modello: i parametri del modello devono essere regolati nel modo in cui un vettore ripristinato dallo stato iniziale è il più vicino all'originale. Un vettore restaurato è un vettore ricevuto da un'inferenza probabilistica da stati nascosti, che a loro volta, sono stati ricevuti da un'inferenza probabilistica da stati visibili, cioè dal vettore originale.

L'algoritmo di addestramento è Contrastive Divergence CD-k

Questo algoritmo è stato inventato dal professor Hinton nel 2002 ed è straordinariamente semplice. L'idea principale è che i valori di aspettativa matematica siano sostituiti da valori definiti. Introdotta è l'idea del campionamento di Gibbs.

Il CD-k è simile a:

  1. Lo stato dei neuroni visibili è impostato uguale al modello di input;
  2. Vengono disegnate le probabilità degli stati del livello nascosto;
  3. Ad ogni neurone dello strato nascosto viene assegnato lo stato "1" con probabilità uguale al suo stato attuale;
  4. Le probabilità degli stati del livello visibile vengono disegnate in base al livello nascosto;
  5. Se l'iterazione corrente è inferiore a k, tornare al passaggio 2;
  6. Vengono disegnate le probabilità degli stati del livello nascosto;

Nelle sue lezioni, Hinton disegna questo schema:

Fig.10. Algoritmo dell'apprendimento CD-k

Fig.10. Algoritmo dell'apprendimento CD-k

In altre parole, più a lungo facciamo campionamento, più preciso è il gradiente. Il professore afferma che il risultato ricevuto per CD-1, cioè una sola iterazione di campionamento, è già buono.


2.3. Reti di autoassociatori impilati (Stacked Autoassociators Networks). Stackеd Autoencoder SAE, Stacked Restricted Boltzmann Machine (Stacked RBM)

Per estrarre astrazioni di alto livello dal set di dati di input, gli autoassociatori vengono combinati in una rete.

La Fig. 11 rappresenta una struttura di autoencoder impilati e una rete neurale, che insieme rappresentano una rete neurale profonda con pesi inizializzati da un autoencoder impilato

Fig. 11. Struttura di un DN SAE

Fig. 11. Struttura di un DN SAE

In Fig.12 c'è un pattern di un RBM impilato (SRBM) e una rete neurale, che insieme rappresentano una rete neurale profonda con pesi inizializzati da SRBM.

Queste illustrazioni di strutture di rete profonde sottolineano il fatto che le informazioni vengono estratte dal basso verso l'alto.

Fig. 12. Struttura di un DN SRBM

Fig. 12. Struttura di un DN SRBM

2.4. Formazione di reti profonde (DN). Fasi. Peculiarità

La formazione di reti profonde comprende due fasi. Nella prima fase, una rete di autoassociatori (SAE o SRBM, a seconda del tipo di DN) riceve una formazione non supervisionata su un array di dati non formattato. Successivamente, i neuroni dello strato nascosto della MLP ordinaria vengono inizializzati dai pesi dello strato nascosto ricevuti dopo l'allenamento. La Fig. 11 e la Fig. 12 rappresentano un modello dei processi di apprendimento e trasferimento. Dopo l'allenamento del primo АЕ / RBM, i pesi neuronali dello strato nascosto diventano input del secondo ecc. In questo modo, la generalizzazione delle informazioni sulla struttura (linea, contorno, patter ecc.) viene estratta dai dati.

La seconda fase è il tempo per la messa a punto del MLP (supervised training) su set di dati formattati utilizzando metodi ben noti. La pratica ha dimostrato che tale inizializzazione imposta i pesi neuronali degli strati nascosti della MLP al minimo globale e la successiva messa a punto richiede un tempo molto breve.

Inoltre, per le reti profonde con il numero di strati maggiore di tre, D. Hinton ha suggerito che la messa a punto dovrebbe essere condotta in due fasi. Nella prima fase dovrebbero essere addestrati solo due strati superiori e nella seconda il resto della rete.

Va detto che un SRBM ha risultati meno stabili di formazione non supervisionata rispetto a un SAE.

Nota: Molto spesso questi termini sono confusi. Un SRBM è identificato con una rete di credenze profonde DBN. Nonostante il fatto che un RBM derivi da un DBN, queste sono strutture totalmente diverse. Un DBN è una rete neurale multistrato, con pesi neuronali di strati nascosti inizializzati casualmente da modelli binari.


3. Esperimenti pratici

Le reti profonde saranno eseguite in R.

3.1. Il linguaggio R

Cronologia R è un linguaggio di programmazione e un ambiente per i calcoli statistici e la creazione di grafici, sviluppato nel 1996 dagli scienziati neozelandesi Ross Ihaka e Robert Gentleman della Aokland University.

R è un progetto GNU che è un software libero e la sua filosofia si riduce ai seguenti principi:

  • libertà di lanciare programmi per qualsiasi scopo (libertà 0);
  • libertà di imparare come funziona un programma e adattarlo alle proprie esigenze (libertà 1);
  • libertà di distribuire copie per aiutare gli altri (libertà 2);
  • libertà di migliorare il programma e lasciare che la società tragga beneficio dai miglioramenti.

Nella prospettiva storica, R è un'alternativa per l'implementazione di S. Quest'ultimo è stato sviluppato da John Chambers e dai suoi colleghi della società Bell Labs nel 1976. Oggi, R è ancora in fase di miglioramento da parte del team centrale di R, di cui fa parte John Chambers.

Per ripetere gli esperimenti, è necessario installare R e Rstudio. Informazioni su dove scaricarlo e come si può trovare su Internet. Se ci sono domande, possiamo discuterne nei commenti all'articolo.

Vantaggi di R:

  • Oggi R è lo standard nei calcoli statistici.
  • Viene sviluppato e supportato dalla comunità scientifica globale delle università.
  • Ampia gamma di pacchetti per tutti i campi avanzati del data mining. Il tempo tra la pubblicazione dell'idea e la sua implementazione nel pacchetto R di solito non è più di 2 settimane.
  • E, ultimo ma non meno importante, è assolutamente gratuito. Un famoso sviluppatore di un sistema operativo gratuito ha detto una volta: "I programmi sono come il sesso - è meglio quando è gratuito".


3.2. Variazioni di implementazione e problemi riscontrati

Esistono due possibili modi di implementazione.

Il primo prevede l'utilizzo di programmi unici di John Hinton per Matlab. Per questo è richiesto il "R.matlab". Questo pacchetto dispone dei metodi writeMat() e readMat() per la lettura e la scrittura dei file MAT. Consente la comunicazione (implementazione del codice, invio e ricezione di oggetti, ecc.) da Matlab v6 e versioni successive avviate localmente o sull'host remoto nel collegamento client-server. I dettagli possono essere trovati nella descrizione del pacchetto. Questo è il modo per coloro che si trovano a proprio agio con Matlab. Non ho provato a utilizzare questo metodo ma c'è la possibilità di collegare Matlab e MQL in questo modo.

Il secondo modo di implementazione consiste nell'utilizzare i pacchetti R su questo argomento. Lo esploreremo.

Ci sono tre pacchetti che so essere collegati all'argomento di questo articolo:

  1. "deepnet" è un semplice pacchetto che implementa i modelli DN SAE e DN SRBM. La lunghezza del set di dati di input all'apprendimento supervisionato e non supervisionato è la stessa. Non dà l'opportunità di eseguire la messa a punto del sistema in due fasi. Utilizzato per l'esplorazione e il test dei modelli all'inizio.

  2. "darh" è un pacchetto avanzato e di ampio respiro per la modellazione per DN SRBM. C'è un modello per DN SAE ma non sono riuscito a lanciarlo. Questo pacchetto è per utenti esperti, consente di creare e ottimizzare un modello di qualsiasi livello di complessità. Si basa sui programmi unici di Hinton nel linguaggio m per MatLab.

  3. "H2O" è un ampio pacchetto per l'addestramento di reti profonde (non solo) su grandi set di dati (>1 Гб) scritti in file csv.

Negli esperimenti seguenti useremo il pacchetto "deepnet".


3.3. Preparazione dei dati di input e di destinazione per l'esperimento

Oggi il data mining ha un certo ordine di lavoro:

  1. Selezione dei dati di input (studio, analisi, preparazione preliminare, valutazione). Suddivisione dei dati nei set di formazione, convalida e test (campioni);
  2. Training di un modello sul set di dati di training e selezione di uno/più modelli su quello di validazione;
  3. Valutazione della qualità del modello/dei modelli sul campione di prova e definizione dei parametri ottimali del modello o del miglior modello fuori dal set con determinate misure;
  4. Lasciare che il modello / i modelli inizino il lavoro.

La prima fase è la più dispendiosa in termini di tempo e molto importante per il risultato finale. Per essere onesti, questa fase non è formalizzata e in generale è quasi una forma d'arte. Molto dipende dall'esperienza di un ricercatore. Tuttavia! Ottenere valutazioni quantitative del set di dati di input per selezionare quelli più importanti è molto importante. La selezione automatica delle migliori variabili per un determinato modello è ancora meglio in questo caso. R offre ampie funzionalità per affrontare le sfide in tutte le fasi.

I dati di origine non sono solo molto importanti, ma hanno anche molti aspetti interessanti. Meritano un articolo a parte. Poiché l'obiettivo di questo articolo è quello di raccontare una cosa complessa in parole molto semplici, discuteremo i punti importanti ma non entreremo molto nei dettagli.


3.3.1. Dati di origine

Per la nostra classificazione abbiamo bisogno di un insieme di variabili indipendenti (input) e una variabile target. Poiché il principale vantaggio pronunciato delle reti profonde è la loro capacità di apprendere rapidamente su campioni di input di grandi dimensioni, creiamo un set di dati di input composto da 17 predittori (11 indicatori). ZigZag ha un ruolo di variabile target. Scarica nell'ambiente R vettori di Open, High, Low, Close quote 4000 bars deep. Il modo per farlo è discusso di seguito nella descrizione della scrittura di un indicatore. In questa fase non è importante. Tutti gli ulteriori calcoli saranno eseguiti in R.

Costruisci una matrice da 4 vettori, prezzo medio e dimensioni del corpo della barra. Trasformalo in una funzione:

pr.OHLC <- function (o, h, l, c) 
{
  #Unite quote vectors into a matrix having previously expanded them
  #Indexing of time series of vectors in R starts with 1. 
  #Direction of indexing is from old to new ones.   
  price <- cbind(Open = rev(o), High = rev(h), Low = rev(l), Close = rev(c))
  Med <- (price[, 2] + price[, 3])/2
  CO <- price[, 4] - price[, 1]
  #add Med and CO to the matrix
  price <- cbind(price, Med, CO)
}

Vedi il risultato (stato alle 08.10. 14 12:00)

> head(price)
        Open    High     Low   Close      Med     CO
[1,] 1.33848 1.33851 1.33824 1.33844 1.338375 -4e-05
[2,] 1.33843 1.33868 1.33842 1.33851 1.338550  8e-05
[3,] 1.33849 1.33862 1.33846 1.33859 1.338540  1e-04
[4,] 1.33858 1.33861 1.33856 1.33859 1.338585  1e-05
[5,] 1.33862 1.33868 1.33855 1.33855 1.338615 -7e-05
[6,] 1.33853 1.33856 1.33846 1.33855 1.338510  2e-05


3.3.2. Dati di input (predittori)

Elenca gli indicatori. Gli indicatori sono stati selezionati in modo casuale, senza preferenze per ottenere la massima differenza di dimensioni di input.

Il calcolo di tutti gli indicatori viene eseguito utilizzando il pacchetto "TTR" contenente numerosi indicatori.


3.3.2.1. Indicatore Welles Wilder's Directional Movement Index - ADX(HLC, n) - 4 out (Dip, Din,DX, ADX)

Calcola e guarda come appare sulle prime 200 barre:

> library(TTR)
> adx<-ADX(price, n = 16)
> plot.ts(head(adx, 200))

Fig. 13. Indicatore Welles Wilder's Directional Movement Index - ADX(HLC, n)

Fig. 13. Indicatore Welles Wilder's Directional Movement Index - ADX(HLC, n)

> summary(adx)
      DIp             DIn                DX                 ADX    
 Min.   :15.90   Min.   :  5.468   Min.   : 0.00831      Min.   : 5.482   
 1st Qu.:41.21   1st Qu.: 33.599   1st Qu.: 8.05849      1st Qu.:14.046 
 Median :47.36   Median : 43.216   Median :16.95423      Median :18.099
 Mean   :47.14   Mean   : 46.170   Mean   :19.73032      Mean   :19.609 
 3rd Qu.:53.31   3rd Qu.: 55.315   3rd Qu.:27.97471      3rd Qu.:23.961     
 Max.   :80.12   Max.   :199.251   Max.   :81.08751      Max.   :52.413
 NA's   :16      NA's   :16        NA's   :16            NA's   :31 

All'inizio della matrice ci sono 31 valori indefiniti (NA). Quindi esegui gli stessi calcoli per tutti gli indicatori senza spiegazioni dettagliate.


3.3.2.2. aroon(HL, n) - 1 out (oscillatore)

Calcola e vedi le prime 200 barre di un solo "oscillatore" variabile

> ar<-aroon(price[ , c('High', 'Low')], n = 16)[ ,'oscillator']
> plot(head(ar, 200), t = "l")
> abline(h = 0)

Fig. 14. Indicatore aroon(HL,n)

Fig. 14. Indicatore aroon(HL, n)

> summary(ar)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
-100.00  -56.25  -18.75   -7.67   43.75  100.00      16 


3.3.2.3. Commodity Channel Index - CCI(HLC, n) - 1 uscita

> cci<-CCI(price[ ,2:4], n = 16)
> plot.ts(head(cci, 200))
> abline(h = 0)

Fig. 15. Indicatore Commodity Channel Index - CCI(HLC, n)

Fig. 15. Indicatore Commodity Channel Index - CCI(HLC, n)

> summary(cci)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
-469.10  -90.95  -18.74  -14.03   66.91  388.20      15 


3.3.2.4. Chaikin Volatility - chaikinVolatility (HLC, n) - 1 uscita

> chv<-chaikinVolatility(price[ , 2:4], n = 16)
> summary(chv)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max.     NA's 
-0.67570 -0.29940  0.02085  0.12890  0.41580  5.15700       31 
> plot(head(chv, 200), t = "l")
> abline(h = 0)

Fig. 16. Indicatore chaikinVolatility (HLC, n)

Fig. 16. Indicatore chaikinVolatility (HLC, n)

3.3.2.5. Oscillatore Chande Momentum - CMO(Med, n) - 1 uscita

> cmo<-CMO(price[ ,'Med'], n = 16)
> plot(head(cmo, 200), t = "l")
> abline(h = 0)

Fig. 17. Indicatore Chande Momentum Oscillatore - CMO(Med, n)

Fig. 17. Indicatore Chande Momentum Oscillatore - CMO(Med, n)

> summary(cmo)
   Min.    1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
-97.670 -32.650  -5.400  -6.075  19.530  93.080      16 


3.3.2.6. Oscillatore MACD - MACD(Med, nFast, nSlow, nSig) è usato 1 in uscita (macd)

> macd<-MACD(price[ ,'Med'], 12, 26, 9)[ ,'macd']
> plot(head(macd, 200), t = "l")
> abline(h = 0)

Fig. 18. Indicatore oscillatore MACD

Fig. 18. Indicatore oscillatore MACD

> summary(macd)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max.      NA's
-0.346900 -0.025150 -0.005716 -0.011370  0.013790  0.088880      25       


3.3.2.7. OsMA(Med,nFast, nSlow, nSig) – 1 uscita

> osma<-macd - MACD(price[ ,'Med'],12, 26, 9)[ ,'signal']
> plot(head(osma, 200), t = "l")
> abline(h = 0)

Fig. 19. Indicatore OsMA(Med,nFast, nSlow, nSig)

Fig. 19. Indicatore OsMA (Med, nFast, nSlow, nSig)

> summary(osma)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max.     NA's 
-0.10560 -0.00526  0.00034  0.00007  0.00646  0.05922       33 


3.3.2.8. Indice di forza relativa - RSI(Med,n) – 1 out

> rsi<-RSI(price[ ,'Med'], n = 16)
> plot(head(rsi, 200), t = "l")
> abline(h = 50)

Fig. 20. Indicatore Indice di Forza Relativa - RSI(Med,n)

Fig. 20. Indicatore Indice di Forza Relativa - RSI(Med,n)

> summary(rsi)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   5.32   37.33   47.15   46.53   55.71   84.82      16 


3.3.2.9. Stochastic Oscillator - stoch(HLC, nFastK=14, nFastD=3, nSlowD=3) - 3 out

> stoh<-stoch(price[ ,2:4], 14, 3, 3)
> plot.ts(head(stoh, 200))

Fig. 21. Indicatore Oscillatore stocastico - stoch(HLC, nFastK=14, nFastD=3,nSlowD=3)

Fig. 21. Indicator Stochastic Oscillator - stoch(HLC, nFastK=14, nFastD=3, nSlowD=3)

> summary(stoh)
     fastK            fastD             slowD        
 Min.   :0.0000   Min.   :0.01782   Min.   :0.02388  
 1st Qu.:0.2250   1st Qu.:0.23948   1st Qu.:0.24873  
 Median :0.4450   Median :0.44205   Median :0.44113  
 Mean   :0.4622   Mean   :0.46212   Mean   :0.46207  
 3rd Qu.:0.6842   3rd Qu.:0.67088   3rd Qu.:0.66709  
 Max.   :1.0000   Max.   :0.99074   Max.   :0.97626  
 NA's   :13       NA's   :15        NA's   :17     


3.3.2.10. Stochastic Momentum Index - SMI(HLC, n = 13, nFast = 2, nSlow = 25, nSig = 9) — 2 out

> smi<-SMI(price[ ,2:4],n = 13, nFast = 2, nSlow = 25, nSig = 9)
> plot.ts(head(smi, 200))

Fig. 22. Indicatore Stochastic Momentum Index - SMI(HLC, n = 13, nFast = 2, nSlow = 25, nSig = 9)

Fig. 22. Indicatore Stochastic Momentum Index - SMI(HLC, n = 13, nFast = 2, nSlow = 25, nSig = 9)

> summary(smi)
      SMI              signal       
 Min.   :-82.185   Min.   :-78.470  
 1st Qu.:-33.392   1st Qu.:-31.307  
 Median : -9.320   Median : -8.839  
 Mean   : -8.942   Mean   : -8.985  
 3rd Qu.: 15.664   3rd Qu.: 14.069  
 Max.   : 71.878   Max.   : 63.865  
 NA's   :25        NA's   :33  


3.3.2.11. Volatilità (Yang e Zhang) - volatilità (OHLC, n, calc="yang.zhang", N=96)- 1 out

> vol<-volatility(price[ ,1:4],n = 16,calc = "yang.zhang", N =96)
> plot.ts(head(vol, 200))

Fig. 23. Indicatore Volatilità (Yang e Zhang) - volatilità(OHLC, n, calc="yang.zhang", N=96)

Fig. 23. Indicatore Volatilità (Yang e Zhang) - volatilità (OHLC, n, calc="yang.zhang", N=96)

> summary(vol)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max.      NA's
0.000599 0.001858 0.002638 0.003127 0.004015 0.012840      16      

Quindi abbiamo 17 variabili da 11 indicatori per EURUSD sul timeframe М15 per il campione OHLC a 4000 bar di profondità.

Usali per formare una matrice e scrivere i parametri di cui sopra in una funzione con un parametro formale р, che sarà necessario per l'ottimizzazione.

Calcola la matrice dei parametri di input usando la formula:

In<-function(p = 16){
  adx<-ADX(price, n = p);
  ar<-aroon(price[ ,c('High', 'Low')], n=p)[ ,'oscillator'];
  cci<-CCI(price[ ,2:4], n = p);
  chv<-chaikinVolatility(price[ ,2:4], n = p);
  cmo<-CMO(price[ ,'Med'], n = p);
  macd<-MACD(price[ ,'Med'], 12, 26, 9)[ ,'macd'];
  osma<-macd - MACD(price[ ,'Med'],12, 26, 9)[ ,'signal'];
  rsi<-RSI(price[ ,'Med'], n = p);
  stoh<-stoch(price[ ,2:4],14, 3, 3);
  smi<-SMI(price[ ,2:4],n = p, nFast = 2, nSlow = 25, nSig = 9);
  vol<-volatility(price[ ,1:4],n = p,calc="yang.zhang", N=96);
  In<-cbind(adx, ar, cci, chv, cmo, macd, osma, rsi, stoh, smi, vol);
  return(In)
}
> X<-In()
> tail(X)
             DIp      DIn       DX      ADX   ar      cci       chv
[3995,] 46.49620 36.32411 12.28212 18.17544 25.0 168.0407 0.1835102
[3996,] 52.99009 31.61164 25.26952 18.61882 37.5 227.7030 0.3189822
[3997,] 58.11948 28.16241 34.72000 19.62515 37.5 145.2337 0.3448520
[3998,] 56.00323 30.48687 29.50206 20.24245 37.5 118.5831 0.3068059
[3999,] 55.96197 28.78737 32.06467 20.98134 37.5 116.5376 0.3517668
[4000,] 54.97777 26.85440 34.36713 21.81795 62.5 160.0767 0.6169701
             cmo         macd       osma      rsi     fastK
[3995,] 29.71342 -0.020870825 0.01666593 52.91932 0.8832685
[3996,] 41.89526 -0.009654368 0.02230591 61.49793 0.8833819
[3997,] 30.98237 -0.002051532 0.02392699 58.94513 0.7259475
[3998,] 33.84813  0.003454534 0.02354645 58.00549 0.7930029
[3999,] 38.84892  0.009590136 0.02374564 60.63806 0.8367347
[4000,] 54.71698  0.019303110 0.02676689 66.64815 0.9354120
            fastD     slowD        SMI    signal         vol
[3995,] 0.7773581 0.7735064 -35.095406 -47.27712 0.003643196
[3996,] 0.7691688 0.7761507 -26.482951 -43.11828 0.003858942
[3997,] 0.8308660 0.7924643 -19.699762 -38.43458 0.003920541
[3998,] 0.8007775 0.8002707 -13.141932 -33.37605 0.003916109
[3999,] 0.7852284 0.8056239  -6.569699 -28.01478 0.003999789
[4000,] 0.8550499 0.8136852   2.197810 -21.97226 0.004293766

Vengono preparati i dati di input grezzi.


3.3.3. Dati di output (destinazione)

Ora formeremo l'output (dati di destinazione). Come accennato in precedenza, useremo ZigZag.

Useremo ZigZag con la larghezza del canale di 37 punti grandi. ZigZag sarà calcolato dal prezzo medio. L'indicatore può essere calcolato dai prezzi HL, tuttavia il prezzo medio è preferibile in quanto l'indicatore è più stabile in questo caso. Dopo aver estratto il segnale (0 - Acquista, 1 -Vendi), convertilo in una matrice di ingresso, che assume il modello di rete.

Scrivi una funzione:

Out<-function(ch=0.0037){
  # ZigZag has values on each bar and not only in the points 
  zz<-ZigZag(price[ ,'Med'], change = ch, percent = F, retrace = F, lastExtreme = T);
  n<-1:length(zz);
  # On the last bars substitute the undefined values for the last known ones
  for(i in n) { if(is.na(zz[i])) zz[i] = zz[i-1];}
  #Define the speed of ZigZag changes and move one bar forward
  dz<-c(diff(zz), NA);
  #If the speed >0 - signal = 0(Buy), if <0, signal = 1 (Sell) otherwise NA
  sig<-ifelse(dz>0, 0, if else(dz<0, 1, NA));
  return(sig);
}

Calcola i segnali.

> Y<-Out()
> table(Y)
Y
   0    1 
1567 2423 

Il rapporto di classe è sbilanciato. Il numero di esempi di una classe è maggiore dell'altra. Tutti i modelli della classificazione sono ostili nei confronti di tali insiemi.

Correggeremo questa situazione nel momento della separazione dei dati in campioni di formazione e test.


3.3.4. Cancellazione dei dati

Cancella i nostri set di dati da dati non predefiniti. La compensazione in questo caso implica un ciclo più ampio di compiti. Include la cancellazione di "variabili virtualmente zero" e quelle altamente correlate, nonché alcuni altri compiti che non discuteremo qui.

Scrivere una funzione e cancellare i dati

Clearing<-function(x, y){
  dt<-cbind(x,y);
  n<-ncol(dt)
  dt<-na.omit(dt)
  return(dt);  
}
> dt<-Clearing(X,Y); nrow(dt)
[1] 3957

La matrice è diventata più corta di 43 barre.


3.3.5. Formazione e test della formazione dei campioni

Esistono diversi modi per suddividere i dati di origine nei campioni di training e test. Impiegheremo regolarmente la divisione casuale dei dati di origine nell’addestramento e ne testeremo uno in proporzione 8/10. È importante che i campioni siano stratificati, il che significa che il rapporto tra le istanze di classe nei campioni di addestramento e di prova deve corrispondere al rapporto di classe nel set di dati di origine. Sarebbe anche utile correggere la disuguaglianza di classe nel set di dati di origine. Ci sono due modi per farlo: o livellare per classe maggiore o per classe minore. Poiché abbiamo bisogno di più esempi, andremo al livello della classe superiore "1". In questo caso useremo il pacchetto "caret".

Formiamo un nuovo insieme equilibrato in cui il numero di istanze di entrambe le classi sia lo stesso e uguale a quello maggiore.


3.3.6. Bilanciamento delle classi

Di seguito è riportata la funzione che livella il numero di classi dal lato maggiore (se la divergenza è maggiore del 15%) e restituisce una matrice bilanciata

Balancing<-function(DT){
  #Calculate a table with a number of classes
  cl<-table(DT[ ,ncol(DT)]);
  #If the divergence is less than 15%, return the initial matrix
  if(max(cl)/min(cl)<= 1.15) return(DT)
  #Otherwise level by the greater side
  DT<-if(max(cl)/min(cl)> 1.15){ 
         upSample(x = DT[ ,-ncol(DT)],y = as.factor(DT[ , ncol(DT)]), yname = "Y")
        }
  #Convert у (factor) into a number
  DT$Y<-as.numeric(DT$Y)
  #Recode у from 1,2 into 0,1
  DT$Y<-ifelse(DT$Y == 1, 0, 1)
  #Convert dataframe to matrix
  DT<-as.matrix(DT)
  return(DT);
}

Spiegazione. Nella prima stringa calcolare il numero di istanze di ogni classe (vettore, con la dimensione uguale al numero di classi).

Trova il rapporto tra il vettore maggiore e quello più piccolo e se è inferiore a quello della soglia impostata, esci. Se il rapporto è maggiore, calcola la funzione, dopo aver inserito х e y separatamente. Y deve essere precedentemente convertito in un fattore.

Questo è il requisito per i parametri formali della funzione upSample(). Poiché non abbiamo bisogno della variabile target come fattore, la riconvalidiamo in una numerica con valori 0 e 1. Si prega di notare che quando convertiamo una variabile numerica (0,1) in un fattore, riceviamo variabili di testo "0" e "1". Alla conversione inversa in variabili numeriche, otteniamo 1 e 2 (!). Li sostituiamo con 0 e 1. Il nostro set di dati viene convertito dal "frame di dati" alla classe "matrix". Calcola

dt.b<-Balancing(dt)
x<-dt.b[ ,-ncol(dt.b)]
y<-dt.b[ , ncol(dt.b)]

In questo modo abbiamo il set di dati dt di origine (input e output) e il set bilanciato dt.b.

Dividilo in campioni di allenamento e di prova

Ottieni gli indici dell’allenamento e i campioni di prova dal pacchetto "rminer" utilizzando la funzione holdout().

> library('rminer')
> t<-holdout(y, ratio = 8/10, mode = "random")

L'oggetto t è un elenco contenente gli indici del set di dati di allenamento (t$tr) e test (t$ts). I set ricevuti sono stratificati.


3.3.7. Preelaborazione

La nostra fonte di dati di input contiene variabili con intervalli di valori diversi. Essenzialmente, le reti profonde sono reti regolari con un modo particolare di inizializzare i pesi.

Le reti neurali possono ricevere le variabili di input nell'intervallo (-1; 1) o (0, 1). Normalizzare le variabili di input nell'intervallo [-1, 1].

Per questo utilizza la funzione preProcess() dal pacchetto "caret". Si noti che i parametri di pre-elaborazione devono essere calcolati sul set di dati di addestramento e devono essere salvati per un'ulteriore pre-elaborazione del set di dati di prova e dei nuovi dati di input.

> spSign<-preProcess(x[t$tr, ], method = "spatialSign")
> x.tr<-predict(spSign, x[t$tr, ])
> x.ts<-predict(spSign, x[t$ts, ])

Ora abbiamo tutto per costruire, addestrare e testare una rete neurale profonda.


3.4. Modelli di creazione, formazione e test

Costruiremo e addestreremo il modello DN SAE. La formula del modello e la descrizione delle variabili:

sae.dnn.train(x, y, hidden = c(10), activationfun = "sigm", learningrate = 0.8, momentum = 0.5, learningrate_scale = 1, output = "sigm", sae_output = "linear",
  numepochs = 3, batchsize = 100, hidden_dropout = 0, visible_dropout = 0)

dove:

  • х è una matrice di dati di input;
  • y è un vettore o una matrice di variabili target;
  • hidden è un vettore con un numero di neuroni in ogni strato nascosto. Impostazione predefinita с(10);
  • activationfun è una funzione di attivazione di neuroni nascosti. Può essere "sigm", "lineare", "tanh". Per impostazione predefinita "sigm";
  • learningrate è un livello di allenamento per la discesa a gradiente. Impostazione predefinita = 0.8;
  • momentum è uno slancio per la discesa a gradiente. Impostazione predefinita = 0.5;
  • learningrate_scale livello di allenamento può essere moltiplicato per questo valore dopo ogni iterazione. Impostazione predefinita = 1.0;
  • numepochs è un numero di iterazioni per l'allenamento. Impostazione predefinita = 3;
  • batchsize è la dimensione di una piccola quantità di dati da addestrare. Impostazione predefinita = 100;
  • output è la funzione di attivazione per i neuroni di uscita, può essere "sigm", "lineare", "softmax". Per impostazione predefinita "sigm";
  • sae_output è la funzione di attivazione dei neuroni di uscita di SAE, può essere "sigm", "lineare", "softmax". Impostazione predefinita "lineare";
  • hidden_dropout è una parte eliminabile per i livelli nascosti. Impostazione predefinita = 0;
  • visible_dropout è una parte eliminabile del livello visibile (input). Impostazione predefinita = 0;

Creeremo un modello con le seguenti dimensioni (17, 100, 100, 100, 1), lo addestreremo, annoteremo il tempo di apprendimento e osserveremo la previsione.

> system.time(SAE<-sae.dnn.train(x= x.tr, y= y[t$tr], hidden=c(100,100,100), activationfun = "tanh", learningrate = 0.6, momentum = 0.5, learningrate_scale = 1.0, output = "sigm", sae_output = "linear", numepochs = 10, batchsize = 100, hidden_dropout = 0, visible_dropout = 0))
begin to train sae ......
training layer 1 autoencoder ...
training layer 2 autoencoder ...
training layer 3 autoencoder ...
sae has been trained.
begin to train deep nn ......
deep nn has been trained.
   user  system elapsed 
  12.92    0.00   13.09 

Come possiamo vedere, ci sono due fasi. All'inizio l'autoencoder viene addestrato strato per strato e poi la rete neurale.

Il piccolo numero di tempi di allenamento e l'immenso numero di neuroni nascosti nei tre strati sono stati impostati di proposito. L'intero processo ha richiesto 13 secondi!

Valutiamo le previsioni sul set di test dei predittori.

> pr.sae<-nn.predict(SAE, x.ts);
> summary(pr.sae)
       V1        
 Min.   :0.2649  
 1st Qu.:0.2649  
 Median :0.5881  
 Mean   :0.5116  
 3rd Qu.:0.7410  
 Max.   :0.7410 

Converti nei livelli 0,1 e calcola le misure

> pr<-ifelse(pr.sae>mean(pr.sae), 1, 0)
> confusionMatrix(y[t$ts], pr)
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 316 128
         1 134 378
                                         
               Accuracy : 0.7259         
                 95% CI : (0.6965, 0.754)
    No Information Rate : 0.5293         
    P-Value [Acc > NIR] : <2e-16         
                                         
                  Kappa : 0.4496         
 Mcnemar's Test P-Value : 0.7574         
                                         
            Sensitivity : 0.7022         
            Specificity : 0.7470         
         Pos Pred Value : 0.7117         
         Neg Pred Value : 0.7383         
             Prevalence : 0.4707         
         Detection Rate : 0.3305         
   Detection Prevalence : 0.4644         
      Balanced Accuracy : 0.7246         
                                         
       'Positive' Class : 0 

Questo non è un coefficiente eccezionale. Siamo più interessati al profitto che faremo usando questi segnali, non al coefficiente. Controllalo sulle ultime 500 barre (circa una settimana). Riceveremo segnali sulle ultime 500 barre sequenziali dalla nostra rete addestrata.

Normalizza le ultime 500 barre di dati di input, ricevi previsioni dalla rete neurale addestrata e convertirle in segnali -1= (Vendi) e 1 = (Acquista)

> new.x<-predict(spSign,tail(dt[ ,-ncol(dt)], 500))
> pr.sae1<-nn.predict(SAE, new.x)
> pr.sig<-ifelse(pr.sae1>mean(pr.sae1), -1, 1)
> table(pr.sig)
pr.sig
 -1   1 
235 265 
> new.y<-ifelse(tail(dt[  , ncol(dt)], 500) == 0, 1, -1)
> table(new.y)
new.y
 -1   1 
201 299 
> cm1<-confusionMatrix(new.y, pr.sig)
> cm1
Confusion Matrix and Statistics

          Reference
Prediction  -1   1
        -1 160  41
        1   75 224
                                          
               Accuracy : 0.768           
                 95% CI : (0.7285, 0.8043)
    No Information Rate : 0.53            
    P-Value [Acc > NIR] : < 2.2e-16       
                                          
                  Kappa : 0.5305          
 Mcnemar's Test P-Value : 0.002184        
                                          
            Sensitivity : 0.6809          
            Specificity : 0.8453          
         Pos Pred Value : 0.7960          
         Neg Pred Value : 0.7492          
             Prevalence : 0.4700          
         Detection Rate : 0.3200          
   Detection Prevalence : 0.4020          
      Balanced Accuracy : 0.7631          
                                          
       'Positive' Class : -1   

Il coefficiente di precisione non è male, anche se siamo più interessati al profitto, non al coefficiente.

Testa il profitto per le ultime 500 barre utilizzando i nostri segnali previsti e ottieni la curva di bilanciamento:

> bal<-cumsum(tail(price[ , 'CO'], 500) * pr.sig)
> plot(bal, t = "l")
> abline(h = 0)

Fig. 24. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale

Fig. 24. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale

Il saldo è stato calcolato senza prendere in considerazione spread, slippage e altre realtà di un mercato live.

Ora confronta con l'equilibrio che sarebbe stato ottenuto dai segnali ideali di ZZ. La linea rossa è l'equilibrio dei segnali della rete neurale:

> bal.zz<-cumsum(tail(price[ , 'CO'], 500) * new.y)
> plot(bal.zz,  t = "l")
> lines(bal,  col = 2)

Fig. 25. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale e dai segnali ZigZag

Fig. 25. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale e dai segnali ZigZag

C'è un potenziale di miglioramento.

Scrivi due funzioni per facilitare due funzioni helper Estimation() e Testing(). Il primo genererà i coefficienti Accuracy/Err e il secondo balance Bal/BalZZ.

Permette di ottenere subito un risultato modificando alcuni parametri di rete per vedere quali parametri influenzano la qualità della rete.

Avendo scritto una funzione di fitness, i parametri di rete ottimali possono essere trovati utilizzando l'algoritmo evolutivo (genetico) senza interruzioni per il processo di trading. Non dedicheremo tempo ad esso in questo articolo e lo considereremo in dettaglio un'altra volta.

Di seguito è riportata la funzione Estimation() che calcola i coefficienti Err/Accuracy:

Estimation<-function(X, Y, r = 8/10, m = "random", norm = "spatialSign",
                     h = c(10), act = "tanh", LR = 0.8, Mom = 0.5, 
                     out = "sigm", sae = "linear", Ep = 10, Bs = 50, 
                     CM=F){
  #Indices of the training and test data set
  t<-holdout(Y, ratio = r, mode = m)
  #Parameters of preprocessing
  prepr<-preProcess(X[t$tr,  ], method = norm)
  #Divide into train and test data sets with preprocessing 
  x.tr<-predict(prepr, X[t$tr,  ])
  x.ts<-predict(prepr, X[t$ts,  ])
  y.tr<- Y[t$tr]; y.ts<- Y[t$ts]
  #Train the model
  SAE<-sae.dnn.train(x = x.tr , y = y.tr , hidden = h, 
                     activationfun = act,
                     learningrate = LR, momentum = Mom, 
                      output = out, sae_output = sae, 
                     numepochs = Ep, batchsize = Bs)
  #Obtain a forecast on the test data set
  pr.sae<-nn.predict(SAE, x.ts)
  #Recode it into signals 1,0
  pr<-ifelse(pr.sae>mean(pr.sae), 1, 0)
  #Calculate the Accuracy coefficient or classification error
  if(CM) err<-unname(confusionMatrix(y.ts, pr)$overall[1])
  if(!CM) err<-nn.test(SAE, x.ts, y.ts, mean(pr.sae))
  return(err)
}

Parametri Formali

  • X – matrice di predittori grezzi in ingresso;
  • Y – vettore della variabile target;
  • r – rapporto allenamento/prova;
  • m – modalità di formazione del campione (casuale o conseguente);
  • norm – modalità di normalizzazione dei parametri di input ([ -1, 1]= "spatialSign";[ 0, 1]="intervallo");
  • h – vettore con un numero di neuroni negli strati nascosti;
  • atto – funzione di attivazione dei neuroni nascosti;
  • LR – livello di formazione;
  • Мом — slancio;
  • out – funzione di attivazione del livello di output;
  • sae – funzione di attivazione dell'autoencoder;
  • Ep – numero delle epoche di formazione;
  • Bs – dimensione del piccolo campione;
  • СM– Variabile booleana, se TRUE print Accuracy. Else Err.

Ad esempio calcoleremo l'errore di classificazione sul set di dati sbilanciato dt dalla rete con tre strati nascosti contenenti ciascuno 30 neuroni:

> Err<-Estimation(X = dt[ ,-ncol(dt)], Y = dt[ ,ncol(dt)], h=c(30, 30, 30), LR= 0.7)
begin to train sae ......
training layer 1 autoencoder ...
training layer 2 autoencoder ...
training layer 3 autoencoder ...
sae has been trained.
begin to train deep nn ......
deep nn has been trained.
> Err
[1] 0.1376263

La funzione Testing() calcola il bilanciamento dai segnali di previsione o da quelli ideali (ZigZag):

Testing<-function(dt1, dt2, r=8/10, m = "random", norm = "spatialSign",
                     h = c(10), act = "tanh", LR = 0.8, Mom = 0.5, 
                     out = "sigm", sae = "linear", Ep = 10, Bs=50, 
                     pr = T, bar = 500){
  X<-dt1[  ,-ncol(dt1)]
  Y<-dt1[  ,ncol(dt1)]
  t<-holdout(Y,  ratio = r,  mode = m)
  prepr<-preProcess(X[t$tr,  ], method = norm)
  x.tr<-predict(prepr, X[t$tr,  ])
  y.tr<- Y[t$tr]; 
  SAE<-sae.dnn.train(x = x.tr , y = y.tr , hidden = h, 
                     activationfun = act,
                     learningrate = LR, momentum = Mom, 
                     output = out, sae_output = sae, 
                     numepochs = Ep, batchsize = Bs)
  X<-dt2[ ,-ncol(dt2)]
  Y<-dt2[ ,ncol(dt2)]
  x.ts<-predict(prepr, tail(X, bar))
  y.ts<-tail(Y, bar)
  pr.sae<-nn.predict(SAE, x.ts)
  sig<-ifelse(pr.sae>mean(pr.sae), -1, 1)
  sig.zz<-ifelse(y.ts == 0, 1,-1 )
  bal<-cumsum(tail(price[  ,'CO'], bar) * sig)
  bal.zz<-cumsum(tail(price[  ,'CO'], bar) * sig.zz)
  if(pr) return(bal)
  if(!pr) return(bal.zz)
}

Parametri Formali

  • dt1 – matrice della variabile di input e target utilizzata per l'addestramento della rete;
  • dt2 - matrice delle variabili di input e target utilizzate per testare la rete;
  • pr – variabile booleana, se TRUE stampa il saldo dai segnali previsionali, altrimenti da ZigZag;
  • barra - il numero delle ultime barre da utilizzare per il calcolo del saldo.

Calcola il saldo sulle ultime 500 barre del nostro set di dati dt durante l'allenamento sul set di dati dt.b dalla rete neurale con gli stessi parametri di cui sopra:

> Bal<-Testing(dt.b, dt, h=c(30, 30, 30), LR= 0.7)
begin to train sae ......
training layer 1 autoencoder ...
training layer 2 autoencoder ...
training layer 3 autoencoder ...
sae has been trained.
begin to train deep nn ......
deep nn has been trained.
> plot(Bal, t = "l")
> abline(h = 0)

Fig. 26. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale h(30,30,30)

Fig. 26. Bilanciamento sulle ultime 500 barre dai segnali della rete neurale h(30,30,30)

Se confrontiamo il risultato con il saldo ottenuto in precedenza, possiamo vedere un miglioramento significativo. Tuttavia questo non è il punto più interessante.

Se diamo un'occhiata al grafico dei prezzi sulle ultime 500 barre, allora possiamo vedere quali parti di esso sono state meglio accettate dalla nostra rete (150-350 barre).

> plot(tail(price[  ,'Close'], 500), t = "l")
> abline(v = c(150,350), col=2)

Fig. 27. Trama del prezzo di chiusura sulle ultime 500 barre

Fig. 27. Trama del prezzo di chiusura sulle ultime 500 barre

Nota: Durante la decodifica degli output delle previsioni, abbiamo utilizzato una versione semplificata maggiore/inferiore alla media, anche se è possibile utilizzare altre versioni.

Se i valori sono maggiori di 0,6 o inferiori a 0,4, il segmento instabile di 0,4-0,6 viene tagliato. Limiti di classe più precisi possono essere ottenuti al momento della calibrazione. Se ne parlerà più avanti.

La nostra funzione Testing() verrà modificata un po' se verrà introdotto un parametro aggiuntivo dec. Questo ci permetterà di selezionare un modo per decodificare ("media" o "60/40") e verificare sui valori previsti quale impatto avrà sulla bilancia.

Testing.1<-function(dt1, dt2, r = 8/10, m = "random", norm = "spatialSign",
                     h = c(10), act = "tanh", LR = 0.8, Mom = 0.5, 
                     out = "sigm", sae = "linear", Ep = 10, Bs = 50, 
                     pr = T, bar = 500, dec=1){
  X<-dt1[ ,-ncol(dt1)]
  Y<-dt1[ ,ncol(dt1)]
  t<-holdout(Y, ratio = r, mode = m)
  prepr<-preProcess(X[t$tr, ], method = norm)
  x.tr<-predict(prepr, X[t$tr, ])
  y.tr<- Y[t$tr]; 
  SAE<-sae.dnn.train(x = x.tr , y = y.tr , hidden = h, 
                     activationfun = act,
                     learningrate = LR, momentum = Mom, 
                     output = out, sae_output = sae, 
                     numepochs = Ep, batchsize = Bs)
  X<-dt2[ ,-ncol(dt2)]
  Y<-dt2[ ,ncol(dt2)]
  x.ts<-predict(prepr, tail(X, bar))
  y.ts<-tail(Y, bar)
  pr.sae<-nn.predict(SAE, x.ts)
  #Variant +/- mean
  if(dec == 1) sig<-ifelse(pr.sae>mean(pr.sae), -1, 1)
  #Variant 60/40
  if(dec == 2) sig<-ifelse(pr.sae>0.6, -1, ifelse(pr.sae<0.4, 1, 0))
  sig.zz<-ifelse(y.ts == 0, 1,-1 )
  bal<-cumsum(tail(price[  ,'CO'], bar) * sig)
  bal.zz<-cumsum(tail(price[  ,'CO'], bar) * sig.zz)
  if(pr) return(bal)
  if(!pr) return(bal.zz)
}

Calcola e valuta il saldo con il primo e il secondo modo di decodifica.

Affinché i risultati si ripetano, impostare il generatore di numeri pseudocasuali nella stessa posizione.

> set.seed<-1245
> Bal1<-Testing.1(dt.b, dt, h = c(30, 30, 30), LR = 0.7, dec = 1)
begin to train sae ......
training layer 1 autoencoder ...
training layer 2 autoencoder ...
training layer 3 autoencoder ...
sae has been trained.
begin to train deep nn ......
deep nn has been trained.
> set.seed<-1245
> Bal2<-Testing.1(dt.b, dt, h = c(30, 30, 30), LR = 0.7, dec = 2)
begin to train sae ......
training layer 1 autoencoder ...
training layer 2 autoencoder ...
training layer 3 autoencoder ...
sae has been trained.
begin to train deep nn ......
deep nn has been trained.
> plot(Bal2, t = "l")
> lines(Bal1, col = 2)

Fig. 28. Bilanciamento per le ultime 500 barre dai segnali della rete neurale con diversi modi di decodifica delle previsioni

Fig. 28. Bilanciamento per le ultime 500 barre dai segnali della rete neurale con diversi modi di decodificare le previsioni

Chiaramente, l'equilibrio al secondo modo 60/40 sembra migliore. Anche qui c'è spazio per miglioramenti.

Ecco l'ultima cosa da controllare. In teoria, un insieme di diverse reti neurali dà un risultato migliore e più stabile. Testeremo un ensemble composto da diverse reti, che sono addestrate sugli stessi campioni anche se possono essere addestrate su campioni indipendenti. Il risultato della previsione dell'ensemble è una semplice media delle previsioni di tutte le reti. Esistono altri modi più complessi di fare la media.

Miglioreremo la nostra funzione Testing() aggiungendo un altro parametro : ans=1 specificando il numero delle reti nell'insieme.


3.4.1. Calcoli paralleli

Poiché i calcoli di diversi modelli indipendenti possono essere facilmente parallelizzati, useremo l'opportunità fornita dal linguaggio R e creeremo un cluster costituito da diversi core del processore o computer di una rete locale, indipendentemente dai sistemi operativi di questi computer.

Per questo abbiamo bisogno dei pacchetti "foreach" e "doParallel". Di seguito è riportata una funzione molto semplice che avvierà un cluster per tutti i core del nostro processore.

library(doParallel)
library(foreach)
puskCluster<-function(){
  cores<-detectCores()
  cl<-makePSOCKcluster(cores)
  registerDoParallel(cl)
  clusterSetRNGStream(cl)
 return(cl)
}

Diversi punti sono chiariti di seguito. Nelle prime due stringhe carichiamo le librerie necessarie. Devono essere precedentemente installati sul tuo computer. Quindi definiamo quanti core ci sono nel processore, creiamo un cluster, registriamo un pacchetto per calcoli paralleli, installiamo un generatore di numeri pseudocasuali indipendente in ogni flusso di calcoli e restituiamo l'handle del cluster. La qualità del generatore di numeri pseudocasuali per i calcoli di ogni modello è estremamente importante anche se questo è un argomento separato.

Dopo che il cluster è stato avviato e tutti i calcoli richiesti sono stati effettuati, dobbiamo ricordarci di fermarlo:

cl<-puskCluster()
stopCluster(cl) 

I calcoli paralleli verranno eseguiti dalla seguente formula dal pacchetto "foreach":

SAE<-foreach(times(ans), .packages = "deepnet") %dopar%  
                sae.dnn.train(x = x.tr , y = y.tr , hidden = h, 
                        activationfun = act,
                        learningrate = LR, momentum = Mom, 
                        output = out, sae_output = sae, 
                        numepochs = Ep, batchsize = Bs)

dove times(ans) è un numero di reti che vogliamo ottenere e .packages punta al pacchetto per assumere la funzione calcolata.

Il risultato ha una forma di elenco e contiene il numero di reti addestrate di cui abbiamo bisogno.

Quindi richiediamo la previsione da ogni rete e calcoliamo la media.

pr.sae<-(foreach(i = 1:ans, .combine = "+") %do%  nn.predict(SAE[[i]], x.ts))/ans

Qui c’è un vettore degli indici di rete addestrati,.combine="+" specifica in quale forma dovrebbero essere restituite le previsioni restituite in tutte le reti neurali. In questo caso abbiamo richiesto di restituire una somma ed eseguire questi calcoli in sequenza, non in modo parallelo (operatore %do%). La somma ottenuta sarà divisa per il numero delle reti neurali la quale renderà il risultato finale. Questo è bello e semplice.

Calcola il saldo ottenuto da insiemi costituiti da 3 e 4 reti neurali con gli stessi parametri di quelli sopra e utilizzando il modo di decodifica 60/40. Confronta i risultati su una rete neurale. Per valutare l'efficacia dei calcoli paralleli, aumenta il numero di epoche a 300 e cronometra il processo di ottenimento della previsione.

1. Una rete neurale:

> system.time(Bal21<-Testing.1(dt.b, dt, h = c(30, 30, 30), LR = 0.7, dec = 2, Ep=300))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.000057
####loss on step 20000 is : 0.000043
training layer 2 autoencoder ...
####loss on step 10000 is : 0.000081
####loss on step 20000 is : 0.000086
training layer 3 autoencoder ...
####loss on step 10000 is : 0.000072
####loss on step 20000 is : 0.000066
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.069451
####loss on step 20000 is : 0.079629
deep nn has been trained.
   user  system elapsed 
 115.78    0.00  116.96 
> plot(Bal21, t = "l")
> abline(h = 0)

2. Insieme di 3 reti neurali:

> system.time(Bal41<-Testing.2(dt.b, dt, h = c(30, 30, 30), LR = 0.7, Ep=300, dec = 2, ans=3))
   user  system elapsed 
   0.22    0.06  233.64 
> lines(Bal41, col=4)

3. Insieme di 4 reti neurali:

> system.time(Bal44<-Testing.2(dt.b, dt, h = c(30, 30, 30), LR = 0.7, Ep=300, dec = 2, ans=4))
   user  system elapsed 
   0.13    0.03  247.86 
> lines(Bal44, col=2)

Il tempo di esecuzione al calcolo parallelo è ottimale se il numero di flussi è multiplo al numero di core. Ho usato 2 core.

Detto questo, non ci sono vantaggi significativi nel saldo. Nel grafico sottostante, il grafico blu denota 3 reti, quella rossa - 4 reti e quella nera - una rete.

Fig. 29. Bilanciamento sulle ultime 500 barre dai segnali degli insiemi costituiti da 3 e 4 reti neurali e una rete

Fig. 29. Bilanciamento sulle ultime 500 barre dai segnali degli insiemi costituiti da 3 e 4 reti neurali e una rete

In generale, il risultato dipende da molti parametri, a partire dai dati di input e output, dal modo in cui si normalizzano, dal numero di strati nascosti e dal numero di neuroni in quegli strati, dal livello di allenamento, dal numero di epoche di allenamento e molti altri.

Ultimi tre esempi. Calcola il bilanciamento sulle ultime 1000 barre con tre reti neurali con diversi numeri di neuroni nascosti in tre strati nascosti.

> system.time(Bal0<-Testing.1(dt.b, dt, h = c(30, 30, 30), LR = 0.7, dec = 2, Ep=300, bar=1000))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.000054
####loss on step 20000 is : 0.000044
training layer 2 autoencoder ...
####loss on step 10000 is : 0.000078
####loss on step 20000 is : 0.000079
training layer 3 autoencoder ...
####loss on step 10000 is : 0.000090
####loss on step 20000 is : 0.000072
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.072633
####loss on step 20000 is : 0.057917
deep nn has been trained.
   user  system elapsed 
 116.09    0.02  116.26 
> max(Bal0)
[1] 0.04725
> plot(Bal0, t="l")
> tail(Bal0,1)
[1] 0.03514

Il profitto massimo è di 472 punti, sull'ultima barra di 351 punti. Sul grafico è disegnato in nero.

> system.time(Bal0<-Testing.1(dt.b, dt, h = c(13, 8, 5), LR = 0.7, dec = 2, Ep=300, bar=1000))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.005217
####loss on step 20000 is : 0.004846
training layer 2 autoencoder ...
####loss on step 10000 is : 0.051324
####loss on step 20000 is : 0.046230
training layer 3 autoencoder ...
####loss on step 10000 is : 0.023292
####loss on step 20000 is : 0.026113
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.057788
####loss on step 20000 is : 0.056932
deep nn has been trained.
   user  system elapsed 
  64.04    0.01   64.24 
Warning message:
In sae$encoder[[i - 1]]$W[[1]] %*% t(train_x) + sae$encoder[[i -  :
  longer object length is not a multiple of shorter object length
> lines(Bal0, col="blue")

Questa è chiaramente una variazione inefficace.

La terza variante:

> system.time(Bal0<-Testing.1(dt.b, dt, h = c(50, 50, 50), LR = 0.7, dec = 2, Ep=300, bar=1000))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.000018
####loss on step 20000 is : 0.000013
training layer 2 autoencoder ...
####loss on step 10000 is : 0.000062
####loss on step 20000 is : 0.000048
training layer 3 autoencoder ...
####loss on step 10000 is : 0.000053
####loss on step 20000 is : 0.000055
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.096490
####loss on step 20000 is : 0.084860
deep nn has been trained.
   user  system elapsed 
 186.18    0.00  186.39 
> lines(Bal0, col="red")
> max(Bal0)
[1] 0.0543

Fig. 30. Bilanciamento sulle ultime 1000 barre dai segnali di tre reti neurali con diversi numeri di neuroni nascosti

Fig. 30. Bilanciamento sulle ultime 1000 barre dai segnali di tre reti neurali con diversi numeri di neuroni nascosti

I risultati mostrano che la terza variante è la migliore delle tre con il profitto massimo di 543 punti. Abbiamo solo cambiato il numero di neuroni nascosti e questo ha portato a un miglioramento significativo. La ricerca di parametri ottimali dovrebbe essere eseguita attraverso algoritmi evolutivi. Spetta al lettore esplorare questo aspetto. 

Va tenuto presente che l'algoritmo dell'autore non è stato completamente implementato in questo pacchetto.


4. L'implementazione (Indicatore ed Expert Advisor)

Ora scriveremo un programma per l'indicatore e per l’Expert Advisor utilizzando una rete profonda per ricevere segnali di trading.

Esistono due modi per tale implementazione:

  • Il primo. L'addestramento della rete neurale viene eseguito manualmente in Rstudio. Dopo aver ottenuto risultati accettabili, salva la rete nel catalogo appropriato. Quindi avvia l'EA e l'indicatore sul grafico. L'EA caricherà la rete addestrata. L'indicatore prepara un vettore di nuovi dati di input su ogni nuova barra e lo passa all'EA. L'EA presenta i dati di rete, riceve un segnale e quindi agisce su di esso. L'EA sta portando avanti le sue attività abituali come ordini di apertura e chiusura, trailing ecc. L'obiettivo dell'indicatore è quello di preparare e trasmettere all'EA nuovi dati di input su ogni nuova barra e, soprattutto, presentare i segnali previsti dalla rete su un grafico. La pratica dimostra che il controllo visivo è il modo più efficiente per valutare una rete neurale.
  • Secondo modo. Avvia l'EA e l'indicatore sul grafico. Al primo lancio, l'indicatore trasmette all'EA un ampio set preparato di dati di input e output. L'EA lancia addestramenti, test e selezione della migliore rete neurale. Dopo di che il lavoro va avanti come nel primo modo.

Scriveremo l'indicatore di collegamento-EA seguendo il primo algoritmo. EA con un minimo di fiocchi e fronzoli.

Perché è così difficile? Questo modo di implementazione consente di collegare diversi indicatori posizionati su diversi simboli / intervalli di tempo a un EA e lavorare con loro di conseguenza. Per questo, l'EA deve passare attraverso una piccola modernizzazione. Ne parleremo più avanti.

Di seguito è riportata la struttura di interazione tra l'indicatore e l'EA:

Fig. 31. Struttura di interazione tra l'indicatore e l'EA

Fig. 31. Struttura dell'interazione tra l'indicatore e l'EA

4.1. Addestramento e salvataggio del modello

Utilizzando l'indicatore posto sul grafico di nostro interesse, otteniamo i dati di origine necessari. Per fare questo, posiziona l'indicatore sul grafico, dopo aver impostato una variabile di input send = false, cioè la rappresentazione visiva non dovrebbe essere inviata al server. Al primo avvio su questo simbolo o intervallo di tempo, l'indicatore è quello di creare le seguenti directory /Simbolo/TF/Test_Data/ nel file di dati del terminale (/MQL4/Files).

Tale organizzazione di directory offre l'opportunità di non mettere insieme i risultati degli esperimenti durante l'addestramento preliminare dei modelli e di non sovrascrivere i vecchi dati con quelli nuovi. I risultati intermedi saranno memorizzati nella directory /Symbol/TF/Test_Data/ e il modello che eA utilizzerà per il lavoro si troverà in /Symbol/TF/ (dovrà essere posizionato lì manualmente). Lo stesso risultato sarà al primo lancio su un nuovo simbolo o sul periodo di tempo dell'EA.

Quindi, per EURUSD, М30, ci sono 4000 barre il 14.10.2014. Abbiamo bisogno del dt[] dataframe.

Classi di equilibrio:

> dt.b<-Balancing(dt)
> table(dt.b[ ,ncol(dt.b)])
   0    1 
2288 2288

Ora, con la funzione precedentemente scritta Testing.1(), addestra la rete neurale profonda con 500 e 300 epoche e valuta il bilancio ottenuto sulle ultime 500 barre dai segnali previsti dalla rete neurale.

> system.time(bal<-Testing.1(dt.b, dt, h = c(50, 50, 50), LR = 0.7, dec = 2, Ep=500, bar=500))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.000017
####loss on step 20000 is : 0.000015
####loss on step 30000 is : 0.000015
training layer 2 autoencoder ...
####loss on step 10000 is : 0.000044
####loss on step 20000 is : 0.000041
####loss on step 30000 is : 0.000039
training layer 3 autoencoder ...
####loss on step 10000 is : 0.000042
####loss on step 20000 is : 0.000042
####loss on step 30000 is : 0.000036
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.089417
####loss on step 20000 is : 0.043276
####loss on step 30000 is : 0.069399
deep nn has been trained.
   user  system elapsed 
 267.59    0.08  269.37 
> plot(bal, t="l")

Salva la rete neurale con un nome diverso e addestrane un'altra

> SAE1<-SAE
> system.time(bal<-Testing.1(dt.b, dt, h = c(50, 50, 50), LR = 0.7, dec = 2, Ep=300, bar=500))
begin to train sae ......
training layer 1 autoencoder ...
####loss on step 10000 is : 0.000020
####loss on step 20000 is : 0.000016
training layer 2 autoencoder ...
####loss on step 10000 is : 0.000050
####loss on step 20000 is : 0.000050
training layer 3 autoencoder ...
####loss on step 10000 is : 0.000051
####loss on step 20000 is : 0.000043
sae has been trained.
begin to train deep nn ......
####loss on step 10000 is : 0.083888
####loss on step 20000 is : 0.083941
deep nn has been trained.
   user  system elapsed 
 155.32    0.02  156.25 
> lines(bal, col=2)

Dai un'occhiata ai grafici dei bilanci (l'ultimo risultato evidenziato in rosso).

Fig. 32. Bilanciamento sulle ultime 500 barre dai segnali delle reti neurali addestrate in 500 e 300 epoche

Fig. 32. Fig. 32. Bilanciamento sulle ultime 500 barre dai segnali delle reti neurali addestrate in 500 e 300 epoche

Come possiamo vedere, la rete neurale addestrata in 300 epoche, ha mostrato un risultato migliore rispetto alla rete addestrata in 500 epoche.

Il tempo di formazione di quest'ultimo è adatto per una rapida riqualificazione durante una sessione di trading in questo lasso di tempo.

Per ulteriori lavori su un grafico reale abbiamo bisogno di due oggetti: modello addestrato "SAE" e parametri di normalizzazione "prepr" per i dati di input. Salvali nella directory pertinente, nel mio caso questo è "D:/Alpari Limited MT4/MQL4/Files/EURUSD/M30/Test_2014-10-14". Questo è definito e funziona come funzionante, se hai aperto in Rstudio l'area di lavoro "i_SAE_EURUSD_30.Rdata" salvata dall'indicatore.

save(SAE, prepr, file="SAE.model")

Nel file "SAE.model", abbiamo salvato il modello stesso e i parametri di normalizzazione. Usare il modello senza questi ultimi non ha senso. Puoi sperimentare e salvare i modelli che ti piacciono ogni giorno. Verranno salvati nelle cartelle "/File/Simbolo/TF/Test_Data". Affinché l'EA utilizzi il modello, inserisci manualmente il file "SAE.model" nella cartella "File/Symbol/TF/". Questa cartella può contenere un solo modello e l'EA la utilizzerà per lavoro.

Dopo aver caricato il file "SAE.model", l'EA carica questi oggetti nell'area di lavoro. A questo punto la parte manuale del lavoro è terminata, è possibile posizionare l'indicatore-EA sul grafico e testarlo in tempo reale.

Per valutare l'efficacia del lavoro dell'EA, sono necessari criteri quantitativi. Il coefficiente di precisione non è adatto a questo scopo.

La media del rapporto di previsione del saldo ricevuto da ZigZag e il rapporto di bilanciamento sull'ultima barra al numero di barre. Nel nostro caso questo è il saldo di ZigZag:

sig.zz<-ifelse(tail(dt[  , ncol(dt)], 500) == 0, 1, -1)
bal.zz<-cumsum(tail(price[  , 'CO'], 500) * sig.zz)
Kzz<-mean(bal.zz / bal)
> Kzz
[1] 0.9173312

Questo è un punteggio molto alto ma è relativo.

Se vediamo come appare nel tempo, possiamo vedere che per le prime 50-100 barre questo è un indice instabile, anche se in seguito diventa quasi costante. Le statistiche sono di seguito:

> plot(bal/bal.zz, t="l")
> summary(bal/bal.zz)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
-15.2500   0.7341   0.7844   0.9173   0.8833  55.0000

Fig. 33. Rapporto tra il bilancio previsionale e il saldo ottenuto da ZigZag

Fig. 33. Rapporto tra il bilancio previsionale e il saldo ottenuto da ZigZag

Il secondo è più preciso in quanto mostra quanti punti di profitto ci sono per una barra su un tratto lungo N barre.

Ad esempio, per il saldo per rete neurale previsione sul tratto di 500 barre:

> Kb<-tail(bal,1)/length(bal)*10^Dig
> Kb
[1] 11.508

dai segnali ZigZag:

> Kbz<-tail(bal.zz,1)/length(bal)*10^Dig
> Kbz
[1] 13.784

Quando viene definito il limite inferiore di efficacia su uno dei parametri, conosciamo il momento in cui possiamo riqualificare la rete neurale o ottimizzarne i parametri.

L'EA visualizzerà i seguenti parametri sul grafico: OP – operazione eseguita, Acc – Accuratezza, K – è Kb definito in precedenza, Kmax – lo stesso parametro di Kb ma definito sulla bilancia alta e dà un'idea di quanto questo parametro differisca sull'ultima barra da quella massimale.


4.2. Ordine di installazione e lancio

Nell'archivio allegato SAE.zip potete trovare:

  1. L'indicatore i_SAE.mq4, inserito nella cartella ~/MQL4/Indicators/
  2. Il e_SAE.mq4 EA, inserito nella cartella ~/MQL4/Experts/
  3. La libreria mt4Rb7.dll, viene inserita nella cartella ~/MQL4/Libraries/.
  4. Il file di intestazione mt4Rb7.mqh, inserito nella cartella ~/MQL4/Include/. La libreria e il file di intestazione sono stati sviluppati e gentilmente forniti da Bernd Kreuss. Il nome include l'indice dell'ultima modifica (b7). Quando ci sono molte versioni con gli stessi nomi, ci sono confusioni che richiedono molto tempo per essere rettificate.
  5. Script su R: i_SAE.r (script indicatore principale), i_SAE_fun.r (funzioni dello script indicatore), e_SAE.r (script EA), e_SAE_init.r (script di inizializzazione EA), SAE_SetDir.r (script di convalida e creazione delle directory necessarie). Poiché gli script non dipendono né dal simbolo né da un timefreame, possono trovarsi in una directory separata. Nel mio caso questo è "C:Rdata/SAE/". La directory "C:Rdata/" contiene diversi script non collegati a un determinato progetto. Se metti gli script in una cartella diversa dalla mia, apporta le correzioni appropriate nell'indicatore e EA che è corretto il modo per gli script.
  6. SAE.model è un file con il modello "SAE" e i parametri di normalizzazione "prepr". Il modello è stato addestrato su EURUSD (M30), ultima data 14.10.14. Il processo di formazione è stato descritto sopra.

Inoltre, non dimenticare la strada per la directory in cui è stata memorizzata il linguaggio R sul tuo computer.

E’ preferibile seguire il seguente ordine per iniziare a lavorare. Posiziona l'EA sul grafico. Se si decide di posizionare un EA su un altro simbolo, è necessario specificare una porta diversa dai server avviati in precedenza. Ad esempio, la porta 8886 (per impostazione predefinita la porta 8888).

Nota: Questo è un modo assolutamente inefficiente. Ogni server ha una dimensione di 120-130 Mb. Questo è come le cose sono oggi.

Dopo la normale inizializzazione EA, l'avviso "Nessun risultato di calcolo! Simbolo" apparirà. Quindi installare l'indicatore con il parametro esterno send = true e la porta del server specificata a cui l'indicatore deve connettersi (vedere sopra). Se tutto funziona correttamente, i dati reali "operazione", Precisione, K e Kmax appariranno nella stringa di output e inizierà il trading.

Il controllo efficiente del processo può essere facilitato al meglio dal Task Manager di Windows. Se Rterm non viene visualizzato nell'elenco dopo il lancio dell'EA o dell'indicatore, il processo R è stato interrotto. La ragione principale di tali interruzioni è un errore di sintassi negli script, la mancata corrispondenza della lunghezza del vettore MQL ricevente e del vettore estratto da Rterm.

Gli script possono essere sottoposti a debug in Rstudio avviando gli script riga per riga dall'inizio alla fine.

Purtroppo non sono stato in grado di avviare l'EA nel tester, quindi deve essere testato su un account demo.


4.3. Modi e metodi per migliorare le caratteristiche qualitative

  1. Modifica il set degli indicatori utilizzati nell'input.
  2. Modifica la modalità di normalizzazione dei dati di input.
  3. Ottimizza i parametri del "supervisore" e gli indicatori all'ingresso.
  4. Modifica la codifica della variabile di input per la matrice con due colonne. Calibra il segnale di previsione.
  5. Ottimizza i parametri di rete (numero di neuroni negli strati nascosti, numero di livelli, livello di apprendimento, numero di epoche).

Conclusione

Abbiamo creato, addestrato e testato modelli di rete profonda con inizializzazione dei pesi dei neuroni negli strati nascosti da SAE. Le reti si riqualificano molto rapidamente e consentono di riqualificarle senza interrompere il processo di trading.

I risultati mostrati dalle reti neurali sono nella media in termini di metriche. Il risultato ideale non era l'obiettivo iniziale.

Utilizzando un tale modello e una valutazione permanente del coefficiente di efficacia, il modello può essere riaddestrato e ottimizzato senza interrompere il processo di trading.

Allegato:

  1. SAE.zip - indicatore, EA e file di accompagnamento.
  2. R_intro.zip - letteratura su R e Rstudio in Rusian.
  3. DeepLearning.zip - letteratura di Deep Learning.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/1103

File allegati |
DeepLearning.zip (6542.81 KB)
R-intro.zip (15278.8 KB)
sae.zip (394.31 KB)
Manuale MQL5: Elaborazione dell'evento TradeTransaction Manuale MQL5: Elaborazione dell'evento TradeTransaction
Questo articolo considera le capacità del linguaggio MQL5 dal punto di vista della programmazione event-driven. Il più grande vantaggio di questo approccio è che il programma può ricevere informazioni sull'attuazione graduale di un'operazione di trading. L'articolo contiene anche un esempio di ricezione ed elaborazione di informazioni sull'operazione di trading in corso utilizzando il gestore dell'evento TradeTransaction. A mio parere, un tale approccio può essere utilizzato per copiare le offerte da un terminale all'altro.
Come abbiamo sviluppato il servizio MetaTrader Signals e il Social Trading Come abbiamo sviluppato il servizio MetaTrader Signals e il Social Trading
Continuiamo a potenziare il servizio Segnali, migliorare i meccanismi, aggiungere nuove funzioni e correggere i difetti. Il MetaTrader Signals Service del 2012 e l'attuale MetaTrader Signals Service sono come due servizi completamente diversi. Attualmente, stiamo implementando un servizio Virtual Hosting Cloud che consiste in una rete di server per il supporto di versioni specifiche del terminale client MetaTrader.
Manuale MQL5: Gestione di eventi grafici personalizzati Manuale MQL5: Gestione di eventi grafici personalizzati
Questo articolo prende in considerazione gli aspetti della progettazione e dello sviluppo del sistema di eventi grafici personalizzati nell'ambiente MQL5. Qui è possibile trovare anche un esempio di approccio alla classificazione degli eventi, nonché un codice di programma per una classe di eventi e una classe di gestori di eventi personalizzati.
Analisi di regressione dell'influenza dei dati macroeconomici sulla fluttuazione dei prezzi delle valute Analisi di regressione dell'influenza dei dati macroeconomici sulla fluttuazione dei prezzi delle valute
Questo articolo considera l'applicazione dell'analisi di regressione multipla alle statistiche macroeconomiche. Fornisce inoltre una panoramica della valutazione dell'impatto statistico sulla fluttuazione del tasso di cambio della valuta sulla base dell'esempio della coppia di valute EURUSD. Tale valutazione consente di automatizzare l'analisi fondamentale che diventa disponibile anche per i trader alle prime armi.