PRML Kapitel 5 Python-Implementierung eines Netzwerks mit gemischter Dichte

Letztes Mal habe ich ein gewöhnliches neuronales Netzwerk implementiert, ohne Bibliotheken wie Tensorflow und Chainer zu verwenden. Es gibt jedoch bereits viele solcher Implementierungen im Netz, und das ist nicht sehr interessant. Deshalb habe ich dieses Mal ein Netzwerk mit gemischter Dichte ** implementiert, um mich auf das letzte Mal vorzubereiten. Da der Code des zuletzt implementierten neuronalen Netzwerks verwendet wird, lesen Sie bitte Vorheriger Artikel.

Netzwerk mit gemischter Dichte

Probleme mit herkömmlichen Modellen

Bei der Lösung des Regressionsproblems ist es möglicherweise nicht möglich, mit der Fehlerfunktion der Quadratsumme gut damit umzugehen. Die folgende Abbildung (Reproduktion von PRML Abbildung 5.19) zeigt das Ergebnis, als das neuronale Netzwerk unter Verwendung der Fehlerfunktion der Quadratsumme unter Verwendung der blauen Punkte als Trainingsdaten trainiert wurde. inverse_problem.png Wenn $ x = 0,5 $ ist, sieht der Wert von $ y $ bei 0,2, 0,5 oder 0,8 gut aus. Da ich jedoch einen von ihnen auswählen muss, wird er 0,5 und ich passe nicht zu den anderen beiden. ** Ich habe das neuronale Netzwerk trainiert, passte aber nicht sehr gut, da die Kostenfunktion einer monomodalen Gaußschen Verteilung nachempfunden ist **. Die Beziehung zwischen der Eingabe $ x $ und dem Ziel $ t $ wird in einer Gaußschen Verteilung wie folgt ausgedrückt.

p(t|x) = \mathcal{N}(t|\mu(x),\sigma^2),

Basierend darauf wurden Anpassung und Schätzung der Funktion $ \ mu (x) $ durchgeführt. Und das geschätzte $ \ mu (x) $ ist in der obigen Abbildung rot, was ein schlechtes Ergebnis ist.

Gemischte Gaußsche Verteilung

Das Netzwerk mit gemischter Dichte löst das obige Problem, indem eine Kostenfunktion verwendet wird, die einer multimodalen gemischten Gaußschen Verteilung nachempfunden ist. Bereiten Sie einen Mischungskoeffizienten $ \ pi \ _k $ für jede K-Gauß-Verteilung vor und ermitteln Sie die Beziehung zwischen der Eingabe $ x $ und dem Ziel $ t $.

p(t|x) = \sum_{k=1}^K\pi_k(x)\mathcal{N}(t|\mu_k(x),\sigma^2_k(x))

Modell mit. Die Summe der Mischungskoeffizienten beträgt jedoch 1 ($ \ sum_k \ pi_k = 1 $). Im obigen Beispiel für Trainingsdaten gibt es bei $ x = 0,5 $ einen Satz von 3 Datenpunkten um $ y = 0,2,0,5,0,8 $. Daher scheint es gut, $ K = 3 $ zu setzen. Durch Anpassen der drei Gaußschen Verteilungen an verschiedene Sätze von Datenpunkten können sogar multimodale Daten verarbeitet werden. Daher ist angesichts des Trainingsdatensatzes $ \ {x \ _n, t \ _n \} _ {n = 1} ^ N $ die zu optimierende Kostenfunktion

\begin{align}
E(w) &= \sum_{n=1}^N E_n\\
&= -\sum_{n=1}^N \ln p(t_n|x_n)\\
&= -\sum_{n=1}^N \ln \left\{\sum_{k=1}^K\pi_k(x_n,w)\mathcal{N}\left(t_n|\mu_k(x_n,w),\sigma^2_k(x_n,w)\right)\right\}
\end{align}

Es wird sein. Dann schätzen wir den Parameter $ w $, der die obige Gleichung minimiert. Ein neuronales Netzwerk wird für die Funktionen $ \ pi_k, \ mu_k, \ sigma_k $ verwendet. Wenn Sie die Eingabe $ x $ mit dem Parameter $ w $ in das Netzwerk einfügen, werden der Mischungskoeffizient, der Mittelwert und die Varianz ausgegeben und die Wahrscheinlichkeitsverteilung von $ t $ berechnet.

Netzwerkstruktur

Diesmal ist die Eingabe $ {\ bf x} $ eindimensional, da die Regression für die Daten durchgeführt wird, wie in der obigen Abbildung gezeigt. Die Anzahl der Knoten in der Mitte $ {\ bf z} $ beträgt laut PRML 5, und die Anzahl der Knoten in der Ausgabe $ {\ bf y} $ beträgt 9. Die Parameter der ersten Schicht sind $ W ^ {(1)}, {\ bf b} ^ {(1)} $, die Aktivierungsfunktion ist $ f (\ cdot) $ und die Parameter der zweiten Schicht sind $ W ^ { Als (2)}, {\ bf b} ^ {(2)} $ ist die Vorwärtsausbreitung wie folgt.

\begin{align}
{\bf z} &= f(W^{(1)}{\bf x} + {\bf b}^{(1)})\\
{\bf y} &= W^{(2)}{\bf z} + {\bf b}^{(2)}
\end{align}

Diese neun Ausgaben sind die Aktivitäten der gemischten Gaußschen Verteilungsparameter $ \ pi_k, \ mu_k, \ sigma_k $. Erstens ist die Ausgabe $ {\ bf y} $ die Aktivität, die $ \ pi, \ mu, \ sigma $ drei von oben entspricht.

{\bf y} =
\begin{bmatrix}
a_{\pi_1}\\
a_{\pi_2}\\
a_{\pi_3}\\
a_{\mu_1}\\
a_{\mu_2}\\
a_{\mu_3}\\
a_{\sigma_1}\\
a_{\sigma_2}\\
a_{\sigma_3}
\end{bmatrix}

Da der Mischungskoeffizient $ \ pi_k $ eine Einschränkung von $ \ sum_k \ pi_k = 1 $ hat, wird der Mischungskoeffizient von der Softmax-Funktion ausgegeben.

\pi_k = {\exp(a_{\pi_k})\over\sum_{l=1}^K\exp(a_{\pi_l})}

Der Durchschnitt ist $ \ mu_k = a_ {\ mu_k} $ ohne die nichtlineare Transformation. Da die Standardabweichung $ \ sigma $ 0 oder mehr ist, verwenden Sie die Exponentialfunktion $ \ sigma_k = \ exp (a_ {\ sigma_k}) $. Sie haben jetzt die Funktionen $ \ pi_k, \ mu_k, \ sigma_k $, die zur Berechnung der gemischten Gaußschen Verteilung benötigt werden.

Steigung

Wie ich in der vorherigen Implementierung eines neuronalen Netzwerks geschrieben habe, ist zum Trainieren eines neuronalen Netzwerks ein Gradient erforderlich, der durch Differenzieren der Kostenfunktion mit der Ausgabe des neuronalen Netzwerks erhalten wird. Damit können Sie auch die Fehler-Backpropagation verwenden, um die Differenz für den Kostenfunktionsparameter $ w $ zu berechnen. Der Gradient am Ausgang des neuronalen Netzes dieser Kostenfunktion ist

\gamma_{nk}(t_n|x_n) = {\pi_k\mathcal{N}(t_n|\mu_k(x_n,w),\sigma_k^2(x_n,w))\over\sum_l\pi_l\mathcal{N}(t_n|\mu_l(x_n,w),\sigma_l^2(x_n,w))}

Verwenden von,

\begin{align}
{\partial E_n\over\partial a_{\pi_k}} &= \pi_k - \gamma_{nk}\\
{\partial E_n\over\partial a_{\mu_k}} &= \gamma_{nk}{\mu_k - t_n\over\sigma^2_k}\\
{\partial E_n\over\partial a_{\sigma_k}} &= \gamma_{nk}\left(1 - {||t_n - \mu_k||^2\over \sigma^2_k}\right)
\end{align}

Es wird sein. Die Ableitung von Formeln ist eine Übung in PRML. Lesen Sie daher bitte die Antwort oder das Papier zum Netzwerk mit gemischter Dichte.

Implementierung

Kostenfunktion

Der Code der oben geschriebenen Formel lautet wie folgt.

#Kostenfunktionsklasse
class GaussianMixture(object):
    """Negative Log Likelihood of Gaussian Mixture model"""
    def __init__(self, n_components):
        #Anzahl der Gaußschen Verteilungen, 3 in vorherigen Beispielen
        self.n_components = n_components

    #Methode zur Berechnung des Wertes der Kostenfunktion
    def __call__(self, X, targets):

        #Konvertieren Sie den Netzwerkausgang X mit Aktivierungsfunktion, um die Standardabweichung, den Mischungskoeffizienten und den Durchschnitt zu berechnen
        sigma, weight, mu = self.activate(X)

        #Gaußsche Funktion N.(t|mu,sigma^2)Berechnen Sie den Wert von
        gauss = self.gauss(mu, sigma, targets)

        #Negative Log-Wahrscheinlichkeit E für gemischte Gaußsche Verteilung(w):PRML(Gleichung 5.153)
        return -np.sum(np.log(np.sum(weight * gauss, axis=1)))

    #Konvertieren mit Aktivierungsfunktion
    def activate(self, X):
        assert np.size(X, 1) == 3 * self.n_components

        #Teilen Sie X, wo es der Standardabweichung, dem Mischungskoeffizienten und dem Mittelwert entspricht
        X_sigma, X_weight, X_mu = np.split(X, [self.n_components, 2 * self.n_components], axis=1)

        #Standardabweichung mit Aktivierungsfunktion umrechnen
        sigma = np.exp(X_sigma)

        #Konvertieren Sie den Mischungskoeffizienten mit der Aktivierungsfunktion und subtrahieren Sie den Maximalwert, damit die Ziffern nicht überlaufen
        weight = np.exp(X_weight - np.max(X_weight, 1, keepdims=True))
        weight /= np.sum(weight, axis=1, keepdims=True)

        return sigma, weight, X_mu

    #Gaußsche Funktion N.(target|mu,sigma^2)Berechnung
    def gauss(self, mu, sigma, targets):
        return np.exp(-0.5 * (mu - targets) ** 2 / np.square(sigma)) / np.sqrt(2 * np.pi * np.square(sigma))

    #Unterscheiden Sie die Kostenfunktion nach Aktivität
    def delta(self, X, targets):
        sigma, weight, mu = self.activate(X)
        var = np.square(sigma)
        gamma = weight * self.gauss(mu, sigma, targets)
        gamma /= np.sum(gamma, axis=1, keepdims=True)

        #Berechnen Sie jedes Differential
        delta_mu = gamma * (mu - targets) / var
        delta_sigma = gamma * (1 - (mu - targets) ** 2 / var)
        delta_weight = weight - gamma

        #Verbinden und dann zurückkehren
        delta = np.hstack([delta_sigma, delta_weight, delta_mu])
        return delta

Erstellung von Trainingsdaten

#Erstellen Sie Trainingsdaten, die der Umkehrfunktion der Funktion func folgen
def create_toy_dataset(func, n=300):
    t = np.random.uniform(size=(n, 1))
    x = func(t) + np.random.uniform(-0.05, 0.05, size=(n, 1))
    return x, t

Mini-Stapelverarbeitung

Eine der Methoden, die ich in Eile angewendet habe, weil es Zeiten gab, in denen das Lernen nicht gut lief. Anstatt alle Trainingsdaten zur Berechnung des Gradienten zu verwenden, nehmen wir einige aus den Trainingsdaten und führen die Gradientenberechnung durch. Auf diese Weise können Sie möglicherweise die lokale Lösung verlassen.

#Trainingsdatensatz x,Wähle zufällig n Paare aus t aus
def sample(x, t, n=None):
    assert len(x) == len(t)
    N = len(x)
    if n is None:
        n = N
    indices = np.random.choice(N, n, replace=False)
    return x[indices], t[indices]

Netzwerke mit gemischter Dichte lernen

Dies ist die Hauptfunktion, die das Netzwerk mit gemischter Dichte lernt und das Ergebnis veranschaulicht.

def main():

    def func(x):
        return x + 0.3 * np.sin(2 * np.pi * x)

    #Generieren Sie Datenpunkte gemäß der Umkehrfunktion der Funktion func
    x, t = create_toy_dataset(func)

    #Bestimmen Sie die Struktur des neuronalen Netzwerks.
    layers = [TanhLayer(1, 5, std=0.1), LinearLayer(5, 9, std=0.1)]
    #Bestimmen Sie die zu optimierende Kostenfunktion
    cost_function = GaussianMixture(3)
    #Erstellen Sie ein neuronales Netzwerk
    nn = NeuralNetwork(layers, cost_function)
    #Kommentieren Sie die folgende Zeile aus, um zu überprüfen, ob die Implementierung funktioniert.
    # nn._gradient_check(np.array([[0.5]]), np.array([[0.5]]))

    #Stellen Sie den ersten Lernkoeffizienten ein
    learning_rate = 1e-4
    for i in xrange(500000):
        #Berechnen Sie den Wert der Kostenfunktion alle 10.000 Mal und setzen Sie den Lernkoeffizienten auf 0.9 mal
        if i % 10000 == 0:
            print "step %6d, cost %f" % (i, nn.cost(x, t))
            learning_rate *= 0.9
        #Mini-Stapelverarbeitung
        batch = sample(x, t, n=100)
        nn.fit(*batch, learning_rate=learning_rate)

    #Testdaten erstellen
    x_test = np.linspace(x.min(), x.max(), 100)
    y_test = np.linspace(t.min(), t.max(), 100)
    X_test, Y_test = np.meshgrid(x_test, y_test)
    test = np.array([X_test, Y_test]).transpose(1, 2, 0).reshape(-1, 2)

    #Berechnen Sie die Wahrscheinlichkeit von Testdaten
    sigma, weight, mu = nn(test[:, 0].reshape(-1, 1))
    probs = cost_function.gauss(mu, sigma, test[:, 1].reshape(-1, 1))
    probs = np.sum(weight * probs, axis=1)
    Probs = probs.reshape(100, 100)

    #PRML Abbildung 5.21(a)Reproduktion von
    plt.plot(x_test, weight[:100, 0], color="blue")
    plt.plot(x_test, weight[:100, 1], color="red")
    plt.plot(x_test, weight[:100, 2], color="green")
    plt.title("weights")
    plt.show()

    #PRML Abbildung 5.21(b)Reproduktion von
    plt.plot(x_test, mu[:100, 0], color="blue")
    plt.plot(x_test, mu[:100, 1], color="red")
    plt.plot(x_test, mu[:100, 2], color="green")
    plt.title("means")
    plt.show()

    #PRML Abbildung 5.21(c)Reproduktion von
    plt.scatter(x, t, alpha=0.5, label="observation")
    levels_log = np.linspace(0, np.log(probs.max()), 21)
    levels = np.exp(levels_log)
    levels[0] = 0
    plt.contourf(X_test, Y_test, Probs, levels, alpha=0.5)
    plt.colorbar()
    plt.xlim(x.min(), x.max())
    plt.ylim(t.min(), t.max())
    plt.show()

Ganzer Code

Das neural_network in der dritten Zeile ist das neural_network.py, das [letztes Mal] implementiert wurde (http://qiita.com/cutting_the_Gordian_knot/items/507f2f1531b870a973bf). Legen Sie es in das gleiche Verzeichnis wie diesen Code.

mixture_density_network.py


import matplotlib.pyplot as plt
import numpy as np
from neural_network import TanhLayer, LinearLayer, NeuralNetwork


class GaussianMixture(object):
    """Negative Log Likelihood of Gaussian Mixture model"""
    def __init__(self, n_components):
        self.n_components = n_components

    def __call__(self, X, targets):
        sigma, weight, mu = self.activate(X)
        gauss = self.gauss(mu, sigma, targets)
        return -np.sum(np.log(np.sum(weight * gauss, axis=1)))

    def activate(self, X):
        assert np.size(X, 1) == 3 * self.n_components
        X_sigma, X_weight, X_mu = np.split(X, [self.n_components, 2 * self.n_components], axis=1)
        sigma = np.exp(X_sigma)
        weight = np.exp(X_weight - np.max(X_weight, 1, keepdims=True))
        weight /= np.sum(weight, axis=1, keepdims=True)
        return sigma, weight, X_mu

    def gauss(self, mu, sigma, targets):
        return np.exp(-0.5 * (mu - targets) ** 2 / np.square(sigma)) / np.sqrt(2 * np.pi * np.square(sigma))

    def delta(self, X, targets):
        sigma, weight, mu = self.activate(X)
        var = np.square(sigma)
        gamma = weight * self.gauss(mu, sigma, targets)
        gamma /= np.sum(gamma, axis=1, keepdims=True)

        delta_mu = gamma * (mu - targets) / var
        delta_sigma = gamma * (1 - (mu - targets) ** 2 / var)
        delta_weight = weight - gamma
        delta = np.hstack([delta_sigma, delta_weight, delta_mu])
        return delta


def create_toy_dataset(func, n=300):
    t = np.random.uniform(size=(n, 1))
    x = func(t) + np.random.uniform(-0.05, 0.05, size=(n, 1))
    return x, t


def sample(x, t, n=None):
    assert len(x) == len(t)
    N = len(x)
    if n is None:
        n = N
    indices = np.random.choice(N, n, replace=False)
    return x[indices], t[indices]


def main():

    def func(x):
        return x + 0.3 * np.sin(2 * np.pi * x)

    x, t = create_toy_dataset(func)

    layers = [TanhLayer(1, 5, std=0.1), LinearLayer(5, 9, std=0.1)]
    cost_function = GaussianMixture(3)
    nn = NeuralNetwork(layers, cost_function)
    # nn._gradient_check(np.array([[0.5]]), np.array([[0.5]]))
    learning_rate = 1e-4
    for i in xrange(500000):
        if i % 10000 == 0:
            print "step %6d, cost %f" % (i, nn.cost(x, t))
            learning_rate *= 0.9
        batch = sample(x, t, n=100)
        nn.fit(*batch, learning_rate=learning_rate)

    x_test = np.linspace(x.min(), x.max(), 100)
    y_test = np.linspace(t.min(), t.max(), 100)
    X_test, Y_test = np.meshgrid(x_test, y_test)
    test = np.array([X_test, Y_test]).transpose(1, 2, 0).reshape(-1, 2)

    sigma, weight, mu = nn(test[:, 0].reshape(-1, 1))
    probs = cost_function.gauss(mu, sigma, test[:, 1].reshape(-1, 1))
    probs = np.sum(weight * probs, axis=1)
    Probs = probs.reshape(100, 100)

    plt.plot(x_test, weight[:100, 0], color="blue")
    plt.plot(x_test, weight[:100, 1], color="red")
    plt.plot(x_test, weight[:100, 2], color="green")
    plt.title("weights")
    plt.show()

    plt.plot(x_test, mu[:100, 0], color="blue")
    plt.plot(x_test, mu[:100, 1], color="red")
    plt.plot(x_test, mu[:100, 2], color="green")
    plt.title("means")
    plt.show()

    plt.scatter(x, t, alpha=0.5, label="observation")
    levels_log = np.linspace(0, np.log(probs.max()), 21)
    levels = np.exp(levels_log)
    levels[0] = 0
    plt.contourf(X_test, Y_test, Probs, levels, alpha=0.5)
    plt.colorbar()
    plt.xlim(x.min(), x.max())
    plt.ylim(t.min(), t.max())
    plt.show()


if __name__ == '__main__':
    main()

Ergebnis

Als Ergebnis der Ausführung des obigen Codes zum Trainieren des Netzwerks mit gemischter Dichte unter Verwendung des blauen Punkts als Trainingsdatenpunkt wurde das in Abbildung 5.21 von PRML gezeigte Diagramm reproduziert. Die Linienfarbe usw. kann jedoch unterschiedlich sein. Es wird durch drei Gaußsche Verteilungen, blau, rot und grün, an die Trainingsdatenpunkte angepasst. result_weights.png result_means.png result_distributions.png

Stand des Lernens

Wie beim letzten Mal habe ich ein Video des Lernprozesses gemacht. anime_gaussian_mixture.gif

Am Ende

Ich hatte erst von dem Mixed-Density-Netzwerk gehört, als ich es auf PRML gelesen hatte. Als ich im Internet suchte, war der Artikel des PRML-Autors CM Bishop aus dem Jahr 1994 ein Hit, also diese Person selbst Kann von befürwortet worden sein. Das Netzwerk mit gemischter Dichte scheint effektiver zu sein als das herkömmliche Modell, wenn es multimodal ist. Daher möchte ich dies auf einige tatsächliche Daten anwenden.

Recommended Posts

PRML Kapitel 5 Python-Implementierung eines Netzwerks mit gemischter Dichte
PRML Kapitel 5 Python-Implementierung für neuronale Netze
PRML Kapitel 9 Mixed Gaussian Distribution Python-Implementierung
PRML Kapitel 14 Bedingte gemischte Modell-Python-Implementierung
PRML Kapitel 3 Evidence Ungefähre Python-Implementierung
PRML Kapitel 8 Summe der Produkte Algorithmus Python-Implementierung
PRML Kapitel 4 Bayesianische logistische Regression Python-Implementierung
PRML Kapitel 10 Variante Mixed Gaussian Distribution Python-Implementierung
PRML Kapitel 6 Gaussian Return Python-Implementierung
PRML Kapitel 2 Python-Implementierung von Student t-Distribution
PRML Kapitel 1 Bayesian Curve Fitting Python-Implementierung
PRML Kapitel 11 Implementierung der Markov-Kette Monte Carlo Python
PRML Kapitel 12 Bayesianische Hauptanalyse Python-Implementierung
Python-Implementierung gemischte Bernoulli-Verteilung
Implementierung eines neuronalen Netzwerks in Python
PRML Kapitel 7 Verwandte Vector Machine Python-Implementierung für Regressionsprobleme
Erläuterung und Implementierung von PRML Kapitel 4
Implementierung einer gemischten Normalverteilung in Python
PRML Kapitel 13 Wahrscheinlichste Schätzung Python-Implementierung des Hidden-Markov-Modells
PRML-Implementierung Kapitel 3 Lineares Basisfunktionsmodell
Implementiert in Python PRML Kapitel 7 Nichtlineare SVM
Implementiert in Python PRML Kapitel 5 Neuronales Netzwerk
Implementiert in Python PRML Kapitel 1 Bayesianische Schätzung
Implementiert in Python PRML Kapitel 3 Bayesianische lineare Regression
Python vs Ruby "Deep Learning von Grund auf neu" Kapitel 3 Implementierung eines dreischichtigen neuronalen Netzwerks
Implementiert in Python PRML Kapitel 1 Polygonkurvenanpassung
[Python] Implementierung von Clustering mit einem gemischten Gaußschen Modell
Implementiert in Python PRML Kapitel 4 Klassifizierung nach Perceptron-Algorithmus
RNN-Implementierung in Python
ValueObject-Implementierung in Python
[Python] Kapitel 01-01 Über Python (Erster Python)
SVM-Implementierung in Python