Mixture Density Networks


Hallo allerseits!

Lassen Sie uns, wie Sie vielleicht vermutet haben, über neuronale Netze und maschinelles Lernen sprechen. Aus dem Namen geht hervor, was über Mixture Density Networks und dann nur über MDN gesagt wird. Ich möchte den Namen nicht übersetzen und so lassen, wie er ist. Ja, ja, ja ... es wird ein wenig langweilige Mathematik und Wahrscheinlichkeitstheorie geben, aber ohne sie liegt es leider oder zum Glück an Ihnen, zu entscheiden, wie schwer es ist, sich die Welt des maschinellen Lernens vorzustellen. Aber ich beeile mich, Sie zu beruhigen, es wird relativ klein und es wird nicht sehr schwierig sein. Wie auch immer, Sie können es überspringen, aber sehen Sie sich nur eine kleine Menge Code in Python und PyTorch an. Richtig, wir werden das Netzwerk mit PyTorch sowie verschiedenen Diagrammen mit den Ergebnissen schreiben. Das Wichtigste ist jedoch, dass es die Möglichkeit gibt, ein wenig zu verstehen und zu verstehen, was MD-Netzwerke sind.

Nun, fangen wir an!



Regression


Lassen Sie uns zunächst unser Wissen ein wenig auffrischen und ganz kurz daran erinnern, was lineare Regression ist .

Wir haben einen Vektor X = \ {x_1, x_2, ..., x_n \}X = \ {x_1, x_2, ..., x_n \} Wir müssen den Wert vorhersagen Y , was irgendwie davon abhängt X unter Verwendung eines linearen Modells:

 hatY=XT hat beta

Als Fehlerfunktion verwenden wir den quadratischen Fehler:

SE( beta)= sumni=1(yi hatyi)2= sumNi=1(yixTi hat beta)2

Dieses Problem kann direkt gelöst werden, indem die Ableitung von SE genommen und ihr Wert auf Null gesetzt wird:

 frac deltaSE( beta) delta beta=2XT( mathbfyX beta)=0

Wir finden also einfach das Minimum und SE ist eine quadratische Funktion, was bedeutet, dass das Minimum immer existiert. Danach können Sie bereits leicht finden  beta ::

 hat beta=(XTX)1XT mathbfy

Das ist alles, das Problem ist gelöst. Hier beenden wir die Erinnerung an die lineare Regression.

Natürlich kann die Abhängigkeit, die der Art der Datengenerierung innewohnt, unterschiedlich sein, und dann muss unserem Modell bereits eine gewisse Nichtlinearität hinzugefügt werden. Das Regressionsproblem direkt für große und reale Daten zu lösen, ist ebenfalls eine schlechte Idee, da es eine Matrix gibt XTX Abmessungen n timesn und man muss immer noch seine inverse Matrix finden, und es kommt oft vor, dass eine solche Matrix einfach nicht existiert. In diesem Fall helfen uns verschiedene Methoden, die auf dem Gefälle basieren. Die Nichtlinearität von Modellen kann auf verschiedene Arten implementiert werden, einschließlich der Verwendung neuronaler Netze.

Aber jetzt sprechen wir nicht darüber, sondern über Fehlerfunktionen. Was ist der Unterschied zwischen SE und Log-Likelihood, wenn Daten eine nichtlineare Beziehung haben können?

Wir beschäftigen uns mit dem Zoo, nämlich: OLS, LS, SE, MSE, RSS
All dies ist im Wesentlichen ein und dasselbe, RSS - Restquadratsumme, OLS - gewöhnliche kleinste Quadrate, LS - kleinste Quadrate, MSE - mittlerer quadratischer Fehler, SE - quadratischer Fehler. In verschiedenen Quellen finden Sie unterschiedliche Namen. Das Wesentliche davon ist nur eines: quadratische Abweichung . Sie können natürlich verwirrt sein, aber Sie gewöhnen sich schnell daran.

Es ist anzumerken, dass MSE die Standardabweichung ist, ein bestimmter Durchschnittswert des Fehlers für den gesamten Trainingsdatensatz. In der Praxis wird normalerweise MSE verwendet. Die Formel ist nicht besonders unterschiedlich:

MSE( beta)= frac1N sumni=1(yi hatyi)2

N - die Größe des Datensatzes,  hatyi - Modellvorhersage für yi .

Hör auf! Wahrscheinlichkeit? Dies ist etwas aus der Wahrscheinlichkeitstheorie. Das stimmt - es ist reine Wahrscheinlichkeitstheorie. Aber wie kann die quadratische Abweichung mit der Wahrscheinlichkeitsfunktion in Beziehung gesetzt werden? Und wie es ausgeht. Es ist verbunden mit dem Finden der maximalen Wahrscheinlichkeit (Maximum Likelihood) und mit einer Normalverteilung, genauer gesagt mit ihrem Durchschnitt  mu .

Um dies zu erkennen, schauen wir uns noch einmal die Quadratabweichungsfunktion an:

RSS( beta)= sumni=1(yi hatyi)2 qquad qquad(1)

Nehmen wir nun an, dass die Wahrscheinlichkeitsfunktion eine Normalform hat, d. H. Eine Gaußsche oder Normalverteilung:

L(X)=p(X| Theta)= prodX mathcalN(xi; mu, sigma2)

Im Allgemeinen, was die Wahrscheinlichkeitsfunktion ist und welche Bedeutung sie hat, werde ich nicht sagen. Sie können sie an anderer Stelle lesen. Sie sollten sich auch mit dem Konzept der bedingten Wahrscheinlichkeit, dem Bayes-Theorem und vielem mehr vertraut machen, um ein tieferes Verständnis zu erlangen. Dies alles geht in die reine Wahrscheinlichkeitstheorie ein, die sowohl in der Schule als auch an der Universität studiert wird.

Wenn wir uns nun an die Normalverteilungsformel erinnern, erhalten wir:

L(X; mu, sigma2)= prodX frac1 sqrt2 pi sigma2e frac(xi mu)22 sigma2 qquad qquad(2)

Was ist, wenn wir die Standardabweichung setzen?  sigma2=1 und entfernen Sie alle Konstanten in Formel (2), entfernen Sie einfach, reduzieren Sie nicht, da das Finden des Minimums der Funktion nicht von ihnen abhängt. Dann werden wir das sehen:

L(X; mu, sigma2) sim prodXe(xi mu)2

Immer noch nichts wie? Nein? Was ist, wenn wir den Logarithmus der Funktion nehmen? Aus dem Logarithmus ergeben sich im Allgemeinen einige Pluspunkte: Die Multiplikation wird zu einer Summe, ein Grad zur Multiplikation und  loge=1 - Für diese Eigenschaft sollte klargestellt werden, dass es sich um den natürlichen Logarithmus handelt und genau genommen  lne=1 . Und im Allgemeinen ändert der Logarithmus einer Funktion nicht ihr Maximum, und dies ist das wichtigste Merkmal für uns. Der Zusammenhang mit Log-Likelihood und Likelihood und warum dies nützlich sein wird, wird unten in einem kleinen Exkurs beschrieben. Und so haben wir alle Konstanten entfernt und den Logarithmus der Wahrscheinlichkeitsfunktion übernommen. Sie haben auch das Minuszeichen entfernt und so Log-Likelihood in Negative Log-Likelihood (NLL) umgewandelt. Die Verbindung zwischen ihnen wird auch als Bonus beschrieben. Als Ergebnis haben wir die NLL-Funktion erhalten:

 logL(X; mu,I2) sim sum(X mu)2

Schauen Sie sich die RSS-Funktion (1) noch einmal an. Ja, sie sind gleich! Genau! Es ist auch zu sehen, dass  mu= haty .

Wenn Sie die MSE-Standardabweichungsfunktion verwenden, erhalten wir daraus:

 operatornameargminMSE( beta) sim operatornameargmax mathbbEX simPdata logPmodel(x; beta)

wo  mathbbE - mathematische Erwartung  beta - Modellparameter, in Zukunft werden wir sie bezeichnen als:  theta .

Schlussfolgerung: Wenn wir die LS-Familie als Fehlerfunktion in der Regressionsfrage verwenden, lösen wir im Wesentlichen das Problem, die Maximum-Likelihood-Funktion zu finden, wenn die Verteilung Gaußsch ist. Und der vorhergesagte Wert  haty gleich dem Durchschnitt in der Normalverteilung. Und jetzt wissen wir, wie all dies zusammenhängt, wie die Wahrscheinlichkeitstheorie (mit ihrer Wahrscheinlichkeitsfunktion und Normalverteilung) und Standardabweichungsmethoden oder OLS zusammenhängt. Weitere Details hierzu finden Sie in [2].

Und hier ist der versprochene Bonus. Da es sich um die Beziehungen zwischen den verschiedenen Fehlerfunktionen handelt, werden wir Folgendes berücksichtigen (nicht unbedingt zu lesen):

Die Beziehung zwischen Cross-Entropy, Likelihood, Log-Likelihood und negativer Log-Likelihood
Angenommen, wir haben Daten X = \ {x_1, x_2, x_3, x_4, ... \}X = \ {x_1, x_2, x_3, x_4, ... \} Jeder Punkt gehört beispielsweise zu einer bestimmten Klasse \ {x_1 \ rightarrow1, x_2 \ rightarrow2, x_3 \ rightarrow n, ... \}\ {x_1 \ rightarrow1, x_2 \ rightarrow2, x_3 \ rightarrow n, ... \} . Insgesamt dort n Klassen, während Klasse 1 auftritt c1 Zeiten, Klasse 2 - c2 Zeiten und Klasse n - - cn mal. Auf diesen Daten haben wir ein Modell trainiert  theta . Die Wahrscheinlichkeitsfunktion (Wahrscheinlichkeit) dafür sieht folgendermaßen aus:

P(Daten| Theta)=P(0,1,...,n| Theta)=P(0| Theta)P(1| Theta)...P(n| Theta)

P(1| theta)P(2| theta)...P(n| theta)= prodc1 haty1 prodc2 haty2... prodcn hatyn= hatyc11 hatyc22... hatycnn


wo P(n| theta)= hatyn - vorhergesagte Wahrscheinlichkeit für die Klasse n .

Wir nehmen den Logarithmus der Wahrscheinlichkeitsfunktion und erhalten die Log-Wahrscheinlichkeit:

 logP(Daten| Theta)= log( hatyc11... hatycnn)=c1 log haty1+...+cn log hatyn= sumnici log hatyi

Wahrscheinlichkeit  haty in[0,1] liegt im Bereich von 0 bis 1, basierend auf der Definition der Wahrscheinlichkeit. Daher hat der Logarithmus einen negativen Wert. Und wenn wir Log-Likelihood mit -1 multiplizieren, erhalten wir die Funktion Negative Log-Likelihood (NLL):

NLL= logP(Daten| Theta)= sumnici log hatyi

Wenn wir die NLL durch die Anzahl der Punkte in dividieren X , N=c1+c2+...+cn dann bekommen wir:

- \ frac {1} {N} \ log {P (Daten | \ theta)} = - \ sum_i ^ n {\ frac {c_i} {N} \ log {\ hat {y_i}}

- \ frac {1} {N} \ log {P (Daten | \ theta)} = - \ sum_i ^ n {\ frac {c_i} {N} \ log {\ hat {y_i}}

Es kann festgestellt werden, dass die reale Wahrscheinlichkeit für die Klasse n ist gleich: yn= fraccnN . Von hier bekommen wir:

NLL= sumniyi log hatyi

Betrachten Sie nun die Definition der Kreuzentropie H(p,q)= sump logq dann bekommen wir:

NLL=H(yi, hatyi)

In dem Fall, wenn wir nur zwei Klassen haben n=2 (binäre Klassifikation) Wir erhalten die Formel für die binäre Kreuzentropie (Sie können auch den bekannten Namen Log-Loss treffen):

H(y, haty)=(y log haty+(1y) log(1 haty))

Aus alledem kann verstanden werden, dass in einigen Fällen das Minimieren der Kreuzentropie dem Minimieren der NLL oder dem Finden des Maximums der Wahrscheinlichkeitsfunktion (Wahrscheinlichkeit) oder der Log-Wahrscheinlichkeit gleichkommt.

Ein Beispiel. Betrachten Sie eine binäre Klassifikation. Wir haben Klassenwerte:

y = np.array([0, 1, 1, 1, 1, 0, 1, 1]).astype(np.float32) 

Wirkliche Wahrscheinlichkeit y für Klasse 0 ist gleich 2/8=0,25 , denn Klasse 1 ist gleich 6/8=0,75 . Angenommen, wir haben einen binären Klassifikator, der die Wahrscheinlichkeit der Klasse 0 vorhersagt  haty für jedes Beispiel für Klasse 1 ist die Wahrscheinlichkeit (1 haty) . Zeichnen wir die Werte der Log-Loss-Funktion für verschiedene Vorhersagen  haty ::


In der Grafik können Sie sehen, dass das Minimum der Log-Loss-Funktion dem Punkt 0,75 entspricht, d. H. Wenn unser Modell die Verteilung der Quelldaten vollständig „gelernt“ hat,  haty=y .

Regression des neuronalen Netzes


Also kamen wir zu einer interessanteren Praxis. Mal sehen, wie Sie das Problem der Regression mithilfe neuronaler Netze (neuronale Netze) lösen können. Wir werden alles in der Programmiersprache Python implementieren, um ein Netzwerk zu erstellen, verwenden wir die PyTorch Deep Learning-Bibliothek.

Erzeugung von Quelldaten


Daten eingeben  mathbfX in mathbbRN erzeugen mit einer gleichmäßigen Verteilung, nehmen Sie das Intervall von -15 bis 15,  mathbfX inU[15,15] . Punkte  mathbfY Wir erhalten unter Verwendung der Gleichung:

 mathbfY=0,5 mathbfX+8 sin(0,3 mathbfX)+Rauschen qquad qquad(3)

wo Lärmä Ist ein Rauschvektor der Dimension N erhalten unter Verwendung der Normalverteilung mit Parametern:  mu=0, sigma2=1 .

Datengenerierung
 N = 3000 #   IN_DIM = 1 OUT_DIM = IN_DIM x = np.random.uniform(-15., 15., (IN_DIM, N)).T.astype(np.float32) noise = np.random.normal(size=(N, 1)).astype(np.float32) y = 0.5*x+ 8.*np.sin(0.3*x) + noise #  3 x_train, x_test, y_train, y_test = train_test_split(x, y) #      



Das Diagramm der empfangenen Daten.

Netzwerkaufbau


Erstellen Sie ein reguläres neuronales Feed-Forward-Netzwerk oder FFNN.

Gebäude FFNN
 class Net(nn.Module): def __init__(self, input_dim=IN_DIM, out_dim=OUT_DIM, layer_size=40): super(Net, self).__init__() self.fc = nn.Linear(input_dim, layer_size) self.logit = nn.Linear(layer_size, out_dim) def forward(self, x): x = F.tanh(self.fc(x)) #  4 x = self.logit(x) return x 


Unser Netzwerk besteht aus einer verborgenen Schicht mit einer Dimension von 40 Neuronen und einer Aktivierungsfunktion - hyperbolischer Tangens:

 tanhx= fracexexex+ex qquad qquad(4)

Die Ausgangsschicht ist eine normale lineare Transformation ohne Aktivierungsfunktion.

Lernen und Ergebnisse erzielen


Als Optimierer verwenden wir AdamOptimizer. Die Anzahl der Studienepochen = 2000, die Lernrate (Lernrate oder lr) = 0,1.

FFNN-Schulung
 def train(net, x_train, y_train, x_test, y_test, epoches=2000, lr=0.1): criterion = nn.MSELoss() optimizer = optim.Adam(net.parameters(), lr=lr) N_EPOCHES = epoches BS = 1500 n_batches = int(np.ceil(x_train.shape[0] / BS)) train_losses = [] test_losses = [] for i in range(N_EPOCHES): for bi in range(n_batches): x_batch, y_batch = fetch_batch(x_train, y_train, bi, BS) x_train_var = Variable(torch.from_numpy(x_batch)) y_train_var = Variable(torch.from_numpy(y_batch)) optimizer.zero_grad() outputs = net(x_train_var) loss = criterion(outputs, y_train_var) loss.backward() optimizer.step() with torch.no_grad(): x_test_var = Variable(torch.from_numpy(x_test)) y_test_var = Variable(torch.from_numpy(y_test)) outputs = net(x_test_var) test_loss = criterion(outputs, y_test_var) test_losses.append(test_loss.item()) train_losses.append(loss.item()) if i%100 == 0: sys.stdout.write('\r Iter: %d, test loss: %.5f, train loss: %.5f' %(i, test_loss.item(), loss.item())) sys.stdout.flush() return train_losses, test_losses net = Net() train_losses, test_losses = train(net, x_train, y_train, x_test, y_test) 


Schauen wir uns nun die Lernergebnisse an.


Diagramm der MSE-Funktionswerte in Abhängigkeit von der Iteration des Trainings, Diagramm der Werte für Trainingsdaten und Testdaten.


Reale und vorhergesagte Ergebnisse anhand von Testdaten.

Invertierte Daten


Wir erschweren die Aufgabe und invertieren die Daten.

Dateninversion
 x_train_inv = y_train y_train_inv = x_train x_test_inv = y_train y_test_inv = x_train 



Invertierter Datendiagramm.

Zur Vorhersage  mathbf hatY Lassen Sie uns das direkte Vertriebsnetz aus dem vorherigen Abschnitt verwenden und sehen, wie es damit umgeht.

 inv_train_losses, inv_test_losses = train(net, x_train_inv, y_train_inv, x_test_inv, y_test_inv) 


Diagramm der MSE-Funktionswerte in Abhängigkeit von der Iteration des Trainings, Diagramm der Werte für Trainingsdaten und Testdaten.


Reale und vorhergesagte Ergebnisse anhand von Testdaten.

Wie Sie den obigen Grafiken entnehmen können, hat unser Netzwerk solche Daten überhaupt nicht verarbeitet, sondern kann sie einfach nicht vorhersagen. Und das alles geschah, weil in einem solchen umgekehrten Problem für einen Punkt x kann mehreren Punkten entsprechen y . Sie fragen, was ist mit dem Lärm? Er schuf auch eine Situation, in der für einen x könnte ein paar Werte bekommen y . Ja, das ist richtig. Aber der springende Punkt ist, dass trotz des Rauschens alles eine eindeutige Verteilung war. Und da hat unser Modell im Wesentlichen vorausgesagt p(y|x) und im Fall von MSE war es der Durchschnittswert für die Normalverteilung (warum es im ersten Teil des Artikels beschrieben wird), dann kam es mit der „direkten“ Aufgabe gut zurecht. Ansonsten erhalten wir mehrere verschiedene Distributionen für eine x und dementsprechend können wir mit nur einer Normalverteilung kein gutes Ergebnis erzielen.

Mixture Density Network


Der Spaß beginnt! Was ist Mixture Density Network (im Folgenden: MDN oder MD-Netzwerk)? Im Allgemeinen ist dies ein bestimmtes Modell, das mehrere Verteilungen gleichzeitig simulieren kann:

p( mathbfy| mathbfx; theta)= sumKk pik( mathbfx) mathcalN( mathbfy; muk( mathbf)x), sigma2( mathbfx)) qquad qquad(5)

Was für eine seltsame Formel, sagst du? Lass es uns herausfinden. Unser MD-Netzwerk lernt, den Mittelwert zu modellieren  mu und Varianz  sigma2 für mehrere Distributionen. In der Formel (5)  pik( mathbfx) - die sogenannten Signifikanzfaktoren einer separaten Verteilung für jeden Punkt xi in mathbfx , ein bestimmter Mischungsfaktor oder wie viel jede der Verteilungen zu einem bestimmten Punkt beiträgt. Insgesamt dort K Verteilungen.

Noch ein paar Worte dazu  pik( mathbfx) - in der Tat ist dies auch eine Verteilung und repräsentiert die Wahrscheinlichkeit, dass für einen Punkt xi in mathbfx wird eine Bedingung sein k .

Fuh, wieder diese Mathematik, lass uns schon etwas schreiben. Und so werden wir beginnen, ein Netzwerk zu realisieren. Für unser Netzwerk nehmen wir K=30 .

 self.fc = nn.Linear(input_dim, layer_size) self.fc2 = nn.Linear(layer_size, 50) self.pi = nn.Linear(layer_size, coefs) self.mu = nn.Linear(layer_size, out_dim*coefs) # mean self.sigma_sq = nn.Linear(layer_size, coefs) # variance 

Definieren Sie die Ausgabeebenen für unser Netzwerk:

 x = F.relu(self.fc(x)) x = F.relu(self.fc2(x)) pi = F.softmax(self.pi(x), dim=1) sigma_sq = torch.exp(self.sigma_sq(x)) mu = self.mu(x) 

Wir schreiben die Fehlerfunktion oder Verlustfunktion, Formel (5):

 def gaussian_pdf(x, mu, sigma_sq): return (1/torch.sqrt(2*np.pi*sigma_sq)) * torch.exp((-1/(2*sigma_sq)) * torch.norm((x-mu), 2, 1)**2) losses = Variable(torch.zeros(y.shape[0])) # p(y|x) for i in range(COEFS): likelihood = gaussian_pdf(y, mu[:, i*OUT_DIM:(i+1)*OUT_DIM], sigma_sq[:, i]) prior = pi[:, i] losses += prior * likelihood loss = torch.mean(-torch.log(losses)) 

Vollständiger MDN-Build-Code
 COEFS = 30 class MDN(nn.Module): def __init__(self, input_dim=IN_DIM, out_dim=OUT_DIM, layer_size=50, coefs=COEFS): super(MDN, self).__init__() self.fc = nn.Linear(input_dim, layer_size) self.fc2 = nn.Linear(layer_size, 50) self.pi = nn.Linear(layer_size, coefs) self.mu = nn.Linear(layer_size, out_dim*coefs) # mean self.sigma_sq = nn.Linear(layer_size, coefs) # variance self.out_dim = out_dim self.coefs = coefs def forward(self, x): x = F.relu(self.fc(x)) x = F.relu(self.fc2(x)) pi = F.softmax(self.pi(x), dim=1) sigma_sq = torch.exp(self.sigma_sq(x)) mu = self.mu(x) return pi, mu, sigma_sq #       def gaussian_pdf(x, mu, sigma_sq): return (1/torch.sqrt(2*np.pi*sigma_sq)) * torch.exp((-1/(2*sigma_sq)) * torch.norm((x-mu), 2, 1)**2) #   def loss_fn(y, pi, mu, sigma_sq): losses = Variable(torch.zeros(y.shape[0])) # p(y|x) for i in range(COEFS): likelihood = gaussian_pdf(y, mu[:, i*OUT_DIM:(i+1)*OUT_DIM], sigma_sq[:, i]) prior = pi[:, i] losses += prior * likelihood loss = torch.mean(-torch.log(losses)) return loss 


Unser MD-Netzwerk ist einsatzbereit. Fast fertig. Es bleibt, sie zu trainieren und die Ergebnisse zu betrachten.

MDN-Schulung
 def train_mdn(net, x_train, y_train, x_test, y_test, epoches=1000): optimizer = optim.Adam(net.parameters(), lr=0.01) N_EPOCHES = epoches BS = 1500 n_batches = int(np.ceil(x_train.shape[0] / BS)) train_losses = [] test_losses = [] for i in range(N_EPOCHES): for bi in range(n_batches): x_batch, y_batch = fetch_batch(x_train, y_train, bi, BS) x_train_var = Variable(torch.from_numpy(x_batch)) y_train_var = Variable(torch.from_numpy(y_batch)) optimizer.zero_grad() pi, mu, sigma_sq = net(x_train_var) loss = loss_fn(y_train_var, pi, mu, sigma_sq) loss.backward() optimizer.step() with torch.no_grad(): if i%10 == 0: x_test_var = Variable(torch.from_numpy(x_test)) y_test_var = Variable(torch.from_numpy(y_test)) pi, mu, sigma_sq = net(x_test_var) test_loss = loss_fn(y_test_var, pi, mu, sigma_sq) train_losses.append(loss.item()) test_losses.append(test_loss.item()) sys.stdout.write('\r Iter: %d, test loss: %.5f, train loss: %.5f' %(i, test_loss.item(), loss.item())) sys.stdout.flush() return train_losses, test_losses mdn_net = MDN() mdn_train_losses, mdn_test_losses = train_mdn(mdn_net, x_train_inv, y_train_inv, x_test_inv, y_test_inv) 



Das Diagramm der Verlustfunktionswerte in Abhängigkeit von der Iteration des Trainings, das Diagramm der Werte für Trainingsdaten und Testdaten.

Da unser Netzwerk die Mittelwerte für mehrere Verteilungen gelernt hat, schauen wir uns Folgendes an:

 pi, mu, sigma_sq = mdn_net(Variable(torch.from_numpy(x_test_inv))) 


Grafik für die beiden wahrscheinlichsten Mittelwerte für jeden Punkt (links). Grafik für die 4 wahrscheinlichsten Mittelwerte für jeden Punkt (rechts).


Diagramm für alle Mittelwerte für jeden Punkt.

Um Daten vorherzusagen, wählen wir zufällig mehrere Werte aus  mu und  sigma2 basierend auf dem Wert  pik( mathbfx) . Und dann basierend auf ihnen, um Zieldaten zu generieren  haty unter Verwendung der Normalverteilung.

Vorhersage des Ergebnisses
 def rand_n_sample_cumulative(pi, mu, sigmasq, samples=10): n = pi.shape[0] out = Variable(torch.zeros(n, samples, OUT_DIM)) for i in range(n): for j in range(samples): u = np.random.uniform() prob_sum = 0 for k in range(COEFS): prob_sum += pi.data[i, k] if u < prob_sum: for od in range(OUT_DIM): sample = np.random.normal(mu.data[i, k*OUT_DIM+od], np.sqrt(sigmasq.data[i, k])) out[i, j, od] = sample break return out pi, mu, sigma_sq = mdn_net(Variable(torch.from_numpy(x_test_inv))) preds = rand_n_sample_cumulative(pi, mu, sigma_sq, samples=10) 


Vorausgesagte Daten für 10 zufällig ausgewählte Werte  mu und  sigma2 (links) und für zwei (rechts).

Aus den Zahlen geht hervor, dass MDN bei der „inversen“ Aufgabe hervorragende Arbeit geleistet hat.

Verwendung komplexerer Daten


Lassen Sie uns sehen, wie unser MD-Netzwerk komplexere Daten wie Spiraldaten verarbeitet. Die Gleichung der hyperbolischen Spirale in kartesischen Koordinaten:

x= rho cos phi qquad qquad qquad qquad qquad qquad(6)y= rho sin phi

Spiraldatengenerierung
 N = 2000 x_train_compl = [] y_train_compl = [] x_test_compl = [] y_test_compl = [] noise_train = np.random.uniform(-1, 1, (N, IN_DIM)).astype(np.float32) noise_test = np.random.uniform(-1, 1, (N, IN_DIM)).astype(np.float32) for i, theta in enumerate(np.linspace(0, 5*np.pi, N).astype(np.float32)): #  6 r = ((theta)) x_train_compl.append(r*np.cos(theta) + noise_train[i]) y_train_compl.append(r*np.sin(theta)) x_test_compl.append(r*np.cos(theta) + noise_test[i]) y_test_compl.append(r*np.sin(theta)) x_train_compl = np.array(x_train_compl).reshape((-1, 1)) y_train_compl = np.array(y_train_compl).reshape((-1, 1)) x_test_compl = np.array(x_test_compl).reshape((-1, 1)) y_test_compl = np.array(y_test_compl).reshape((-1, 1)) 



Diagramm der Spiraldaten.

Lassen Sie uns zum Spaß sehen, wie ein reguläres Feed-Forward-Netzwerk mit einer solchen Aufgabe fertig wird.


Wie erwartet kann das Feed-Forward-Netzwerk das Regressionsproblem für solche Daten nicht lösen.

Wir verwenden das zuvor beschriebene und erstellte MD-Netzwerk für das Training von Spiraldaten.


Mixture Density Network hat in dieser Situation großartige Arbeit geleistet.

Fazit


Zu Beginn dieses Artikels haben wir uns an die Grundlagen der linearen Regression erinnert. Wir haben gesehen, dass dies gemeinsam zwischen der Ermittlung des Durchschnitts für die Normalverteilung und der MSE liegt. Demontiert, wie NLL und Kreuzentropie verbunden sind. Und am wichtigsten ist, dass wir das MDN-Modell herausgefunden haben, das aus Daten lernen kann, die aus einer gemischten Verteilung stammen. Ich hoffe, der Artikel ist verständlich und interessant, obwohl es ein bisschen Mathe gab.

Der vollständige Code kann auf GitHub angezeigt werden.


Literatur


  1. Mixture Density Networks (Christopher M. Bishop, Forschungsgruppe Neural Computing, Abteilung für Informatik und Angewandte Mathematik, Aston University, Birmingham) - Der Artikel beschreibt die Theorie der MD-Netzwerke vollständig.
  2. Kleinste Quadrate und maximale Wahrscheinlichkeit (MROsborne)

Source: https://habr.com/ru/post/de433804/


All Articles