[PYTHON] Ich habe versucht, das lokale Minimum der Goldstein-Preis-Funktion zu bekämpfen

Zuvor habe ich erfahren, dass es in der SciPy-Bibliothek eine RosenBrock-Funktion zum Testen des Optimierers gibt. Bei der Suche in Wikipedia stellte ich jedoch fest, dass es neben RosenBrock verschiedene andere Benchmarking-Funktionen gibt.

https://en.wikipedia.org/wiki/Test_functions_for_optimization

Es wird erwartet, dass die einfachste Form der Kugelfunktion intuitiv leicht die optimale Lösung (Minimalwertpunkt) zu finden ist, andere Funktionen können jedoch schwierig sein, die optimale Lösung zu finden. Dieses Mal möchte ich "Goldstein Price Function" aus dieser Liste aufnehmen.

Fig. Sphere Function Sphere_func0.png (Referenzfigur, das ist einfach zu handhaben ...)

Fig. Goldstein-Price Function Goldstein_price_func2.png (Dieses Mal werden wir uns darum kümmern.)

Goldstein-Eigenschaften der Preisfunktion

Erstens lautet die Formel der Funktion wie folgt.

f(x,y) = (1+(x+y+1)^2 (19 -14x+3x^2-14y+6xy+3y^2))\\
(30 + (2x -3y)^2 (18 - 32x +12x^2 +48y -36xy+27y^2)

Wie im 3D-Diagramm in der obigen Abbildung gezeigt, ist die Nichtlinearität der Funktion groß, da die Werte auf der z-Achse größer sind als die Werte auf der x-Achse und der y-Achse. Der Minimalwertpunkt (optimale Lösung) dieser Funktion ist

f(0, -1) = 3

Wie gezeigt, wird z = 3 durch (x, y) = (0, -1) erhalten, aber es gibt mehrere minimale Punkte (lokales Minimum) um dieses herum. Ich habe ein Konturdiagramm gezeichnet, um die Situation im Detail zu sehen. GoldsteinPrice_contour1.PNG

Es gibt eine rillenartige Form in einer diagonalen Kreuzform, und der Schnittpunkt der Rille ist der globale Mindestpunkt "(x, y) = (0, -1)". Es gibt eine Insel in einem etwas großen Gebiet in der Nähe von (1, 0,2) oben rechts, und es besteht die Möglichkeit, dass das lokale Minimum erreicht wird. Zusätzlich werden kleine Local Mimimum-Kandidaten in der Rillenform beobachtet. Dies scheint schwierig zu handhaben.

Löse mit TensorFlow

Da wir verschiedene Optimierer haben, haben wir uns entschlossen, diese mit TensorFlow zu lösen. Der Code sieht folgendermaßen aus:

Erstens ist die Definition der Goldstein-Preis-Funktion. Es wird gemäß der Definition der Funktion codiert, aber die Quadratberechnung verwendet "tf.square ()".

def goldsteinprice_tf(x, y):
    # goal : (x, y) = (0., -1.0)
    term1 = (19. - 14. * x + 3. * x * x -14. * y + 6. * x * y + 3. * y * y)
    term2 = 1. + tf.square((x + y + 1.0)) * term1
    term3 = 18. -32. * x + 12. * x * x + 48. * y - 36. * x * y + 27. * y * y
    term4 = 30. + tf.square((2. * x - 3. * y)) * term3
    z = term2 * term4
    return z

Stellen Sie den Anfangswert ein und geben Sie die Goldstein-Preis-Funktion als Kosten an.

    # set initial parameter
    x0, y0 = (0., 0.)
    x = tf.Variable(x0)
    y = tf.Variable(y0)
    loss = goldsteinprice_tf(x, y)

Der Optimierer kann aus 6 Arten von TensorFlow-Optimierern ausgewählt werden.

    lrate = 1.e-03    #Lernrate
    sw = 4            # Optimizer Selection
    
    # need to check sw = [2, 5]
    if sw == 1:
        optimizer = tf.train.GradientDescentOptimizer(lrate)
    elif sw == 2:
        optimizer = tf.train.AdagradOptimizer(lrate, initial_accumulator_value=0.1)
    elif sw == 3:
        optimizer = tf.train.MomentumOptimizer(lrate, momentum=0.0)
    elif sw == 4:
        optimizer = tf.train.AdamOptimizer(lrate)
    elif sw == 5:
        optimizer = tf.train.FtrlOptimizer(lrate)
    elif sw == 6:
        optimizer = tf.train.RMSPropOptimizer(lrate, decay=0.0)
    else:
        print('Error.')
    
    train_op = optimizer.minimize(loss)

Jetzt müssen Sie nur noch die Variablen initialisieren und die Sitzung ausführen.

   init = tf.initialize_all_variables()

    with tf.Session() as sess:
        sess.run(init)
        print('Training...')
        print('initial (x, y) = (%8.4f, %8.4f) : loss = %8.4f' 
            % (sess.run(x), sess.run(y), sess.run(loss)))
        
        for i in range(10001):
            train_op.run()

            if i % 100 == 0:
                loss_ = float(sess.run(loss))
                # loss_log.append(loss_)
                x_ = sess.run(x)
                y_ = sess.run(y)
            
            if i % 1000 == 0:                # echo status on screen
                print('(x, y) = (%8.4f, %8.4f) : loss = %8.4f' 
                    % (x_, y_, loss_))

        # Check trained parameter
        print('final (x, y) = (%8.4f, %8.4f) : loss = %8.4f' 
            % (sess.run(x), sess.run(y), sess.run(loss)))

Folgende Berechnungsparameter können ausgewählt werden

Als Berechnungsbeispiel lautet das Ausführungsergebnis der obigen Listeneinstellungen (Anfangswert (0,0), AdamOptimizer, Schleife 10.000 Mal) wie folgt.

Training...
initial (x, y) = (  0.0000,   0.0000) : loss = 600.0000
(x, y) = ( -0.0010,  -0.0010) : loss = 598.5597
(x, y) = ( -0.5198,  -0.4769) : loss =  31.8792
(x, y) = ( -0.5756,  -0.4230) : loss =  30.2262
(x, y) = ( -0.5987,  -0.4012) : loss =  30.0007
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
(x, y) = ( -0.6000,  -0.4000) : loss =  30.0000
final (x, y) = ( -0.6000,  -0.4000) : loss =  30.0000

Die Situation ist im lokalen Minimum (-0,6, -0,4) hervorragend erfasst. Übrigens, als der Anfangswert in der Nähe des globalen Minimums eingestellt und berechnet wurde, wurde bestätigt, dass er ordnungsgemäß zum Minimalpunkt (0, -1) konvergierte.

Globale Optimierungsmethode "Backmethode"

Verlassen wir hier TensorFlow und probieren die globale Optimierungsmethode "Simuliertes Tempern" aus. [Wikipedia](https://ja.wikipedia.org/wiki/%E7%84%BC%E3%81%8D%E3%81%AA%E3%81%BE%E3%81%97%E6%B3 Die Erklärung in% 95) lautet wie folgt.

Wenn der SA-Algorithmus wiederholt eine Lösung findet, findet er eine Lösung in der zufälligen Umgebung der aktuellen Lösung, die vom Wert der angegebenen Funktion und dem globalen Parameter T (dh Temperatur) beeinflusst wird. Dann nimmt der Wert von T (Temperatur) aufgrund der Ähnlichkeit mit dem oben erwähnten physikalischen Prozess allmählich ab. Da T zunächst groß ist, ändert sich die Lösung daher kühn, konvergiert jedoch, wenn T gegen Null geht. Zuerst können Sie den Hang leicht erklimmen, sodass Sie nicht darüber nachdenken müssen, was zu tun ist, wenn Sie in ein lokales Minimum fallen, das beim Bergsteigen ein Problem darstellt.

Das Wunderbare war, dass der Pseudocode auch gepostet wurde, also habe ich ihn in Python-Code konvertiert und ausgeführt.

Der Hauptteil des Codes lautet wie folgt.

def sim_anneal(startState, maxIter, goalE):
    state = startState
    x_, y_ = state[0], state[1]
    e = goldsteinprice(x_, y_)
    bestState = state
    bestE = e
    for iter in range(0, maxIter):
        delta = np.random.rand(2) - 0.5
        nextState = state + delta * 1.
        nextE = goldsteinprice(nextState[0], nextState[1])
        
        if bestE > nextE:
            bestState = nextState
            bestE = nextE
            if goalE >= bestE:
                return bestState
        r = np.random.rand()
        if probability(e, nextE, temperature(10.0, iter/maxIter)) >= r:
            state = nextState
            e = nextE
        if iter % 100 ==0:
            print('iter: nextE, bestE, goalE = (%5d, %9.3f, %9.3f, %9.3f)' 
               % (iter, nextE, bestE, goalE))
            
    return bestState

Wenn die Berechnung ausgeführt wird, erreicht sie die Nähe von Global Munimum (0.0, -1.0).

Fig. Parameter(x,y) Path (Simulated Annealing) GoldsteinPrice_SA.png

Auch bei dieser Berechnung gibt es neben dem Anfangswert verschiedene Berechnungsparameteroptionen. Nach mehrmaliger Ausführung der Berechnung ist mir auch aufgefallen, dass sie von der Art der Zufallszahlen abhängt. In einigen Fällen würde die Berechnung an einer völlig anderen Stelle enden, wenn der Startwert der Zufallszahl nicht festgelegt und die Berechnung viele Male ausgeführt wurde. Die Ergebnisse sind schwer zu lesen, daher handelt es sich nicht um eine vielseitige Berechnungsmethode.

Wiederholen Sie mit TensorFlow Optimizer

Um die Auswirkung des Anfangswertes zu sehen, 9 Anfangswerte: [[0., 0.], [0., 1.], [1., 0.], [1., 1.], [0., -1.], [-1., 0. ], [-1., -1.], [-1., 1.], [1., -1.]] .

Zunächst wird das Berechnungsergebnis mit dem Adagrad Optimizer in der folgenden Abbildung dargestellt.

Fig. Parameter(x,y) path from 9 points (Adagrad) gsp_p1_Adagrad.png

Keiner von ihnen hat den Mindestpunkt erreicht, außer in dem Fall, in dem er von Anfang an im globalen Minimum lag. (Es kann durch Anpassen der Lernrate und anderer Parameter verbessert werden.) Das Ergebnis der Verwendung von Adam Optimizer ist unten dargestellt.

Fig. Parameter(x,y) path from 9 points (Adam) gsp_p1_Adam.png

Hier wird der Minimalpunkt in zwei Fällen erreicht, aber wenn einer ausgeschlossen wird, weil der Anfangswert der Minimalpunkt war, ist auch der Fall von "(x0, y0) = (1.0, -1.0)" erfolgreich.

Aus der obigen Situation habe ich schließlich versucht, den Anfangswert mit einer Zufallszahl festzulegen. Normalerweise werden beim Lernen des neuronalen Netzes Zufallszahlen verwendet, um die Gewichte zu initialisieren, und der Zweck besteht darin, "den Lernfortschritt durch Eliminieren der Symmetrie des Netzes zu fördern". In Anbetracht der Möglichkeit, auf das lokale Minimum zu fallen, unterscheidet sich die Bedeutung dieses Mal geringfügig, da die Zufallszahlen initialisiert werden, um Parameter weitgehend zuzuweisen.

    num_jobs = 10

    with tf.Session() as sess:
        for job in range(num_jobs):
            init_param = tf.Variable(tf.random_uniform([2], minval=-1., maxval=1.))
            x = tf.slice(init_param, [0], [1])
            y = tf.slice(init_param, [1], [1])

            loss = goldsteinprice_tf(x, y)
(Weggelassen)

Wie oben erwähnt, hat tf.random_uniform () eine Zufallszahl von -1,0 bis 1,0 generiert und als Anfangswert verwendet. Das Berechnungsergebnis ist wie folgt.

Fig. Parameter(x,y) path from random point gsp_p2_Adam.png (Ich habe versucht, die Farben des Pfades zu trennen.)

Obwohl es vom Ergebnis des 9-Punkte-Anfangswertes etwas pessimistischer war, hat es mit hoher Wahrscheinlichkeit (0, -1) von Global Minumum erreicht. Sie finden das Golobal-Minimum mit einer Wahrscheinlichkeit von 30% oder mehr.

Dieses Mal habe ich versucht, ohne praktischen Zweck mit der Goldestein-Preis-Funktion zu "kämpfen", aber ich habe verschiedene Schwierigkeiten beim Finden des optimalen Punktes herausgefunden. Durch die Verwendung einer Zufallszahl als Anfangswert kann das Problem des lokalen Minimums bis zu einem gewissen Grad vermieden werden. Wie steht es jedoch mit dem Bereich der Zufallszahl? Darauf scheint es keine allgemeine Antwort zu geben.

Unter der Annahme einer Situation, in der Trainingsdaten in ein tatsächliches Klassifizierungsproblem eingegeben werden, kann es jedoch Situationen geben, in denen die Trainingsdaten selbst einen Fehler aufweisen und nicht vom lokalen Minimum erfasst werden, indem die probabilistische Gradientenabstiegsmethode verwendet wird. Ich glaube. (Natürlich ist es sehr nützlich, verschiedene Anfangswerte in einer Situation auszuprobieren, in der Sie Zeit verbringen können.)

Referenzen (Website)

--Testfunktionen zur Optimierung (Wikipedia) ... Ein schönes Funktionsdiagramm (3D-Plot) wird veröffentlicht. https://en.wikipedia.org/wiki/Test_functions_for_optimization

Recommended Posts

Ich habe versucht, das lokale Minimum der Goldstein-Preis-Funktion zu bekämpfen
Ich habe versucht, den Index der Liste mithilfe der Aufzählungsfunktion abzurufen
Ich habe die Pivot-Table-Funktion von Pandas ausprobiert
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich habe versucht, die Grundform von GPLVM zusammenzufassen
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren
Ich habe versucht, die Spacha-Informationen von VTuber zu visualisieren
Ich habe versucht, den negativen Teil von Meros zu löschen
Ich habe versucht, die Stimmen der Sprecher zu klassifizieren
Ich habe versucht, die String-Operationen von Python zusammenzufassen
Ich habe versucht, die Entropie des Bildes mit Python zu finden
[Pferderennen] Ich habe versucht, die Stärke des Rennpferdes zu quantifizieren
Ich habe versucht, die Standortinformationen des Odakyu-Busses zu erhalten
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
[Python] Ich habe versucht, die folgende Beziehung von Twitter zu visualisieren
Ich habe ein wenig versucht, das Verhalten der Zip-Funktion
[Maschinelles Lernen] Ich habe versucht, die Theorie von Adaboost zusammenzufassen
Ich habe versucht, den Ipython-Cluster unter AWS auf das Minimum zu starten
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren (Re-Challenge)
Ich habe versucht, den Ball zu bewegen
Ich habe versucht, den Abschnitt zu schätzen.
Ich möchte den Namen der ausgeführten Funktion / Methode erhalten
Ich habe versucht, die Bewässerung des Pflanzgefäßes mit Raspberry Pi zu automatisieren
Ich habe versucht, das SD-Boot-Image von LicheePi Nano zu erstellen
Ich habe versucht, die Größe des logischen Volumes mit LVM zu erweitern
Ich habe versucht, die Effizienz der täglichen Arbeit mit Python zu verbessern
Ich habe versucht, den allgemeinen Zustand der VTuber-Kanalbetrachter zu visualisieren
Ich habe den asynchronen Server von Django 3.0 ausprobiert
Ich habe versucht, den Befehl umask zusammenzufassen
Ich habe versucht, die grafische Modellierung zusammenzufassen.
Ich habe versucht, das Umfangsverhältnis π probabilistisch abzuschätzen
Ich habe versucht, die COTOHA-API zu berühren
Ich habe versucht, die Exponentialfunktion und die Logistikfunktion an die Anzahl der COVID-19-positiven Patienten in Tokio anzupassen
Ich habe versucht, das Gesichtsbild mit sparse_image_warp von TensorFlow Addons zu transformieren
Ich habe versucht, Zabbix Server über einen Ausführungsfehler der AWS Lambda-Funktion zu informieren
Ich habe versucht, die Trefferergebnisse von Hachinai mithilfe der Bildverarbeitung zu erhalten
Ich habe versucht, die Altersgruppe und die Ratenverteilung von Atcoder zu visualisieren
Ich habe versucht, die Beispielnachrichten zur Geschäftsintegration in Amazon Transcribe zu übertragen
zoom Ich habe versucht, den Grad der Aufregung der Geschichte auf der Konferenz zu quantifizieren
Ich habe versucht, die Ähnlichkeit der Frageabsicht mit Doc2Vec von gensim abzuschätzen
Ich habe versucht, die Genauigkeit meines eigenen neuronalen Netzwerks zu verbessern
Ich habe 6 Methoden gemessen, um den Index des Maximalwerts (Minimalwerts) der Liste zu erhalten
Ich habe versucht, den Authentifizierungscode der Qiita-API mit Python abzurufen.
(Python) Ich habe versucht, 1 Million Hände zu analysieren ~ Ich habe versucht, die Anzahl der AA ~ zu schätzen
Ich habe versucht, die logische Denkweise über Objektorientierung zusammenzufassen.
Ich habe versucht, die optimale Route des Traumlandes durch (Quanten-) Tempern zu finden
Ich habe versucht, die Beschleunigung von Python durch Cython zu verifizieren und zu analysieren
Ich habe versucht, die Negativität von Nono Morikubo zu analysieren. [Vergleiche mit Posipa]
Ich habe versucht, den Text des Romans "Wetterkind" mit Word Cloud zu visualisieren
[Linux] Ich habe versucht, die sichere Bestätigungsmethode von FQDN (CentOS7) zu überprüfen.
Ich habe versucht, das RSS des Top-Songs des iTunes Store automatisch abzurufen
Ich habe versucht, die Filminformationen der TMDb-API mit Python abzurufen
Ich habe versucht, den Höhenwert von DTM in einem Diagramm anzuzeigen
Ich habe die übliche Geschichte ausprobiert, Deep Learning zu verwenden, um den Nikkei-Durchschnitt vorherzusagen
Mit COTOHA habe ich versucht, den emotionalen Verlauf des Laufens von Meros zu verfolgen.
Ich habe versucht, das Ergebnis des A / B-Tests mit dem Chi-Quadrat-Test zu überprüfen
Python: Ich möchte die Verarbeitungszeit einer Funktion genau messen