Guida al linguaggio di specifica della rete neurale Net# per Machine Learning Studio (versione classica)
SI APPLICA A: Machine Learning Studio (versione classica) di Azure Machine Learning
Importante
Il supporto dello studio di Azure Machine Learning (versione classica) terminerà il 31 agosto 2024. È consigliabile passare ad Azure Machine Learning entro tale data.
A partire dal 1° dicembre 2021 non sarà possibile creare nuove risorse dello studio di Azure Machine Learning (versione classica). Fino al 31 agosto 2024 sarà possibile continuare a usare le risorse dello studio di Azure Machine Learning (versione classica).
- Vedere le informazioni sullo spostamento di progetti di apprendimento automatico da ML Studio (versione classica) ad Azure Machine Learning.
- Scoprire di più su Azure Machine Learning
La documentazione relativa allo studio di Machine Learning (versione classica) è in fase di ritiro e potrebbe non essere aggiornata in futuro.
NET # è un linguaggio sviluppato da Microsoft e usato per definire architetture di reti neurali complesse, ad esempio reti neurali profonde o convoluzioni di dimensioni arbitrarie. È possibile usare strutture complesse per migliorare l'apprendimento relativo a dati quali immagini, audio e video.
È possibile usare una specifica dell'architettura Net# in tutti i moduli di rete neurale in Machine Learning Studio (versione classica):
- Rete neurale multiclasse
- Rete neurale a due classi
- Neural Network Regression (Regressione rete neurale)
Questo articolo descrive i concetti di base e la sintassi per lo sviluppo di una rete neurale personalizzata con Net#:
- Requisiti relativi alla rete neurale e come definire i componenti principali
- Sintassi e parole chiave del linguaggio di specifica Net#
- Esempi di reti neurali personalizzate create usando Net#
Nozioni di base sulla rete neurale
Una struttura di rete neurale è composta da nodi organizzati in livelli e connessioni ponderate (o bordi) tra i nodi. Le connessioni sono direzionali e ognuna ha un nodo di origine e un nodo di destinazione.
Ogni livello di cui è possibile eseguire il training (livello nascosto o di output) ha una o più aggregazioni di connessioni. Un'aggregazione di connessioni è costituita da un livello di origine e da una specifica delle connessioni provenienti da quel livello di origine. Tutte le connessioni in una determinata aggregazione condividono lo stesso livello di origine e lo stesso livello di destinazione. In Net# un'aggregazione di connessioni è considerata come appartenente al livello di destinazione dell'aggregazione.
Net# supporta diversi tipi di aggregazioni di connessioni, permettendo quindi di personalizzare il modo in cui gli input sono mappati ai livelli nascosti e agli output.
L'aggregazione predefinita o standard è un'aggregazione completa, in cui ogni nodo del livello di origine è connesso a tutti i nodi del livello di destinazione.
Net# supporta anche i quattro tipi seguenti di aggregazioni di connessioni avanzate:
Aggregazioni filtrate. È possibile definire un predicato usando le posizioni del nodo del livello di origine e del nodo del livello di destinazione. I nodi vengono connessi se il predicato è True.
Aggregazioni convoluzionali. È possibile definire piccoli gruppi di nodi vicini nel livello di origine. Ogni nodo nel livello di destinazione è connesso a un intorno di nodi nel livello di origine.
Aggregazioni di pooling e aggregazioni di normalizzazione delle risposte. Sono simili alle aggregazioni convoluzionali, in quanto l'utente definisce piccoli intorni di nodi nel livello di origine. La differenza è che i pesi dei bordi in questi pacchetti non sono addestrabili. Infatti, una funzione predefinita viene applicata ai valori del nodo di origine per determinare il valore del nodo di destinazione.
Personalizzazioni supportate
L'architettura dei modelli di rete neurale creati in Machine Learning Studio (versione classica) può essere ampiamente personalizzata tramite Net#. È possibile:
- Creare livelli nascosti e controllare il numero di nodi in ogni livello.
- Specificare la modalità di connessione reciproca dei livelli.
- Definire strutture di connettività speciali, ad esempio aggregazioni di convoluzioni e per la condivisione dei pesi.
- Specificare diverse funzioni di attivazione.
Per informazioni dettagliate sulla sintassi del linguaggio di specifica, vedere Specifiche di struttura.
Per esempi di definizione di reti neurali per alcune attività comuni di Machine Learning, dalle più semplici alle più complesse, vedere Esempi.
Requisiti generali
- Devono essere esattamente disponibili un livello di output, almeno un livello di input e zero o più livelli nascosti.
- Ogni livello ha un numero fisso di nodi, disposti concettualmente in una matrice rettangolare di dimensioni arbitrarie.
- I livelli di input non sono associati a parametri sottoposti a training e rappresentano il punto in cui i dati delle istanze entrano nella rete.
- I livelli sottoponibili a training, ovvero i livelli nascosti e di output hanno parametri sottoposti a training associati, noti come pesi e distorsioni.
- I nodi di origine e di destinazione devono trovarsi in livelli separati.
- La connessione deve essere aciclica, ovvero non può essere presente una catena di connessioni che riporta al nodo di origine iniziale.
- Il livello di output non può essere un livello di origine di un'aggregazione di connessioni.
Specifiche di struttura
La specifica della struttura di una rete neurale è composta da tre sezioni: la dichiarazione delle costanti, la dichiarazione dei livelli e la dichiarazione delle connessioni. È anche disponibile una sezione facoltativa denominata dichiarazione delle condivisioni. Le sezioni possono essere specificate in qualsiasi ordine.
Dichiarazione della costante
Una dichiarazione della costante è facoltativa. Fornisce un mezzo per definire i valori usati in una qualunque posizione nella definizione della rete neurale. L'istruzione di dichiarazione è costituita da un identificatore seguito da un segno di uguale e un'espressione valore.
Ad esempio, l'istruzione seguente definisce una costante x
:
Const X = 28;
Per definire contemporaneamente due o più costanti, racchiudere i nomi e i valori degli identificatori tra parentesi graffe e separarle da punti e virgola. Ad esempio:
Const { X = 28; Y = 4; }
La parte destra di ogni espressione di assegnazione può essere costituita da un valore Integer, un numero reale, un valore booleano (true/false) o un'espressione matematica. Ad esempio:
Const { X = 17 * 2; Y = true; }
Dichiarazione dei livelli
La dichiarazione di livello è obbligatoria. Definisce le dimensioni e l'origine del livello, inclusi il raggruppamento di connessione e gli attributi. L'istruzione della dichiarazione inizia con il nome del livello (di input, nascosto o di output), seguito dalle dimensioni del livello (una tupla di valori Integer positivi). Ad esempio:
input Data auto;
hidden Hidden[5,20] from Data all;
output Result[2] from Hidden all;
- Il prodotto delle dimensioni è il numero di nodi nel livello. In questo esempio ci sono due dimensioni [5,20]. Ciò significa che nel livello ci sono 100 nodi.
- I livelli possono essere dichiarati in qualsiasi ordine, con una eccezione: se sono stati definiti più livelli di input, l'ordine in cui vengono dichiarati deve corrispondere all'ordine delle funzionalità nei dati di input.
Per specificare che il numero di nodi in un livello deve essere determinato automaticamente, usare la parola chiave auto
. La parola chiave auto
ha effetti diversi, a seconda del livello:
- Nella dichiarazione di un livello di input il numero di nodi corrisponde al numero di funzionalità nei dati di input.
- In una dichiarazione di livello nascosto, il numero di nodi corrisponde al numero specificato dal valore del parametro per il numero di nodi nascosti.
- Nella dichiarazione di un livello di output il numero di nodi corrisponde a 2 per la classificazione a due classi, 1 per la regressione ed è uguale al numero di nodi di output per la classificazione a più classi.
Ad esempio, la definizione di rete seguente permette la determinazione automatica delle dimensioni di tutti i livelli:
input Data auto;
hidden Hidden auto from Data all;
output Result auto from Hidden all;
Una dichiarazione di livelli per un livello di cui è possibile eseguire il training, ovvero i livelli nascosti o di output, può includere facoltativamente la funzione di output, definita anche funzione di attivazione, che assume il valore predefinito sigmoid per i modelli di classificazione e linear per i modelli di regressione. Anche se si usa l'impostazione predefinita, è possibile dichiarare in modo esplicito la funzione di attivazione, se lo si desidera per maggiore chiarezza.
Sono supportate le funzioni di output seguenti:
- sigmoid
- lineare
- softmax
- rlinear
- square
- sqrt
- srlinear
- abs
- tanh
- brlinear
Ad esempio, la dichiarazione seguente usa la funzione softmax:
output Result [100] softmax from Hidden all;
Dichiarazione della connessione
Immediatamente dopo aver definito il livello sottoponibile a training, è necessario dichiarare connessioni tra i livelli definiti. La dichiarazione di aggregazione delle connessioni inizia con la parola chiave from
, seguita dal nome del livello di origine dell'aggregazione e dal tipo di aggregazione di connessioni da creare.
Sono attualmente supportati cinque tipi di aggregazioni di connessioni:
- Aggregazioni complete, indicate dalla parola chiave
all
- Aggregazioni filtrate, indicate dalla parola chiave
where
, seguita da un'espressione del predicato - Aggregazioni convoluzionali, indicate dalla parola chiave
convolve
, seguite dagli attributi di convoluzione - Aggregazioni di pooling, indicate dalle parole chiave max pool o mean pool
- Aggregazioni di normalizzazione delle risposte, indicate dalla parola chiave response norm
Aggregazioni complete
Un'aggregazione completa di connessioni include una connessione da ogni nodo del livello di origine verso ogni nodo del livello di destinazione. Si tratta del tipo di connessione di rete predefinito.
Aggregazioni filtrate
Una specifica di aggregazione di connessioni filtrata include un predicato, espresso sintatticamente in modo analogo a un'espressione lambda in C#. L'esempio seguente definisce due aggregazioni filtrate:
input Pixels [10, 20];
hidden ByRow[10, 12] from Pixels where (s,d) => s[0] == d[0];
hidden ByCol[5, 20] from Pixels where (s,d) => abs(s[1] - d[1]) <= 1;
Nel predicato per
ByRow
,s
è un parametro che rappresenta un indice nella matrice rettangolare di nodi del livello di inputPixels
ed
è un parametro che rappresenta un indice nella matrice di nodi del livello nascostoByRow
. Il tipo dis
ed
è una tupla di valori interi di lunghezza due. Concettualmente,s
include tutte le coppie di valori interi con0 <= s[0] < 10
e0 <= s[1] < 20
ed
include tutte le coppie di valori interi con0 <= d[0] < 10
e0 <= d[1] < 12
.Una condizione è presente nella parte destra dell'espressione del predicato. In questo esempio, per ogni valore di
s
ed
tale da rendere la condizione true, c'è un bordo dal nodo del livello di origine al nodo del livello di destinazione. Questa espressione di filtro indica quindi che l'aggregazione include una connessione dal nodo definito das
al nodo definito dad
in tutti i casi in cui s[0] è uguale a d[0].
È facoltativamente possibile specificare un insieme di pesi per un'aggregazione filtrata. Il valore dell'attributo Weights deve essere una tupla di valori a virgola mobile, la cui lunghezza corrisponde al numero di connessioni definite dall'aggregazione. Per impostazione predefinita, i pesi sono generati in modo casuale.
I valori dei pesi sono raggruppati in base all'indice dei nodi di destinazione, ovvero, se il primo nodo di destinazione è connesso ai nodi di origine K, i primi elementi K
della tupla Weights rappresentano i pesi per il primo nodo di destinazione nell'ordine dell'indice di origine. La stessa procedura è applicabile ai nodi di destinazione rimanenti.
È possibile specificare i pesi direttamente come valori costanti. Se ad esempio si sono appresi in precedenza i pesi, è possibile specificarli come costanti usando questa sintassi:
const Weights_1 = [0.0188045055, 0.130500451, ...]
Aggregazioni convoluzionali
Quando i dati di training hanno una struttura omogenea, le connessioni convoluzionali vengono solitamente usate per ottenere funzionalità di livello elevato dei dati. Ad esempio, nei dati di tipo immagine, audio o video è possibile che la dimensionalità spaziale o temporale sia abbastanza uniforme.
Le aggregazioni convoluzionali usanokernels rettangolari inseriti nelle dimensioni. Essenzialmente, ogni kernel definisce un insieme di pesi applicati nei vicinati locali, indicati come applicazioni di kernel. Ogni applicazione di kernel corrisponde a un nodo nel livello di origine indicato come nodo centrale. I pesi di un kernel sono condivisi tra molte connessioni. In un'aggregazione convoluzionale ogni kernel è rettangolare e tutte le applicazioni di kernel hanno le stesse dimensioni.
Le aggregazioni convoluzionali supportano gli attributi seguenti:
InputShape definisce la dimensionalità del livello di origine ai fini di questa aggregazione convoluzionale. Il valore deve essere una tupla di valori Integer positivi. Il prodotto dei valori Integer deve essere uguale al numero di nodi del livello di origine, ma non deve corrispondere in altro modo alla dimensionalità dichiarata per il livello di origine. La lunghezza di questa tupla diventa il valore di arietà per l'aggregazione convoluzionale. In genere, l'arietà rappresenta il numero di argomenti oppure operandi che una funzione può accettare.
Per definire la forma e le posizioni dei kernel, usare gli attributi KernelShape, Stride, Padding, LowerPad e UpperPad:
KernelShape: (obbligatorio) definisce la dimensionalità di ogni kernel per l'aggregazione convoluzionale. Il valore deve essere una tupla di numeri interi positivi con una lunghezza uguale al valore del grado dell'aggregazione. Ogni componente di questa tupla non deve essere maggiore del componente corrispondente di InputShape.
Stride: (facoltativo) definisce le dimensioni del passo di inserimento della convoluzione (una sola dimensione del passo per ogni dimensione), ovvero la distanza tra i nodi centrali. Il valore deve essere una tupla di numeri interi positivi con una lunghezza corrispondente al valore del grado dell'aggregazione. Ogni componente di questa tupla non deve essere maggiore del componente corrispondente di KernelShape. Il valore predefinito è una tupla con tutti i componenti uguali a uno.
Sharing: (facoltativo) definisce la condivisione dei pesi per ogni dimensione della convoluzione. Il valore può essere un singolo valore booleano o una tupla di valori booleani, con lunghezza corrispondente al valore del grado dell'aggregazione. Un singolo valore booleano viene esteso in modo da diventare una tupla di lunghezza corretta con tutti i componenti uguali al valore specificato. Il valore predefinito è una tupla costituita interamente da valori True.
MapCount: (facoltativo) definisce il numero di mapping di funzionalità per l'aggregazione convoluzionale. Il valore può essere un singolo numero intero positivo o una tupla di numeri interi positivi, con lunghezza corrispondente al valore del grado dell'aggregazione. Un singolo valore Integer viene esteso in modo da diventare una tupla di lunghezza corretta quando i primi componenti sono uguali al valore specificato e tutti i componenti rimanenti sono uguali a uno. Il valore predefinito è uno. Il numero totale di mapping di funzionalità è il prodotto dei componenti della tupla. La fattorizzazione di questo numero totale nei componenti determina il modo in cui i valori di mapping di funzionalità vengono raggruppati nei nodi di destinazione.
Weights: (facoltativo) definisce i pesi iniziali per l'aggregazione. Il valore deve essere una tupla di valori a virgola mobile con una lunghezza corrispondente al numero di pesi per kernel, come definito in seguito in questo articolo. I pesi predefiniti sono generati in modo casuale.
Sono disponibili due set di proprietà che controllano la spaziatura interna. Le proprietà si escludono a vicenda:
Padding: (facoltativo) determina se l'input deve essere riempito tramite uno schema di riempimento predefinito. Il valore può essere un singolo valore booleano o una tupla di valori booleani, con lunghezza corrispondente al valore del grado dell'aggregazione.
Un singolo valore booleano viene esteso in modo da diventare una tupla di lunghezza corretta con tutti i componenti uguali al valore specificato.
Se il valore per una dimensione è True, l'origine sarà riempita in modo logico in quella dimensione con celle a valore zero per supportare altre applicazioni di kernel, in modo che i nodi centrali del primo e dell'ultimo kernel in quella dimensione siano i primi e gli ultimi nodi di quella dimensione nel livello di origine. Il numero di nodi "fittizi" in ogni dimensione viene quindi determinato automaticamente, in modo da inserire esattamente i kernel
(InputShape[d] - 1) / Stride[d] + 1
nel livello di origine riempito.Se il valore per una dimensione è False, i kernel verranno definiti in modo che il numero di nodi esclusi in ogni lato sia uguale (con una differenza massima di 1). Il valore predefinito di questo attributo è una tupla con tutti i componenti uguali a False.
UpperPad e LowerPad: (facoltativi) consentono un maggiore controllo sulla quantità di riempimento da usare. Importante: questi attributi possono essere definiti solo se la proprietà Padding precedente non è definita. I valori devono essere tuple con numeri interi con lunghezza corrispondente al grado dell'aggregazione. Quando questi attributi sono specificati, i nodi "fittizi" vengono aggiunti alle estremità superiori e inferiori di ogni dimensione del livello di input. Il numero di nodi aggiunti alle estremità inferiori e superiori di ogni dimensione è determinato rispettivamente da LowerPad[i] e UpperPad[i].
Per assicurare che i kernel corrispondano solo a nodi "effettivi" e non a nodi "fittizi", è necessario che siano soddisfatte le condizioni seguenti:
Ogni componente diLowerPad deve essere rigorosamente minore di
KernelShape[d]/2
.Ogni componente di UpperPad non deve essere maggiore di
KernelShape[d]/2
.Il valore predefinito di questi attributi è una tupla con tutti i componenti uguali a 0.
L'impostazione Padding = true consente tutto il riempimento necessario per mantenere il "centro" del kernel all'interno dell'input "reale". In questo modo i calcoli matematici variano un po' per calcolare le dimensioni di output. In genere, le dimensioni di output D vengono calcolate come
D = (I - K) / S + 1
, doveI
è la dimensione di input,K
è la dimensione del kernel,S
è lo stride e/
è la divisione intera (con arrotondamento a zero). Se si imposta UpperPad = [1, 1], la dimensione di inputI
è in realtà 29, ovveroD = (29 - 5) / 2 + 1 = 13
. Se Padding è true,I
viene essenzialmente incrementato diK - 1
, ovveroD = ((28 + 4) - 5) / 2 + 1 = 27 / 2 + 1 = 13 + 1 = 14
. Specificando i valori per UpperPad e LowerPad si ottiene un maggiore controllo sul riempimento rispetto all'impostazione Padding = true.
Per altre informazioni sulle reti convoluzionali e le relative applicazioni, vedere gli articoli seguenti:
- http://d2l.ai/chapter_convolutional-neural-networks/lenet.html
- https://research.microsoft.com/pubs/68920/icdar03.pdf
Aggregazioni di pooling
Un'aggregazione di pooling applica una geometria analoga alla connettività convoluzionale, ma usa funzioni predefinite per i valori del nodo di origine per derivare il valore del nodo di destinazione. Le aggregazioni di pooling non hanno quindi stati sottoponibili a training (pesi o distorsioni). Le aggregazioni di pooling supportano tutti gli attributi convoluzionali, ad eccezione di Sharing, MapCount e Weights.
In genere, i kernel riepilogati da unità di pooling adiacenti non sono sovrapposti. Se Stride[d] equivale a KernelShape[d] in ogni dimensione, il livello ottenuto è il livello di pooling locale tradizionale, usato in genere nelle reti neurali convoluzionali. Ogni nodo di destinazione calcola il valore massimo o medio delle attività del rispettivo kernel nel livello di origine.
L'esempio seguente illustra un'aggregazione di pooling:
hidden P1 [5, 12, 12]
from C1 max pool {
InputShape = [ 5, 24, 24];
KernelShape = [ 1, 2, 2];
Stride = [ 1, 2, 2];
}
- L'arietà dell'aggregazione è uguale a 3: la lunghezza delle tuple
InputShape
,KernelShape
eStride
. - Il numero di nodi del livello di origine è pari a
5 * 24 * 24 = 2880
. - Questo è un livello di pooling locale tradizionale, perché KernelShape e Stride sono uguali.
- Il numero di nodi del livello di destinazione è pari a
5 * 12 * 12 = 1440
.
Per altre informazioni sui livelli di pooling, vedere gli articoli seguenti:
- https://www.cs.toronto.edu/~hinton/absps/imagenet.pdf (Sezione 3.4)
- https://cs.nyu.edu/~koray/publis/lecun-iscas-10.pdf
- https://cs.nyu.edu/~koray/publis/jarrett-iccv-09.pdf
Aggregazioni di normalizzazione delle risposte
La normalizzazione delle risposte è uno schema di normalizzazione locale introdotto per la prima volta da Geoffrey Hinton e altri, nel documento ImageNet Classification with Deep Convolutional Neural Networks (Classificazione ImageNet con reti neurali convoluzionali profonde).
La normalizzazione delle risposte viene usata per semplificare la generalizzazione nelle reti neurali. Quando un neurone opera a un livello di attivazione molto elevato, un livello di normalizzazione delle risposte locale sopprime il livello di attivazione dei neuroni circostanti. Ciò avviene tramite tre parametri (α
, β
e k
) e una struttura convoluzionale (o forma di vicinato). Ogni neurone nel livello di destinazione y corrisponde a un neurone x nel livello di origine. Il livello di attivazione di y è dato dalla formula seguente, dove f
corrisponde al livello di attivazione di un neurone e Nx
è il kernel o l'insieme contenente i neuroni nel vicinato di x, come definito dalla struttura convoluzionale seguente:
Le aggregazioni di normalizzazione delle risposte supportano tutti gli attributi convoluzionali, ad eccezione di Sharing, MapCount e Weights.
Se il kernel contiene neuroni nello stesso mapping di x, lo schema di normalizzazione è definito normalizzazione dello stesso mapping. Per definire la normalizzazione nello stesso mapping, la prima coordinata in InputShape deve avere valore 1.
Se il kernel contiene neuroni nella stessa posizione spaziale di x, ma i neuroni si trovano in mapping diversi, lo schema di normalizzazione sarà definito normalizzazione tra mapping. Questo tipo di normalizzazione delle risposte implementa una forma di inibizione laterale ispirata dal tipo trovato nei neuroni reali, creando una competizione per livelli di attivazione elevati tra gli output di neuroni calcolati nei diversi mapping. Per definire la normalizzazione tra mapping, è necessario che la prima coordinata sia superiore a uno e non sia superiore al numero di mapping e che il resto delle coordinate abbia valore 1.
Poiché le aggregazioni di normalizzazione delle risposte applicano una funzione predefinita ai valori del nodo di origine per determinare il valore del nodo di destinazione, non hanno stati sottoponibili a training (pesi o distorsioni).
Nota
I nodi del livello di destinazione corrispondono ai neuroni che costituiscono i nodi centrali dei kernel. Ad esempio, se KernelShape[d]
è dispari, KernelShape[d]/2
corrisponderà al nodo centrale del kernel. Se KernelShape[d]
è pari, il nodo centrale si trova in KernelShape[d]/2 - 1
. Se quindi Padding[d]
è False, il primo e l'ultimo nodo KernelShape[d]/2
non hanno nodi corrispondenti nel livello di destinazione. Per evitare questa situazione, definire Padding come [true, true, …, true].
Oltre ai quattro attributi descritti precedentemente, le aggregazioni di normalizzazione delle risposte supportano anche gli attributi seguenti:
- Alpha: (obbligatorio) specifica un valore a virgola mobile che corrisponde a
α
nella formula precedente. - Beta: (obbligatorio) specifica un valore a virgola mobile che corrisponde a
β
nella formula precedente. - Offset: (facoltativo) specifica un valore a virgola mobile che corrisponde a
k
nella formula precedente. Assume il valore predefinito 1.
L'esempio seguente definisce un'aggregazione di normalizzazione delle risposte usando questi attributi:
hidden RN1 [5, 10, 10]
from P1 response norm {
InputShape = [ 5, 12, 12];
KernelShape = [ 1, 3, 3];
Alpha = 0.001;
Beta = 0.75;
}
- Il livello di origine include cinque mappe, ognuna con una dimensione di 12x12, in totale in 1440 nodi.
- Il valore di KernelShape indica che si tratta dello stesso livello di normalizzazione di mapping, in cui il vicinato è un rettangolo 3x3.
- Se il valore predefinito di Padding è False, il livello di destinazione ha solo 10 nodi in ogni dimensione. Per includere un nodo nel livello di destinazione corrispondente a ogni nodo nel livello di origine, aggiungere Padding = [true, true, true]; e modificare le dimensioni di RN1 su [5, 12, 12].
Dichiarazione delle condivisioni
Net# supporta facoltativamente la definizione di più aggregazioni con pesi condivisi. I pesi di qualsiasi aggregazione possono essere condivisi se le loro strutture sono uguali. La sintassi seguente definisce le aggregazioni con i pesi condivisi:
share-declaration:
share { layer-list }
share { bundle-list }
share { bias-list }
layer-list:
layer-name , layer-name
layer-list , layer-name
bundle-list:
bundle-spec , bundle-spec
bundle-list , bundle-spec
bundle-spec:
layer-name => layer-name
bias-list:
bias-spec , bias-spec
bias-list , bias-spec
bias-spec:
1 => layer-name
layer-name:
identifier
Ad esempio, la dichiarazione di condivisioni seguente specifica i nomi dei livelli, indicando che devono essere condivisi sia i pesi che le distorsioni:
Const {
InputSize = 37;
HiddenSize = 50;
}
input {
Data1 [InputSize];
Data2 [InputSize];
}
hidden {
H1 [HiddenSize] from Data1 all;
H2 [HiddenSize] from Data2 all;
}
output Result [2] {
from H1 all;
from H2 all;
}
share { H1, H2 } // share both weights and biases
- Le funzionalità di input sono partizionate in due livelli di input di dimensioni identiche.
- I livelli nascosti calcolano quindi le funzionalità di livello superiore nei due livelli di input.
- La dichiarazione di condivisione specifica che H1 e H2 devono essere calcolati in modo analogo dai rispettivi input.
In alternativa, è possibile specificare questo concetto con due dichiarazioni delle condivisioni separate, come indicato di seguito:
share { Data1 => H1, Data2 => H2 } // share weights
<!-- -->
share { 1 => H1, 1 => H2 } // share biases
È possibile usare la forma breve solo se i livelli contengono una singola aggregazione. In genere, la condivisione è possibile solo se la struttura rilevante è identica, ovvero se le dimensioni, la geometria convoluzionale e così via sono identiche.
Esempi di utilizzo di Net#
Questa sezione offre alcuni esempi di utilizzo di Net# per aggiungere livelli nascosti, definire il modo in cui i livelli nascosti interagiscono con altri livelli e creare reti convoluzionali.
Definire una semplice rete neurale personalizzata, ad esempio "Hello World"
Questo esempio illustra come creare un modello di rete neurale con un singolo livello nascosto.
input Data auto;
hidden H [200] from Data all;
output Out [10] sigmoid from H all;
L'esempio illustra alcuni comandi di base come indicato di seguito:
- La prima riga definisce il livello di input (denominato
Data
). Quando si usa laauto
parola chiave , la rete neurale include automaticamente tutte le colonne di funzionalità negli esempi di input. - La seconda riga crea il livello nascosto. Il nome
H
è assegnato al livello nascosto, che ha 200 nodi. Questo livello è completamente connesso al livello di input. - La terza riga definisce il livello di output (denominato
Out
), che contiene 10 nodi di output. Se la rete neurale viene usata per la classificazione, è disponibile un nodo di output per ogni classe. La parola chiave sigmoid indica la funzione di output applicata al livello di output.
Definire più livelli nascosti: esempio obiettivo computer
L'esempio seguente illustra come definire una rete neurale leggermente più complessa, con più livelli nascosti personalizzati.
// Define the input layers
input Pixels [10, 20];
input MetaData [7];
// Define the first two hidden layers, using data only from the Pixels input
hidden ByRow [10, 12] from Pixels where (s,d) => s[0] == d[0];
hidden ByCol [5, 20] from Pixels where (s,d) => abs(s[1] - d[1]) <= 1;
// Define the third hidden layer, which uses as source the hidden layers ByRow and ByCol
hidden Gather [100]
{
from ByRow all;
from ByCol all;
}
// Define the output layer and its sources
output Result [10]
{
from Gather all;
from MetaData all;
}
Questo esempio descrive diverse funzionalità del linguaggio di specifica delle reti neurali:
- La struttura ha due livelli di input,
Pixels
eMetaData
. - Il livello
Pixels
è un livello di origine per due aggregazioni di connessioni, con livelli di destinazione,ByRow
eByCol
. - I livelli
Gather
eResult
sono livelli di destinazione in più aggregazioni di connessioni. - Il livello di output,
Result
, è un livello di destinazione in due aggregazioni di connessione. Una con il secondo livello nascostoGather
come livello di destinazione e l'altra con il livello di inputMetaData
come livello di destinazione. - I livelli nascosti,
ByRow
eByCol
, specificano connettività filtrata usando espressioni del predicato. Più precisamente, il nodo inByRow
su [x, y] è connesso ai nodi inPixels
che hanno la prima coordinata indice uguale alla prima coordinata del nodo x. Analogamente, il nodo inByCol
su [x, y] è connesso ai nodi inPixels
che hanno la seconda coordinata indice all'interno di una della seconda coordinata del nodo y.
Definire una rete per la classificazione multiclasse convoluzionale: esempio di riconoscimento cifra
La definizione della rete seguente è progettata per riconoscere numeri e illustra alcune tecniche avanzate per la personalizzazione di una rete neurale.
input Image [29, 29];
hidden Conv1 [5, 13, 13] from Image convolve
{
InputShape = [29, 29];
KernelShape = [ 5, 5];
Stride = [ 2, 2];
MapCount = 5;
}
hidden Conv2 [50, 5, 5]
from Conv1 convolve
{
InputShape = [ 5, 13, 13];
KernelShape = [ 1, 5, 5];
Stride = [ 1, 2, 2];
Sharing = [false, true, true];
MapCount = 10;
}
hidden Hid3 [100] from Conv2 all;
output Digit [10] from Hid3 all;
La struttura ha un livello di input singolo,
Image
.La parola chiave
convolve
indica che i livelliConv1
eConv2
sono livelli convoluzionali. Tutte queste dichiarazioni di livelli sono seguite da un elenco di attributi convoluzionali.La rete ha un terzo livello nascosto,
Hid3
, che è completamente connesso al secondo livello nascosto,Conv2
.Il livello di output,
Digit
, è connesso solo al terzo livello nascosto,Hid3
. La parola chiaveall
indica che il livello di output è completamente connesso aHid3
.L'arità della convoluzione è tre: la lunghezza delle tuple
InputShape
,KernelShape
,Stride
eSharing
.Il numero di pesi per kernel è
1 + KernelShape\[0] * KernelShape\[1] * KernelShape\[2] = 1 + 1 * 5 * 5 = 26
. Oppure26 * 50 = 1300
.È possibile calcolare i nodi in ogni livello nascosto come indicato di seguito:
NodeCount\[0] = (5 - 1) / 1 + 1 = 5
NodeCount\[1] = (13 - 5) / 2 + 1 = 5
NodeCount\[2] = (13 - 5) / 2 + 1 = 5
Il numero totale di nodi può essere calcolato usando la dimensionalità dichiarata del livello, [50, 5, 5], come indicato di seguito:
MapCount * NodeCount\[0] * NodeCount\[1] * NodeCount\[2] = 10 * 5 * 5 * 5
Poiché
Sharing[d]
è False solo perd == 0
, il numero di kernel èMapCount * NodeCount\[0] = 10 * 5 = 50
.
Riconoscimenti
Il linguaggio Net # per personalizzare l'architettura delle reti neurali è stato sviluppato presso Microsoft da Shon Katzenberger (progettista, Machine Learning) e Alexey Kamenev (ingegnere di software, Microsoft Research). Viene usato internamente per progetti Machine Learning e le applicazioni che vanno dal rilevamento immagine alle analisi di testo. Per altre informazioni, vedere Reti neurali in Machine Learning Studio - Introduzione a Net#