Black box: SVN – Support Vector Machines
Idea
Luego de analizar que significa SVN, vamos a ver la implementacion practica en un problema cotidiano: como funciona el reconocimiento de imagenes, y en particular vamos a intentar replicar el funcionamiento de los sistemas de OCR (Optical Character Recognition).
Vamos a utilizar el dataset donado a la UCI Machine learning Data Reposity compuesto por 20.000 ejemplos de las 26 letras del alfabeto en mayuscula, usando 20 distintas formas incluyendo la distorcion como una herramienta mas.
Resultado luego de implementar SVMs
Se puede ver que la implementacion es sumamente sencilla, en nuestro ejemplo hemos probado con el kernel “vanilladot”, alcanzando una exactitud del 84%. Al generar un nuevo modelo utilizando el kernel “rbfdot”, se alcanzo una exactitud del 92%.
Consideraciones generales
La primer pregunta al plantearnos resolver un problema de ML, es que algoritmo se adapta mejor. En este caso con reconocimiento de imagenes elegimos SVM porque:
- SVM se adapta para realizar la tarea dado que son algoritmos que no se ven afectados por el ruido (esto es, la falta de exactitud) del dataset, en terminos practicos nuestro dataset contiene imagenes que no son claras o nitidas.
- SVM es un algoritmo de caja negra, no sabemos como aplica cada una de las reglas, en el caso de reconocimiento de imagenes no necesitamos entender una a una las reglas a aplicar en el conjunto de datos, solo nos interesa que reconozca las imagenes.
Librerias que implementan SVMs
Existen varios paquetes que nos pueden servir para utilizar SVMs:
- e071 package provee una interfaz en R utilizando la libreria LIBSVM, una libreria muy conocida y utilizada escrita en C++
- klaR package utiliza el algoritmo SVMlight
- kernlab package es la libreria recomendada si estamos trabajando por primera vez con SVM. Algunos de los grandes pros son: fue escrita directamente en R (lo cual permite realizar algun tipo de modificacion o consultar el codigo directamente), tambien utiliza el package caret permitiendo que cualquier implementacion pueda ser evaluada y que pueda ser mejorada su performance.
Implementaciones de kernel
El kernel se utiliza para asignar nuestro conjunto de datos de entrada en el espacio de características de alta dimensión. Y luego, dentro de ese espacio, buscamos el limite. Existen distintas implementaciones de kernel, entre ellas:
- Linear
- Polynomial
- Gaussian (RBF)
- Sigmoid
De acuerdo al teorema No-Free Lunch no existen garantias de que un kernel tenga una mejor performance que otro. Por eso es que a priori, sera imposible determinar cual kernel va a funcionar mejor con el conjunto de datos de entrada del que dispongamos. La regla mas clara es que si el kernel funciona (nos permite alcanzar una mejor performance que otros), ese es el kernel adecuado para nuestro set de datos.
Evaluacion del modelo
Uno de los puntos mas importantes en cualquier implementacion de ML, es la evaluacion del modelo, en este caso
comparamos el clasificador obtenido: letter_classifier vs el conjunto de letras que dejamos para verificar: letters_test
letter_prediction <- predict(letter_classifier, letters_test)
table(letter_prediction, letters_test$letter)
A | B | C | D | |
A | 144 | 0 | 0 | 0 |
B | 0 | 121 | 0 | 5 |
C | 0 | 0 | 121 | 0 |
D | 2 | 2 | 0 | 156 |
- El resultado sera una tabla conteniendo cantidad de letras identificadas y cantidad de errores: en la diagonal la cantidad de identificaciones correctas
- En las distintas posiciones los errores, que pueden marcar ciertos patrones: cuales son las letras mas dificiles de identificar o bien cuales son letras con cierto parecido y por lo tanto con mas errores de identificacion entre si
Implementacion tecnica
Get the data
library(kernlab)
letters <- read.csv("letterdata.csv")
letters_train <- letters[1:16000,]
letters_test <- letters[16000:20000,]
Analyzing the model
letter_classifier <- ksvm(letter ~ ., data = letters_train, kernel = "vanilladot")
letter_classifier
letter_prediction <- predict(letter_classifier, letters_test)
table(letter_prediction, letters_test$letter)
agreement <- letter_prediction == letters_test$letter
table(agreement)
prop.table(table(agreement))
# FALSE TRUE
# 0.1607098 0.8392902
Improving the model
letter_classifier_rbf <- ksvm(letter ~ ., data = letters_train, kernel = "rbfdot")
letter_prediction_rbf <- predict(letter_classifier_rbf, letters_test)
agreement_rbf <- letter_prediction_rbf == letters_test$letter
table(agreement_rbf)
prop.table(table(agreement_rbf))
# FALSE TRUE
# 0.07048238 0.92951762