Kit de herramientas cognitivas de Microsoft - Guía rápida

En este capítulo, aprenderemos qué es CNTK, sus características, la diferencia entre su versión 1.0 y 2.0 y aspectos destacados importantes de la versión 2.7.

¿Qué es Microsoft Cognitive Toolkit (CNTK)?

Microsoft Cognitive Toolkit (CNTK), anteriormente conocido como Computational Network Toolkit, es un juego de herramientas gratuito, fácil de usar, de código abierto y de calidad comercial que nos permite entrenar algoritmos de aprendizaje profundo para aprender como el cerebro humano. Nos permite crear algunos sistemas populares de aprendizaje profundo comofeed-forward neural network time series prediction systems and Convolutional neural network (CNN) image classifiers.

Para un rendimiento óptimo, sus funciones de marco están escritas en C ++. Aunque podemos llamar a su función usando C ++, pero el enfoque más comúnmente utilizado para el mismo es usar un programa Python.

Características de CNTK

A continuación, se muestran algunas de las características y capacidades que se ofrecen en la última versión de Microsoft CNTK:

Componentes integrados

  • CNTK tiene componentes integrados altamente optimizados que pueden manejar datos multidimensionales densos o escasos de Python, C ++ o BrainScript.

  • Podemos implementar CNN, FNN, RNN, Batch Normalization y Sequence-to-Sequence con atención.

  • Nos proporciona la funcionalidad para agregar nuevos componentes centrales definidos por el usuario en la GPU de Python.

  • También proporciona ajuste automático de hiperparámetros.

  • Podemos implementar el aprendizaje por refuerzo, las redes generativas adversarias (GAN), el aprendizaje supervisado y no supervisado.

  • Para conjuntos de datos masivos, CNTK tiene lectores optimizados integrados.

Uso de recursos de manera eficiente

  • CNTK nos proporciona un paralelismo con alta precisión en múltiples GPU / máquinas a través de SGD de 1 bit.

  • Para adaptarse a los modelos más grandes en memoria de GPU, proporciona uso compartido de memoria y otros métodos integrados.

Expresar nuestras propias redes fácilmente

  • CNTK tiene API completas para definir su propia red, alumnos, lectores, capacitación y evaluación de Python, C ++ y BrainScript.

  • Usando CNTK, podemos evaluar fácilmente modelos con Python, C ++, C # o BrainScript.

  • Proporciona API tanto de alto nivel como de bajo nivel.

  • Según nuestros datos, puede dar forma automáticamente a la inferencia.

  • Tiene bucles simbólicos de red neuronal recurrente (RNN) completamente optimizados.

Medir el rendimiento del modelo

  • CNTK proporciona varios componentes para medir el rendimiento de las redes neuronales que crea.

  • Genera datos de registro de su modelo y el optimizador asociado, que podemos usar para monitorear el proceso de entrenamiento.

Versión 1.0 vs Versión 2.0

La siguiente tabla compara las versiones 1.0 y 2.0 de CNTK:

Versión 1.0 Versión 2.0
Fue lanzado en 2016. Es una reescritura significativa de la versión 1.0 y se lanzó en junio de 2017.
Utilizaba un lenguaje de programación patentado llamado BrainScript. Sus funciones de marco se pueden llamar usando C ++, Python. Podemos cargar fácilmente nuestros módulos en C # o Java. BrainScript también es compatible con la versión 2.0.
Se ejecuta en sistemas Windows y Linux, pero no directamente en Mac OS. También se ejecuta en sistemas Windows (Win 8.1, Win 10, Server 2012 R2 y posteriores) y Linux, pero no directamente en Mac OS.

Aspectos destacados importantes de la versión 2.7

Version 2.7es la última versión principal lanzada de Microsoft Cognitive Toolkit. Tiene soporte completo para ONNX 1.4.1. A continuación se presentan algunos aspectos destacados importantes de esta última versión lanzada de CNTK.

  • Soporte completo para ONNX 1.4.1.

  • Soporte para CUDA 10 para sistemas Windows y Linux.

  • Es compatible con el bucle avanzado de redes neuronales recurrentes (RNN) en la exportación ONNX.

  • Puede exportar modelos de más de 2GB en formato ONNX.

  • Es compatible con FP16 en la acción de entrenamiento del lenguaje de scripting BrainScript.

Aquí, entenderemos sobre la instalación de CNTK en Windows y en Linux. Además, el capítulo explica la instalación del paquete CNTK, los pasos para instalar Anaconda, los archivos CNTK, la estructura de directorios y la organización de la biblioteca CNTK.

Prerrequisitos

Para instalar CNTK, debemos tener Python instalado en nuestras computadoras. Puedes ir al enlacehttps://www.python.org/downloads/y seleccione la última versión para su sistema operativo, es decir, Windows y Linux / Unix. Para obtener un tutorial básico sobre Python, puede consultar el enlacehttps://www.tutorialspoint.com/python3/index.htm.

CNTK es compatible con Windows y Linux, por lo que analizaremos ambos.

Instalación en Windows

Para ejecutar CNTK en Windows, usaremos el Anaconda versionde Python. Sabemos que Anaconda es una redistribución de Python. Incluye paquetes adicionales comoScipy yScikit-learn que son utilizados por CNTK para realizar varios cálculos útiles.

Entonces, primero veamos los pasos para instalar Anaconda en su máquina:

Step 1−Primero descargue los archivos de instalación del sitio web público https://www.anaconda.com/distribution/.

Step 2 - Una vez que haya descargado los archivos de instalación, inicie la instalación y siga las instrucciones del enlace https://docs.anaconda.com/anaconda/install/.

Step 3- Una vez instalado, Anaconda también instalará algunas otras utilidades, que incluirán automáticamente todos los ejecutables de Anaconda en la variable PATH de su computadora. Podemos administrar nuestro entorno Python desde este indicador, podemos instalar paquetes y ejecutar scripts de Python.

Instalación del paquete CNTK

Una vez que se realiza la instalación de Anaconda, puede usar la forma más común de instalar el paquete CNTK a través del ejecutable pip usando el siguiente comando:

pip install cntk

Hay varios otros métodos para instalar Cognitive Toolkit en su máquina. Microsoft tiene un conjunto prolijo de documentación que explica los otros métodos de instalación en detalle. Por favor siga el enlacehttps://docs.microsoft.com/en-us/cognitive-toolkit/Setup-CNTK-on-your-machine.

Instalación en Linux

La instalación de CNTK en Linux es un poco diferente a su instalación en Windows. Aquí, para Linux usaremos Anaconda para instalar CNTK, pero en lugar de un instalador gráfico para Anaconda, usaremos un instalador basado en terminal en Linux. Aunque el instalador funcionará con casi todas las distribuciones de Linux, limitamos la descripción a Ubuntu.

Entonces, primero veamos los pasos para instalar Anaconda en su máquina:

Pasos para instalar Anaconda

Step 1- Antes de instalar Anaconda, asegúrese de que el sistema esté completamente actualizado. Para verificar, primero ejecute los siguientes dos comandos dentro de una terminal:

sudo apt update
sudo apt upgrade

Step 2 - Una vez que la computadora esté actualizada, obtenga la URL del sitio web público https://www.anaconda.com/distribution/ para obtener los últimos archivos de instalación de Anaconda.

Step 3 - Una vez que se copia la URL, abra una ventana de terminal y ejecute el siguiente comando -

wget -0 anaconda-installer.sh url SHAPE \* MERGEFORMAT 
     y

	
	
	             f
 
 
      x
	  
|                     }

Reemplace la url marcador de posición con la URL copiada del sitio web de Anaconda.

Step 4 - A continuación, con la ayuda del siguiente comando, podemos instalar Anaconda -

sh ./anaconda-installer.sh

El comando anterior se instalará por defecto Anaconda3 dentro de nuestro directorio de inicio.

Instalación del paquete CNTK

Una vez que se realiza la instalación de Anaconda, puede usar la forma más común de instalar el paquete CNTK a través del ejecutable pip usando el siguiente comando:

pip install cntk

Examinando archivos CNTK y estructura de directorios

Una vez que CNTK está instalado como un paquete de Python, podemos examinar su estructura de archivos y directorios. Está enC:\Users\ \Anaconda3\Lib\site-packages\cntk, como se muestra a continuación en la captura de pantalla.

Verificación de la instalación de CNTK

Una vez que CNTK está instalado como un paquete de Python, debe verificar que CNTK se haya instalado correctamente. Desde el shell de comandos de Anaconda, inicie el intérprete de Python ingresandoipython. Luego, importa CNTK ingresando el siguiente comando.

import cntk as c

Una vez importado, verifique su versión con la ayuda del siguiente comando:

print(c.__version__)

El intérprete responderá con la versión CNTK instalada. Si no responde, habrá un problema con la instalación.

La organización de la biblioteca CNTK

CNTK, técnicamente un paquete de Python, está organizado en 13 subpaquetes de alto nivel y 8 subpaquetes más pequeños. La siguiente tabla consta de los 10 paquetes más utilizados:

No Señor Nombre y descripción del paquete
1

cntk.io

Contiene funciones para leer datos. Por ejemplo: next_minibatch ()

2

cntk.layers

Contiene funciones de alto nivel para crear redes neuronales. Por ejemplo: Denso ()

3

cntk.learners

Contiene funciones para entrenamiento. Por ejemplo: sgd ()

4

cntk.losses

Contiene funciones para medir el error de entrenamiento. Por ejemplo: squared_error ()

5

cntk.metrics

Contiene funciones para medir el error del modelo. Por ejemplo: classificatoin_error

6

cntk.ops

Contiene funciones de bajo nivel para crear redes neuronales. Por ejemplo: tanh ()

7

cntk.random

Contiene funciones para generar números aleatorios. Por ejemplo: normal ()

8

cntk.train

Contiene funciones de entrenamiento. Por ejemplo: train_minibatch ()

9

cntk.initializer

Contiene inicializadores de parámetros de modelo. Por ejemplo: normal () y uniforme ()

10

cntk.variables

Contiene construcciones de bajo nivel. Por ejemplo: Parámetro () y Variable ()

Microsoft Cognitive Toolkit ofrece dos versiones de compilación diferentes, a saber, solo CPU y solo GPU.

CPU solo versión de compilación

La versión de compilación solo para CPU de CNTK usa Intel MKLML optimizado, donde MKLML es el subconjunto de MKL (Math Kernel Library) y se lanzó con Intel MKL-DNN como una versión terminada de Intel MKL para MKL-DNN.

Versión de compilación solo de GPU

Por otro lado, la versión de CNTK compilada solo para GPU utiliza bibliotecas NVIDIA altamente optimizadas, como CUB y cuDNN. Es compatible con la formación distribuida en varias GPU y varias máquinas. Para un entrenamiento distribuido aún más rápido en CNTK, la versión de compilación de GPU también incluye:

  • SGD cuantificado de 1 bit desarrollado por MSR.

  • Algoritmos de entrenamiento paralelo SGD de bloque-momento.

Habilitación de GPU con CNTK en Windows

En la sección anterior, vimos cómo instalar la versión básica de CNTK para usar con la CPU. Ahora analicemos cómo podemos instalar CNTK para usar con una GPU. Pero, antes de profundizar en él, primero debe tener una tarjeta gráfica compatible.

En la actualidad, CNTK admite la tarjeta gráfica NVIDIA con al menos soporte CUDA 3.0. Para asegurarse, puede consultar enhttps://developer.nvidia.com/cuda-gpus si su GPU es compatible con CUDA.

Entonces, veamos los pasos para habilitar GPU con CNTK en el sistema operativo Windows:

Step 1 - Dependiendo de la tarjeta gráfica que esté utilizando, primero debe tener los controladores GeForce o Quadro más recientes para su tarjeta gráfica.

Step 2 - Una vez que haya descargado los controladores, debe instalar el kit de herramientas CUDA Versión 9.0 para Windows desde el sitio web de NVIDIA https://developer.nvidia.com/cuda-90-download-archive?target_os=Windows&target_arch=x86_64. Después de la instalación, ejecute el instalador y siga las instrucciones.

Step 3 - A continuación, debe instalar los binarios cuDNN del sitio web de NVIDIA https://developer.nvidia.com/rdp/form/cudnn-download-survey. Con la versión CUDA 9.0, cuDNN 7.4.1 funciona bien. Básicamente, cuDNN es una capa en la parte superior de CUDA, utilizada por CNTK.

Step 4 - Después de descargar los archivos binarios de cuDNN, debe extraer el archivo zip en la carpeta raíz de la instalación del kit de herramientas de CUDA.

Step 5- Este es el último paso que permitirá el uso de GPU dentro de CNTK. Ejecute el siguiente comando dentro del símbolo del sistema Anaconda en el sistema operativo Windows:

pip install cntk-gpu

Habilitación de GPU con CNTK en Linux

Veamos cómo podemos habilitar la GPU con CNTK en el sistema operativo Linux:

Descarga del kit de herramientas CUDA

Primero, debe instalar el kit de herramientas CUDA desde el sitio web de NVIDIA https://developer.nvidia.com/cuda-90-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type = runfilelocal .

Ejecutando el instalador

Ahora, una vez que tenga los binarios en el disco, ejecute el instalador abriendo una terminal y ejecutando el siguiente comando y la instrucción en la pantalla:

sh cuda_9.0.176_384.81_linux-run

Modificar la secuencia de comandos del perfil de Bash

Después de instalar el kit de herramientas CUDA en su máquina Linux, debe modificar el script del perfil BASH. Para esto, primero abra el archivo $ HOME / .bashrc en el editor de texto. Ahora, al final del guión, incluya las siguientes líneas:

export PATH=/usr/local/cuda-9.0/bin${PATH:+:${PATH}} export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64\ ${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
Installing

Instalación de bibliotecas cuDNN

Por fin necesitamos instalar los binarios cuDNN. Se puede descargar del sitio web de NVIDIA.https://developer.nvidia.com/rdp/form/cudnn-download-survey. Con la versión CUDA 9.0, cuDNN 7.4.1 funciona bien. Básicamente, cuDNN es una capa en la parte superior de CUDA, utilizada por CNTK.

Una vez descargada la versión para Linux, extráigala al /usr/local/cuda-9.0 carpeta usando el siguiente comando -

tar xvzf -C /usr/local/cuda-9.0/ cudnn-9.0-linux-x64-v7.4.1.5.tgz

Cambie la ruta al nombre del archivo según sea necesario.

En este capítulo, aprenderemos en detalle sobre las secuencias en CNTK y su clasificación.

Tensores

El concepto sobre el que trabaja CNTK es tensor. Básicamente, las entradas, salidas y parámetros de CNTK se organizan comotensors, que a menudo se considera una matriz generalizada. Cada tensor tiene unrank -

  • El tensor de rango 0 es un escalar.

  • El tensor de rango 1 es un vector.

  • El tensor del rango 2 es una matriz.

Aquí, estas diferentes dimensiones se denominan axes.

Ejes estáticos y ejes dinámicos

Como su nombre lo indica, los ejes estáticos tienen la misma longitud a lo largo de la vida de la red. Por otro lado, la longitud de los ejes dinámicos puede variar de una instancia a otra. De hecho, normalmente no se conoce su longitud antes de que se presente cada minibatch.

Los ejes dinámicos son como ejes estáticos porque también definen una agrupación significativa de los números contenidos en el tensor.

Ejemplo

Para que quede más claro, veamos cómo se representa un minibatch de videoclips cortos en CNTK. Suponga que la resolución de los clips de vídeo es de 640 * 480. Además, los clips se graban en color, que normalmente se codifica con tres canales. Además, significa que nuestro minibatch tiene lo siguiente:

  • 3 ejes estáticos de longitud 640, 480 y 3 respectivamente.

  • Dos ejes dinámicos; la duración del video y los ejes del minibatch.

Significa que si un minibatch tiene 16 videos, cada uno de los cuales tiene 240 cuadros de longitud, se representaría como 16*240*3*640*480 tensores.

Trabajar con secuencias en CNTK

Entendamos las secuencias en CNTK aprendiendo primero sobre la Red de memoria a corto y largo plazo.

Red de memoria a largo plazo (LSTM)

Las redes de memoria a largo plazo a corto plazo (LSTM) fueron introducidas por Hochreiter & Schmidhuber. Resolvió el problema de conseguir una capa recurrente básica para recordar cosas durante mucho tiempo. La arquitectura de LSTM se muestra arriba en el diagrama. Como podemos ver, tiene neuronas de entrada, células de memoria y neuronas de salida. Para combatir el problema del gradiente de desaparición, las redes de memoria a corto y largo plazo utilizan una celda de memoria explícita (almacena los valores anteriores) y las siguientes puertas:

  • Forget gate- Como su nombre lo indica, le dice a la celda de memoria que olvide los valores anteriores. La celda de memoria almacena los valores hasta que la puerta, es decir, "puerta olvidada", le dice que los olvide.

  • Input gate - Como su nombre lo indica, agrega cosas nuevas a la celda.

  • Output gate - Como su nombre lo indica, la puerta de salida decide cuándo pasar los vectores de la celda al siguiente estado oculto.

Es muy fácil trabajar con secuencias en CNTK. Veámoslo con la ayuda del siguiente ejemplo:

import sys
import os
from cntk import Trainer, Axis
from cntk.io import MinibatchSource, CTFDeserializer, StreamDef, StreamDefs,\
   INFINITELY_REPEAT
from cntk.learners import sgd, learning_parameter_schedule_per_sample
from cntk import input_variable, cross_entropy_with_softmax, \
   classification_error, sequence
from cntk.logging import ProgressPrinter
from cntk.layers import Sequential, Embedding, Recurrence, LSTM, Dense
def create_reader(path, is_training, input_dim, label_dim):
   return MinibatchSource(CTFDeserializer(path, StreamDefs(
      features=StreamDef(field='x', shape=input_dim, is_sparse=True),
      labels=StreamDef(field='y', shape=label_dim, is_sparse=False)
   )), randomize=is_training,
   max_sweeps=INFINITELY_REPEAT if is_training else 1)
def LSTM_sequence_classifier_net(input, num_output_classes, embedding_dim,
LSTM_dim, cell_dim):
   lstm_classifier = Sequential([Embedding(embedding_dim),
      Recurrence(LSTM(LSTM_dim, cell_dim)),
      sequence.last,
      Dense(num_output_classes)])
return lstm_classifier(input)
def train_sequence_classifier():
   input_dim = 2000
   cell_dim = 25
   hidden_dim = 25
   embedding_dim = 50
   num_output_classes = 5
   features = sequence.input_variable(shape=input_dim, is_sparse=True)
   label = input_variable(num_output_classes)
   classifier_output = LSTM_sequence_classifier_net(
   features, num_output_classes, embedding_dim, hidden_dim, cell_dim)
   ce = cross_entropy_with_softmax(classifier_output, label)
   pe =      classification_error(classifier_output, label)
   rel_path = ("../../../Tests/EndToEndTests/Text/" +
      "SequenceClassification/Data/Train.ctf")
   path = os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)
   reader = create_reader(path, True, input_dim, num_output_classes)
input_map = {
   features: reader.streams.features,
   label: reader.streams.labels
}
lr_per_sample = learning_parameter_schedule_per_sample(0.0005)
progress_printer = ProgressPrinter(0)
trainer = Trainer(classifier_output, (ce, pe),
sgd(classifier_output.parameters, lr=lr_per_sample),progress_printer)
minibatch_size = 200
for i in range(255):
   mb = reader.next_minibatch(minibatch_size, input_map=input_map)
trainer.train_minibatch(mb)
   evaluation_average = float(trainer.previous_minibatch_evaluation_average)
   loss_average = float(trainer.previous_minibatch_loss_average)
return evaluation_average, loss_average
if __name__ == '__main__':
   error, _ = train_sequence_classifier()
   print(" error: %f" % error)
average  since  average  since  examples
loss     last   metric   last
------------------------------------------------------
1.61    1.61    0.886     0.886     44
1.61     1.6    0.714     0.629    133
 1.6    1.59     0.56     0.448    316
1.57    1.55    0.479      0.41    682
1.53     1.5    0.464     0.449   1379
1.46     1.4    0.453     0.441   2813
1.37    1.28     0.45     0.447   5679
 1.3    1.23    0.448     0.447  11365

error: 0.333333

La explicación detallada del programa anterior se cubrirá en las próximas secciones, especialmente cuando construiremos redes neuronales recurrentes.

Este capítulo trata sobre la construcción de un modelo de regresión logística en CNTK.

Conceptos básicos del modelo de regresión logística

La regresión logística, una de las técnicas de AA más simples, es una técnica especialmente para la clasificación binaria. En otras palabras, crear un modelo de predicción en situaciones en las que el valor de la variable a predecir puede ser uno de solo dos valores categóricos. Uno de los ejemplos más simples de regresión logística es predecir si la persona es hombre o mujer, según la edad, la voz, los cabellos, etc. de la persona.

Ejemplo

Entendamos matemáticamente el concepto de regresión logística con la ayuda de otro ejemplo:

Supongamos que queremos predecir la solvencia crediticia de una solicitud de préstamo; 0 significa rechazar y 1 significa aprobar, según el solicitantedebt , income y credit rating. Representamos deuda con X1, ingresos con X2 y calificación crediticia con X3.

En Regresión logística, determinamos un valor de peso, representado por w, para cada característica y un solo valor de sesgo, representado por b.

Ahora suponga,

X1 = 3.0
X2 = -2.0
X3 = 1.0

Y supongamos que determinamos el peso y el sesgo de la siguiente manera:

W1 = 0.65, W2 = 1.75, W3 = 2.05 and b = 0.33

Ahora, para predecir la clase, necesitamos aplicar la siguiente fórmula:

Z = (X1*W1)+(X2*W2)+(X3+W3)+b
i.e. Z = (3.0)*(0.65) + (-2.0)*(1.75) + (1.0)*(2.05) + 0.33
= 0.83

A continuación, necesitamos calcular P = 1.0/(1.0 + exp(-Z)). Aquí, la función exp () es el número de Euler.

P = 1.0/(1.0 + exp(-0.83)
= 0.6963

El valor de P se puede interpretar como la probabilidad de que la clase sea 1. Si P <0,5, la predicción es clase = 0; de lo contrario, la predicción (P> = 0,5) es clase = 1.

Para determinar los valores de peso y sesgo, debemos obtener un conjunto de datos de entrenamiento que tengan los valores predictores de entrada conocidos y los valores de etiquetas de clase correctos conocidos. Después de eso, podemos usar un algoritmo, generalmente Gradient Descent, para encontrar los valores de peso y sesgo.

Ejemplo de implementación del modelo LR

Para este modelo LR, usaremos el siguiente conjunto de datos:

1.0, 2.0, 0
3.0, 4.0, 0
5.0, 2.0, 0
6.0, 3.0, 0
8.0, 1.0, 0
9.0, 2.0, 0
1.0, 4.0, 1
2.0, 5.0, 1
4.0, 6.0, 1
6.0, 5.0, 1
7.0, 3.0, 1
8.0, 5.0, 1

Para iniciar la implementación de este modelo LR en CNTK, primero debemos importar los siguientes paquetes:

import numpy as np
import cntk as C

El programa está estructurado con la función main () de la siguiente manera:

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")

Ahora, necesitamos cargar los datos de entrenamiento en la memoria de la siguiente manera:

data_file = ".\\dataLRmodel.txt"
print("Loading data from " + data_file + "\n")
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[0,1])
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[2], ndmin=2)

Ahora, crearemos un programa de entrenamiento que crea un modelo de regresión logística que es compatible con los datos de entrenamiento:

features_dim = 2
labels_dim = 1
X = C.ops.input_variable(features_dim, np.float32)
y = C.input_variable(labels_dim, np.float32)
W = C.parameter(shape=(features_dim, 1)) # trainable cntk.Parameter
b = C.parameter(shape=(labels_dim))
z = C.times(X, W) + b
p = 1.0 / (1.0 + C.exp(-z))
model = p

Ahora, necesitamos crear Lerner y entrenador de la siguiente manera:

ce_error = C.binary_cross_entropy(model, y) # CE a bit more principled for LR
fixed_lr = 0.010
learner = C.sgd(model.parameters, fixed_lr)
trainer = C.Trainer(model, (ce_error), [learner])
max_iterations = 4000

Entrenamiento del modelo LR

Una vez que hemos creado el modelo LR, a continuación, es el momento de iniciar el proceso de formación:

np.random.seed(4)
N = len(features_mat)
for i in range(0, max_iterations):
row = np.random.choice(N,1) # pick a random row from training items
trainer.train_minibatch({ X: features_mat[row], y: labels_mat[row] })
if i % 1000 == 0 and i > 0:
mcee = trainer.previous_minibatch_loss_average
print(str(i) + " Cross-entropy error on curr item = %0.4f " % mcee)

Ahora, con la ayuda del siguiente código, podemos imprimir los pesos y el sesgo del modelo:

np.set_printoptions(precision=4, suppress=True)
print("Model weights: ")
print(W.value)
print("Model bias:")
print(b.value)
print("")
if __name__ == "__main__":
main()

Entrenamiento de un modelo de regresión logística: ejemplo completo

import numpy as np
import cntk as C
   def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
print("Loading data from " + data_file + "\n")
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[0,1])
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[2], ndmin=2)
features_dim = 2
labels_dim = 1
X = C.ops.input_variable(features_dim, np.float32)
y = C.input_variable(labels_dim, np.float32)
W = C.parameter(shape=(features_dim, 1)) # trainable cntk.Parameter
b = C.parameter(shape=(labels_dim))
z = C.times(X, W) + b
p = 1.0 / (1.0 + C.exp(-z))
model = p
ce_error = C.binary_cross_entropy(model, y) # CE a bit more principled for LR
fixed_lr = 0.010
learner = C.sgd(model.parameters, fixed_lr)
trainer = C.Trainer(model, (ce_error), [learner])
max_iterations = 4000
np.random.seed(4)
N = len(features_mat)
for i in range(0, max_iterations):
row = np.random.choice(N,1) # pick a random row from training items
trainer.train_minibatch({ X: features_mat[row], y: labels_mat[row] })
if i % 1000 == 0 and i > 0:
mcee = trainer.previous_minibatch_loss_average
print(str(i) + " Cross-entropy error on curr item = %0.4f " % mcee)
np.set_printoptions(precision=4, suppress=True)
print("Model weights: ")
print(W.value)
print("Model bias:")
print(b.value)
if __name__ == "__main__":
  main()

Salida

Using CNTK version = 2.7
1000 cross entropy error on curr item = 0.1941
2000 cross entropy error on curr item = 0.1746
3000 cross entropy error on curr item = 0.0563
Model weights:
[-0.2049]
   [0.9666]]
Model bias:
[-2.2846]

Predicción usando modelo LR entrenado

Una vez que se ha entrenado el modelo LR, podemos usarlo para la predicción de la siguiente manera:

En primer lugar, nuestro programa de evaluación importa el paquete numpy y carga los datos de entrenamiento en una matriz de características y una matriz de etiqueta de clase de la misma manera que el programa de entrenamiento que implementamos anteriormente:

import numpy as np
def main():
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=(0,1))
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=[2], ndmin=2)

A continuación, es hora de establecer los valores de los pesos y el sesgo que fueron determinados por nuestro programa de entrenamiento:

print("Setting weights and bias values \n")
weights = np.array([0.0925, 1.1722], dtype=np.float32)
bias = np.array([-4.5400], dtype=np.float32)
N = len(features_mat)
features_dim = 2

A continuación, nuestro programa de evaluación calculará la probabilidad de regresión logística recorriendo cada elemento de entrenamiento de la siguiente manera:

print("item pred_prob pred_label act_label result")
for i in range(0, N): # each item
   x = features_mat[i]
   z = 0.0
   for j in range(0, features_dim):
   z += x[j] * weights[j]
   z += bias[0]
   pred_prob = 1.0 / (1.0 + np.exp(-z))
  pred_label = 0 if pred_prob < 0.5 else 1
   act_label = labels_mat[i]
   pred_str = ‘correct’ if np.absolute(pred_label - act_label) < 1.0e-5 \
    else ‘WRONG’
  print("%2d %0.4f %0.0f %0.0f %s" % \ (i, pred_prob, pred_label, act_label, pred_str))

Ahora demostremos cómo hacer predicciones:

x = np.array([9.5, 4.5], dtype=np.float32)
print("\nPredicting class for age, education = ")
print(x)
z = 0.0
for j in range(0, features_dim):
z += x[j] * weights[j]
z += bias[0]
p = 1.0 / (1.0 + np.exp(-z))
print("Predicted p = " + str(p))
if p < 0.5: print("Predicted class = 0")
else: print("Predicted class = 1")

Programa completo de evaluación de predicciones

import numpy as np
def main():
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=(0,1))
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=[2], ndmin=2)
print("Setting weights and bias values \n")
weights = np.array([0.0925, 1.1722], dtype=np.float32)
bias = np.array([-4.5400], dtype=np.float32)
N = len(features_mat)
features_dim = 2
print("item pred_prob pred_label act_label result")
for i in range(0, N): # each item
   x = features_mat[i]
   z = 0.0
   for j in range(0, features_dim):
     z += x[j] * weights[j]
   z += bias[0]
   pred_prob = 1.0 / (1.0 + np.exp(-z))
   pred_label = 0 if pred_prob < 0.5 else 1
   act_label = labels_mat[i]
   pred_str = ‘correct’ if np.absolute(pred_label - act_label) < 1.0e-5 \
     else ‘WRONG’
  print("%2d %0.4f %0.0f %0.0f %s" % \ (i, pred_prob, pred_label, act_label, pred_str))
x = np.array([9.5, 4.5], dtype=np.float32)
print("\nPredicting class for age, education = ")
print(x)
z = 0.0
for j in range(0, features_dim):
   z += x[j] * weights[j]
z += bias[0]
p = 1.0 / (1.0 + np.exp(-z))
print("Predicted p = " + str(p))
if p < 0.5: print("Predicted class = 0")
else: print("Predicted class = 1")
if __name__ == "__main__":
  main()

Salida

Establecimiento de pesos y valores de sesgo.

Item  pred_prob  pred_label  act_label  result
0   0.3640         0             0     correct
1   0.7254         1             0      WRONG
2   0.2019         0             0     correct
3   0.3562         0             0     correct
4   0.0493         0             0     correct
5   0.1005         0             0     correct
6   0.7892         1             1     correct
7   0.8564         1             1     correct
8   0.9654         1             1     correct
9   0.7587         1             1     correct
10  0.3040         0             1      WRONG
11  0.7129         1             1     correct
Predicting class for age, education =
[9.5 4.5]
Predicting p = 0.526487952
Predicting class = 1

Este capítulo trata sobre conceptos de red neuronal con respecto a CNTK.

Como sabemos, se utilizan varias capas de neuronas para crear una red neuronal. Pero, surge la pregunta de que en CNTK ¿cómo podemos modelar las capas de una NN? Se puede hacer con la ayuda de las funciones de capa definidas en el módulo de capa.

Función de capa

En realidad, en CNTK, trabajar con las capas tiene una sensación de programación funcional distinta. La función de capa parece una función normal y produce una función matemática con un conjunto de parámetros predefinidos. Veamos cómo podemos crear el tipo de capa más básico, Denso, con la ayuda de la función de capa.

Ejemplo

Con la ayuda de seguir los pasos básicos, podemos crear el tipo de capa más básico:

Step 1 - Primero, necesitamos importar la función de capa Densa del paquete de capas de CNTK.

from cntk.layers import Dense

Step 2 - Luego del paquete raíz CNTK, necesitamos importar la función input_variable.

from cntk import input_variable

Step 3- Ahora, necesitamos crear una nueva variable de entrada usando la función input_variable. También necesitamos proporcionar su tamaño.

feature = input_variable(100)

Step 4 - Por fin, crearemos una nueva capa usando la función Densa además de proporcionar la cantidad de neuronas que queramos.

layer = Dense(40)(feature)

Ahora, podemos invocar la función de capa densa configurada para conectar la capa densa a la entrada.

Ejemplo de implementación completo

from cntk.layers import Dense
from cntk import input_variable
feature= input_variable(100)
layer = Dense(40)(feature)

Personalizar capas

Como hemos visto, CNTK nos proporciona un conjunto bastante bueno de valores predeterminados para construir NN. Residencia enactivationfunción y otras configuraciones que elijamos, el comportamiento y el rendimiento de la NN es diferente. Es otro algoritmo de derivación muy útil. Esa es la razón, es bueno entender qué podemos configurar.

Pasos para configurar una capa densa

Cada capa en NN tiene sus opciones de configuración únicas y cuando hablamos de capa Densa, tenemos las siguientes configuraciones importantes para definir:

  • shape - Como su nombre lo indica, define la forma de salida de la capa que determina además el número de neuronas en esa capa.

  • activation - Define la función de activación de esa capa, por lo que puede transformar los datos de entrada.

  • init- Define la función de inicialización de esa capa. Inicializará los parámetros de la capa cuando comencemos a entrenar el NN.

Veamos los pasos con la ayuda de los cuales podemos configurar un Dense capa -

Step1 - Primero, necesitamos importar el Dense función de capa del paquete de capas de CNTK.

from cntk.layers import Dense

Step2 - A continuación del paquete de operaciones de CNTK, necesitamos importar el sigmoid operator. Se utilizará para configurar como función de activación.

from cntk.ops import sigmoid

Step3 - Ahora, desde el paquete inicializador, necesitamos importar el glorot_uniform inicializador.

from cntk.initializer import glorot_uniform

Step4 - Por fin, crearemos una nueva capa usando la función Densa además de proporcionar el número de neuronas como primer argumento. Además, proporcionesigmoid operador como activation función y la glorot_uniform como el init función para la capa.

layer = Dense(50, activation = sigmoid, init = glorot_uniform)

Ejemplo de implementación completo -

from cntk.layers import Dense
from cntk.ops import sigmoid
from cntk.initializer import glorot_uniform
layer = Dense(50, activation = sigmoid, init = glorot_uniform)

Optimizando los parámetros

Hasta ahora, hemos visto cómo crear la estructura de una NN y cómo configurar varios ajustes. Aquí, veremos, cómo podemos optimizar los parámetros de una NN. Con la ayuda de la combinación de dos componentes a saberlearners y trainers, podemos optimizar los parámetros de una NN.

componente de entrenador

El primer componente que se utiliza para optimizar los parámetros de un NN es trainercomponente. Básicamente implementa el proceso de retropropagación. Si hablamos de su funcionamiento, pasa los datos por la NN para obtener una predicción.

Después de eso, usa otro componente llamado aprendiz para obtener los nuevos valores para los parámetros en un NN. Una vez que obtiene los nuevos valores, aplica estos nuevos valores y repite el proceso hasta que se cumpla un criterio de salida.

componente de aprendizaje

El segundo componente que se utiliza para optimizar los parámetros de un NN es learner componente, que es básicamente responsable de realizar el algoritmo de descenso de gradiente.

Estudiantes incluidos en la biblioteca CNTK

A continuación se muestra la lista de algunos de los estudiantes interesantes incluidos en la biblioteca CNTK:

  • Stochastic Gradient Descent (SGD) - Este alumno representa el descenso de gradiente estocástico básico, sin extras.

  • Momentum Stochastic Gradient Descent (MomentumSGD) - Con SGD, este alumno aplica el impulso para superar el problema de los máximos locales.

  • RMSProp - Este alumno, para controlar la tasa de descenso, utiliza tasas de aprendizaje decrecientes.

  • Adam - Este alumno, con el fin de disminuir la tasa de descenso con el tiempo, utiliza el impulso decreciente.

  • Adagrad - Este alumno, tanto para las funciones que ocurren con frecuencia como para las que ocurren con poca frecuencia, utiliza diferentes tasas de aprendizaje.

CNTK - Creación de la primera red neuronal

Este capítulo desarrollará la creación de una red neuronal en CNTK.

Construye la estructura de la red

Con el fin de aplicar los conceptos de CNTK para construir nuestro primer NN, vamos a usar NN para clasificar las especies de flores de iris en función de las propiedades físicas del ancho y largo del sépalo, y del ancho y largo del pétalo. El conjunto de datos que utilizaremos el conjunto de datos de iris que describe las propiedades físicas de diferentes variedades de flores de iris:

  • Longitud del sépalo
  • Ancho del sépalo
  • Longitud del pétalo
  • Ancho del pétalo
  • Clase ie iris setosa o iris versicolor o iris virginica

Aquí, crearemos una NN regular llamada NN de avance. Veamos los pasos de implementación para construir la estructura de NN -

Step 1 - Primero, importaremos los componentes necesarios como nuestros tipos de capa, funciones de activación y una función que nos permita definir una variable de entrada para nuestro NN, desde la biblioteca CNTK.

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu

Step 2- Después de eso, crearemos nuestro modelo usando la función secuencial. Una vez creado, lo alimentaremos con las capas que queramos. Aquí, vamos a crear dos capas distintas en nuestro NN; uno con cuatro neuronas y otro con tres neuronas.

model = Sequential([Dense(4, activation=relu), Dense(3, activation=log_sogtmax)])

Step 3- Por último, para compilar el NN, vincularemos la red a la variable de entrada. Tiene una capa de entrada con cuatro neuronas y una capa de salida con tres neuronas.

feature= input_variable(4)
z = model(feature)

Aplicar una función de activación

Hay muchas funciones de activación para elegir y elegir la función de activación correcta definitivamente marcará una gran diferencia en el rendimiento de nuestro modelo de aprendizaje profundo.

En la capa de salida

Elegir un activation La función en la capa de salida dependerá del tipo de problema que vamos a resolver con nuestro modelo.

  • Para un problema de regresión, deberíamos usar un linear activation function en la capa de salida.

  • Para un problema de clasificación binaria, deberíamos usar un sigmoid activation function en la capa de salida.

  • Para problemas de clasificación de clases múltiples, deberíamos usar un softmax activation function en la capa de salida.

  • Aquí, vamos a construir un modelo para predecir una de las tres clases. Significa que necesitamos usarsoftmax activation function en la capa de salida.

En la capa oculta

Elegir un activation La función en la capa oculta requiere algo de experimentación para monitorear el rendimiento y ver qué función de activación funciona bien.

  • En un problema de clasificación, necesitamos predecir la probabilidad de que una muestra pertenezca a una clase específica. Por eso necesitamos unactivation functioneso nos da valores probabilísticos. Para alcanzar este objetivo,sigmoid activation function puede ayudarnos.

  • Uno de los principales problemas asociados con la función sigmoidea es el problema del gradiente de desaparición. Para superar ese problema, podemos utilizarReLU activation function que convierte todos los valores negativos a cero y funciona como un filtro de paso para valores positivos.

Elegir una función de pérdida

Una vez que tenemos la estructura para nuestro modelo NN, debemos optimizarlo. Para optimizar necesitamos unloss function. diferente aactivation functions, tenemos menos funciones de pérdida para elegir. Sin embargo, la elección de una función de pérdida dependerá del tipo de problema que vamos a resolver con nuestro modelo.

Por ejemplo, en un problema de clasificación, deberíamos usar una función de pérdida que pueda medir la diferencia entre una clase predicha y una clase real.

función de pérdida

Para el problema de clasificación, vamos a resolver con nuestro modelo NN, categorical cross entropyLa función de pérdida es la mejor candidata. En CNTK, se implementa comocross_entropy_with_softmax que se puede importar desde cntk.losses paquete, de la siguiente manera

label= input_variable(3)
loss = cross_entropy_with_softmax(z, label)

Métrica

Con tener la estructura para nuestro modelo NN y una función de pérdida para aplicar, tenemos todos los ingredientes para comenzar a hacer la receta para optimizar nuestro modelo de aprendizaje profundo. Pero, antes de profundizar en esto, deberíamos aprender sobre las métricas.

cntk.metrics

CNTK tiene el paquete llamado cntk.metricsdesde donde podemos importar las métricas que vamos a utilizar. Mientras construimos un modelo de clasificación, usaremosclassification_error matriz que producirá un número entre 0 y 1. El número entre 0 y 1 indica el porcentaje de muestras predichas correctamente -

Primero, necesitamos importar la métrica de cntk.metrics paquete -

from cntk.metrics import classification_error
error_rate = classification_error(z, label)

La función anterior realmente necesita la salida del NN y la etiqueta esperada como entrada.

CNTK: entrenamiento de la red neuronal

Aquí, entenderemos cómo entrenar la red neuronal en CNTK.

Entrenando un modelo en CNTK

En la sección anterior, definimos todos los componentes del modelo de aprendizaje profundo. Ahora es el momento de entrenarlo. Como comentamos anteriormente, podemos entrenar un modelo NN en CNTK usando la combinación delearner y trainer.

Elegir un alumno y organizar la formación

En esta sección, definiremos el learner. CNTK ofrece varioslearnersPara escoger de. Para nuestro modelo, definido en secciones anteriores, usaremosStochastic Gradient Descent (SGD) learner.

Para entrenar la red neuronal, configuremos el learner y trainer con la ayuda de los siguientes pasos:

Step 1 - Primero, necesitamos importar sgd función de cntk.lerners paquete.

from cntk.learners import sgd

Step 2 - A continuación, necesitamos importar Trainer función de cntk.trainpaquete de entrenador.

from cntk.train.trainer import Trainer

Step 3 - Ahora, necesitamos crear un learner. Se puede crear invocandosgd función junto con proporcionar los parámetros del modelo y un valor para la tasa de aprendizaje.

learner = sgd(z.parametrs, 0.01)

Step 4 - Por fin, necesitamos inicializar el trainer. Debe proporcionarse la red, la combinación de losloss y metric junto con learner.

trainer = Trainer(z, (loss, error_rate), [learner])

La tasa de aprendizaje que controla la velocidad de optimización debe ser un número pequeño entre 0,1 y 0,001.

Elegir un alumno y configurar la formación: ejemplo completo

from cntk.learners import sgd
from cntk.train.trainer import Trainer
learner = sgd(z.parametrs, 0.01)
trainer = Trainer(z, (loss, error_rate), [learner])

Alimentando datos al entrenador

Una vez que elegimos y configuramos el entrenador, es hora de cargar el conjunto de datos. Hemos salvado eliris conjunto de datos como.CSV archivo y usaremos el paquete de lucha de datos llamado pandas para cargar el conjunto de datos.

Pasos para cargar el conjunto de datos desde el archivo .CSV

Step 1 - Primero, necesitamos importar el pandas paquete.

from import pandas as pd

Step 2 - Ahora, necesitamos invocar la función llamada read_csv función para cargar el archivo .csv desde el disco.

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, 
‘petal_length’, ‘petal_width’, index_col=False)

Una vez que cargamos el conjunto de datos, debemos dividirlo en un conjunto de características y una etiqueta.

Pasos para dividir el conjunto de datos en características y etiquetas

Step 1- Primero, debemos seleccionar todas las filas y las primeras cuatro columnas del conjunto de datos. Se puede hacer usandoiloc función.

x = df_source.iloc[:, :4].values

Step 2- A continuación, debemos seleccionar la columna de especies del conjunto de datos de iris. Usaremos la propiedad de valores para acceder al subyacentenumpy formación.

x = df_source[‘species’].values

Pasos para codificar la columna de especies en una representación vectorial numérica

Como discutimos anteriormente, nuestro modelo se basa en la clasificación, requiere valores de entrada numéricos. Por lo tanto, aquí necesitamos codificar la columna de especies en una representación vectorial numérica. Veamos los pasos para hacerlo -

Step 1- Primero, necesitamos crear una expresión de lista para iterar sobre todos los elementos de la matriz. Luego, busque en el diccionario label_mapping para cada valor.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 2- A continuación, convierta este valor numérico convertido en un vector codificado en caliente. Nosotros usaremosone_hot funciona de la siguiente manera:

def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result

Step 3 - Por fin, necesitamos convertir esta lista convertida en una numpy formación.

y = np.array([one_hot(label_mapping[v], 3) for v in y])

Pasos para detectar el sobreajuste

La situación, cuando su modelo recuerda muestras pero no puede deducir reglas de las muestras de entrenamiento, es sobreajuste. Con la ayuda de los siguientes pasos, podemos detectar el sobreajuste en nuestro modelo:

Step 1 - Primero, desde sklearn paquete, importa el train_test_split función de la model_selection módulo.

from sklearn.model_selection import train_test_split

Step 2 - A continuación, necesitamos invocar la función train_test_split con las características xy las etiquetas y de la siguiente manera -

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0-2, 
stratify=y)

Especificamos un test_size de 0.2 para reservar el 20% de los datos totales.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Pasos para alimentar el conjunto de entrenamiento y el conjunto de validación a nuestro modelo

Step 1 - Para entrenar nuestro modelo, primero, invocaremos el train_minibatchmétodo. Luego, dele un diccionario que asigne los datos de entrada a la variable de entrada que hemos utilizado para definir el NN y su función de pérdida asociada.

trainer.train_minibatch({ features: X_train, label: y_train})

Step 2 - Siguiente, llame train_minibatch usando el siguiente bucle for -

for _epoch in range(10):
trainer.train_minbatch ({ feature: X_train, label: y_train})
print(‘Loss: {}, Acc: {}’.format(
trainer.previous_minibatch_loss_average,
trainer.previous_minibatch_evaluation_average))

Introducir datos en el entrenador: ejemplo completo

from import pandas as pd
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, index_col=False)
x = df_source.iloc[:, :4].values
x = df_source[‘species’].values
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result
y = np.array([one_hot(label_mapping[v], 3) for v in y])
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0-2, stratify=y)
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
trainer.train_minibatch({ features: X_train, label: y_train})
for _epoch in range(10):
trainer.train_minbatch ({ feature: X_train, label: y_train})
print(‘Loss: {}, Acc: {}’.format(
trainer.previous_minibatch_loss_average,
trainer.previous_minibatch_evaluation_average))

Midiendo el desempeño de NN

Con el fin de optimizar nuestro modelo NN, cada vez que pasamos datos a través del entrenador, mide el rendimiento del modelo a través de la métrica que configuramos para el entrenador. Tal medición del rendimiento del modelo NN durante el entrenamiento se basa en los datos de entrenamiento. Pero, por otro lado, para un análisis completo del rendimiento del modelo, también necesitamos usar datos de prueba.

Entonces, para medir el desempeño del modelo usando los datos de prueba, podemos invocar el test_minibatch método en el trainer como sigue -

trainer.test_minibatch({ features: X_test, label: y_test})

Haciendo predicciones con NN

Una vez que entrenó un modelo de aprendizaje profundo, lo más importante es hacer predicciones usando eso. Para hacer una predicción a partir del NN entrenado anteriormente, podemos seguir los pasos dados:

Step 1 - Primero, necesitamos elegir un elemento aleatorio del conjunto de prueba usando la siguiente función -

np.random.choice

Step 2 - A continuación, debemos seleccionar los datos de muestra del conjunto de prueba utilizando sample_index.

Step 3 - Ahora, para convertir la salida numérica a la NN en una etiqueta real, cree un mapeo invertido.

Step 4 - Ahora, use el seleccionado sampledatos. Haga una predicción invocando NN z como función.

Step 5- Ahora, una vez que obtenga la salida prevista, tome el índice de la neurona que tiene el valor más alto como valor predicho. Se puede hacer usando elnp.argmax función de la numpy paquete.

Step 6 - Por último, convierta el valor del índice en la etiqueta real usando inverted_mapping.

Hacer predicciones con NN - Ejemplo completo

sample_index = np.random.choice(X_test.shape[0])
sample = X_test[sample_index]
inverted_mapping = {
   1:’Iris-setosa’,
   2:’Iris-versicolor’,
   3:’Iris-virginica’
}
prediction = z(sample)
predicted_label = inverted_mapping[np.argmax(prediction)]
print(predicted_label)

Salida

Después de entrenar el modelo de aprendizaje profundo anterior y ejecutarlo, obtendrá el siguiente resultado:

Iris-versicolor

CNTK - Grandes conjuntos de datos y en memoria

En este capítulo, aprenderemos cómo trabajar con conjuntos de datos grandes y en memoria en CNTK.

Entrenamiento con pequeños conjuntos de datos en memoria

Cuando hablamos de introducir datos en el entrenador CNTK, puede haber muchas formas, pero dependerá del tamaño del conjunto de datos y del formato de los datos. Los conjuntos de datos pueden ser pequeños en memoria o grandes conjuntos de datos.

En esta sección, trabajaremos con conjuntos de datos en memoria. Para ello, utilizaremos los siguientes dos marcos:

  • Numpy
  • Pandas

Usando matrices Numpy

Aquí, trabajaremos con un conjunto de datos generado aleatoriamente en CNTK. En este ejemplo, vamos a simular datos para un problema de clasificación binaria. Supongamos que tenemos un conjunto de observaciones con 4 características y queremos predecir dos posibles etiquetas con nuestro modelo de aprendizaje profundo.

Ejemplo de implementación

Para esto, primero debemos generar un conjunto de etiquetas que contengan una representación de un vector caliente de las etiquetas que queremos predecir. Se puede hacer con la ayuda de los siguientes pasos:

Step 1 - Importar el numpy paquete de la siguiente manera:

import numpy as np
num_samples = 20000

Step 2 - Luego, genere un mapeo de etiquetas usando np.eye funciona de la siguiente manera:

label_mapping = np.eye(2)

Step 3 - Ahora usando np.random.choice función, recopile las 20000 muestras aleatorias de la siguiente manera:

y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)

Step 4 - Ahora, por fin, utilizando la función np.random.random, genere una matriz de valores de punto flotante aleatorios de la siguiente manera:

x = np.random.random(size=(num_samples, 4)).astype(np.float32)

Una vez que generamos una matriz de valores aleatorios de punto flotante, necesitamos convertirlos a números de punto flotante de 32 bits para que puedan coincidir con el formato esperado por CNTK. Sigamos los pasos a continuación para hacer esto:

Step 5 - Importe las funciones de capa densa y secuencial del módulo cntk.layers de la siguiente manera -

from cntk.layers import Dense, Sequential

Step 6- Ahora, necesitamos importar la función de activación para las capas en la red. Vamos a importar elsigmoid como función de activación -

from cntk import input_variable, default_options
from cntk.ops import sigmoid

Step 7- Ahora, necesitamos importar la función de pérdida para entrenar la red. Vamos a importarbinary_cross_entropy como función de pérdida -

from cntk.losses import binary_cross_entropy

Step 8- A continuación, necesitamos definir las opciones predeterminadas para la red. Aquí, proporcionaremos elsigmoidfunción de activación como configuración predeterminada. Además, cree el modelo utilizando la función de capa secuencial de la siguiente manera:

with default_options(activation=sigmoid):
model = Sequential([Dense(6),Dense(2)])

Step 9 - A continuación, inicialice un input_variable con 4 funciones de entrada que sirven como entrada para la red.

features = input_variable(4)

Step 10 - Ahora, para completarlo, necesitamos conectar la variable de características a la NN.

z = model(features)

Entonces, ahora tenemos un NN, con la ayuda de los siguientes pasos, entreneémoslo usando un conjunto de datos en memoria:

Step 11 - Para entrenar este NN, primero necesitamos importar el alumno de cntk.learnersmódulo. Nosotros importaremossgd alumno de la siguiente manera:

from cntk.learners import sgd

Step 12 - Junto con esa importación el ProgressPrinter desde cntk.logging módulo también.

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

Step 13 - A continuación, defina una nueva variable de entrada para las etiquetas de la siguiente manera -

labels = input_variable(2)

Step 14 - Para entrenar el modelo NN, a continuación, necesitamos definir una pérdida usando el binary_cross_entropyfunción. Además, proporcione el modelo zy la variable de etiquetas.

loss = binary_cross_entropy(z, labels)

Step 15 - A continuación, inicialice el sgd alumno de la siguiente manera:

learner = sgd(z.parameters, lr=0.1)

Step 16- Por último, llame al método de tren en la función de pérdida. Además, proporcione los datos de entrada,sgd aprendiz y el progress_printer.−

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

Ejemplo de implementación completo

import numpy as np
num_samples = 20000
label_mapping = np.eye(2)
y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)
x = np.random.random(size=(num_samples, 4)).astype(np.float32)
from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid
from cntk.losses import binary_cross_entropy
with default_options(activation=sigmoid):
   model = Sequential([Dense(6),Dense(2)])
features = input_variable(4)
z = model(features)
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(2)
loss = binary_cross_entropy(z, labels)
learner = sgd(z.parameters, lr=0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

Salida

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average   since   average   since examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.52      1.52      0         0     32
1.51      1.51      0         0     96
1.48      1.46      0         0    224
1.45      1.42      0         0    480
1.42       1.4      0         0    992
1.41      1.39      0         0   2016
1.4       1.39      0         0   4064
1.39      1.39      0         0   8160
1.39      1.39      0         0  16352

Usando Pandas DataFrames

Las matrices Numpy son muy limitadas en lo que pueden contener y una de las formas más básicas de almacenar datos. Por ejemplo, una única matriz n-dimensional puede contener datos de un solo tipo de datos. Pero, por otro lado, para muchos casos del mundo real, necesitamos una biblioteca que pueda manejar más de un tipo de datos en un solo conjunto de datos.

Una de las bibliotecas de Python llamada Pandas facilita el trabajo con este tipo de conjuntos de datos. Introduce el concepto de DataFrame (DF) y nos permite cargar conjuntos de datos desde el disco almacenados en varios formatos como DF. Por ejemplo, podemos leer DF almacenados como CSV, JSON, Excel, etc.

Puede aprender la biblioteca Python Pandas con más detalle en https://www.tutorialspoint.com/python_pandas/index.htm.

Ejemplo de implementación

En este ejemplo, vamos a utilizar el ejemplo de clasificación de tres posibles especies de flores de iris en función de cuatro propiedades. También hemos creado este modelo de aprendizaje profundo en las secciones anteriores. El modelo es el siguiente:

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)

El modelo anterior contiene una capa oculta y una capa de salida con tres neuronas para que coincida con el número de clases que podemos predecir.

A continuación, usaremos el train método y lossfunción para entrenar la red. Para esto, primero debemos cargar y preprocesar el conjunto de datos del iris, de modo que coincida con el diseño y formato de datos esperados para el NN. Se puede hacer con la ayuda de los siguientes pasos:

Step 1 - Importar el numpy y Pandas paquete de la siguiente manera:

import numpy as np
import pandas as pd

Step 2 - A continuación, use el read_csv función para cargar el conjunto de datos en la memoria -

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’,
 ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

Step 3 - Ahora, necesitamos crear un diccionario que mapeará las etiquetas en el conjunto de datos con su representación numérica correspondiente.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 4 - Ahora, usando iloc indexador en el DataFrame, seleccione las primeras cuatro columnas de la siguiente manera:

x = df_source.iloc[:, :4].values

Step 5−A continuación, debemos seleccionar las columnas de especies como etiquetas para el conjunto de datos. Se puede hacer de la siguiente manera:

y = df_source[‘species’].values

Step 6 - Ahora, necesitamos mapear las etiquetas en el conjunto de datos, lo cual se puede hacer usando label_mapping. Además, useone_hot codificación para convertirlos en matrices de codificación one-hot.

y = np.array([one_hot(label_mapping[v], 3) for v in y])

Step 7 - A continuación, para usar las características y las etiquetas mapeadas con CNTK, necesitamos convertirlos a ambos en flotantes -

x= x.astype(np.float32)
y= y.astype(np.float32)

Como sabemos, las etiquetas se almacenan en el conjunto de datos como cadenas y CNTK no puede funcionar con estas cadenas. Esa es la razón, necesita vectores codificados one-hot que representen las etiquetas. Para esto, podemos definir una función digamosone_hot como sigue -

def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result

Ahora, tenemos la matriz numpy en el formato correcto, con la ayuda de los siguientes pasos podemos usarlos para entrenar nuestro modelo:

Step 8- Primero, necesitamos importar la función de pérdida para entrenar la red. Vamos a importarbinary_cross_entropy_with_softmax como función de pérdida -

from cntk.losses import binary_cross_entropy_with_softmax

Step 9 - Para entrenar a este NN, también necesitamos importar el alumno de cntk.learnersmódulo. Nosotros importaremossgd alumno de la siguiente manera:

from cntk.learners import sgd

Step 10 - Junto con esa importación el ProgressPrinter desde cntk.logging módulo también.

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

Step 11 - A continuación, defina una nueva variable de entrada para las etiquetas de la siguiente manera -

labels = input_variable(3)

Step 12 - Para entrenar el modelo NN, a continuación, necesitamos definir una pérdida usando el binary_cross_entropy_with_softmaxfunción. También proporcione el modelo zy la variable de etiquetas.

loss = binary_cross_entropy_with_softmax (z, labels)

Step 13 - A continuación, inicialice el sgd alumno de la siguiente manera:

learner = sgd(z.parameters, 0.1)

Step 14- Por último, llame al método de tren en la función de pérdida. Además, proporcione los datos de entrada,sgd aprendiz y el progress_printer.

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=
[progress_writer],minibatch_size=16,max_epochs=5)

Ejemplo de implementación completo

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)
import numpy as np
import pandas as pd
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
x = df_source.iloc[:, :4].values
y = df_source[‘species’].values
y = np.array([one_hot(label_mapping[v], 3) for v in y])
x= x.astype(np.float32)
y= y.astype(np.float32)
def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result
from cntk.losses import binary_cross_entropy_with_softmax
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(3)
loss = binary_cross_entropy_with_softmax (z, labels)
learner = sgd(z.parameters, 0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer],minibatch_size=16,max_epochs=5)

Salida

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average    since    average   since   examples
loss        last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.1         1.1        0       0      16
0.835     0.704        0       0      32
1.993      1.11        0       0      48
1.14       1.14        0       0     112
[………]

Entrenamiento con grandes conjuntos de datos

En la sección anterior, trabajamos con pequeños conjuntos de datos en memoria usando Numpy y pandas, pero no todos los conjuntos de datos son tan pequeños. Especialmente los conjuntos de datos que contienen imágenes, videos y muestras de sonido son grandes.MinibatchSourcees un componente que puede cargar datos en trozos, proporcionado por CNTK para trabajar con conjuntos de datos tan grandes. Algunas de las características deMinibatchSource Los componentes son los siguientes:

  • MinibatchSource puede evitar que NN se sobreajuste al aleatorizar automáticamente las muestras leídas desde la fuente de datos.

  • Tiene una canalización de transformación incorporada que se puede utilizar para aumentar los datos.

  • Carga los datos en un subproceso en segundo plano separado del proceso de entrenamiento.

En las siguientes secciones, vamos a explorar cómo utilizar una fuente de minibatch con datos sin memoria para trabajar con grandes conjuntos de datos. También exploraremos cómo podemos usarlo para alimentar para entrenar a un NN.

Crear instancia de MinibatchSource

En la sección anterior, usamos el ejemplo de la flor de iris y trabajamos con un pequeño conjunto de datos en memoria usando Pandas DataFrames. Aquí, reemplazaremos el código que usa datos de un pandas DF conMinibatchSource. Primero, necesitamos crear una instancia deMinibatchSource con la ayuda de los siguientes pasos:

Ejemplo de implementación

Step 1 - Primero, desde cntk.io módulo importe los componentes para el minibatchsource de la siguiente manera:

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer,
 INFINITY_REPEAT

Step 2 - Ahora, usando StreamDef class, cree una definición de flujo para las etiquetas.

labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)

Step 3 - A continuación, cree para leer las características archivadas desde el archivo de entrada, cree otra instancia de StreamDef como sigue.

feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)

Step 4 - Ahora, necesitamos proporcionar iris.ctf archivo como entrada e inicializar el deserializer como sigue -

deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=
label_stream, features=features_stream)

Step 5 - Por fin, necesitamos crear una instancia de minisourceBatch mediante el uso deserializer como sigue -

Minibatch_source = MinibatchSource(deserializer, randomize=True)

Creación de una instancia de MinibatchSource: ejemplo de implementación completo

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True)

Creando archivo MCTF

Como ha visto anteriormente, estamos tomando los datos del archivo 'iris.ctf'. Tiene el formato de archivo llamado CNTK Text Format (CTF). Es obligatorio crear un archivo CTF para obtener los datos delMinibatchSourceinstancia que creamos arriba. Veamos cómo podemos crear un archivo CTF.

Ejemplo de implementación

Step 1 - Primero, necesitamos importar los paquetes pandas y numpy de la siguiente manera -

import pandas as pd
import numpy as np

Step 2- A continuación, necesitamos cargar nuestro archivo de datos, es decir, iris.csv en la memoria. Luego, guárdelo en eldf_source variable.

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

Step 3 - Ahora, usando ilocindexador como características, tome el contenido de las primeras cuatro columnas. Además, use los datos de la columna de especies de la siguiente manera:

features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values

Step 4- A continuación, necesitamos crear un mapeo entre el nombre de la etiqueta y su representación numérica. Se puede hacer creandolabel_mapping como sigue -

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 5 - Ahora, convierta las etiquetas en un conjunto de vectores codificados one-hot de la siguiente manera -

labels = [one_hot(label_mapping[v], 3) for v in labels]

Ahora, como hicimos antes, cree una función de utilidad llamada one_hotpara codificar las etiquetas. Se puede hacer de la siguiente manera:

def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result

Como hemos cargado y preprocesado los datos, es hora de almacenarlos en el disco en el formato de archivo CTF. Podemos hacerlo con la ayuda de seguir el código de Python:

With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

Creación de un archivo MCTF: ejemplo de implementación completo

import pandas as pd
import numpy as np
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
labels = [one_hot(label_mapping[v], 3) for v in labels]
def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result
With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

Alimentando los datos

Una vez que crea MinibatchSource,ejemplo, tenemos que entrenarlo. Podemos usar la misma lógica de entrenamiento que usamos cuando trabajamos con pequeños conjuntos de datos en memoria. Aquí usaremosMinibatchSource instancia como entrada para el método de tren en la función de pérdida de la siguiente manera:

Ejemplo de implementación

Step 1 - Para registrar el resultado de la sesión de entrenamiento, primero importe el ProgressPrinter de cntk.logging módulo de la siguiente manera -

from cntk.logging import ProgressPrinter

Step 2 - A continuación, para configurar la sesión de formación, importe el trainer y training_session desde cntk.train módulo de la siguiente manera -

from cntk.train import Trainer,

Step 3 - Ahora, necesitamos definir un conjunto de constantes como minibatch_size, samples_per_epoch y num_epochs como sigue -

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30

Step 4 - A continuación, para saber CNTK cómo leer datos durante el entrenamiento, necesitamos definir un mapeo entre la variable de entrada para la red y los flujos en la fuente del minibatch.

input_map = {
     features: minibatch.source.streams.features,
     labels: minibatch.source.streams.features
}

Step 5 - A continuación, para registrar la salida del proceso de entrenamiento, inicialice el progress_printer variable con una nueva ProgressPrinter instancia de la siguiente manera:

progress_writer = ProgressPrinter(0)

Step 6 - Por último, necesitamos invocar el método del tren en la pérdida de la siguiente manera -

train_history = loss.train(minibatch_source,
parameter_learners=[learner],
  model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

Alimentando los datos: ejemplo de implementación completo

from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
input_map = {
   features: minibatch.source.streams.features,
   labels: minibatch.source.streams.features
}
progress_writer = ProgressPrinter(0)
train_history = loss.train(minibatch_source,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

Salida

-------------------------------------------------------------------
average   since   average   since  examples
loss      last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.21      1.21      0        0       32
1.15      0.12      0        0       96
[………]

CNTK: medición del rendimiento

Este capítulo explicará cómo medir el rendimiento del modelo en CNKT.

Estrategia para validar el desempeño del modelo

Después de crear un modelo de AA, solíamos entrenarlo con un conjunto de muestras de datos. Debido a este entrenamiento, nuestro modelo ML aprende y deriva algunas reglas generales. El rendimiento del modelo de aprendizaje automático es importante cuando alimentamos el modelo con nuevas muestras, es decir, muestras diferentes a las proporcionadas en el momento del entrenamiento. El modelo se comporta de manera diferente en ese caso. Puede que sea peor para hacer una buena predicción sobre esas nuevas muestras.

Pero el modelo también debe funcionar bien para nuevas muestras porque en el entorno de producción obtendremos una entrada diferente a la que usamos los datos de muestra para fines de capacitación. Esa es la razón por la que debemos validar el modelo de aprendizaje automático mediante el uso de un conjunto de muestras diferentes de las muestras que usamos con fines de capacitación. Aquí, vamos a discutir dos técnicas diferentes para crear un conjunto de datos para validar una NN.

Conjunto de datos de reserva

Es uno de los métodos más sencillos para crear un conjunto de datos para validar un NN. Como su nombre lo indica, en este método retendremos un conjunto de muestras del entrenamiento (digamos, 20%) y lo usaremos para probar el rendimiento de nuestro modelo ML. El siguiente diagrama muestra la relación entre las muestras de capacitación y validación:

El modelo de conjunto de datos de retención garantiza que tengamos suficientes datos para entrenar nuestro modelo ML y, al mismo tiempo, tendremos una cantidad razonable de muestras para obtener una buena medición del rendimiento del modelo.

Para incluirlo en el conjunto de entrenamiento y de prueba, es una buena práctica elegir muestras aleatorias del conjunto de datos principal. Garantiza una distribución uniforme entre el entrenamiento y el conjunto de prueba.

A continuación, se muestra un ejemplo en el que estamos produciendo nuestro propio conjunto de datos de reserva utilizando train_test_split función de la scikit-learn biblioteca.

Ejemplo

from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)
# Here above test_size = 0.2 represents that we provided 20% of the data as test data.
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
classifier_knn = KNeighborsClassifier(n_neighbors=3)
classifier_knn.fit(X_train, y_train)
y_pred = classifier_knn.predict(X_test)
# Providing sample data and the model will make prediction out of that data
sample = [[5, 5, 3, 2], [2, 4, 3, 5]]
preds = classifier_knn.predict(sample)
pred_species = [iris.target_names[p] for p in preds] print("Predictions:", pred_species)

Salida

Predictions: ['versicolor', 'virginica']

Mientras usamos CNTK, necesitamos aleatorizar el orden de nuestro conjunto de datos cada vez que entrenamos nuestro modelo porque:

  • Los algoritmos de aprendizaje profundo están muy influenciados por los generadores de números aleatorios.

  • El orden en el que proporcionamos las muestras a NN durante el entrenamiento afecta en gran medida su rendimiento.

La principal desventaja de usar la técnica de retención de datos es que no es confiable porque a veces obtenemos muy buenos resultados, pero a veces, obtenemos malos resultados.

Validación cruzada de K-fold

Para hacer que nuestro modelo ML sea más confiable, existe una técnica llamada validación cruzada de K-fold. En la naturaleza, la técnica de validación cruzada de K-fold es la misma que la técnica anterior, pero la repite varias veces, generalmente de 5 a 10 veces. El siguiente diagrama representa su concepto:

Trabajo de validación cruzada de K-fold

El funcionamiento de la validación cruzada de K-fold se puede entender con la ayuda de los siguientes pasos:

Step 1- Al igual que en la técnica de conjunto de datos Hand-out, en la técnica de validación cruzada de K-fold, primero necesitamos dividir el conjunto de datos en un conjunto de entrenamiento y prueba. Idealmente, la proporción es 80-20, es decir, 80% del conjunto de entrenamiento y 20% del conjunto de prueba.

Step 2 - A continuación, necesitamos entrenar nuestro modelo usando el conjunto de entrenamiento.

Step 3−Por último, usaremos el conjunto de pruebas para medir el rendimiento de nuestro modelo. La única diferencia entre la técnica del conjunto de datos de Hold-out y la técnica de validación k-cross es que el proceso anterior se repite generalmente de 5 a 10 veces y al final se calcula el promedio sobre todas las métricas de rendimiento. Ese promedio sería la métrica de rendimiento final.

Veamos un ejemplo con un pequeño conjunto de datos:

Ejemplo

from numpy import array
from sklearn.model_selection import KFold
data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
kfold = KFold(5, True, 1)
for train, test in kfold.split(data):
   print('train: %s, test: %s' % (data[train],(data[test]))

Salida

train: [0.1 0.2 0.4 0.5 0.6 0.7 0.8 0.9], test: [0.3 1. ]
train: [0.1 0.2 0.3 0.4 0.6 0.8 0.9 1. ], test: [0.5 0.7]
train: [0.2 0.3 0.5 0.6 0.7 0.8 0.9 1. ], test: [0.1 0.4]
train: [0.1 0.3 0.4 0.5 0.6 0.7 0.9 1. ], test: [0.2 0.8]
train: [0.1 0.2 0.3 0.4 0.5 0.7 0.8 1. ], test: [0.6 0.9]

Como vemos, debido al uso de un escenario de prueba y entrenamiento más realista, la técnica de validación cruzada de k-fold nos brinda una medición de desempeño mucho más estable pero, en el lado negativo, lleva mucho tiempo validar modelos de aprendizaje profundo.

CNTK no admite la validación de k-cross, por lo tanto, necesitamos escribir nuestro propio script para hacerlo.

Detectar desajustes y sobreajustes

Ya sea que usemos el conjunto de datos Hand-out o la técnica de validación cruzada de k veces, descubriremos que el resultado de las métricas será diferente para el conjunto de datos utilizado para el entrenamiento y el conjunto de datos utilizado para la validación.

Detectando sobreajuste

El fenómeno llamado sobreajuste es una situación en la que nuestro modelo ML modela los datos de entrenamiento excepcionalmente bien, pero no funciona bien en los datos de prueba, es decir, no pudo predecir los datos de prueba.

Ocurre cuando un modelo de aprendizaje automático aprende un patrón y ruido específicos de los datos de entrenamiento hasta tal punto que impacta negativamente la capacidad de ese modelo para generalizar desde los datos de entrenamiento a datos nuevos, es decir, no vistos. Aquí, el ruido es la información irrelevante o la aleatoriedad en un conjunto de datos.

Las siguientes son las dos formas con la ayuda de las cuales podemos detectar si nuestro modelo está sobreajustado o no:

  • El modelo de sobreajuste funcionará bien en las mismas muestras que usamos para el entrenamiento, pero funcionará muy mal en las nuevas muestras, es decir, muestras diferentes a las de entrenamiento.

  • El modelo está sobreajustado durante la validación si la métrica en el conjunto de prueba es menor que la misma métrica que usamos en nuestro conjunto de entrenamiento.

Detectando falta de ajuste

Otra situación que puede surgir en nuestro ML es la falta de adecuación. Esta es una situación en la que nuestro modelo ML no modeló bien los datos de entrenamiento y no puede predecir resultados útiles. Cuando comencemos a entrenar en la primera época, nuestro modelo estará desajustado, pero se volverá menos inadecuado a medida que avance el entrenamiento.

Una de las formas de detectar si nuestro modelo es inadecuado o no es observar las métricas del conjunto de entrenamiento y el conjunto de prueba. Nuestro modelo será inadecuado si la métrica en el conjunto de prueba es más alta que la métrica en el conjunto de entrenamiento.

CNTK - Clasificación de redes neuronales

En este capítulo, estudiaremos cómo clasificar una red neuronal utilizando CNTK.

Introducción

La clasificación puede definirse como el proceso para predecir etiquetas de salida categóricas o respuestas para los datos de entrada dados. La salida categorizada, que se basará en lo que el modelo ha aprendido en la fase de entrenamiento, puede tener la forma "Negro" o "Blanco" o "spam" o "no spam".

Por otro lado, matemáticamente, es la tarea de aproximar una función de mapeo, digamos f de las variables de entrada digamos X a las variables de salida digamos Y.

Un ejemplo clásico de problema de clasificación puede ser la detección de spam en correos electrónicos. Es obvio que solo puede haber dos categorías de salida, "spam" y "no spam".

Para implementar dicha clasificación, primero necesitamos hacer un entrenamiento del clasificador donde los correos electrónicos "spam" y "no spam" se usarían como datos de entrenamiento. Una vez, el clasificador entrenado con éxito, se puede utilizar para detectar un correo electrónico desconocido.

Aquí, vamos a crear un 4-5-3 NN usando un conjunto de datos de flores de iris con lo siguiente:

  • Nodos de 4 entradas (uno para cada valor predictor).

  • 5 nodos de procesamiento ocultos.

  • Nodos de 3 salidas (porque hay tres posibles especies en el conjunto de datos de iris).

Cargando conjunto de datos

Usaremos un conjunto de datos de flores de iris, a partir del cual queremos clasificar las especies de flores de iris en función de las propiedades físicas del ancho y largo del sépalo, y del ancho y largo de los pétalos. El conjunto de datos describe las propiedades físicas de diferentes variedades de flores de iris:

  • Longitud del sépalo

  • Ancho del sépalo

  • Longitud del pétalo

  • Ancho del pétalo

  • Clase ie iris setosa o iris versicolor o iris virginica

Tenemos iris.CSVarchivo que usamos antes en capítulos anteriores también. Se puede cargar con la ayuda dePandasbiblioteca. Pero, antes de usarlo o cargarlo para nuestro clasificador, necesitamos preparar los archivos de entrenamiento y prueba, para que se pueda usar fácilmente con CNTK.

Preparación de archivos de prueba y entrenamiento

El conjunto de datos Iris es uno de los conjuntos de datos más populares para proyectos de AA. Tiene 150 elementos de datos y los datos sin procesar se ven de la siguiente manera:

5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
…
7.0 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
…
6.3 3.3 6.0 2.5 virginica
5.8 2.7 5.1 1.9 virginica

Como se dijo anteriormente, los primeros cuatro valores de cada línea describen las propiedades físicas de las diferentes variedades, es decir, longitud del sépalo, ancho del sépalo, longitud del pétalo, ancho del pétalo de las flores del iris.

Pero, deberíamos tener que convertir los datos en el formato, que pueda ser usado fácilmente por CNTK y ese formato es un archivo .ctf (también creamos un iris.ctf en la sección anterior). Se verá así:

|attribs 5.1 3.5 1.4 0.2|species 1 0 0
|attribs 4.9 3.0 1.4 0.2|species 1 0 0
…
|attribs 7.0 3.2 4.7 1.4|species 0 1 0
|attribs 6.4 3.2 4.5 1.5|species 0 1 0
…
|attribs 6.3 3.3 6.0 2.5|species 0 0 1
|attribs 5.8 2.7 5.1 1.9|species 0 0 1

En los datos anteriores, la etiqueta | attribs marca el inicio del valor de la característica y la | especie etiqueta los valores de la etiqueta de clase. También podemos usar cualquier otro nombre de etiqueta de nuestro deseo, incluso podemos agregar la identificación del artículo. Por ejemplo, observe los siguientes datos:

|ID 001 |attribs 5.1 3.5 1.4 0.2|species 1 0 0 |#setosa
|ID 002 |attribs 4.9 3.0 1.4 0.2|species 1 0 0 |#setosa
…
|ID 051 |attribs 7.0 3.2 4.7 1.4|species 0 1 0 |#versicolor
|ID 052 |attribs 6.4 3.2 4.5 1.5|species 0 1 0 |#versicolor
…

Hay un total de 150 elementos de datos en el conjunto de datos del iris y, para este ejemplo, usaremos la regla del conjunto de datos de retención 80-20, es decir, 80% (120 elementos) elementos de datos con fines de entrenamiento y 20% restante (30 elementos) elementos de datos para pruebas propósito.

Construyendo modelo de clasificació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='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', 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

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 = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 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)
nnet = oLayer
model = C.ops.softmax(nnet)

Ahora, una vez que creamos el modelo dual sin entrenamiento, necesitamos configurar un objeto de algoritmo de aprendizaje y luego usarlo para crear un objeto de entrenamiento de entrenador. Vamos a utilizar aprendiz SGD ycross_entropy_with_softmax función de pérdida -

tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Codifique el algoritmo de aprendizaje de la siguiente manera:

max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Ahora, una vez que terminamos con el objeto Trainer, 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)
iris_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))

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

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification 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 no vistos:

np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[6.4, 3.2, 4.5, 1.5]], dtype=np.float32)
print("\nPredicting Iris species for input features: ")
print(unknown[0]) pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])

Modelo de clasificació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='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', 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("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 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)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])
if __name__== ”__main__”:
main()

Salida

Using CNTK version = 2.7
batch 0: mean loss = 1.0986, mean accuracy = 40.00%
batch 500: mean loss = 0.6677, mean accuracy = 80.00%
batch 1000: mean loss = 0.5332, mean accuracy = 70.00%
batch 1500: mean loss = 0.2408, mean accuracy = 100.00%
Evaluating test data
Classification accuracy = 94.58%
Predicting species for input features:
[7.0 3.2 4.7 1.4]
Prediction probabilities:
[0.0847 0.736 0.113]

Guardar el modelo entrenado

Este conjunto de datos de Iris tiene solo 150 elementos de datos, por lo que solo tomaría unos segundos entrenar el modelo de clasificador 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 que no tengamos que retenerlo desde cero. Con la ayuda de seguir el código de Python, podemos guardar nuestro NN entrenado:

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

A continuación se presentan los argumentos de save() función utilizada 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 haya guardado el modelo entrenado, es muy fácil cargar ese modelo. Solo necesitamos usar elload ()función. Comprobemos esto en el siguiente ejemplo:

import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralclassifier.model”)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])

La ventaja del modelo guardado es que, una vez que carga un modelo guardado, se puede utilizar exactamente como si el modelo se acabara de entrenar.

CNTK - Clasificación binaria de redes neuronales

Entendamos, en este capítulo, qué es la clasificación binaria de redes neuronales usando CNTK.

La clasificación binaria que usa NN es como una clasificación de clases múltiples, lo único es que solo hay dos nodos de salida en lugar de tres o más. Aquí, vamos a realizar una clasificación binaria usando una red neuronal usando dos técnicas, a saber, la técnica de un nodo y la técnica de dos nodos. La técnica de un nodo es más común que la técnica de dos nodos.

Cargando conjunto de datos

Para que ambas técnicas se implementen mediante NN, utilizaremos un conjunto de datos de billetes. El conjunto de datos se puede descargar del Repositorio de aprendizaje automático de UCI, que está disponible enhttps://archive.ics.uci.edu/ml/datasets/banknote+authentication.

Para nuestro ejemplo, usaremos 50 elementos de datos auténticos con clase de falsificación = 0 y los primeros 50 elementos falsos con clase de falsificación = 1.

Preparación de archivos de prueba y entrenamiento

Hay 1372 elementos de datos en el conjunto de datos completo. El conjunto de datos sin procesar tiene el siguiente aspecto:

3.6216, 8.6661, -2.8076, -0.44699, 0
4.5459, 8.1674, -2.4586, -1.4621, 0
…
-1.3971, 3.3191, -1.3927, -1.9948, 1
0.39012, -0.14279, -0.031994, 0.35084, 1

Ahora, primero necesitamos convertir estos datos en bruto en formato CNTK de dos nodos, que sería el siguiente:

|stats 3.62160000 8.66610000 -2.80730000 -0.44699000 |forgery 0 1 |# authentic 
|stats 4.54590000 8.16740000 -2.45860000 -1.46210000 |forgery 0 1 |# authentic 
. . .
|stats -1.39710000 3.31910000 -1.39270000 -1.99480000 |forgery 1 0 |# fake 
|stats 0.39012000 -0.14279000 -0.03199400 0.35084000 |forgery 1 0 |# fake

Puede utilizar el siguiente programa de Python para crear datos en formato CNTK a partir de datos sin procesar:

fin = open(".\\...", "r") #provide the location of saved dataset text file.
for line in fin:
   line = line.strip()
   tokens = line.split(",")
   if tokens[4] == "0":
    print("|stats %12.8f %12.8f %12.8f %12.8f |forgery 0 1 |# authentic" % \
(float(tokens[0]), float(tokens[1]), float(tokens[2]), float(tokens[3])) )
   else:
    print("|stats %12.8f %12.8f %12.8f %12.8f |forgery 1 0 |# fake" % \
(float(tokens[0]), float(tokens[1]), float(tokens[2]), float(tokens[3])) )
fin.close()

Modelo de clasificación binaria de dos nodos

Hay muy poca diferencia entre la clasificación de dos nodos y la clasificación de clases múltiples. Aquí primero, necesitamos procesar los archivos de datos en formato CNTK y para eso vamos a usar la función auxiliar llamadacreate_reader como sigue -

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', 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

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 = 4
hidden_dim = 10
output_dim = 2
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file

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)
nnet = oLayer
model = C.ops.softmax(nnet)

Ahora, una vez que creamos el modelo dual sin entrenamiento, necesitamos configurar un objeto de algoritmo de aprendizaje y luego usarlo para crear un objeto de entrenamiento de entrenador. Vamos a usar la función de aprendizaje SGD y cross_entropy_with_softmax loss -

tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 500
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Ahora, una vez que terminamos con el objeto Trainer, 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)
banknote_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))

Una vez que se completa el entrenamiento, evaluemos el modelo utilizando elementos de datos de prueba:

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification 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 no vistos:

np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])
if pred_prob[0,0] < pred_prob[0,1]:
  print(“Prediction: authentic”)
else:
  print(“Prediction: fake”)

Modelo completo de clasificación de dos nodos

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', 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("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 10
output_dim = 2
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
withC.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)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 500
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
banknote_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])
if pred_prob[0,0] < pred_prob[0,1]:
print(“Prediction: authentic”)
else:
print(“Prediction: fake”)
if __name__== ”__main__”:
main()

Salida

Using CNTK version = 2.7
batch 0: mean loss = 0.6928, accuracy = 80.00%
batch 50: mean loss = 0.6877, accuracy = 70.00%
batch 100: mean loss = 0.6432, accuracy = 80.00%
batch 150: mean loss = 0.4978, accuracy = 80.00%
batch 200: mean loss = 0.4551, accuracy = 90.00%
batch 250: mean loss = 0.3755, accuracy = 90.00%
batch 300: mean loss = 0.2295, accuracy = 100.00%
batch 350: mean loss = 0.1542, accuracy = 100.00%
batch 400: mean loss = 0.1581, accuracy = 100.00%
batch 450: mean loss = 0.1499, accuracy = 100.00%
Evaluating test data
Classification accuracy = 84.58%
Predicting banknote authenticity for input features:
[0.6 1.9 -3.3 -0.3]
Prediction probabilities are:
[0.7847 0.2536]
Prediction: fake

Modelo de clasificación binaria de un nodo

El programa de implementación es casi como lo hemos hecho anteriormente para la clasificación de dos nodos. El principal cambio es que cuando se utiliza la técnica de clasificación de dos nodos.

Podemos usar la función de clasificación_error () incorporada de CNTK, pero en el caso de la clasificación de un nodo, CNTK no admite la función de clasificación_error (). Esa es la razón por la que necesitamos implementar una función definida por programa de la siguiente manera:

def class_acc(mb, x_var, y_var, model):
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]):
   p = model.eval(x_mat[i]
   y = y_mat[i]
   if p[0,0] < 0.5 and y[0,0] == 0.0 or p[0,0] >= 0.5 and y[0,0] == 1.0:
num_correct += 1
 else:
  num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)

Con ese cambio, veamos el ejemplo completo de clasificación de un nodo:

Modelo de clasificación completo de un nodo

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='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', 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 class_acc(mb, x_var, y_var, model):
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]):
  p = model.eval(x_mat[i]
  y = y_mat[i]
  if p[0,0] < 0.5 and y[0,0] == 0.0 or p[0,0] >= 0.5 and y[0,0] == 1.0:
  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 = 4
hidden_dim = 10
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file
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 = oLayer
tr_loss = C.cross_entropy_with_softmax(model, Y)
max_iter = 1000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(model.parameters, learn_rate)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
banknote_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 100 == 0:
mcee=trainer.previous_minibatch_loss_average
ca = class_acc(curr_batch, X,Y, model)
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, ca))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map)
acc = class_acc(all_test, X,Y, model)
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval({X:unknown})
print("Prediction probability: ")
print(“%0.4f” % pred_prob[0,0])
if pred_prob[0,0] < 0.5:
  print(“Prediction: authentic”)
else:
  print(“Prediction: fake”)
if __name__== ”__main__”:
   main()

Salida

Using CNTK version = 2.7
batch 0: mean loss = 0.6936, accuracy = 10.00%
batch 100: mean loss = 0.6882, accuracy = 70.00%
batch 200: mean loss = 0.6597, accuracy = 50.00%
batch 300: mean loss = 0.5298, accuracy = 70.00%
batch 400: mean loss = 0.4090, accuracy = 100.00%
batch 500: mean loss = 0.3790, accuracy = 90.00%
batch 600: mean loss = 0.1852, accuracy = 100.00%
batch 700: mean loss = 0.1135, accuracy = 100.00%
batch 800: mean loss = 0.1285, accuracy = 100.00%
batch 900: mean loss = 0.1054, accuracy = 100.00%
Evaluating test data
Classification accuracy = 84.00%
Predicting banknote authenticity for input features:
[0.6 1.9 -3.3 -0.3]
Prediction probability:
0.8846
Prediction: fake

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 lotes 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 no vistos:

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 utilizar exactamente como si el modelo se acabara de entrenar.

CNTK - Modelo de clasificación

Este capítulo le ayudará a comprender cómo medir el rendimiento del modelo de clasificación en CNTK. Comencemos con la matriz de confusión.

Matriz de confusión

Matriz de confusión: una tabla con el resultado previsto frente al resultado esperado es la forma más fácil de medir el rendimiento de un problema de clasificación, donde el resultado puede ser de dos o más tipos de clases.

Para entender cómo funciona, vamos a crear una matriz de confusión para un modelo de clasificación binaria que predice si una transacción con tarjeta de crédito fue normal o un fraude. Se muestra de la siguiente manera:

Fraude real Normal real

Predicted fraud

Verdadero positivo

Falso positivo

Predicted normal

Falso negativo

Verdadero negativo

Como podemos ver, la matriz de confusión de muestra anterior contiene 2 columnas, una para fraude de clase y otra para clase normal. De la misma manera tenemos 2 filas, una se agrega para fraude de clase y otra se agrega para clase normal. A continuación se muestra la explicación de los términos asociados con la matriz de confusión:

  • True Positives - Cuando tanto la clase real como la clase pronosticada del punto de datos es 1.

  • True Negatives - Cuando tanto la clase real como la clase predicha del punto de datos es 0.

  • False Positives - Cuando la clase real de punto de datos es 0 y la clase prevista de punto de datos es 1.

  • False Negatives - Cuando la clase real de punto de datos es 1 y la clase prevista de punto de datos es 0.

Veamos, cómo podemos calcular el número de cosas diferentes de la matriz de confusión -

  • Accuracy- Es el número de predicciones correctas realizadas por nuestro modelo de clasificación ML. Se puede calcular con la ayuda de la siguiente fórmula:

  • Precision−Nos dice cuántas muestras se predijeron correctamente de todas las muestras que predijimos. Se puede calcular con la ayuda de la siguiente fórmula:

  • Recall or Sensitivity- La recuperación es el número de positivos devueltos por nuestro modelo de clasificación de ML. En otras palabras, nos dice cuántos de los casos de fraude en el conjunto de datos fueron realmente detectados por el modelo. Se puede calcular con la ayuda de la siguiente fórmula:

  • Specificity- Contrario a recordar, da la cantidad de negativos devueltos por nuestro modelo de clasificación ML. Se puede calcular con la ayuda de la siguiente fórmula:

Medida F

Podemos usar la medida F como alternativa a la matriz de confusión. La principal razón detrás de esto es que no podemos maximizar la recuperación y la precisión al mismo tiempo. Existe una relación muy fuerte entre estas métricas y eso se puede entender con la ayuda del siguiente ejemplo:

Supongamos que queremos usar un modelo DL para clasificar las muestras de células como cancerosas o normales. Aquí, para alcanzar la máxima precisión, necesitamos reducir el número de predicciones a 1. Aunque, esto puede darnos una precisión de alrededor del 100 por ciento, pero la memoria será realmente baja.

Por otro lado, si queremos alcanzar el máximo recuerdo, necesitamos hacer tantas predicciones como sea posible. Aunque, esto puede darnos un alcance de alrededor del 100 por ciento de recuperación, pero la precisión será realmente baja.

En la práctica, necesitamos encontrar una forma de equilibrar la precisión y el recuerdo. La métrica de medida F nos permite hacerlo, ya que expresa un promedio armónico entre precisión y recuperación.

Esta fórmula se llama la medida F1, donde el término adicional llamado B se establece en 1 para obtener una proporción igual de precisión y recuperación. Para enfatizar la recuperación, podemos establecer el factor B en 2. Por otro lado, para enfatizar la precisión, podemos establecer el factor B en 0.5.

Usar CNTK para medir el desempeño de la clasificación

En la sección anterior, hemos creado un modelo de clasificación utilizando un conjunto de datos de flores de Iris. Aquí, mediremos su desempeño utilizando una matriz de confusión y una métrica de medida F.

Creando matriz de confusión

Ya creamos el modelo, por lo que podemos iniciar el proceso de validación, que incluye confusion matrix, en el mismo. Primero, vamos a crear una matriz de confusión con la ayuda delconfusion_matrix función de scikit-learn. Para esto, necesitamos las etiquetas reales para nuestras muestras de prueba y las etiquetas predichas para las mismas muestras de prueba.

Calculemos la matriz de confusión usando el siguiente código de Python:

from sklearn.metrics import confusion_matrix
y_true = np.argmax(y_test, axis=1)
y_pred = np.argmax(z(X_test), axis=1)
matrix = confusion_matrix(y_true=y_true, y_pred=y_pred)
print(matrix)

Salida

[[10 0 0]
[ 0 1 9]
[ 0 0 10]]

También podemos usar la función de mapa de calor para visualizar una matriz de confusión de la siguiente manera:

import seaborn as sns
import matplotlib.pyplot as plt
g = sns.heatmap(matrix,
     annot=True,
     xticklabels=label_encoder.classes_.tolist(),
     yticklabels=label_encoder.classes_.tolist(),
     cmap='Blues')
g.set_yticklabels(g.get_yticklabels(), rotation=0)
plt.show()

También deberíamos tener un número de rendimiento único, que podemos usar para comparar el modelo. Para esto, necesitamos calcular el error de clasificación usandoclassification_error función, del paquete de métricas en CNTK como se hizo al crear el modelo de clasificación.

Ahora, para calcular el error de clasificación, ejecute el método de prueba en la función de pérdida con un conjunto de datos. Después de eso, CNTK tomará las muestras que proporcionamos como entrada para esta función y hará una predicción basada en las características de entrada X_test.

loss.test([X_test, y_test])

Salida

{'metric': 0.36666666666, 'samples': 30}

Implementación de medidas F

Para implementar F-Measures, CNTK también incluye una función llamada fmeasures. Podemos usar esta función, mientras entrenamos el NN reemplazando la celdacntk.metrics.classification_error, con una llamada a cntk.losses.fmeasure al definir la función de fábrica de criterio de la siguiente manera:

import cntk
@cntk.Function
def criterion_factory(output, target):
   loss = cntk.losses.cross_entropy_with_softmax(output, target)
metric = cntk.losses.fmeasure(output, target)
   return loss, metric

Después de usar la función cntk.losses.fmeasure, obtendremos una salida diferente para el loss.test llamada al método dada de la siguiente manera:

loss.test([X_test, y_test])

Salida

{'metric': 0.83101488749, 'samples': 30}

CNTK - Modelo de regresión

Aquí, estudiaremos sobre la medición del desempeño con respecto a un modelo de regresión.

Conceptos básicos de la validación de un modelo de regresión

Como sabemos, los modelos de regresión son diferentes a los modelos de clasificación, en el sentido de que no existe una medida binaria de lo correcto o incorrecto para las muestras de los individuos. En los modelos de regresión, queremos medir qué tan cerca está la predicción del valor real. Cuanto más se acerque el valor de predicción al resultado esperado, mejor será el rendimiento del modelo.

Aquí, vamos a medir el desempeño de NN usado para la regresión usando diferentes funciones de tasa de error.

Calcular el margen de error

Como se discutió anteriormente, al validar un modelo de regresión, no podemos decir si una predicción es correcta o incorrecta. Queremos que nuestra predicción se acerque lo más posible al valor real. Pero aquí es aceptable un pequeño margen de error.

La fórmula para calcular el margen de error es la siguiente:

Aquí,

Predicted value = indicado y por un sombrero

Real value = predicho por y

Primero, necesitamos calcular la distancia entre el valor predicho y el real. Luego, para obtener una tasa de error general, debemos sumar estas distancias al cuadrado y calcular el promedio. Esto se llamamean squared función de error.

Pero, si queremos cifras de rendimiento que expresen un margen de error, necesitamos una fórmula que exprese el error absoluto. La formula paramean absolute La función de error es la siguiente:

La fórmula anterior toma la distancia absoluta entre el valor predicho y el real.

Usar CNTK para medir el rendimiento de la regresión

Aquí, veremos cómo usar las diferentes métricas que discutimos en combinación con CNTK. Usaremos un modelo de regresión que predice millas por galón para automóviles siguiendo los pasos que se indican a continuación.

Pasos de implementación

Step 1 - Primero, necesitamos importar los componentes requeridos desde cntk paquete de la siguiente manera:

from cntk import default_option, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import relu

Step 2 - A continuación, necesitamos definir una función de activación predeterminada utilizando el default_optionsfunciones. Luego, cree un nuevo conjunto de capas secuenciales y proporcione dos capas densas con 64 neuronas cada una. Luego, agregamos una capa densa adicional (que actuará como la capa de salida) al conjunto de capas secuenciales y damos 1 neurona sin una activación de la siguiente manera:

with default_options(activation=relu):
model = Sequential([Dense(64),Dense(64),Dense(1,activation=None)])

Step 3- Una vez que se ha creado la red, necesitamos crear una función de entrada. Necesitamos asegurarnos de que tenga la misma forma que las funciones que vamos a utilizar para el entrenamiento.

features = input_variable(X.shape[1])

Step 4 - Ahora, necesitamos crear otro input_variable con tamaño 1. Se utilizará para almacenar el valor esperado para NN.

target = input_variable(1)
z = model(features)

Ahora, necesitamos entrenar el modelo y, para hacerlo, vamos a dividir el conjunto de datos y realizar el preprocesamiento mediante los siguientes pasos de implementación:

Step 5−Primero, importe StandardScaler de sklearn.preprocessing para obtener los valores entre -1 y +1. Esto nos ayudará a evitar la explosión de problemas de gradientes en la NN.

from sklearn.preprocessing import StandardScalar

Step 6 - A continuación, importe train_test_split de sklearn.model_selection de la siguiente manera

from sklearn.model_selection import train_test_split

Step 7 - Suelta el mpg columna del conjunto de datos utilizando el dropmétodo. Por último, divida el conjunto de datos en un conjunto de entrenamiento y validación utilizando eltrain_test_split funciona de la siguiente manera:

x = df_cars.drop(columns=[‘mpg’]).values.astype(np.float32)
y=df_cars.iloc[: , 0].values.reshape(-1, 1).astype(np.float32)
scaler = StandardScaler()
X = scaler.fit_transform(x)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

Step 8 - Ahora, necesitamos crear otra variable_entrada con tamaño 1. Se usará para almacenar el valor esperado para NN.

target = input_variable(1)
z = model(features)

Hemos dividido y preprocesado los datos, ahora necesitamos entrenar a la NN. Como hicimos en secciones anteriores al crear el modelo de regresión, necesitamos definir una combinación de pérdida ymetric función para entrenar el modelo.

import cntk
def absolute_error(output, target):
   return cntk.ops.reduce_mean(cntk.ops.abs(output – target))
@ cntk.Function
def criterion_factory(output, target):
   loss = squared_error(output, target)
   metric = absolute_error(output, target)
   return loss, metric

Ahora, echemos un vistazo a cómo usar el modelo entrenado. Para nuestro modelo, usaremos Criterion_factory como la combinación de pérdidas y métricas.

from cntk.losses import squared_error
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_printer = ProgressPrinter(0)
loss = criterion_factory (z, target)
learner = sgd(z.parameters, 0.001)
training_summary=loss.train((x_train,y_train),parameter_learners=[learner],callbacks=[progress_printer],minibatch_size=16,max_epochs=10)

Ejemplo de implementación completo

from cntk import default_option, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import relu
with default_options(activation=relu):
model = Sequential([Dense(64),Dense(64),Dense(1,activation=None)])
features = input_variable(X.shape[1])
target = input_variable(1)
z = model(features)
from sklearn.preprocessing import StandardScalar
from sklearn.model_selection import train_test_split
x = df_cars.drop(columns=[‘mpg’]).values.astype(np.float32)
y=df_cars.iloc[: , 0].values.reshape(-1, 1).astype(np.float32)
scaler = StandardScaler()
X = scaler.fit_transform(x)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
target = input_variable(1)
z = model(features)
import cntk
def absolute_error(output, target):
   return cntk.ops.reduce_mean(cntk.ops.abs(output – target))
@ cntk.Function
def criterion_factory(output, target):
loss = squared_error(output, target)
metric = absolute_error(output, target)
return loss, metric
from cntk.losses import squared_error
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_printer = ProgressPrinter(0)
loss = criterion_factory (z, target)
learner = sgd(z.parameters, 0.001)
training_summary=loss.train((x_train,y_train),parameter_learners=[learner],callbacks=[progress_printer],minibatch_size=16,max_epochs=10)

Salida

-------------------------------------------------------------------
average  since   average   since  examples
loss     last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.001
690       690     24.9     24.9       16
654       636     24.1     23.7       48
[………]

Para validar nuestro modelo de regresión, debemos asegurarnos de que el modelo maneja los datos nuevos tan bien como lo hace con los datos de entrenamiento. Para esto, necesitamos invocar eltest método en loss y metric combinación con los datos de prueba de la siguiente manera:

loss.test([X_test, y_test])

Salida−

{'metric': 1.89679785619, 'samples': 79}

CNTK - Conjuntos de datos sin memoria

En este capítulo, se explicará cómo medir el rendimiento de conjuntos de datos sin memoria.

En secciones anteriores, hemos discutido sobre varios métodos para validar el rendimiento de nuestro NN, pero los métodos que hemos discutido son los que se ocupan de los conjuntos de datos que caben en la memoria.

Aquí, surge la pregunta sobre los conjuntos de datos sin memoria, porque en el escenario de producción, necesitamos muchos datos para entrenar NN. En esta sección, vamos a discutir cómo medir el rendimiento cuando se trabaja con fuentes de minibatch y bucle de minibatch manual.

Fuentes de minibatch

Mientras trabajamos con conjuntos de datos sin memoria, es decir, fuentes de minibatch, necesitamos una configuración de pérdida ligeramente diferente, así como métrica, que la configuración que usamos al trabajar con conjuntos de datos pequeños, es decir, conjuntos de datos en memoria. Primero, veremos cómo configurar una forma de alimentar datos al entrenador del modelo NN.

Los siguientes son los pasos de implementación:

Step 1 - Primero, desde cntk.El módulo io importa los componentes para crear la fuente del minibatch de la siguiente manera:

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer,
 INFINITY_REPEAT

Step 2 - A continuación, cree una nueva función llamada decir create_datasource. Esta función tendrá dos parámetros, a saber, nombre de archivo y límite, con un valor predeterminado deINFINITELY_REPEAT.

def create_datasource(filename, limit =INFINITELY_REPEAT)

Step 3 - Ahora, dentro de la función, usando StreamDefclass crate una definición de flujo para las etiquetas que se lee en el campo de etiquetas que tiene tres características. También necesitamos estableceris_sparse a False como sigue

labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)

Step 4 - A continuación, cree para leer las características archivadas desde el archivo de entrada, cree otra instancia de StreamDef como sigue.

feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)

Step 5 - Ahora, inicialice el CTFDeserializerclase de instancia. Especifique el nombre de archivo y los flujos que necesitamos deserializar de la siguiente manera:

deserializer = CTFDeserializer(filename, StreamDefs(labels=
label_stream, features=features_stream)

Step 6 - A continuación, necesitamos crear una instancia de minisourceBatch usando deserializador de la siguiente manera -

Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source

Step 7- Por último, debemos proporcionar una fuente de capacitación y prueba, que también creamos en secciones anteriores. Estamos utilizando un conjunto de datos de flores de iris.

training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)

Una vez que crea MinibatchSourceejemplo, tenemos que entrenarlo. Podemos usar la misma lógica de entrenamiento que usamos cuando trabajamos con pequeños conjuntos de datos en memoria. Aquí usaremosMinibatchSource ejemplo, como entrada para el método de tren en la función de pérdida de la siguiente manera:

Los siguientes son los pasos de implementación:

Step 1 - Para registrar el resultado de la sesión de entrenamiento, primero importe el ProgressPrinter desde cntk.logging módulo de la siguiente manera -

from cntk.logging import ProgressPrinter

Step 2 - A continuación, para configurar la sesión de formación, importe el trainer y training_session desde cntk.train módulo de la siguiente manera

from cntk.train import Trainer, training_session

Step 3 - Ahora, necesitamos definir un conjunto de constantes como minibatch_size, samples_per_epoch y num_epochs como sigue

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs

Step 4 - A continuación, para saber cómo leer los datos durante el entrenamiento en CNTK, necesitamos definir un mapeo entre la variable de entrada para la red y los flujos en la fuente del minibatch.

input_map = {
   features: training_source.streams.features,
   labels: training_source.streams.labels
}

Step 5 - Junto a registrar la salida del proceso de entrenamiento, inicialice el progress_printer variable con una nueva ProgressPrinterejemplo. Además, inicialice eltrainer y proporcione el modelo de la siguiente manera:

progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels

Step 6 - Por fin, para iniciar el proceso de formación, necesitamos invocar el training_session funciona de la siguiente manera:

session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()

Una vez que entrenamos el modelo, podemos agregar validación a esta configuración usando un TestConfig objeto y asígnelo al test_config argumento de palabra clave del train_session función.

Los siguientes son los pasos de implementación:

Step 1 - Primero, necesitamos importar el TestConfig clase del módulo cntk.train como sigue

from cntk.train import TestConfig

Step 2 - Ahora, necesitamos crear una nueva instancia del TestConfig con el test_source como entrada

Test_config = TestConfig(test_source)

Ejemplo completo

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
def create_datasource(filename, limit =INFINITELY_REPEAT)
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(filename, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source
training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)
from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs
input_map = {
   features:   training_source.streams.features,
   labels: training_source.streams.labels
 }
progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels
session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()
from cntk.train import TestConfig
Test_config = TestConfig(test_source)

Salida

-------------------------------------------------------------------
average   since   average   since  examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.57      1.57     0.214    0.214   16
1.38      1.28     0.264    0.289   48
[………]
Finished Evaluation [1]: Minibatch[1-1]:metric = 69.65*30;

Bucle de minibatch manual

Como vemos anteriormente, es fácil medir el rendimiento de nuestro modelo NN durante y después del entrenamiento, utilizando las métricas cuando se entrena con API regulares en CNTK. Pero, por otro lado, las cosas no serán tan fáciles mientras se trabaja con un bucle de minibatch manual.

Aquí, estamos utilizando el modelo que se muestra a continuación con 4 entradas y 3 salidas del conjunto de datos Iris Flower, creado también en secciones anteriores.

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu, sigmoid
from cntk.learners import sgd
model = Sequential([
   Dense(4, activation=sigmoid),
   Dense(3, activation=log_softmax)
])
features = input_variable(4)
labels = input_variable(3)
z = model(features)

A continuación, la pérdida para el modelo se define como la combinación de la función de pérdida de entropía cruzada y la métrica de medida F como se usó en las secciones anteriores. Vamos a utilizar elcriterion_factory utilidad, para crear esto como un objeto de función CNTK como se muestra a continuación

import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}

Ahora, como hemos definido la función de pérdida, veremos cómo podemos utilizarla en el entrenador, para configurar una sesión de entrenamiento manual.

Los siguientes son los pasos de implementación:

Step 1 - Primero, necesitamos importar los paquetes requeridos como numpy y pandas para cargar y preprocesar los datos.

import pandas as pd
import numpy as np

Step 2 - A continuación, para registrar información durante el entrenamiento, importe el ProgressPrinter clase de la siguiente manera

from cntk.logging import ProgressPrinter

Step 3 - Entonces, necesitamos importar el módulo de entrenador del módulo cntk.train de la siguiente manera -

from cntk.train import Trainer

Step 4 - A continuación, cree una nueva instancia de ProgressPrinter como sigue -

progress_writer = ProgressPrinter(0)

Step 5 - Ahora, necesitamos inicializar el entrenador con los parámetros la pérdida, el alumno y el progress_writer como sigue -

trainer = Trainer(z, loss, learner, progress_writer)

Step 6−A continuación, para entrenar el modelo, crearemos un ciclo que iterará sobre el conjunto de datos treinta veces. Este será el ciclo de entrenamiento externo.

for _ in range(0,30):

Step 7- Ahora, necesitamos cargar los datos desde el disco usando pandas. Luego, para cargar el conjunto de datos enmini-batches, selecciona el chunksize argumento de palabra clave a 16.

input_data = pd.read_csv('iris.csv',
names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)

Step 8 - Ahora, cree un ciclo de entrenamiento interno para iterar sobre cada uno de los mini-batches.

for df_batch in input_data:

Step 9 - Ahora dentro de este ciclo, lea las primeras cuatro columnas usando el iloc indexador, como el features para entrenar y convertirlos a float32 -

feature_values = df_batch.iloc[:,:4].values
feature_values = feature_values.astype(np.float32)

Step 10 - Ahora, lea la última columna como las etiquetas para entrenar, de la siguiente manera -

label_values = df_batch.iloc[:,-1]

Step 11 - A continuación, usaremos vectores one-hot para convertir las cadenas de etiquetas a su presentación numérica de la siguiente manera -

label_values = label_values.map(lambda x: label_mapping[x])

Step 12- Después de eso, tome la presentación numérica de las etiquetas. A continuación, conviértalos en una matriz numpy, para que sea más fácil trabajar con ellos de la siguiente manera:

label_values = label_values.values

Step 13 - Ahora, necesitamos crear una nueva matriz numpy que tenga el mismo número de filas que los valores de etiqueta que hemos convertido.

encoded_labels = np.zeros((label_values.shape[0], 3))

Step 14 - Ahora, para crear etiquetas codificadas en caliente, seleccione las columnas según los valores numéricos de las etiquetas.

encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.

Step 15 - Por fin, necesitamos invocar el train_minibatch en el entrenador y proporcione las características procesadas y etiquetas para el minibatch.

trainer.train_minibatch({features: feature_values, labels: encoded_labels})

Ejemplo completo

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu, sigmoid
from cntk.learners import sgd
model = Sequential([
   Dense(4, activation=sigmoid),
   Dense(3, activation=log_softmax)
])
features = input_variable(4)
labels = input_variable(3)
z = model(features)
import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}
import pandas as pd
import numpy as np
from cntk.logging import ProgressPrinter
from cntk.train import Trainer
progress_writer = ProgressPrinter(0)
trainer = Trainer(z, loss, learner, progress_writer)
for _ in range(0,30):
   input_data = pd.read_csv('iris.csv',
      names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
      index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
label_values = label_values.map(lambda x: label_mapping[x])
label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), 
label_values] = 1.
   trainer.train_minibatch({features: feature_values, labels: encoded_labels})

Salida

-------------------------------------------------------------------
average    since    average   since  examples
loss       last      metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.45       1.45     -0.189    -0.189   16
1.24       1.13     -0.0382    0.0371  48
[………]

En el resultado anterior, obtuvimos tanto el resultado de la pérdida como la métrica durante el entrenamiento. Esto se debe a que combinamos una métrica y una pérdida en un objeto de función y usamos una impresora de progreso en la configuración del entrenador.

Ahora, para evaluar el desempeño del modelo, necesitamos realizar la misma tarea que con el entrenamiento del modelo, pero esta vez, necesitamos usar un Evaluatorinstancia para probar el modelo. Se muestra en el siguiente código Python

from cntk import Evaluator
evaluator = Evaluator(loss.outputs[1], [progress_writer])
input_data = pd.read_csv('iris.csv',
   names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
   label_values = label_values.map(lambda x: label_mapping[x])
   label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.
   evaluator.test_minibatch({ features: feature_values, labels:
      encoded_labels})
evaluator.summarize_test_progress()

Ahora, obtendremos un resultado parecido al siguiente:

Salida

Finished Evaluation [1]: Minibatch[1-11]:metric = 74.62*143;

CNTK - Supervisión del modelo

En este capítulo, entenderemos cómo monitorear un modelo en CNTK.

Introducción

En secciones anteriores, hemos realizado algunas validaciones en nuestros modelos NN. Pero, ¿es también necesario y posible monitorizar nuestro modelo durante el entrenamiento?

Si, ya lo hemos usado ProgressWriterclass para monitorear nuestro modelo y hay muchas más formas de hacerlo. Antes de profundizar en las formas, primero echemos un vistazo a cómo funciona el monitoreo en CNTK y cómo podemos usarlo para detectar problemas en nuestro modelo NN.

Devoluciones de llamada en CNTK

En realidad, durante el entrenamiento y la validación, CNTK nos permite especificar devoluciones de llamada en varios puntos de la API. Primero, echemos un vistazo más de cerca a cuándo CNTK invoca devoluciones de llamada.

¿Cuándo CNTK invoca devoluciones de llamada?

CNTK invocará las devoluciones de llamada en los momentos de entrenamiento y prueba establecidos cuando--

  • Se completa un minibatch.

  • Se completa un barrido completo del conjunto de datos durante el entrenamiento.

  • Se completa un minibote de pruebas.

  • Se completa un barrido completo sobre el conjunto de datos durante la prueba.

Especificar devoluciones de llamada

Mientras trabajamos con CNTK, podemos especificar devoluciones de llamada en varios puntos de la API. Por ejemplo

¿Cuándo llamar al tren en una función de pérdida?

Aquí, cuando llamamos a train en una función de pérdida, podemos especificar un conjunto de devoluciones de llamada a través del argumento de devoluciones de llamada de la siguiente manera:

training_summary=loss.train((x_train,y_train),
parameter_learners=[learner],
callbacks=[progress_writer]),
minibatch_size=16, max_epochs=15)

Cuando se trabaja con fuentes de minibatch o se utiliza un bucle de minibatch manual

En este caso, podemos especificar devoluciones de llamada para propósitos de monitoreo mientras creamos el Trainer como sigue

from cntk.logging import ProgressPrinter
callbacks = [
   ProgressPrinter(0)
]
Trainer = Trainer(z, (loss, metric), learner, [callbacks])

Varias herramientas de monitoreo

Estudiemos sobre diferentes herramientas de seguimiento.

ProgressPrinter

Mientras lee este tutorial, encontrará ProgressPrintercomo la herramienta de seguimiento más utilizada. Algunas de las características deProgressPrinter herramienta de monitoreo son−

ProgressPrinterclass implementa un registro básico basado en consola para monitorear nuestro modelo. Puede registrarse en el disco que queramos.

Especialmente útil cuando se trabaja en un escenario de formación distribuida.

También es muy útil cuando se trabaja en un escenario en el que no podemos iniciar sesión en la consola para ver el resultado de nuestro programa Python.

Con la ayuda del siguiente código, podemos crear una instancia de ProgressPrinter-

ProgressPrinter(0, log_to_file=’test.txt’)

Obtendremos el resultado de algo que hemos visto en las secciones anteriores.

Test.txt
CNTKCommandTrainInfo: train : 300
CNTKCommandTrainInfo: CNTKNoMoreCommands_Total : 300
CNTKCommandTrainBegin: train
-------------------------------------------------------------------
average since average since examples
loss last metric last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.45 1.45 -0.189 -0.189 16
1.24 1.13 -0.0382 0.0371 48
[………]

TensorBoard

Una de las desventajas de usar ProgressPrinter es que no podemos tener una buena visión de cómo es difícil la pérdida y el progreso de las métricas a lo largo del tiempo. TensorBoardProgressWriter es una excelente alternativa a la clase ProgressPrinter en CNTK.

Antes de usarlo, primero debemos instalarlo con la ayuda del siguiente comando:

pip install tensorboard

Ahora, para usar TensorBoard, necesitamos configurar TensorBoardProgressWriter en nuestro código de entrenamiento de la siguiente manera:

import time
from cntk.logging import TensorBoardProgressWriter
tensorbrd_writer = TensorBoardProgressWriter(log_dir=’logs/{}’.format(time.time()),freq=1,model=z)

Es una buena práctica llamar al método close en TensorBoardProgressWriter instancia después de hecho con el entrenamiento de NNmodelo.

Podemos visualizar el TensorBoard registro de datos con la ayuda del siguiente comando:

Tensorboard –logdir logs

CNTK - Red neuronal convolucional

En este capítulo, estudiemos cómo construir una red neuronal convolucional (CNN) en CNTK.

Introducción

Las redes neuronales convolucionales (CNN) también están formadas por neuronas, que tienen pesos y sesgos que se pueden aprender. Por eso, de esta manera, son como redes neuronales ordinarias (NN).

Si recordamos el funcionamiento de los NN ordinarios, cada neurona recibe una o más entradas, toma una suma ponderada y pasa por una función de activación para producir la salida final. Aquí, surge la pregunta de que si las CNN y las NN ordinarias tienen tantas similitudes, ¿qué hace que estas dos redes sean diferentes entre sí?

¿Qué los hace diferentes es el tratamiento de los datos de entrada y los tipos de capas? La estructura de los datos de entrada se ignora en NN ordinario y todos los datos se convierten en una matriz 1-D antes de introducirlos en la red.

Pero la arquitectura de red neuronal convolucional puede considerar la estructura 2D de las imágenes, procesarlas y permitirle extraer las propiedades que son específicas de las imágenes. Además, las CNN tienen la ventaja de tener una o más capas convolucionales y una capa de agrupación, que son los componentes principales de las CNN.

Estas capas van seguidas de una o más capas completamente conectadas como en los NN multicapa estándar. Entonces, podemos pensar en CNN como un caso especial de redes completamente conectadas.

Arquitectura de red neuronal convolucional (CNN)

La arquitectura de CNN es básicamente una lista de capas que transforma el volumen tridimensional, es decir, ancho, alto y profundidad de la imagen, en un volumen de salida tridimensional. Un punto importante a tener en cuenta aquí es que, cada neurona en la capa actual está conectada a un pequeño parche de la salida de la capa anterior, que es como superponer un filtro N * N en la imagen de entrada.

Utiliza filtros M, que son básicamente extractores de características que extraen características como bordes, esquinas, etc. Las siguientes son las capas [INPUT-CONV-RELU-POOL-FC] que se utilizan para construir redes neuronales convolucionales (CNN) -

  • INPUT- Como su nombre lo indica, esta capa contiene los valores de píxeles sin procesar. Los valores de píxeles sin procesar significan los datos de la imagen tal como están. Por ejemplo, INPUT [64 × 64 × 3] es una imagen RGB de 3 canales de ancho 64, alto 64 y profundidad 3.

  • CONV- Esta capa es uno de los componentes básicos de las CNN, ya que la mayor parte del cálculo se realiza en esta capa. Ejemplo: si usamos 6 filtros en la ENTRADA [64 × 64 × 3] mencionada anteriormente, esto puede resultar en el volumen [64 × 64 × 6].

  • RELU−También llamada capa de unidad lineal rectificada, que aplica una función de activación a la salida de la capa anterior. De otra manera, RELU agregaría una no linealidad a la red.

  • POOL- Esta capa, es decir, la capa de agrupación, es otro componente básico de las CNN. La tarea principal de esta capa es el muestreo descendente, lo que significa que opera de forma independiente en cada porción de la entrada y la redimensiona espacialmente.

  • FC- Se llama capa totalmente conectada o más específicamente capa de salida. Se utiliza para calcular la puntuación de la clase de salida y la salida resultante es el volumen del tamaño 1 * 1 * L donde L es el número correspondiente a la puntuación de la clase.

El siguiente diagrama representa la arquitectura típica de las CNN

Creando la estructura de CNN

Hemos visto la arquitectura y los conceptos básicos de CNN, ahora vamos a construir una red convolucional usando CNTK. Aquí, primero veremos cómo armar la estructura de la CNN y luego veremos cómo entrenar los parámetros de la misma.

Por fin veremos cómo podemos mejorar la red neuronal cambiando su estructura con varias configuraciones de capas diferentes. Vamos a utilizar el conjunto de datos de imágenes MNIST.

Entonces, primero creemos una estructura de CNN. Generalmente, cuando creamos una CNN para reconocer patrones en imágenes, hacemos lo siguiente:

  • Usamos una combinación de capas de convolución y agrupación.

  • Una o más capas ocultas al final de la red.

  • Finalmente, terminamos la red con una capa softmax para fines de clasificación.

Con la ayuda de los siguientes pasos, podemos construir la estructura de la red.

Step 1- Primero, necesitamos importar las capas requeridas para CNN.

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling

Step 2- A continuación, necesitamos importar las funciones de activación para CNN.

from cntk.ops import log_softmax, relu

Step 3- Después de eso, para inicializar las capas convolucionales más tarde, necesitamos importar el glorot_uniform_initializer como sigue

from cntk.initializer import glorot_uniform

Step 4- A continuación, para crear variables de entrada, importe el input_variablefunción. E importardefault_option función, para facilitar un poco la configuración de NN.

from cntk import input_variable, default_options

Step 5- Ahora para almacenar las imágenes de entrada, cree una nueva input_variable. Contendrá tres canales, a saber, rojo, verde y azul. Tendría el tamaño de 28 por 28 píxeles.

features = input_variable((3,28,28))

Step 6−A continuación, necesitamos crear otro input_variable para almacenar las etiquetas para predecir.

labels = input_variable(10)

Step 7- Ahora, necesitamos crear el default_optionpara la NN. Y necesitamos usar elglorot_uniform como función de inicialización.

with default_options(initialization=glorot_uniform, activation=relu):

Step 8- A continuación, para establecer la estructura de la NN, necesitamos crear una nueva Sequential conjunto de capas.

Step 9- Ahora necesitamos agregar un Convolutional2D capa con una filter_shape de 5 y un strides ajuste de 1, dentro de Sequentialconjunto de capas. Además, habilite el relleno, de modo que la imagen se rellene para conservar las dimensiones originales.

model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),

Step 10- Ahora es el momento de agregar un MaxPooling capa con filter_shape de 2, y un strides ajuste de 2 para comprimir la imagen a la mitad.

MaxPooling(filter_shape=(2,2), strides=(2,2)),

Step 11- Ahora, como hicimos en el paso 9, necesitamos agregar otro Convolutional2D capa con una filter_shape de 5 y un stridesajuste de 1, utilice 16 filtros. Además, habilite el relleno, para que se mantenga el tamaño de la imagen producida por la capa de agrupación anterior.

Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),

Step 12- Ahora, como hicimos en el paso 10, agregue otro MaxPooling capa con una filter_shape de 3 y un strides ajuste de 3 para reducir la imagen a un tercio.

MaxPooling(filter_shape=(3,3), strides=(3,3)),

Step 13- Por último, agregue una capa Densa con diez neuronas para las 10 clases posibles que la red puede predecir. Para convertir la red en un modelo de clasificación, utilice unlog_siftmax función de activación.

Dense(10, activation=log_softmax)
])

Ejemplo completo para crear una estructura CNN

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)

Entrenando CNN con imágenes

Como hemos creado la estructura de la red, es hora de entrenar la red. Pero antes de comenzar el entrenamiento de nuestra red, necesitamos configurar fuentes de minibatch, porque entrenar un NN que trabaja con imágenes requiere más memoria que la mayoría de las computadoras.

Ya hemos creado fuentes de minibatch en secciones anteriores. A continuación se muestra el código Python para configurar dos fuentes de minibatch:

Como tenemos el create_datasource función, ahora podemos crear dos fuentes de datos separadas (entrenamiento y prueba uno) para entrenar el modelo.

train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)

Ahora, ya que hemos preparado las imágenes, podemos empezar a entrenar a nuestra NN. Como hicimos en secciones anteriores, podemos usar el método de entrenamiento en la función de pérdida para iniciar el entrenamiento. A continuación se muestra el código para esto:

from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)

Con la ayuda del código anterior, hemos configurado la pérdida y el aprendizaje para la NN. El siguiente código entrenará y validará el NN−

from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   labels: train_datasource.streams.labels
}
loss.train(train_datasource,
     max_epochs=10,
     minibatch_size=64,
     epoch_size=60000,
        parameter_learners=[learner],
     model_inputs_to_streams=input_map,
     callbacks=[progress_writer, test_config])

Ejemplo de implementación completo

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
   mapping_file = os.path.join(folder, 'mapping.bin')
   image_transforms = []
   if train:
    image_transforms += [
     xforms.crop(crop_type='randomside', side_ratio=0.8),
     xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
   stream_definitions = StreamDefs(
   features=StreamDef(field='image', transforms=image_transforms),
    labels=StreamDef(field='label', shape=10)
)
   deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
   loss = cross_entropy_with_softmax(output, targets)
   metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   labels: train_datasource.streams.labels
}
loss.train(train_datasource,
     max_epochs=10,
     minibatch_size=64,
     epoch_size=60000,
        parameter_learners=[learner],
     model_inputs_to_streams=input_map,
     callbacks=[progress_writer, test_config])

Salida

-------------------------------------------------------------------
average  since  average  since  examples
loss     last   metric   last
------------------------------------------------------
Learning rate per minibatch: 0.2
142      142      0.922   0.922    64
1.35e+06 1.51e+07 0.896   0.883    192
[………]

Transformaciones de imagen

Como hemos visto, es difícil entrenar las NN utilizadas para el reconocimiento de imágenes y también requieren una gran cantidad de datos para entrenar. Un problema más es que tienden a sobreajustarse en las imágenes utilizadas durante el entrenamiento. Veamos con un ejemplo, cuando tenemos fotos de rostros en posición vertical, nuestro modelo tendrá dificultades para reconocer rostros que estén girados en otra dirección.

Para superar este problema, podemos utilizar el aumento de imágenes y CNTK admite transformaciones específicas al crear fuentes de minibatch para imágenes. Podemos usar varias transformaciones de la siguiente manera:

  • Podemos recortar aleatoriamente las imágenes utilizadas para el entrenamiento con solo unas pocas líneas de código.

  • También podemos utilizar una escala y un color.

Veamos con la ayuda del siguiente código de Python, cómo podemos cambiar la lista de transformaciones al incluir una transformación de recorte dentro de la función utilizada para crear la fuente del minibatch anteriormente.

import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
   mapping_file = os.path.join(folder, 'mapping.bin')
   image_transforms = []
   if train:
   image_transforms += [
     xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
   stream_definitions = StreamDefs(
   features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
   deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)

Con la ayuda del código anterior, podemos mejorar la función para incluir un conjunto de transformaciones de imagen, de modo que, cuando estemos entrenando, podamos recortar la imagen aleatoriamente, de modo que obtengamos más variaciones de la imagen.

CNTK - Red neuronal recurrente

Ahora, entendamos cómo construir una red neuronal recurrente (RNN) en CNTK.

Introducción

Aprendimos a clasificar imágenes con una red neuronal y es uno de los trabajos icónicos del aprendizaje profundo. Pero, otra área en la que sobresale la red neuronal y se están realizando muchas investigaciones son las redes neuronales recurrentes (RNN). Aquí, vamos a saber qué es RNN y cómo se puede utilizar en escenarios en los que necesitamos lidiar con datos de series de tiempo.

¿Qué es la red neuronal recurrente?

Las redes neuronales recurrentes (RNN) pueden definirse como la clase especial de NN que son capaces de razonar a lo largo del tiempo. Los RNN se utilizan principalmente en escenarios, en los que debemos tratar con valores que cambian con el tiempo, es decir, datos de series de tiempo. Para entenderlo de una mejor manera, hagamos una pequeña comparación entre las redes neuronales regulares y las redes neuronales recurrentes:

  • Como sabemos, en una red neuronal normal, solo podemos proporcionar una entrada. Esto lo limita a resultados en una sola predicción. Para darle un ejemplo, podemos traducir un texto usando redes neuronales regulares.

  • Por otro lado, en las redes neuronales recurrentes, podemos proporcionar una secuencia de muestras que resulten en una sola predicción. En otras palabras, usando RNN podemos predecir una secuencia de salida basada en una secuencia de entrada. Por ejemplo, ha habido bastantes experimentos exitosos con RNN en tareas de traducción.

Usos de la red neuronal recurrente

Los RNN se pueden utilizar de varias formas. Algunos de ellos son los siguientes:

Predecir una única salida

Antes de profundizar en los pasos, sobre cómo RNN puede predecir una salida única basada en una secuencia, veamos cómo se ve un RNN básico.

Como podemos en el diagrama anterior, RNN contiene una conexión de bucle invertido a la entrada y siempre que alimentamos una secuencia de valores procesará cada elemento en la secuencia como pasos de tiempo.

Además, debido a la conexión de bucle invertido, RNN puede combinar la salida generada con la entrada para el siguiente elemento de la secuencia. De esta manera, RNN construirá una memoria sobre toda la secuencia que se puede usar para hacer una predicción.

Para hacer predicciones con RNN, podemos realizar los siguientes pasos:

  • Primero, para crear un estado oculto inicial, necesitamos alimentar el primer elemento de la secuencia de entrada.

  • Después de eso, para producir un estado oculto actualizado, necesitamos tomar el estado oculto inicial y combinarlo con el segundo elemento en la secuencia de entrada.

  • Por último, para producir el estado oculto final y predecir la salida para el RNN, necesitamos tomar el elemento final en la secuencia de entrada.

De esta manera, con la ayuda de esta conexión de bucle invertido, podemos enseñarle a un RNN a reconocer patrones que ocurren con el tiempo.

Predecir una secuencia

El modelo básico, discutido anteriormente, de RNN también se puede extender a otros casos de uso. Por ejemplo, podemos usarlo para predecir una secuencia de valores basados ​​en una sola entrada. En este escenario, para poder realizar predicciones con RNN podemos realizar los siguientes pasos:

  • Primero, para crear un estado oculto inicial y predecir el primer elemento en la secuencia de salida, necesitamos alimentar una muestra de entrada a la red neuronal.

  • Después de eso, para producir un estado oculto actualizado y el segundo elemento en la secuencia de salida, necesitamos combinar el estado oculto inicial con la misma muestra.

  • Por último, para actualizar el estado oculto una vez más y predecir el elemento final en la secuencia de salida, alimentamos la muestra otra vez.

Predicción de secuencias

Como hemos visto, cómo predecir un valor único en función de una secuencia y cómo predecir una secuencia en función de un valor único. Ahora veamos cómo podemos predecir secuencias para secuencias. En este escenario, para poder realizar predicciones con RNN podemos realizar los siguientes pasos:

  • Primero, para crear un estado oculto inicial y predecir el primer elemento en la secuencia de salida, necesitamos tomar el primer elemento en la secuencia de entrada.

  • Después de eso, para actualizar el estado oculto y predecir el segundo elemento en la secuencia de salida, necesitamos tomar el estado oculto inicial.

  • Por último, para predecir el elemento final en la secuencia de salida, necesitamos tomar el estado oculto actualizado y el elemento final en la secuencia de entrada.

Trabajo de RNN

Para comprender el funcionamiento de las redes neuronales recurrentes (RNN), primero debemos comprender cómo funcionan las capas recurrentes en la red. Primero, analicemos cómo podemos predecir la salida con una capa recurrente estándar.

Predicción de salida con capa RNN estándar

Como comentamos anteriormente, también, una capa básica en RNN es bastante diferente de una capa regular en una red neuronal. En la sección anterior, también demostramos en el diagrama la arquitectura básica de RNN. Para actualizar el estado oculto por primera vez, podemos usar la siguiente fórmula:

En la ecuación anterior, calculamos el nuevo estado oculto calculando el producto escalar entre el estado oculto inicial y un conjunto de pesos.

Ahora, para el siguiente paso, el estado oculto para el paso de tiempo actual se usa como el estado oculto inicial para el siguiente paso de tiempo en la secuencia. Es por eso que, para actualizar el estado oculto por el segundo paso de tiempo, podemos repetir los cálculos realizados en el primer paso de la siguiente manera:

A continuación, podemos repetir el proceso de actualización del estado oculto para el tercer y último paso de la secuencia como se muestra a continuación:

Y cuando hayamos procesado todos los pasos anteriores en la secuencia, podemos calcular la salida de la siguiente manera:

Para la fórmula anterior, hemos utilizado un tercer conjunto de pesos y el estado oculto del paso de tiempo final.

Unidades recurrentes avanzadas

El problema principal con la capa recurrente básica es el problema del gradiente que desaparece y, debido a esto, no es muy bueno para aprender correlaciones a largo plazo. En palabras simples, la capa recurrente básica no maneja muy bien las secuencias largas. Esa es la razón por la que algunos otros tipos de capas recurrentes que son mucho más adecuados para trabajar con secuencias más largas son los siguientes:

Memoria a largo plazo (LSTM)

Las redes de memoria a largo plazo a corto plazo (LSTM) fueron introducidas por Hochreiter & Schmidhuber. Resolvió el problema de conseguir una capa recurrente básica para recordar cosas durante mucho tiempo. La arquitectura de LSTM se muestra arriba en el diagrama. Como podemos ver, tiene neuronas de entrada, células de memoria y neuronas de salida. Para combatir el problema del gradiente de desaparición, las redes de memoria a corto y largo plazo utilizan una celda de memoria explícita (almacena los valores anteriores) y las siguientes puertas:

  • Forget gate- Como su nombre lo indica, le dice a la celda de memoria que olvide los valores anteriores. La celda de memoria almacena los valores hasta que la puerta, es decir, "puerta olvidada", le dice que los olvide.

  • Input gate- Como su nombre lo indica, agrega cosas nuevas a la celda.

  • Output gate- Como su nombre lo indica, la puerta de salida decide cuándo pasar los vectores de la celda al siguiente estado oculto.

Unidades recurrentes cerradas (GRU)

Gradient recurrent units(GRU) es una ligera variación de la red LSTM. Tiene una puerta menos y está cableado ligeramente diferente a los LSTM. Su arquitectura se muestra en el diagrama anterior. Tiene neuronas de entrada, células de memoria cerradas y neuronas de salida. La red de unidades recurrentes cerradas tiene las dos puertas siguientes:

  • Update gate- Determina las siguientes dos cosas:

    • ¿Qué cantidad de información debe mantenerse del último estado?

    • ¿Qué cantidad de información se debe dejar entrar de la capa anterior?

  • Reset gate- La funcionalidad de la puerta de reinicio es muy parecida a la de la puerta de olvido de la red de LSTM. La única diferencia es que se ubica de manera ligeramente diferente.

A diferencia de la red de memoria a largo plazo, las redes de unidades periódicas cerradas son un poco más rápidas y fáciles de ejecutar.

Creando estructura RNN

Antes de que podamos comenzar a hacer predicciones sobre la salida de cualquiera de nuestras fuentes de datos, primero debemos construir RNN y la construcción de RNN es bastante similar a como construimos una red neuronal regular en la sección anterior. A continuación se muestra el código para construir uno

from cntk.losses import squared_error
from cntk.io import CTFDeserializer, MinibatchSource, INFINITELY_REPEAT, StreamDefs, StreamDef
from cntk.learners import adam
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
BATCH_SIZE = 14 * 10
EPOCH_SIZE = 12434
EPOCHS = 10

Replanteo de múltiples capas

También podemos apilar múltiples capas recurrentes en CNTK. Por ejemplo, podemos usar la siguiente combinación de capas:

from cntk import sequence, default_options, input_variable
from cntk.layers import Recurrence, LSTM, Dropout, Dense, Sequential, Fold
features = sequence.input_variable(1)
with default_options(initial_state = 0.1):
   model = Sequential([
      Fold(LSTM(15)),
      Dense(1)
   ])(features)
target = input_variable(1, dynamic_axes=model.dynamic_axes)

Como podemos ver en el código anterior, tenemos las siguientes dos formas en las que podemos modelar RNN en CNTK:

  • Primero, si solo queremos el resultado final de una capa recurrente, podemos usar el Fold capa en combinación con una capa recurrente, como GRU, LSTM o incluso RNNStep.

  • En segundo lugar, como una forma alternativa, también podemos utilizar el Recurrence bloquear.

Entrenamiento de RNN con datos de series de tiempo

Una vez que construimos el modelo, veamos cómo podemos entrenar a RNN en CNTK -

from cntk import Function
@Function
def criterion_factory(z, t):
   loss = squared_error(z, t)
   metric = squared_error(z, t)
   return loss, metric
loss = criterion_factory(model, target)
learner = adam(model.parameters, lr=0.005, momentum=0.9)

Ahora, para cargar los datos en el proceso de entrenamiento, debemos deserializar secuencias de un conjunto de archivos CTF. El siguiente código tiene elcreate_datasource , que es una función de utilidad útil para crear la fuente de datos de entrenamiento y prueba.

target_stream = StreamDef(field='target', shape=1, is_sparse=False)
features_stream = StreamDef(field='features', shape=1, is_sparse=False)
deserializer = CTFDeserializer(filename, StreamDefs(features=features_stream, target=target_stream))
   datasource = MinibatchSource(deserializer, randomize=True, max_sweeps=sweeps)
return datasource
train_datasource = create_datasource('Training data filename.ctf')#we need to provide the location of training file we created from our dataset.
test_datasource = create_datasource('Test filename.ctf', sweeps=1) #we need to provide the location of testing file we created from our dataset.

Ahora que hemos configurado las fuentes de datos, el modelo y la función de pérdida, podemos comenzar el proceso de entrenamiento. Es bastante similar a lo que hicimos en secciones anteriores con redes neuronales básicas.

progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   target: train_datasource.streams.target
}
history = loss.train(
   train_datasource,
   epoch_size=EPOCH_SIZE,
   parameter_learners=[learner],
   model_inputs_to_streams=input_map,
   callbacks=[progress_writer, test_config],
   minibatch_size=BATCH_SIZE,
   max_epochs=EPOCHS
)

Obtendremos una salida similar a la siguiente:

Salida−

average  since  average  since  examples
loss      last  metric  last
------------------------------------------------------
Learning rate per minibatch: 0.005
0.4      0.4    0.4      0.4      19
0.4      0.4    0.4      0.4      59
0.452    0.495  0.452    0.495   129
[…]

Validando el modelo

En realidad, rechazar con un RNN es bastante similar a hacer predicciones con cualquier otro modelo CNK. La única diferencia es que necesitamos proporcionar secuencias en lugar de muestras individuales.

Ahora, cuando nuestro RNN finalmente haya terminado con el entrenamiento, podemos validar el modelo probándolo usando algunas secuencias de muestras de la siguiente manera:

import pickle
with open('test_samples.pkl', 'rb') as test_file:
test_samples = pickle.load(test_file)
model(test_samples) * NORMALIZE

Salida−

array([[ 8081.7905],
[16597.693 ],
[13335.17 ],
...,
[11275.804 ],
[15621.697 ],
[16875.555 ]], dtype=float32)