From 0b6fdbae890bd3ece00e35903e222ebb53751cab Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 16:42:52 +0900 Subject: [PATCH 1/6] Added Korean Translated Lab Guides. --- Lab 1/README-ko.md | 79 ++++++++++++++++++++++++++++++++++++++ Lab 2/README-ko.md | 80 +++++++++++++++++++++++++++++++++++++++ Music-terminologies-ko.md | 19 ++++++++++ README-ko.md | 28 ++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 Lab 1/README-ko.md create mode 100644 Lab 2/README-ko.md create mode 100644 Music-terminologies-ko.md create mode 100644 README-ko.md diff --git a/Lab 1/README-ko.md b/Lab 1/README-ko.md new file mode 100644 index 0000000..610008c --- /dev/null +++ b/Lab 1/README-ko.md @@ -0,0 +1,79 @@ +# Lab 1 - DeepComposer 모델로 음악 작곡하기 + +## 전제 조건: (계속 진행하기 전에 숙지하세요) +1. 본 Lab에서는 Chrome 브라우저를 사용합니다. +2. AWS DeepComposer 키보드를 연결합니다. + +## AWS DeepComposer 콘솔 접근: + +시작하려면 Deepcomposer 링크를 클릭하세요: https://us-east-1.console.aws.amazon.com/deepcomposer + +![access-console](images/lab1-access-console.png) + +AWS account ID, IAM Username와 Password를 입력하고 Sign In 버튼을 클릭해 주세요. + +**참고 - N.Virginia(us-east-1) AWS 리전의 콘솔에 액세스해야 합니다.** 드롭 다운을 사용하여 올바른 리전을 선택할 수 있습니다. +![aws-region](images/aws-region.jpg) + +## 시작하기: +![models](images/models.jpg) + +왼쪽 네비게이션 메뉴에서 **Models**을 선택하세요. + +![create-models](images/create-models.jpg) + +여러분의 계정에서 모델을 생성하려면 ***Create a model**을 클릭하세요. + +AWS DeepComposer는 몇 가지 사전 학습된 모델들을 제공합니다. 이를 사용하려면 이러한 모델들을 여러분의 계정에 복제해야 합니다. + +![clone-models](images/clone-models.jpg) + +**Clone a pre-trained model**를 선택하여 모델을 계정에 복제합니다. + +목록에서 원하는 모델을 선택하세요. + +모델의 이름을 입력해 주세오. 모델 리스트에 모델이 여러분이 입력하신 이름으로 나타날 것입니다. + +![create-model-button](images/create-model-button.jpg) + +Click **Create model** to create the model in your account + +![music-studio](images/music-studio.jpg) + +왼쪽 네비게이션 메뉴에서 **Music Studio**을 클릭하세요. + +![play-default](images/lab1-play-default.PNG) + +기본 입력 멜로디를 연주하려면 *play*를 클릭하세요. + +![generate-composition](images/lab1-generate-composition.PNG) + +컴포지션(composition)을 생성하려면 **Generate composition**을 클릭하세요. AI 생성 컴포지션이 생성됩니다. + +새로운 AI 생성 음악 작곡을 재생하려면 *play*를 클릭하세요. + +## 입력 멜로디: + +![record-composition](images/lab1-record.PNG) + +Click *record* to start recording + +![custom-input](images/lab1-custom-music.png) + +실제 키보드에서 음표를 연주해 봅니다. + +*record* 버튼을 다시 클릭하여 녹음을 중지하세요. + +녹음된 음악을 재생하여 입력을 확인하십시오. 녹음된 음악이 마음에 들지 않으면, *record*를 클릭하여 녹음을 다시 시작할 수 있습니다. + +![model-jazz](images/lab1-model-default.PNG) + + *Model*에서 **Jazz** 모델을 선택하세요. + +여러분이 제공한 입력 멜로디를 기반으로 컴포지션을 생성하려면 **Generate Composition**을 클릭하세요. *참고: 이 단계는 여러분이 선택한 장르의 음악 작품을 생성하는 데 몇 분이 소요됩니다.* + +컴포지션을을 재생하고 AI기 생성한 음악을 즐기려면 *play*를 클릭하세요. + +다른 장르 또는 샘플 입력 멜로디로 실험해 보세요. + +**축하합니다! 사전 학습된 모델을 사용하여 새로운 음악을 생성하는 방법을 배웠습니다.** diff --git a/Lab 2/README-ko.md b/Lab 2/README-ko.md new file mode 100644 index 0000000..c2cc30b --- /dev/null +++ b/Lab 2/README-ko.md @@ -0,0 +1,80 @@ +# Lab 2 - Amazon SageMaker로 사용자 정의(custom) GAN 모델 학습하기 + +## 목표 + +여러분은 이 랩에서 사용자 지정(custom) GAN 아키텍처를 구축하고 Amazon SageMaker를 사용하여 모델을 학습하는 방법을 배웁니다. + +## 전제 조건(Prerequisites) + +* Amazon SageMaker 접근 권한 + +## 비용 + +`ml.c5.4xlarge` 인스턴스를 사용하면 전체 학습을 실행하는 데 3-4 시간이 걸립니다. 자세한 내용은 [Amazon SageMaker 요금](https://aws.amazon.com/sagemaker/pricing/)을 참조하세요. + +## 셋업 + +먼저 Amazon SageMaker 노트북 인스턴스를 생성합니다. + +https://console.aws.amazon.com/sagemaker/home?region=us-east-1#/dashboard 링크를 사용하여 Amazon SageMaker로 이동하세요. + +![notebook-instance](images/notebook-instance.PNG) + +왼쪽 네비게이션 바(navigation bar)에서 **Notebook instances**를 클릭하세요. + +**Create notebook instance**을 선택하세요. + +![create-notebook](images/create_notebook.png) + +노트북 인스턴스 생성 양식에서 **Notebook instance type**으로 "c5.4xlarge"를 선택하세요. + +![notebook-instance-settings](images/notebook_instance_settings.png) + +**Permissions and encryption**에 대해 아래 사항들을 설정해 주세요: +* IAM role: Use an existing role or create a new role +* Root access: Enable +* Encryption key: No Custom Encryption + +![notebook-instance-settings](images/permissions_and_encryption.png) + +**Git repositories**에 대해 아래 사항들을 설정해 주세요: +* Repository: Clone a public Git repository to this notebook instance only +* Git repository URL: https://github.com/aws-samples/aws-deepcomposer-samples + +![notebook-instance-settings](images/notebook_git_settings.png) + +**Open Jupyter**를 클릭하세요. + +![open-notebook](images/open_jupyter.png) + +**Lab 2** 폴더를 클릭하고, **GAN-ko.ipynb** 파일을 클릭해 주세요. + +![GAN-notebook](images/gan_notebook.png) + +*커널(kernel)을 선택하라는 메시지가 표시될 수 있습니다. 드롭 다운(Drop down)을 선택하고 커널로 **conda_python3**을 선택하세요.* + +![set-kernel](images/set-kernel.PNG) + +이 jupyter 노트북에는 사용자 정의 GAN 모델을 밑바닥부터(from scratch) 작성하는 지침과 코드가 포함되어 있습니다. 노트북 내용을 따라 모든 코드 셀(code cell)을 끝까지 실행하십시오. + +![run-notebook](images/run-notebook.PNG) + +코드 셀을 실행하려면 실행할 코드 셀을 선택하고 **Run**을 클릭하세요. (Shift+Enter 단축키로도 동일 작업을 수행하실 수 있습니다.) + +![kernel-empty](images/kernel-empty.png) + +커널에 빈 원이 있다면, 그것은 코드를 실행할 준비가 되어 있음을 의미합니다. + +![kernel-busy](images/kernel-busy.png) + +커널에 채워진 원이 있으면 사용 중임을 의미합니다. 다음 코드 셀을 실행하기 전에 이가 해제될 때까지 기다려 주세요. + +## 다음 단계 + +**밑바닥부터(from stratch) 사용자 정의 GAN 모델을 구축하신 것을 축하합니다!** + +이제 모델을 사용하여 사용자 정의 MIDI 입력 데이터를 기반으로 작곡을 해 보세요. + +**중요: 추가 과금을 피하기 위해 Lab 완료 후 Amazon SageMaker 인스턴스를 중지해야 합니다.** + +![notebook-stop](images/notebook-stop.png) \ No newline at end of file diff --git a/Music-terminologies-ko.md b/Music-terminologies-ko.md new file mode 100644 index 0000000..2d5728c --- /dev/null +++ b/Music-terminologies-ko.md @@ -0,0 +1,19 @@ +## 음악 용어(Music Terminologies) + +*__Pitch(피치):__* 우리 뇌가 음을 인식하는 정도를 나타냅니다. + +*__Duration(지속 시간):__* 사운드 길이를 나타냅니다. + +*__Loudness(음량):__* 소리가 얼마나 큰지(loud) 또는 조용한지(quiet)를 나타냅니다. + +*__Timbre(음색):__* 같은 크기, 같은 높이의 음을 구별할 수 있게 해주는 소리의 특성입니다. (예: 같은 크기, 같은 높이의 음이라도 기타로 들을 때와 피아노로 들을 때의 소리가 다름) + +![piano](Lab%202/images/Piano.png) + +*__Note:__* : 음악 소리를 나타내는 기호로, 각 note는 음악의 피치와 지속 시간 등의 정보를 포함하고 있습니다. + +서양 음악에서 음표는 첫 7글자(A, B, C, D, E, F 및 G)로 표시되고 유럽에서는 La, [t/s]i, Do, Re, Mi, Fa, Sol로 표시됩니다. + +8번째 음 또는 옥타브는 1번째와 같은 이름을 갖지만 두 배의 주파수를 가집니다. + +구별하기 위해 일반적으로 문자 뒤에 숫자를 넣습니다. (예: C3 (피아노의 중간 C)). C4는 1 옥타브 위 (C3의 2배 주파수) \ No newline at end of file diff --git a/README-ko.md b/README-ko.md new file mode 100644 index 0000000..4b955b2 --- /dev/null +++ b/README-ko.md @@ -0,0 +1,28 @@ +# 들어가며 + +이 워크샵은 AWS DeepComposer Workshop([영문 원본](https://github.com/aws-samples/aws-deepcomposer-samples))의 한국어 번역으로, 한국 고객들을 위해 원저자들의 공식적인 허락을 받아 한글화하였습니다. +일부 단어 및 용어들은 번역 없이 원문을 그대로 사용하였으며, 번역으로 인해 의미가 모호할 수 있는 단어 및 용어들은 번역된 내용에 괄호를 추가하여 괄호 안에 원문을 같이 표기하였습니다. +아래 예시들을 참조해 주세요. +- 원문 사용: generative, discriminative +- 괄호 추가: 전통적인(traditional), 사용자 정의 입력(custom input) + +# AWS DeepComposer + +AWS DeepComposer 워크샵에 오신 것을 환영합니다. 워크샵은 2개의 Lab으로 구성되어 있으며, +Lab 진행 중 특정 task나 code cell의 수행 시간이 오래 소요될 때 Optional Reading의 내용을 읽어 보시는 것을 추천드립니다. + +## [Lab 1: DeepComposer 모델로 음악 작곡하기](Lab%201) + +## [Lab 2: Amazon SageMaker로 사용자 정의(custom) GAN 모델 학습하기](Lab%202) + +# Optional Reading + +## [GAN 아키텍처의 loss function](Loss-functions.md) + +## [음악 용어](Music-terminologies.md) + +## [re:Invent DeepComposer 워크숍 장표(deck)](reinvent-workshop-deck) + +# License + +이 라이브러리는 MIT-0 라이센스에 따라 제공됩니다. LICENSE 파일을 참조하십시오. From bed26551b8cec10c75732d9e1c02c1004f6c18c9 Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 16:43:19 +0900 Subject: [PATCH 2/6] Added Korean Translated Lab Guides. --- Lab 2/GAN-ko.ipynb | 1187 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1187 insertions(+) create mode 100644 Lab 2/GAN-ko.ipynb diff --git a/Lab 2/GAN-ko.ipynb b/Lab 2/GAN-ko.ipynb new file mode 100644 index 0000000..4816c8d --- /dev/null +++ b/Lab 2/GAN-ko.ipynb @@ -0,0 +1,1187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This tutorial is a brief introduction to music generation using **Generative Adversarial Networks** (**GAN**s). \n", + "\n", + "The goal of this tutorial is to train a machine learning model using a dataset of Bach compositions so that the model learns to add accompaniments to a single track input melody. In other words, if the user provides a single piano track of a song such as \"twinkle twinkle little star\", the GAN model would add three other piano tracks to make the music sound more Bach-inspired.\n", + "\n", + "The proposed algorithm consists of two competing networks: a generator and a critic (discriminator). A generator is a deep neural network that learns to create new synthetic data that resembles the distribution of the dataset on which it was trained. A critic is another deep neural network that is trained to differentiate between real and synthetic data. The generator and the critic are trained in alternating cycles such that the generator learns to produce more and more realistic data (Bach-like music in this use case) while the critic iteratively gets better at learning to differentiate real data (Bach music) from the synthetic ones.\n", + "\n", + "As a result, the quality of music produced by the generator gets more and more realistic with time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![High level WGAN-GP architecture](images/dgan.png \"WGAN-GP architecture\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dependencies\n", + "First, let's import all of the python packages we will use throughout the tutorial.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n", + "\n", + "# Permission is hereby granted, free of charge, to any person obtaining a copy of\n", + "# this software and associated documentation files (the \"Software\"), to deal in\n", + "# the Software without restriction, including without limitation the rights to\n", + "# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n", + "# the Software, and to permit persons to whom the Software is furnished to do so.\n", + "\n", + "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", + "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n", + "# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n", + "# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n", + "# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n", + "# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "\n", + "\n", + "# Create the environment\n", + "!conda update --all --y \n", + "!pip install tensorflow-gpu==1.14.0\n", + "!pip install numpy==1.16.4\n", + "!pip install pretty_midi\n", + "!pip install pypianoroll\n", + "!pip install music21\n", + "!pip install seaborn\n", + "!pip install --ignore-installed moviepy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# IMPORTS\n", + "import os \n", + "import numpy as np\n", + "from PIL import Image\n", + "import logging\n", + "import pypianoroll\n", + "import scipy.stats\n", + "import pickle\n", + "import music21\n", + "from IPython import display\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Configure Tensorflow\n", + "import tensorflow as tf\n", + "print(tf.__version__)\n", + "tf.logging.set_verbosity(tf.logging.ERROR)\n", + "tf.enable_eager_execution()\n", + "\n", + "# Use this command to make a subset of GPUS visible to the jupyter notebook.\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0'\n", + "os.environ[\"CUDA_DEVICE_ORDER\"]=\"PCI_BUS_ID\"\n", + "\n", + "# Utils library for plotting, loading and saving midi among other functions\n", + "from utils import display_utils, metrics_utils, path_utils, inference_utils, midi_utils\n", + "\n", + "LOGGER = logging.getLogger(\"gan.train\")\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configuration" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we configure paths to retrieve our dataset and save our experiments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "root_dir = './Experiments'\n", + "\n", + "# Directory to save checkpoints\n", + "model_dir = os.path.join(root_dir,'2Bar') # JSP: 229, Bach: 19199\n", + "\n", + "# Directory to save pianorolls during training\n", + "train_dir = os.path.join(model_dir, 'train')\n", + "\n", + "# Directory to save checkpoint generated during training\n", + "check_dir = os.path.join(model_dir, 'preload')\n", + "\n", + "# Directory to save midi during training\n", + "sample_dir = os.path.join(model_dir, 'sample')\n", + "\n", + "# Directory to save samples generated during inference\n", + "eval_dir = os.path.join(model_dir, 'eval')\n", + "\n", + "os.makedirs(train_dir, exist_ok=True)\n", + "os.makedirs(eval_dir, exist_ok=True)\n", + "os.makedirs(sample_dir, exist_ok=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data Preparation\n", + "\n", + "### Dataset summary\n", + "\n", + "In this tutorial, we use the [`JSB-Chorales-dataset`](http://www-etud.iro.umontreal.ca/~boulanni/icml2012), comprising 229 chorale snippets. A chorale is a hymn that is usually sung with a single voice playing a simple melody and three lower voices providing harmony. In this dataset, these voices are represented by four piano tracks.\n", + "\n", + "Let's listen to a song from this dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display_utils.playmidi('./original_midi/MIDI-0.mid')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Data format - piano roll" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the purpose of this tutorial, we represent music from the JSB-Chorales dataset in the piano roll format.\n", + "\n", + "**Piano roll** is a discrete representation of music which is intelligible by many machine learning algorithms. Piano rolls can be viewed as a two-dimensional grid with \"Time\" on the horizontal axis and \"Pitch\" on the vertical axis. A one or zero in any particular cell in this grid indicates if a note was played or not at that time for that pitch.\n", + "\n", + "Let us look at a few piano rolls in our dataset. In this example, a single piano roll track has 32 discrete time steps and 128 pitches. We see four piano rolls here, each one representing a separate piano track in the song." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Dataset\n", + "\n", + "You might notice this representation looks similar to an image. While the sequence of notes is often the natural way that people view music, many modern machine learning models instead treat music as images and leverage existing techniques within the computer vision domain. You will see such techniques used in our architecture later in this tutorial." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Why 32 time steps?**\n", + "\n", + "For the purpose of this tutorial, we sample two non-empty bars (https://en.wikipedia.org/wiki/Bar_(music)) from each song in the JSB-Chorales dataset. A **bar** (or **measure**) is a unit of composition and contains four beats for songs in our particular dataset (our songs are all in 4/4 time) :\n", + "\n", + "We’ve found that using a resolution of four time steps per beat captures enough of the musical detail in this dataset.\n", + "\n", + "This yields...\n", + "\n", + "$$ \\frac{4\\;timesteps}{1\\;beat} * \\frac{4\\;beats}{1\\;bar} * \\frac{2\\;bars}{1} = 32\\;timesteps $$\n", + "\n", + "Let us now load our dataset as a numpy array. Our dataset comprises 229 samples of 4 tracks (all tracks are piano). Each sample is a 32 time-step snippet of a song, so our dataset has a shape of...\n", + "(num_samples, time_steps, pitch_range, tracks) = (229, 32, 128, 4)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "training_data = np.load('./dataset/train.npy')\n", + "print(training_data.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see a sample of the data we'll feed into our model. The four graphs represent the four tracks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display_utils.show_pianoroll(training_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load data " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now create a Tensorflow dataset object from our numpy array to feed into our model. The dataset object helps us feed batches of data into our model. A batch is a subset of the data that is passed through the deep learning network before the weights are updated. Batching data is necessary in most training scenarios as our training environment might not be able to load the entire dataset into memory at once." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Number of input data samples in a batch\n", + "BATCH_SIZE = 64\n", + "\n", + "#Shuffle buffer size for shuffling data\n", + "SHUFFLE_BUFFER_SIZE = 1000\n", + "\n", + "#Preloads PREFETCH_SIZE batches so that there is no idle time between batches\n", + "PREFETCH_SIZE = 4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def prepare_dataset(filename):\n", + " \n", + " \"\"\"Load the samples used for training.\"\"\"\n", + " \n", + " data = np.load(filename)\n", + " data = np.asarray(data, dtype=np.float32) # {-1, 1}\n", + "\n", + " print('data shape = {}'.format(data.shape))\n", + "\n", + " dataset = tf.data.Dataset.from_tensor_slices(data)\n", + " dataset = dataset.shuffle(SHUFFLE_BUFFER_SIZE).repeat()\n", + " dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)\n", + " dataset = dataset.prefetch(PREFETCH_SIZE)\n", + "\n", + " return dataset \n", + "\n", + "dataset = prepare_dataset('./dataset/train.npy')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model architecture\n", + "In this section, we will walk through the architecture of the proposed GAN.\n", + "\n", + "The model consists of two networks, a generator and a critic. These two networks work in a tight loop as following:\n", + "\n", + "* Generator:\n", + " 1. The generator takes in a batch of single-track piano rolls (melody) as the input and generates a batch of multi-track piano rolls as the output by adding accompaniments to each of the input music tracks. \n", + " 2. The critic then takes these generated music tracks and predicts how far it deviates from the real data present in your training dataset.\n", + " 3. This feedback from the critic is used by the generator to update its weights.\n", + "* Critic: As the generator gets better at creating better music accompaniments using the feedback from the critic, the critic needs to be retrained as well.\n", + " 1. Train the critic with the music tracks just generated by the generator as fake inputs and an equivalent number of songs from the original dataset as the real input. \n", + "* Alternate between training these two networks until the model converges and produces realistic music, beginning with the critic on the first iteration.\n", + "\n", + "We use a special type of GAN called the **Wasserstein GAN with Gradient Penalty** (or **WGAN-GP**) to generate music. While the underlying architecture of a WGAN-GP is very similar to vanilla variants of GAN, WGAN-GPs help overcome some of the commonly seen defects in GANs such as the vanishing gradient problem and mode collapse (see appendix for more details).\n", + "\n", + "Note our \"critic\" network is more generally called a \"discriminator\" network in the more general context of vanilla GANs." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The generator is adapted from the U-Net architecture (a popular CNN that is used extensively in the computer vision domain), consisting of an “encoder” that maps the single track music data (represented as piano roll images) to a relatively lower dimensional “latent space“ and a ”decoder“ that maps the latent space back to multi-track music data.\n", + "\n", + "Here are the inputs provided to the generator:\n", + "\n", + "**Single-track piano roll input**: A single melody track of size (32, 128, 1) => (TimeStep, NumPitches, NumTracks) is provided as the input to the generator. \n", + "\n", + "**Latent noise vector**: A latent noise vector z of dimension (2, 8, 512) is also passed in as input and this is responsible for ensuring that there is a distinctive flavor to each output generated by the generator, even when the same input is provided.\n", + "\n", + "Notice from the figure below that the encoding layers of the generator on the left side and decoder layer on on the right side are connected to create a U-shape, thereby giving the name U-Net to this architecture." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this implementation, we build the generator following a simple four-level Unet architecture by combining `_conv2d`s and `_deconv2d`, where `_conv2d` compose the contracting path and `_deconv2d` forms the expansive path. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def _conv2d(layer_input, filters, f_size=4, bn=True):\n", + " \"\"\"Generator Basic Downsampling Block\"\"\"\n", + " d = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=2,\n", + " padding='same')(layer_input)\n", + " d = tf.keras.layers.LeakyReLU(alpha=0.2)(d)\n", + " if bn:\n", + " d = tf.keras.layers.BatchNormalization(momentum=0.8)(d)\n", + " return d\n", + "\n", + "\n", + "def _deconv2d(layer_input, pre_input, filters, f_size=4, dropout_rate=0):\n", + " \"\"\"Generator Basic Upsampling Block\"\"\"\n", + " u = tf.keras.layers.UpSampling2D(size=2)(layer_input)\n", + " u = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=1,\n", + " padding='same')(u)\n", + " u = tf.keras.layers.BatchNormalization(momentum=0.8)(u)\n", + " u = tf.keras.layers.ReLU()(u)\n", + "\n", + " if dropout_rate:\n", + " u = tf.keras.layers.Dropout(dropout_rate)(u)\n", + " \n", + " u = tf.keras.layers.Concatenate()([u, pre_input])\n", + " return u\n", + "\n", + " \n", + "def build_generator(condition_input_shape=(32, 128, 1), filters=64,\n", + " instruments=4, latent_shape=(2, 8, 512)):\n", + " \"\"\"Buld Generator\"\"\"\n", + " c_input = tf.keras.layers.Input(shape=condition_input_shape)\n", + " z_input = tf.keras.layers.Input(shape=latent_shape)\n", + "\n", + " d1 = _conv2d(c_input, filters, bn=False)\n", + " d2 = _conv2d(d1, filters * 2)\n", + " d3 = _conv2d(d2, filters * 4)\n", + " d4 = _conv2d(d3, filters * 8)\n", + "\n", + " d4 = tf.keras.layers.Concatenate(axis=-1)([d4, z_input])\n", + "\n", + " u4 = _deconv2d(d4, d3, filters * 4)\n", + " u5 = _deconv2d(u4, d2, filters * 2)\n", + " u6 = _deconv2d(u5, d1, filters)\n", + "\n", + " u7 = tf.keras.layers.UpSampling2D(size=2)(u6)\n", + " output = tf.keras.layers.Conv2D(instruments, kernel_size=4, strides=1,\n", + " padding='same', activation='tanh')(u7) # 32, 128, 4\n", + "\n", + " generator = tf.keras.models.Model([c_input, z_input], output, name='Generator')\n", + "\n", + " return generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now dive into each layer of the generator to see the inputs/outputs at each layer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Models\n", + "generator = build_generator()\n", + "generator.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Critic (Discriminator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The goal of the critic is to provide feedback to the generator about how realistic the generated piano rolls are, so that the generator can learn to produce more realistic data. The critic provides this feedback by outputting a scalar that represents how “real” or “fake” a piano roll is.\n", + "\n", + "Since the critic tries to classify data as “real” or “fake”, it is not very different from commonly used binary classifiers. We use a simple architecture for the critic, composed of four convolutional layers and a dense layer at the end." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Discriminator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "def _build_critic_layer(layer_input, filters, f_size=4):\n", + " \"\"\"\n", + " This layer decreases the spatial resolution by 2:\n", + "\n", + " input: [batch_size, in_channels, H, W]\n", + " output: [batch_size, out_channels, H/2, W/2]\n", + " \"\"\"\n", + " d = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=2,\n", + " padding='same')(layer_input)\n", + " # Critic does not use batch-norm\n", + " d = tf.keras.layers.LeakyReLU(alpha=0.2)(d) \n", + " return d\n", + "\n", + "\n", + "def build_critic(pianoroll_shape=(32, 128, 4), filters=64):\n", + " \"\"\"WGAN critic.\"\"\"\n", + " \n", + " condition_input_shape = (32,128,1)\n", + " groundtruth_pianoroll = tf.keras.layers.Input(shape=pianoroll_shape)\n", + " condition_input = tf.keras.layers.Input(shape=condition_input_shape)\n", + " combined_imgs = tf.keras.layers.Concatenate(axis=-1)([groundtruth_pianoroll, condition_input])\n", + "\n", + "\n", + " \n", + " d1 = _build_critic_layer(combined_imgs, filters)\n", + " d2 = _build_critic_layer(d1, filters * 2)\n", + " d3 = _build_critic_layer(d2, filters * 4)\n", + " d4 = _build_critic_layer(d3, filters * 8)\n", + "\n", + " x = tf.keras.layers.Flatten()(d4)\n", + " logit = tf.keras.layers.Dense(1)(x)\n", + "\n", + " critic = tf.keras.models.Model([groundtruth_pianoroll,condition_input], logit,\n", + " name='Critic')\n", + " \n", + "\n", + " return critic" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create the Discriminator\n", + "\n", + "critic = build_critic()\n", + "critic.summary() # View discriminator architecture." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training\n", + "\n", + "We train our models by searching for model parameters which optimize an objective function. For our WGAN-GP, we have special loss functions that we minimize as we alternate between training our generator and critic networks:\n", + "\n", + "*Generator Loss:*\n", + "* We use the Wasserstein (Generator) loss function which is negative of the Critic Loss function. The generator is trained to bring the generated pianoroll as close to the real pianoroll as possible.\n", + " * $\\frac{1}{m} \\sum_{i=1}^{m} -D_w(G(z^{i}|c^{i})|c^{i})$\n", + "\n", + "*Critic Loss:*\n", + "\n", + "* We begin with the Wasserstein (Critic) loss function designed to maximize the distance between the real piano roll distribution and generated (fake) piano roll distribution.\n", + " * $\\frac{1}{m} \\sum_{i=1}^{m} [D_w(G(z^{i}|c^{i})|c^{i}) - D_w(x^{i}|c^{i})]$\n", + "\n", + "* We add a gradient penalty loss function term designed to control how the gradient of the critic with respect to its input behaves. This makes optimization of the generator easier. \n", + " * $\\frac{1}{m} \\sum_{i=1}^{m}(\\lVert \\nabla_{\\hat{x}^i}D_w(\\hat{x}^i|c^{i}) \\rVert_2 - 1)^2 $" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the different loss functions\n", + "\n", + "def generator_loss(critic_fake_output):\n", + " \"\"\" Wasserstein GAN loss\n", + " (Generator) -D(G(z|c))\n", + " \"\"\"\n", + " return -tf.reduce_mean(critic_fake_output)\n", + "\n", + "\n", + "def wasserstein_loss(critic_real_output, critic_fake_output):\n", + " \"\"\" Wasserstein GAN loss\n", + " (Critic) D(G(z|c)) - D(x|c)\n", + " \"\"\"\n", + " return tf.reduce_mean(critic_fake_output) - tf.reduce_mean(\n", + " critic_real_output)\n", + "\n", + "\n", + "def compute_gradient_penalty(critic, x, fake_x):\n", + " \n", + " c = tf.expand_dims(x[..., 0], -1)\n", + " batch_size = x.get_shape().as_list()[0]\n", + " eps_x = tf.random.uniform(\n", + " [batch_size] + [1] * (len(x.get_shape()) - 1)) # B, 1, 1, 1, 1\n", + " inter = eps_x * x + (1.0 - eps_x) * fake_x\n", + "\n", + " with tf.GradientTape() as g:\n", + " g.watch(inter)\n", + " disc_inter_output = critic((inter,c), training=True)\n", + " grads = g.gradient(disc_inter_output, inter)\n", + " slopes = tf.sqrt(1e-8 + tf.reduce_sum(\n", + " tf.square(grads),\n", + " reduction_indices=tf.range(1, grads.get_shape().ndims)))\n", + " gradient_penalty = tf.reduce_mean(tf.square(slopes - 1.0))\n", + " \n", + " return gradient_penalty\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With our loss functions defined, we associate them with Tensorflow optimizers to define how our model will search for a good set of model parameters. We use the *Adam* algorithm, a commonly used general-purpose optimizer. We also set up checkpoints to save our progress as we train." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Setup Adam optimizers for both G and D\n", + "generator_optimizer = tf.keras.optimizers.Adam(1e-3, beta_1=0.5, beta_2=0.9)\n", + "critic_optimizer = tf.keras.optimizers.Adam(1e-3, beta_1=0.5, beta_2=0.9)\n", + "\n", + "# We define our checkpoint directory and where to save trained checkpoints\n", + "ckpt = tf.train.Checkpoint(generator=generator,\n", + " generator_optimizer=generator_optimizer,\n", + " critic=critic,\n", + " critic_optimizer=critic_optimizer)\n", + "ckpt_manager = tf.train.CheckpointManager(ckpt, check_dir, max_to_keep=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we define the `generator_train_step` and `critic_train_step` functions, each of which performs a single forward pass on a batch and returns the corresponding loss." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@tf.function\n", + "def generator_train_step(x, condition_track_idx=0):\n", + "\n", + " ############################################\n", + " #(1) Update G network: maximize D(G(z|c))\n", + " ############################################\n", + "\n", + " # Extract condition track to make real batches pianoroll\n", + " c = tf.expand_dims(x[..., condition_track_idx], -1)\n", + "\n", + " # Generate batch of latent vectors\n", + " z = tf.random.truncated_normal([BATCH_SIZE, 2, 8, 512])\n", + "\n", + " with tf.GradientTape() as tape:\n", + " fake_x = generator((c, z), training=True)\n", + " fake_output = critic((fake_x,c), training=False)\n", + "\n", + " # Calculate Generator's loss based on this generated output\n", + " gen_loss = generator_loss(fake_output)\n", + "\n", + " # Calculate gradients for Generator\n", + " gradients_of_generator = tape.gradient(gen_loss,\n", + " generator.trainable_variables)\n", + " # Update Generator\n", + " generator_optimizer.apply_gradients(\n", + " zip(gradients_of_generator, generator.trainable_variables))\n", + "\n", + " return gen_loss\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@tf.function\n", + "def critic_train_step(x, condition_track_idx=0):\n", + "\n", + " ############################################################################\n", + " #(2) Update D network: maximize (D(x|c)) + (1 - D(G(z|c))|c) + GradientPenality() \n", + " ############################################################################\n", + "\n", + " # Extract condition track to make real batches pianoroll\n", + " c = tf.expand_dims(x[..., condition_track_idx], -1)\n", + "\n", + " # Generate batch of latent vectors\n", + " z = tf.random.truncated_normal([BATCH_SIZE, 2, 8, 512])\n", + "\n", + " # Generated fake pianoroll\n", + " fake_x = generator((c, z), training=False)\n", + "\n", + "\n", + " # Update critic parameters\n", + " with tf.GradientTape() as tape:\n", + " real_output = critic((x,c), training=True)\n", + " fake_output = critic((fake_x,c), training=True)\n", + " critic_loss = wasserstein_loss(real_output, fake_output)\n", + "\n", + " # Caculate the gradients from the real and fake batches\n", + " grads_of_critic = tape.gradient(critic_loss,\n", + " critic.trainable_variables)\n", + "\n", + " with tf.GradientTape() as tape:\n", + " gp_loss = compute_gradient_penalty(critic, x, fake_x)\n", + " gp_loss *= 10.0\n", + "\n", + " # Calculate the gradients penalty from the real and fake batches\n", + " grads_gp = tape.gradient(gp_loss, critic.trainable_variables)\n", + " gradients_of_critic = [g + ggp for g, ggp in\n", + " zip(grads_of_critic, grads_gp)\n", + " if ggp is not None]\n", + "\n", + " # Update Critic\n", + " critic_optimizer.apply_gradients(\n", + " zip(gradients_of_critic, critic.trainable_variables))\n", + "\n", + " return critic_loss + gp_loss\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we begin training, let's define some training configuration parameters and prepare to monitor important quantities. Here we log the losses and metrics which we can use to determine when to stop training. Consider coming back here to tweak these parameters and explore how your model responds. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# We use load_melody_samples() to load 10 input data samples from our dataset into sample_x \n", + "# and 10 random noise latent vectors into sample_z\n", + "sample_x, sample_z = inference_utils.load_melody_samples(n_sample=10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Number of iterations to train for\n", + "iterations = 1000\n", + "\n", + "# Update critic n times per generator update \n", + "n_dis_updates_per_gen_update = 5\n", + "\n", + "# Determine input track in sample_x that we condition on\n", + "condition_track_idx = 0 \n", + "sample_c = tf.expand_dims(sample_x[..., condition_track_idx], -1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now train our model!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Clear out any old metrics we've collected\n", + "metrics_utils.metrics_manager.initialize()\n", + "\n", + "# Keep a running list of various quantities:\n", + "c_losses = []\n", + "g_losses = []\n", + "\n", + "# Data iterator to iterate over our dataset\n", + "it = iter(dataset)\n", + "\n", + "for iteration in range(iterations):\n", + "\n", + " # Train critic\n", + " for _ in range(n_dis_updates_per_gen_update):\n", + " c_loss = critic_train_step(next(it))\n", + "\n", + " # Train generator\n", + " g_loss = generator_train_step(next(it))\n", + "\n", + " # Save Losses for plotting later\n", + " c_losses.append(c_loss)\n", + " g_losses.append(g_loss)\n", + "\n", + " display.clear_output(wait=True)\n", + " fig = plt.figure(figsize=(15, 5))\n", + " line1, = plt.plot(range(iteration+1), c_losses, 'r')\n", + " line2, = plt.plot(range(iteration+1), g_losses, 'k')\n", + " plt.xlabel('Iterations')\n", + " plt.ylabel('Losses')\n", + " plt.legend((line1, line2), ('C-loss', 'G-loss'))\n", + " display.display(fig)\n", + " plt.close(fig)\n", + " \n", + " # Output training stats\n", + " print('Iteration {}, c_loss={:.2f}, g_loss={:.2f}'.format(iteration, c_loss, g_loss))\n", + " \n", + " # Save checkpoints, music metrics, generated output\n", + " if iteration < 100 or iteration % 50 == 0 :\n", + " # Check how the generator is doing by saving G's samples on fixed_noise\n", + " fake_sample_x = generator((sample_c, sample_z), training=False)\n", + " metrics_utils.metrics_manager.append_metrics_for_iteration(fake_sample_x.numpy(), iteration)\n", + "\n", + " if iteration % 50 == 0:\n", + " # Save the checkpoint to disk.\n", + " ckpt_manager.save(checkpoint_number=iteration) \n", + " \n", + " fake_sample_x = fake_sample_x.numpy()\n", + " \n", + " # plot the pianoroll\n", + " display_utils.plot_pianoroll(iteration, sample_x[:4], fake_sample_x[:4], save_dir=train_dir)\n", + "\n", + " # generate the midi\n", + " destination_path = path_utils.generated_midi_path_for_iteration(iteration, saveto_dir=sample_dir)\n", + " midi_utils.save_pianoroll_as_midi(fake_sample_x[:4], destination_path=destination_path)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### We have started training!\n", + "\n", + "When using the Wasserstein loss function, we should train the critic to converge to ensure that the gradients for the generator update are accurate. This is in contrast to a standard GAN, where it is important not to let the critic get too strong, to avoid vanishing gradients.\n", + "\n", + "Therefore, using the Wasserstein loss removes one of the key difficulties of training GANs—how to balance the training of the discriminator and generator. With WGANs, we can simply train the critic several times between generator updates, to ensure it is close to convergence. A typical ratio used is five critic updates to one generator update.\n", + "\n", + "### \"Babysitting\" the learning process\n", + "\n", + "Given that training these models can be an investment in time and resources, we must to continuously monitor training in order to catch and address anomalies if/when they occur. Here are some things to look out for:\n", + "\n", + "**What should the losses look like?**\n", + "\n", + "The adversarial learning process is highly dynamic and high-frequency oscillations are quite common. However if either loss (critic or generator) skyrockets to huge values, plunges to 0, or get stuck on a single value, there is likely an issue somewhere.\n", + "\n", + "**Is my model learning?**\n", + "- Monitor the critic loss and other music quality metrics (if applicable). Are they following the expected trajectories?\n", + "- Monitor the generated samples (piano rolls). Are they improving over time? Do you see evidence of mode collapse? Have you tried listening to your samples?\n", + "\n", + "**How do I know when to stop?**\n", + "- If the samples meet your expectations\n", + "- Critic loss no longer improving\n", + "- The expected value of the musical quality metrics converge to the corresponding expected value of the same metric on the training data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### How to measure sample quality during training \n", + "\n", + "Typically, when training any sort of neural networks, it is standard practice to monitor the value of the loss function throughout the duration of the training. The critic loss in WGANs has been found to correlate well with sample quality.\n", + "\n", + "While standard mechanisms exist for evaluating the accuracy of more traditional models like classifiers or regressors, evaluating generative models is an active area of research. Within the domain of music generation, this hard problem is even less well-understood.\n", + "\n", + "To address this, we take high-level measurements of our data and show how well our model produces music that aligns with those measurements. If our model produces music which is close to the mean value of these measurements for our training dataset, our music should match on general “shape”.\n", + "\n", + "We’ll look at three such measurements:\n", + "- **Empty bar rate:** The ratio of empty bars to total number of bars.\n", + "- **Pitch histogram distance:** A metric that captures the distribution and position of pitches.\n", + "- **In Scale Ratio:** Ratio of the number of notes that are in C major key, which is a common key found in music, to the total number of notes. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluate results\n", + "\n", + "Now that we have finished training, let's find out how we did. We will analyze our model in several ways:\n", + "1. Examine how the generator and critic losses changed while training\n", + "2. Understand how certain musical metrics changed while training\n", + "3. Visualize generated piano roll output for a fixed input at every iteration and create a video\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us first restore our last saved checkpoint. If you did not complete training but still want to continue with a pre-trained version, set `TRAIN = False`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ckpt = tf.train.Checkpoint(generator=generator)\n", + "ckpt_manager = tf.train.CheckpointManager(ckpt, check_dir, max_to_keep=5)\n", + "\n", + "ckpt.restore(ckpt_manager.latest_checkpoint).expect_partial()\n", + "print('Latest checkpoint {} restored.'.format(ckpt_manager.latest_checkpoint))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot losses" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display_utils.plot_loss_logs(g_losses, c_losses, figsize=(15, 5), smoothing=0.01)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Observe how the critic loss (C_loss in the graph) decays to zero as we train. In WGAN-GPs, the critic loss decreases (almost) monotonically as you train." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot metrics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "metrics_utils.metrics_manager.set_reference_metrics(training_data)\n", + "metrics_utils.metrics_manager.plot_metrics()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each row here corresponds to a different music quality metric and each column denotes an instrument track. \n", + "\n", + "Observe how the expected value of the different metrics (blue scatter) approach the corresponding training set expected values (red) as the number of iterations increase. You might expect to see diminishing returns as the model converges.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generated samples during training\n", + "\n", + "The function below helps you probe intermediate samples generated in the training process. Remember that the conditioned input here is sampled from our training data. Let's start by listening to and observing a sample at iteration 0 and then iteration 100. Notice the difference!\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Enter an iteration number (can be divided by 50) and listen to the midi at that iteration\n", + "iteration = 50\n", + "midi_file = os.path.join(sample_dir, 'iteration-{}.mid'.format(iteration))\n", + "display_utils.playmidi(midi_file) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Enter an iteration number (can be divided by 50) and look at the generated pianorolls at that iteration\n", + "iteration = 50\n", + "pianoroll_png = os.path.join(train_dir, 'sample_iteration_%05d.png' % iteration)\n", + "display.Image(filename=pianoroll_png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see how the generated piano rolls change with the number of iterations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import Video\n", + "\n", + "\n", + "display_utils.make_training_video(train_dir)\n", + "video_path = \"movie.mp4\"\n", + "Video(video_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inference " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generating accompaniment for custom input\n", + "\n", + "Congratulations! You have trained your very own WGAN-GP to generate music. Let us see how our generator performs on a custom input.\n", + "\n", + "The function below generates a new song based on \"Twinkle Twinkle Little Star\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "latest_midi = inference_utils.generate_midi(generator, eval_dir, input_midi_file='./input_twinkle_twinkle.mid')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "display_utils.playmidi(latest_midi)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also take a look at the generated piano rolls for a certain sample, to see how diverse they are!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inference_utils.show_generated_pianorolls(generator, eval_dir, input_midi_file='./input_twinkle_twinkle.mid')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What's next?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using your own data (Optional)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To create your own dataset you can extract the piano roll from MIDI data. An example of creating a piano roll from a MIDI file is given below" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from pypianoroll import Multitrack\n", + "\n", + "midi_data = Multitrack('./input_twinkle_twinkle.mid')\n", + "tracks = [track.pianoroll for track in midi_data.tracks]\n", + "sample = np.stack(tracks, axis=-1)\n", + "\n", + "print(sample.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Open source implementations\n", + "For more open-source implementations of generative models for music, check out:\n", + "\n", + "- [MuseGAN](https://github.com/salu133445/musegan): Official TensorFlow Implementation that uses GANs to generate multi track polyphonic music\n", + "- [GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): GANSynth uses a Progressive GAN architecture to incrementally upsample with convolution from a single vector to the full audio spectrogram\n", + "- [Music Transformer](https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): Uses transformers to generate music!\n", + "\n", + "GANs have also achieved state of the generative modeling in several other domains including cross domain image tranfer, celebrity face generation, super resolution text to image and image inpainting.\n", + "\n", + "- [Keras-GAN](https://github.com/eriklindernoren/Keras-GAN): Library of reference implementations in Keras for image generation(good for educational purposes).\n", + "\n", + "There's an ocean of literatures out there that use GANs for modeling distributions across fields! If you are interested, [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo) is a good place to start." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### References\n", + "\n", + "1. [Dong, H.W., Hsiao, W.Y., Yang, L.C. and Yang, Y.H., 2018, April. MuseGAN: Multi-track sequential generative adversarial networks for symbolic music generation and accompaniment. In Thirty-Second AAAI Conference on Artificial Intelligence.](https://arxiv.org/abs/1709.06298)\n", + "2. [Ishaan, G., Faruk, A., Martin, A., Vincent, D. and Aaron, C., 2017. Improved training of wasserstein gans. In Advances in Neural Information Processing Systems.](https://arxiv.org/abs/1704.00028)\n", + "3. [Arjovsky, M., Chintala, S. and Bottou, L., 2017. Wasserstein gan. arXiv preprint arXiv:1701.07875.](https://arxiv.org/abs/1701.07875)\n", + "4. [Foster, D., 2019. Generative Deep Learning: Teaching Machines to Paint, Write, Compose, and Play. O'Reilly Media.](https://www.amazon.com/Generative-Deep-Learning-Teaching-Machines/dp/1492041947)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### More on Wassertein GAN with Gradient Penalty (optional)\n", + "\n", + "While GANs are a major breakthrough for generative modeling, plain GANs are also notoriously difficult to train. Some common problems encountered are:\n", + "\n", + "* **Oscillating loss:** The loss of the discriminator and generator can start to oscillate without exhibiting any long term stability.\n", + "* **Mode collapse:** The generator may get stuck on a small set of samples that always fool the discriminator. This reduces the capability of the network to produce novel samples.\n", + "* **Uninformative loss:** The lack of correlation between the generator loss and quality of generated output makes plain GAN training difficult to interpret.\n", + "\n", + "\n", + "The [Wasserstein GAN](#references) was a major advancement in GANs and helped mitigate to some of these issues. Some of its features are:\n", + "\n", + "1. It significantly improves the interpretability of loss functions and provides clearer stopping criteria\n", + "2. WGANs generally produce results of higher quality (demonstrated within the image generation domain)\n", + "\n", + "**Mathematics of Wasserstein GAN with Gradient Penalty**\n", + "\n", + "The [Wasserstein distance](https://en.wikipedia.org/wiki/Wasserstein_metric) between the true distribution $P_r$ and generated piano roll distribution $P_g$ is defined as follows:\n", + "\n", + "$$\\mathbb{W}(P_{r},P_{g})=\\sup_{\\lVert{f} \\rVert_{L} \\le 1} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(f(x)) - \\mathbb{E}_{x \\sim \\mathbb{P}_g}(f(x)) $$\n", + "\n", + "In this equation we are trying to minimize the distance between the expectation of the real distribution and the expectation of the generation distribution. $f$ is subject to a technical constraint in that it must be [1-Lipschitz](https://en.wikipedia.org/wiki/Lipschitz_continuity).\n", + "\n", + "To enforce the 1-Lipschitz condition that basically constraints the gradients from varying too rapidly we use the gradient penalty.\n", + "\n", + "**Gradient penalty**: We want to penalize the gradients of the critic. We implicitly define $P_{\\hat{x}}$ by sampling uniformly along straight lines between pairs of points sampled from the data distribution $P_r$ and the generator distribution $P_g$. This was originally motivated by the fact that the optimal critic contains straight lines with gradient norm 1 connecting coupled points from $P_r$ and $P_g$. We use a penalty coefficient $\\lambda$= 10 as was recommended in the original paper. \n", + "\n", + "The loss with gradient penalty is:\n", + "\n", + "$$\\mathbb{L}(P_{r},P_{g},P_{\\hat{x}} )= \\mathbb{W}(P_{r},P_{g}) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D(\\hat{x}) \\rVert_2 - 1)^2]$$\n", + "|\n", + "This loss can be parametrized in terms of $w$ and $\\theta$. We then use neural networks to learn the functions $f_w$ (discriminator) and $g_\\theta$ (generator).\n", + "$$\\mathbb{W}(P_{r},P_{\\theta})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) $$\n", + "$$\\mathbb{L}(P_{r},P_{\\theta},P_{\\hat{x}})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D_w(\\hat{x}) \\rVert_2 - 1)^2]$$\n", + "\n", + "where $$ \\hat{x} = \\epsilon x + (1- \\epsilon) G(z) $$ and $$\\epsilon \\sim Unif(0,1)$$\n", + "\n", + "The basic procedure to train is as following: \n", + "1. We draw real_x from the real distribution $P_r$ and fake_x from the generated distribution $G_{\\theta}(z)$ where $z \\sim p(z)$\n", + "2. The latent vectors are sampled from z and then tranformed using the generator $G_{\\theta}$ to get the fake samples fake_x. They are evaluated using the critic function $D_w$\n", + "3. We are trying to minimize the Wasserstein distance between the two distributions\n", + "\n", + "Both the generator and critic are conditioned on the input pianoroll melody." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "conda_python3", + "language": "python", + "name": "conda_python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 318d503e4bb1869a2646ee6fd5204d25d4860c4b Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 17:06:56 +0900 Subject: [PATCH 3/6] Fixed typos --- Lab 1/README-ko.md | 2 +- Loss-functions-ko.md | 42 ++++++++++++++++++++++++++++++++++++++++++ README-ko.md | 8 ++++---- 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 Loss-functions-ko.md diff --git a/Lab 1/README-ko.md b/Lab 1/README-ko.md index 610008c..85b53b4 100644 --- a/Lab 1/README-ko.md +++ b/Lab 1/README-ko.md @@ -56,7 +56,7 @@ Click **Create model** to create the model in your account ![record-composition](images/lab1-record.PNG) -Click *record* to start recording +녹음을 시작하려면 *record*를 클릭하세요. ![custom-input](images/lab1-custom-music.png) diff --git a/Loss-functions-ko.md b/Loss-functions-ko.md new file mode 100644 index 0000000..bd88a79 --- /dev/null +++ b/Loss-functions-ko.md @@ -0,0 +1,42 @@ +## Loss Function이란 무엇인가요? ## + +Loss function은 모델이 얼마나 정확하게 예측하는지에 대한 피드백을 네트워크에 제공함으로써, 딥러닝 알고리즘을 학습할 때 가장 중요한 구성 요소 중 하나입니다. "Loss function"은 일반적으로 ground truth를 포함한 하나의 학습 배치(batch)에 대해 네트워크에서 출력된 모든 값들을 loss(또는 예측의 부정확함)로 표현하는 단일 값에 매핑하는 수학 함수입니다. +Loss function의 값이 높을수록 일반적으로 알고리즘의 출력 예측이 실제와 크게 다르다는 것을 의미합니다. +Cross Entropy loss, Mean Squared Error 및 그 변형들이 가장 일반적으로 사용되는 loss function입니다. +CNN, RNN 또는 LSTM과 같은 일반적인 딥러닝 네트워크에서는 학습이 진행됨에 따라 loss 값이 감소할 것으로 예상되며, 이는 모델이 올바르게 학습하고 있음을 의미합니다. + +## GAN의 loss function은 어떻게 다른가요? ## + +GAN의 loss function은 위에서 설명한 일반 네트워크의 loss function과 다르지 않습니다. 그러나, GAN의 가장 중요한 속성은 2개의 네트워크가 별도로(또는 교대로) generator와 critic(discriminator)로 학습해야 한다는 것입니다. 결과적으로, 이들 네트워크 각각은 각각의 학습 동안 자신의 loss function을 가지게 됩니다. + +*__Critic loss function:__*: Critic 학습은 고양이와 개 클래스가 "실제"와 "가짜" 클래스로 대체된다는 점을 제외하고 고양이-개 감지기와 같은 모든 표준 알고리즘을 학습하는 것과 매우 유사합니다. Critic loss function은 실제 데이터가 "실제"로 분류되고 generator의 가짜 데이터가 한 번의 critic 학습에 대해 "가짜"로 얼마나 정확하게 분류되는지 평가합니다. Critic loss function은 generator의 "가짜" 데이터가 종종 critic에 의해 "실제"로 분류되어 generator에 의해 쉽게 속이는 것을 암시하는 경우 큰 값을 출력합니다. + +*__Generator loss function:__*: Generator 학습 중에 생성된 데이터가 이를 속일 만큼 현실적인지 확인하기 위해, 하나의 배치에 대한 generator의 출력이 critic에게 공급(feed into)됩니다. 잘 학습된 generator는 일반적으로 critic에게 생성된 데이터가 실제라고 믿게 하여 loss function score가 더 작아질 것이라고 속이는 것입니다. + +## GAN loss function들의 문제점은 무엇인가요?? ## + +Cross entropy와 같은 표준 loss function을 사용하는 경우, GAN loss function에서 많은 문제점들이 발생합니다. + +*__(1) Oscillating losses:__* 이전 섹션에서 언급했듯이 표준 고양이-개 감지기 유형 문제에서 학습이 진행됨에 따라 loss function 값이 감소할 것으로 예상합니다. 그러나 이것은 GAN에게는 해당되지 않습니다. Generator와 critic이 교대로 학습을 수행하기 때문에, 그들은 서로에 대해 "더 강하고" 더 "약하게" loss를 얻음으로써 loss값들의 진동이 일어납니다(oscillating). 이것은 학습이 전반적으로 잘 진행되었는지 여부와 generator에 의해 생성된 데이터가 충분한지 이해하기 어렵게 만듭니다. + +*__(2) Mode collapse:__* 종종, generator는 critic이 항상 속아넘거가데 되는 1개의 특정 출력에 대해 critic을 속이는 것을 학습합니다. 이렇게 되면 generator는 새로운 종류의 데이터를 학습하고 생성하려는 동기가 없어져 최적의 generator 되지 못한다. + +## Wasserstein loss function과 WGAN은 무엇인가요? ## + +위에서 논의된 문제는 Wasserstein loss라는 새로운 유형의 loss function로 극복되었으며, 이를 사용하는 GAN을 WGAN(Wasserstein GAN) 이라고 합니다. 실무에 적용 시에는 수학적으로 깊은 이해 없이, +Wasserstein loss가 주로 위에서 논의한 문제를 해결한다는 것을 아는 것으로 충분합니다. + +(1) Loss 값과 모델 학습 간에 상관 관계가 있도록 Loss function을 정의합니다. + +(2) GAN이 시간이 지남에 따라 안정적이 되도록 합니다. + +## Loss function은 DeepComposer에서 어떻게 작동하나요? ## + +GAN loss function 대해 언급한 모든 내용은 DeepComposer에도 적용되므로, DeepComposer 아키텍처에서도 Wasserstein loss function을 사용합니다. +그러나 Wasserstein loss function은 GAN에 잘 맞는 또 다른 유형의 loss function에 불과하기 때문에, DeepComposer에서 사용되는 loss function에 대해 명확히 이해하는 것이 중요합니다. +이를 염두에 두고, loss function이 DeepComposer 아키텍처 어떻게 관련되어 있는지 확인해 봅시다. + +*__(1) Critic loss function:__* Critic 학습 중에는 실제 데이터(멜로디가 있는 멀티 트랙 곡 + 학습 데이터셋의 반주)와 가짜 데이터(generator에 의해 생성된 악기 반주들에서 생성된 노래)의 2가지 타입 데이터가 필요합니다. +Loss function은 critic이 실제 노래를 "실제"로 식별하고 가짜 노래를 "가짜"로 얼마나 잘 식별할 수 있는지를 나타내는 값을 출력합니다. 값이 높으면 critic이 약하고 generator에 의해 쉽게 속이는 것을 나타내므로, 이 값은 critic의 학습을 개선하기 위한 피드백을 제공하는 데 사용됩니다. + +*__(2) Generator loss function:__* Generator 학습 중에 generator는 단일 멜로디 트랙을 입력으로 받아 멀티 트랙 곡을 출력합니다. 이 결과는 이제 critic(weight들이 동결된)에게 전달되어 critic이 실제 곡들의 분포 대비 얼마나 가깝게 생각하는지 알아봅니다. 높은 값을 산출하는 loss function은 critic이 올바르게 속지 않았음을 의미하므로, generator가 더 잘 학습하도록 페널티를 부여합니다. \ No newline at end of file diff --git a/README-ko.md b/README-ko.md index 4b955b2..737439f 100644 --- a/README-ko.md +++ b/README-ko.md @@ -11,15 +11,15 @@ AWS DeepComposer 워크샵에 오신 것을 환영합니다. 워크샵은 2개의 Lab으로 구성되어 있으며, Lab 진행 중 특정 task나 code cell의 수행 시간이 오래 소요될 때 Optional Reading의 내용을 읽어 보시는 것을 추천드립니다. -## [Lab 1: DeepComposer 모델로 음악 작곡하기](Lab%201) +## [Lab 1: DeepComposer 모델로 음악 작곡하기](./Lab%201/README-ko.md) -## [Lab 2: Amazon SageMaker로 사용자 정의(custom) GAN 모델 학습하기](Lab%202) +## [Lab 2: Amazon SageMaker로 사용자 정의(custom) GAN 모델 학습하기](./Lab%202/README-ko.md) # Optional Reading -## [GAN 아키텍처의 loss function](Loss-functions.md) +## [GAN 아키텍처의 loss function](Loss-functions-ko.md) -## [음악 용어](Music-terminologies.md) +## [음악 용어(Music Terminologies)](Music-terminologies-ko.md) ## [re:Invent DeepComposer 워크숍 장표(deck)](reinvent-workshop-deck) From 819884572cee9877b20474e9542d47416d72d666 Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 17:09:55 +0900 Subject: [PATCH 4/6] Fixed GAN-ko.ipynb --- Lab 2/GAN-ko.ipynb | 261 ++++++++++++++++++++++----------------------- 1 file changed, 129 insertions(+), 132 deletions(-) diff --git a/Lab 2/GAN-ko.ipynb b/Lab 2/GAN-ko.ipynb index 4816c8d..2de3fd7 100644 --- a/Lab 2/GAN-ko.ipynb +++ b/Lab 2/GAN-ko.ipynb @@ -11,13 +11,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This tutorial is a brief introduction to music generation using **Generative Adversarial Networks** (**GAN**s). \n", + "이 튜토리얼은 **Generative Adversarial Networks**(**GAN**)을 사용한 음악 생성에 대한 간략한 소개입니다.\n", "\n", - "The goal of this tutorial is to train a machine learning model using a dataset of Bach compositions so that the model learns to add accompaniments to a single track input melody. In other words, if the user provides a single piano track of a song such as \"twinkle twinkle little star\", the GAN model would add three other piano tracks to make the music sound more Bach-inspired.\n", + "이 튜토리얼의 목표는 모델이 싱글 트랙 입력 멜로디에 반주를 추가하는 방법을 배우도록 바흐(Bach) 컴포지션의 데이터셋을 사용하여 머신 러닝 모델을 학습하는 것입니다. 다시 말해, 사용자가 \"twinkle twinkle little star\"와 같은 노래의 싱글 피아노 트랙을 입력하는 경우, GAN 모델은 3개의 다른 피아노 트랙을 추가하여 음악 사운드를 보다 바흐 스타일과 가깝게 연주합니다.\n", "\n", - "The proposed algorithm consists of two competing networks: a generator and a critic (discriminator). A generator is a deep neural network that learns to create new synthetic data that resembles the distribution of the dataset on which it was trained. A critic is another deep neural network that is trained to differentiate between real and synthetic data. The generator and the critic are trained in alternating cycles such that the generator learns to produce more and more realistic data (Bach-like music in this use case) while the critic iteratively gets better at learning to differentiate real data (Bach music) from the synthetic ones.\n", + "제안된 알고리즘은 두 개의 경쟁 네트워크인 generator와 critic(discriminator)로 구성됩니다. Generator는 학습된 데이터셋의 분포와 유사한 새로운 합성 데이터를 생성하는 방법을 배우는 딥 뉴럴 네트워크입니다. Critic은 실제 데이터와 합성 데이터를 구별하도록 학습된 또 다른 딥 뉴럴 네트워크입니다. Generator와 critic은 교대 주기로 학습되어 generator는 점점 더 현실적인 데이터(이 사용 사례에서는 바흐와 같은 음악)를 생성하는 법을 배우고, critic은 실제 데이터(바흐 음악)와 합성 데이터를 구별하는 법을 더 잘 배우게 됩니다.\n", "\n", - "As a result, the quality of music produced by the generator gets more and more realistic with time." + "결과적으로, generator가 생성한 음악의 품질은 시간이 지날수록 더욱 현실감 있게 됩니다." ] }, { @@ -32,7 +32,8 @@ "metadata": {}, "source": [ "## Dependencies\n", - "First, let's import all of the python packages we will use throughout the tutorial.\n" + "\n", + "먼저, 본 튜토리얼에서 사용할 모든 파이썬 패키지들을 가져 오겠습니다." ] }, { @@ -114,7 +115,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Here we configure paths to retrieve our dataset and save our experiments." + "데이터셋을 검색하고 실험 결과를 저장하기 위한 경로를 설정합니다." ] }, { @@ -151,11 +152,11 @@ "source": [ "## Data Preparation\n", "\n", - "### Dataset summary\n", + "### 데이터셋 요약\n", "\n", - "In this tutorial, we use the [`JSB-Chorales-dataset`](http://www-etud.iro.umontreal.ca/~boulanni/icml2012), comprising 229 chorale snippets. A chorale is a hymn that is usually sung with a single voice playing a simple melody and three lower voices providing harmony. In this dataset, these voices are represented by four piano tracks.\n", + "이 튜토리얼에서는 229개의 코랄(chorale) snippet들로 구성된 [`JSB-Chorales-dataset`](http://www-etud.iro.umontreal.ca/~boulanni/icml2012)을 사용합니다. 코랄은 찬송가로 보통 싱글 멜로디를 연주하는 싱글 음색(voice)과 하모니를 제공하는 3개의 하위 음색으로 노래됩니다. 이 데이터셋에서 이 음색은 4개의 피아노 트랙으로 표시됩니다.\n", "\n", - "Let's listen to a song from this dataset." + "이 데이터셋의 노래를 한 번 들어 보겠습니다." ] }, { @@ -171,18 +172,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Data format - piano roll" + "### 데이터 포맷 - piano roll" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For the purpose of this tutorial, we represent music from the JSB-Chorales dataset in the piano roll format.\n", + "본 튜토리얼의 실습을 위해, JSB-Choales 데이터셋의 음악을 piano roll 포맷으로 표현해 보겠습니다.\n", "\n", - "**Piano roll** is a discrete representation of music which is intelligible by many machine learning algorithms. Piano rolls can be viewed as a two-dimensional grid with \"Time\" on the horizontal axis and \"Pitch\" on the vertical axis. A one or zero in any particular cell in this grid indicates if a note was played or not at that time for that pitch.\n", + "**Piano roll**은 음악을 머신 러닝 알고리즘들의 입력에 적용할 수 있게 변환한 이산적인(discrete) 표현이며, 가로 축에 \"시간(Time)\", 세로 축에 \"피치(Pitch)\"가 있는 2차원 격자입니다. 이 그리드의 특정 셀에서 1 또는 0은 해당 피치에 대해 음이 연주되었는지 여부를 나타냅니다.\n", "\n", - "Let us look at a few piano rolls in our dataset. In this example, a single piano roll track has 32 discrete time steps and 128 pitches. We see four piano rolls here, each one representing a separate piano track in the song." + "데이터셋에서 piano roll 몇 개를 살펴 보겠습니다. 이 예시에서, 싱글 piano roll 트랙은 32개의 이산적인 타임스텝(time step)과 128개의 피치를 갖습니다. 여기에는 4개의 piano roll들이 있는데, 각 piano roll은 노래에서 별도의 피아노 트랙을 나타냅니다." ] }, { @@ -191,24 +192,22 @@ "source": [ "\"Dataset\n", "\n", - "You might notice this representation looks similar to an image. While the sequence of notes is often the natural way that people view music, many modern machine learning models instead treat music as images and leverage existing techniques within the computer vision domain. You will see such techniques used in our architecture later in this tutorial." + "이 표현이 이미지(image)와 비슷하게 보일 수 있습니다. 일련의 음표가 사람들이 음악을 보는 자연스러운 방법인 경우가 많지만, 많은 현대 머신 러닝 모델들은 음악을 이미지로 취급하고 컴퓨터 비전 영역 내의 기존 기술을 활용합니다. 여러분은 이 튜토리얼의 뒷부분에서 Deepcomposer 아키텍처에 사용된 이러한 기술들을 보게 될 것입니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Why 32 time steps?**\n", - "\n", - "For the purpose of this tutorial, we sample two non-empty bars (https://en.wikipedia.org/wiki/Bar_(music)) from each song in the JSB-Chorales dataset. A **bar** (or **measure**) is a unit of composition and contains four beats for songs in our particular dataset (our songs are all in 4/4 time) :\n", + "**왜 32개의 타임 스텝인가요?**\n", "\n", - "We’ve found that using a resolution of four time steps per beat captures enough of the musical detail in this dataset.\n", + "이 튜토리얼에서는 JSB-Chorales 데이터셋의 각 노래에서 2개의 non-empty bar (https://en.wikipedia.org/wiki/Bar_(music)) 를 샘플링합니다. **Bar** (또는 **measure**)는 구성 단위이며 특정 데이터셋의 노래에 대한 4개의 비트(beat)를 포함합니다 (우리의 노래는 모두 4/4 time입니다).\n", "\n", - "This yields...\n", + "비트(beat) 당 4개의 타임 스텝 해상도를 사용하면 이 데이터셋의 음악적 세부 사항을 충분히 포착할 수 있으며, 이를 수식으로 표현하면 아래와 같습니다.\n", "\n", "$$ \\frac{4\\;timesteps}{1\\;beat} * \\frac{4\\;beats}{1\\;bar} * \\frac{2\\;bars}{1} = 32\\;timesteps $$\n", "\n", - "Let us now load our dataset as a numpy array. Our dataset comprises 229 samples of 4 tracks (all tracks are piano). Each sample is a 32 time-step snippet of a song, so our dataset has a shape of...\n", + "이제 데이터셋을 numpy 배열로 로드하겠습니다. 튜토리얼에서 사용할 데이터셋은 4개 트랙의 229개 샘플들로 구성됩니다(모든 트랙은 피아노입니다). 각 샘플은 노래의 32개 타임 스텝 snippet이므로 데이터셋의 크기는 다음과 같습니다.
\n", "(num_samples, time_steps, pitch_range, tracks) = (229, 32, 128, 4)." ] }, @@ -228,7 +227,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's see a sample of the data we'll feed into our model. The four graphs represent the four tracks." + "모델에 공급(feed into)할 데이터 샘플을 보도록 하겠습니다. 4개의 그래프는 4개의 트랙을 나타냅니다." ] }, { @@ -244,14 +243,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Load data " + "### 데이터 로드" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We now create a Tensorflow dataset object from our numpy array to feed into our model. The dataset object helps us feed batches of data into our model. A batch is a subset of the data that is passed through the deep learning network before the weights are updated. Batching data is necessary in most training scenarios as our training environment might not be able to load the entire dataset into memory at once." + "이제, numpy 배열에서 Tensorflow dataset 객체를 만들어 모델에 공급(feed into)해 보겠습니다. Dataset 객체는 모델에 데이터 배치를 공급하는 데 도움이 됩니다. 배치는 가중치가 업데이트되기 전에 딥 러닝 네트워크를 통해 전달되는 데이터의 하위 집합입니다. 학습 환경에서 전체 데이터셋을 한 번에 메모리에 로드하지 못할 수 있으므로, 대부분의 학습 시나리오에서 데이터 배치가 필요합니다." ] }, { @@ -300,21 +299,21 @@ "metadata": {}, "source": [ "## Model architecture\n", - "In this section, we will walk through the architecture of the proposed GAN.\n", + "이 섹션에서는 제안된 GAN의 아키텍처를 살펴 보겠습니다.\n", "\n", - "The model consists of two networks, a generator and a critic. These two networks work in a tight loop as following:\n", + "이 모델은 generator와 critic의 두 가지 네트워크로 구성됩니다. 이 두 네트워크는 다음과 같이 긴밀한(tight) 루프로 작동합니다.\n", "\n", - "* Generator:\n", - " 1. The generator takes in a batch of single-track piano rolls (melody) as the input and generates a batch of multi-track piano rolls as the output by adding accompaniments to each of the input music tracks. \n", - " 2. The critic then takes these generated music tracks and predicts how far it deviates from the real data present in your training dataset.\n", - " 3. This feedback from the critic is used by the generator to update its weights.\n", - "* Critic: As the generator gets better at creating better music accompaniments using the feedback from the critic, the critic needs to be retrained as well.\n", - " 1. Train the critic with the music tracks just generated by the generator as fake inputs and an equivalent number of songs from the original dataset as the real input. \n", - "* Alternate between training these two networks until the model converges and produces realistic music, beginning with the critic on the first iteration.\n", + "* Generator :\n", + "    1. Generator는 싱글 트랙 piano roll(멜로디) 배치를 입력으로 취하고, 각 입력 음악 트랙에 반주를 추가하여 출력으로 멀티 트랙 piano roll 배치를 생성합니다.\n", + "    2. 그러면 critic은 생성된 음악 트랙을 가져 와서 학습 데이터셋에 존재하는 실제 데이터와 얼마나 멀리 떨어져 있는지 예측합니다.\n", + "    3. Critic으로부터의 이 피드백은 가중치를 업데이트하기 위해 generator에서 사용됩니다.\n", + "* Critic : Generator가 critic의 피드백을 사용하여 더 좋은 음악 반주를 만드는 데 익숙해 짐에 따라, critic도 재학습이 필요합니다.\n", + "    1. Generator에서 방금 생성한 음악 트랙을 가짜 입력으로, 원래 데이터셋과 동일한 수의 노래들을 실제 입력으로 하여 비평가를 학습시킵니다.\n", + "* 첫 에포크(epoch)에 대한 critic부터 시작하여, 모델이 수렴하고 보다 사실적인 음악을 생성할 때까지 이 두 네트워크를 교대로 전환합니다.\n", "\n", - "We use a special type of GAN called the **Wasserstein GAN with Gradient Penalty** (or **WGAN-GP**) to generate music. While the underlying architecture of a WGAN-GP is very similar to vanilla variants of GAN, WGAN-GPs help overcome some of the commonly seen defects in GANs such as the vanishing gradient problem and mode collapse (see appendix for more details).\n", + "음악을 생성하기 위해, **Gradient Penalty가 있는 Wasserstein GAN** (또는 **WGAN-GP**)이라는 특별한 유형의 GAN을 사용합니다. WGAN-GP의 기본 아키텍처는 GAN의 vanilla 변형과 매우 유사하지만 WGAN-GP는 vanishing gradient 문제 및 mode collapse와 같이 GAN에서 일반적으로 보이는 결함들을 극복하는 데 도움이 됩니다 (자세한 내용은 appendix을 참조하세요).\n", "\n", - "Note our \"critic\" network is more generally called a \"discriminator\" network in the more general context of vanilla GANs." + "참고로, \"critic\" 네트워크는 vanilla GAN의 더 일반적인 맥락에서, 일반적으로 \"discriminator\" 네트워크라고 불립니다." ] }, { @@ -328,15 +327,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The generator is adapted from the U-Net architecture (a popular CNN that is used extensively in the computer vision domain), consisting of an “encoder” that maps the single track music data (represented as piano roll images) to a relatively lower dimensional “latent space“ and a ”decoder“ that maps the latent space back to multi-track music data.\n", + "이 generator는 U-Net 아키텍처(컴퓨터 비전 도메인에서 널리 사용되는 유명한 CNN)를 채택한 것으로, 싱글 트랙 음악 데이터(piano roll롤 이미지로 표현)를 비교적 저차원 \"latent 공간\"에 매핑하는 \"인코더(encoder)\"와 latent 공간을 다시 멀티 트랙 음악 데이터에 매핑하는 \"디코더(decoder)\"로 구성되어 있습니다.\n", "\n", - "Here are the inputs provided to the generator:\n", + "Generator의 입력 데이터는 다음과 같습니다.\n", "\n", - "**Single-track piano roll input**: A single melody track of size (32, 128, 1) => (TimeStep, NumPitches, NumTracks) is provided as the input to the generator. \n", + "**싱글 트랙 piano roll 입력**: \n", + "(32, 128, 1) => (TimeStep, NumPitches, NumTracks) 크기의 싱글 멜로디 트랙이 generator에 대한 입력으로 전달됩니다.\n", "\n", - "**Latent noise vector**: A latent noise vector z of dimension (2, 8, 512) is also passed in as input and this is responsible for ensuring that there is a distinctive flavor to each output generated by the generator, even when the same input is provided.\n", + "**Latent noise 벡터**: 차원 (2, 8, 512)의 latent noise 벡터 $z$도 입력으로 전달되며, 이는 동일한 입력이 전달되는 경우라도 generator에 의해 생성된 각 출력이 고유한 특징이 있는지 확인하는 역할을 합니다.\n", "\n", - "Notice from the figure below that the encoding layers of the generator on the left side and decoder layer on on the right side are connected to create a U-shape, thereby giving the name U-Net to this architecture." + "참고로, 아래 그림에서 왼쪽에 있는 generator의 인코더 레이어와 오른쪽에 있는 디코더 레이어가 연결되어 U자 모양을 만들기에, 이 아키텍처에 U-Net이라는 이름이 붙여졌습니다." ] }, { @@ -350,7 +350,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In this implementation, we build the generator following a simple four-level Unet architecture by combining `_conv2d`s and `_deconv2d`, where `_conv2d` compose the contracting path and `_deconv2d` forms the expansive path. " + "이 구현에서는 `_conv2d`와 `_deconv2d`를 결합하여, 간단한 4계층 U-Net 아키텍처를 따라 generator를 빌드합니다. 여기서 `_conv2d`는 contracting path를 구성하고 `_deconv2d`는 expansive path를 형성합니다." ] }, { @@ -414,7 +414,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now dive into each layer of the generator to see the inputs/outputs at each layer." + "이제 각 레이어(layer)의 입력/출력을 보기 위해, generator의 각 레이어를 살펴 보도록 하겠습니다." ] }, { @@ -439,9 +439,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The goal of the critic is to provide feedback to the generator about how realistic the generated piano rolls are, so that the generator can learn to produce more realistic data. The critic provides this feedback by outputting a scalar that represents how “real” or “fake” a piano roll is.\n", + "Critic의 목표는 생성된 piano roll이 얼마나 현실적인지 생성기에 피드백을 제공하여, Generator가 보다 현실적인 데이터를 생성하는 방법을 배울 수 있도록 하는 것입니다. Critic은 piano roll이 얼마나 \"실제\" 또는 \"가짜\"인지를 나타내는 스칼라(scalar)를 출력하여 이 피드백을 제공합니다.\n", "\n", - "Since the critic tries to classify data as “real” or “fake”, it is not very different from commonly used binary classifiers. We use a simple architecture for the critic, composed of four convolutional layers and a dense layer at the end." + "Critic은 데이터를 \"실제\" 또는 \"가짜\"로 분류하려고 시도하기 때문에, 일반적으로 사용되는 이진 분류기(binary classifier)와 크게 다르지 않습니다. \n", + "Critic은 4개의 convolution 레이어와 마지막 계층에 dense 레이어로 구성된 간단한 아키텍처를 사용합니다." ] }, { @@ -516,18 +517,19 @@ "source": [ "## Training\n", "\n", - "We train our models by searching for model parameters which optimize an objective function. For our WGAN-GP, we have special loss functions that we minimize as we alternate between training our generator and critic networks:\n", + "목적 함수(objective function)를 최적화하는 모델 파라메터를 검색하여 모델을 학습합니다. WGAN-GP에는 generator와 critic 네트워크를 번갈아 가며 교대 학습할 때, 목적 함수를 최소화하는 특수 loss function을 사용합니다.\n", "\n", "*Generator Loss:*\n", - "* We use the Wasserstein (Generator) loss function which is negative of the Critic Loss function. The generator is trained to bring the generated pianoroll as close to the real pianoroll as possible.\n", + "* Critic Loss 함수의 음수인 Wasserstein (Generator) loss function을 사용합니다. Generator는 생성된 piano roll을 가능한 한 실제 피아노 롤에 최대한 가깝게 하도록 학습됩니다.\n", " * $\\frac{1}{m} \\sum_{i=1}^{m} -D_w(G(z^{i}|c^{i})|c^{i})$\n", "\n", "*Critic Loss:*\n", "\n", - "* We begin with the Wasserstein (Critic) loss function designed to maximize the distance between the real piano roll distribution and generated (fake) piano roll distribution.\n", + "* 먼저 실제 piano roll 확률 분포와 생성된(가짜) piano roll 확률 분포 사이의 거리를 최대화하도록 설계된 Wasserstein (Critic) loss function을 적용합니다.\n", + "\n", " * $\\frac{1}{m} \\sum_{i=1}^{m} [D_w(G(z^{i}|c^{i})|c^{i}) - D_w(x^{i}|c^{i})]$\n", "\n", - "* We add a gradient penalty loss function term designed to control how the gradient of the critic with respect to its input behaves. This makes optimization of the generator easier. \n", + "* 입력 데이터에 대한 critic의 gradient가 어떻게 행동하는지 제어하기 위해 고안된 gradient penalty loss function 항을 추가합니다. 이것은 Generator의 최적화를 더 쉽게 합니다.\n", " * $\\frac{1}{m} \\sum_{i=1}^{m}(\\lVert \\nabla_{\\hat{x}^i}D_w(\\hat{x}^i|c^{i}) \\rVert_2 - 1)^2 $" ] }, @@ -578,7 +580,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With our loss functions defined, we associate them with Tensorflow optimizers to define how our model will search for a good set of model parameters. We use the *Adam* algorithm, a commonly used general-purpose optimizer. We also set up checkpoints to save our progress as we train." + "Loss function이 정의된 상태에서 적절한 모델 파라메터 셋을 검색하는 방법을 정의하기 위해 Tensorflow optimizers 클래스를 사용합니다. 본 튜토리얼에서는 일반적으로 사용되는 범용 최적화 기법인 *Adam* 알고리즘을 사용합니다. 또한 학습 시 진행 상황을 저장하기 위한 체크포인트(Checkpoint)도 설정합니다." ] }, { @@ -603,7 +605,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now we define the `generator_train_step` and `critic_train_step` functions, each of which performs a single forward pass on a batch and returns the corresponding loss." + "이제 `generator_train_step` 및 `critic_train_step` 함수를 정의합니다. 각 함수는 배치에서 단일 forward pass를 수행하고 해당 loss를 리턴합니다." ] }, { @@ -696,7 +698,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Before we begin training, let's define some training configuration parameters and prepare to monitor important quantities. Here we log the losses and metrics which we can use to determine when to stop training. Consider coming back here to tweak these parameters and explore how your model responds. " + "학습을 시작하기 전에 몇 가지 학습 설정 파라메터들를 정의하고 주요 정량적 지표들을 모니터링할 준비를 하겠습니다. 여기에서 학습 중단시기를 결정하는 데 사용할 수 있는 loss 및 metric을 기록합니다. 이 파라메터들을 조정하고 모델이 어떻게 반응하는지 알아 보려면 이 코드 셀(Code shell)로 돌아와 주세요." ] }, { @@ -731,7 +733,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now train our model!" + "이제 모델을 학습해 보겠습니다!" ] }, { @@ -800,46 +802,50 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### We have started training!\n", + "### 이제 학습을 시작했습니다!\n", + "\n", + "Wasserstein loss function을 사용할 때, 여러분은 critic을 수렴하도록(generator 업데이트의 gradient가 정확한 지의 여부를 확인) 학습시켜야 합니다. 이는 vanishing gradient를 피하기 위해 critic이 너무 강해지지 않도록 하는 것이 중요한 표준 GAN과는 대조적입니다.\n", + "\n", + "따라서 Wasserstein loss를 사용하면 GAN 학습의 주요 어려움들 중 하나인 discriminator와 generator 학습의 균형을 맞추는 방법이 제거됩니다. WGAN을 사용하면 generator 업데이트 간에 여러 번 critic을 학습시켜 수렴에 가깝게 만들 수 있습니다. 일반적으로 사용되는 비율은 1번 generator 업데이트 시, 5번의 critic 업데이트를 수행하는 것입니다.\n", "\n", - "When using the Wasserstein loss function, we should train the critic to converge to ensure that the gradients for the generator update are accurate. This is in contrast to a standard GAN, where it is important not to let the critic get too strong, to avoid vanishing gradients.\n", "\n", - "Therefore, using the Wasserstein loss removes one of the key difficulties of training GANs—how to balance the training of the discriminator and generator. With WGANs, we can simply train the critic several times between generator updates, to ensure it is close to convergence. A typical ratio used is five critic updates to one generator update.\n", + "### 학습 과정 모니터링\n", "\n", - "### \"Babysitting\" the learning process\n", + "이러한 모델을 학습 시 시간과 리소스가 많이 소요되므로, 예외가 발생하는 경우 이상점들(anomalies)을 포착하고 해결하기 위해 지속적으로 학습 과정을 모니터링해야 합니다. 주의해야 할 사항들은 다음과 같습니다.\n", "\n", - "Given that training these models can be an investment in time and resources, we must to continuously monitor training in order to catch and address anomalies if/when they occur. Here are some things to look out for:\n", + "**Loss는 어떻게 보이나요?**\n", "\n", - "**What should the losses look like?**\n", + "Adversarial 학습 과정은 매우 역동적이고 고주파 진동 현상이 매우 일반적입니다. 그러나 Loss(critic 또는 generator)가 큰 값으로 급등하거나 0으로 급락하거나 단일 값에 정체되어 있으면, 어딘가에 문제가 있을 수 있습니다.\n", "\n", - "The adversarial learning process is highly dynamic and high-frequency oscillations are quite common. However if either loss (critic or generator) skyrockets to huge values, plunges to 0, or get stuck on a single value, there is likely an issue somewhere.\n", + "**모델이 정상적으로 학습 중인가요?**\n", "\n", - "**Is my model learning?**\n", - "- Monitor the critic loss and other music quality metrics (if applicable). Are they following the expected trajectories?\n", - "- Monitor the generated samples (piano rolls). Are they improving over time? Do you see evidence of mode collapse? Have you tried listening to your samples?\n", + "- 가능한 경우, Critic loss 및 기타 음악 품질 지표들을 모니터링합니다. 예상 궤도를 따르고 있습니까?\n", + "- 생성된 샘플들(piano rolls)을 모니터링합니다. 이들이 시간이 지남에 따라 개선되고 있나요? mode collapse 현상이 보이나요? 샘플들을 직접 들어 보셨나요? \n", "\n", - "**How do I know when to stop?**\n", - "- If the samples meet your expectations\n", - "- Critic loss no longer improving\n", - "- The expected value of the musical quality metrics converge to the corresponding expected value of the same metric on the training data" + "**언제 중지해야 하는지 어떻게 알 수 있나요?**\n", + "\n", + "- 샘플이 기대치를 충족시키는 경우\n", + "- Critic loss가 더 이상 개선되지 않을 경우\n", + "- 음악 품질 지표의 기대값(expected value)이 학습 데이터에 대한 동일한 지표의 해당 기대값에 수렴 시" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### How to measure sample quality during training \n", + "### 학습 중 샘플 품질을 측정하는 방법\n", + "\n", + "일반적으로 모든 종류의 신경망을 학습할 때는 학습 기간 동안 loss function 값을 모니터링하는 것이 표준 관행입니다. WGAN의 critic loss은 샘플 품질과 밀접한 관련이 있는 것으로 밝혀졌습니다.\n", "\n", - "Typically, when training any sort of neural networks, it is standard practice to monitor the value of the loss function throughout the duration of the training. The critic loss in WGANs has been found to correlate well with sample quality.\n", + "분류 또는 회귀와 같은 보다 전통적인(traditional) 모델의 정확도를 평가하기 위한 표준 메커니즘이 존재하지만, generative 모델을 평가하는 것은 활발한 연구 분야이며 음악 생성 도메인 내에서는 더 어렵습니다.\n", "\n", - "While standard mechanisms exist for evaluating the accuracy of more traditional models like classifiers or regressors, evaluating generative models is an active area of research. Within the domain of music generation, this hard problem is even less well-understood.\n", + "이 문제를 해결하기 위해, 데이터에 대한 높은 수준의 측정들을 수행하고 모델이 이러한 측정치들에 맞는 음악을 얼마나 잘 생성하는지 확인해 보겠습니다. 만약 어려분의 모델이 학습 데이터셋에 대해 이러한 측정의 평균값(mean value)에 가까운 음악을 생성한다면, 음악은 일반적인 “모양(shape)” 과 일치해야 합니다.\n", "\n", - "To address this, we take high-level measurements of our data and show how well our model produces music that aligns with those measurements. If our model produces music which is close to the mean value of these measurements for our training dataset, our music should match on general “shape”.\n", + "다음과 같은 세 가지 측정들을 살펴 보겠습니다.\n", "\n", - "We’ll look at three such measurements:\n", - "- **Empty bar rate:** The ratio of empty bars to total number of bars.\n", - "- **Pitch histogram distance:** A metric that captures the distribution and position of pitches.\n", - "- **In Scale Ratio:** Ratio of the number of notes that are in C major key, which is a common key found in music, to the total number of notes. \n" + "- **Empty bar rate:** 총 bar 대비 empty bar의 비율입니다.\n", + "- **Pitch histogram distance:** 피치(pitch)의 분포와 위치를 캡처하는 지표입니다.\n", + "- **In Scale Ratio:** 음악에서 발견되는 공통 키인 C 메이저 키에 있는 노트 수와 총 노트 수의 비율입니다." ] }, { @@ -848,17 +854,18 @@ "source": [ "## Evaluate results\n", "\n", - "Now that we have finished training, let's find out how we did. We will analyze our model in several ways:\n", - "1. Examine how the generator and critic losses changed while training\n", - "2. Understand how certain musical metrics changed while training\n", - "3. Visualize generated piano roll output for a fixed input at every iteration and create a video\n" + "학습이 완료되었으니 모델을 평가해 봅시다. 여러분은 다양한 방법들로 모델을 분석할 수 있습니다.\n", + "\n", + "1. 학습하는 동안 generator와 critic 손실이 어떻게 변했는지 조사\n", + "2. 학습하는 동안 특정 음악 지표가 어떻게 변경되었는지 분석\n", + "3. 매 iteration마다 고정 입력값을 위해 생성된 piano roll 출력 시각화 및 비디오 생성" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first restore our last saved checkpoint. If you did not complete training but still want to continue with a pre-trained version, set `TRAIN = False`." + "마지막으로 저장된 체크포인트를 먼저 복원하겠습니다. 학습을 완료하지 않았지만 사전 학습된(pre-trained) 버전으로 계속하려면 `TRAIN = False`로 설정하세요." ] }, { @@ -894,7 +901,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Observe how the critic loss (C_loss in the graph) decays to zero as we train. In WGAN-GPs, the critic loss decreases (almost) monotonically as you train." + "학습하면서 critic loss(그래프의 C_loss)가 어떻게 0으로 감소하는지 관찰해 보세요. WGAN-GP에서는 학습할 때 critic loss가 거의 단조(monotonically) 감소합니다." ] }, { @@ -918,19 +925,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Each row here corresponds to a different music quality metric and each column denotes an instrument track. \n", + "여기의 각 행은 서로 다른 음악 품질 지표에 해당하며 각 열은 악기 트랙(instrument track)을 나타냅니다.\n", "\n", - "Observe how the expected value of the different metrics (blue scatter) approach the corresponding training set expected values (red) as the number of iterations increase. You might expect to see diminishing returns as the model converges.\n" + "Iteration 횟수가 증가함에 따라 서로 다른 지표의 기대값(파란색 scatter)이 해당 학습셋의 기대값(빨간색)에 어떻게 가까워지는지 관찰해 보세요. 모델이 수렴함에 따라 리턴값이 감소함을 기대할 수 있습니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Generated samples during training\n", - "\n", - "The function below helps you probe intermediate samples generated in the training process. Remember that the conditioned input here is sampled from our training data. Let's start by listening to and observing a sample at iteration 0 and then iteration 100. Notice the difference!\n", - "\n" + "### 학습 중 생성된 샘플\n", + "아래 Code cell은 학습 과정에서 생성된 중간 샘플들을 조사하는 데 도움이 됩니다. 여기서 조건부 입력(conditioned input)은 학습 데이터에서 샘플링됩니다. Iteration 0과 iteration 100에서 샘플을 듣고 관찰하는 것으로 시작하겠습니다. 차이점을 주목해 주세요!" ] }, { @@ -961,7 +966,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's see how the generated piano rolls change with the number of iterations." + "생성된 piano roll이 iteration 횟수에 따라 어떻게 변하는 지 확인해 봅니다." ] }, { @@ -991,9 +996,8 @@ "source": [ "### Generating accompaniment for custom input\n", "\n", - "Congratulations! You have trained your very own WGAN-GP to generate music. Let us see how our generator performs on a custom input.\n", - "\n", - "The function below generates a new song based on \"Twinkle Twinkle Little Star\"." + "축하합니다! 음악을 생성하도록 사용자 정의 WGAN-GP를 학습했습니다. Generator가 사용자 정의 입력(custom input)에서 어떻게 수행되는지 확인해 보세요.\n", + "아래 Code cell은 \"Twinkle Twinkle Little Star\"를 기반으로 새 노래를 생성합니다." ] }, { @@ -1020,7 +1024,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can also take a look at the generated piano rolls for a certain sample, to see how diverse they are!" + "또한 특정 샘플에 대해 생성된 piano roll들을 보고 얼마나 다양한 지 확인할 수 있습니다!" ] }, { @@ -1043,15 +1047,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Using your own data (Optional)\n", - "\n" + "### (Optional) 사용자 정의 데이터 사용" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "To create your own dataset you can extract the piano roll from MIDI data. An example of creating a piano roll from a MIDI file is given below" + "사용자 정의 데이터셋을 만들려면 MIDI 데이터에서 piano roll을 추출할 수 있습니다. MIDI 파일에서 pinao roll을 만드는 예는 다음과 같습니다." ] }, { @@ -1081,18 +1084,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Open source implementations\n", - "For more open-source implementations of generative models for music, check out:\n", + "### 오픈 소스 구현\n", + "음악에 대한 generative 모델의 오픈 소스 구현에 대해서는 아래 링크들을 확인하세요.\n", "\n", - "- [MuseGAN](https://github.com/salu133445/musegan): Official TensorFlow Implementation that uses GANs to generate multi track polyphonic music\n", - "- [GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): GANSynth uses a Progressive GAN architecture to incrementally upsample with convolution from a single vector to the full audio spectrogram\n", - "- [Music Transformer](https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): Uses transformers to generate music!\n", + "-[MuseGAN](https://github.com/salu133445/musegan): GAN을 사용하여 멀티 트랙 폴리포닉(polyphonic) 음악을 생성하는 공식 TensorFlow 구현\n", + "-[GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): 프로그레시브 GAN 아키텍처를 사용하여 단일 벡터에서 전체 오디오 스펙트로그램(spectrogram)으로 컨볼루션을 사용하여 업샘플링\n", + "-[Music Transformer] (https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): 트랜스포머(Transformer)를 사용하여 음악 생성\n", "\n", - "GANs have also achieved state of the generative modeling in several other domains including cross domain image tranfer, celebrity face generation, super resolution text to image and image inpainting.\n", + "GAN은 또한 도메인 간 이미지 이동, 유명인사 얼굴 생성, 이미지에 대한 초고해상도 텍스트, 이미지 inpainting을 포함한 여러 도메인에서 성과를 보이고 있습니다.\n", "\n", - "- [Keras-GAN](https://github.com/eriklindernoren/Keras-GAN): Library of reference implementations in Keras for image generation(good for educational purposes).\n", + "-[Keras-GAN] (https://github.com/eriklindernoren/Keras-GAN): 이미지 생성을 위한 Keras의 참조 구현 라이브러리(교육 목적에 적합).\n", "\n", - "There's an ocean of literatures out there that use GANs for modeling distributions across fields! If you are interested, [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo) is a good place to start." + "여러 분야들에 대한 확률 분포를 모델링하기 위해 GAN을 사용하는 문헌들이 많이 있습니다! 관심이 있으시면 [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo)에서 시작해 보세요" ] }, { @@ -1111,56 +1114,50 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### More on Wassertein GAN with Gradient Penalty (optional)\n", + "### (Optional) Wassertein GAN with Gradient Penalty에 대한 보충 내용\n", "\n", - "While GANs are a major breakthrough for generative modeling, plain GANs are also notoriously difficult to train. Some common problems encountered are:\n", + "GAN은 generative 모델링을 위한 주요 혁신이지만, 일반(plain) GAN도 학습하기가 어렵습니다. 몇 가지 일반적인 문제들은 다음과 같습니다.\n", "\n", - "* **Oscillating loss:** The loss of the discriminator and generator can start to oscillate without exhibiting any long term stability.\n", - "* **Mode collapse:** The generator may get stuck on a small set of samples that always fool the discriminator. This reduces the capability of the network to produce novel samples.\n", - "* **Uninformative loss:** The lack of correlation between the generator loss and quality of generated output makes plain GAN training difficult to interpret.\n", + "* **Oscillating loss:** Discriminator와 generator의 loss는 장기적인 안정성을 나타내지 않고 진동하기 시작할 수 있습니다.\n", + "* **Mode collapse:** Generator는 항상 discriminator를 속이는 작은 샘플셋에 갇힐 수 있습니다. 이것은 새로운 샘플을 생성하는 네트워크의 능력을 감소시킵니다.\n", + "* **Uninformative loss:** Generator loss와 생성된 출력 데이터의 품질 사이에 상관 관계가 없기 때문에, 일반 GAN 학습을 해석하기가 어렵습니다.\n", "\n", + "[Wasserstein GAN](#references)은 GAN의 주요 발전으로 이러한 문제들 중 일부를 완화하는 데 도움이 되었습니다. 그 기능들 중 일부는 다음과 같습니다.\n", "\n", - "The [Wasserstein GAN](#references) was a major advancement in GANs and helped mitigate to some of these issues. Some of its features are:\n", + "1. Loss function의 해석성을 크게 개선하고 보다 명확한 학습 중단 기준(stopping criteria)을 제공합니다.\n", + "2. WGAN은 일반적으로 더 고품질의 결과를 생성하며, 이는 이미지 생성 도메인에서 실험으로 확인되었습니다.\n", "\n", - "1. It significantly improves the interpretability of loss functions and provides clearer stopping criteria\n", - "2. WGANs generally produce results of higher quality (demonstrated within the image generation domain)\n", + "**Wasserstein GAN with Gradient Penalty의 수학적 내용**\n", "\n", - "**Mathematics of Wasserstein GAN with Gradient Penalty**\n", - "\n", - "The [Wasserstein distance](https://en.wikipedia.org/wiki/Wasserstein_metric) between the true distribution $P_r$ and generated piano roll distribution $P_g$ is defined as follows:\n", + "실제 분포 $P_r$와 생성된 piano roll 분포 $P_g$ 사이의 [Wasserstein distance](https://en.wikipedia.org/wiki/Wasserstein_metric)는 다음과 같이 정의됩니다.\n", "\n", "$$\\mathbb{W}(P_{r},P_{g})=\\sup_{\\lVert{f} \\rVert_{L} \\le 1} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(f(x)) - \\mathbb{E}_{x \\sim \\mathbb{P}_g}(f(x)) $$\n", "\n", - "In this equation we are trying to minimize the distance between the expectation of the real distribution and the expectation of the generation distribution. $f$ is subject to a technical constraint in that it must be [1-Lipschitz](https://en.wikipedia.org/wiki/Lipschitz_continuity).\n", + "이 수식에서 우리는 실제 분포의 기대값과 생성 분포의 기대값 사이의 거리를 최소화하려고 합니다. 이 때, $f$는 [1-Lipschitz](https://en.wikipedia.org/wiki/Lipschitz_continuity) 여야 한다는 기술적 제약이 따릅니다.\n", "\n", - "To enforce the 1-Lipschitz condition that basically constraints the gradients from varying too rapidly we use the gradient penalty.\n", + "Gradient가 너무 빠르게 변하는 것을 기본적으로 제한하는 1-Lipschitz 조건을 강제하기 위해 gradient penalty를 사용합니다.\n", "\n", - "**Gradient penalty**: We want to penalize the gradients of the critic. We implicitly define $P_{\\hat{x}}$ by sampling uniformly along straight lines between pairs of points sampled from the data distribution $P_r$ and the generator distribution $P_g$. This was originally motivated by the fact that the optimal critic contains straight lines with gradient norm 1 connecting coupled points from $P_r$ and $P_g$. We use a penalty coefficient $\\lambda$= 10 as was recommended in the original paper. \n", + "**Gradient penalty** : 우리는 critic의 gradient에 핸디캡을 부여하고 싶습니다. 데이터 분포 $P_r$와 생성자 분포 $P_g$에서 샘플링된 점 쌍(pairs of points) 사이의 직선을 따라 균일하게 샘플링하여 $P_{\\hat{x}}$를 암시적으로(implicitly) 정의합니다. 이것은 최적의 critic이 $P_r$와 $P_g$의 결합 점을 연결하는 gradient norm 1을 가진 직선을 포함한다는 사실에 의해 모티베이션을 받은 것입니다. 본 구현에서는 원래 논문에서 권장한 penalty coefficient $\\lambda = 10$을 사용합니다.\n", "\n", - "The loss with gradient penalty is:\n", + "Gradient penalty로 인한 loss는 다음과 같습니다.\n", "\n", "$$\\mathbb{L}(P_{r},P_{g},P_{\\hat{x}} )= \\mathbb{W}(P_{r},P_{g}) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D(\\hat{x}) \\rVert_2 - 1)^2]$$\n", - "|\n", - "This loss can be parametrized in terms of $w$ and $\\theta$. We then use neural networks to learn the functions $f_w$ (discriminator) and $g_\\theta$ (generator).\n", + "\n", + "이 loss는 $w$ 및 $\\theta$로 매개변수화할 수 있습니다. 그런 다음, 신경망을 사용하여 $f_w$ (discriminator) 와 $g_\\theta$ (generator) functrion을 학습합니다.\n", + "\n", "$$\\mathbb{W}(P_{r},P_{\\theta})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) $$\n", "$$\\mathbb{L}(P_{r},P_{\\theta},P_{\\hat{x}})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D_w(\\hat{x}) \\rVert_2 - 1)^2]$$\n", "\n", - "where $$ \\hat{x} = \\epsilon x + (1- \\epsilon) G(z) $$ and $$\\epsilon \\sim Unif(0,1)$$\n", + "이 때, $\\hat{x}$과 $\\epsilon$은 아래와 같습니다. $$ \\hat{x} = \\epsilon x + (1- \\epsilon) G(z), \\;\\; \\epsilon \\sim Unif(0,1)$$\n", "\n", - "The basic procedure to train is as following: \n", - "1. We draw real_x from the real distribution $P_r$ and fake_x from the generated distribution $G_{\\theta}(z)$ where $z \\sim p(z)$\n", - "2. The latent vectors are sampled from z and then tranformed using the generator $G_{\\theta}$ to get the fake samples fake_x. They are evaluated using the critic function $D_w$\n", - "3. We are trying to minimize the Wasserstein distance between the two distributions\n", "\n", - "Both the generator and critic are conditioned on the input pianoroll melody." + "학습 기본 절차는 다음과 같습니다.\n", + "1. 실제 분포 $P_r$에서 real_x를 추출하고 생성된 분포 $G_{\\theta}(z)$에서 fake_x를 추출합니다. ($z \\sim p(z)$)\n", + "2. z에서 latent vector들을 샘플링한 다음, $G_{\\theta}$ generator로 변환하여 가짜 샘플 fake_x를 얻습니다. 변환된 샘플들은 Critic function $D_w$에 의해 평가됩니다.\n", + "3. 두 분포 사이의 Wasserstein distance를 최소화합니다.\n", + "\n", + "generator와 critic은 모두 입력 piano roll 멜로디에서 조절됩니다." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1179,7 +1176,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.6.5" } }, "nbformat": 4, From e3a98c9f2bcefcbe73d6bbb3dcef11a4e3451937 Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 17:47:44 +0900 Subject: [PATCH 5/6] Fixed GAN-ko.ipynb --- Lab 2/GAN-ko.ipynb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Lab 2/GAN-ko.ipynb b/Lab 2/GAN-ko.ipynb index 2de3fd7..1c2b990 100644 --- a/Lab 2/GAN-ko.ipynb +++ b/Lab 2/GAN-ko.ipynb @@ -304,11 +304,11 @@ "이 모델은 generator와 critic의 두 가지 네트워크로 구성됩니다. 이 두 네트워크는 다음과 같이 긴밀한(tight) 루프로 작동합니다.\n", "\n", "* Generator :\n", - "    1. Generator는 싱글 트랙 piano roll(멜로디) 배치를 입력으로 취하고, 각 입력 음악 트랙에 반주를 추가하여 출력으로 멀티 트랙 piano roll 배치를 생성합니다.\n", - "    2. 그러면 critic은 생성된 음악 트랙을 가져 와서 학습 데이터셋에 존재하는 실제 데이터와 얼마나 멀리 떨어져 있는지 예측합니다.\n", - "    3. Critic으로부터의 이 피드백은 가중치를 업데이트하기 위해 generator에서 사용됩니다.\n", - "* Critic : Generator가 critic의 피드백을 사용하여 더 좋은 음악 반주를 만드는 데 익숙해 짐에 따라, critic도 재학습이 필요합니다.\n", - "    1. Generator에서 방금 생성한 음악 트랙을 가짜 입력으로, 원래 데이터셋과 동일한 수의 노래들을 실제 입력으로 하여 비평가를 학습시킵니다.\n", + " 1. Generator는 싱글 트랙 piano roll(멜로디) 배치를 입력으로 취하고, 각 입력 음악 트랙에 반주를 추가하여 출력으로 멀티 트랙 piano roll 배치를 생성합니다.\n", + " 2. 그러면 critic은 생성된 음악 트랙을 가져 와서 학습 데이터셋에 존재하는 실제 데이터와 얼마나 멀리 떨어져 있는지 예측합니다.\n", + " 3. Critic으로부터의 이 피드백은 가중치를 업데이트하기 위해 generator에서 사용됩니다.\n", + "- Critic : Generator가 critic의 피드백을 사용하여 더 좋은 음악 반주를 만드는 데 익숙해 짐에 따라, critic도 재학습이 필요합니다.\n", + " 1. Generator에서 방금 생성한 음악 트랙을 가짜 입력으로, 원래 데이터셋과 동일한 수의 노래들을 실제 입력으로 하여 비평가를 학습시킵니다.\n", "* 첫 에포크(epoch)에 대한 critic부터 시작하여, 모델이 수렴하고 보다 사실적인 음악을 생성할 때까지 이 두 네트워크를 교대로 전환합니다.\n", "\n", "음악을 생성하기 위해, **Gradient Penalty가 있는 Wasserstein GAN** (또는 **WGAN-GP**)이라는 특별한 유형의 GAN을 사용합니다. WGAN-GP의 기본 아키텍처는 GAN의 vanilla 변형과 매우 유사하지만 WGAN-GP는 vanishing gradient 문제 및 mode collapse와 같이 GAN에서 일반적으로 보이는 결함들을 극복하는 데 도움이 됩니다 (자세한 내용은 appendix을 참조하세요).\n", @@ -819,7 +819,7 @@ "\n", "**모델이 정상적으로 학습 중인가요?**\n", "\n", - "- 가능한 경우, Critic loss 및 기타 음악 품질 지표들을 모니터링합니다. 예상 궤도를 따르고 있습니까?\n", + "- 가능한 경우, Critic loss 및 기타 음악 품질 지표들을 모니터링합니다. 예상 궤도를 따르고 있나요?\n", "- 생성된 샘플들(piano rolls)을 모니터링합니다. 이들이 시간이 지남에 따라 개선되고 있나요? mode collapse 현상이 보이나요? 샘플들을 직접 들어 보셨나요? \n", "\n", "**언제 중지해야 하는지 어떻게 알 수 있나요?**\n", @@ -977,7 +977,6 @@ "source": [ "from IPython.display import Video\n", "\n", - "\n", "display_utils.make_training_video(train_dir)\n", "video_path = \"movie.mp4\"\n", "Video(video_path)" @@ -1087,13 +1086,13 @@ "### 오픈 소스 구현\n", "음악에 대한 generative 모델의 오픈 소스 구현에 대해서는 아래 링크들을 확인하세요.\n", "\n", - "-[MuseGAN](https://github.com/salu133445/musegan): GAN을 사용하여 멀티 트랙 폴리포닉(polyphonic) 음악을 생성하는 공식 TensorFlow 구현\n", - "-[GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): 프로그레시브 GAN 아키텍처를 사용하여 단일 벡터에서 전체 오디오 스펙트로그램(spectrogram)으로 컨볼루션을 사용하여 업샘플링\n", - "-[Music Transformer] (https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): 트랜스포머(Transformer)를 사용하여 음악 생성\n", + "- [MuseGAN](https://github.com/salu133445/musegan): GAN을 사용하여 멀티 트랙 폴리포닉(polyphonic) 음악을 생성하는 공식 TensorFlow 구현\n", + "- [GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): 프로그레시브 GAN 아키텍처를 사용하여 단일 벡터에서 전체 오디오 스펙트로그램(spectrogram)으로 컨볼루션을 사용하여 업샘플링\n", + "- [Music Transformer] (https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): 트랜스포머(Transformer)를 사용하여 음악 생성\n", "\n", "GAN은 또한 도메인 간 이미지 이동, 유명인사 얼굴 생성, 이미지에 대한 초고해상도 텍스트, 이미지 inpainting을 포함한 여러 도메인에서 성과를 보이고 있습니다.\n", "\n", - "-[Keras-GAN] (https://github.com/eriklindernoren/Keras-GAN): 이미지 생성을 위한 Keras의 참조 구현 라이브러리(교육 목적에 적합).\n", + "- [Keras-GAN](https://github.com/eriklindernoren/Keras-GAN): 이미지 생성을 위한 Keras의 참조 구현 라이브러리(교육 목적에 적합).\n", "\n", "여러 분야들에 대한 확률 분포를 모델링하기 위해 GAN을 사용하는 문헌들이 많이 있습니다! 관심이 있으시면 [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo)에서 시작해 보세요" ] From e0af71669990c45470a6b4a31d1482d7e6e7a304 Mon Sep 17 00:00:00 2001 From: Daekeun Kim Date: Sun, 2 Feb 2020 17:59:53 +0900 Subject: [PATCH 6/6] Fixed typos --- Lab 2/GAN-ko.ipynb | 4 ++-- Loss-functions-ko.md | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lab 2/GAN-ko.ipynb b/Lab 2/GAN-ko.ipynb index 1c2b990..6b65d70 100644 --- a/Lab 2/GAN-ko.ipynb +++ b/Lab 2/GAN-ko.ipynb @@ -1088,13 +1088,13 @@ "\n", "- [MuseGAN](https://github.com/salu133445/musegan): GAN을 사용하여 멀티 트랙 폴리포닉(polyphonic) 음악을 생성하는 공식 TensorFlow 구현\n", "- [GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): 프로그레시브 GAN 아키텍처를 사용하여 단일 벡터에서 전체 오디오 스펙트로그램(spectrogram)으로 컨볼루션을 사용하여 업샘플링\n", - "- [Music Transformer] (https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): 트랜스포머(Transformer)를 사용하여 음악 생성\n", + "- [Music Transformer](https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): 트랜스포머(Transformer)를 사용하여 음악 생성\n", "\n", "GAN은 또한 도메인 간 이미지 이동, 유명인사 얼굴 생성, 이미지에 대한 초고해상도 텍스트, 이미지 inpainting을 포함한 여러 도메인에서 성과를 보이고 있습니다.\n", "\n", "- [Keras-GAN](https://github.com/eriklindernoren/Keras-GAN): 이미지 생성을 위한 Keras의 참조 구현 라이브러리(교육 목적에 적합).\n", "\n", - "여러 분야들에 대한 확률 분포를 모델링하기 위해 GAN을 사용하는 문헌들이 많이 있습니다! 관심이 있으시면 [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo)에서 시작해 보세요" + "여러 분야들에 대한 확률 분포를 모델링하기 위해 GAN을 사용하는 문헌들이 많이 있습니다! 관심이 있으시면 [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo)에서 시작해 보세요." ] }, { diff --git a/Loss-functions-ko.md b/Loss-functions-ko.md index bd88a79..ab2cf88 100644 --- a/Loss-functions-ko.md +++ b/Loss-functions-ko.md @@ -7,23 +7,23 @@ CNN, RNN 또는 LSTM과 같은 일반적인 딥러닝 네트워크에서는 학 ## GAN의 loss function은 어떻게 다른가요? ## -GAN의 loss function은 위에서 설명한 일반 네트워크의 loss function과 다르지 않습니다. 그러나, GAN의 가장 중요한 속성은 2개의 네트워크가 별도로(또는 교대로) generator와 critic(discriminator)로 학습해야 한다는 것입니다. 결과적으로, 이들 네트워크 각각은 각각의 학습 동안 자신의 loss function을 가지게 됩니다. +GAN의 loss function은 위에서 설명한 일반적인 네트워크의 loss function과 다르지 않습니다. 그러나, GAN의 가장 중요한 속성은 2개의 네트워크가 별도로(또는 교대로) generator와 critic(discriminator)로 학습해야 한다는 것입니다. 결론적으로, 두 네트워크들은 각자 학습하는 동안 자신의 loss function을 가지게 됩니다. -*__Critic loss function:__*: Critic 학습은 고양이와 개 클래스가 "실제"와 "가짜" 클래스로 대체된다는 점을 제외하고 고양이-개 감지기와 같은 모든 표준 알고리즘을 학습하는 것과 매우 유사합니다. Critic loss function은 실제 데이터가 "실제"로 분류되고 generator의 가짜 데이터가 한 번의 critic 학습에 대해 "가짜"로 얼마나 정확하게 분류되는지 평가합니다. Critic loss function은 generator의 "가짜" 데이터가 종종 critic에 의해 "실제"로 분류되어 generator에 의해 쉽게 속이는 것을 암시하는 경우 큰 값을 출력합니다. +*__Critic loss function:__* Critic 학습은 고양이와 개 클래스가 "실제"와 "가짜" 클래스로 대체된다는 점을 제외하고 고양이-개 감지기와 같은 모든 표준 알고리즘을 학습하는 것과 매우 유사합니다. Critic loss function은 실제 데이터가 "실제"로 분류되고 generator의 가짜 데이터가 한 번의 critic 학습에 대해 "가짜"로 얼마나 정확하게 분류되는지 평가합니다. Critic loss function은 generator의 "가짜" 데이터가 종종 critic에 의해 "실제"로 분류되어 generator에 의해 쉽게 속이는 것을 암시하는 경우 큰 값을 출력합니다. -*__Generator loss function:__*: Generator 학습 중에 생성된 데이터가 이를 속일 만큼 현실적인지 확인하기 위해, 하나의 배치에 대한 generator의 출력이 critic에게 공급(feed into)됩니다. 잘 학습된 generator는 일반적으로 critic에게 생성된 데이터가 실제라고 믿게 하여 loss function score가 더 작아질 것이라고 속이는 것입니다. +*__Generator loss function:__* Generator 학습 중에 생성된 데이터가 이를 속일 만큼 현실적인지 확인하기 위해, 하나의 배치에 대한 generator의 출력이 critic에게 공급(feed into)됩니다. 잘 학습된 generator는 일반적으로 critic에게 생성된 데이터가 실제라고 믿게 하여 loss function score가 더 작아질 것이라고 속이는 것입니다. ## GAN loss function들의 문제점은 무엇인가요?? ## Cross entropy와 같은 표준 loss function을 사용하는 경우, GAN loss function에서 많은 문제점들이 발생합니다. -*__(1) Oscillating losses:__* 이전 섹션에서 언급했듯이 표준 고양이-개 감지기 유형 문제에서 학습이 진행됨에 따라 loss function 값이 감소할 것으로 예상합니다. 그러나 이것은 GAN에게는 해당되지 않습니다. Generator와 critic이 교대로 학습을 수행하기 때문에, 그들은 서로에 대해 "더 강하고" 더 "약하게" loss를 얻음으로써 loss값들의 진동이 일어납니다(oscillating). 이것은 학습이 전반적으로 잘 진행되었는지 여부와 generator에 의해 생성된 데이터가 충분한지 이해하기 어렵게 만듭니다. +*__(1) Oscillating losses:__* 이전 섹션에서 언급했듯이, 표준 고양이-개 감지기 유형 문제에서 학습이 진행됨에 따라 loss function 값이 감소할 것으로 예상합니다. 그러나, 이는 GAN에는 해당되지 않습니다. Generator와 critic이 교대로 학습을 수행하기 때문에, 그들은 서로에 대해 "더 강하고" 더 "약하게" loss를 얻음으로써 loss값들의 진동이 일어납니다(oscillating). 이 현상은 학습이 전반적으로 잘 진행되었는지 여부와 generator에 의해 생성된 데이터가 충분한지 이해하기 어렵게 만듭니다. -*__(2) Mode collapse:__* 종종, generator는 critic이 항상 속아넘거가데 되는 1개의 특정 출력에 대해 critic을 속이는 것을 학습합니다. 이렇게 되면 generator는 새로운 종류의 데이터를 학습하고 생성하려는 동기가 없어져 최적의 generator 되지 못한다. +*__(2) Mode collapse:__* 종종, generator는 critic이 항상 속는 1개의 특정 출력에 대해 critic을 속이는 것을 학습합니다. 이렇게 되면, generator는 새로운 종류의 데이터를 학습하고 생성하려는 동기가 없어져 최적의 generator 되지 못합니다. ## Wasserstein loss function과 WGAN은 무엇인가요? ## -위에서 논의된 문제는 Wasserstein loss라는 새로운 유형의 loss function로 극복되었으며, 이를 사용하는 GAN을 WGAN(Wasserstein GAN) 이라고 합니다. 실무에 적용 시에는 수학적으로 깊은 이해 없이, +위에서 논의된 문제들은 Wasserstein loss라는 새로운 유형의 loss function으로 극복되었으며, 이를 사용하는 GAN을 WGAN(Wasserstein GAN) 이라고 합니다. 실무에 적용 시에는 수학적으로 깊은 이해 없이, Wasserstein loss가 주로 위에서 논의한 문제를 해결한다는 것을 아는 것으로 충분합니다. (1) Loss 값과 모델 학습 간에 상관 관계가 있도록 Loss function을 정의합니다. @@ -34,9 +34,9 @@ Wasserstein loss가 주로 위에서 논의한 문제를 해결한다는 것을 GAN loss function 대해 언급한 모든 내용은 DeepComposer에도 적용되므로, DeepComposer 아키텍처에서도 Wasserstein loss function을 사용합니다. 그러나 Wasserstein loss function은 GAN에 잘 맞는 또 다른 유형의 loss function에 불과하기 때문에, DeepComposer에서 사용되는 loss function에 대해 명확히 이해하는 것이 중요합니다. -이를 염두에 두고, loss function이 DeepComposer 아키텍처 어떻게 관련되어 있는지 확인해 봅시다. +이를 염두에 두고, loss function이 DeepComposer 아키텍처가 어떻게 관련되어 있는지 확인해 봅시다. *__(1) Critic loss function:__* Critic 학습 중에는 실제 데이터(멜로디가 있는 멀티 트랙 곡 + 학습 데이터셋의 반주)와 가짜 데이터(generator에 의해 생성된 악기 반주들에서 생성된 노래)의 2가지 타입 데이터가 필요합니다. Loss function은 critic이 실제 노래를 "실제"로 식별하고 가짜 노래를 "가짜"로 얼마나 잘 식별할 수 있는지를 나타내는 값을 출력합니다. 값이 높으면 critic이 약하고 generator에 의해 쉽게 속이는 것을 나타내므로, 이 값은 critic의 학습을 개선하기 위한 피드백을 제공하는 데 사용됩니다. -*__(2) Generator loss function:__* Generator 학습 중에 generator는 단일 멜로디 트랙을 입력으로 받아 멀티 트랙 곡을 출력합니다. 이 결과는 이제 critic(weight들이 동결된)에게 전달되어 critic이 실제 곡들의 분포 대비 얼마나 가깝게 생각하는지 알아봅니다. 높은 값을 산출하는 loss function은 critic이 올바르게 속지 않았음을 의미하므로, generator가 더 잘 학습하도록 페널티를 부여합니다. \ No newline at end of file +*__(2) Generator loss function:__* Generator 학습 중에 generator는 단일 멜로디 트랙을 입력으로 받아 멀티 트랙 곡을 출력합니다. 이 결과는 이제 critic(weight들은 이때 동결됩니다)에게 전달되어 critic이 실제 곡들의 분포 대비 얼마나 가깝게 생각하는지 알 수 있게 됩니다. 높은 값을 산출하는 loss function은 critic이 올바르게 속지 않았음을 의미하므로, generator가 더 잘 학습하도록 페널티를 부여합니다. \ No newline at end of file