Genshi Yonezu vend à chaque fois qu'il compose. Les paroles qui sortent semblent avoir le pouvoir de fasciner les gens. Cette fois, j'ai décidé de laisser l'apprentissage profond apprendre son charme.
Cet article concerne le "Prétraitement des données". Voici les étapes générales:
Généralement, le «prétraitement» fait référence au traitement des données pour améliorer la précision comme la normalisation, mais ce «prétraitement» signifie la mise en forme de sorte qu'il devienne une entrée ou une sortie de l'apprentissage en profondeur. ..
Cadre: Pytorch Modèle: seq2seq avec attention
C'est l'une des méthodes utilisées pour la "traduction automatique". Ce qui suit est une image de seq2seq.
Article cité: [Encoder-decoder model and Teacher Forcing, Scheduled Sampling, Professor Forcing](https://satopirka.com/2018/02/encoder-decoder%E3%83%A2%E3%83%87%E3%83] % AB% E3% 81% A8professeur-forçageprofesseur-forçage-d'échantillonnage programmé
Cela permet à Decoder de générer des phrases basées sur les informations codées du côté de l'encodeur, mais il y a en fait quelques problèmes. Autrement dit, l'entrée Decoder ne peut être représentée que par un vecteur de longueur fixe. La sortie de Encoder est la couche cachée $ h $, mais cette taille est fixe. Par conséquent, un ensemble de données avec une longueur de série d'entrée trop longue ne pourra pas compresser correctement les informations en $ h $, et un ensemble de données avec une longueur de série d'entrée trop courte incorporera des informations inutiles dans $ h $. Je vais. Par conséquent, vous voudrez utiliser ** non seulement l'état de la dernière couche cachée de l'encodeur, mais également l'état de la couche cachée au milieu **.
C'est le fond de l'inventeur d'Attention.
L'attention est une méthode pour prêter attention aux points importants du passé (= Attention) lors du traitement des données de séries chronologiques. Cette fois, le "prochain passage" est prédit pour le "passage lyrique" d'une certaine chanson, donc afin de prédire le passage suivant, à quoi devons-nous prêter attention dans le passage précédent? Devenir. Ci-dessous, une image de Attention.
source: Effective Approaches to Attention-based Neural Machine Translation
Selon le document de référence, il est plus précisément appelé le modèle de l'attention globale. En collectant tous les états cachés de l'encodeur en tant que vecteur et en prenant le produit interne de ceux-ci et la sortie du décodeur, ** "La similitude entre tous les états cachés de l'encodeur et la sortie du décodeur" ** peut être obtenue. La mesure de cette similitude par produit interne est la raison pour laquelle on l'appelle Attention qui "se concentre sur des facteurs importants".
Après avoir téléchargé le module personnalisé requis sur Google colab Copiez et exécutez main.py décrit plus loin.
** Module personnalisé requis **
Comme indiqué ci-dessous, Genji Yonezu prédit le "prochain passage" du "passage unique" des chansons qui ont été publiées jusqu'à présent.
|Texte de saisie|Texte de sortie| |-------+-------| |Je suis vraiment content de te voir| _Tous sont tristes bien sûr| |Tous sont tristes bien sûr| _J'ai des souvenirs douloureusement heureux maintenant| |J'ai des souvenirs douloureusement heureux maintenant| _Levez et faites les adieux qui viendront un jour| |Levez et faites les adieux qui viendront un jour| _Il suffit de prendre la place de quelqu'un et de vivre|
Ceci a été créé en grattant sur Lyrics Net.
Obtenez les paroles en grattant avec le code ci-dessous Ceux-ci sont exécutés par Google Colab.
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
# Option Chrome pour lancer Selenium dans n'importe quel environnement
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 = 'nom de l'auteur'
driver = webdriver.Chrome(chrome_options=options)
dc = DriverConrol(driver)
dc.get (BASE_URL) #access
# Chercher
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)
# Obtenez l'URL à la fois avec les demandes
response = requests.get(dc.get_url())
response.encoding = response.apparent_encoding # Caractères anti-déformés
soup = BeautifulSoup(response.text, "html.parser")
side_td1s = soup.find_all (class _ = "side td1") # Récupère tous les éléments td avec le côté classe td1
lyric_urls = [side_td1.find ('a', href = re.compile ('song')). get ('href') pour side_td1 dans side_td1s] # side_td1s contient, href contient une balise Obtenez l'élément href de
music_names = [side_td1.find ('a', href = re.compile ('song')). text for side_td1 in side_td1s] # Récupère tous les titres de chansons
# Obtenez les paroles et ajoutez-les à lyric_lis
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')
** Extrait des paroles acquises **
Je suis vraiment content de te voir
Tous sont tristes bien sûr
J'ai des souvenirs douloureusement heureux maintenant
Levez et faites les adieux qui viendront un jour
Il suffit de prendre la place de quelqu'un et de vivre
J'aimerais pouvoir être une pierre
Si tel est le cas, il n'y a pas de malentendu ni de confusion
De cette façon sans même te connaître
...
À l'heure actuelle, il est loin des données affichées dans [Configuration du problème], donc "formater les données" est effectué.
Autrement dit, il fait cela.
Formatez les données avec le code suivant Le code prête à confusion, mais le prétraitement est maintenant terminé.
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
==========================================
# Préparation des données
==========================================
# Chemin Genshi Yonezu_lyrics.txt
file_path = "paroles / Genshi Yonezu_lyrics.txt"
edit_file_path = "lyrique / Genshi Yonezu_lyrics_edit.txt"
yonedu_dataset = LyricDataset(file_path, edited_file_path)
yonedu_dataset.prepare()
check
print(yonedu_dataset[0])
# Divisez en train et testez à 8: 2
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 input array (chaque élément est du texte)
self.output_lines = [] # tableau de données correct de NN (chaque élément est du texte)
self.word2id = {} # e.g.) {'word0': 0, 'word1': 1, ...}
self.input_data = [] # Un passage de paroles dans lequel chaque mot est ID
self.output_data = [] # Le prochain passage où chaque mot est ID
self.word_num_max = None
self.transform = transform
self._no_brank()
def prepare(self):
# Renvoie un tableau (texte) qui est l'entrée de NN et un tableau qui est les données de réponse correctes (texte) de NN.
self.get_text_lines()
Attribuez un identifiant à chaque caractère qui apparaît dans # date.txt
pour la ligne dans self.input_lines + self.output_lines: # Premier passage et passages suivants
self.get_word2id(line)
# Trouver le nombre maximum de mots dans un passage
self.get_word_num_max()
# Renvoie un tableau (ID) qui est l'entrée de NN et un tableau qui est la donnée de réponse correcte (ID) de NN.
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):
# Prenez un espace entre les lignes
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":
continue # Ignorer les lettres et les espaces
fw.write(line)
def get_text_lines(self, to_file=True):
"""
Prend le chemin file_path du fichier de paroles sans lignes vides et renvoie un tableau similaire au suivant
"""
# Yonezu Genshi_lyrics.txt est lu ligne par ligne, divisé en "un passage de paroles" et "prochain passage", et séparé par entrée et sortie.
with open(self.edited_file_path, "r") as f:
line_list = f.readlines () #Lyrics passage ... ligne
line_num = len(line_list)
for i, line in enumerate(line_list):
if i == line_num - 1:
continue # Il n'y a pas de "prochain passage" à la fin
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):
# À la recherche du plus long
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
Le code semble être plus long que prévu, donc cette fois je vais le limiter au "prétraitement des données".
Recommended Posts