sábado, 16 de julio de 2022

Ajuste de redes densas mediante hyperas

Vamos a ver cómo seleccionar y ajustar hiperparámetros para redes neuronales densas usando hiperparámetros.

Antes de comenzar a usar hyperas, debemos comprender la biblioteca de Python llamada hyperopt. Hyperopt proporciona la capacidad de optimizar los espacios de búsqueda de dimensiones reales, valoradas, discretas y condicionales. Hyperas,  es un envoltorio alrededor de hyperopt para una creación de prototipos más rápida utilizando varios modelos de redes neuronales de Keras. Podemos usar hyperas para aprovechar el poder de los hyperopt sin tener que aprender una sintaxis sofisticada.

Definimos un modelo de Keras usando una notación de plantilla simple para definir los hiperparámetros a ajustar para obtener un modelo de red neuronal sintonizado. Es posible que nuestras máquinas tradicionales no puedan proporcionar la potencia informática necesaria para escribir aplicaciones que requieran hardware sofisticado y potencia de procesamiento. Google Colab,  puede incluso fallar cuando queremos trabajar con mecanismos  sofisticados de aprendizaje de redes neuronales.

En tales casos, optamos por un servicio en la nube. Un ejemplo destacado es AWS SageMaker. Podemos utilizar este servicio para definir, construir, entrenar y probar modelos de redes neuronales. Para comenzar a trabajar con  SageMaker, primero debemos iniciar sesión en la consola de administración de AWS desde la URL aws.amazon.com. Hacemos clic en la pestaña Iniciar sesión en la consola que se encuentra en la parte superior derecha de la página. Si no hemos iniciado sesión antes, se nos pedirá que proporcionemos nuestras credenciales de AWS.

 

Ajuste de redes densas mediante hyperas

Podemos usar el campo de búsqueda ubicado justo debajo de Buscar servicios, comenzamos a escribir la palabra SageMaker, y seleccionamos el servicio Amazon SageMaker. Queremos escribir una aplicación Python simple para utilizar las capacidades de hyperas para seleccionar y ajustar hiperparámetros mientras se construye una red neuronal.

Seleccionamos la opción Instancia de Notebook, del  menú izquierdo.

 

Amazon sagemaker

En la página de instancias de Notebook, se nos proporciona cierta información sobre la instancia de Notebook. Como el tipo de instancia, cuándo se creó y el estado actual. Podemos crear una nueva instancia, haciendo clic en el botón Create Notebook Instance. Utilizaremos la instancia existente, por lo que  hacemos clic en Abrir Jupyter en la pestaña Acciones.

 

redes neuronales con AWS Sagemaker

Seleccionamos el entorno Tensorflow que utilizaremos con Keras y en el cuaderno de jupyter escribimos:

! Pip install hyperas

! Pip install hyperopt

Estas dos declaraciones  instalarán hyperas e hyperopt usando el comando pip convencional de Python. Ejecutamos esta celda de código, haciendo clic en el botón de reproducción de radio ubicado justo al lado de la celda de código.

En la siguiente celda de código, importamos las bibliotecas y paquetes necesarios para construir un modelo de red neuronal y trabajar con hiperparámetros.

Estamos importando keras.models, keras.layers, keras.datasets y keras.utils. Este conjunto de importaciones proporcionará los datos junto con las capacidades esenciales de construir modelos de redes neuronales utilizando varios tipos de capas y funciones de activación.

from __future__ import print_function

from hyperopt import trials, STATUS_OK, tpe

from hyperas import optim

from hyperas.distributions import choice, uniform

from keras.models import Sequential

from keras.layers.core import Dense, Dropout, Activation

from keras.datasets import mnist

from keras.utils import np_utils

A veces, podemos obtener un error si TensorFlow no está instalado y configurado correctamente. La siguiente tarea es definir una función para preparar el modelo de datos. Esta función está separada del modelo de red para garantizar que no necesitemos volver a cargar los datos cada vez que queramos evaluar o volver a ejecutar el modelo.

Estamos construyendo conjuntos de datos X_train, Y_train, X_test e Y_test. Estos son los conjuntos de datos de entrenamiento y prueba. Cargamos los datos usando la declaración, mnist.load_data. Es una función de mnist y mnist es un modelo de datos que importamos de Keras en la celda de código anterior.

def data():

    (X_train, y_train), (x_test, y_test) = mnist.load_data ()

A continuación, rellenamos los conjuntos de datos X_train y X_test con los datos de mnist.

      X_train = X_train.reshape (60000, 784)

    X_test = X_test.reshape (10000, 784)

Hemos tomado 60000 y 784 como dimensiones para X_train. Y hemos hecho lo mismo para X_test, donde la dimensión es 10000 y 784. Después vinculamos X_train y X_test con un tipo de datos particular usando la declaración astype float32. usamos la función astype y pasamos el tipo de datos como float32.

       X_train = X_train.astype ('float32')

    X_test = X_test.astype ('float32')

Después factorizamos los datos en los conjuntos de datos de prueba y X_train. dividimos los datos de X_train y los conjuntos de datos de prueba entre 255.  Y especificamos el número de clases para la clasificación.

      X_train /= 255

    X_test /= 255

Suponemos que el número de clases es 10 convertimos Y_train y los conjuntos de datos de prueba en una matriz de clases categórica o binaria pasando los respectivos conjuntos de datos en el número de clases.

Finalmente, devolvemos X_train, Y_train, X_test y Y_test.

       nb_classes = 10

    Y_train = np_utils.to_categorical (y_train, nb_classes)

    Y_test = np_utils.to_categorical (y_test, nb_classes)

    return X_train, Y_train, X_test, Y_test


En conjunto la celda quedará

def data():

    (X_train, y_train), (x_test, y_test) = mnist.load_data ()

    X_train = X_train.reshape (60000, 784)

    X_test = X_test.reshape (10000, 784)

    X_train = X_train.astype ('float32')

    X_test = X_test.astype ('float32')

    X_train /= 255

    X_test /= 255

    nb_classes = 10

    Y_train = np_utils.to_categorical (y_train, nb_classes)

    Y_test = np_utils.to_categorical (y_test, nb_classes)

    return X_train, Y_train, X_test, Y_test

Hemos creado un modelo de datos que podemos usar para construir y entrenar el modelo de red neuronal. El siguiente paso es construir un modelo de red neuronal. El tipo de modelo que estamos construyendo es un modelo secuencial.

def model (X_train, Y_train, X_test, Y_test):

Agregando una capa densa, que es una operación lineal, donde cada entrada se conectará a cada salida con ciertos pesos, y estamos pasando la forma y las dimensiones de la entrada.

  model = Sequential()

Esta será la capa de entrada, y para esta capa estamos usando la función de activación relu.

    model.add (Dense (512, input_shape = (784,)))

    model.add (Activation ('relu'))

A continuación, agregaremos una capa de salida para garantizar que algunos de los elementos se puedan reducir. Después de agregar la capa de entrada, estamos agregando una capa oculta usando la operación lineal densa a la que estamos pasando la opción.

     model.add (Dropout({{uniform (0, 1)}}))

   model.add (Dense({{choice([256, 512, 1024])}}))

   model.add (Activation({{choice(['relu','sigmoid'])}}))

Hemos agregado múltiples capas para construir nuestra red neuronal.

       model.add (Dropout({{uniform (0, 1)}}))

Después de agregar las capas de entrada y ocultas, especificamos una declaración if. Si nuestra elección es cuatro, la declaración agregará otra capa, pero si nuestra elección es tres, usaremos las capas existentes que hemos agregado. También hemos especificado las declaraciones para agregar la cuarta capa, y finalmente estamos agregando la capa de salida utilizando la declaración model.add dense.

if {{choice(['three', 'four'])}} == 'four':

    model.add (Dense (100))

    model.add ({{choice ([Dropout (0.5), Activation ('linear')])}})

    model.add (Activación ('relu'))

    model.add (Dense (10))

Y estamos usando la función de activación softmax para la capa de salida.

model.add (Activación ('softmax'))

Así que hemos definido nuestro modelo de red neuronal que contiene múltiples capas, incluida una capa de entrada y una de salida. La celda completa queda:

def model (X_train, Y_train, X_test, Y_test):

   

    model = Sequential()

    model.add (Dense (512, input_shape = (784,)))

    model.add (Activation ('relu'))

    model.add (Dropout({{uniform (0, 1)}}))

    model.add (Dense({{choice([256, 512, 1024])}}))

    model.add (Activation({{choice(['relu','sigmoid'])}}))

    model.add (Dropout({{uniform (0, 1)}}))

 

if {{choice(['three', 'four'])}} == 'four':

    model.add (Dense (100))

    model.add ({{choice ([Dropout (0.5), Activation ('linear')])}})

    model.add (Activación ('relu'))

    model.add (Dense (10))

    model.add (Activación ('softmax'))

La capa de entrada usa relu como función de activación, la capa de salida usa softmax como función de activación, y las capas ocultas o intermedias usan diferentes funciones de activación. Después de definir las capas para el modelo de red neuronal, la siguiente tarea es compilarlo.

Para compilar el modelo, estamos usando la función del modelo llamada compilar, a la que le estamos pasando la entropía cruzada categórica como función de pérdida, ya que hemos convertido el conjunto de datos en categórico.

model.compile(loss = 'categorical_crossentropy',

          optimizer = {{choice (['rmsprop', 'adam', 'sgd'])}},

          metrics = ['accuracy'])

El segundo argumento es el optimizador. Se utiliza para indicar cómo se debe compilar el modelo o crear una instancia de un objeto. Se especifican tres opciones de optimizador diferentes, rmsprop, adam y sgd, que es la abreviatura de descenso de gradiente estocástico.

El tercer y último argumento que hemos pasado es métrica que le ponemos  precisión. Después de compilar el modelo, la siguiente tarea es ajustar el modelo con los conjuntos de datos de entrenamiento.

Estamos usando la función ajustada a la que estamos pasando los conjuntos de datos X e Y_train. Estamos pasando el tamaño del lote, la elección del tamaño del lote es 64 y 128.

model.fit (X_train, Y_train ,

    batch_size = {{choice ([64, 128])}},

    nb_epoch = 1,

    verbose = 2,

    validation_data = (X_test, Y_test))

Estamos pasando el número de épocas para la propagación hacia adelante y hacia atrás, y estamos configurando el detallado (verbose) en 2. También estamos pasando otro argumento importante en forma de datos de validación, que se utilizarán para validar el modelo de red neuronal. Los datos de validación que hemos especificado son los conjuntos de datos X e Y_test.

Después de validar el modelo, evaluaremos el modelo y el resultado de la evaluación que estamos usando es la puntuación y la precisión. Estamos usando la función evaluar a la que le estamos pasando los conjuntos de datos X e Y_test seguidos por el detallado que se establece en 0.

score, acc = model.evaluate (X_test, Y_test, verbose = 0)

Hemos establecido verbose en 0 ya que no queremos ningún resultado adicional. Finalmente, imprimimos la precisión de la prueba y devolvemos el factor de pérdida, el estado y el modelo.

print ('Exactitud de la prueba:', acc)

return {'loss': -acc, 'status': STATUS_OK, 'model': model}

Tenemos que asegurarnos de que estamos especificando valores adecuados. Por ejemplo, hemos especificado menos precisión –acc para el factor de pérdida, STATUS_OK para el modelo de estado, y model para el nombre de nuestro modelo de red neuronal. 

Hemos definido nuestra red neuronal, hemos compilado el modelo y hemos aplicado los conjuntos de entrenamiento junto con los datos de validación para asegurar que el modelo esté validado y probado.

Para ejecutar el modelo, hyperas proporciona la función optim.minimize.

appropiate_run, appropiate_model = optim.minimize (model = model,

data = data,

max_evals = 10,

algo = tpe.suggest,

notebook_name = 'nombre_notebook_de_jupyter', #ojo, esto es importante

trial = Trials ())

Tenemos que pasar el modelo, los datos, el número máximo de evaluaciones que queremos realizar, y el algoritmo que queremos utilizar, que en este caso se sugiere. También tenemos que pasar el nombre del cuaderno, que es el mismo que el del archivo. Y finalmente, también tenemos que aprobar los ensayos, lo que indica el número de ensayos que se realizarán para el modelo actual, con el fin de proporcionar un modelo adecuado y un resultado de ejecución adecuado.

Tras la ejecución, se nos proporcionan ciertos mensajes de registro de salida. Navegaremos más hacia abajo para explorar los resultados del modelo. Podemos observar que el modelo se entrenó con 60.000 muestras y ha utilizado otras 10.000 muestras para su validación. Se ejecutó una sola iteración y se nos proporciona el tiempo que tomó completar la ejecución, seguido del factor de pérdida, precisión, pérdida de validación y precisión de validación.

El resultado final que obtenemos es la precisión de la prueba. Obtendremos 10 resultados de precisión de prueba diferentes, ya que hemos especificado 10 evaluaciones en la celda de código.

Tenemos que esperar a que se completen las validaciones antes de poder observar el resultado final. Se nos proporciona la precisión de la prueba final, que es de 0,96. Se ejecutaron diez de cada diez épocas de validación.

La salida también incluye el mejor factor de pérdida y el tiempo que tomó completar la validación.

El resultado final es el resultado de la selección de hiperparámetros y el ajuste que facilitamos usando hyperas cuando estábamos ejecutando el modelo de red neuronal. Podemos seleccionar diferentes hiperparámetros o ajustar las selecciones de hiperparámetros existentes. Por ejemplo, podemos cambiar las evaluaciones máximas, podemos cambiar el número de épocas, incluso podemos cambiar el tamaño del lote y ejecutar el modelo. Podemos continuar este proceso hasta q


sábado, 9 de julio de 2022

Curso avanzado de C#. Creación e implementación de jerarquías de clases

Heredar de una clase base La sección "Creación de tipos de referencia", explica cómo crear clases. El siguiente código muestra la definición de una clase Persona simple y debe ser familiar para  nosotros

Public Class Persona

{

       Public String Nombre { Get; Set; }

       Public String Apellido { Get; Set; }

       Public Persona(String nombre, String apellido)

       {

             // Valida el nombre y el apellido

             If (( nombre == null) || (nombre .Length < 1))

                    Throw New ArgumentOutOfRangeException(

                    "Nombre", nombre,

                    "El nombre no puede ser nulo o quedar en blanco.");

             If ((apellido == null) || (apellido .Length < 1))

                    Throw New ArgumentOutOfRangeException(

                    "Apellido", apellido,

                    "El  apellido no puede ser nulo o quedar en blanco.");

                    // Guarda el nombre y el apellido.

                    Nombre = nombre;

                    Apellido = apellido;

       }

}

La clase Persona contiene dos propiedades de cadena implementadas automáticamente: Nombre y Apellido. (Una clase utilizada por una aplicación real probablemente tendría muchas más propiedades para contener información como como la dirección postal, números de teléfono y direcciones de correo electrónico). Nuestro constructor toma los nombres y apellidos como parámetros, realiza alguna validación y guarda los valores en las propiedades Nombre y Apellido.

Curso avanzado de C#. Creación e implementación de jerarquías de clases
Fotos similares a esta aquí


Ahora supongamos que queremos  crear una clase de Empleado que tenga las propiedades Nombre, Apellido y NombreDepartamento. Podemos construir esta clase desde cero, pero necesitaremos las mismas propiedades que las de la clase Persona y necesitaremos las mismas validaciones, por lo que crearlo desde cero requeriría duplicar  todo ese código. Una mejor solución es derivar la clase Empleado de la clase Persona para que herede de la clase padre los campos, propiedades, métodos y eventos. Un empleado es una especie de persona, por lo que tiene sentido que la clase Empleado derive desde la clase Persona. No hay ninguna razón por la que el mismo código dentro de la clase Persona no funcionara también para los objetos  de la clase Empleado. 

Terminología de clases

Hay mucha terminología en torno a las jerarquías de clases. Cuando derivamos una clase de otra, la nueva clase hereda todo el código incluido en la clase original. En este caso, la clase original se llama padre clase, clase base o superclase. La nueva clase se llama clase derivada, hija, secundaria, o subclase. Derivar una clase de otra se llama subclasificación. 

_________________________________________________


Para derivar una clase de otra, simplemente hay que poner el nombre de la clase con dos puntos y luego el nombre de la clase principal. El siguiente código muestra una clase  empleado que se deriva de la clase persona. 

Public Class Empleado :  Persona

{

    Public String NombreDepartamento { Get; Set; }

}

En este ejemplo, la clase Empleado hereda los campos, propiedades, métodos y eventos definidos por la clase Persona. También agrega una nueva propiedad, Nombre Departamento. Aunque una clase secundaria hereda la mayoría del código en su clase padre, no hereda el constructor de la clase. En este punto, un programa podría utilizar el siguiente código para crear un objeto Empleado sin inicializar sus propiedades Nombre y Apellido:

Empleado empleado = new Empleado();

Dado que este código no inicializa las propiedades Nombre y Apellido del empleado, estas tienen los valores nulos, lo que anula el propósito del constructor de la clase Persona. La solución es hacer que los constructores de la clase secundaria llamen a los constructores de la clase principal. 

Llamar a constructores de clases principales 

Para asegurarse de que se llama al constructor de la clase Persona para validar el Nombre y Apellido del empleado. Debemos darle un constructor a la clase Empleado, con  una lista de argumentos del constructor seguida por dos puntos, la clase base y cualquier parámetro que deseemos pasar al constructor de la clase base.

En este ejemplo, el constructor Empleado debe pasar el nombre y apellido que recibe al Constructor de la clase de persona. El código resaltado muestra dónde el constructor llama al constructor de la clase base : 

Public Class Empleado :  Persona

{

      Public String NombreDepartamento { Get; Set; }

      Public Empleado(String Nombre, string Apellido,

      string nombredepartamento)

            :base(Nombre, Apellido)

      {

            // Valida NombreDepartamento.

            If ((nombredepartamento == null) || (nombredepartamento.Length < 1))

            Throw New ArgumentOutOfRangeException(

            "nombredepartmento", nombredepartmento,

            "NombreDepartamento no debe ser nulo o estar en vacío.");

            // Graba el Nombre del Departamento.

            NombreDepartmento = nombreDepartmento;

      }

}

Si la clase base tiene varios constructores, la clase secundaria puede usar la palabra clave base para invocar cualquiera de ellos. El programa usa los argumentos que siguen a la palabra clave base para averiguar qué constructor utilizar. 

Nota: Cuando un constructor utiliza la palabra clave base para invocar un constructor de la clase base, El constructor de la clase base se ejecuta antes que el cuerpo del hijo. 

Si tanto la clase principal como la secundaria tienen constructores, el constructor de la clase secundaria debe invocar uno de los constructores de la clase padre. Esto significa que la llamada al constructor en la clase base que hemos resaltado arriba, requiere un fragmento de código. Si eliminamos ese código, Visual Studio muestra el mensaje de error "JerarquiaPersona no contiene un constructor que tome 0 argumentos". (Aquí, JerarquiaPersona es el espacio de nombres que contiene la clase Persona.) El constructor de la clase Empleado está tratando implícitamente de acceder a un constructor de Persona que no toma parámetros y no puede encontrar uno. Una rareza de este sistema es que podemos crear una clase Empleado sin constructores aunque  permite al programa crear una instancia de la clase Empleado sin invocar un constructor de la clase Persona. Eso significa que la siguiente definición para la clase Empleado es legal: 

Public Class Empleado :  Persona

{

      Public String NombreDepartamento { Get; Set; }

}

Si deseamos evitar que el programa eluda los constructores de la clase principal, debemos dotar la clase secundaria de al menos un constructor.

Llamar a constructores de la misma clase 

A menudo, es conveniente dar a una clase varios constructores para realizar diferentes tipos de inicialización. Dependiendo de qué parámetros se pasen al constructor. En ese caso, varios constructores puede que necesiten realizar las mismas tareas. Por ejemplo, supongamos que la clase Persona tiene las propiedades Nombre y Apellido y queremos permitir que el programa cree un objeto Persona especificando solo el nombre o nombre y apellido. 

Class Persona

{

     Public String Nombre { Get; Set; }

     Public String Apellido { Get; Set; }

     // Constructor con nombre.

     Public Persona(String nombre)

     {

          Nombre = nombre;

     }

     // Constructor con Nombre y Apellido.

     Public Persona(String nombre, String apellido)

     {

          Nombre =  nombre;

          Apellido = apellido;

     }

}

El primer constructor toma un nombre como parámetro y lo almacena en la propiedad Nombre. El segundo constructor toma el nombre y el apellido como parámetros y guarda sus valores en las Propiedades Nombre y Apellido. En este código, el segundo constructor comienza realizando el mismo trabajo que el primer constructor hace cuando guarda el nombre. En un escenario mas complicado en el que los constructores realizan tareas más difíciles, esta repetición de código sería un problema. Significaría varias copias del mismo código para implementar, depurar y mantener. Una forma de evitar esta duplicación de código es hacer que un constructor llame a otro. En este podríamos reescribir el segundo constructor para que llame al primer constructor para que pueda manejar el parámetro de nombre. Para ello, hacemos que el constructor invoque a un segundo constructor de la misma manera que se invoca a un constructor de la  clase base, excepto que utiliza la palabra clave this en lugar de la palabra clave base. 

El siguiente código muestra cómo el segundo constructor de la clase Persona puede invocar a su primer constructor. Se resalta el código que invoca al primer constructor. 

// Constructor con Nombre y Apellido.

Public Persona(String nombre, String apellido)

      :this(nombre)

{

      Apellido = apellido;

}

Nota: Cuando un constructor utiliza la palabra clave this para invocar un segundo constructor en la misma clase, el segundo constructor se ejecuta antes de que se ejecute el cuerpo del primer constructor. 

Si derivamos la clase Empleado de la clase Persona y la clase Empleado incluye una propiedad NombreDepartamento. Es posible que queramos diferentes constructores de empleados que puedan tomar como parámetros nombre, nombre y apellido, o nombre y apellido y nombre de departamento. Estos constructores pueden utilizar la misma técnica que se muestra en esta versión de la clase Persona para hacer que los constructores más complicados invoquen a los más simples. Los constructores Empleado también pueden utilizar la palabra clave base descrita en la sección anterior para invocar a los constructores de la clase Persona. Por ejemplo, el constructor Empleado(nombre, apellido,nombredepartamento) podemos utilizar esta técnica para invocar al constructor Empleado( nombre, apellido) y ese constructor puede utilizar la palabra clave  base para invocar al constructor de Persona(nombre, apellido). 







sábado, 2 de julio de 2022

Curso de Photoshop: Balance de blancos

Utilizaremos el balance de blancos para eliminar los tonos amarillentos o azulados de nuestras fotos en interiores.

Para ello, vamos a Brigde y abrimos la foto con camera raw. 

Abrir en cámara raw adobe photoshop brigde


En la parte derecha arriba tenemos Equilibrio de blancos y 
una lista desplegable de la que podemos elegir el tipo de balance de blancos que deseemos.

Balance de blancos Photoshop


Así por ejemplo si hicimos la foto bajo luz fluorescente podemos elegir la opción de fluorescente o la de flash si 
hicimos la foto con flash.

Una vez elegido el balance de blancos predeterminado, podemos ajustarlo aun más desplazando las barras de temperatura y matiz si consideramos que la foto aun es demasiado cálida o fría. Teniendo en cuenta que no deberemos de desplazar estas barras exageradamente hacia la izquierda o la derecha.

Temperatura y matiz en balance de blancos


La barra de temperatura añadirá a la imagen colores más cálidos (amarillos) o más fríos (azules) y la de matiz se desplazará entre los colores rosados y los verdes.

Un método más exacto para ajustar el balance de blancos consiste en pulsar sobre la herramienta Equilibrio de blancos de la barra superior y después pinchar con ella sobre un área blanquecina o grisácea de nuestra foto, esto ajustará automáticamente nuestra foto.

Herramienta de Equilibrio de blancos Photoshop


Balance de blancos


Si no nos gusta el resultado, podemos pulsar sobre un área diferente hasta que el resultado sea el deseado.

Al fin y al cabo el balance de blancos es una decisión creativa de cada uno, de modo que si el anterior método aunque es el más exacto, no nos convence, podemos variarlo. Si el resultado de esta herramienta no nos convence, haciendo doble click sobre el icono de la herramienta de equilibrio de blancos, podemos volver al resultado inicial.

Si una vez elegida la herramienta de equilibrio de blancos hacemos click con el botón derecho del ratón sobre la foto, también se mostrará un menú como el del principio  botón.

Balance de blancos Brigde photoshop