2. 목차
1. R.T.Bach
2. 컴퓨터, 음악을 배우다
2.1. 확률 모델 정의
2.2. softmax regression
2.3. RNN의 도입
3. 노트 데이터 형식
3.1. flag
3.2. duration
3.3. pitch
3.4. one-hot encoding
4. 코랄 작품 분석
5. 분석 네트워크 설계
6. 재구성
7. 결과
3. R.T.Bach
머신러닝을 통해 바하의 작품을 분석하고 그 결과를 토대로 바하 스타일로
작곡하게 만든 어플리케이션
•RNN (Recurrent Neural Network) 알고리즘 사용
•Tensorflow 파이썬 머신러닝 라이브러리 사용
•Bach 4성 코랄 작품 데이터 사용
4. cell
R.T.Bach - RNN (Recurrent Neural Network)
연속적인 데이터를 학습시키는데 사용되는 딥러닝 기법
현재 입력 데이터와 기존의 상태값을 입력 받아, 현재의 상태값을 계산해 내보낸다.
현재의 상태값은 다음 순서에 사용되는 기존의 상태값이 되며, 매 순서에서 사용되는 cell의 내부 구성은 같다.
cell
현재
입력 데이터
cell
이전
입력 데이터
다음
입력 데이터
이전
상태값
현재
상태값
5. R.T.Bach - Tensorflow
Google에서 만든 파이썬 머신러닝 라이브러리
Github에 오픈소스로 제공
Tensor 오브젝트를 연결한 그래프를 통해 네트워크 구성
Tensorboard로 트레이닝 상태, 네트워크 구현, 각종 그래프들을 시각화 가능
6. R.T.Bach – Johann Sebastian Bach
(1685.3–1750.7) 18세기 독일 바로크 양식의 클래식 작곡가
관현악, 오라토리오, 건반 소품 등 모든 편성에 걸쳐 방대한 음악 작곡
4성부 코랄의 경우 300-400여개의 작품이 남아있다
다량의 비슷한 데이터들이 필요한 머신 러닝을 위해 적합
7. 컴퓨터 음악을 배우다 – 확률 모델 정의
Q. 컴퓨터가 어떻게 작곡을 배우게 할 수 있을까?
A. 선율을 연쇄적인 확률 모델의 결과물로 해석!
start
30%
20%
50%
𝑝 𝐶 𝑠𝑡𝑎𝑟𝑡 = 50% 𝑝 𝐶 𝐶, 𝑠𝑡𝑎𝑟𝑡 = 35%
35%
30%
35%
25%
45%
30%
𝑝 𝐺 𝐶, … = 30%
30%
45%
25%
𝑝 𝐺 𝐺, … = 45%
30%
45%
25%
𝑝 𝐴 𝐺, … = 30%
35%
40%
25%
𝑝 𝐴 𝐴, … = 40%
40%
35%
25%
𝑝 𝐺 𝐴, … = 25%
결과
8. 컴퓨터 음악을 배우다 – 확률 모델 정의
Q. 결과물(음악 작품)에서 어떻게 확률 모델을 유추할 수 있을까?
A. softmax regression을 사용!
softmax regression은 원래 분류 문제를 해결하기 위해서 만들어진 것으로 주어진 입력에 대해, 몇 개의 정해 놓은 클래스
에 속할 확률을 유추하는데 사용된다.
코끼리고양이 강아지 쥐
60% 10% 20% 10%
9. 분류를 위해 사용되던 softmax regression 모델을 차용하여 현재까지의 노트들을 입력 x로 생
각하고, 다음에 나올 노트를 분류 y로 생각하여 적용할 수 있다!
60% 10% 20% 10%
?
컴퓨터 음악을 배우다 – 확률 모델 정의
10. 컴퓨터 음악을 배우다 – softmax regression
고양이 코끼리 강아지 쥐
65 78 23 113 243 … (벡터화)
affine
softmax
cross-entropy
1 0 0 0
x
logit
y’
y
Softmax regression을 위해서는 먼저 입력 데이터와 이를 분류하는 지
표가 되는 라벨이 필요하다. 입력 데이터는 값의 나열로 된 벡터형식
의 데이터로 변환하고, 라벨은 해당 분류에 해당하는 값만 1이 되는
one-hot 벡터로 변환한다. 입력데이터는 affine계층과 softmax계층을
거쳐서 모든 원소의 합이 1이 되는 pmf로 변환하고, 이를 앞서 만든
one-hot 벡터와 cross-entropy를 취해 loss값을 얻는다. regression은 이
loss값을 최소화하는 affine계층의 weight와 bias값을 얻는 것으로 진
행된다. 각 계층은 모두 미분 가능하므로, gradient descent 등의 방법
을 통해 최적화를 진행해 나갈 수 있다.
11. 컴퓨터 음악을 배우다 – softmax regression
Softmax regression은 주어진 벡터에 대해 다수의 클래스에 분류될 확률을 계산한다. 입력 벡터 x를 [−∞, ∞] 범위와 y와 크기가 같은 logit 벡터
로 변환한 뒤 softmax를 취해 [0, 1]의 범위를 갖는 PMF(probability mass function) y’으로 변환한다. one-hot 인코딩 된 y는 1을 갖는 라벨로 분류
될 확률이 100%라는 뜻의 PMF로 여길 수 있으므로, y에 대해 y’의 cross-entropy를 취해 loss를 구할 수 있다. 구한 loss를 토대로 gradient
descent 기법을 통해 이 과정에서 유일한 변수인 W와 b를 학습한다.
softmax
cross-entropy
𝑦
𝑥
𝑠𝑜𝑓𝑡𝑚𝑎𝑥 𝑥 𝑗 =
𝑒 𝑙𝑜𝑔𝑖𝑡 𝑗
𝑘 𝑒 𝑙𝑜𝑔𝑖𝑡 𝑘
affine
𝑙𝑜𝑔𝑖𝑡
𝑦’
𝑙𝑜𝑔𝑖𝑡 = 𝑥𝑊 + 𝑏
𝑙𝑜𝑠𝑠 = −
𝑗
𝑦𝑗 𝑙𝑜𝑔𝑦′ 𝑗
현재의 입력 𝑥를 affine 변환을 통해 비교대상인 𝑦벡터와 크기가 같은
벡터로 변환한다.
이 때, 𝑊의 shape은 (𝑠 의 크기 × 𝑦의 크기)가 된다.
12. Affine 변환은 linear 변환에 상수항을 더한 개념이다.
즉, 어떠한 입력 𝑥에 대해서 출력 𝑦는 𝑥𝑊 + 𝑏 로 주어진다. 이 때, 𝑊는 변환행렬이고 𝑏는 상수 벡터이다.
𝑥가 n차원의 데이터라고 하고, 𝑊가 n x m꼴의 행렬이라면 𝑦는 m차원의 데이터가 된다.
𝑥1 𝑥2 𝑥3
𝑤11 𝑤12
𝑤21 𝑤22
𝑤31 𝑤32
𝑏1 𝑏2+𝑦 = 𝑤11 𝑥1 + 𝑤12 𝑥2 + 𝑤13 𝑥3 + 𝑏1 𝑤21 𝑥1 + 𝑤22 𝑥2 + 𝑤23 𝑥3 + 𝑏2=
3, 21, 3 1, 2𝑠ℎ𝑎𝑝𝑒:
3차원 데이터에서 2차원 데이터로 변환
컴퓨터 음악을 배우다 – softmax regression – affine 변환
13. tensorflow에서 affine 변환을 위해서 따로 제공하고 있는 함수는 없다. tensorflow에서는 affine 변환을 수행
하기 위해서는 행렬곱 함수와 연산자 오버로딩을 통한 행렬 덧셈연산을 조합해서 만들 수 있다.
W = tf.get_variable(name=“weight”, shape(x_size, y_size), dtype=tf.float32,
initializer=tf.random_normal_initializer())
b = tf.get_variable(name=“bias”, shape(1, y_size), dtype=tf.float32,
initializer=tf.constant_initializer(0.0)
y = tf.matmul(W, x) + b
Tensorflow의 함수 tf.matmul은 행렬간의 곱셈을 수행한다. 기호는 연산은 tf.add를 연산자 오버로딩을 통
해서 호출한다. weight와 bias는 tf.get_variable을 통해 트레이닝이 가능한 텐서로 할당 받는다.
컴퓨터 음악을 배우다 – softmax regression – affine 변환
14. Softmax 계층은 𝑠𝑜𝑓𝑡𝑚𝑎𝑥 𝑥 𝑗 =
𝑒
𝑙𝑜𝑔𝑖𝑡 𝑗
𝑘 𝑒 𝑙𝑜𝑔𝑖𝑡 𝑘
라는 식으로 주어지며, [−∞, ∞]범위의 logit 데이터를 [0, 1]범위
의 데이터로 변환해 이를 PMF로 사용할 수 있도록 한다.
pmf = tf.nn.softmax(logit)
Tensorflow에서는 tf.nn.softmax라는 함수를 제공하여 이를 쉽게 구현할 수 있다.
0 1-1 2 3-2-3
0 1-1 2 3-2-3
softmax
컴퓨터 음악을 배우다 – softmax regression – softmax
15. Cross-entropy 계층은 − 𝑗 𝑦𝑗 𝑙𝑜𝑔𝑦′
𝑗
라는 식으로 주어지며, 두 PMF 𝑦𝑗 와 𝑦′
𝑗
를 비교하여 다른 정도를 반
환한다. 결과값이 작을수록 두 PMF가 비슷하다는 뜻으로, 동일한 PMF의 cross-entropy는 0이다. Cross-
entropy는 식에서 알 수 있듯이 교환법칙이 성립되지 않으며, 라벨에 의해 정해진 PMF를 𝑦𝑗 로, 트레이닝
할 변수에 의해 만들어진 PMF를 𝑦′
𝑗
로 정한다.
# y, y_는 비교할 두 PMF
d = tf.constant(value=1e-7, dtype=tf.float32, …)
cross_entropy = -tf.reduce_sum(y * tf.log(y_ + d))
0
0.5
1
1.5
LABEL1 LABEL2 LABEL3 LABEL4
y y'
Tensorflow에서는 tf.log함수와 tf.reduce_sum을 통해서 cross-entropy계층을 만들 수 있다. log의 결과가
− ∞가 되는 것을 방지하기 위해 delta를 정의하여 더할 수 있다.
컴퓨터 음악을 배우다 – softmax regression – cross-entropy
16. Tensorflow에는 라벨 벡터가 되는 y가 one-hot 벡터일 때, softmax regression을 쉽게 할 수 있도록 도와주는 함수가 존재한
다. logit 벡터로 변환하는 과정은 weight와 bias를 손수 할당하여 구현해주어야 하며, 만들어진 logit 벡터와 y를
tf.nn.sparse_softmax_cross_entropy_with_logits 함수는 통해 cross-entropy를 구할 수 있다.
# state : 현재의 상태 벡터 (batch_size, time_,
# y : 라벨 텐서
# y_size: 라벨 벡터의 크기
W = tf.get_variable(name=‘weight’, shape(state_size, y_size), …
b = tf.get_variable(name=‘bias’, shape(1, y_size), …
logits = tf.matmul(state, W) + b
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)
softmax regression에서 라벨 벡터가 one-hot 벡터이면 cross-entropy를 쉽게 구할 수 있다. cross-entropy의 식 𝑙𝑜𝑠𝑠 = − 𝑗 𝑦𝑗 𝑙𝑜𝑔𝑦′
𝑗
에서 어떠한 인덱스 k에 대해, 𝑦 𝑘 = 1 이라면, 𝑗 = 𝑘 를 만족하지 않는 모든 𝑗 에 대해 𝑦𝑗 = 0 이므로, 𝑙𝑜𝑠𝑠 = 𝑦 𝑘 𝑙𝑜𝑔𝑦′
𝑘
로 식이 간단해
지기 때문이다. Tenorflow는 위 함수를 통해 이를 구현하고 있는 것으로 보인다.
컴퓨터 음악을 배우다 – softmax regression – cross-entropy
17. 컴퓨터 음악을 배우다 - RNN
연쇄적 확률 모델의 문제점
선율이 길어짐에 따라 점점 많은 조건들을 고려해야한다.
𝑝 𝑥𝑡 𝑥𝑡−1, 𝑥𝑡−2, 𝑥𝑡−3, 𝑥𝑡−4, 𝑥𝑡−5, 𝑥𝑡−6, …
100개의 노트가 있는 선율의 마지막 노트를 정하기 위해선 앞서 나온 99개
의 노트의 정보가 필요
18. 해결책1. 마르코프 연쇄
미리 정한 만큼의 과거의 데이터만 현재에 영향을 미친다고 가정
𝑝 𝑥𝑡 𝑥𝑡−1, 𝑥𝑡−2, … , 𝑥𝑡−𝑘
문제점 : 실제로 얼마만큼의 과거의 데이터가 현재에 영향을 미치는지 알 수
없다.
𝑘 = 6
컴퓨터 음악을 배우다 - RNN
19. 해결책2. RNN의 도입
𝑥𝑡를 정하기 위해서 𝑥𝑡−1, 𝑥𝑡−2, 𝑥𝑡−3, … 이 사상(image)된 𝑠𝑡𝑎𝑡𝑒𝑡−1 만을 고려하
면 된다.
cellRNN cell cell cell
𝑠𝑡𝑎𝑡𝑒𝑡−1를 고려해 예측!
… … …
𝑠𝑡𝑎𝑡𝑒𝑡−2
컴퓨터 음악을 배우다 - RNN
20. RNN 이란? 연속적인 데이터를 학습시키는데 사용되는 딥러닝 기법
현재 입력 데이터 xt와 기존의 상태 st-1를 합친 후 (concatenate) affine 변환, activation functio을 적용하여
현재의 상태 st를 내보낸다.
St는 다음 순서에 사용되며, 매 순서에서 사용되는 cell은 같다.
affine
activation
xt
concat
St
affine
activation
Xt+1
concat
St+1
affine
activation
Xt-1
St-2 concat
St-1
컴퓨터 음악을 배우다 - RNN
21. RNN의 activation function으로는 대개 tanh 함수가 사용된다. 입력 x에 대해서 tanh함수는 다음과 같이 주
어진다. tanh 함수의 미분은 다음과 같이 tanh 함수 자체를 포함하고 있어 forward propagation시 계산했던
값을 그대로 이용할 수 있다는 장점이 있다.
𝑡𝑎𝑛ℎ′
(𝑥) = 1 − 𝑡𝑎𝑛ℎ2
(𝑥)
또한 tanh 함수는 미분을 연쇄적으로 하여도 미분값이 0으로 소멸되는 일이 없어, back propagatio시
vanishing gradient 문제가 덜 일어나는 이점이 있다. (sigmoid 함수 대비 이점)
tanh 𝑥 tanh ′(𝑥) tanh ′′(𝑥) tanh ′′′(𝑥)
컴퓨터 음악을 배우다 – RNN – activation function
22. Tensorflow에서는 RNN을 위한 내장된 함수를 제공한다. tf.contrib.rnn.BasicRNNCell을 통해서 RNN의 기본이 되는 cell을
만들고, tf.nn.dynamic_rnn을 통해서 실제 RNN 과정을 수행한다. 앞서 설명했던 affine-activation 계층으로 이루어진
BasicRNNCell 뿐만 아니라, Vanishing gradient problem해결에 도움을 주는 LSTMCell과 GRUCell등도 지원한다.
state_size = 64
cell = tf.contrib.rnn.BasicRNNCell(state_size)
states, last_state = tf.nn.dynamic_rnn(cell=cell, inputs=onehot_inputs,
initial_state=init_state, scope=scope)
BasicRNNCell은 상태값을 담고 있는 state의 크기를 파라메터로 받는다. state는 현재까지 입력된 입력들의 지문과 같은 기능을 하기 때문에, 입
력의 크기와 반영될 입력의 개수 등을 토대로 사용자가 임의로 정해야 한다. dynamic_rnn함수는 앞서만든 cell 오브젝트와, input tesnor, intial
state, 내부적으로 선언될 weight와 bias의 variable scope를 파라메터로 받는다. input tensor는 (batch size, time size, input size)의 shape을 가지고
있어야한다. 트레이닝의 성능을 높이기 위해서 한번에 여러 입력을 처리하기 위해 batch 모드로 실행이 되며, back-propagation이 이뤄지는
크기만큼 time size를 지정해줘야 한다. 함수에 대한 리턴 값으로는 매 순번 시간마다 생성된 상태값들 즉, 𝑠𝑡, 𝑠𝑡+1, 𝑠𝑡+2,…, 𝑠𝑡+𝑡𝑖𝑚𝑒_𝑠𝑖𝑧𝑒−1 와 마
지막 상태값인 𝑠𝑡+𝑡𝑖𝑚𝑒_𝑠𝑖𝑧𝑒−1을 받을 수 있다. 맨 시작의 경우, init_state를 zero vector로 초기화 시켜 놓고, 그 다음부터는 리턴 받은 last_state를
그대로 재입력하여 반복해서 사용할 수 있다. 하나의 Tensorflow 세션에서 여러 RNN을 수행하기 위해서는 scope를 달리해서 사용하면 된다.
예를 들어 soprano와 bass의 선율을 분석하는 RNN은 달라야하므로, 이 둘의 scope를 달리 할 수 있다.
컴퓨터 음악을 배우다 - RNN
23. R.T.Bach - RNN (Recurrent Neural Network) : tensorflow
dynamic_rnn
cell
time size
batchsize
input
tensor
time size
batchsize
output
tensor
Tensorflow에서 사용되는 내장 RNN 함수의 도식
24. 노트 데이터 형식
노트 하나는 pitch, duration, flag의 정보를 가지고 있다. pitch는 음의 높낮이, duration은 음의
길이, flag는 멜로디의 시작과 끝이나 카덴스 등을 나타낸다.
위 멜로디의 경우, 다음과 같이 pitch, duration, flag의 정보를 담은 3차원 벡터의 리스트로 표현할 수 있다.
[(none, none, start), (A4, quarter, normal), (D5, quarter, normal), (C5, quarter, normal), (Bb4, quarter, normal), (A4, quarter, normal), (G4, half,
normal), (G4, half, cadence), (none, none, end)]
class Note:
def __init__(self, flag, duration, pitch):
self.flag = flag
self.duration = duration
self.pitch = pitch
25. 노트 데이터 형식 - pitch
pitch는 음의 높낮이로 midi의 경우 0에서 127까지의 정수로 표기된다.
하지만 각 성부에서 실제적으로 가질 수 있는 pitch의 범위는 제한적이므로 각 성부에 따라 범위를 제한할
수 있다. 즉, Soprano, Alto, Tenor, Bass 각각 C5, G4, G3, C3를 중심으로 3옥타브의 범위를 갖는 것으로 제한
한다.
Bass C3
Tenor G3
Alto G4
Soprano C5
3옥타브
상한
하한
26. 노트 데이터 형식 - pitch
범위가 제한되어 있는 pitch값을 갖기 위해 pitch의 범위 3옥타브와, 각 성부에 해당하는 pitch의 중앙값을
constant로 정의해둔다.
PitchRange = 36 # three octaves
PitchCenters = [72, 67, 55, 48] # corresponding to [C5, G4, G3, C3]
def get_range_pitch(midi_pitch, pitch_center):
return midi_pitch - pitch_center + PitchRange / 2
def get_midi_pitch(range_pitch, pitch_center):
return range_pitch + pitch_center - PitchRange / 2
Midi의 pitch 값을 정해 놓은 제한된 pitch 값으로 변환시키기 위해 get_range_pitch라는 함수를 정의한다.
이 함수는 midi의 pitch값과 앞서 정의한 pitch 중앙값들 중 해당하는 성부의 값을 파라메터로 받고, 범위
가 제한된 pitch값을 리턴한다.
반대로 범위가 제한된 pitch값을 다시 midi의 pitch값으로 되돌리기 위해 get_midi_pitch라는 함수를 정의
한다. 이 함수는 범위가 제한된 pitch값과 앞서 저의한 pitch 중앙값들 중 해당하는 성부의 값을 파라메터
로 받고, midi의 pitch값을 리턴한다.
27. 노트 데이터 형식 - duration
duration는 음의 길이로 코랄의 경우 대개 16분음표, 8분음표, 4분음표, 2분음표, 점2분음표, 온음표 내에
서 결정된다.
가장 길이가 짧은 16분음표를 1에 대응시키고 다른 음표들도 길이에 비례하게 대응시킨다. 즉, 16분음표
– 1, 8분음표 – 2, 점 8분음표 – 3, 4분음표 – 4, …
최대로 가질 수 있는 길이는 온음표 – 16이 되고, 길이가 없는 노트 (Start노트, End노트)를 위해 할당한 0값
을 포함해서 17개 범위의 값을 할당한다.
값 : 1 2 4 6 8 12 16
28. 노트 데이터 형식 – flag
flag는 멜로디의 시작과 끝을 알리는 start, end 값이나 종지를 알리는 Cadence값을 갖는다. 이
외의 노트들은 normal 값을 가진다. start와 end 노트는 악보로 표시되지 않으며, duration과
pitch를 갖지 않고(기본값 0으로 설정), 선율의 시작과 끝 만을 나타낸다.
end = 0, start = 1, normal = 2, cadence = 3로 할당한다.
start endnormal … … cadence
29. 노트 데이터 형식 – one-hot encoding
입력 데이터는 flag와 duration과 pitch를 각각 one-hot encoding한 형태를 concatenate하여 제
공된다.
만약 flag가 normal, duration이 4분음표, pitch가 G4인 soprano 노트의 경우 다음과 같은 형태
의 벡터로 표현된다.
= (normal, 4분음표, G4) = (2, 4, 12)
=(0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
flag 영역 duration 영역 pitch 영역
30. 노트 데이터 형식 – one-hot encoding
Tensorflow 에는 one-hot encoding을 쉽게 할 수 있도록 tf.one_hot 함수를 제공한다. tf.one_hot 함수는 input tensor와 depth
를 파라메터로 받아 input tensor의 값을 인덱스로 하여 해당 인덱스만 1이고 나머지는 0이 되는 벡터를 반환한다. depth
는 벡터의 크기이다.
예를 들어 tensor x가 ((0, 1, 2), (1, 2, 3))이라는 값을 가지고 있는 벡터일 때,
one_hot_x = tf.one_hot(x, 4)
위 tensor one_hot_x은 ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0)), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))) 라는 값을 갖게 된다.
((0, 1, 2)
(1, 2, 3))
((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0)
(0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
tf.one_hot
31. 코랄 작품 분석
코랄은 Soparano, Alto, Tenor, Bass 4성부를 가지고 있다.
32. 코랄 작품 분석 - Soprano
Soprano는 단선율의 노래로써 가장 높은 우선순위를 가지고 작곡되며, 다른
성부들에 대한 의존성이 적다.
Soprano 선율의 노트 하나의 출현은 앞서 나왔던 노트들에 의해 결정된다고
가정할 수 있다.
𝑝 𝑠𝑜𝑝𝑡 = 𝐴 | 𝑠𝑜𝑝𝑡−1 = 𝐺, 𝑠𝑜𝑝𝑡−2 = 𝐴, 𝑠𝑜𝑝𝑡−3 = 𝐵𝑏, …
33. 코랄 작품 분석 - Soprano
𝑠𝑜𝑝𝑡 하나를 구하기 위해 𝑠𝑜𝑝𝑡−1, 𝑠𝑜𝑝𝑡−2, … 𝑠𝑜𝑝1 을 모두 고려하는 것은 계산
이 불필요하게 많아진다. 매 노트를 참조할 때마다 RNN을 이용하여 상태값
으로 인코딩해 놓고 이전의 노트들을 인코딩한 𝑠𝑡−1를 이용하여 현재의 노트
𝑠𝑜𝑝𝑡를 구한다.
𝑝 𝑠𝑜𝑝𝑡 = 𝐴 | 𝑠𝑜𝑝𝑡−1 = 𝐺, 𝑠𝑜𝑝𝑡−2 = 𝐴, 𝑠𝑜𝑝𝑡−3 = 𝐵𝑏, … ≅ 𝑝 𝑠𝑜𝑝𝑡 = 𝐴 𝑠𝑡−1)
𝑠𝑡−1
34. 코랄 작품 분석 - Bass
Bass 선율은 Soprano에 대한 대선율로써 구성되어야 한다. 그러므로 앞서 나왔던 노트들 뿐 아니라, 현재
Soprano 선율의 상태 또한 고려되어야 한다. 현재 시간 t를 기준으로 soprano의 선율을 순방향과 역방향으
로 RNN을 이용하여 미리 정의해 놓은 노트 개수만큼 propagation을 진행해 상태값을 인코딩시킨다.
𝑝 𝑏𝑎𝑠𝑠𝑡 | 𝑠𝑡−1
𝑏𝑎𝑠𝑠
, 𝑠𝑡
𝑠𝑜𝑝(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
, 𝑠𝑡
𝑠𝑜𝑝(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
𝑠𝑡−1
𝑏𝑎𝑠𝑠
𝑠𝑡
𝑠𝑜𝑝(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
𝑠𝑡
𝑠𝑜𝑝(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
35. 코랄 작품 분석 –Tenor
Tenor 성부는 Soprano와 Bass가 완성된 후 이에 의존적으로 채워 넣을 수 있는 성부이다.
그러므로 Tenor 성부는 앞서 나왔던 노트들과 Soprano, Bass의 선율의 상태에 의해 결정된다고 볼 수 있다.
𝑝 𝑡𝑒𝑛𝑜𝑟𝑡 | 𝑠𝑡−1
𝑡𝑒𝑛𝑜𝑟
, 𝑠𝑡
𝑠𝑜𝑝 𝑓𝑜𝑟𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑠𝑜𝑝 𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑏𝑎𝑠𝑠(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
, 𝑠𝑡
𝑏𝑎𝑠𝑠(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
𝑠𝑡−1
𝑡𝑒𝑛𝑜𝑟
𝑠𝑡
𝑠𝑜𝑝(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
𝑠𝑡
𝑠𝑜𝑝(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
𝑠𝑡
𝑠𝑜𝑝(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
𝑠𝑡
𝑠𝑜𝑝(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
36. 코랄 작품 분석 – Alto
Tenor의 경우와 마찬가지로 Alto 성부 또한 앞서 나왔던 노트들과 다른 3성부에 의해 현재 노트가 결정된
다고 볼 수 있다.
𝑝 𝑎𝑙𝑡𝑜𝑡 | 𝑠𝑡−1
𝑎𝑙𝑡𝑜
, 𝑠𝑡
𝑠𝑜𝑝 𝑓𝑜𝑟𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑠𝑜𝑝 𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑏𝑎𝑠𝑠 𝑓𝑜𝑟𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑏𝑎𝑠𝑠 𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑡𝑒𝑛𝑜𝑟(𝑓𝑜𝑟𝑤𝑎𝑟𝑑)
, 𝑠𝑡
𝑡𝑒𝑛𝑜𝑟(𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑)
37. • softmax regression의 경우 기본적으로 하나의 출력과 하나의 라벨 벡터를 비교한다. 하지만 앞서 정의한 노트 데이터의 경우 flag, duration, pitch 3종류
의 데이터가 한 노트에 존재한다. 이를 구현하기 위해 각 요소의 회귀가 순서대로 종속적으로 이루어지도록 설계한다. 𝑝𝑚𝑓𝑓𝑙𝑎𝑔 는 오직 상태값 𝑠𝑡에 종
속적이고, 이로 얻은 𝑝𝑚𝑓𝑓𝑙𝑎𝑔 와 𝑠𝑡를 이용하여 𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 을 얻는다. 𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ 는 𝑝𝑚𝑓𝑓𝑙𝑎𝑔 와 𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 과 𝑠𝑡를 이용하여 얻어낸다.
분석 네트워크 설계 – 다중 종속 회귀(multi-dependent regression)
softmax
cross-entropy
𝑠𝑡
affine(flag)
𝑙𝑜𝑔𝑖𝑡 𝑓𝑙𝑎𝑔
𝑝𝑚𝑓𝑓𝑙𝑎𝑔
𝑥𝑡+1
𝑓𝑙𝑎𝑔
𝑝𝑚𝑓𝑓𝑙𝑎𝑔 = 𝑝 𝑥𝑡+1
𝑓𝑙𝑎𝑔
𝑠𝑡) 𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 = 𝑝 𝑥𝑡+1
𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
𝑥𝑡+1
𝑓𝑙𝑎𝑔
, 𝑠𝑡) 𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ = 𝑝 𝑥𝑡+1
𝑝𝑖𝑡𝑐ℎ
𝑥𝑡+1
𝑓𝑙𝑎𝑔
, 𝑥𝑡+1
𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
, 𝑠𝑡)
softmax
cross-entropy
affine(duration)
𝑙𝑜𝑔𝑖𝑡 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
𝑥𝑡+1
𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
softmax
cross-entropy
affine(pitch)
𝑙𝑜𝑔𝑖𝑡 𝑝𝑖𝑡𝑐ℎ
𝑥𝑡+1
𝑝𝑖𝑡𝑐ℎ
concatenate concatenate
𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ
44. 6. 재구성 – 다중 종속 출력(multi-dependent output)
Soprano를 제외한 bass, tenor, alto선율의 분석 및 재구성의 경우 다른 성부에 대한 RNN propagation이 forward와 backward 양방향으로 이루어진다. 분석의 경우 각 방향
에 대한 상태값을 이용한 회귀가 독립적으로 이루어지는데, 재구성 단계에서는 각 방향에 대한 상태값을 이용하여 pmf를 구한 뒤, 서로 곱한 결합확률에서 flag, duration,
pitch의 요소를 얻어낸다.
softmax
𝑠𝑡
𝑓𝑜𝑟𝑤𝑎𝑟𝑑
Affine(flag)
𝑥𝑡
𝑓𝑙𝑎𝑔
softmax
choice
Affine(flag)
𝑝𝑚𝑓𝑓𝑙𝑎𝑔
𝑓𝑜𝑟𝑤𝑎𝑟𝑑 ×
𝑠𝑡
𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
softmax
𝑥𝑡
𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
softmax
choice
Affine(flag)
𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
×
concat concat
Affine(flag)
softmax
𝑥𝑡
𝑝𝑖𝑡𝑐ℎ
softmax
choice
Affine(flag)
𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ
×
concat concat
Affine(flag)
𝑝𝑚𝑓𝑓𝑙𝑎𝑔
𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
𝑓𝑜𝑟𝑤𝑎𝑟𝑑
𝑝𝑚𝑓𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ
𝑓𝑜𝑟𝑤𝑎𝑟𝑑 𝑝𝑚𝑓𝑝𝑖𝑡𝑐ℎ
𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
45. 6. 재구성 – 다중 종속 출력(multi-dependent output)
def get_flag_pmf(state, weight_flag, bias_flag)
logit_flag_forward = tf.matmul(state[Forward], weight_flag[Forward]) + bias_flag[Forward]
logit_flag_backward = tf.matmul(state[Backward], weight_flag[Backward]) + bias_flag[Backward]
pmf_flag_forward = tf.nn.softmax(logit_flag_forward)
pmf_flag_backward = tf.nn.softmax(logit_flag_backward)
return pmf_flag_forward * pmf_flag_backward
# 𝑠𝑡
𝑓𝑜𝑟𝑤𝑎𝑟𝑑
, 𝑠𝑡
𝑏𝑎𝑐𝑘𝑤𝑎𝑟𝑑
와 flag에 대한 weight, bias를 받아 𝑝𝑚𝑓𝑓 𝑙𝑎𝑔를 구한다.
# get_duration_pmf와 get_pitch_pmf도 같은 식으로 forward, backward 각각의 pmf를 구하고 서로 곱한 값을 리턴한다.
46. 재구성 - Soprano
Soprano의 경우, 시간 t에서 하나의 노트를 얻기 위해 앞서 나왔던 노트들의 상태 𝑠𝑡−1가 필요하다. 앞서 나왔던 노트들이 없는 경우 초기 상태
𝑠0는 zero 벡터 (모든 원소가 0인 벡터)로 초기화하며, 초기 입력은 앞서 정의하였던 Start flag를 가진 벡터로 지정한다. RNN cell을 거쳐 나온
상태 값을 이용하여 앞서 설계한 다중 출력 레이어를 거쳐서 flag, duration, pitch 벡터를 얻는다. 이렇게 얻은 벡터들은 다시 다음 단계의 입력
이 되고, 이러한 과정을 End flag를 얻을 때까지 연쇄적으로 반복한다.
flag 구하기
𝑝 𝑓𝑙𝑎𝑔𝑡 𝑠𝑡) = 𝑠𝑜𝑓𝑡𝑚𝑎𝑥 𝑠𝑡 ∙ 𝑊𝑓𝑙𝑎𝑔 + 𝑏𝑓𝑙𝑎𝑔
𝑓𝑙𝑎𝑔𝑡 = 𝑐ℎ𝑜𝑖𝑐𝑒(𝑝 𝑓𝑙𝑎𝑔𝑡 𝑠𝑡))
duration 구하기
𝑝 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡 𝑓𝑙𝑎𝑔𝑡, 𝑠𝑡) = 𝑠𝑜𝑓𝑡𝑚𝑎𝑥 𝑐𝑜𝑛𝑐𝑎𝑡(𝑓𝑙𝑎𝑔𝑡, 𝑠𝑡) ∙ 𝑊𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 + 𝑏 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛
𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡 = 𝑐ℎ𝑜𝑖𝑐𝑒(𝑝 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡 𝑓𝑙𝑎𝑔𝑡, 𝑠𝑡))
pitch 구하기
𝑝 𝑝𝑖𝑡𝑐ℎ 𝑡 𝑓𝑙𝑎𝑔𝑡, 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡, 𝑠𝑡) = 𝑠𝑜𝑓𝑡𝑚𝑎𝑥 𝑐𝑜𝑛𝑐𝑎𝑡(𝑓𝑙𝑎𝑔𝑡, 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡, 𝑠𝑡) ∙ 𝑊𝑝𝑖𝑡𝑐ℎ + 𝑏 𝑝𝑖𝑡𝑐ℎ
𝑝𝑖𝑡𝑐ℎ 𝑡 = 𝑐ℎ𝑜𝑖𝑐𝑒(𝑝 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛 𝑡 𝑓𝑙𝑎𝑔𝑡, 𝑠𝑡))
현재 노트 구하기
𝑠𝑜𝑝𝑡 = 𝑐𝑜𝑛𝑐𝑎𝑡(𝑓𝑙𝑎𝑔𝑡, 𝑑𝑢𝑟𝑎𝑡𝑖𝑜𝑛𝑡, 𝑝𝑖𝑡𝑐ℎ 𝑡)
초기값
𝑠0 = 𝑧𝑒𝑟𝑜 𝑣𝑒𝑐𝑡𝑜𝑟, 𝑠𝑜𝑝0 = 𝑆𝑡𝑎𝑟𝑡 𝑛𝑜𝑡𝑒
상태값 구하기
𝑠𝑡 = 𝑐𝑒𝑙𝑙 𝑠𝑡−1, 𝑠𝑜𝑝𝑡−1
56. 결과
반짝반짝 작은별 멜로디 화성화
https://soundcloud.com/hutenheu
m/twinkle-major
57. 결과
반짝반짝 작은 별 단조화
멜로디 화성화
https://soundcloud.com/hutenheu
m/twinkle-minor
58. 결과
베토벤 합창 선율 화성화
https://soundcloud.com/hutenheum/beethoven
59. 결과
문제점
1. Soprano선율을 만드는 경우 처음 조성과 마지막 조성이 일치 하지 않는 경우가 생김
→ 조성에 대한 정보를 global context로 적용하는 것이 필요
2. 성부 간의 병행이 자주 일어남
→ 성부 간의 노트 진행에 추가적인 조건 구성이 필요
3. 박자, 박절 정보가 누락되어 상황에 맞지 않는 종지, 화성진행이 일어남
→ 박자 정보를 global context로, 박절 정보를 노트에 추가시키는 것이 필요
60. 관련 연구들
1. Bachbot
http://bachbot.com
피아노 롤 방식으로 입력데이터를 구성하고 embedding과 LSTM을 이용
2. Hexahedria
http://www.hexahedria.com/2015/08/03/composing-music-with-recurrent-neural-networks/
시간축에 대해서 뿐만 아니라 pitch축으로도 RNN을 구성하여 (Biaxial RNN) 성부 개수가 자유로운
다성음악 구성
3. RNN-RBM 모델
http://danshiebler.com/2016-08-10-musical-tensorflow-part-one-the-rbm/
pitch축에 대해 RBM(restricted boltzmann machine) 모델을 사용하여 다성음악 구성
61. About Me…
박수철 - 서울 사당동 거주
https://www.facebook.com/fuku.abca
https://github.com/sempre20
https://soundcloud.com/hutenheum
주로 하는 일
클래식, 전자음악 작곡
안드로이드, DSP 프로그래머
관심사
유튜브, 수학, 잠, 나무위키, 냉면, 한강 산책, 천
주교, 공상 …