Giugno 2018

Volume 33 Numero 6

Il presente articolo è stato tradotto automaticamente.

Esecuzione dei test - Regressione neurale con CNTK

Dal James McCaffrey | 2018 giugno

Download del codice disponibile all'indirizzo msdn.com/magazine/0518magcode.

L'obiettivo di un problema di regressione consiste nell'ottenere una previsione quando il valore da prevedere è un singolo valore numerico. Ad esempio, è possibile

desidera stimare l'altezza di una persona in base al peso, età e sesso. Esistono numerose tecniche utilizzabili per affrontare un problema di regressione. In questo articolo verrà illustrato come utilizzare la libreria CNTK per creare un modello di regressione di rete neurale.

È un buon metodo per visualizzare in questo articolo è a due punte per dare un'occhiata il programma demo in figura 1. Il programma demo crea un modello di regressione per il benchmark di Set di dati Hydrodynamics Yacht noto. L'obiettivo consiste nello stimare una misura di resistenza per una convessa yacht, in base alle variabili predittive sei: centro della spinta del convessa, coefficiente prismatic, rapporto di spostamento di lunghezza, circolazione d'aria Trasmetti rapporto, rapporto raggio di lunghezza e numero di Froude.

Figura 1 regressione usando una rete neurale CNTK

Il programma demo crea una rete neurale con due livelli nascosti, ognuno dei quali include cinque nodi di elaborazione. Dopo il training, il modello viene utilizzato per eseguire stime per due degli elementi di dati. Il primo elemento ha valori predittive (0,52, 0,79, 0,55, 0.41, 0,65, compreso tra 0,00). La resistenza convessa stimato è 0.0078 e la resistenza effettiva è sarà 0,0030. Il secondo elemento presenta valori predittive (1.00, 1.00, 0,55, 0.56, 0.46, 1,00). La resistenza convessa stimato è 0.8125 e la resistenza effettiva è 0.8250. Il modello sembra essere piuttosto accurato.

Questo articolo si presuppone avere intermedie o migliori delle competenze di programmazione, ma non che si conoscono CNTK o reti neurali. La dimostrazione codificata tramite Python, la lingua predefinita per l'apprendimento, ma anche se non si conosce Python dovrebbe essere in grado di seguire la procedura senza troppa difficoltà. Il codice per il programma demo viene presentato nella sua interezza in questo articolo. Il file di dati convessa yacht utilizzato dal programma demo è reperibile in bit.ly/2Ibsm5Ded è anche disponibile nel download che accompagna questo articolo.

Informazioni sui dati

Quando si crea un modello di machine learning, la preparazione dei dati è quasi sempre la parte che richiedono più tempo del progetto. Il set di dati non elaborato ha 308 elementi ed è simile a:

-2.3 0.568 4.78 3.99 3.17 0.125 0.11
-2.3 0.568 4.78 3.99 3.17 0.150 0.27
...
-5.0 0.530 4.78 3.75 3.15 0.125 0.09
...
-2.3 0.600 4.34 4.23 2.73 0.450 46.66

Il file è delimitato da spazi. I primi sei valori sono i valori predittive (spesso chiamati funzionalità nella terminologia di machine learning). L'ultimo valore per ogni riga è la "residuary resistenza per unità di peso di spostamento."

Poiché è presente più di una variabile predittiva, non è possibile visualizzare il set di dati completo in un grafico. È tuttavia possibile ottenere un'idea approssimativa della struttura dei dati esaminando il grafico nel figura 2. Il grafico vengono visualizzati solo i valori presenti predittive prismatic coefficiente e la resistenza convessa. Si noterà che i valori dei coefficienti prismatic, autonomamente, non forniscono informazioni sufficienti per creare una stima accurata di resistenza convessa.

Figura 2 Yacht parziale convessa dati

Quando si utilizzano le reti neurali, è in genere necessario normalizzare i dati per creare un modello affidabile. Si usa la normalizzazione min-max sui valori predittive sei e dai valori resistenza convessa. È possibile eliminare i dati non elaborati in un foglio di calcolo di Excel e, per ogni colonna, è possibile calcolare i valori max e min. Quindi, per ogni colonna, è possibile sostituire ogni valore v con (v - min) / (max - min). Ad esempio, il valore minimo coefficiente prismatic è 0,53 e il valore massimo è 0.60. Il primo valore nella colonna è 0.568 ed è normalizzato secondo (0.568 - 0,53) / (0.60 - 0,53) = 0.038 / 0,07 = 0.5429.

Dopo la normalizzazione, è possibile inserire tag | predittori e | resistenza nel foglio di calcolo Excel in modo che i dati possono essere lette facilmente da un oggetto lettore dati CNTK. Quindi, dopo aver esportato i dati come file delimitato da tabulazioni. I dati risultanti simile:

|predictors  0.540000  0.542857 . . |resistance  0.001602
|predictors  0.540000  0.542857 . . |resistance  0.004166
...

Le alternative per la normalizzazione min-max includono normalizzazione del punteggio z e normalizzazione di ordine di grandezza.

Il programma Demo

Il programma demo completo, con poche modifiche secondarie per risparmiare spazio, viene presentato nel figura 3. Tutti i normali errori è stato rimosso. È possibile impostare un rientro con due caratteri di spazio anziché le quattro consuete come una questione di preferenze personali e risparmiare spazio. Si noti che il ' \' carattere viene utilizzato da Python per la continuazione di riga.

Figura 3 regressione Demo programma

# hydro_reg.py
# CNTK 2.4 with Anaconda 4.1.1 (Python 3.5, NumPy 1.11.1)
# Predict yacht hull resistance based on six predictors

import numpy as np
import cntk as C

def create_reader(path, input_dim, output_dim, rnd_order,
  sweeps):
  x_strm = C.io.StreamDef(field='predictors',
    shape=input_dim, is_sparse=False)
  y_strm = C.io.StreamDef(field='resistance',
    shape=output_dim, is_sparse=False)
  streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
  deserial = C.io.CTFDeserializer(path, streams)
  mb_src = C.io.MinibatchSource(deserial,
    randomize=rnd_order, max_sweeps=sweeps)
  return mb_src

# ========================================================

def main():
  print("\nBegin yacht hull regression \n")
  print("Using CNTK version = " + \
    str(C.__version__) + "\n")
  input_dim = 6  # center of buoyancy, etc.
  hidden_dim = 5
  output_dim = 1  # residuary resistance
  train_file = ".\\Data\\hydro_data_cntk.txt"
  # data resembles:
  # |predictors 0.540  0.542 . . |resistance  0.001
  # |predictors 0.540  0.542 . . |resistance  0.004
  # 1. create neural network model
  X = C.ops.input_variable(input_dim, np.float32)
  Y = C.ops.input_variable(output_dim)
  print("Creating a 6-(5-5)-1 tanh regression NN for \
yacht hull dataset ")
  with C.layers.default_options():
    hLayer1 = C.layers.Dense(hidden_dim,
      activation=C.ops.tanh, name='hidLayer1')(X)
    hLayer2 = C.layers.Dense(hidden_dim,
      activation=C.ops.tanh, name='hidLayer2')(hLayer1)  
    oLayer = C.layers.Dense(output_dim,
      activation=None, name='outLayer')(hLayer2)
  model = C.ops.alias(oLayer)  # alias
  # 2. create learner and trainer
  print("Creating a squared error batch=11 Adam \
fixed LR=0.005 Trainer \n")
  tr_loss = C.squared_error(model, Y)
  max_iter = 50000
  batch_size = 11
  learn_rate = 0.005
  learner = C.adam(model.parameters, learn_rate, 0.99)
  trainer = C.Trainer(model, (tr_loss), [learner])
  # 3. create reader for train data
  rdr = create_reader(train_file, input_dim, output_dim,
    rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
  hydro_input_map = {
    X : rdr.streams.x_src,
    Y : rdr.streams.y_src
  }
  # 4. train
  print("Starting training \n")
  for i in range(0, max_iter):
    curr_batch = rdr.next_minibatch(batch_size,
      input_map=hydro_input_map)
    trainer.train_minibatch(curr_batch)
    if i % int(max_iter/10) == 0:
      mcee = trainer.previous_minibatch_loss_average
      print("batch %6d: mean squared error = %8.4f" % \
        (i, mcee))
  print("\nTraining complete")
  # (could save model to disk here)
  # 5. use trained model to make some predictions
  np.set_printoptions(precision=2, suppress=True)
  inpts = np.array(
    [[0.520000, 0.785714, 0.550000, 0.405512, \
      0.648352, 0.000000],
     [1.000000, 1.000000, 0.550000, 0.562992, \
      0.461538, 1.000000]],
    dtype=np.float32)
  actuals = np.array([0.003044, 0.825028],
    dtype=np.float32)
  for i in range(len(inpts)):
    print("\nInput: ", inpts[i])
    pred = model.eval(inpts[i])
    print("predicted resistance: %0.4f" % pred[0][0])
    print("actual resistance:    %0.4f" % actuals[i])
  print("\nEnd yacht hull regression ")

# ========================================================

if __name__ == "__main__":
  main()

Installazione CNTK può risultare un po' difficile. Installare la distribuzione Anaconda Python, che contiene l'interprete Python necessario, i pacchetti necessari, ad esempio NumPy e SciPy, più interessanti utilità, ad esempio pip. È possibile utilizzare Anaconda3 4.1.1 a 64 bit, che ha 3.5 Python. Dopo aver installato Anaconda, installare CNTK come un pacchetto di Python, non è un sistema autonomo, tramite l'utilità pip. Da una shell del normale, il comando utilizzato è:

>pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.4-cp35-cp35m-win_amd64.whl

La dimostrazione hydro_reg.py ha una funzione helper create_reader. È possibile considerare create_reader come boilerplate per un problema di regressione CNTK. L'unica differenza che sarà necessario modificare nella maggior parte degli scenari riguarda i nomi di tag nel file di dati.

Tutta la logica di controllo è in una singola funzione principale. Inizia il codice:

def main():
  print("Begin yacht hull regression \n")
  print("Using CNTK version = " + \
    str(C.__version__) + "\n")
  input_dim = 6  # center of buoyancy, etc.
  hidden_dim = 5
  output_dim = 1  # residuary resistance
  train_file = ".\\Data\\hydro_data_cntk.txt"
...

Poiché è giovani CNTK e in fase di sviluppo continuo, è consigliabile per visualizzare la versione che viene utilizzato (2.4 in questo caso). Il numero di nodi di input è determinato dalla struttura del set di dati. Per un problema di regressione, il numero di nodi di output è sempre impostato su 1. Il numero di livelli nascosti e il numero di nodi di elaborazione in ogni livello nascosto sono parametri gratuiti, deve essere determinati da prove ed errori.

Il programma demo utilizza tutti gli 308 elementi per il training. Un approccio alternativo consiste per suddividere il set di dati in un training set (in genere l'80% dei dati) e un set di test (rimanente % 20). Dopo il training, è possibile calcolare la metrica di perdita e sull'accuratezza del modello su set di dati di test per verificare che le metriche sono simili a quelle sui dati di training.

Creazione del modello di rete neurale

La dimostrazione imposta gli oggetti CNTK per contenere le previsioni e i valori di resistenza convessa true:

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim)

CNTK Usa valori a 32 bit per impostazione predefinita perché precisione a 64 bit è raramente necessario. Il nome della funzione input_variable può essere confusione se si ha familiarità con CNTK. In questo caso, "input_" si riferisce al fatto che gli oggetti restituiti contengono valori che provengono dai dati di input (che corrispondono ai sia di input e output della rete neurale).

La creazione della rete neurale con queste istruzioni:

print("Creating a 6-(5-5)-1 NN")
with C.layers.default_options():
  hLayer1 = C.layers.Dense(hidden_dim,
    activation=C.ops.tanh, name='hidLayer1')(X)
  hLayer2 = C.layers.Dense(hidden_dim,
    activation=C.ops.tanh, name='hidLayer2')(hLayer1)  
  oLayer = C.layers.Dense(output_dim,
    activation=None, name='outLayer')(hLayer2)
model = C.ops.alias(oLayer)  # alias

È presente una netta questo proposito. Python "con" istruzione utilizzabile per passare un set di valori dei parametri comuni a più funzioni. In questo caso, i valori della rete neurale pesi e i pregiudizi vengono inizializzati utilizzando i valori predefiniti CNTK. Le reti neurali sono estremamente riservate valori pesi e i pregiudizi iniziali, in modo da fornire valori non predefiniti è uno dei primi aspetti per provare a eseguire quando si verifica un errore di rete neurale per informazioni su, ovvero una situazione comune sicuramente.

La rete neurale ha due livelli nascosti. L'oggetto X come funziona l'input per il primo livello nascosto; il primo livello nascosto funge da input per il secondo livello nascosto; e il secondo nascosto atti di livello come input per il livello di output.

I due livelli nascosti usano l'attivazione tanh (tangente iperbolica). Le due alternative principali sono attivazione logistica sigmoide e rettificato lineare unità (ReLU). Il livello di output viene utilizzato "None" attivazione, ovvero i valori dei nodi di output non modificato. Questo è il modello di progettazione da usare per un problema di regressione. Non utilizza l'attivazione viene chiamato a volte tramite la funzione di attivazione identificare perché la funzione identity matematiche è f (x) = x, che non ha alcun effetto.

Il programma demo crea un alias denominato "modello" per il livello di output. Questa tecnica è facoltativa ed è un po' meno evidenti. L'idea è che una rete neurale è essenzialmente una funzione matematica complessa. I nodi di output rappresentano concettualmente entrambi un livello di rete e il modello di rete/nel suo complesso.

Training del modello

Gli elementi centrali di funzionalità CNTK sono la possibilità di eseguire il training di un modello di rete neurale. Training viene preparato con queste istruzioni:

tr_loss = C.squared_error(model, Y)
max_iter = 50000
batch_size = 11
learn_rate = 0.005
learner = C.adam(model.parameters, learn_rate, 0.99)
trainer = C.Trainer(model, (tr_loss), [learner])

Una funzione di perdita (errore) è necessario pertanto l'oggetto di training in grado di modificare i pesi e i pregiudizi per ridurre l'errore. 2.4 CNTK ha nove perdita funzioni, ma squared_error semplice è quasi sempre adatto per un problema di regressione. Il numero di iterazioni corrisponde al numero di operazioni di aggiornamento e deve essere determinato dal prove ed errori.

L'oggetto Trainer richiede un oggetto strumento di apprendimento. È possibile pensare a uno strumento di apprendimento come un algoritmo. CNTK supporta gli algoritmi di apprendimento otto. Per problemi di regressione, è possibile in genere ottengono risultati soddisfacenti con base con sfumatura stocastica o Adam più sofisticate ("stima momentum adattivo").

Le dimensioni del batch viene utilizzata da CNTK per stabilire con quale frequenza eseguire gli aggiornamenti di compensazione e il peso. La dimostrazione imposta le dimensioni del batch a 11. Pertanto, gli 308 elementi verranno raggruppati in 308 / 11 = 28 selezionate in modo casuale in batch. Ogni batch viene analizzato e quindi gli aggiornamenti vengono eseguiti. La velocità di apprendimento controlla la grandezza delle rettifiche di distorsione e il peso. Determinare i valori validi per la dimensione del batch, il numero massimo di iterazioni e la velocità di apprendimento sono spesso maggiori sfide durante la creazione di un modello di stima della rete neurale.

La funzione create_reader chiamate definito dal programma demo, ovviamente, creare un oggetto del lettore. E viene creato un input_map che indica il lettore in cui sono i valori della funzionalità e dove è il valore-a-prevedere:

rdr = create_reader(train_file, input_dim, output_dim,
  rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
hydro_input_map = {
  X : rdr.streams.x_src,
  Y : rdr.streams.y_src
}

Il parametro rnd_order garantisce che i dati elementi verranno elaborati in modo diverso a ogni passaggio, è importante per evitare di training da bloccare. L'argomento INFINITELY_REPEAT consente training sulla passa più attraverso il set di dati 308-item.

Dopo la preparazione del training del modello come segue:

for i in range(0, max_iter):
  curr_batch = rdr.next_minibatch(batch_size,
    input_map=hydro_input_map)
  trainer.train_minibatch(curr_batch)
  if i % int(max_iter/10) == 0:
    mcee = trainer.previous_minibatch_loss_average
    print("batch %6d: mean squared error = %8.4f" % \
      (i, mcee))

La funzione next_minibatch estrae gli 11 elementi dai dati. La funzione train utilizza l'algoritmo di Adam per aggiornare i pesi e i pregiudizi basati dell'errore quadratico medio tra valori resistenza convessa calcolata e resistenza effettivo. Verrà visualizzato l'errore quadratico sul batch 11-item corrente ogni 50.000 / 10 = 5000 batch è possibile monitorare visivamente lo stato di avanzamento di training: È possibile visualizzare i valori di perdita/errore in genere di ridurre i.

Utilizzo del modello

Dopo il training del modello, il programma demo effettua alcune stime. In primo luogo, i valori predittive per due elementi arbitrari dal set di dati normalizzato vengono (elementi selezionati 99 e 238) e inseriti in una matrice di matrici di matrici stile:

inpts = np.array(
  [[0.520000, 0.785714, 0.550000, 0.405512,
    0.648352, 0.000000],
   [1.000000, 1.000000, 0.550000, 0.562992,
    0.461538, 1.000000]],
  dtype=np.float32)

Successivamente, i valori di resistenza normalizzato convessa effettivo corrispondenti vengono inseriti in una matrice:

actuals = np.array([0.003044, 0.825028], dtype=np.float32)

Quindi, i valori predittive vengono utilizzati per calcolare i valori stimati utilizzando la funzione model.eval e vengono visualizzati i valori stimati ed effettivi:

for i in range(len(inpts)):
  print("\nInput: ", inpts[i])
  pred = model.eval(inpts[i])
  print("predicted resistance: %0.4f" % pred[0][0])
  print("actual resistance:    %0.4f" % actuals[i])
print("End yacht hull regression ")

Si noti che viene restituito il valore di resistenza convessa stimati come una matrice di matrici di matrici con un singolo valore. Pertanto, il valore stesso è [0] [0] (riga 0, colonna 0). Si lavora con le forme di CNTK vettori e matrici è una sfida significativa sintassi. Quando si lavora con CNTK impiegano molto tempo stampa gli oggetti e visualizzazione dei loro forma, lungo le righe di print(something.shape).

Conclusioni

Quando si crea un modello di regressione di rete neurale, non vi è alcuna metrica di accuratezza predefiniti. Se si desidera calcolare l'accuratezza della stima che è necessario definire cosa significa per un valore stimato sia abbastanza ravvicinati per il valore effettivo corrispondente affinché venga considerato corretto. In genere, si potrebbe specificare una percentuale/proporzione, ad esempio 0,10 e valutare un valore stimato come valore corretto se si trova all'interno di tale percentuale del valore effettivo.

Poiché il modello demo funziona con dati normalizzati, se si utilizza il modello per eseguire una stima nuovi valori predittive non visti in precedenza, è necessario normalizzare tramite gli stessi valori min-max utilizzati sui dati di training. Allo stesso modo, un valore di resistenza convessa stimati, pv, è normalizzato, in modo sarebbe necessario eseguire la denormalizzazione calcolando pv * (max - min) + min.

Il termine "regressione" può avere diversi significati diversi. In questo articolo il termine si riferisce a uno scenario di problema in cui l'obiettivo consiste nello stimare un valore numerico singolo (resistenza convessa). La tecnica di regressione lineare statistiche classico è molto più semplice rispetto alla regressione della rete neurale, ma in genere molto meno precisi. Di machine learning tecnica di regressione logistica consente di stimare un singolo valore numerico compreso tra 0,0 e 1,0, che viene interpretato come un valore di probabilità e quindi utilizzati per stimare un valore categorico, ad esempio "male" (p < 0,5) o "female" (p > 0,5).


Ripristino di emergenza. James McCaffrey funziona per Microsoft Research Redmond, WA Ha lavorato su diversi prodotti Microsoft, tra cui Internet Explorer e Bing. Dr. McCaffrey può essere raggiunto al jamccaff@microsoft.com.