Ich lese ein Meisterwerk, ** "Deep Learning from Zero 2" **. Diesmal ist ein Memo von Kapitel 8. Um den Code auszuführen, laden Sie den gesamten Code von Github herunter und verwenden Sie das Jupiter-Notizbuch in Kapitel 08.
2.Attention Unten sehen Sie ein schematisches Diagramm der Aufmerksamkeit im Seq2seq-Modell.
Setzen Sie ** Aufmerksamkeit ** zwischen ** LSTM ** und ** Affine ** zu allen Zeiten von ** Decoder **. Geben Sie dann ** hs **, eine Sammlung von ** versteckten Vektoren (hs0 bis hs4) ** zu jedem Zeitpunkt von ** Encoder **, in alle Attentions ein.
In jeder Aufmerksamkeit wird die Ähnlichkeit (Vektorprodukt) zwischen der Eingabe von LSTM und hs berechnet, und die Bedeutung versteckter Vektoren (hs0 bis hs4) wird durch eine Wahrscheinlichkeitsverteilung berechnet. Dann wird der verborgene Vektor durch seine Wahrscheinlichkeitsverteilung gewichtet und synthetisiert und an Affine gesendet.
Es ist ein schematisches Diagramm innerhalb der Aufmerksamkeitsebene und das dort durchgeführte Matrixberechnungsbild (wenn Chargengröße N = 1).
Zuerst der Teil ** Attention_weight **. Finden Sie das ** Produkt ** der ** Vektoren hs0 bis hs4 ** des Encoders und des ** Vektors h ** des Decoders und addieren Sie sie in der ** Spaltenrichtung (Achse = 2) **. Je höher die ** Ähnlichkeit von, desto größer die **. Wenn Softmax durch diese Zahl geleitet wird, erhält man einen ** Vektor a **, der die ** Gewichtung der Vektoren hs0 bis hs4 ** darstellt.
Als nächstes folgt der Teil ** Weight_Sum **. Das ** Produkt ** der ** Vektoren hs0 bis hs4 ** und ** des Vektors a ** wird berechnet, und der ** Vektor C *, der durch die ** Zeilenrichtung (Achse = 1) ** addiert wird, ist ** Aufmerksamkeit ( Aufmerksamkeit () Die Informationen (siehe) werden gewichtet und kombiniert (hinzugefügt), um einen Vektor ** zu bilden. Durch das Senden an Affine kann Affine ** Informationen auf der Encoder-Seite erhalten, auf die zu diesem Zeitpunkt zusätzlich zu den Informationen aus dem herkömmlichen LSTM ** verwiesen werden sollte.
Übrigens, bei der Berechnung von np.sum (x, Achse =?) Von x = (N, T, H), Summe (Addition in Chargenrichtung), so dass die N-Achse gelöscht wird, wenn ** Achse = 0. Wenn dann ** Achse = 1 ist, erfolgt die Summe (Addition in Zeilenrichtung), so dass die T-Achse gelöscht wird **, und wenn ** Achse = 2, wird die H-Achse gelöscht ** (Addition in Spaltenrichtung). Machen.
Werfen wir einen Blick auf den Code für Attention_weight.
class AttentionWeight:
def __init__(self):
self.params, self.grads = [], []
self.softmax = Softmax()
self.cache = None
def forward(self, hs, h):
N, T, H = hs.shape
#Da hr für den Rundfunk verwendet wird, wird nur die Dimension ohne Wiederholung angepasst.
hr = h.reshape(N, 1, H) #.repeat(T, axis=1)
t = hs * hr #Nehmen Sie das Produkt der Vektoren
s = np.sum(t, axis=2) #Addition in Spaltenrichtung
a = self.softmax.forward(s) #Berechnen Sie die Wahrscheinlichkeitsverteilung a, die die Wichtigkeit jedes versteckten Vektors darstellt
self.cache = (hs, hr)
return a
def backward(self, da):
hs, hr = self.cache
N, T, H = hs.shape
ds = self.softmax.backward(da)
dt = ds.reshape(N, T, 1).repeat(H, axis=2) # (N, T, H)Umstellung auf
dhs = dt * hr
dhr = dt * hs
dh = np.sum(dhr, axis=1)
return dhs, dh
Für die Vorwärtsausbreitung wird t = hs * hr durch Senden berechnet, so dass hr nicht wiederholt wird. Schauen wir uns als nächstes Weight_sum an.
class WeightSum:
def __init__(self):
self.params, self.grads = [], []
self.cache = None
def forward(self, hs, a):
N, T, H = hs.shape
#Da ar für den Rundfunk verwendet wird, werden nur die Abmessungen ohne Wiederholung angepasst.
ar = a.reshape(N, T, 1) #.repeat(T, axis=1)
t = hs * ar #Nehmen Sie das Produkt von Vektoren
c = np.sum(t, axis=1) #Zeilenrichtung hinzufügen
self.cache = (hs, ar)
return c
def backward(self, dc):
hs, ar = self.cache
N, T, H = hs.shape
dt = dc.reshape(N, 1, H).repeat(T, axis=1)
dar = dt * hs
dhs = dt * ar
da = np.sum(dar, axis=2)
return dhs, da
Für die Vorwärtsausbreitung wird t = hs * ar durch Rundfunk berechnet, sodass ar nicht wiederholt wird. Fügen Sie diese beiden Klassen zu einer "Klassenaufmerksamkeit" zusammen.
class Attention:
def __init__(self):
self.params, self.grads = [], []
self.attention_weight_layer = AttentionWeight()
self.weight_sum_layer = WeightSum()
self.attention_weight = None
def forward(self, hs, h):
a = self.attention_weight_layer.forward(hs, h)
out = self.weight_sum_layer.forward(hs, a)
self.attention_weight = a
return out
def backward(self, dout):
dhs0, da = self.weight_sum_layer.backward(dout)
dhs1, dh = self.attention_weight_layer.backward(da)
dhs = dhs0 + dhs1
return dhs, d
Zusätzlich wird es in der Klasse TimeAttention zusammengefasst, um der Zeit zu entsprechen.
class TimeAttention:
def __init__(self):
self.params, self.grads = [], []
self.layers = None
self.attention_weights = None
def forward(self, hs_enc, hs_dec):
N, T, H = hs_dec.shape
out = np.empty_like(hs_dec)
self.layers = []
self.attention_weights = []
for t in range(T):
layer = Attention()
out[:, t, :] = layer.forward(hs_enc, hs_dec[:,t,:])
self.layers.append(layer)
self.attention_weights.append(layer.attention_weight)
return out
def backward(self, dout):
N, T, H = dout.shape
dhs_enc = 0
dhs_dec = np.empty_like(dout)
for t in range(T):
layer = self.layers[t]
dhs, dh = layer.backward(dout[:, t, :])
dhs_enc += dhs
dhs_dec[:,t,:] = dh
return dhs_enc, dhs_dec
Lassen Sie uns nun den Beispielcode (Datumsformatkonvertierung) ** train.py ** von seq2seq mit diesem Aufmerksamkeitsmechanismus ausführen.
import sys
sys.path.append('..')
import numpy as np
import matplotlib.pyplot as plt
from dataset import sequence
from common.optimizer import Adam
from common.trainer import Trainer
from common.util import eval_seq2seq
from attention_seq2seq import AttentionSeq2seq
from ch07.seq2seq import Seq2seq
#Daten lesen
(x_train, t_train), (x_test, t_test) = sequence.load_data('date.txt')
char_to_id, id_to_char = sequence.get_vocab()
#Eingabeanweisung invertieren
x_train, x_test = x_train[:, ::-1], x_test[:, ::-1]
#Hyper-Parametereinstellungen
vocab_size = len(char_to_id)
wordvec_size = 16
hidden_size = 256
batch_size = 128
max_epoch = 10
max_grad = 5.0
model = AttentionSeq2seq(vocab_size, wordvec_size, hidden_size)
# model = Seq2seq(vocab_size, wordvec_size, hidden_size)
# model = PeekySeq2seq(vocab_size, wordvec_size, hidden_size)
optimizer = Adam()
trainer = Trainer(model, optimizer)
acc_list = []
for epoch in range(max_epoch):
trainer.fit(x_train, t_train, max_epoch=1,
batch_size=batch_size, max_grad=max_grad)
correct_num = 0
for i in range(len(x_test)):
question, correct = x_test[[i]], t_test[[i]]
verbose = i < 10
correct_num += eval_seq2seq(model, question, correct,
id_to_char, verbose, is_reverse=True)
acc = float(correct_num) / len(x_test)
acc_list.append(acc)
print('val acc %.3f%%' % (acc * 100))
model.save_params()
#Zeichnen eines Diagramms
x = np.arange(len(acc_list))
plt.plot(x, acc_list, marker='o')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.ylim(-0.05, 1.05)
plt.show()
Nach 2 Epochen beträgt die Genauigkeit 100%. Wie erwartet ist es die Kraft der Aufmerksamkeit.
Recommended Posts