CNTK - Regresión de red neuronal

El capítulo le ayudará a comprender la regresión de la red neuronal con respecto a CNTK.

Introducción

Como sabemos, para predecir un valor numérico a partir de una o más variables predictoras, utilizamos la regresión. Tomemos un ejemplo de predicción del valor medio de una casa en, digamos, una de las 100 ciudades. Para hacerlo, tenemos datos que incluyen:

  • Una estadística de criminalidad para cada ciudad.

  • La antigüedad de las casas en cada pueblo.

  • Una medida de la distancia de cada ciudad a una ubicación privilegiada.

  • La proporción de estudiantes por maestro en cada ciudad.

  • Una estadística demográfica racial para cada pueblo.

  • El valor medio de la vivienda en cada ciudad.

Con base en estas cinco variables predictoras, nos gustaría predecir el valor mediano de la vivienda. Y para esto podemos crear un modelo de regresión lineal a lo largo de las líneas de -

Y = a0+a1(crime)+a2(house-age)+(a3)(distance)+(a4)(ratio)+(a5)(racial)

En la ecuación anterior:

Y es un valor mediano predicho

a0 es una constante y

a1 hasta a5 todas son constantes asociadas con los cinco predictores que discutimos anteriormente.

También tenemos un enfoque alternativo de usar una red neuronal. Creará un modelo de predicción más preciso.

Aquí, crearemos un modelo de regresión de red neuronal utilizando CNTK.

Cargando conjunto de datos

Para implementar la regresión de la red neuronal usando CNTK, usaremos el conjunto de datos de valores de la casa del área de Boston. El conjunto de datos se puede descargar del Repositorio de aprendizaje automático de UCI, que está disponible enhttps://archive.ics.uci.edu/ml/machine-learning-databases/housing/. Este conjunto de datos tiene un total de 14 variables y 506 instancias.

Pero, para nuestro programa de implementación, usaremos seis de las 14 variables y 100 instancias. De 6, 5 como predictores y uno como valor a predecir. De 100 casos, utilizaremos 80 para entrenamiento y 20 para propósitos de prueba. El valor que queremos predecir es el precio medio de la vivienda en una ciudad. Veamos los cinco predictores que usaremos:

  • Crime per capita in the town - Esperaríamos que se asociaran valores más pequeños con este predictor.

  • Proportion of owner - unidades ocupadas construidas antes de 1940 - Esperaríamos que se asociaran valores más pequeños con este predictor porque un valor más grande significa una casa más antigua.

  • Weighed distance of the town to five Boston employment centers.

  • Area school pupil-to-teacher ratio.

  • An indirect metric of the proportion of black residents in the town.

Preparación de archivos de prueba y entrenamiento

Como hicimos antes, primero debemos convertir los datos sin procesar al formato CNTK. Vamos a utilizar los primeros 80 elementos de datos con fines de entrenamiento, por lo que el formato CNTK delimitado por tabulaciones es el siguiente:

|predictors 1.612820 96.90 3.76 21.00 248.31 |medval 13.50
|predictors 0.064170 68.20 3.36 19.20 396.90 |medval 18.90
|predictors 0.097440 61.40 3.38 19.20 377.56 |medval 20.00
. . .

Los siguientes 20 elementos, también convertidos al formato CNTK, se utilizarán con fines de prueba.

Construyendo modelo de regresión

Primero, necesitamos procesar los archivos de datos en formato CNTK y para eso, usaremos la función auxiliar llamada create_reader como sigue -

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='medval', 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

A continuación, necesitamos crear una función auxiliar que acepte un objeto de mini-lote CNTK y calcule una métrica de precisión personalizada.

def mb_accuracy(mb, x_var, y_var, model, delta):
   num_correct = 0
   num_wrong = 0
   x_mat = mb[x_var].asarray()
   y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
  v = model.eval(x_mat[i])
  y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)

Ahora, necesitamos establecer los argumentos de la arquitectura para nuestro NN y también proporcionar la ubicación de los archivos de datos. Se puede hacer con la ayuda del siguiente código de Python:

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)

Ahora, con la ayuda de la siguiente línea de código, nuestro programa creará el NN no capacitado:

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)

Ahora, una vez que hemos creado el modelo dual no capacitado, necesitamos configurar un objeto de algoritmo de aprendizaje. Vamos a utilizar aprendiz SGD ysquared_error función de pérdida -

tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch=C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])

Ahora, una vez que terminemos con el objeto del algoritmo de aprendizaje, necesitamos crear una función de lector para leer los datos de entrenamiento:

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

Ahora es el momento de entrenar nuestro modelo NN -

for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
mcee = trainer.previous_minibatch_loss_average
acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))

Una vez que hayamos terminado con el entrenamiento, evaluemos el modelo usando elementos de datos de prueba:

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)

Después de evaluar la precisión de nuestro modelo NN entrenado, lo usaremos para hacer una predicción sobre datos invisibles:

np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])

Modelo de regresión completo

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='medval', 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 mb_accuracy(mb, x_var, y_var, model, delta):
num_correct = 0
num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
   v = model.eval(x_mat[i])
   y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)
tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch = C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
   mcee = trainer.previous_minibatch_loss_average
   acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
   print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))
   print("\nEvaluating test data \n")
   rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
   boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
   num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
if __name__== ”__main__”:
   main()

Salida

Using CNTK version = 2.7
batch 0: mean squared error = 385.6727, accuracy = 0.00%
batch 300: mean squared error = 41.6229, accuracy = 20.00%
batch 600: mean squared error = 28.7667, accuracy = 40.00%
batch 900: mean squared error = 48.6435, accuracy = 40.00%
batch 1200: mean squared error = 77.9562, accuracy = 80.00%
batch 1500: mean squared error = 7.8342, accuracy = 60.00%
batch 1800: mean squared error = 47.7062, accuracy = 60.00%
batch 2100: mean squared error = 40.5068, accuracy = 40.00%
batch 2400: mean squared error = 46.5023, accuracy = 40.00%
batch 2700: mean squared error = 15.6235, accuracy = 60.00%
Evaluating test data
Prediction accuracy = 64.00%
Predicting median home value for feature/predictor values:
[0.09 50. 4.5 17. 350.]
Predicted value is:
$21.02(x1000)

Guardar el modelo entrenado

Este conjunto de datos de valor de Boston Home tiene solo 506 elementos de datos (entre los cuales demandamos solo 100). Por lo tanto, solo tomaría unos segundos entrenar el modelo regresor NN, pero el entrenamiento en un conjunto de datos grande con cientos o miles de elementos de datos puede llevar horas o incluso días.

Podemos guardar nuestro modelo, para no tener que retenerlo desde cero. Con la ayuda de seguir el código de Python, podemos guardar nuestro NN entrenado:

nn_regressor = “.\\neuralregressor.model” #provide the name of the file
model.save(nn_regressor, format=C.ModelFormat.CNTKv2)

Los siguientes son los argumentos de la función save () utilizados anteriormente:

  • El nombre de archivo es el primer argumento de save()función. También se puede escribir junto con la ruta del archivo.

  • Otro parámetro es el format parámetro que tiene un valor predeterminado C.ModelFormat.CNTKv2.

Cargando el modelo entrenado

Una vez que guardó el modelo entrenado, es muy fácil cargar ese modelo. Solo necesitamos usar la función load (). Comprobemos esto en el siguiente ejemplo:

import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralregressor.model”)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting area median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])

El beneficio del modelo guardado es que una vez que carga un modelo guardado, se puede usar exactamente como si el modelo se acabara de entrenar.