Programación funcional para el aprendizaje profundo

Autor: Joyce Xu

Traductor:  Paula Vidal

Hasta hace poco tiempo atras, el concepto de “programación funcional” y “aprendizaje automático” se atribuía a dos mundos claramente separados. El primero es un paradigma de programación que ha ganado popularidad, cuando el mundo ha recurrido a la simplicidad y la modularidad para producir aplicaciones escalables complejas; el segundo es una herramienta utilizada para instruir una computadora como un autocomplementado de garabatos y el otro para componer música. Por lo tanto, no existia diálogo entre estos dos elementos.

Pero al estudiarlos y profundizarlos con cuidado, uno se da cuenta de que su superposición es práctica y teórica. En primer lugar, el aprendizaje automático no es un elemento en sí mismo, sino que, para que se aproveche mejor, debe incorporarse en aplicaciones escalables complejas. En segundo lugar, el aprendizaje automático, y en particular el aprendizaje profundo, es funcional en su diseño:

  • Los modelos de aprendizaje profundo estan compuestos en series: la programación funcional implica la composición de cadenas de funciones de orden superior para operar en estructuras de datos simples. Las redes neuronales están diseñadas de la misma manera, unidas las funciones de transformación de una capa a otra, para operar en una matriz simple de datos de entrada. De hecho, todo el proceso de aprendizaje profundo puede verse como la optimización de un conjunto de funciones compuestas. Esto significa que los modelos en sí mismos son intrínsecamente funcionales

 

  • Los componentes del aprendizaje profundo son inmutables: cuando aplicamos las funciones a los datos de entrada, nuestros datos no cambian, sino que se produce un nuevo conjunto de valores. Además, cuando los pesos están actualizados, no necesitan ser “cambiados” sino reemplazados por un nuevo valor. En teoría, la actualización de ponderación se puede aplicar en cualquier orden (es decir, no dependen uno del otro) y, por lo tanto, no es necesario realizar un seguimiento secuencial del cambio relativo.

 

  • La programación funcional ayuda y facilita a la paralelización. Algo más importante, es que las funciones que son totalmente compuestos en serie y son fáciles de paralelizar. Esto implica una mayor velocidad y poder computacional. La programación funcional proporciona concurrencia y paralelismo a casi cero costos, lo que hace que sea más fácil trabajar en aprendizaje profundo con modelos grandes y distribuidos.

 

Existen diferentes teorías y perspectivas sobre la combinación de programación funcional y aprendizaje profundo, tanto desde un punto de vista matemático como práctico, pero a veces es más fácil verlo de una manera práctica. En este artículo vamos a presentar las ideas que subyacen a la programación funcional y cómo aplicarlas en un modelo de aprendizaje profundo Cortex para la clasificación de valores anómalos.

 

Las bases de Clojure

Antes de continuar con el tutorial de Cortex, vamos a presentar algunas nociones básicas sobre Clojure. Clojure es un lenguaje de programación funcional que es excelente para la concurrencia y el procesamiento de datos. Afortunadamente para nosotros, estos son extremadamente útiles en el aprendizaje automático. De hecho, la razón principal por la que utilizamos Clojure para el aprendizaje automático es que el trabajo de preparación de conjuntos de datos de practica (manipulación de datos, procesamiento, etc.) puede compensar fácilmente la implementación de los algoritmos, especialmente cuando existen bibliotecas sólidas como Cortex. Usar Clojure y .edn (en lugar de C ++ y protobuf) nos da una ventaja en términos de velocidad en los proyectos de aprendizaje automático.

Puede encontrar una introducción más detallada sobre este lenguaje lo puedes encontrar aquí.

Comencemos con lo básico: el código de Clojure se compone de un conjunto de términos . Estos están encerrados entre paréntesis y generalmente se tratan como funciones de llamada. (+ 2 3)          ; => 5
(if false 1 0)   ; => 0

Hay 4 estructuras de datos básicas: vectores, listas, hash-maps y sets. Las comas se consideran espacios en blanco, por lo que generalmente se omiten.

[1 2 3]            ; vector (ordered)
‘(1 2 3)           ; lists (ordered)
{:a 1 :b 2 :c 3}   ; hashmap or map (unrdered)
#{1 2 3}           ; set (unordered, unique values)

La comilla simple, que precede a la lista, es solo un instrumento para garantizar que no se detecte como un concepto.

Clojure también tiene muchas funciones integradas para trabajar en estas estructuras de datos. Parte del atractivo de Clojure radica en su diseño rico en características para muy pocos tipos de datos, lo que contrasta con la práctica común de tener pocas funciones especializadas para la mayor cantidad posible de estructuras de datos. Clojure, al ser un lenguaje de programación funcional, admite funciones de alto nivel, lo que significa que las funciones se pueden importar como argumentos en otras funciones.

 

(count [a b c])              ; => 3

(range 5)                    ; => (0 1 2 3 4)

(take 2 (drop 5 (range 10))) ; => (5 6)

(:b {:a 1 :b 2 :c 3})        ; use keyword as function => 2

(map inc [1 2 3])            ; map and increment => (2 3 4)

(filter even? (range 5))     ; filter collection based off predicate => (0 2 4)

(reduce + [1 2 3 4])         ; apply + to first two elements, then apply + to that result and the 3rd element, and so forth => 10

Por supuesto, podríamos escribir nuestras funciones en Clojure usando defn. La definición de las funciones de Clojure sigue la forma (defn fn-name [params*] expressions )y también devuelve el valor de la última expresión en el cuerpo.

(defn add2
[x]
(+ x 2))(add2 5)     ; => 7

Las expresiones “let” crean y asocian las variables dentro de los ámbitos léxicos, llamados ámbito léxico, de “let”. Esto se hace en la expresión (let [a 4] (…)), donde la variable “a” tiene un valor de 4 solo en los parentesis internos. Estas variables se llaman “locales”.

(defn square-and-add
[a b]
(let [a-squared (* a a)
b-squared (* b b)]
(+ a-squared b-squared)))

(square-and-add 3 4)       ; => 225

Finalmente, tenemos dos formas de crear funciones “anónimas”, que se pueden asignar a una función funcional local o una función de orden superior.

(fn [x] (* 5 x))          ; anonymous function#(* 5 %)                  ; equivalent anonymous function, where the % represents the function’s argument(map #(* 5 %) [1 2 3])    ; => (5 10 15)

Esto es todo con respecto a la información para tener una base. Ahora que hemos aprendido algunas nociones sobre Clojure, volvamos al aprendizaje automático.

 

Cortex

Cortex está escrito en Clojure, y actualmente es una de las bibliotecas de aprendizaje automático más grandes y de más rápido crecimiento, que utiliza un lenguaje de programación funcional. El resto del artículo se centrará en cómo construir un modelo de clasificación en Cortex, junto con los paradigmas de programación funcional y las técnicas de enriquecimiento de datos (aumento de datos) requeridas.

Data preprocessing

Tomamos un conjunto de datos de fraude de tarjetas de crédito proporcionado por este sitio. Estos conjuntos de datos son muy desequilibrados, debido al hecho de que los contenedores solo tienen 492 cajas de frondas positivas de un total de 248,807, en la práctica 0,172%. Esto creará problemas, pero por ahora, veamos los datos y veamos cómo funciona el modelo.

Para garantizar el anonimato de los datos personales, todas las características originales, excepto “time” y “amount”, ya se han transformado en componentes principales, o PCA (donde cada entrada representa una nueva variable que contiene la información más relevante de los datos sin procesar ). Una breve mirada a los datos nos muestra que la primera variable “time” tiene un contenido de información limitado, por lo que la dejamos de lado. A continuación vemos como se ve nuestro grupo de códigos:

 

(ns fraud-detection.core

(:require [clojure.java.io :as io]

[clojure.string :as string] [clojure.data.csv :as csv] [clojure.core.matrix :as mat] [clojure.core.matrix.stats :as matstats]

[cortex.nn.layers :as layers]

[cortex.nn.network :as network]

[cortex.nn.execute :as execute]

[cortex.optimize.adadelta :as adadelta]

[cortex.optimize.adam :as adam]

[cortex.metrics :as metrics]

[cortex.util :as util]

[cortex.experiment.util :as experiment-util]

[cortex.experiment.train :as experiment-train]))

(def orig-data-file “resources/creditcard.csv”)

(def log-file “training.log”)

(def network-file “trained-network.nippy”)

;; Read input csv and create a vector of maps {:data […] :label [..]},

;; where each map represents one training instance in the data

(defonce create-dataset

(memoize

(fn []

(let [credit-data (with-open [infile (io/reader orig-data-file)]

(rest (doall (csv/read-csv infile))))

data (mapv #(mapv read-string %) (map #(drop 1 %) (map drop-last credit-data))) ; drop label and time

labels (mapv #(util/idx->one-hot (read-string %) 2) (map last credit-data))

dataset (mapv (fn [d l] {:data d :label l}) data labels)]

dataset))))

 

Lo encuentran aqui : fraud-detection-data.cjl

Las redes neuronales Cortex utilizan datos de entrada en forma de mapas, donde cada mapa representa un solo dato con una etiqueta asociada (por ejemplo, si tengo una imagen de perro, la etiqueta será “perro”). Una clasificación, por ejemplo, puede aparecer como [{:data [12 10 38] :label “cat”} {:data [20 39 3] :label “dog“} … ]

En nuestra función para crear conjuntos de dataset ad hoc, vemos que en el archivo de formato de comma-separated value, todas las columnas distintas de la última forman nuestros “data” (o características), mientras que la última columna representa el label , o la etiqueta. Mientras tanto, transformamos los label one-hot vector  (por ejemplo [0 1 0 0]) en función de la clase de clasificación. Esto se debe a que la última capa soft max  en nuestra red neuronal produce un vector de probabilidad de clase, no la etiqueta en sí misma. Finalmente, creamos el mapa a partir de estas dos variables y lo guardamos como un dataset.

 

Descripción del modelo

Crear un modelo en Cortex es una operación bastante simple y directa. En primer lugar, debemos definir un mapa de parámetros más altos que se utilizarán más adelante durante el entrenamiento. Más tarde, para definir el modelo, simplemente unimos las capas:

(def params

{:test-ds-size      50000 ;; total = 284807, test-ds ~= 17.5%

:optimizer         (adam/adam)   ;; alternately, (adadelta/adadelta)

:batch-size        100

:epoch-count       50

:epoch-size        200000})

(def network-description

[(layers/input (count (:data (first (create-dataset)))) 1 1 :id :data) ;width, height, channels, args

(layers/linear->relu 20) ; num-output & args

(layers/dropout 0.9)

(layers/linear->relu 10)

(layers/linear 2)

(layers/softmax :id :label)])

Donde network-description es un vector de capas de redes neuronales. Nuestro modelo consiste en:

  • Una capa con input
  • Una capa totalmente conectada (y lineal) con la función de activación  ReLu
  • Un layer drop out
  • Otro extraño completamente conectado con ReLu
  • Una capa con output de 2 dimesiones pasa a través de la función softmax

 

En la primera y la última capa, debemos especificar un : id. esto se refiere a una clave en el mapa de datos en la cual nuestra red deberia observar. Recuerde que el mapa resulta como {: data […]: label […]}). Para nuestra capa de input, pasamos: identificación de datos para que el modelo tome datos de entrenamiento en los próximos pasos. En la capa final, sin embargo, proporcionamos: label como : id, de modo que podamos usar el label real para calcular nuestro error.

Entrenamiento y evaluación

A partir de aquí se vuelve más complejo. La función de entrenamiento no es realmente tan complicada: Cortex da funciones preconstruidas para un entrenamiento de alto nivel, por lo que todo lo que tenemos que hacer es establecer nuestros parámetros (la red, el dataset de entrenamiento y verificación, etc.). La única advertencia que le damos es que el sistema espera un conjunto de dataset “infinitos” para el entrenamiento. sin embargo, Cortex presenta una función llamada infinite-class-balanced-dataset que nos ayuda a transformarla.

(defn train

“Trains network for :epoch-count number of epochs”

[]

(let [network (network/linear-network network-description)

[train-orig test-ds] (get-train-test-dataset)

train-ds (experiment-util/infinite-class-balanced-dataset train-orig

:class-key :label

:epoch-size (:epoch-size params))]

(experiment-train/train-n network train-ds test-ds

:batch-size (:batch-size params)

:epoch-count (:epoch-count params)

:optimizer (:optimizer params)

:test-fn f1-test-fn)))

Entonces llegamos a la parte compleja: f1-test-fn. Durante el entrenamiento, de hecho, la función train-n espera que se le proporcione un: test-fn que verifique su rendimiento y determine si se debe guardar como una “best network” . Existe una función de prueba que llama default que identifica la pérdida cross-entropica (cross-entropy loss)  pero su valor de pérdida no es tan simple de interpretar y, además, no se ajusta perfectamente a nuestro conjunto de dataset desequilibrado. Para resolver este problema, escribiremos una función de prueba personal.

 

Pero ahora surge una pregunta: ¿cómo podemos verificar el rendimiento de nuestro modelo? La métrica estándar en las tareas de clasificación suele ser la precisión, pero, con nuestro conjunto de datos desequilibrado, esta medición es casi inútil. Dado que los ejemplos positivos solo representan el 0,172% del conjunto de datos total, incluso un modelo que se limita a predecir ejemplos negativos, podría alcanzar una precisión del 99.828%. Un porcentaje particularmente alto, pero si este modelo se usara en la realidad, surgirían varios problemas.

Entonces, un mejor grupo de métricas son: precisión, recuperación, y F1 score (o genericamente F-beta).

1 1

 

Precisamente, por lo tanto, nos enfrentamos a una pregunta: “de todos los ejemplos que predije que serían positivos, ¿qué proporción es  positiva?” En cuanto a la recuperación, preguntamos: “de todos los ejemplos positivos, ¿qué proporción es mas exacta y  predice que sea positivo?

El puntaje F-beta (una generalización del puntaje tradicional F1) es un promedio ponderado de precisión y recuperación, medido en una escala de 0 a 1:

2.jpg 2

Cuando beta = 1, obtenemos F1 a partir of2 * (precisión * recuperación) / (precisión + recuperación). Usualmente, beta representa cuántas veces la recuperación debería ser más importante que la precisión. En nuestro modelo, utilizamos el puntaje F1 como nuestro puntaje para estar muy cerca, pero también registramos los puntajes de precisión y recuperación para detectar el saldo. Este es nuestro f1-test-fn

 

(defn f-beta

“F-beta score, default uses F1”

([precision recall] (f-beta precision recall 1))

([precision recall beta]

(let [beta-squared (* beta beta)]

(* (+ 1 beta-squared)

(try                         ;; catch divide by 0 errors

(/ (* precision recall)

(+ (* beta-squared precision) recall))

(catch ArithmeticException e

0))))))

(defn f1-test-fn

“Test function that takes in two map arguments, global info and local epoch info.

Compares F1 score of current network to that of the previous network,

and returns map:

{:best-network? boolean

:network (assoc new-network :evaluation-score-to-compare)}”

[;; global arguments

{:keys [batch-size context]}

;per-epoch arguments

{:keys [new-network old-network test-ds]} ]

(let [batch-size (long batch-size)

test-results (execute/run new-network test-ds

:batch-size batch-size

:loss-outputs? true

:context context)

;;; test metrics

test-actual (mapv #(vec->label [0.0 1.0] %) (map :label test-ds))

test-pred (mapv #(vec->label [0.0 1.0] % [1 0.9]) (map :label test-results))

precision (metrics/precision test-actual test-pred)

recall (metrics/recall test-actual test-pred)

f-beta (f-beta precision recall)

;; if current f-beta higher than the old network’s, current is best network

best-network? (or (nil? (get old-network :cv-score))

(> f-beta (get old-network :cv-score)))

updated-network (assoc new-network :cv-score f-beta)

epoch (get new-network :epoch-count)]

(experiment-train/save-network updated-network network-file)

(log (str “Epoch: ” epoch “\n”

“Precision: ” precision  “\n”

“Recall: ” recall “\n”

“F1: ” f-beta “\n\n”))

{:best-network? best-network?

:network updated-network}))

La función ejecuta la red en el conjunto de prueba, calcula la puntuación F1 y, finalmente, actualiza y guarda la red como resultado. Además, imprime cada una de nuestras métricas de evaluación en cada punto. Si ahora ejecutamos el REPL, obtendríamos una puntuación que sería más o menos la misma:

 

Epoch: 30
Precision: 0.2515923566878981
Recall: 0.9186046511627907
F1: 0.395

Un resultado bastante pobre.

Enriquecimiento de datos (Data Augmentation)

Aquí nos encontramos con el problema del que hablamos al principio de este artículo, debido al desequilibrio del dataset. El modelo ahora no tiene suficientes ejemplos positivos de los que aprender. Cuando llamamos experiment-util/infinite-class-balanced-dataset en nuestra función de entrenamiento, de hecho estamos creando cientos de copias de cada instancia de entrenamiento positivo para equilibrar nuestro dataset. Como resultado, el modelo almacena esos valores de características, en lugar de aprender la distinción entre clases.

Una forma de resolver este problema es utilizar el enriquecimiento de datos, con el cual genero datos adicionales y artificiales basados en los ejemplos que ya tenemos disponibles. Para crear ejemplos de entrenamiento que sean positivos, debemos agregar cualquier cantidad de ruido a los features vectors  (vectores que contienen las características) para cada ejemplo positivo existente. La cantidad de ruido que agreguemos dependerá de la varianza de cada característica en las clases positivas, de modo que las características con amplia diferencia están enriquecidas con una gran cantidad de ruido, y lo opuesto para aquellas con baja diferencia.

A continuación se muestra el código para el enriquecimiento de datos:

(defonce get-scaled-variances

(memoize

(fn []

(let [{positives true negatives false} (group-by #(= (:label %) [0.0 1.0]) (create-dataset))

pos-data (mat/matrix (map #(:data %) positives))

variances (mat/matrix (map #(matstats/variance %) (mat/columns pos-data)))

scaled-vars (mat/mul (/ 5000 (mat/length variances)) variances)]

scaled-vars))))

(defn add-rand-variance

“Given vector v, add random vector based off the variance of each feature”

[v scaled-vars]

(let [randv (map #(- (* 2 (rand %)) %) scaled-vars)]

(mapv + v randv)))

(defn augment-train-ds

“Takes train dataset and augments positive examples to reach 50/50 balance”

[orig-train]

(let [{train-pos true train-neg false} (group-by #(= (:label %) [0.0 1.0]) orig-train)

pos-data (map #(:data %) train-pos)

num-augments (- (count train-neg) (count train-pos))

augments-per-sample (int (/ num-augments (count train-pos)))

augmented-data (apply concat (repeatedly augments-per-sample

#(mapv (fn [p] (add-rand-variance p (get-scaled-variances))) pos-data)))

augmented-ds (mapv (fn [d] {:data d :label [0 1]}) augmented-data)]

(shuffle (concat orig-train augmented-ds))))

augment-train-ds  tome nuestro dataset de entrenamiento original, calcule el número de enriquecimientos necesarios para lograr un equilibrio de clase de 50/50, y luego aplica estos enriquecimientos a nuestros ejemplos existentes a través de cualquier vector de ruido (add-rand-variance) según la diferebcua permitida (get-scaled-variances ). Finalmente, unimos los ejemplos enriquecidos con el conjunto dataset original y obtenga un dataset equilibrado.

Durante el entrenamiento, el modelo detecta una cantidad irrealmente grande de ejemplos positivos, mientras que el conjunto de verificación se mantendrá positivo al 0.172%. como resultado, aunque el modelo pueda aprender mejor la diferencia entre las dos clases, abrumaremos a nuestra clase con ejemplos positivos. Para resolver este problema, podemos cambiar los umbrales relevantes para forzar la predicción positiva durante la prueba. En otras palabras, en lugar de exigir al modelo al menos el 50% de certeza de la positividad de los ejemplos para clasificarlos como tales, podemos aumentar la demanda al menos al 70%. Después de algunas pruebas, notamos que el umbral mínimo debe establecerse en 90%. El código se puede encontrar en vec-> labelfunction en el código fuente, y se hace referencia a la línea 31 de f1-test-fn.

Usando el nuevo y enriquecido dataset de entrenamiento, nuestros puntajes se ven así:

Epoch: 25
Precision: 0.8658536585365854
Recall: 0.8255813953488372
F1: 0.8452380952380953

Resultados significativamente mejores que los anteriores.

Conclusiones

Este modelo obviamente aún puede mejorarse. Aquí les damos algunos consejos:

  • ¿Todas las características de PCA feature son informativas? Observe la distribución de valores para ejemplos positivos y negativos a través de las características y descarte cualquier característica que no ayude a distinguir entre las dos categorias.
  • ¿Hay otras arquitecturas de redes neuronales, funciones de activación, etc. que funcionan mejor?
  • ¿Existen diferentes técnicas de enriquecimiento de datos que podrían funcionar mejor?
  • ¿Cómo se compara el rendimiento del modelo en Cortex con Keras/Tensorflow/Theano/Caffe?

El código completo de fuente  para este proyecto se puede encontrar aquí. Le recomendamos que experimente con los siguientes pasos para explorar diferentes arquitecturas de red ( aquí hay un buen ejemplo de clasificación de imágenes en CNN que puede tomar como referencia).

La GTX 745 y la instalación de tensorflow – gpu en Windows

Autora: Eleonora Bernasconi

 

Especificaciones de la tarjeta de gráficos NVIDIA GeForce GTX 745

Especificaciones: https://www.geforce.com/hardware/desktop-gpus/geforce-gtx-745-oem/specifications

Núcleos CUDA: 384

Base Clock (MHz): 1033

Velocidad de la memoria ( Gbps ): 1.8 Gbps

Cantidad de memoria: 4 GB

Interfaz de memoria: DDR3

Ancho de banda máx (GB/sec): 28.8

 

Figura 01 – nvidia-smi para el monitoreo de GPU

Abra el símbolo del sistema e ingrese:

cd C:\Program Files\NVIDIA Corporation\NVSMI

nvidia-smi

N.B. El porcentaje de uso de la GPU oscila entre 92% y 94%, en el Administrador de tareas de Windows permanece en 70%.

 

Instalación de Tensorflow con GPU para Windows 10

Requisitos

Python 3.5

Nvidia CUDA GPU. Verifique que la GPU sea compatible con CUDA.

Configurando la tarjeta GPU Nvidia

Instala Cuda Toolkit 8.0 e cuDNN v5.1.

Descarga e instalación de CUDA Toolkit

Toolkit 8.0 https://developer.nvidia.com/cuda-downloads

Ejemplo de directorio de instalación: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0

Descarga e instalación de cuDNN

Installa cuDNN versione 5.1 per Windows 10: https://developer.nvidia.com/cudnn

Extraiga los archivos cuDNN e ingréselos en el directorio Toolkit.

Variables de entorno

Después de instalar CUDA toolkit, asegúrese de que CUDA_HOME esté configurado en las variables de entorno; de lo contrario, agréguelo manualmente.

Figura 02 – Variables de entorno CUDA_HOME parte 01

 

Figura 03 – Variables de entorno CUDA_HOME parte 02

Instala Anaconda

Descarga : https://www.anaconda.com/download/

Cree un nuevo entorno con el nombre tensorflow-gpu y la versión 3.5.2 de python

conda create -n tensorflow-gpu python=3.5.2

N.B. En caso de que se encuentre con versiones incompatibles entre sí, simplemente active estos comandos para resolver el problema:

conda install -c conda-forge tensorflow-gpu

Anaconda instalará automáticamente las versiones requeridas de cuda, cudNN y otros paquetes.

Figura 04 – conda install -c conda-forge tensorflow-gpu

activate tensorflow-gpu

Figura 05 – activate tensorflow-gpu

 

Instala tensorFlow

pip install tensorflow-gpu

Figura 06 – pip install tensorflow-gpu

i Ahora ha terminado y tiene instalado con éxito tensorflow con la GPU !

i Recuerde activar el comando:activate tensorflow-gpu para entrar en modo GPU!

Prueba de GPU

python

import tensorflow as tf

sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))

 

Figura 07 – prueba de GPU

 

Prueba en CIFAR-10 con 10 épocas

Tiempo promedio por época:150 sec

Tiempo total: 25 min

Figura 08 – Prueba en CIFAR-10 con 10 épocas 

Spark y Machine Learning (MLlib)

Autor: Antonio Berti

En este tutorial vamos a aprender el uso de la libreria de Apache Foundation para el Machine Learning llamada MLlib.

MLIB forma parte de las API de Spark y es interoperable con NumPy de Python así como las librerias de R. implementado con Spark es posible utilizar cualquier tipo de datos de cualquier origen o de la plataforma Hadoop como por ejemplo HDFS, HBase, las fuentes  datos provenientes de database relacionadas o fuentes de datos locales, como documentos de texto.

Spark sobresale en los procesos de cálculos iterativo permitiendo que los procesos escritos en las librerias MLlib se ejecuten rápidamente permitiendo su uso y tambien  sobre todo a nivel industrial.

MLlib proporciona muchos tipos de algoritmos, así como numerosas funciones de utilidad. ML incluye algoritmos de clasificación, regresión, árboles de decisión, algoritmos de recomendación, agrupamiento. Entre las utilidades más utilizados puede incluir las características de las transformaciones, la estandarización y normalización, funciones estadísticas y álgebra lineal.

 

Primero que todo cargamos la base de datos

val data =MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

 

El conjunto de datos se divide en una parte utilizada para entrenar el modelo (60%) y otra parte para las prueba (40%).

 

val splits = data.randomSplit(Array(0.6, 0.4), seed=11L)

val training = splits(0).cache()

val test = splits(1)

Se ejecuta el modelo en la base de datos de prueba.

val model = new LogisticRegressionWithLBFGS()
.setNumClasses(10)&nbsp
.run(training)

Se entrena el algoritmo y se costruye el modelo

val predictionAndLabels = test.map {case LabeledPoint(label, features) =>

 val prediction = model.predict(features)

  (prediction, label)}

De esta forma, se obtiene la métrica del modelo y la precisión del pronóstico.

val metrics = new MulticlassMetrics(predictionAndLabels)

val accuracy = metrics.accuracy

println("Accuracy = $accuracy")

Es posible guardar el modelo recién entrenado y volver a cargarlo en la memoria para su uso posterior.

model.save(sc, "target/tmp/scalaLogisticRegressionWithLBFGSModel")

val sameModel = LogisticRegressionModel.load(sc,

               "target/tmp/scalaLogisticRegressionWithLBFGSModel")

 

Referencias

documentación spark – http://spark.apache.org

documentación mllib – http://spark.apache.org/docs/latest/ml-guide.html

dataset de ejemplos mllib – https://github.com/apache/spark/tree/master/data/mllib

codigo de ejemplo  – https://github.com/apache/spark/tree/master/examples/src/main/scala/org/apache/spark/examples

 

Creación de un Tensor en Pytorch

Autor: Andrea Mercuri

Al igual que los otros Framework  para el deep learning, también en PyTorch son absolutamente esenciales los tensores. Cuando representamos los cálculos que son efectuados por una red neuronal  como operaciones  tensoriales obtenemos dos ventajas: utilizamos un  código matemático  compacto  y permitimos que la CPU haga cálculos paralelos.
Los tensores pueden residir en la RAM principal de la computadora y ser procesados por la CPU o RAM de una tarjeta de video y procesados por una GPU. Estos últimos se identifican por una series de diferencias de los primeros. A continuación veremos una lista de todos los tipos de tensores presentes en PyTorch.

Tipo Tensores CPU Tensores GPU
32-bit coma flotante torch.FloatTensor torch.cuda.FloatTensor
64-bit coma flotante torch.DoubleTensor torch.cuda.DoubleTensor
16-bit coma flotante torch.HalfTensor torch.cuda.HalfTensor
8-bit entero (sin signo) torch.ByteTensor torch.cuda.ByteTensor
8-bit entero (con signo) torch.CharTensor torch.cuda.CharTensor
16-bit entero (con signo) torch.ShortTensor torch.cuda.ShortTensor
32-bit entero (con signo) torch.IntTensor torch.cuda.IntTensor
64-bit entero (con signo) torch.LongTensor torch.cuda.LongTensor

En primer lugar importamos PyTorch.

import torch

Podemos crear un tensor  estos siempre  siempre tienen que inicializarlos llamando al constructor de uno de los tipos enumerados anteriormente.

x = torch.FloatTensor(3, 2)
print(x)
1.00000e-25 *
&nbsp&nbsp9.9872  0.0000
&nbsp&nbsp9.9872  0.0000
&nbsp&nbsp0.0000  0.0000
&nbsp&nbsp[torch.FloatTensor of size 3x2]

En este caso, el tensor se crea en la RAM principal. Si queremos crear un tensor en la GPU corriente, tenemos que usar uno de los tipos CUDA.

x = torch.cuda.FloatTensor(3, 2)
print(x)
nan nan
nan nan
nan nan
[torch.cuda.FloatTensor of size 3x2 (GPU 0)]

En este caso, nos enteramos  que el tensor se encuentra en la primera GPU. Las GPU que están presentes en la máquina están enumeradas con números  enteros a partir de 0.
Podemos crear tensores a partir de  las listas de Python

torch.FloatTensor([[1,2,3],[4,5,6]])
1  2  3
4  5  6
[torch.FloatTensor of size 2x3]

o de array numpy.

x_np = np.array([1,2,3,4], dtype=np.float32)
x = torch.FloatTensor(x_np)

Obtenemos el mismo resultado con el método  from_numpy.

x = torch.from_numpy(x_np)

Notemos que el array numpy y el tensor PyTorch comparten los datos. Si cambiamos uno de los dos, el otro sufre los mismos cambios.

x[0] = 0
print(x_np)
[ 0.,  2.,  3.,  4.]
print(x)
0
2
3
4
[torch.FloatTensor of size 4]

Podemos crear tensores desde otros tensores.

y = torch.FloatTensor(x)
print(y)
0
2
3
4
[torch.FloatTensor of size 4]

Incluso en este caso, el tensor creado comparte los datos con el tensor original.
Podemos crear tensores desde cero.

torch.zeros(3,2)
0  0
0  0
0  0
[torch.FloatTensor of size 3x2]

Podemos crear tensores de números aleatorios extraídos de una determinada distribución, por ejemplo, espaciadas dentro el intervalo [0,1].

torch.rand(2, 3)
0.1256  0.0406  0.2072
0.2479  0.0515  0.093
[torch.FloatTensor of size 2x3]

Cada tensor vive en la memoria principal o en una tarjeta de video. Dos tensores pueden ser operandos de la misma operación solo si residen en la misma memoria ( en este caso el resultado aún reside en la misma memoria). Si tratamos de combinar (por ejemplo, sumando) un tensor que reside en la RAM principal y uno que está en una tarjeta de video (o dos tensores en dos tarjetas de video diferentes) será una excepción.

xcpu = torch.FloatTensor(3,2)
xgpu = torch.cuda.FloatTensor(3,2)
xcpu + xgpu
TypeError             Traceback (most recent call last)
in ()
----> 1 xcpu + xgpu
…

Si queremos obtener una copia de un tensor x en la primera GPU, podemos usar el método cuda.

y = x.cuda(device=0)

Si el tensor ya está en la primera GPU regresa el tensor original .En lugar de obtener una copia de un tensor x en la RAM principal, usamos el método cpu.

y = x.cpu()

Podemos convertir un tensor a otro tipo diferente  pasando del método de type al tipo de destinacion.

y = x.type(torch.ByteTensor)

Obtenemos el mismo resultado al inserir un método específico de conversión.

y = x.byte()

Si además de cambiar el tipo  queremos copiar el tensor en la GPU ,tenemos que pasar del método type a un tipo cuda.

y = x.type(torch.cuda.ByteTensor)

o escribir

y = x.byte().cuda()

Para usar la segunda GPU usamos set_device.

torch.cuda.set_device(1)

Si ahora escribimos

torch.cuda.current_device()

obtenemos 1 como valor de retorno. Esto significa que ahora la GPU actual es la segunda y no la primera y, por ejemplo, cuando usamos el método cuda en un tensor creamos una copia en la segunda GPU en lugar de la primera.
También se puede usar un context manager para cambiar temporalmente la GPU actual.
Por ejemplo, escribiendo

with torch.cuda.device(1):
&nbsp&nbspx1 = torch.cuda.FloatTensor(2,3)
x2 = torch.cuda.FloatTensor(2,3)

cuando en la GPU el índice es 0,x1 viene creado en la segunda GPU  un (índice 1), x2 y en la primera (índice 0).
Todas las funciones relativas a las creaciónes de tensores están incluidas en los package torchtorch.cuda  y en la clase torch.Tensor. En los próximos tutoriales continuaremos aprendiendo de los tensores.
Referencias

Instalación de Keras/Tensorflow-Theano en Windows

Autores: Francesco Pugliese & Matteo Testi

En este post, veremos cómo abordar el abrumador problema de la instalación de Windows en el marco de framework para Deep Learning “Keras” y tambien veremos el stack de backend “Tensorflow / Theano”.
La instalación parte descargando  paquete de Python 3. Elegimos la opcion Miniconda en el siguiente enlace: https://conda.io/miniconda.html   aparecerá la siguiente pantalla:

 

Seleccione Python 3.6 y la versión de Windows de 64 bits o 32 bits. Haga clic en el paquete descargado y ejecute la instalación dejando todo predeterminado. Al final de la instalación, acepte el reinicio de la máquina.

Después de reiniciar su PC, desde el cuadro de búsqueda de Windows, escriba cmd.exe y ejecute el prompt. A continuación, ejecute el script c:\Users\-utente-\Miniconda3\Scripts\activate.bat donde iniciará el prompt de Anaconda(replace-user- con el nombre de cuenta específico).

En este punto escriba: conda install numpy scipy mkl-service m2w64-toolchain para instalar:

  1. La libreria “numpy” de Python es muy útil para gestionar matrices y array en general.
  2. la libreria para el cálculo científico en python “scipy”.
  3. la libreria para “mkl-service” es para optomizar, las rutinas de vectores matemáticos para acelerar las funciones y aplicaciones matemáticas.
  4. la libreria “libpython” para Python 3 con código para Machine Learning y para desarrollar código eficiente.
  5. la biblioteca “m2w64-toolchain” que proporciona una versión compatible con GCC, por lo tanto, es muy recomendable.

Las librerias opcionales son:

  1. la libreria “nose” para el testing de los programas  Python.
  2. la libreria “nose-parameterized” para el testing paramétrico.
  3. la libreria “sphinx” para crear documentación elegante del programa en varios formatos (HTML, PDF, ePyub, etc.).
  4. la libreria “pydot-ng” es la interfaz al lenguaje de representación gráfica de Graphviz’s Dot.

Una vez hecho el set up de Pyton,descargue los controladores de Cuda desde el siguiente enlace:

https://developer.nvidia.com/cuda-downloads

 

Se abrirá la siguiente pantalla con distintas opciones del sistema operativo y las versiones requeridas:

 

 

 

Descargar la versión local (recomendada) del archivo instalado y proceda con la instalación de los driver Cuda, que son las librerias de programación pararela de la GPU Nvidia (Graphic Processing Unit) que esta presente en la tarjeta grafica. Si es necesario, también acepte la instalación del driver de la tarjeta de video si en el caso este no estuviera actualizado o no funcionara correctamente.

Después de haber terminado instalacion de los driver Cuda (y de los driver de la tarjeta de video), el siguiente paso es instalar Theano y la libreria de soporte “libgpuarray”, que es una libreria para manipular los tensores en la GPUcon el comando:

conda install theano pygpu

NOTA 1 Theano: para la instalación de Theano siempre se recomienda la instalación la versión anterior de Cuda. Esto se debe a que Theano no viene actualizado a menudo esto comporta que te puedes encontrar con  errores de compilación esto  sucede cuando has instalado una version  de Theano con la última versión de Cuda. Por ejemplo, en este momento la versión más estable de Theano es 0.9.0, por lo que recomendamos instalar Cuda 8.0 en lugar de Cuda 9.0. Existen tutoriales en intenet que te dicen que te dan consejos como funcionaria perfectamente Cuda 9 con Theano 0,9, segun mi opinion considero que son complicados y quitan tiempo. Es aconsejable tener una configuración estable de Cuda-Theano por esto les aconsejo elegir las versiones que les he recomendado.

Entonces, ahora es necesario  instalar Visual Studio que proporciona  el compilador  C ++ para Windows a Theano (de hecho, el CCG instalado anteriormente sólo se refiere al compilador de C). Para hacer esto se descarga Visual Studio Community en el siguiente enlace: https://www.visualstudio.com/it/downloads/ y despues tienes que seguir todos los pasos necesarios,  instalar sólo los componentes esenciales para el C++.

NOTA 2 Theano: Aparentemente después del próximo lanzamiento, Theano se retirará, explicado por el mismo Bengio en este post: link Las razones son tantas, creemos que se deben esencialmente a la competencia masiva de otros frameworks para Deep Learning (mxnet, tensorflow, deeplearning4j, gluon , por nombrar algunos) que vienen actualizados rapidamente. Como hemos demostrado, Theano sufre problemas constantes de actualización. Sin embargo, creemos que todavía es un hito para Deep Learning, Theano es el primero en introducir la diferenciación automática y la paralelización eficiente y transparente de las operaciones de la matriz GPU que han dado lugar a la difusion de las  deep neural networks en la GPU . Por lo tanto, creemos que es necesario darle un reconocimiento, a este excepcional framework, también tenemos reconocer, que todavía proporciona sus ventajas de versatilidad y velocidad cuando se utiliza como backend de Keras.

NOTA Visual Studio: también Visual Studio recientemente tiene problemas de compatibilidad con Theano. En particular, Visual Studio 2017 generará una excepción en la fase de importación de Theano, ya sea Cuda 9 que Cuda 8. Por lo tanto, recomendamos instalar una versión anterior estable como Visual Studio 2013

Una vez que haya instalado Visual Studio, es necesecario  completar el archivo  theanorc, de  la configuración de Theano,que se encuentra con Miniconda3 en la ruta de acceso: c: \ Users \ – user – \. Theanorc

Rellene  el .theanorc de la siguiente manera, suponiendo que haya instalado Cuda 8 y Visual Studio 2013:

[global]
device = gpu
floatX = float32

[cuda]
root = C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0

[dnn]
enabled=False

[nvcc]
compiler_bindir = C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin

[lib]
cnmem = 0

Analizemos un momento estos parámetros: la sección “device” de [global] sirve para decidir si se desea usar la CPU o la GPU, la sección “root” de [cuda] es necesaria para definir la ruta de las librerias de Cuda, mientras que “compiler_bindir” ” de [nvcc] sirve para definir la ruta del compilador C ++ de Visual Studio que es necesaria para compilar los programas de Theano. El parámetro CNMeM es una libreria (built-in de Theano) que le permite definir (a través de un valor entre 0 y 1) el modo en el cual el framework de Deep Learning puede manejar la memoria de la GPU, y es una manera para acelerar la computación de las redes neuronales deep en Theano. Por ejemplo, las tarjetas de video compartidas con la pantalla se aconseja ajustar alrededor de 0.8, mientras que para las tarjetas de video stand-alone, osea que estan dedicadas solo a Deep Learning, recomendamos un cnmem igual a 1.

Otro parámetro muy importante para acelerar el cálculo, especialmente con respecto a la convolución, es el parámetro “enabled” de [dnn] que permite habilitar o deshabilitar las librerias Nvidia CuDNN. Básicamente es una libreria que  optimiza las deep neural networks, lo que le permite acelerar el traning, las pruebas e incluso reducir el consumo de memoria. Para instalar CuDNN se necesita ir a este enlace: https://developer.nvidia.com/cudnn y hacer click en el boton download e iniciar la descarga( talvez es necesario registrarse como membership de Nvidia) deberia abrirse la siguiente pantalla

developer.nvidia.com
The NVIDIA CUDA® Deep Neural Network library (cuDNN) is a GPU-accelerated library of primitives for deep neural networks. cuDNN provides highly tuned implementations …

 

 

NOTA cuDNN: también aquí, como en los casos anteriores, se recomienda no descargar la última versión de cuDNN, sino uno o dos precedentes, ya que Cuda 8 o Theano 0.9 no podran ser vistas, en este caso recomendamos versión cuDNN 6.0. Y con Theano 0.9 todavía puede tener una advertencia de que la versión cuDNN es muy reciente y podría causar problemas. También probamos problemas de incompatibilidad entre la última versión de cuDNN y TensorFlow.

Al descomprimir el archivo descargado, obtendrá 3 carpetas: bin, lib e include.  Lo que necesitas  hacer es copiar el contenido de las carpetas en las mismas carpetas dentro del directorio de Cuda, es decir, dentro de:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0

Copie cudnn64_6.dll dentro de la bin del path Cuda, copie cudnn.h dentro include y luego copie cudnn.lib dentro lib.

Una vez que instalado cuDNN, proceda con la instalación de Keras a través de pip:

pip install keras

La declaración instalará todas las dependencias y también la última versión (actualmente Keras 2.0.9). Para configurar Theano como backend de Keras, entre a la carpeta: c: \ users \ -user – \. Keras y edite el archivo keras.json de la siguiente manera, o estableciendo “theano” en la entrada “backend”

{

“floatx”: “float32”,
“epsilon”: 1e-07,
“backend”: “theano”,
“image_data_format”: “channels_last”
}

Para probar que todo está bien, reinicie el prompt de anaconda y ejecute python. Dentro el prompt de Python escriba: import keras. Si todo esta en la dirección correcta, debería aparecer la siguiente pantalla:

 

Recuerdense del primer “warning” mencionado  sobre las cuDNN y comunicado por Theano mismo: si encuentra los problemas antes mencionados, efectuar el downgrade de las  cuDNN a la versión 5.1 según  como lo ha  recomendado por el mismo team. El lanzamiento de la versión estable de Theano 0.10 debería resolver todos estos problemas de compatibilidad.

De todos modos, encontramos que el entorno configurado con Keras y Theano de esta manera funciona perfectamente en una variedad de modelos que hemos entrenado y probado. Usamos Theano porque a menudo es más rápido que TensorFlow en algúnos training de Computer Vision.

Sin embargo, si desea utilizar TensorFlow como un backend, es necesario instalarlo. Para instalar tensorflow para la GPU, necesita el siguiente comando:

pip install –upgrade tensorflow-gpu

Este instalará la última versión (1.4.0) de Tensorflow-gpu. Para probarlo con Keras, reemplace “theano” con la cadena “tensorflow” en el archivo “keras.json”, reinicie el prompt de anaconda y haga nuevamente import keras.

NOTA TensorFlow: no esta admitido en plataformas de 32 bits, el procedimiento de instalación solo descargará en il wheel relativo al framework de 64 bits. También para descargar la versión de la CPU, solo necesitan especificar: pip install –upgrade tensorflow.

Si todo salió bien, esta vez deberia aparecer el  TensorFlow como backend de keras:

 

Otros paquetes útiles que recomendamos para trabajar con Keras son:

  1. scikit-image: Una libreria muy útil de image processing  en python, que permite, entre otras cosas, guardar matrices y tensores en una imagen JPEG u otros muchos formatos admitidos. Instalable con: conda install scikit-image.
  2. gensim: Una  libreria de word embeddings  que implementa, entre otras cosas, el algoritmo word2vec. Instalable con: conda install gensim.
  3. h5py: La  libreria como interfaz   conectada al formato de rescate HDF5 de Pythonic, necesario para guardar modelos  de entrenamientos en discos Keras. Instalado con pip install h5py.

A este punto, el entorno Keras / Tf-Th en Windows está listo para ser usado, y podran probar su código y sus modelos mediante el uso de la GPU.

Buen trabajo!

 

Nos vemos en el siguiente tutorial.

Un saludo de Deep Learning Italia.

Para información y aclaración, aquí están nuestros correos electrónicos:

Francesco Pugliese – f.pugliese@deeplearningitalia.com

Matteo Testi – m.testi@deeplearningitalia.com