JavaRush /Blog Java /Random-ES /Aprendizaje automático para desarrolladores de Java, part...

Aprendizaje automático para desarrolladores de Java, parte 2

Publicado en el grupo Random-ES
Aprendizaje automático para desarrolladores de Java, parte 1
Aprendizaje automático para desarrolladores de Java, Parte 2 - 1

Estimación de la función objetiva

Recordemos que la función objetivo , también conocida como función de predicción, es el resultado del proceso de preparación o entrenamiento. Matemáticamente, el desafío es encontrar una función que tome una variable como entrada хy devuelva el valor predicho у.
Aprendizaje automático para desarrolladores de Java, Parte 2 - 2
(J(θ))En el aprendizaje automático, se utiliza una función de costo para calcular el valor de error o "costo" de una función objetivo determinada.
Aprendizaje automático para desarrolladores de Java, partes 2 - 3
La función de costo muestra qué tan bien se ajusta el modelo a los datos de entrenamiento. Para determinar el costo de la función objetivo que se muestra arriba, es necesario calcular el error al cuadrado de cada casa de ejemplo (i). El error es la distancia entre el valor calculado уy el valor real yde la casa del ejemplo i.
Aprendizaje automático para desarrolladores de Java, partes 2 - 4
Por ejemplo, el precio real de una casa con una superficie de 1330 = 6.500.000 € . Y la diferencia entre el precio de la vivienda pronosticado por la función objetivo entrenada es 7.032.478 € : la diferencia (o error) es 532.478 € . También puedes ver esta diferencia en el gráfico de arriba. La diferencia (o error) se muestra como líneas rojas discontinuas verticales para cada par de entrenamiento de área de precio. Después de calcular el costo de la función objetivo entrenada, debe sumar el error al cuadrado de cada casa en el ejemplo y calcular el valor principal. Cuanto menor sea el valor del precio (J(θ)), más precisas serán las predicciones de nuestra función objetivo. El Listado 3 muestra una implementación Java simple de una función de costo que toma como entrada una función objetivo, una lista de datos de entrenamiento y etiquetas asociadas con ellos. Los valores de predicción se calcularán en un bucle y el error se calculará restando el valor del precio real (tomado de la etiqueta). Posteriormente se sumará el cuadrado de los errores y se calculará el valor del error. El costo se devolverá como un valor de tipo double:

Listado-3

public static double cost(Function<ltDouble[], Double> targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels) {
 int m = dataset.size();
 double sumSquaredErrors = 0;

 // рассчет квадрата ошибки («разницы») для каждого тренировочного примера и //добавление его к сумме
 for (int i = 0; i < m; i++) {
 // получаем вектор признаков из текущего примера
 Double[] featureVector = dataset.get(i);
 // предсказываем significado и вычисляем ошибку базируясь на реальном
 //значении (метка)
 double predicted = targetFunction.apply(featureVector);
 double label = labels.get(i);
 double gap = predicted - label;
 sumSquaredErrors += Math.pow(gap, 2);
 }

 // Вычисляем и возращаем significado ошибки (чем меньше тем лучше)
 return (1.0 / (2 * m)) * sumSquaredErrors;
}
¿Interesado en leer sobre Java? ¡ Únase al grupo de desarrolladores de Java !

Aprender la función objetivo

Aunque la función de costo ayuda a evaluar la calidad de la función objetivo y los parámetros theta, aún es necesario encontrar los parámetros theta más adecuados. Puede utilizar el algoritmo de descenso de gradiente para esto.

Descenso de gradiente

El descenso de gradiente minimiza la función de costos. Esto significa que se utiliza para encontrar los parámetros theta que tienen el costo mínimo (J(θ))según los datos de entrenamiento. Aquí hay un algoritmo simplificado para calcular valores theta nuevos y más apropiados:
Aprendizaje automático para desarrolladores de Java, Parte 2 - 5
Entonces, los parámetros del vector theta mejorarán con cada iteración del algoritmo. El coeficiente de aprendizaje α especifica el número de cálculos en cada iteración. Estos cálculos se pueden realizar hasta que se encuentren valores theta "buenos". Por ejemplo, la siguiente función de regresión lineal tiene tres parámetros theta:
Aprendizaje automático para desarrolladores de Java, Parte 2 - 6
En cada iteración, se calculará un nuevo valor para cada uno de los parámetros theta: , y . Después de cada iteración, se puede crear una implementación nueva y más apropiada utilizando el nuevo vector theta 0 , θ 1 , θ 2 } . El Listado -4 muestra el código Java para el algoritmo de caída del gradiente. Theta para la función de regresión se entrenará utilizando datos de entrenamiento, datos de marcadores y tasa de aprendizaje . El resultado será una función objetivo mejorada utilizando parámetros theta. El método se llamará una y otra vez, pasando la nueva función objetivo y los nuevos parámetros theta de cálculos anteriores. Y estas llamadas se repetirán hasta que la función objetivo configurada alcance un nivel mínimo: θ0θ1θ2LinearRegressionFunction(α)train()

Listado-4

public static LinearRegressionFunction train(LinearRegressionFunction targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels,
 double alpha) {
 int m = dataset.size();
 double[] thetaVector = targetFunction.getThetas();
 double[] newThetaVector = new double[thetaVector.length];

 // вычисление нового значения тета для каждого elemento тета массива
 for (int j = 0; j < thetaVector.length; j++) {
 // сумируем разницу ошибки * признак
 double sumErrors = 0;
 for (int i = 0; i < m; i++) {
 Double[] featureVector = dataset.get(i);
 double error = targetFunction.apply(featureVector) - labels.get(i);
 sumErrors += error * featureVector[j];
 }

 //вычисляем новые значения тета
 double gradient = (1.0 / m) * sumErrors;
 newThetaVector[j] = thetaVector[j] - alpha * gradient;
 }

 return new LinearRegressionFunction(newThetaVector);
}
Para garantizar que el costo disminuya continuamente, puede ejecutar la función de costo J(θ)después de cada paso de capacitación. Después de cada iteración, el costo debería disminuir. Si esto no sucede, significa que el valor del coeficiente de aprendizaje es demasiado grande y el algoritmo simplemente no alcanzó el valor mínimo. En tal caso, el algoritmo de caída del gradiente falla. Los gráficos siguientes muestran la función objetivo utilizando los nuevos parámetros theta calculados, comenzando con el vector theta inicial {1.0, 1.0}. La columna de la izquierda muestra la gráfica de la función de predicción después de 50 iteraciones; columna central después de 200 repeticiones; y la columna de la derecha después de 1000 repeticiones. De estos podemos ver que el precio disminuye después de cada iteración y la nueva función objetivo se ajusta cada vez mejor. Después de 500-600 repeticiones, los parámetros theta ya no cambian significativamente y el precio alcanza un nivel estable. Después de esto, la precisión de la función objetivo no se puede mejorar de esta manera.
Aprendizaje automático para desarrolladores de Java, Parte 2 - 7
En este caso, aunque el coste ya no disminuye significativamente después de 500-600 iteraciones, la función objetivo todavía no es óptima. Esto indica una discrepancia . En el aprendizaje automático, el término "inconsistencia" se utiliza para significar que el algoritmo de aprendizaje no encuentra tendencias subyacentes en los datos. Según la experiencia de la vida real, es probable que se espere una reducción del precio por metro cuadrado en las propiedades más grandes. De esto podemos concluir que el modelo utilizado para el proceso de aprendizaje de la función objetivo no se ajusta lo suficientemente bien a los datos. La discrepancia se debe a menudo a una simplificación excesiva del modelo. Esto sucedió en nuestro caso, la función objetivo es demasiado simple y para el análisis utiliza un único parámetro: el área de la casa. Pero esta información no es suficiente para predecir con precisión el precio de una casa.

Agregar funciones y escalarlas

Si descubre que su función objetivo no corresponde al problema que está tratando de resolver, es necesario ajustarla. Una forma común de corregir la inconsistencia es agregar características adicionales al vector de características. En el ejemplo del precio de una casa, puedes añadir características como el número de habitaciones o la antigüedad de la casa. Es decir, en lugar de usar un vector con un valor de característica {size}para describir una casa, puede usar un vector con varios valores; por ejemplo, {size, number-of-rooms, age}. en algunos casos, la cantidad de características en los datos de entrenamiento disponibles no es suficiente. Entonces vale la pena intentar utilizar características polinómicas que se calculan utilizando las existentes. Por ejemplo, tienes la oportunidad de ampliar la función objetivo para determinar el precio de una casa para que incluya una característica calculada de metros cuadrados (x2):
Aprendizaje automático para desarrolladores de Java, Parte 2 - 8
El uso de múltiples funciones requiere escalado de funciones , que se utiliza para estandarizar el rango entre diferentes funciones. Por lo tanto, el rango de valores para el atributo de tamaño 2 es significativamente mayor que el rango de valores para el atributo de tamaño. Sin escalamiento de características, el tamaño 2 influirá indebidamente en la función de costos. El error introducido por el atributo de tamaño 2 será significativamente mayor que el error introducido por el atributo de tamaño. A continuación se proporciona un algoritmo de escalado de características simple:
Aprendizaje automático para desarrolladores de Java, Parte 2 - 9
Este algoritmo se implementa en la clase FeaturesScalingen el código de ejemplo siguiente. La clase FeaturesScalingpresenta un método comercial para crear una función de escalado que se ajusta a los datos de entrenamiento. Internamente, las instancias de datos de entrenamiento se utilizan para calcular los valores promedio, mínimo y máximo. La función resultante toma el vector de características y produce uno nuevo con las características escaladas. El escalado de funciones es necesario tanto para el proceso de aprendizaje como para el proceso de predicción, como se muestra a continuación:
// создание массива данных
List<ltDouble[]> dataset = new ArrayList<>();
dataset.add(new Double[] { 1.0, 90.0, 8100.0 }); // feature vector of house#1
dataset.add(new Double[] { 1.0, 101.0, 10201.0 }); // feature vector of house#2
dataset.add(new Double[] { 1.0, 103.0, 10609.0 }); // ...
//...

// создание меток
List<ltDouble> labels = new ArrayList<>();
labels.add(249.0); // price label of house#1
labels.add(338.0); // price label of house#2
labels.add(304.0); // ...
//...

// создание расширенного списка признаков
Function<ltDouble[], Double[]> scalingFunc = FeaturesScaling.createFunction(dataset);
List<ltDouble[]> scaledDataset = dataset.stream().map(scalingFunc).collect(Collectors.toList());

// создаем функцию которая инициализирует теты и осуществляет обучение //используя коэффициент обучения 0.1

LinearRegressionFunction targetFunction = new LinearRegressionFunction(new double[] { 1.0, 1.0, 1.0 });
for (int i = 0; i < 10000; i++) {
 targetFunction = Learner.train(targetFunction, scaledDataset, labels, 0.1);
}

// делаем предсказание стоимости дома с площадью 600 m2
Double[] scaledFeatureVector = scalingFunc.apply(new Double[] { 1.0, 600.0, 360000.0 });
double predictedPrice = targetFunction.apply(scaledFeatureVector);
A medida que se agregan más funciones, aumenta el ajuste a la función objetivo, pero tenga cuidado. Si va demasiado lejos y agrega demasiadas funciones, puede terminar aprendiendo una función objetivo que esté sobreadaptada.

Sobrecoincidencia y validación cruzada

El sobreajuste ocurre cuando la función o modelo objetivo se ajusta demasiado bien a los datos de entrenamiento, hasta el punto de capturar ruido o variaciones aleatorias en los datos de entrenamiento. En el siguiente gráfico situado más a la derecha se muestra un ejemplo de sobreajuste:
Aprendizaje automático para desarrolladores de Java, Parte 2 - 10
Sin embargo, un modelo de sobreajuste funciona muy bien con datos de entrenamiento, pero tendrá un rendimiento deficiente con datos reales desconocidos. Hay varias formas de evitar el sobreajuste.
  • Utilice un conjunto de datos más grande para el entrenamiento.
  • Utilice menos funciones como se muestra en los gráficos anteriores.
  • Utilice un algoritmo de aprendizaje automático mejorado que tenga en cuenta la regularización.
Si un algoritmo de predicción sobreajusta los datos de entrenamiento, es necesario eliminar características que no benefician su precisión. La dificultad es encontrar características que tengan un efecto más significativo que otras en la precisión de la predicción. Como se muestra en los gráficos, el sobreajuste se puede determinar visualmente mediante gráficos. Esto funciona bien para gráficos con 2 o 3 coordenadas; resulta difícil trazar y evaluar el gráfico si utiliza más de 2 funciones. En la validación cruzada, se vuelven a probar los modelos después del entrenamiento utilizando datos desconocidos para el algoritmo una vez finalizado el proceso de entrenamiento. Los datos etiquetados disponibles deben dividirse en 3 conjuntos:
  • datos de entrenamiento;
  • datos de verificación;
  • datos de prueba.
En este caso, el 60 por ciento de los registros etiquetados que caracterizan las casas deben usarse en el proceso de entrenamiento de variantes del algoritmo objetivo. Después del proceso de entrenamiento, la mitad de los datos restantes (no utilizados previamente) deben usarse para verificar que el algoritmo objetivo entrenado funciona bien con los datos desconocidos. Normalmente, se selecciona para su uso el algoritmo que funciona mejor que otros. Los datos restantes se utilizan para calcular el valor de error para el modelo final seleccionado. Existen otras técnicas de validación cruzada, como k-fold . Sin embargo, no los describiré en este artículo.

Herramientas de aprendizaje automático y marco Weka.

La mayoría de los marcos y bibliotecas proporcionan una extensa colección de algoritmos de aprendizaje automático. Además, proporcionan una cómoda interfaz de alto nivel para entrenar, probar y procesar modelos de datos. Weka es uno de los frameworks más populares para JVM. Weka es una práctica biblioteca Java que contiene pruebas gráficas para validar modelos. El siguiente ejemplo utiliza la biblioteca Weka para crear un conjunto de datos de entrenamiento que contiene características y etiquetas. Método setClassIndex(): para marcar. En Weka, una etiqueta se define como una clase:
// определяем атрибуты для признаков и меток
ArrayList<ltAttribute> attributes = new ArrayList<>();
Attribute sizeAttribute = new Attribute("sizeFeature");
attributes.add(sizeAttribute);
Attribute squaredSizeAttribute = new Attribute("squaredSizeFeature");
attributes.add(squaredSizeAttribute);
Attribute priceAttribute = new Attribute("priceLabel");
attributes.add(priceAttribute);


// создаем и заполняем список признаков 5000 примеров
Instances trainingDataset = new Instances("trainData", attributes, 5000);
trainingDataset.setClassIndex(trainingSet.numAttributes() - 1);
Instance instance = new DenseInstance(3);

instance.setValue(sizeAttribute, 90.0);
instance.setValue(squaredSizeAttribute, Math.pow(90.0, 2));
instance.setValue(priceAttribute, 249.0);
trainingDataset.add(instance);
Instance instance = new DenseInstance(3);
instance.setValue(sizeAttribute, 101.0);
...
El conjunto de datos y el objeto de muestra se pueden guardar y cargar desde un archivo. Weka utiliza ARFF (Formato de archivo de relación de atributos) que es compatible con los puntos de referencia de gráficos de Weka. Este conjunto de datos se utiliza para entrenar una función objetivo conocida como clasificador en Weka. En primer lugar, debes definir la función objetivo. El siguiente código LinearRegressioncreará una instancia del clasificador. Este clasificador se entrenará utilizando buildClassifier(). El método buildClassifier()selecciona parámetros theta basándose en datos de entrenamiento en busca del mejor modelo objetivo. Con Weka, no tiene que preocuparse por establecer la tasa de aprendizaje o el número de iteraciones. Weka también realiza el escalado de funciones de forma independiente.
Classifier targetFunction = new LinearRegression();
targetFunction.buildClassifier(trainingDataset);
Una vez realizados estos ajustes, la función objetivo se puede utilizar para predecir el precio de la casa, como se muestra a continuación:
Instances unlabeledInstances = new Instances("predictionset", attributes, 1);
unlabeledInstances.setClassIndex(trainingSet.numAttributes() - 1);
Instance unlabeled = new DenseInstance(3);
unlabeled.setValue(sizeAttribute, 1330.0);
unlabeled.setValue(squaredSizeAttribute, Math.pow(1330.0, 2));
unlabeledInstances.add(unlabeled);

double prediction = targetFunction.classifyInstance(unlabeledInstances.get(0));
Weka ofrece una clase Evaluationpara probar un clasificador o modelo entrenado. En el código siguiente, se utiliza una matriz seleccionada de datos de validación para evitar resultados falsos. Los resultados de la medición (coste del error) se mostrarán en la consola. Normalmente, los resultados de la evaluación se utilizan para comparar modelos que se entrenaron utilizando diferentes algoritmos de aprendizaje automático o variaciones de estos:
Evaluation evaluation = new Evaluation(trainingDataset);
evaluation.evaluateModel(targetFunction, validationDataset);
System.out.println(evaluation.toSummaryString("Results", false));
El ejemplo anterior utiliza la regresión lineal, que predice valores numéricos, como el precio de una casa, en función de los valores de entrada. La regresión lineal admite la predicción de valores numéricos continuos. Para predecir valores binarios ("Sí" y "No"), es necesario utilizar otros algoritmos de aprendizaje automático. Por ejemplo, árbol de decisión, redes neuronales o regresión logística.
// использование логистической регрессии
Classifier targetFunction = new Logistic();
targetFunction.buildClassifier(trainingSet);
Puede utilizar uno de estos algoritmos, por ejemplo, para predecir si un mensaje de correo electrónico es spam, predecir el tiempo o predecir si una casa se venderá bien. Si desea enseñarle a su algoritmo a predecir el clima o qué tan rápido se venderá una casa, necesita un conjunto de datos diferente, p.topseller:
// использование атрибута маркера topseller en lugar de атрибута маркера цена
ArrayList<string> classVal = new ArrayList<>();
classVal.add("true");
classVal.add("false");

Attribute topsellerAttribute = new Attribute("topsellerLabel", classVal);
attributes.add(topsellerAttribute);
Este conjunto de datos se utilizará para entrenar un nuevo clasificador topseller. Una vez entrenada, la llamada de predicción debería devolver un índice de clase de token que pueda usarse para obtener el valor predicho.
int idx = (int) targetFunction.classifyInstance(unlabeledInstances.get(0));
String prediction = classVal.get(idx);

Conclusión

Aunque el aprendizaje automático está estrechamente relacionado con la estadística y utiliza muchos conceptos matemáticos, el kit de herramientas de aprendizaje automático le permite comenzar a integrar el aprendizaje automático en sus programas sin un conocimiento profundo de las matemáticas. Sin embargo, cuanto mejor comprenda los algoritmos de aprendizaje automático subyacentes, como el algoritmo de regresión lineal que exploramos en este artículo, más podrá elegir el algoritmo correcto y ajustarlo para obtener un rendimiento óptimo. Traducción del inglés. Autor: Gregor Roth, arquitecto de software, JavaWorld.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION