[PYTHON] Apprentissage des classements à l'aide d'un réseau neuronal (implémentation RankNet par Chainer)

Quel est cet article?

Dans le cadre de l'apprentissage automatique, il y a l'apprentissage du classement (apprentissage du classement, apprentissage du classement). RankNet, qui utilise un réseau neuronal, est l'un des modèles d'apprentissage des rangs. Dans cet article, je parlerai de la mise en œuvre de RankNet à l'aide de Chainer.

En regardant les résultats de la prédiction, la mise en œuvre semble être correcte, mais s'il y a des erreurs telles que la façon d'utiliser Chainer, je vous serais reconnaissant de bien vouloir le signaler.

Qu'est-ce que l'apprentissage de rang en premier lieu

Dans l'apprentissage des classements, un ensemble de $ ({\ mathbf x}, y) = $ (caractéristiques, degré d'aptitude) est appris. Apprenez la fonction $ f $ qui renvoie une grande valeur pour les éléments avec un degré de conformité élevé et une petite valeur pour les éléments avec un faible degré de conformité.

Supposons maintenant que deux éléments $ A $ et $ B $ soient représentés comme suit.

A=(\mathbf{x}_A, y_A) \\
B=(\mathbf{x}_B, y_B)

Supposons également que $ A $ est plus approprié que $ B $. Autrement dit, supposons que $ y_A> y_B $ soit valable. A ce moment, la fonction $ f $ est apprise de sorte que la relation suivante soit vraie.

f(\mathbf{x}_A)>f(\mathbf{x}_B)

On a l'impression que quelque chose ne va pas, alors aime vivre! Je vais expliquer l'utilisation. Tout d'abord, aimez vivre! Ajoutons le degré d'aptitude (☆, ☆☆, ☆☆☆) au personnage de. Plus le nombre de ☆ est élevé, plus le degré de conformité (favori) est élevé.

cat_1.png

Si vous apprenez la paire suivante, vous devriez obtenir la fonction $ f $ comme ceci. learning.PNG

Lorsque $ f ({\ bf x}) = {\ bf w} ^ T {\ bf x} $, le poids $ {\ bf w} $ est projeté orthogonalement comme la quantité de caractéristiques comme indiqué dans la figure ci-dessous. On estime que les points sont classés par ordre de conformité. Dans un vrai problème, il n'y aurait pas $ {\ bf w} $ qui serait parfaitement aligné par ordre d'aptitude ... (⇒ linéairement inséparable)

wpredict_1.png

En utilisant la fonction $ f $ obtenue à la suite de l'apprentissage, il est possible de prédire le classement des caractères qui n'ont pas encore été ajustés.

calc_f1.png

Ici, j'ai écrit des «paires d'apprentissage», mais en fait, il existe à peu près trois méthodes d'apprentissage par rang, et cela correspond à la méthode appelée par paires. Il existe d'autres méthodes telles que par point et par liste, mais veuillez vous référer aux documents suivants pour ces méthodes.

À propos de RankNet

RankNet est un modèle d'apprentissage de rang basé sur un réseau neuronal et est une méthode par paires. Le modèle de prédiction lui-même est le même qu'un réseau neuronal normal, mais la conception de la fonction de coût est différente. Cependant, l'idée est la même que la fonction d'entropie croisée qui est souvent utilisée comme fonction de coût.

Comme ci-dessus, supposons que les éléments $ A $ et $ B $ soient représentés comme suit, et $ A $ est plus adapté que $ B $.

A=(\mathbf{x}_A, y_A) \\
B=(\mathbf{x}_B, y_B)

Les scores de $ A $ et $ B $ par la fonction $ f $ sont calculés comme suit.

s_A=f(\mathbf{x}_A) \\
s_B=f(\mathbf{x}_B)

La probabilité que $ A $ soit classé plus haut que la sortie de $ B $ par RankNet est exprimée comme suit en utilisant $ s_A $ et $ s_B $.

P_{AB}=\frac{1}{1+e^{-\sigma(s_A-s_B)}}

Intuitivement, nous pouvons voir que lorsque $ s_A $ augmente, $ P_ {AB} $ s'approche de 1, et lorsque $ s_B $ augmente, $ P_ {AB} $ s'approche de 0.

En utilisant $ P_ {AB} $, la fonction de coût est exprimée comme suit.

C_{AB}=-\bar{P}_{AB}\log{P_{AB}}-(1-\bar{P}_{AB})\log(1-P_{AB})

Ici, $ \ bar {P} _ {AB} $ est la probabilité connue que $ A $ soit classé au-dessus de $ B $. Dans Référence, il a été défini comme suit.

\bar{P}_{AB}=\begin{cases}
1 & (A \succ B) \\
0 & (A \prec B) \\
\frac{1}{2} & (otherwise)
\end{cases}

$ C_ {AB} $ est juste une fonction d'entropie croisée, et plus $ P_ {AB} $ est éloigné $ \ bar {P} _ {AB} $, plus la valeur est grande. RankNet apprend à minimiser cette fonction de coût.

Implémentation de RankNet dans Chainer

Maintenant, implémentons RankNet avec Chainer. La fonction de perte softmax_cross_entropy () est implémentée dans Chainer, mais softmax_cross_entropy () ne peut pas être utilisée car elle ne peut recevoir que le type int32 comme variable cible. ($ \ Bar {P} _ {AB} $ peut être $ \ frac {1} {2} $.)

Par conséquent, je dois implémenter la fonction de coût $ C_ {AB} $ par moi-même, mais j'ai pu apprendre sans implémenter ** backward (), qui est implémentée dans d'autres fonctions de perte *. *… Je me demande si backward () n'est pas implémenté pour effectuer automatiquement la différenciation numérique, et je vous serais reconnaissant si vous pouviez commenter.

Voici l'implémentation de RankNet En tant que modèle du réseau neuronal, un simple perceptron multicouche de [couche d'entrée] -> [couche cachée] -> [couche cachée] -> [couche de sortie] est utilisé.

net.py


from chainer import Chain
import chainer.functions as F
import chainer.links as L


class MLP(Chain):

    def __init__(self, n_in, n_hidden):
        super(MLP, self).__init__(
            l1=L.Linear(n_in, n_hidden),
            l2=L.Linear(n_hidden, n_hidden),
            l3=L.Linear(n_hidden, 1)
        )

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)


class RankNet(Chain):

    def __init__(self, predictor):
        super(RankNet, self).__init__(predictor=predictor)

    def __call__(self, x_i, x_j, t_i, t_j):
        s_i = self.predictor(x_i)
        s_j = self.predictor(x_j)
        s_diff = s_i - s_j
        if t_i.data > t_j.data:
            S_ij = 1
        elif t_i.data < t_j.data:
            S_ij = -1
        else:
            S_ij = 0
        self.loss = (1 - S_ij) * s_diff / 2. + \
            F.math.exponential.Log()(1 + F.math.exponential.Exp()(-s_diff))
        return self.loss

Appliquons le RankNet implémenté aux données artificielles. Les données artificielles ont été générées comme suit.

X=({\bf x}_1, {\bf x}_2, \dots, {\bf x}_{1000})^{\rm T} \\
{\bf y}=(y_1, y_2, \dots, y_{1000}) \\
{\bf w} = {\mathcal N}({\bf 0}, {\bf 1}) \\
y_i = uniform(1,5) \\
{\bf x}_i={\mathcal N}(0, 5) + y_i{\bf w}

1000 pièces de données à 50 dimensions, le degré de conformité est soit [1,2,3,4,5]. Lorsqu'elle est tracée dans l'espace PCA, la figure est la suivante.

pca_fig.png

D'une manière ou d'une autre, il semble que le degré de conformité soit plus élevé vers le coin supérieur gauche de la figure et diminue vers le coin inférieur droit.

Vous trouverez ci-dessous le code d'apprentissage et d'évaluation. La formation utilise la méthode de descente de gradient stochastique, et les données d'apprentissage sont échantillonnées au hasard à chaque fois. NDCG @ 100 a été utilisé pour évaluer la précision de la prédiction.

train_toy.py


import numpy as np
from chainer import Variable, optimizers
from sklearn.cross_validation import train_test_split
import net
import matplotlib.pyplot as plt
import seaborn as sns


def make_dataset(n_dim, n_rank, n_sample, sigma):
    ys = np.random.random_integers(n_rank, size=n_sample)
    w = np.random.randn(n_dim)
    X = [sigma * np.random.randn(n_dim) + w * y for y in ys]
    X = np.array(X).astype(np.float32)
    ys = np.reshape(np.array(ys), (-1, 1))
    return X, ys


def ndcg(y_true, y_score, k=100):
    y_true = y_true.ravel()
    y_score = y_score.ravel()
    y_true_sorted = sorted(y_true, reverse=True)
    ideal_dcg = 0
    for i in range(k):
        ideal_dcg += (2 ** y_true_sorted[i] - 1.) / np.log2(i + 2)
    dcg = 0
    argsort_indices = np.argsort(y_score)[::-1]
    for i in range(k):
        dcg += (2 ** y_true[argsort_indices[i]] - 1.) / np.log2(i + 2)
    ndcg = dcg / ideal_dcg
    return ndcg

if __name__ == '__main__':
    np.random.seed(0)
    n_dim = 50
    n_rank = 5
    n_sample = 1000
    sigma = 5.
    X, ys = make_dataset(n_dim, n_rank, n_sample, sigma)
    X_train, X_test, y_train, y_test = train_test_split(X, ys, test_size=0.33)

    n_iter = 2000
    n_hidden = 20
    loss_step = 50
    N_train = np.shape(X_train)[0]

    model = net.RankNet(net.MLP(n_dim, n_hidden))
    optimizer = optimizers.Adam()
    optimizer.setup(model)

    N_train = np.shape(X_train)[0]
    train_ndcgs = []
    test_ndcgs = []
    for step in range(n_iter):
        i, j = np.random.randint(N_train, size=2)
        x_i = Variable(X_train[i].reshape(1, -1))
        x_j = Variable(X_train[j].reshape(1, -1))
        y_i = Variable(y_train[i])
        y_j = Variable(y_train[j])
        model.zerograds()
        loss = model(x_i, x_j, y_i, y_j)
        loss.backward()
        optimizer.update()
        if (step + 1) % loss_step == 0:
            train_score = model.predictor(Variable(X_train))
            test_score = model.predictor(Variable(X_test))
            train_ndcg = ndcg(y_train, train_score.data)
            test_ndcg = ndcg(y_test, test_score.data)
            train_ndcgs.append(train_ndcg)
            test_ndcgs.append(test_ndcg)
            print("step: {0}".format(step + 1))
            print("NDCG@100 | train: {0}, test: {1}".format(train_ndcg, test_ndcg))

    plt.plot(train_ndcgs, label="Train")
    plt.plot(test_ndcgs, label="Test")
    xx = np.linspace(0, n_iter / loss_step, num=n_iter / loss_step + 1)
    labels = np.arange(loss_step, n_iter + 1, loss_step)
    plt.xticks(xx, labels, rotation=45)
    plt.legend(loc="best")
    plt.xlabel("step")
    plt.ylabel("NDCG@10")
    plt.ylim(0, 1.1)
    plt.tight_layout()
    plt.savefig("result.pdf")

result.PNG

Étant donné que les données d'entraînement et les données de test sont générées à partir de la même distribution, il est naturel de dire que c'est naturel, mais vous pouvez voir comment les valeurs d'évaluation augmentent ensemble.

Autre

Je veux faire quelque chose d'intéressant

Recommended Posts

Apprentissage des classements à l'aide d'un réseau neuronal (implémentation RankNet par Chainer)
Implémentation de réseaux neuronaux "flous" avec Chainer
Implémentation simple d'un réseau neuronal à l'aide de Chainer
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
Présentation de DNC (Differentiable Neural Computers) + Implémentation par Chainer
Mise en œuvre de l'optimisation bayésienne des hyper paramètres du réseau de neurones (Chainer + GPyOpt)
Implémentation d'un réseau de neurones convolutifs utilisant uniquement Numpy
Mise en œuvre de l'apprentissage en série de Chainer à l'aide de mini-lots de longueur variable
Implémentation d'un réseau de neurones à deux couches 2
Implémentation d'un système de dialogue utilisant Chainer [seq2seq]
Implémentation de réseau neuronal simple à l'aide de la préparation Chainer-Data-
Implémentation de réseau neuronal simple à l'aide de la description du modèle Chainer-
[Chainer] Classification des documents par réseau de neurones convolutifs
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer Chapitre 13 Formation sur les réseaux neuronaux ~ Chainer terminé
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer Chapitre 13 Bases du réseau neuronal
Implémentation simple d'un réseau de neurones à l'aide de Chainer ~ Définition d'un algorithme d'optimisation ~
Apprentissage par renforcement 10 Essayez d'utiliser un réseau neuronal formé.
Reconnaissance des nombres manuscrits par un réseau neuronal multicouche
Apprentissage profond appris par mise en œuvre (segmentation) ~ Mise en œuvre de SegNet ~
Python vs Ruby "Deep Learning from scratch" Chapitre 3 Implémentation d'un réseau neuronal à 3 couches
[Deep Learning from scratch] Valeur initiale du poids du réseau neuronal utilisant la fonction sigmoïde
[Pour les débutants en apprentissage profond] Implémentation d'une classification binaire simple par couplage complet à l'aide de Keras
[Deep Learning from scratch] Poids initial du réseau neuronal lors de l'utilisation de la fonction Relu
Implémentation de TF-IDF à l'aide de gensim
Réseau de neurones commençant par Chainer
J'ai essayé d'implémenter ListNet d'apprentissage de rang avec Chainer
Implémentation de réseau neuronal en python
Construction d'un réseau neuronal qui reproduit XOR par Z3
Implémentation de réseau neuronal (NumPy uniquement)
Apprentissage par renforcement profond 2 Mise en œuvre de l'apprentissage par renforcement
Etude du réseau neuronal récurrent (RNN) par Chainer ~ Vérification de l'exactitude des nombres aléatoires dans Excel et R ~
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage ((1) Implémentation du blackjack)
Exemple d'implémentation d'un réseau de génération hostile (GAN) par Keras
Résumé de l'implémentation de base par PyTorch
PRML Chapitre 5 Implémentation Python du réseau neuronal
Théorie et implémentation simples des réseaux neuronaux
Renforcer l'apprentissage 8 Essayez d'utiliser l'interface utilisateur de Chainer
Apprentissage profond appris par l'implémentation 1 (édition de retour)
Implémentation des notifications de bureau à l'aide de Python
Touchez l'objet du réseau neuronal
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer jusqu'à la fin du chapitre 2
Prédiction des survivants à l'aide du réseau neuronal titanesque de Kaggle [80,8%]
Deep learning 2 appris par l'implémentation (classification d'images)
[Mémo d'apprentissage] Bases de la classe par python
Othello-De la troisième ligne de "Implementation Deep Learning" (3)
Qiskit: mise en œuvre de l'apprentissage des circuits quantiques (QCL)
Essayez d'utiliser TensorFlow-Part 2-Convolution Neural Network (MNIST)
Implémentation de SVM par méthode de descente de gradient probabiliste
Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)
Mémo d'étude Python & Machine Learning ③: Réseau neuronal
Othello-De la troisième ligne de "Implementation Deep Learning" (2)
[Super Introduction] Apprentissage automatique utilisant Python - De la construction d'environnement à l'implémentation de perceptron simple-
Apprentissage automatique: reconnaissance d'image de MNIST à l'aide de PCA et de Gaussian Native Bayes
Reconsidération de l'implémentation de la pagination par style Relay dans GraphQL (version utilisant la fonction Window)
Mise en place d'un modèle de prédiction des taux de change (taux dollar-yen) par machine learning