[PYTHON] Ich brachte AI dazu, über die Texte von Genshi Yonezu nachzudenken (Vorverarbeitung)

Einführung

Genshi Yonezu verkauft jedes Mal, wenn er komponiert. Die Texte, die herausgesponnen werden, scheinen die Kraft zu haben, Menschen zu faszinieren. Dieses Mal beschloss ich, tiefes Lernen seinen Charme lernen zu lassen.


Dieser Artikel befasst sich mit "Datenvorverarbeitung". Hier sind die allgemeinen Schritte:

  1. Alle Texte von Mr. Yonezu kratzen und bekommen
  2. Formatieren Sie die Daten so, dass sie mit den Einstellungen für Deep Learning-Probleme übereinstimmen
  3. Teilen Sie 8: 2 in Trainingsdaten und Testdaten auf.

Im Allgemeinen bezieht sich "Vorverarbeitung" auf Datenverarbeitung zur Verbesserung der Genauigkeit, wie z. B. Normalisierung, aber diese "Vorverarbeitung" bedeutet Formung, so dass sie eine Eingabe oder Ausgabe von tiefem Lernen wird. ..


Modell verwendet

Rahmen: Pytorch Modell: seq2seq mit Aufmerksamkeit


seq2seq und Achtung Hintergrund

Dies ist eine der Methoden für die "maschinelle Übersetzung". Das Folgende ist ein Bild von seq2seq. seq2seq.png

Zitierter Artikel: [Encoder-Decoder-Modell und Teacher Forcing, Scheduled Sampling, Professor Forcing](https://satopirka.com/2018/02/encoder-decoder%E3%83%A2%E3%83%87%E3%83] % AB% E3% 81% A8Lehrer-forcieren geplant-Sampling-Professor-Forcen /)


Dies ermöglicht es dem Decoder, Sätze basierend auf den auf der Encoderseite codierten Informationen zu generieren, aber es gibt tatsächlich einige Probleme. Das heißt, der Decodereingang kann nur durch einen Vektor fester Länge dargestellt werden. Die Ausgabe von Encoder ist versteckte Ebene $ h $, aber diese Größe ist fest. Daher kann ein Datensatz mit einer zu langen Länge der Eingabeserie die Informationen nicht ordnungsgemäß in $ h $ komprimieren, und ein Datensatz mit einer zu kurzen Länge der Eingabeserie enthält verschwenderische Informationen in $ h $. Ich werde. Daher möchten Sie ** nicht nur den Status der letzten verborgenen Ebene des Encoders verwenden, sondern auch den Status der verborgenen Ebene in der Mitte **.

Dies ist der Hintergrund hinter dem Erfinder von Attention.


Aufmerksamkeitsmechanismus

Aufmerksamkeit ist eine Methode, um beim Umgang mit Zeitreihendaten auf wichtige Punkte in der Vergangenheit (= Aufmerksamkeit) zu achten. Dieses Mal wird die "nächste Passage" für die "lyrische Passage" eines bestimmten Liedes vorhergesagt. Um die nächste Passage vorherzusagen, worauf sollten wir in der vorherigen Passage achten? Werden. Unten ist ein Bild von Attention.

attention.png

source: Effective Approaches to Attention-based Neural Machine Translation


Dem Referenzpapier zufolge wird es genauer als Global Attention-Modell bezeichnet. Durch Sammeln aller verborgenen Zustände des Codierers als Vektor und Nehmen des inneren Produkts von ihnen und der Ausgabe des Decoders ** "Ähnlichkeit zwischen allen verborgenen Zuständen des Codierers und der Ausgabe des Decodierers" ** kann erhalten werden. Die Messung dieser Ähnlichkeit anhand des internen Produkts ist der Grund, warum es als Aufmerksamkeit bezeichnet wird, die sich "auf wichtige Faktoren konzentriert".


Implementierung

Nach dem Hochladen des erforderlichen selbst erstellten Moduls in Google colab Kopieren Sie die später beschriebene main.py und führen Sie sie aus.

** Erforderliches selbst erstelltes Modul ** スクリーンショット 2020-05-09 18.28.25.png


Problemstellung

Wie unten gezeigt, sagt Genji Yonezu die "nächste Passage" aus der "einen Passage" der bisher veröffentlichten Songs voraus.

|Eingabetext|Text ausgeben| |-------+-------| |Ich freue mich sehr, dich zu sehen| _Alle sind selbstverständlich traurig| |Alle sind selbstverständlich traurig| _Ich habe jetzt schmerzlich glückliche Erinnerungen| |Ich habe jetzt schmerzlich glückliche Erinnerungen| _Erhebe dich und gehe zum Abschied, der eines Tages kommen wird| |Erhebe dich und gehe zum Abschied, der eines Tages kommen wird| _Es reicht aus, jemanden einzunehmen und zu leben|

Dies wurde durch Scraping von Lyrics Net erstellt.


Datenaufbereitung

Schaben

Holen Sie sich die Texte, indem Sie mit dem folgenden Code kratzen Diese werden von Google Colab ausgeführt.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.select import Select
import requests
from bs4 import BeautifulSoup
import re
import time

 setting
# Chrome-Option zum Starten von Selen in jeder Umgebung
options = Options()
options.add_argument('--disable-gpu');
options.add_argument('--disable-extensions');
options.add_argument('--proxy-server="direct://"');
options.add_argument('--proxy-bypass-list=*');
options.add_argument('--start-maximized');
options.add_argument('--headless');

class DriverConrol():
    def __init__(self, driver):
        self.driver = driver
        
    def get(self, url):
        self.driver.get(url)
        
    def get_text(self, selector):
        element = self.driver.find_element_by_css_selector(selector)
        return element.text
        
    def get_text_by_attribute(self, selector, attribute='value'):
        element = self.driver.find_element_by_css_selector(selector)
        return element.get_attribute(attribute)
    
    def input_text(self, selector, text):
        element = self.driver.find_element_by_css_selector(selector)
        element.clear()
        element.send_keys(text)
        
    def select_option(self, selector, text):
        element = driver.find_element_by_css_selector(selector)
        Select(element).select_by_visible_text(text)
        
    def click(self, selector):
        element = self.driver.find_element_by_css_selector(selector)
        element.click()
        
    def get_lyric(self, url):
        self.get(url)
        time.sleep(2)
        element = self.driver.find_element_by_css_selector('#kashi_area')
        lyric = element.text
        return lyric
    
    def get_url(self):
        return self.driver.current_url
        
    def quit(self):
        self.driver.quit()

BASE_URL = 'https://www.uta-net.com/'
 search_word = 'Genshi Yonezu'
 search_jenre = 'Name des Schriftstellers'
driver = webdriver.Chrome(chrome_options=options)
dc = DriverConrol(driver)
 dc.get (BASE_URL) #access

# Suche
dc.input_text('#search_form > div:nth-child(1) > input.search_input', search_word)
dc.select_option('#search_form > div:nth-child(2) > select', search_jenre)
dc.click('#search_form > div:nth-child(1) > input.search_submit')
time.sleep(2)

# Holen Sie sich sofort eine URL mit Anfragen
response = requests.get(dc.get_url())
 response.encoding = response.apparent_encoding # Anti-verstümmelte Zeichen
soup = BeautifulSoup(response.text, "html.parser")
 side_td1s =oup.find_all (class _ = "side td1") # Ruft alle td-Elemente mit der Klassenseite td1 ab
 lyric_urls = [side_td1.find ('a', href = re.compile ('song')). get ('href') für side_td1 in side_td1s] # side_td1s enthält, href enthält 'song ein Tag Holen Sie sich das href-Element von
 music_names = [side_td1.find ('a', href = re.compile ('song')). text für side_td1 in side_td1s] # Alle Songtitel abrufen

# Holen Sie sich die Texte und fügen Sie sie zu lyric_lis hinzu
lyric_lis = list()
for lyric_url in lyric_urls:
    lyric_lis.append(dc.get_lyric(BASE_URL + lyric_url))
with open(search_word + '_lyrics.txt', 'wt') as f_lyric, open(search_word + '_musics.txt', 'wt') as f_music:
    for lyric, music in zip(lyric_lis, music_names):
        f_lyric.write(lyric + '\n\n')
        f_music.write(music + '\n')

** Auszug aus den erworbenen Texten **

 Ich freue mich sehr, dich zu sehen
 Alle sind selbstverständlich traurig
 Ich habe jetzt schmerzlich glückliche Erinnerungen
 Erhebe dich und gehe zum Abschied, der eines Tages kommen wird

 Es reicht aus, jemanden einzunehmen und zu leben
 Ich wünschte, ich könnte ein Stein sein
 Wenn ja, gibt es kein Missverständnis oder Verwirrung
 Auf diese Weise, ohne dich zu kennen

...

Datenformung

Gegenwärtig ist es weit von den in [Problemeinstellung] gezeigten Daten entfernt, daher wird "Daten formatieren" durchgeführt.

Das heißt, es macht das.

スクリーンショット 2020-05-09 19.01.02.png

Formatieren Sie die Daten mit dem folgenden Code Der Code ist verwirrend, aber die Vorverarbeitung ist jetzt abgeschlossen.

from datasets import LyricDataset
import torch
import torch.optim as optim
from modules import *
from device import device
from utils import *
from dataloaders import SeqDataLoader
import math
import os
from utils

 ==========================================
# Datenaufbereitung
 ==========================================
# Pfad Genshi Yonezu_lyrics.txt
 file_path = "lyric / Genshi Yonezu_lyrics.txt"
 editierter_Dateipfad = "lyric / Genshi Yonezu_lyrics_edit.txt"

yonedu_dataset = LyricDataset(file_path, edited_file_path)
yonedu_dataset.prepare()
 check
print(yonedu_dataset[0])

# In Zug teilen und um 8: 2 testen
train_rate = 0.8
data_num = len(yonedu_dataset)
train_set = yonedu_dataset[:math.floor(data_num * train_rate)]
test_set = yonedu_dataset[math.floor(data_num * train_rate):]

from sklearn.model_selection import train_test_split
from janome.tokenizer import Tokenizer
import torch
from utils import *

class LyricDataset(torch.utils.data.Dataset):
    def __init__(self, file_path, edited_file_path, transform=None):
        self.file_path = file_path
        self.edited_file_path = edited_file_path
        self.tokenizer = Tokenizer(wakati=True)

 self.input_lines = [] # NN Eingabearray (jedes Element ist Text)
 self.output_lines = [] # NNs korrektes Datenarray (jedes Element ist Text)
        self.word2id = {}  # e.g.) {'word0': 0, 'word1': 1, ...}

 self.input_data = [] # Eine Textpassage, in der jedes Wort ID ist
 self.output_data = [] # Die nächste Passage, in der jedes Wort ID ist

        self.word_num_max = None
        self.transform = transform

        self._no_brank()

    def prepare(self):
 # Gibt ein Array (Text) zurück, das die Eingabe von NN ist, und ein Array, das die richtigen Antwortdaten (Text) von NN enthält.
        self.get_text_lines()

 Weisen Sie jedem Zeichen, das in # date.txt angezeigt wird, eine ID zu
 für Zeile in self.input_lines + self.output_lines: # Erste Passage und nachfolgende Passagen
            self.get_word2id(line)

 # Finden Sie die maximale Anzahl von Wörtern in einer Passage
        self.get_word_num_max()
 # Gibt das Eingabearray (ID) von NN und das Array der korrekten Antwortdaten (ID) von NN zurück
        for input_line, output_line in zip(self.input_lines, self.output_lines):
            self.input_data.append([self.word2id[word] for word in self.line2words(input_line)] \
            + [self.word2id[" "] for _ in range(self.word_num_max - len(self.line2words(input_line)))])
            self.output_data.append([self.word2id[word] for word in self.line2words(output_line)] \
            + [self.word2id[" "] for _ in range(self.word_num_max - len(self.line2words(output_line)))])

    def _no_brank(self):
 # Nehmen Sie ein Leerzeichen zwischen den Zeilen
        with open(self.file_path, "r") as fr, open(self.edited_file_path, "w") as fw:
            for line in fr.readlines():
                if isAlpha(line) or line == "\n":
 weiter # Buchstaben und Leerzeichen überspringen
                fw.write(line)

    def get_text_lines(self, to_file=True):
        """
 Nimmt den Pfad file_path der Lyrics-Datei ohne Leerzeilen und gibt ein Array zurück, das dem folgenden ähnlich ist
        """
 # Yonezu Genshi_lyrics.txt wird zeilenweise gelesen, in "eine Textpassage" und "nächste Passage" unterteilt und durch Eingabe und Ausgabe getrennt.
        with open(self.edited_file_path, "r") as f:
 line_list = f.readlines () #Lyrics Passage ... line
            line_num = len(line_list)
            for i, line in enumerate(line_list):
                if i == line_num - 1:
 weiter # Am Ende gibt es keine "nächste Passage"
                self.input_lines.append(line.replace("\n", ""))
                self.output_lines.append("_" + line_list[i+1].replace("\n", ""))

        if to_file:
            with open(self.edited_file_path, "w") as f:
                for input_line, output_line in zip(self.input_lines, self.output_lines):
                    f.write(input_line + " " + output_line + "\n")


    def line2words(self, line: str) -> list:
        word_list = [token for token in self.tokenizer.tokenize(line)]
        return word_list

    def get_word2id(self, line: str) -> dict:
        word_list = self.line2words(line)
        for word in word_list:
            if not word in self.word2id.keys():
                 self.word2id[word] = len(self.word2id)

    def get_word_num_max(self):
 #Suchen Sie am längsten
        word_num_list = []
        for line in self.input_lines + self.output_lines:
            word_num_list.append(len([self.word2id[word] for word in self.line2words(line)]))
        self.word_num_max = max(word_num_list)

    def __len__(self):
        return len(self.input_data)

    def __getitem__(self, idx):
        out_data = self.input_data[idx]
        out_label = self.output_data[idx]

        if self.transform:
            out_data = self.transform(out_data)

        return out_data, out_label

Diesmal bis zur Vorverarbeitung

Der Code scheint länger zu sein als ich erwartet hatte, daher werde ich ihn diesmal auf "Datenvorverarbeitung" beschränken.

Recommended Posts

Ich brachte AI dazu, über die Texte von Genshi Yonezu nachzudenken (Vorverarbeitung)
Ich brachte AI dazu, über die Texte von Genshi Yonezu nachzudenken (Implementierung)
Die Python-Projektvorlage, an die ich denke.
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Denken Sie an das Rack und WSGI der nächsten Generation
Denken Sie an die Analyseumgebung (Teil 1: Übersicht) * Stand Januar 2017
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
Ich habe ein Punktbild des Bildes von Irasutoya gemacht. (Teil 1)
Ich habe ein Punktbild des Bildes von Irasutoya gemacht. (Teil 2)
Über die Komponenten von Luigi
Über die Funktionen von Python
Ich habe einen schlaffen Bot gemacht, der mich über die Temperatur informiert
[Kaggle] Ich habe mit dem Titanic-Tutorial eine Sammlung von Problemen erstellt
Denken Sie an das Problem der minimalen Änderung
Ich habe den Mechanismus der Flaschenanmeldung untersucht!
Über den Rückgabewert des Histogramms.
Über den Grundtyp von Go
Über die Obergrenze von Threads-max
Über das Verhalten von Yield_per von SqlAlchemy
Über die Größe der Punkte in Matplotlib
Informationen zur Grundlagenliste der Python-Grundlagen
Denken Sie grob über die Verlustfunktion nach
Ich habe einen Kalender erstellt, der den Verteilungsplan von Vtuber automatisch aktualisiert
Ich wollte vorsichtig mit dem Verhalten der Standardargumente von Python sein
Ich möchte meine Gefühle mit den Texten von Mr. Children ausdrücken
Ich habe versucht, die logische Denkweise über Objektorientierung zusammenzufassen.
Ich habe GAN mit Keras gemacht, also habe ich ein Video des Lernprozesses gemacht.
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
Ich habe einen Fehler beim Abrufen der Hierarchie mit MultiIndex von Pandas gemacht
Ich denke, die Grenze des Rucksacks ist nicht das Gewicht, sondern das Volumen w_11 / 22update
Ich habe eine Funktion erstellt, um die Bewegung eines zweidimensionalen Arrays (Python) zu sehen.