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.
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
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.
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.)
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).
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
By TensorFLow
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)
--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