discesa del gradiente stocastica

Adaline in Python – Approfondimento Grafici

Come abbiamo imparato dal capitolo precedente, la differenza sostanziale tra il Perceptron e la regola Adaline sta nell’aggiornamento dei pesi che, nel primo caso avviene tramite l’utilizzo di una funzione a passo unitario mentre per il restante caso attraverso una funzione di attivazione lineare.

Nel modello Adaline inoltre, viene utilizzato un quantizzatore, che permette di prevedere le etichette delle classi.

Il grafico dei costi di Adaline

Come per tuttigli algoritmi di Machine Learning, dobbiamo trovare il tasso di apprendimento tale da garantire una convergenza ottimale. Per l’algoritmo Adaline decidiamo di partire con due tassi di apprendimento corrispondenti a n = 0.1 e n = 0.0001 e successivamente di tracciare le funzioni dei costi rispetto al numero di epoch.

Tutto ciò per vedere con quale efficacia Adaline in Python impara dai dati di addestramento.

Per una migliore gestione del codice, consiglio di proseguire in maniera progressiva a cascata sul file creato per l’implementazione del Perceptron così da avere i due modelli in un singolo file.

Riporto ora il codice necessario per implementare la classe Adaline in Python. Questa sezione l’abbiamo già analizzata nel capitolo precedente.

				
					class AdalineGD(object):
    """ADAptive LInear NEuron classifier.

    Parameters
    ------------
    eta : float
        Learning rate (between 0.0 and 1.0)
    n_iter : int
        Passes over the training dataset.

    Attributes
    -----------
    w_ : 1d-array
        Weights after fitting.
    cost_ : list
        Sum-of-squares cost function value in each epoch.

    """
    def __init__(self, eta=0.01, n_iter=50):
        self.eta = eta
        self.n_iter = n_iter

    def fit(self, X, y):
        """ Fit training data.

        Parameters
        ----------
        X : {array-like}, shape = [n_samples, n_features]
            Training vectors, where n_samples is the number of samples and
            n_features is the number of features.
        y : array-like, shape = [n_samples]
            Target values.

        Returns
        -------
        self : object

        """
        self.w_ = np.zeros(1 + X.shape[1])
        self.cost_ = []

        for i in range(self.n_iter):
            net_input = self.net_input(X)
            # Please note that the "activation" method has no effect
            # in the code since it is simply an identity function. We
            # could write `output = self.net_input(X)` directly instead.
            # The purpose of the activation is more conceptual, i.e.,  
            # in the case of logistic regression, we could change it to
            # a sigmoid function to implement a logistic regression classifier.
            output = self.activation(X)
            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 self.net_input(X)

    def predict(self, X):
        """Return class label after unit step"""
        return np.where(self.activation(X) >= 0.0, 1, -1)
				
			

E ora non ci resta che tracciare il grafico dei costi rispetto al numero di epoch con i tassi di apprendimento precedentemente descritti:

Leggi articolo   Classificazione a massimo margine con le macchine a vettori di supporto
				
					fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8, 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.tight_layout()
# plt.savefig('./adaline_1.png', dpi=300)
plt.show()
				
			

Ed ecco ora il risultato:

Analisi dei grafici di appredimento di Adaline in Python

I due grafici presentano in maniera evidente dei problemi:

  • Il primo grafico mostra ciò che accade se scegliamo un tasso di apprendimento troppo ampio, infatti, invece di minimizzare la funzione di costo, l‘errore diviene sempre più ampio ad ogni epoch.
  • Nel grafico a destra invece, il tasso di apprendimento troppo piccolo permette all’algoritmo di convergere dopo troppi epoch.

Riprendendo il concetto di gradiente, come illustrato dall’immagine:

Discesa del gradiente stocastica

Il grafico a sinistra ci mostra come possiamo cambiare il valore del parametro del peso per minimizzare la funzione di costo J. Invece, come nel caso della figura a destra, notiamo cosa succede se scegliamo un tasso di apprendimento troppo ampio: destabilizziamo sempre il minimo globale.

Necessitiamo quindi di una riduzione di scala per permettere all’algoritmo di performare nel migliore dei modi. La discesa del gradiente è proprio uno di questi algoritmi.

Standardizzazione per la riduzione in scala

La standardizzazione dei dati è il processo di ridimensionamento di uno o più attributi in modo che abbiano un valore medio di 0 e una deviazione standard di 1. Come risultato otterremo che le caratteristiche saranno ridimensionate in modo da avere le proprietà di una distribuzione normale con media nulla e deviazione standard pari a 1. Il valore Z-standard viene calcolato come segue:

Adaline in Python

dove u è la media dei campioni di addestramento, σ è la deviazione standard dei campioni di addestramento e xi è il valore che si vuole standardizzare.

Leggi articolo   Titanic dataset - esercizio di Machine Learning

Per effettuare la standardizzazione di Adaline in Python utilizzeremo i metodi mean e std di NumPy:

				
					X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()
				
			

A questo punto non ci resta che riaddestrare nuovamente Adaline in Python e vedere come converge con tasso di apprendimento n = 0.01.

				
					ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, y)

plot_decision_regions(X_std, y, classifier=ada)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
# plt.savefig('./adaline_2.png', dpi=300)
plt.show()

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')

plt.tight_layout()
# plt.savefig('./adaline_3.png', dpi=300)
plt.show()
				
			
discesa del gradiente stocastica

Notiamo così che l’algoritmo Adaline in Python converge con un tasso di apprendimento n = 0.01.

Condividi il post

Condividi su facebook
Condividi su google
Condividi su twitter
Condividi su email
Condividi su whatsapp