[PYTHON] Lernen Sie das kollaborative Filtern zusammen mit Coursera-Materialien für maschinelles Lernen

Einführung

Die im Empfehlungssystem verwendete kooperative Filterung ist eine Anwendung des maschinellen Lernens, unterscheidet sich jedoch geringfügig von dem einfachen Muster des "überwachten Lernens". Ich habe ein bisschen Literatur und Internetinformationen ausprobiert, aber es ist schwierig, das Konzept und die Systemkonfiguration sofort zu verstehen. Ich erinnerte mich jedoch daran, dass es in Coursera Machine Learning (Woche 9) von Dr. Andrew Ng behandelt wurde, und durch Durchsicht der Lehrmaterialien konnte ich mein Verständnis der kooperativen Filterung vertiefen.

Wie diejenigen, die an diesem Kurs teilgenommen haben, vielleicht wissen, wird Matlab / Octave in den Übungen dieses Kurses verwendet. Dieses Mal habe ich die Co-Filterung (Prototyp) in Python implementiert. Zuerst haben wir den Vorgang mit Numpy + Scipy (Optimize) bestätigt und dann die Implementierung mit TensorFlow bestätigt.

Ein kleiner Überblick über die Co-Filterung

Zitiert aus dem Data Scientist Training Reader, Einführung in das maschinelle Lernen.

Die kooperative Filterung ist eine Methode, um die folgenden Präsentationen auf EC-Standorten zu realisieren.

  • "Personen, die dieses Produkt gekauft haben, haben dieses Produkt auch gekauft."
  • "Leute, die die gleichen Produkte kaufen wie Sie, kaufen auch diese Produkte."

Ich werde es implementieren, wenn ich das Konzept verstehe, aber ich werde die Erklärung in Coursera Machine Learning bestätigen. Hier wird die Erklärung anhand eines Beispiels für das Filmranking erweitert.

Fig.1 Movie Rating Data MovieRatingData.png

Die Tabelle zeigt die Bewertungen von Filmen durch jeden Benutzer, aber die Bewertungen werden nach den Vorlieben des Benutzers aufgeteilt. Daten [X], ein Parameter verschiedener Skalen (in der Coursera-Klasse als Major bezeichnet) wie "starke Tendenz zur Liebesromantik" und "hohe Aktion", werden entsprechend dem Inhalt des Films erstellt. Andererseits ist auch ein Parameter [Theta] für "Benutzerpräferenz" erforderlich. Wie in der Abbildung gezeigt, ist die Größe der Bewertungsdaten eine zweidimensionale Matrix ([Y]) der Anzahl der Filme x der Anzahl der Benutzer. Sie ist jedoch häufig undefiniert, da Benutzer nicht alle Filme bewerten. .. Das auf unbestimmte Zeit? Der Hauptpunkt des Problems besteht darin, die Marke durch Regression zu ergänzen.

Die Erklärung ist, dass, wenn die komplementäre Bewertungsmatrix genau berechnet werden kann, die Verarbeitung im nächsten Prozess der Empfehlung ähnlicher Filme gut durchgeführt werden kann.

Versuchen Sie, mit Numpy + Scipy.Optimize zu implementieren

Wie bei den anderen Übungen im Cousera-Kurs beginnen wir mit der Ermittlung der Kostenfunktion. Da es zwei Parameter gibt, ist es ein ziemlich "harter" Ausdruck.

 \begin{eqnarray}
J(x^{(1)},...,x^{n_m},\theta^{1},...,\theta^{n_u}) = &\ & \frac{1}{2} \sum_{(i,j):r(i,j)=1} 
(({\theta}^{(j)})^T \ x^{(i)} - y^{(i,j)})^2 \ + \\
&\ & (\frac{\lambda}{2} \sum_{j=1}^{n_u} \sum_{k=1}^{n} ({\theta}_k^{(j)}) ^2)
 +  (\frac{\lambda}{2} \sum_{i=1}^{n_m} \sum_{k=1}^{n} ({x}_k^{(i)}) ^2)    
 \end{eqnarray}

Die Kostenfunktion mit den Parametern [X] und [Theta] besteht aus dem quadratischen Fehler zwischen dem durch das Matrixprodukt der Parameter bestimmten Nennvorhersagewert und den tatsächlichen Bewertungsdaten (Etikett) und dem Regularisierungsterm des Parameters. Wenn dies in Python-Code konvertiert wird, sieht es wie folgt aus.

def cofi_costfunc(Y, R, shapes, lambda_c, params):
    #  [J, grad] = COFICOSTFUNC(params, Y, R, num_users, num_movies, ...
    #   num_features, lambda) returns the cost and gradient for the
    #   collaborative filtering problem.
    num_users = shapes[0]
    num_movies = shapes[1]
    num_features = shapes[2]
    boundary = num_movies * num_features
    params_c1 = np.copy(params[:boundary])
    params_c2 = np.copy(params[boundary:])
    X = params_c1.reshape((num_movies, num_features))
    Theta = params_c2.reshape((num_users, num_features))
           
    # You need to return the following values correctly
    Jcost = 0.5 * (((np.dot(X, Theta.T) - Y) * R) ** 2).sum() \
        + 0.5 * lambda_c * ((X.ravel() **2).sum() + (Theta.ravel() **2).sum())

    return Jcost

Die Parameter "X" (Parameter des Filminhalts) und "Theta" (benutzerorientierte Parameter) werden in einem Block "params" eingegeben. Y sind Bewertungsdaten in Form der Anzahl der Filme x Anzahl der Benutzer. R sind Binärdaten mit der gleichen Größe wie Y, die bei Bewertung auf 1 und bei noch keiner Bewertung auf 0 gesetzt werden. (Der Variablentyp des Programms wird als ganzzahliger Typ behandelt.) Nach der Vorverarbeitung besteht die letzte Anweisung darin, die Kosten zu ermitteln, die der obigen Kostenfunktionsformel entsprechen.

Als nächstes folgt die Gleichung des partiellen Differentialkoeffizienten (Gradienten) für die Parameter (x, Theta) dieser Kostenfunktion.

\frac{\partial J}{\partial x_k^{(i)}} = \sum_{j:r(i,j)=1} (( {\theta}^{(j)})^T x^{(i)} 
- y^{(i,j)} ) {\theta}_k^{(j)} + \lambda x_k^{(i)}\\

\frac{\partial J}{\partial {\theta}_k^{(j)}} = \sum_{i:r(i,j)=1} (( {\theta}^{(j)})^T x^{(i)} 
- y^{(i,j)} ) {x}_k^{(i)} + \lambda {\theta}_k^{(j)}

Dies ist auch eine "harte" Formel. Es ist jedoch einfacher zu verstehen, ob es in Code konvertiert wird.

def cofi_costfunc_grad(Y, R, shapes, lambda_c, params):
    #  [J, grad] = COFICOSTFUNC(params, Y, R, num_users, num_movies, ...
    #   num_features, lambda) returns the cost and gradient for the
    #   collaborative filtering problem.
    num_users = shapes[0]
    num_movies = shapes[1]
    num_features = shapes[2]
    boundary = num_movies * num_features
    params_c1 = np.copy(params[:boundary])
    params_c2 = np.copy(params[boundary:])
    X = params_c1.reshape((num_movies, num_features))
    Theta = params_c2.reshape((num_users, num_features))
           
    # You need to return the following values correctly  
    X_grad = np.dot(((np.dot(X, Theta.T) - Y) * R), Theta) + lambda_c * X
    Tgsub = (np.dot(X, Theta.T) - Y) * R
    Theta_grad = np.dot(Tgsub.T, X) + lambda_c * Theta
    Jgrad = np.concatenate((X_grad.ravel(), Theta_grad.ravel()))

    return Jgrad

Der Kostengradient wird in den letzten vier Zeilen berechnet.

In Courseras Übung wird der Prozess zur Optimierung der Kostenminimierung unter Verwendung der im Voraus bereitgestellten Funktion "fmincg.m" durchgeführt. Bei der Konvertierung in Python kann dieselbe Verarbeitung mit scipy.optimize.minimize () ausgeführt werden.

# 
import scipy.optimize as spopt

#Stellen Sie den Anfangswert des Parameters ein
theta_ini = np.concatenate((X.flatten(), Theta.flatten()))

#Wrapper-Funktion vorbereiten
def compute_cost_sp(theta):
    global Y, R, shapes, lambda_c
    j =  cofi_costfunc(Y, R, shapes, lambda_c, params=theta)

    return j

def compute_grad_sp(theta):
    global Y, R, shapes, lambda_c
    j_grad = cofi_costfunc_grad(Y, R, shapes, lambda_c, params=theta)

    return j_grad

# scipy.optimize.Stellen Sie die Minimierungsoptionen ein
options = {'gtol': 1.e-6, 'disp': True}
#Regularisierungskoeffizient
lambda_c = 1.5

res1 = spopt.minimize(compute_cost_sp, theta_ini, method='CG', \
         jac=compute_grad_sp, options=options)
theta =  res1.x

#Teilen Sie eine Reihe von Parametern in X und Theta auf
X = theta[:num_movies*num_features].reshape((num_movies, num_features))
Theta = theta[num_movies*num_features:].reshape((num_users, num_features))

Einzelheiten zu scipy.optimize.minimize finden Sie im Dokument. Sie können jedoch verschiedene Optimierungsmethoden auswählen. Dieses Mal setzen wir method = 'CG' (Conjugate Gradient Method) entsprechend dem Originalmaterial (fmincg.m).

Notwendige Informationen aus den Parametern [X] und [Theta], die durch Minimierung der Kosten auf diese Weise erhalten wurden (z. B. "Personen, die diesen Film hoch bewertet haben, haben diesen Film auch hoch bewertet.") Ist die Verarbeitung des Empfehlungssystems. (Es scheint verschiedene Möglichkeiten zu geben, die Ähnlichkeit zu messen, aber ich werde die Erklärung hier weglassen.)

Verwenden Sie TensorFlow

Es ist ungefähr ein Jahr her, seit TensorFlow letztes Jahr (2015) veröffentlicht wurde. Ich erinnere mich, wie ich den Code aufgeregt geschrieben und den Qiita-Beitrag in Eile geschrieben habe. Dieses Mal haben wir uns für TensorFlow entschieden, um das Erlernen der kooperativen Filterung mit einer höheren Geschwindigkeit durchzuführen.

Im Fall von normalem "überwachtem Lernen" ist die Eingabe-Ausgabe-Beziehung klar, so dass kein Zweifel an der Diagrammdarstellung von TensorFlow besteht, aber diesmal war es ein wenig schwierig.

Daher lautet der Code für die Variablenvorbereitung wie folgt.

# Parameter definition
    if WARM_START:
        data_param = load_data(fn='./data/ex8_movieParams.mat')
        X_np = data_param['X'].astype(np.float32)
        Theta_np = data_param['Theta'].astype(np.float32)
        x = tf.Variable(X_np)
        theta = tf.Variable(Theta_np)
    else:   # COLD START
        x = tf.Variable(tf.random_normal([num_movies, num_features],
            mean=0.0, stddev=0.05))
        theta = tf.Variable(tf.random_normal([num_users, num_features],
            mean=0.0, stddev=0.05))
# Placeholders
    Y_ph = tf.placeholder(tf.float32, shape=[None, num_users])
    R_ph = tf.placeholder(tf.float32, shape=[None, num_users])

Da die Parameterdaten, die zu einem gewissen Grad vorab erlernt wurden, in den Coursera-Programmübungen bereitgestellt wurden, haben wir eine Option für 'WARM_START' vorbereitet, um sie zu verwenden, und eine Option, um von vorne zu beginnen. In 'WARM_START' werden die Daten von numpy.array unverändert an 'tf.Variable ()' übergeben, und im Fall von Nullstart wird eine Zufallszahl mit einem kleinen Wert erzeugt und in x und Theta gesetzt. Zusätzlich wurde der Platzhalter der Lehrerdaten mit der gewünschten Form erstellt. (Shape = [None, num_users] ist in Ordnung mitshape = [num_movies, num_users], wird jedoch gemäß der Konvention von TensorFlow auf None gesetzt.)

Als nächstes definieren wir die Berechnung der Kostenfunktion.

def Ypred(X, Theta):
    '''
      calculate rating with parameter X and Theta
      args.:
        X:      movie contents parameter
        Theta:  user characteristic parameter
    '''
    feat_dim1 = tf.shape(X)[1]
    feat_dim2 = tf.shape(Theta)[1]

    tf.assert_equal(feat_dim1, feat_dim2)
    rating = tf.matmul(X, tf.transpose(Theta))

    return rating


# Cost Function, etc.
    cost = tf.reduce_sum(((Ypred(x, theta) - Y_ph) * R_ph) ** 2)
    L2_sqr = tf.nn.l2_loss(x) + tf.nn.l2_loss(theta)
    lambda_c = 1.0      # L2 norm coefficient      
    loss = cost + lambda_c * L2_sqr

Nicht nur TensorFlow, sondern auch das Deep Learning Framework berechnet automatisch den Gradienten. Wie oben erwähnt, finde ich es "großartig", nur die Kostenfunktion zu definieren. Danach wird der Optimierer wie üblich so eingestellt, dass er eine Lernschleife bildet.

    lr = 1.e-5
    train_step = tf.train.GradientDescentOptimizer(lr).minimize(loss)
    init_op = tf.initialize_all_variables()

    # Train
    with tf.Session() as sess:
        sess.run(init_op)

        for i in range(10001):
            sess.run(train_step, feed_dict={Y_ph: Y_np, R_ph: Y_np})
        
            if i % 1000 == 0:
                loss_mon = loss.eval({Y_ph: Y_np, R_ph: Y_np})
                print(' step, loss = {:6d}: {:10.1f}'.format(i, loss_mon))

        # evaluate ranking with final parameters
        ymat = Ypred(x, theta).eval()
        sio.savemat('./ymat_tf.mat', {'Y': ymat})
        print('ymat is saved to "ymat_tf.mat".')

Ich denke, Sie können Ihren Lieblingsoptimierer anstelle von "tf.train.GradientDescentOptimizer ()" verwenden, aber diesmal habe ich versucht, eine Grundfunktion zu verwenden, da dies ein Problem von Cousera ist. Es dauert einige Zeit, um die Lernrate anzupassen, aber ich konnte die Berechnung sicher durchführen (mit hoher Geschwindigkeit bei GPU-Betrieb).

Ergebnisvergleich

Da es sich bei der Lösung um denselben Algorithmus handelt, sollten das Ergebnis von scipy.optimize.minimize und das Ergebnis von TensorFlow ähnlich sein. Dieses Mal haben wir die Bewertungsmatrix Y aus den erhaltenen Parametern (X, Theta) berechnet und wie im Heatmap-Diagramm gezeigt erstellt. (Blau: niedrige Rate ~ Rot: hohe Rate)

By scipy.optimize.minimize heatmap_sp.png

By TensorFLow heatmap_tf.png

Obwohl es Unterschiede wie Farbschattierungen in den Details gibt, kann dies als großes Muster angesehen werden. Es scheint kein Problem im Berechnungsprozess zu geben.

Wenn Sie den Unterschied zwischen beiden ausgleichen möchten, müssen Sie die Details wie Regularisierung, Lernrate und Konvergenzstatus anpassen. Ich denke, der obige Inhalt ist zum Zweck des "Lernens der kooperativen Filterung" in Ordnung, aber um in Wettbewerben wie Kaggle zu kämpfen, müssen verschiedene Details untersucht werden.

(Die diesmal verwendete Programmierumgebung ist wie folgt. Python 3.5.2, Numpy 1.11.2, Scipy 0.18.1, TensorFlow 0.11.0) (Der Code wurde auf Gist hochgeladen: https://gist.github.com/tomokishii/2e9f83d391df82f25942c1310b41e0b5)

Referenzen, Website

--Cousera, Maschinelles Lernen, von Prof. Andrew Ng (Ein Handbuch / PDF mit Programmieraufgaben wird jede Woche verteilt. Sie können auf die Lehrmaterialvideos und die zugehörigen Dateien mit Programmierübungen auf der Website zugreifen, auch wenn der Kurs beendet ist.)

Recommended Posts

Lernen Sie das kollaborative Filtern zusammen mit Coursera-Materialien für maschinelles Lernen
Genießen Sie Coursera / Machine Learning-Materialien zweimal
Lerne irgendwie maschinelles Lernen
Co-Filterung mit PySpark
Site-Zusammenfassung zum Erlernen des maschinellen Lernens mit englischen Videos
Maschinelles Lernen mit Pokemon gelernt
Maschinelles Lernen mit Python! Vorbereitung
Maschinelles Lernen Minesweeper mit PyTorch
Beginnend mit maschinellem Python-Lernen
Versuchen Sie es mit Kaggle leicht maschinell
Lernen Sie nicht mit der TensorFlow ~ Fibonacci-Sequenz der Bibliothek für maschinelles Lernen
Maschinelles Lernen mit Nogisaka 46 und Keyakizaka 46 Teil 1 Einführung
Ich habe maschinelles Lernen mit liblinear versucht
Maschinelles Lernen mit Python (1) Gesamtklassifizierung
SVM versucht maschinelles Lernen mit Scikit-Learn
Quanteninspiriertes maschinelles Lernen mit Tensornetzwerken
Beginnen Sie mit dem maschinellen Lernen mit SageMaker
"Scraping & maschinelles Lernen mit Python" Lernnotiz
Coursera Machine Learning Challenge in Python: ex7-1 (Bildkomprimierung mit K-bedeutet Clustering)
Vorhersage des Strombedarfs durch maschinelles Lernen Teil 2
Verstärken Sie Bilder für maschinelles Lernen mit Python
Unausgeglichenes Datenlernen mit maschinellem Lernen k-NN
Maschinelles Lernen mit Python (2) Einfache Regressionsanalyse
Eine Geschichte über maschinelles Lernen mit Kyasuket
[Shakyo] Begegnung mit Python zum maschinellen Lernen
Maschinelles Lernen mit Pytorch in Google Colab
Wie man Coursera / Maschinelles Lernen genießt (Woche 10)
Aufbau einer KI / maschinellen Lernumgebung mit Python
[Maschinelles Lernen] Regressionsanalyse mit Scicit Learn
Coursera-Herausforderungen beim maschinellen Lernen in Python: ex3 (Handschriftliche Zahlenerkennung mit logistischer Rekursion)
Maschinelles Lernen
Kapitel 6 Überwachtes Lernen: Klassifizierung pg212 ~ [Lernen Sie, indem Sie sich mit Python bewegen! Neues Lehrbuch für maschinelles Lernen]
[Python] Einfache Einführung in das maschinelle Lernen mit Python (SVM)
Beginn des maschinellen Lernens (empfohlene Unterrichtsmaterialien / Informationen)
Maschinelles Lernen beginnend mit Python Personal Memorandum Part1
[Python] Sammeln Sie Bilder mit Icrawler für maschinelles Lernen [1000 Blatt]
Maschinelles Lernen von Grund auf neu (maschinelles Lernen mit Kaggle)
[Super Einführung in das maschinelle Lernen] Lernen Sie Pytorch-Tutorials
Ich habe mit der maschinellen Vorverarbeitung von Python Data begonnen
Erstellen Sie eine Python-Umgebung für maschinelles Lernen mit Containern
Lernen Sie, indem Sie mit neuem Python laufen! Lehrbuch für maschinelles Lernen von Makoto Ito numpy / keras Achtung!