Ich habe Nachrichtenartikel über das Corona-Virus gesammelt und möchte es verwenden, um die Satzgenerierung herauszufordern.
Ich habe zu Hause angefangen, Deep Learning mit Pytorch zu lernen, also lass es mich ausgeben. Ich lerne noch, also bitte verstehe, dass es einige Fehler geben kann ...
import torch
import torch.nn as nn
import torch.optim as optimizers
from torch.utils.data import DataLoader
import torch.nn.functional as F
from tensorflow.keras.preprocessing.sequence import pad_sequences
from sklearn.utils import shuffle
import random
from tqdm import tqdm_notebook as tqdm
import pickle
import matplotlib.pyplot as plt
import logging
import numpy as np
Liest den vorverarbeiteten und getrennten Text der Nachrichten über das abgekratzte Koronavirus. Vorverarbeitung ist keine große Sache.
Die Nachrichten über das Corona-Virus der letzten Woche wurden auf Yahoo News gesammelt, also habe ich sie von dort erhalten. Ich habe es abgekratzt, ohne zu bemerken, dass es eine Woche lang war, also war die Datenmenge, die ich tatsächlich bekam, zu klein und es war durcheinander. Ich bin zu besorgt, wenn ich damit gut lernen kann, aber ich werde es versuchen. ..
data_news = pickle.load(open("Ziel/corona_wakati.pickle", "rb"))
Die verwendeten Daten sind wie folgt
data_news[0]
['geduldig', 'Ya', 'Mitarbeiter des Gesundheitswesens', 'La', 'Aber', 'Neues Coronavirus', 'Zu', 'Infektion', 'Shi', 'Ta', 'Ding', 'Aber', 'Aufgedeckt', 'Shi', 'Ta', "Ikuno-ku, Stadt Osaka", 'von', '「', 'Nami', 'Ha', 'Ya', 'Rehabilitation', 'Krankenhaus', '」', 'Über', '、', 'Präfektur Osaka', 'Ha', '0', 'Tag', 'Nacht', '、', 'des Weiteren', '0', 'Mann', 'von', 'Infektion', 'Aber', 'klar', 'Zu', 'Jetzt', 'Ta', 'Wann', 'Ankündigung', 'Shi', 'Ta', '。']
Da das Wort selbst vom neuronalen Netz nicht verarbeitet werden kann, wird es auf id gesetzt. Da es notwendig ist, von id zu word zurückzukehren, wenn tatsächlich ein Satz erzeugt wird, werden wir auch einen Decoder implementieren.
Ich wollte eine Allzweckklasse definieren, also habe ich versucht, Symbole am Anfang und Ende des Satzes einzufügen, aber dieses Mal steht immer ein Satzzeichen am Ende des Satzes, daher ist dies nicht erforderlich.
class EncoderDecoder(object):
def __init__(self):
# word_to_ID-Wörterbuch
self.w2i = {}
# id_to_Wortwörterbuch
self.i2w = {}
#Reserviertes Wort(Polsterung,Der Anfang des Satzes)
self.special_chars = ['<pad>', '<s>', '</s>', '<unk>']
self.bos_char = self.special_chars[1]
self.eos_char = self.special_chars[2]
self.oov_char = self.special_chars[3]
#Aufzurufende Funktion
def __call__(self, sentence):
return self.transform(sentence)
#Erstellen Sie ein Wörterbuch
def fit(self, sentences):
self._words = set()
#Erstellen Sie eine Reihe unbekannter Wörter
for sentence in sentences:
self._words.update(sentence)
#Verschieben Sie das reservierte Wort und schütteln Sie die ID
self.w2i = {w: (i + len(self.special_chars))
for i, w in enumerate(self._words)}
#Fügen Sie dem Wörterbuch reservierte Wörter hinzu(<pad>:0, <s>:1, </s>:2, <unk>:3)
for i, w in enumerate(self.special_chars):
self.w2i[w] = i
# word_to_ID mit dem ID-Wörterbuch_to_Erstellen Sie ein Wörterbuch mit Wörtern
self.i2w = {i: w for w, i in self.w2i.items()}
#Konvertieren Sie die gelesenen Daten sofort in id
def transform(self, sentences, bos=False, eos=False):
output = []
#Fügen Sie gegebenenfalls Start- und Endsymbole hinzu
for sentence in sentences:
if bos:
sentence = [self.bos_char] + sentence
if eos:
sentence = sentence + [self.eos_char]
output.append(self.encode(sentence))
return output
#Machen Sie einen Satz nach dem anderen
def encode(self, sentence):
output = []
for w in sentence:
if w not in self.w2i:
idx = self.w2i[self.oov_char]
else:
idx = self.w2i[w]
output.append(idx)
return output
#Satz für Satz in Wortliste umwandeln
def decode(self, sentence):
return [self.i2w[id] for id in sentence]
Verwenden Sie die definierte Klasse wie folgt
en_de = EncoderDecoder()
en_de.fit(data_news)
data_news_id = en_de(data_news)
data_news_id[0]
[7142,
5775,
3686,
4630,
5891,
4003,
358,
3853,
4139,
4604,
4591,
5891,
2233,
4139,
4604,
5507,
7378,
2222,
6002,
3277,
5775,
7380,
7234,
5941,
5788,
2982,
4901,
3277,
6063,
5812,
4647,
2982,
1637,
6063,
6125,
7378,
3853,
5891,
1071,
358,
7273,
4604,
5835,
1328,
4139,
4604,
1226]
Die Dekodierung kehrt zur ursprünglichen Anweisung zurück
en_de.decode(data_news_id[0])
['geduldig', 'Ya', 'Mitarbeiter des Gesundheitswesens', 'La', 'Aber', 'Neues Coronavirus', 'Zu', 'Infektion', 'Shi', 'Ta', 'Ding', 'Aber', 'Aufgedeckt', 'Shi', 'Ta', "Ikuno-ku, Stadt Osaka", 'von', '「', 'Nami', 'Ha', 'Ya', 'Rehabilitation', 'Krankenhaus', '」', 'Über', '、', 'Präfektur Osaka', 'Ha', '0', 'Tag', 'Nacht', '、', 'des Weiteren', '0', 'Mann', 'von', 'Infektion', 'Aber', 'klar', 'Zu', 'Jetzt', 'Ta', 'Wann', 'Ankündigung', 'Shi', 'Ta', '。']
In dieser Satzgenerierungsaufgabe lernen Sie wie im Bild unten gezeigt. Daher ist das richtige Antwortetikett dasjenige mit einer vom Etikett verschobenen Daten. Dieses Mal werde ich meinen eigenen Pytorch-spezifischen Datensatz erstellen und die Daten und Beschriftungen darin erstellen.
Füllen Sie außerdem die angegebene Länge mit 0 auf, um die Länge der Daten zu vereinheitlichen, und geben Sie sie dann als Long Tensor-Typ zurück.
Übrigens wird hier die pad_sequence von Keras verwendet, aber vorerst wird eine ähnliche für Pytorch vorbereitet. Ich verwende jedoch die Keras One, da die Länge, die gepolstert und angepasst werden soll, für die Pyroch One nicht angegeben werden kann.
class MyDataset(torch.utils.data.Dataset):
def __init__(self, data, max_length=50):
self.data_num = len(data)
#Daten um 1 verschieben
self.x = [d[:-1] for d in data]
self.y = [d[1:] for d in data]
#Länge zum Auffüllen und Anpassen
self.max_length = max_length
def __len__(self):
return self.data_num
def __getitem__(self, idx):
out_data = self.x[idx]
out_label = self.y[idx]
#Pad passend zur Länge
out_data = pad_sequences([out_data], padding='post', maxlen=self.max_length)[0]
out_label = pad_sequences([out_label], padding='post', maxlen=self.max_length)[0]
#In LongTensor-Typ konvertieren
out_data = torch.LongTensor(out_data)
out_label = torch.LongTensor(out_label)
return out_data, out_label
dataset = MyDataset(data_news_id, max_length=50)
dataset[0]
(tensor([7142, 5775, 3686, 4630, 5891, 4003, 358, 3853, 4139, 4604, 4591, 5891,
2233, 4139, 4604, 5507, 7378, 2222, 6002, 3277, 5775, 7380, 7234, 5941,
5788, 2982, 4901, 3277, 6063, 5812, 4647, 2982, 1637, 6063, 6125, 7378,
3853, 5891, 1071, 358, 7273, 4604, 5835, 1328, 4139, 4604, 0, 0,
0, 0]),
tensor([5775, 3686, 4630, 5891, 4003, 358, 3853, 4139, 4604, 4591, 5891, 2233,
4139, 4604, 5507, 7378, 2222, 6002, 3277, 5775, 7380, 7234, 5941, 5788,
2982, 4901, 3277, 6063, 5812, 4647, 2982, 1637, 6063, 6125, 7378, 3853,
5891, 1071, 358, 7273, 4604, 5835, 1328, 4139, 4604, 1226, 0, 0,
0, 0]))
Schließlich unterteilt der Data Loader von Pytorch die Daten in Stapel. Wenn die Anzahl der Daten nicht durch die Stapelgröße teilbar ist, unterscheidet sie sich durch die letzte Anzahl der Stapel. Setzen Sie drop_last daher auf True.
data_loader = DataLoader(dataset, batch_size=50, drop_last=True)
Überprüfen Sie nur die erste Charge
for (x, y) in data_loader:
print("x_dim: {}, y_dim: {}".format(x.shape, y.shape))
break
x_dim: torch.Size([50, 50]), y_dim: torch.Size([50, 50])
Es ist schwer zu verstehen, da die Stapelgröße und die Anzahl der Daten einer Daten gleich sind. Bei der Datengenerierung beträgt die Dimension der Daten jedoch (Stapelgröße, Anzahl der Zeitreihen (wenn Sätze als Zeitreihendaten von Wörtern betrachtet werden). Obwohl dies der Fall ist (Eingabedimension), ist Pytorch standardmäßig (Zeitreihennummer, Stapelgröße, Eingabedimension), daher muss batch_first = True angegeben werden. Davon abgesehen gibt es nichts Besonderes zu erwähnen.
class RNNLM(nn.Module):
def __init__(self, embedding_dim, hidden_dim, vocab_size, batch_size=100, num_layers=1, device="cuda"):
super().__init__()
self.num_layers = num_layers
self.batch_size = batch_size
self.hidden_dim = hidden_dim
self.device = device
self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=0)
self.dropout1 = nn.Dropout(0.5)
self.lstm1 = nn.LSTM(embedding_dim, hidden_dim, batch_first=True, num_layers=self.num_layers)
self.dropout2 = nn.Dropout(0.5)
self.lstm2 = nn.LSTM(hidden_dim, hidden_dim, batch_first=True, num_layers=self.num_layers)
self.dropout3 = nn.Dropout(0.5)
self.lstm3 = nn.LSTM(hidden_dim, hidden_dim, batch_first=True, num_layers=self.num_layers)
self.linear = nn.Linear(hidden_dim, vocab_size)
nn.init.xavier_normal_(self.lstm1.weight_ih_l0)
nn.init.orthogonal_(self.lstm1.weight_hh_l0)
nn.init.xavier_normal_(self.lstm2.weight_ih_l0)
nn.init.orthogonal_(self.lstm2.weight_hh_l0)
nn.init.xavier_normal_(self.lstm3.weight_ih_l0)
nn.init.orthogonal_(self.lstm3.weight_hh_l0)
nn.init.xavier_normal_(self.linear.weight)
def init_hidden(self):
self.hidden_state = (torch.zeros(self.num_layers, self.batch_size, self.hidden_dim, device=self.device), torch.zeros(self.num_layers, self.batch_size, self.hidden_dim, device=self.device))
def forward(self, x):
x = self.embedding(x)
x = self.dropout1(x)
h, self.hidden_state = self.lstm1(x, self.hidden_state)
h = self.dropout2(h)
h, self.hidden_state = self.lstm2(h, self.hidden_state)
h = self.dropout3(h)
h, self.hidden_state = self.lstm3(h, self.hidden_state)
y = self.linear(h)
return y
Die Parameter sind durchaus angemessen. Es tut uns leid. ..
Da die Anzahl der Daten gering ist, habe ich die Anzahl der Epochen erhöht und sie stark verändert, um sie häufig zu speichern.
Bei anderen Deep-Learning-Aufgaben kann möglicherweise bewertet werden, ob das Überlernen nicht anhand von Bewertungsdaten erfolgt, oder das Lernen auf dieser Grundlage vorzeitig beendet werden, jedoch mit einer Wahrscheinlichkeit wie dieser. Die Aufgabe der Ausgabe der Verteilung ist schwer quantitativ zu bewerten. Dieses Mal bewerten wir den Lernfortschritt und das Modell anhand eines Index namens Ratlosigkeit. Ratlosigkeit ist etwas kompliziert, wenn sie in einer mathematischen Formel ausgedrückt wird, aber intuitiv ist sie die Umkehrung der Ausgabewahrscheinlichkeit und repräsentiert die Anzahl der Zweige. Mit anderen Worten, im Fall der Aufgabe, das nächste Wort wie dieses Mal vorherzusagen, bedeutet dies, wenn die Ratlosigkeit 2 ist, dass die Wortvorhersage auf 2 Auswahlmöglichkeiten eingegrenzt wird.
if __name__ == '__main__':
np.random.seed(123)
torch.manual_seed(123)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
EMBEDDING_DIM = HIDDEN_DIM = 256
VOCAB_SIZE = len(en_de.i2w)
BATCH_SIZE=50
model = RNNLM(EMBEDDING_DIM, HIDDEN_DIM, VOCAB_SIZE, batch_size=BATCH_SIZE).to(device)
criterion = nn.CrossEntropyLoss(reduction='mean', ignore_index=0)
optimizer = optimizers.Adam(model.parameters(),
lr=0.001,
betas=(0.9, 0.999), amsgrad=True)
hist = {'train_loss': [], 'ppl':[]}
epochs = 1000
def compute_loss(label, pred):
return criterion(pred, label)
def train_step(x, t):
model.train()
model.init_hidden()
preds = model(x)
loss = compute_loss(t.view(-1),
preds.view(-1, preds.size(-1)))
optimizer.zero_grad()
loss.backward()
optimizer.step()
return loss, preds
for epoch in tqdm(range(epochs)):
print('-' * 20)
print('epoch: {}'.format(epoch+1))
train_loss = 0.
loss_count = 0
for (x, t) in data_loader:
x, t = x.to(device), t.to(device)
loss, _ = train_step(x, t)
train_loss += loss.item()
loss_count += 1
# perplexity
ppl = np.exp(train_loss / loss_count)
train_loss /= len(data_loader)
print('train_loss: {:.3f}, ppl: {:.3f}'.format(
train_loss, ppl
))
hist["train_loss"].append(train_loss)
hist["ppl"].append(ppl)
#Speichern Sie alle 20 Epochen.
if epoch % 20 == 0:
model_name = "Ziel/embedding{}_v{}.pt".format(EMBEDDING_DIM, epoch)
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': train_loss
}, model_name)
logging.info("Saving the checkpoint...")
torch.save(model.state_dict(), "Ziel/embedding{}_v{}.model".format(EMBEDDING_DIM, epoch))
--------------------
epoch: 1
train_loss: 6.726, ppl: 833.451
--------------------
epoch: 2
train_loss: 6.073, ppl: 433.903
--------------------
epoch: 3
train_loss: 6.014, ppl: 409.209
--------------------
epoch: 4
train_loss: 5.904, ppl: 366.649
--------------------
epoch: 5
train_loss: 5.704, ppl: 300.046
・ ・ epoch: 995 train_loss: 0.078, ppl: 1.081 -------------------- epoch: 996 train_loss: 0.077, ppl: 1.081 -------------------- epoch: 997 train_loss: 0.076, ppl: 1.079 -------------------- epoch: 998 train_loss: 0.077, ppl: 1.080 -------------------- epoch: 999 train_loss: 0.077, ppl: 1.080 -------------------- epoch: 1000 train_loss: 0.077, ppl: 1.080
Lassen Sie uns den Übergang von train_loss und Ratlosigkeit sehen
#Fehlervisualisierung
train_loss = hist['train_loss']
fig = plt.figure(figsize=(10, 5))
plt.plot(range(len(train_loss)), train_loss,
linewidth=1,
label='train_loss')
plt.xlabel('epochs')
plt.ylabel('train_loss')
plt.legend()
plt.savefig('output.jpg')
plt.show()
ppl = hist['ppl']
fig = plt.figure(figsize=(10, 5))
plt.plot(range(len(ppl)), ppl,
linewidth=1,
label='perplexity')
plt.xlabel('epochs')
plt.ylabel('perplexity')
plt.legend()
plt.show()
train_loss sinkt stetig. Die Ratlosigkeit nahm in den frühen Stadien stark ab und blieb in der zweiten Hälfte niedrig und erreichte schließlich einen relativ niedrigen Wert von 1,08. Die zweite Hälfte hat sich nicht viel geändert, so dass ich möglicherweise nicht 1000 Mal lernen musste.
Als nächstes generieren wir tatsächlich einen Satz. Entscheide dich für ein Startwort und lass es das Wort erraten, das darauf folgt. Indem der Auswahl im Teil np.random.choice die Wahrscheinlichkeitsausgabe als Gewichtung zugewiesen wird, ändert sich das ausgewählte Wort bei jeder Ausführung.
def generate_sentence(morphemes, model_path, embedding_dim, hidden_dim, vocab_size, batch_size=1):
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = RNNLM(embedding_dim, hidden_dim, vocab_size, batch_size).to(device)
checkpoint = torch.load(model_path)
model.load_state_dict(checkpoint)
model.eval()
with torch.no_grad():
for morpheme in morphemes:
model.init_hidden()
sentence = [morpheme]
for _ in range(50):
input_index = en_de.encode([morpheme])
input_tensor = torch.tensor([input_index], device=device)
outputs = model(input_tensor)
probs = F.softmax(torch.squeeze(outputs))
p = probs.cpu().detach().numpy()
morpheme = en_de.i2w[np.random.choice(len(p), p=p)]
sentence.append(morpheme)
if morpheme in ["。", "<pad>"]:
break
print("".join(sentence))
print('-' * 50)
EMBEDDING_DIM = HIDDEN_DIM = 256
VOCAB_SIZE = len(en_de.i2w)
model_path ="Ziel/embedding{}_v{}.model"
morphemes = ["Premierminister", "Gouverneur von Tokio", "Corona", "Neues ModellCoronaウイルス", "Neues Modell", "Japan", "Tokio", "Infizierte Person", "Notfall"]
generate_sentence(morphemes, model_path, EMBEDDING_DIM, HIDDEN_DIM, VOCAB_SIZE)
Die sprintende Stimme des Premierministers ist zu viel, um das Jahr anzukurbeln! “Es gibt keine mittlere Hitze und keine wichtige und gemeinsame Vorsicht. Nützliche Beziehung und Präventionsanforderung beschleunigen Kanto-Teilnahmewirtschaft Toshiko Ungewöhnliche Informationen, die nicht bezahlt und von einem geschlossenen Geschäft aus gestartet wurden Sagen Sie dem Arzt, dass der Generalsekretär abwesend ist
--------------------------------------------------
Der Gouverneur von Tokio bat ebenfalls darum, aber obwohl es kein Bett gab, dachte ich, dass der Laden beurteilt wurde. Was sollte ich von der neuen Coronavirus-Infektion beeilen? Diese Anzahl Entschuldigungsübungen sind zumindest verboten. Angst nach Cremona-Fieber
--------------------------------------------------
Corona Benefits Psychology Die Regierung verfügt nicht über das Ausmaß und die erforderlichen Ressourcen im ganzen Land, und es scheint, als würde sie dies vermeiden, während sie es erzählt. Von der neuen Coronavirus-Infektion
--------------------------------------------------
Ein neuer Sachbearbeiter des Corona-Virus-Fonds berichtete ebenfalls und entschuldigte sich für die Hitze und Reaktion aus dem vergangenen Tokio.
--------------------------------------------------
Es gibt keinen Ankündigungsladen, der als neues Modell ausgewiesen wurde, und mehr als Anwohner (erklären ...). "Ich sage Ihnen, dass es abnehmen wird, und ich erwarte eine Zunahme von Yuriko Naka. Warum fordert die Regierung einen strengen Straßenübergang, der zumindest den US-Präsidenten fordert?
--------------------------------------------------
Das Land direkt neben Japan fordert ein Streichholz. Desinfizieren von T-Shirts. Sagen, wann es weitergehen soll. Johnnys Büro Vergangene Schwerter Vergangene Krankenhauseinweisung Gemeinsames Gefühl, dass dieser medizinische Zusammenbruch das Gefühl verringert hat.
--------------------------------------------------
Von Tokio oder höher, von 0 Yen bis 0 Hin- und Rückfahrten pro Bewertung der Epidemie Um Mitternacht gibt es keine Aussicht.
--------------------------------------------------
0 medizinische Hin- und Rückflugeinrichtungen von infizierten Personen usw. LINE Tokyo Übergangserklärung verringern Eine kleine Praxis für Kunden Ungefähr 0 medizinische Einrichtungen Im vergangenen Bericht um Mitternacht bestätigt Tele-East ist eine wunderbare Infektion Speed Trump-Verwaltung ist nicht verfügbar Komei Party Geschäfte zu reduzieren oder Ausländer ... "Mit der neuen Coronavirus-Infektion
--------------------------------------------------
Bestätigen Sie Notsituationen für Neuankömmlinge. Bewältigung und geschätzte Geschwindigkeit (Vielen Dank, dass Sie die Anzahl der Personen reduziert haben, die Präfekturen desinfizieren. Ausgegebener Führer Frühere Ausgabe
--------------------------------------------------
Ich habe keinen sinnvollen Satz gemacht, aber anscheinend habe ich ein wenig über die Position der Teiltexte gelernt.
Die Satzerstellung war schwierig. Ich möchte weiter lernen und mich verbessern
Wenn Sie Ratschläge oder Vorschläge haben, würde ich mich freuen, wenn Sie einen Kommentar abgeben könnten ..!
Recommended Posts