mirror of
https://github.com/WallyS02/Song-Lyrics-Generator.git
synced 2024-10-03 11:26:10 +00:00
192 lines
12 KiB
TeX
192 lines
12 KiB
TeX
\documentclass{article}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[polish]{babel}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage{graphicx}
|
|
\graphicspath{{images/}}
|
|
\usepackage{blindtext}
|
|
\usepackage{hyperref}
|
|
\usepackage{placeins}
|
|
\usepackage{caption}
|
|
\usepackage{subcaption}
|
|
|
|
\title{Generacja tekstów piosenek}
|
|
\author{Maciej Krzyżanowski, Sebastian Kutny, Tomasz Lewandowski}
|
|
\date{Kwiecień 2023}
|
|
|
|
\begin{document}
|
|
|
|
\maketitle
|
|
|
|
\tableofcontents
|
|
|
|
\newpage
|
|
\section{Wstęp}
|
|
Celem projektu było stworzenie modelu generującego tekst piosenki na podstawie wybranych danych jako tekstów innych utworów. Wykorzystaliśmy 2 metody: łańcuchy Markova oraz rekurencyjne sieci neuronowe. \\ \\ Projekt zawiera narzędzie "scraper" do pozyskiwania danych ze stron:
|
|
\begin{itemize}
|
|
\item \url{https://www.tekstowo.pl}
|
|
\item \url{https://www.azlyrics.com}
|
|
\end{itemize}
|
|
Implementacja została wykonana w języku Python oraz wykorzystuje biblioteki:
|
|
\begin{itemize}
|
|
\item pandas
|
|
\item BeautifulSoup
|
|
\item nltk
|
|
\item request
|
|
\item queue
|
|
\item re
|
|
\end{itemize}
|
|
Dostępna jest opcja łączenia zbiorów danych do jednego pliku w celu wykorzystania ich jednocześnie. \\ \\
|
|
Przed rozpoczęciem przetwarzania danych są one oczyszczane poprzez ujednolcenie wielkości liter, usunięcie niepotrzebnych znaków interpunkcyjnych, słów zakazanych (np:. określających składowe tekstu utworu) oraz wyrażeń ze szczególnymi znakami interpunkcyjnymi jako określających zawartość tekstu.
|
|
\\ \\
|
|
Tekst jest generowany jako dowolna liczba wersów o dowolnej ilości słow.
|
|
\newpage
|
|
\section{Łańcuchy Markova}
|
|
\subsection{Wstęp}
|
|
Łańcuchy Markova to matematyczny model służący do generowania tekstu lub sekwencji innych elementów, takich jak dźwięki lub obrazy. Ideą modelu jest analiza sekwencji istniejących elementów i wykorzystanie tych informacji do przewidywania, jakie elementy powinny pojawić się następnie. \\
|
|
\\
|
|
W przypadku generowania tekstu, łańcuchy Markova są zwykle stosowane do analizy sekwencji słów w tekście źródłowym i generowania nowych sekwencji słów na podstawie tych informacji. Proces zaczyna się od wyboru deterministycznego lub losowego początkowego stanu łańcucha, a następnie generowania kolejnych stanów na podstawie informacji o pradwopodobieństwie wystąpienia po sobie stanów w analizowanym tekście w kontekście poprzednio wygenerowanych stanów. Przykładowo, jeśli w tekście źródłowym po słowie "generator" często pojawia się słowo "piosenek", to model łańcucha Markova przypisze wysokie prawdopodobieństwo wystąpienia słowa "piosenek" po słowie "generator". \\
|
|
\\
|
|
Istnieją różne sposoby implementacji modelu łańcuchów Markova, ale zwykle opierają się one na analizie pewnej liczby poprzednich elementów, zwanej "stopniem" modelu. Na przykład, w przypadku modelu pierwszego stopnia, prawdopodobieństwo wystąpienia danego elementu zależy tylko od poprzedniego elementu, w modelu drugiego stopnia, prawdopodobieństwo zależy od dwóch poprzednich elementów, a w modelu trzeciego stopnia, prawdopodobieństwo zależy od trzech poprzednich elementów itd. Stopień łańcucha nazywamy N-gramem.\\
|
|
\\
|
|
W naszym projektcie N-gram jest parametryzowany i bazuje na N uprzednio wygenerowanych słowach w wersie, losując następne słowo na podstawie prawdopodobieństwa jego wystąpienia po N sekwencji słów uprzednio wygenerowanych. Dodatkowo przy każdym wersie o nieparzystym numerze podejmowana jest próba stworzenia rymującego się wersu na podstawie ostatniej sylaby poprzedniego. Najpierw znajdowane są wszystkie rymujące się zakończenia wersu niebędące ostatnim słowem poprzedniego, a następnie - jeśli takie istnieją - losujemy jedno z nich zamiast z wszyskich pozycji. Przy nieznalezieniu rymujących się słów generacja odbywa się tak jak w zwykłym wypadku. W praktyce szansa na stworzenie rymu jest mała i powinna rosnąć z ilością danych przetwarzanych przez model.\\
|
|
\\
|
|
Model łańcuchów Markova nie jest idealny i może generować sekwencje, które nie są sensowne lub poprawne gramatycznie. Dopiero przy wglądzie modeli w setki stanów wstecz oraz przy bardzo dużej ilości danych można wygenerować tekst podobny do pisanego przez człowieka. \\
|
|
\\
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.75\textwidth]{chain}
|
|
\caption{Przykład łańcucha Markova, dla zdania "The quick brown fox jumps over the lazy dog and the angry dog chase the quick brown fox.", dla wartości $ngram = 1$, oznaczającej stany jako pojedyncze słowama oraz wartoścami prawdopodobieństw przejść pomiędzy stanami obliczonych na podstawie zdania wejściowego.}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
\subsection{Prawo Zipfa}
|
|
Prawo Zipfa to empiryczna obserwacja dotycząca częstotliwości występowania słów w korpusie tekstów. Mówi ono, że jeśli posortujemy słowa występujące w tekście według częstotliwości ich wystąpień i przyporządkujemy każdemu słowu rangę zgodną z jego pozycją w rankingu, to liczba wystąpień słowa o danej randze jest odwrotnie proporcjonalna do wartości tej rangi. W praktyce oznacza to, że najczęściej występujące słowo będzie występować dwa razy częściej niż drugie na liście, trzy razy częściej niż trzecie, i tak dalej. \\
|
|
\\
|
|
Wykorzystując Prawo Zipfa w generacji tekstów piosenek, można zapewnić, że wygenerowany tekst będzie przypominał rzeczywiste teksty pod względem częstotliwości występowania słów.
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{somemix_zipf1}
|
|
\caption{Wykres 1000 najczęściej pojawiających się słów dla zbioru danych $somemix.csv$.}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{somemix_zipf2}
|
|
\caption{Wykres stałej $constant = ranga * wystapienia$ dla zbioru danych $somemix.csv$}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{generated_zipf1}
|
|
\caption{Wykres 1000 najczęściej pojawiających się słów dla piosenki wygenerowanej na podstawie $somemix.csv$ o 100 wersach po 500 słów.}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{generated_zipf2}
|
|
\caption{Wykres stałej $constant = ranga * wystapienia$ dla piosenki wygenerowanej na podstawie $somemix.csv$ o 100 wersach po 500 słów}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
Podobieństwo wykresów wskazuje na to, że tekst wyjściowy modelu będzie tej samej jakości, przypominając tekst dany na wejściu.
|
|
\subsection{Prawo Heapsa}
|
|
Prawo Heapsa opisuje zależność pomiędzy wielkością dokumentu w jednostce liter, słów, stanów złożonych ze słów w kontekście liczby unikalnych liter, słów, stanów złożonych ze słów pojawiających się w tekście. Na podstawie prawa, stwierdzamy, że liczba unikalnych stanów rośnie wolniej wraz ze zwiększającą się ilością stanów tekstu, co pozwala nam przewidzieć ilość unikalnych w zasobie danych, co pozwala na lepszą ocenę modelu Markova.
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}[b]{0.49\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{heaps1}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.49\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{heaps2}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.49\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{heaps3}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.49\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{heaps4}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.49\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{heaps5}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\caption{Wykres zależności liczby stanów unikalnych od rozmiaru tekstu oraz wartości $ngram$ dla zbiorów danych: $kyuss.csv, led\_zeppelin.csv, Black Sabbath.csv, ac\_dc.csv$.}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
Prawo Heapsa sprawdza się dla danych. Dodatkowo widzimy, że zmiana jest zależna od $ngramu$. Rośnie ona zwykle wolniej dla większych $ngramow$ co może oznaczać częste pojawianie się w tekstach określonych złożeń słów.
|
|
\subsection{Entropia Krzyżowa}
|
|
Entropia Krzyżowa to miara zgodności między dwoma rozkładami prawdopodobieństwa. Pozwala określić jak dobrze model generujący tekst przewiduje następny stan na podstawie poprzednich. W przypadku generowania tekstu, entropia krzyżowa może być wykorzystana do oceny jakości generacji. Im mniejsza wartość entropii krzyżowej, tym większa zgodność między rozkładem prawdopodobieństwa generowanego tekstu a rozkładem prawdopodobieństwa prawdziwych tekstów. Pozwala to ocenić czy model tworzy teksty podobne do tych ze zbioru danych, czy też tworzy nowe i oryginalne sentencje.
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.75\textwidth]{cross-entropy}
|
|
\caption{Wykres wartości entropii krzyżowej dla tekstu generowanego na podstawie zbioru danych $somemix.csv$, zależnie od rozmiaru wygenerowanego tekstu.}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
Jak widać, entropia krzyżowa rośnie niemal liniowo względem długości wygenerowanego tekstu. Oznacza to, że model coraz to bardziej generuje tekst niepodobny do oryginalnego zależnie od długości wygenerowanego tekstu.
|
|
\subsection{Perpleksja}
|
|
Perpleksja to stopień trudności zrozumienia tekstu, miara nieprzewidywalności modelu. Im niższa tym tekst bardziej przypomina oryginalny i jest bardziej kreatywny. Aby policzyć wartość perpleksji tekstu korzystamy ze wzoru: $Perplexity(M) = 2^{H(L,M)}$ gdzie $M$ oznacza model, $L$ oznacza wygenerowany tekst, a $H(L, M)$ wartość entropii krzyżowej.
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.75\textwidth]{perplexity}
|
|
\caption{Wykres wartości perpleksji dla tekstu generowanego na podstawie zbioru danych $somemix.csv$, zależnie od rozmiaru wygenerowanego tekstu.}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\\Jak widać, wykresy eksperymentu dla entropii krzyżowej i perpleksji się nie różnią, ponieważ w gruncie rzeczy znaczą tą samą miarę.
|
|
\subsection{Self-BLEU}
|
|
Self-BLEU określa różnorodność generowanego tekstu. Wykorzystuje wskaźnik \href{https://pl.wikipedia.org/wiki/BLEU}{BLEU} (ang. BiLingual Evaluation Understudy), licząc jego wartość dla kombinacji par wszystkich unikalnych sentencji wygenerowanego tekstu, w tym przypadku wersów piosenki, otrzymując końcowo ich średnią. Im mniejsza wartość wskaźnika tym większa różnorodność w tekście. Metryka pozwala uniknąć monotonności tekstu.
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.75\textwidth]{self-bleu}
|
|
\caption{Wykres wartości Self-BLEU dla tekstu generowanego na podstawie zbioru danych $somemix.csv$, zależnie od rozmiaru wygenerowanego tekstu.}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\\Jak widać, tekst zachowuje wysoką różnorodność, poprzez losowy wybór początku wersu rozkładem równomiernym, a z coraz to większym rozmiarem tekstu napotykamy na podobne frazy, co zmniejsza jego różnorodność, jednak wciąż wynik jest zależny od wygenerowanych tekstów.
|
|
\FloatBarrier
|
|
\subsection{Przykładowe wyniki}
|
|
\newpage
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{english_mixtape}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\begin{subfigure}[b]{0.75\textwidth}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{somemix}
|
|
\label{fig:mesh1}
|
|
\end{subfigure}
|
|
\hfill
|
|
\caption{Przykładowe wyniki generacji 10 wersów po 10 słów, kolejno dla zbiorów danych: $english\_mixtape.csv$ oraz $somemix.csv$}
|
|
\label{fig:mesh1}
|
|
\end{figure}
|
|
\FloatBarrier
|
|
\section{Rekurencyjne Sieci Neuronowe}
|
|
\end{document}
|