Vahid Mirjalili

Python Machine Learning


Скачать книгу

for i in range(self.n_iter):

       net_input = self.net_input(X)

       output = self.activation(net_input)

       errors = (y - output)

       self.w_[1:] += self.eta * X.T.dot(errors)

       self.w_[0] += self.eta * errors.sum()

       cost = (errors**2).sum() / 2.0

       self.cost_.append(cost)

       return self

       def net_input(self, X):

       """Calculate net input"""

       return np.dot(X, self.w_[1:]) + self.w_[0]

       def activation(self, X):

       """Compute linear activation"""

       return X

       def predict(self, X):

       """Return class label after unit step"""

       return np.where(self.activation(self.net_input(X))

       >= 0.0, 1, -1)

      En lugar de actualizar los pesos después de evaluar cada muestra de entrenamiento individual, como en el perceptrón, calculamos el gradiente en base a todo el conjunto de datos de entrenamiento mediante self.eta * errors.sum() para el parámetro del sesgo (peso cero) y mediante self.eta * X.T.dot(errors) para los pesos 1 a m, donde X.T.dot(errors) es una multiplicación matriz por vector entre nuestra matriz de características y el vector de error.

      Observa que el método activation no tiene ningún efecto sobre el código, puesto que es simplemente una función de identidad. En este caso, hemos añadido la función de activación (calculada mediante el método activation) para mostrar cómo fluye la información a través de una red neuronal de una sola capa: características a partir de los datos de entrada, entrada de red, activación y salida. En el siguiente capítulo, conoceremos un clasificador de regresión logística que utiliza una función de activación no lineal sin identidad. Veremos que un modelo de regresión logística está estrechamente relacionado con Adaline, siendo la única diferencia su activación y función de coste.

      Ahora, de forma parecida a la implementación del perceptrón anterior, recogemos los valores de coste en una lista self.cost_ para comprobar si el algoritmo converge después del entrenamiento.

Llevar a cabo una multiplicación matriz por vector es similar a calcular un producto escalar, donde cada fila de la matriz es tratada como un único vector de fila. Este enfoque vectorizado representa una notación más compacta y da como resultado un cálculo más eficiente con NumPy. Por ejemplo:

      A la práctica, esto suele requerir algo de experimentación para encontrar un buen rango de aprendizaje para una óptima convergencia. Así que vamos a elegir dos rangos de aprendizaje distintos, y , para empezar y mostrar en un diagrama las funciones de coste frente al número de épocas, y ver cómo aprende la implementación de Adaline de los datos de entrenamiento.

El rango de aprendizaje (eta), así como el número de épocas (n_iter), también se conocen como hiperparámetros del perceptrón y algoritmos de aprendizaje Adaline. En el Capítulo 6, Aprender las mejores prácticas para la evaluación de modelos y el ajuste de hiperparámetros, veremos diferentes técnicas para encontrar automáticamente los valores de distintos hiperparámetros que producen un rendimiento óptimo del modelo de clasificación.

      Ahora veamos en un diagrama el coste contra el número de épocas para los dos rangos de aprendizaje distintos:

      >>> fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 4))

      >>> ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, y)

      >>> ax[0].plot(range(1, len(ada1.cost_) + 1),

      ... np.log10(ada1.cost_), marker='o')

      >>> ax[0].set_xlabel('Epochs')

      >>> ax[0].set_ylabel('log(Sum-squared-error)')

      >>> ax[0].set_title('Adaline - Learning rate 0.01')

      >>> ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, y)

      >>> ax[1].plot(range(1, len(ada2.cost_) + 1),

      ... ada2.cost_, marker='o')

      >>> ax[1].set_xlabel('Epochs')

      >>> ax[1].set_ylabel('Sum-squared-error')

      >>> ax[1].set_title('Adaline - Learning rate 0.0001')

      >>> plt.show()

      Como podemos ver en los diagramas de función coste obtenidos, nos encontraríamos con dos tipos de problemas. El gráfico de la izquierda muestra qué pasaría si eligiéramos un rango de aprendizaje demasiado amplio. En lugar de minimizar la función de coste, el error es mayor en cada época, porque sobrepasamos el mínimo global. Por otro lado, podemos ver que el coste disminuye en el diagrama de la derecha, pero el rango de aprendizaje elegido es tan pequeño que el algoritmo requeriría un número de épocas muy elevado para converger con el mínimo coste global:

      La siguiente imagen ilustra qué pasaría si cambiáramos el valor de un parámetro de peso concreto para minimizar la función de coste . La imagen de la izquierda muestra el caso de una buena elección del rango de aprendizaje, donde el coste disminuye gradualmente, moviéndose en la dirección del mínimo global. Sin embargo, la imagen de la derecha muestra qué pasa si elegimos un rango de aprendizaje demasiado amplio (que sobrepasamos el mínimo global):

      Muchos de los algoritmos de aprendizaje automático con los que nos encontraremos en este libro requieren algún tipo de escalado de características para un rendimiento óptimo, como veremos con mayor detalle en el Capítulo 3, Un recorrido por los clasificadores de aprendizaje automático con scikit-learn y en el Capítulo 4, Generar buenos modelos de entrenamiento - Preprocesamiento de datos.

      El descenso de gradiente es uno de los muchos algoritmos que se benefician del escalado de características. En esta sección, utilizaremos un método de escalado de características denominado normalización, que proporciona a nuestros datos la propiedad de una distribución normal estándar, la cual ayuda al descenso de gradiente a converger más rápidamente. La normalización cambia la media de cada característica para que se centre en cero y para que cada característica tenga una desviación estándar de 1. Por ejemplo, para normalizar la característica j, podemos simplemente sustraer la media de muestra