[PYTHON] Deep learning / Deep learning from scratch 2 Chapitre 4 Mémo

1.Tout d'abord

Je lis un chef-d'œuvre, ** "Deep Learning from Zero 2" **. Cette fois, c'est un mémo du chapitre 4. Pour exécuter le code, téléchargez le code complet depuis Github et utilisez le notebook jupyter dans ch04.

2. Modèle CBOW version haute vitesse

Le thème du chapitre 4 est d'accélérer le modèle CBOW Word2vec implémenté dans le chapitre 3 et d'en faire un modèle pratique. Exécutez ch04 / train.py et regardez le contenu dans l'ordre.

L'ensemble de données utilise Penn Tree Bank, le nombre de vocabulaire est de 10 000 et la taille du corpus du train. Est d'environ 900 000 mots.

import sys
sys.path.append('..')
from common import config
#Lors de l'exécution sur GPU, supprimez le commentaire ci-dessous (cupy requis)
# ===============================================
# config.GPU = True
# ===============================================
from common.np import *
import pickle
from common.trainer import Trainer
from common.optimizer import Adam
from cbow import CBOW
from skip_gram import SkipGram
from common.util import create_contexts_target, to_cpu, to_gpu
from dataset import ptb

#Paramètres des hyper paramètres
window_size = 5
hidden_size = 100
batch_size = 100
max_epoch = 10

#Lire les données
corpus, word_to_id, id_to_word = ptb.load_data('train')
vocab_size = len(word_to_id)

#Obtenez le contexte et la cible
contexts, target = create_contexts_target(corpus, window_size)
if config.GPU:
    contexts, target = to_gpu(contexts), to_gpu(target)

#Construction de réseau
model = CBOW(vocab_size, hidden_size, window_size, corpus)

#Apprentissage, affichage du graphique de transition de perte
optimizer = Adam()
trainer = Trainer(model, optimizer)
trainer.fit(contexts, target, max_epoch, batch_size)
trainer.plot()

#Enregistrez les données dont vous avez besoin pour une utilisation ultérieure
word_vecs = model.word_vecs
if config.GPU:
    word_vecs = to_cpu(word_vecs)
params = {}
params['word_vecs'] = word_vecs.astype(np.float16)
params['word_to_id'] = word_to_id
params['id_to_word'] = id_to_word
pkl_file = 'cbow_params.pkl'  # or 'skipgram_params.pkl'
with open(pkl_file, 'wb') as f:
    pickle.dump(params, f, -1)

スクリーンショット 2020-05-13 16.27.53.png

La perte semble avoir diminué régulièrement. Ensuite, cela devient un point. Jetons un coup d'œil à class CBOW dans cbow.py dans la partie construction du réseau.

# --------------- from cbow.py ---------------
class CBOW:
    def __init__(self, vocab_size, hidden_size, window_size, corpus):
        V, H = vocab_size, hidden_size

        #Initialisation du poids
        W_in = 0.01 * np.random.randn(V, H).astype('f')
        W_out = 0.01 * np.random.randn(V, H).astype('f')

        #Génération de couches
        self.in_layers = []
        for i in range(2 * window_size):
            layer = Embedding(W_in)  #Utiliser le calque d'incorporation
            self.in_layers.append(layer)
        self.ns_loss = NegativeSamplingLoss(W_out, corpus, power=0.75, sample_size=5)

        #Lister tous les poids et dégradés
        layers = self.in_layers + [self.ns_loss]
        self.params, self.grads = [], []
        for layer in layers:
            self.params += layer.params
            self.grads += layer.grads

        #Définir une représentation distribuée des mots dans les variables membres
        self.word_vecs = W_in

L'un des points d'accélération est l'adoption de la ** couche d'intégration **. Jetez un œil à common / layer.py.

3. Couche d'intégration

# --------------- from common/layers.py --------------
class Embedding:
    def __init__(self, W):
        self.params = [W]
        self.grads = [np.zeros_like(W)]
        self.idx = None

    def forward(self, idx):
        W, = self.params
        self.idx = idx
        out = W[idx]  #Sortie de la ligne spécifiée par idx
        return out

    def backward(self, dout):
        dW, = self.grads
        dW[...] = 0
        if GPU:
            np.scatter_add(dW, self.idx, dout)
        else:
            np.add.at(dW, self.idx, dout)  #Ajouter des données à la ligne spécifiée par idx
        return None

スクリーンショット 2020-05-14 15.56.08.png

Dans le chapitre 3, la ** couche MatMul ** a été utilisée pour trouver le produit interne du vecteur et de la matrice de poids, mais quand on y réfléchit, c'est le produit interne du vecteur one-hot et de la matrice de poids, donc ** la matrice de poids $ W_ {in} Tout ce que vous avez à faire est de spécifier la ligne $ **. Il s'agit de la ** couche incorporée **.

De cette façon, la rétropropagation n'a besoin que de mettre à jour la ligne correspondante avec les données précédemment transmises. Cependant, dans l'apprentissage par mini-lots, il est possible que plusieurs données reviennent à la même ligne et se chevauchent, donc ** les données sont ajoutées ** au lieu d'être remplacées.

4.Negative Sampling Le deuxième point d'accélération est ** l'échantillonnage négatif **. Comme dans le chapitre 3, il n'est pas réaliste de classer par Softmax à partir de la sortie du nombre de vocabulaire. Alors que devons-nous faire. La réponse est ** de résoudre le problème de classification à valeurs multiples en l'approximant au problème de classification binaire **.

Jetez un œil à class NegativeSamplingLoss dans negative_sampling_layer.py.

# ------------- form negative_sampling_layer.py --------------
class NegativeSamplingLoss:
    def __init__(self, W, corpus, power=0.75, sample_size=5):
        self.sample_size = sample_size
        self.sampler = UnigramSampler(corpus, power, sample_size)
        self.loss_layers = [SigmoidWithLoss() for _ in range(sample_size + 1)]
        self.embed_dot_layers = [EmbeddingDot(W) for _ in range(sample_size + 1)]

        self.params, self.grads = [], []
        for layer in self.embed_dot_layers:
            self.params += layer.params
            self.grads += layer.grads

    def forward(self, h, target):
        batch_size = target.shape[0]
        negative_sample = self.sampler.get_negative_sample(target)

        #Exemple positif en avant
        score = self.embed_dot_layers[0].forward(h, target)
        correct_label = np.ones(batch_size, dtype=np.int32)
        loss = self.loss_layers[0].forward(score, correct_label)

        #Négatif en avant
        negative_label = np.zeros(batch_size, dtype=np.int32)
        for i in range(self.sample_size):
            negative_target = negative_sample[:, i]
            score = self.embed_dot_layers[1 + i].forward(h, negative_target)
            loss += self.loss_layers[1 + i].forward(score, negative_label)

        return loss

    def backward(self, dout=1):
        dh = 0
        for l0, l1 in zip(self.loss_layers, self.embed_dot_layers):
            dscore = l0.backward(dout)
            dh += l1.backward(dscore)

        return dh

スクリーンショット 2020-05-13 17.36.16.png Pour rapprocher la classification à valeurs multiples de la classification binaire, commencez par établir la probabilité que dire (1) est correct pour la réponse du mot entre vous (0) et au revoir (2) autant que possible (correct). Exemple). Mais ce n'est pas assez.

Par conséquent, j'ajoute que la probabilité qu'un bonjour (5) ou I (4) correctement sélectionné soit incorrect est aussi grande que possible (exemple négatif).

Cette technique est appelée ** Échantillonnage négatif **. Le nombre d'exemples négatifs parmi lesquels choisir est sample_size = 5 dans le code.

Ici, ʻEmbedding_dot_layersapparaît, alors jetons un œil à cela également. De même, il se trouve dansnegatif_sampling_layer.py`.

# ------------- form negative_sampling_layer.py --------------
class EmbeddingDot:
    def __init__(self, W):
        self.embed = Embedding(W)
        self.params = self.embed.params
        self.grads = self.embed.grads
        self.cache = None

    def forward(self, h, idx):
        target_W = self.embed.forward(idx)
        out = np.sum(target_W * h, axis=1)

        self.cache = (h, target_W)
        return out

    def backward(self, dout):
        h, target_W = self.cache
        dout = dout.reshape(dout.shape[0], 1)

        dtarget_W = dout * h
        self.embed.backward(dtarget_W)
        dh = dout * target_W
        return dh

スクリーンショット 2020-05-14 10.56.04.png Afin de prendre en charge le mini-lot, la somme de target_w * h est prise à la fin afin qu'elle puisse être calculée même s'il y a plusieurs idx et h.

5. Évaluation du modèle

Tout d'abord, nous avons déplacé ch04 / train.py, donc les paramètres appris sont stockés dans cbow_params.pkl. Utilisez ceci pour vérifier ʻeval.py` pour voir si la représentation distribuée des mots est bonne.

import sys
sys.path.append('..')
from common.util import most_similar, analogy
import pickle

pkl_file = 'cbow_params.pkl'  #Spécification du nom de fichier

#Lecture de chaque paramètre
with open(pkl_file, 'rb') as f:  
    params = pickle.load(f)  
    word_vecs = params['word_vecs']
    word_to_id = params['word_to_id']
    id_to_word = params['id_to_word']

# most similar task
querys = ['you']
for query in querys:
    most_similar(query, word_to_id, id_to_word, word_vecs, top=5)

スクリーンショット 2020-05-14 15.41.11.png

Commencez par vérifier la similarité des mots en utilisant la méthode most_similar (common / util.py). La chose la plus proche de vous est nous, et moi, eux, votre, suivis de synonymes personnels. Ceci est le résultat du calcul de la similitude de chaque mot avec la similitude cosinus suivante. スクリーンショット 2020-05-14 15.25.40.png

# analogy task
analogy('king', 'man', 'queen',  word_to_id, id_to_word, word_vecs)

スクリーンショット 2020-05-14 15.40.21.png

Voyons maintenant le fameux problème ** king --man + woman = queen ** en utilisant la méthode ʻalalogy` (common / util.py). C'est vrai, non?

Cela résout la tâche de trouver le ** mot x ** de sorte que le vecteur ** "roi → x" ** soit aussi proche que possible du ** vecteur "homme → femme" **.

Recommended Posts

Deep learning / Deep learning from scratch 2 Chapitre 4 Mémo
Deep learning / Deep learning made from scratch Chapitre 3 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 5 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 7 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 8 Mémo
Deep learning / Deep learning made from scratch Chapitre 5 Mémo
Deep learning / Deep learning made from scratch Chapitre 4 Mémo
Deep learning / Deep learning from scratch 2 Chapitre 3 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 6 Mémo
[Mémo d'apprentissage] Le Deep Learning fait de zéro [Chapitre 7]
Deep learning / Deep learning made from scratch Chapitre 6 Mémo
[Mémo d'apprentissage] Deep Learning fait de zéro [Chapitre 5]
[Mémo d'apprentissage] Le Deep Learning fait de zéro [Chapitre 6]
Deep learning / Deep learning made from scratch Chapitre 7 Mémo
[Mémo d'apprentissage] Deep Learning fait de zéro [~ Chapitre 4]
Deep Learning from scratch Chapter 2 Perceptron (lecture du mémo)
Apprentissage amélioré pour apprendre de zéro à profond
Mémo d'auto-apprentissage "Deep Learning from scratch" (partie 12) Deep learning
Apprentissage profond à partir de zéro
Mémo d'auto-apprentissage "Deep Learning from scratch" (glossaire illisible)
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 9) Classe MultiLayerNet
Deep Learning from scratch ① Chapitre 6 "Techniques liées à l'apprentissage"
[Mémo d'apprentissage] Apprentissage profond à partir de zéro ~ Mise en œuvre de l'abandon ~
Mémo d'auto-apprentissage «Deep Learning from scratch» (10) Classe MultiLayerNet
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 11) CNN
Apprentissage profond à partir de zéro 1 à 3 chapitres
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 19) Augmentation des données
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer du chapitre 2
Deep Learning 2 from scratch 1.3 Traitement du langage naturel 1.3 Résumé
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 1
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 5
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 2
Apprentissage profond à partir de zéro (calcul des coûts)
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 3
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 7
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 5
Un amateur a trébuché dans le Deep Learning ❷ fait de zéro Note: Chapitre 1
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 4
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 18) One! Miaou! Grad-CAM!
Un amateur a trébuché dans le Deep Learning à partir de zéro.
Mémo d'apprentissage profond créé à partir de zéro
L'apprentissage en profondeur
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 2
Mémo d'auto-apprentissage "Deep Learning from scratch" (n ° 15) Tutoriel pour débutants TensorFlow
Tutoriel d'apprentissage en profondeur de la construction d'environnement
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 14) Exécutez le programme du chapitre 4 sur Google Colaboratory
Mémo d'auto-apprentissage "Deep Learning from scratch" (partie 8) J'ai dessiné le graphique du chapitre 6 avec matplotlib
Mémo d'auto-apprentissage "Deep Learning from scratch" (n ° 13) Essayez d'utiliser Google Colaboratory
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 10-2) Valeur initiale du poids
Apprentissage profond à partir de zéro (propagation vers l'avant)
Apprentissage profond / Apprentissage profond à partir de zéro 2-Essayez de déplacer GRU
Alignement d'image: du SIFT au deep learning
"Deep Learning from scratch" avec Haskell (inachevé)
[Windows 10] Construction de l'environnement "Deep Learning from scratch"
Enregistrement d'apprentissage de la lecture "Deep Learning from scratch"
[Deep Learning from scratch] À propos de l'optimisation des hyper paramètres
Apprentissage profond à partir des bases mathématiques (pendant la fréquentation)