Je lis un chef-d'œuvre, ** "Deep Learning from Zero 2" **. Cette fois, c'est un mémo du chapitre 3. Pour exécuter le code, téléchargez le code complet depuis Github et utilisez le notebook jupyter dans ch03.
Lançons un modèle CBOW word2vec simple. Exécutez ch03 / train.py.
import sys
sys.path.append('..') #Paramètres d'importation des fichiers dans le répertoire parent
from common.trainer import Trainer
from common.optimizer import Adam
from simple_cbow import SimpleCBOW
from common.util import preprocess, create_contexts_target, convert_one_hot
window_size = 1
hidden_size = 5
batch_size = 3
max_epoch = 1000
#Obtenir le corpus et le dictionnaire
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
#Obtenez le contexte, ciblez
contexts, target = create_contexts_target(corpus, window_size)
#Expression unique
vocab_size = len(word_to_id)
contexts = convert_one_hot(contexts, vocab_size)
target = convert_one_hot(target, vocab_size)
#Construction de réseau
model = SimpleCBOW(vocab_size, hidden_size)
#Affichage de la transition d'apprentissage et de perte
optimizer = Adam()
trainer = Trainer(model, optimizer)
trainer.fit(contexts, target, max_epoch, batch_size)
trainer.plot()
#Affichage vectoriel des mots
word_vecs = model.word_vecs
for word_id, word in id_to_word.items():
print(word, word_vecs[word_id])
Il ne s'agit que de 7 mots word2vec, mais je serais heureux si la perte se résorbe en douceur et qu'un vecteur en 5 dimensions de chaque mot peut être obtenu. Jetons un coup d'œil au code dans l'ordre.
#Obtenir le corpus et le dictionnaire
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
preprocess ()
se trouve dans common / util.py, alors reportez-vous-y.
# -------------- from common/util.py ---------------
def preprocess(text):
text = text.lower() #Des majuscules aux minuscules
text = text.replace('.', ' .') #Un blanc avant la période
words = text.split(' ') #Liste des mots séparés par un espace blanc
word_to_id = {}
id_to_word = {}
for word in words: #De liste en mot un mot à la fois
if word not in word_to_id: #Le mot est mot_to_Sinon dans l'id
new_id = len(word_to_id) # word_to_Définir le nombre d'identifiants enregistrés sur id
word_to_id[word] = new_id # word_to_enregistrement de l'identifiant
id_to_word[new_id] = word # id_to_enregistrement de mots
corpus = np.array([word_to_id[w] for w in words]) #Convertir un corpus en identifiant
return corpus, word_to_id, id_to_word
Décomposez le texte en mots pour obtenir un corpus. Créez un dictionnaire (mots → nombres, nombres → mots) et utilisez ce dictionnaire pour remplacer corpus par id. corpus = [0 1 2 3 4 1 5 6] word_to_id = {'you': 0, 'say': 1, 'goodbye': 2, 'and':3 , 'i': 4, 'hello': 5, '.': 6} id_to_word = {0 :'you', 1 :'say', 2 :'goodbye', 3 :'and', 4 :'i', 5 :'hello', 6 : '.'}
#Obtenez le contexte et la cible
contexts, target = create_contexts_target(corpus, window_size)
create_contexts_target ()
est situé dans common / util.py, alors référez-vous-y.
# -------------- from common/util.py ---------------
def create_contexts_target(corpus, window_size=1):
#la cible est la fenêtre avant et après le corpus_moins la taille
target = corpus[window_size:-window_size]
contexts = []
#Que les contextes soient t minutes avant et après la cible
for idx in range(window_size, len(corpus)-window_size): # idx = 1 〜 6
cs = []
for t in range(-window_size, window_size + 1): # t = -1, 0, 1
if t == 0:
continue # t =Quand c'est 0, ne rien faire
cs.append(corpus[idx + t]) # cs = courpus[idx-1, idx+1]
contexts.append(cs)
return np.array(contexts), np.array(target)
target est l'avant et l'arrière du corpus moins window_size. Ensuite, en mettant la position de la cible dans le corpus dans idx et en spécifiant avant et après avec t, on obtient des contextes. contexts = [[[0 2][1 3][2 4][3 1][4 5][1 6]]] target = [1 2 3 4 1 5]
#Expression unique
vocab_size = len(word_to_id)
contexts = convert_one_hot(contexts, vocab_size)
target = convert_one_hot(target, vocab_size)
convert_one_hot ()
se trouve dans common / util.py, alors reportez-vous-y.
# -------------- from common/util.py ---------------
def convert_one_hot(corpus, vocab_size):
N = corpus.shape[0]
if corpus.ndim == 1: #Pour une dimension(Pour cible)
one_hot = np.zeros((N, vocab_size), dtype=np.int32) #Création de matrice zéro
for idx, word_id in enumerate(corpus): #cible au mot_Affectation séquentielle à l'identifiant
one_hot[idx, word_id] = 1
elif corpus.ndim == 2: #Dans le cas de 2 dimensions(Pour les contextes)
C = corpus.shape[1]
one_hot = np.zeros((N, C, vocab_size), dtype=np.int32) #Création de matrice zéro
for idx_0, word_ids in enumerate(corpus): #mots de contextes_Affectation séquentielle aux identifiants
for idx_1, word_id in enumerate(word_ids): # word_mots des identifiants_Affectation séquentielle à l'identifiant
one_hot[idx_0, idx_1, word_id] = 1
return one_hot
Dans le cas de ** target **, (N, vocab_size) est utilisé pour créer une matrice zéro, et one_hot [idx, word_id] est utilisé pour définir l'emplacement spécifié sur 1.
Dans le cas de ** contextes **, comme il est bidimensionnel, une matrice nulle est créée avec (N, C, vocab_size), et la partie spécifiée est mise à 1 avec one_hot [idx_0, idx_1, word_id].
#Construction de réseau
model = SimpleCBOW(vocab_size, hidden_size)
C'est la partie de la construction du réseau. Parcourons simple_cbow.py, qui a la classe SimpleCBOW ()
.
# -------------- from simple_cbow.py ---------------
class SimpleCBOW:
def __init__(self, vocab_size, hidden_size):
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(H, V).astype('f')
#Génération de couches
self.in_layer0 = MatMul(W_in)
self.in_layer1 = MatMul(W_in)
self.out_layer = MatMul(W_out)
self.loss_layer = SoftmaxWithLoss()
#Lister tous les poids et dégradés
layers = [self.in_layer0, self.in_layer1, self.out_layer]
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
Puisque window_size = 1, il y a deux entrées. L'entrée est 7 vecteurs one-hot, qui est le même que le nombre de vocabulaire, la couche cachée est 5 et la sortie est 7 qui est le même que le nombre de vocabulaire.
** Hypothèse de distribution ** Basé sur "le sens d'un mot est formé par les mots environnants", si vous apprenez à résoudre la question à remplir en blanc de savoir quel est le mot entre deux mots, $ W_ {in} Le $ est une représentation distribuée du mot.
Enfin, le poids W_in est attribué à word_vecs. Ceci est utilisé pour l'affichage vectoriel des mots après l'apprentissage.
# -------------- from simple_cbow.py ---------------
def forward(self, contexts, target):
h0 = self.in_layer0.forward(contexts[:, 0])
h1 = self.in_layer1.forward(contexts[:, 1])
h = (h0 + h1) * 0.5
score = self.out_layer.forward(h)
loss = self.loss_layer.forward(score, target)
return loss
Les poids $ W_ {in} $ pour layer0 et layer1 sont partagés. Après avoir ajouté les signaux de layer0 et layer1, divisez par 2.
# -------------- from simple_cbow.py ---------------
def backward(self, dout=1):
ds = self.loss_layer.backward(dout)
da = self.out_layer.backward(ds)
da *= 0.5
self.in_layer1.backward(da)
self.in_layer0.backward(da)
return None
C'est une propagation de retour d'erreur. Cela ne devrait pas être un problème.
#Affichage du graphique de transition d'apprentissage et de perte
optimizer = Adam()
trainer = Trainer(model, optimizer)
trainer.fit(contexts, target, max_epoch, batch_size)
trainer.plot()
Instanciez class Trainer ()
dans common / trainer.py avec Adam, le modèle et l'optimiseur que vous avez construit le réseau plus tôt. Après cela, apprenez avec ajustement et affichez le graphique de transition de perte avec tracé.
#Affichage vectoriel des mots
word_vecs = model.word_vecs #Poids W_in(Vecteur de mot)Avoir
for word_id, word in id_to_word.items(): # id_to_Obtenir l'index et le mot du mot
print(word, word_vecs[word_id]) #Afficher les mots et les vecteurs
Enfin, appelez le vecteur de mots appris model.word_vecs
pour afficher les mots et les vecteurs.
Recommended Posts