2018. 6. 10. 23:37ㆍPython-이론/python-인공지능2
[keras]퍼셉트론을 사용하여 악보예측해보기
이번에는 퍼셉트론 딥러닝을 이용해서 악보를 훈련한 뒤 예측해보곘다.
나비야 악보
c(도), d(레), e(미), f(파), g(솔), a(라), b(시)
4(4분음표), 8(8분음표)
저는 이 음표들을 이런식으로 훈련 시킬 것 입니다. note8 노트로 적었는데 글씨를 이쁘게 못적었네요 ㅠㅠ
4개의 음표들이 들어간 후 그때의 결과 그 때의 라벨값에 맞추어 훈련한다. 그리고 각 층은 Relu. softmax 같은 활성화 함수를 사용하고 12개의 결과 중 가장 높은 확률의 값의 idx를 반환한다.
에를 들어) 0, 1, 2, 3의 악보가 들어갔으면 4번째 음표의 값을 훈련 후 1, 2, 3, 4의 값이 들어간 후 5번째 값을 훈련한다, 이런식의 훈련이 끝나고 난뒤 예측할 때 0, 1, 2, 3의 음표가 들어갔을 때 다음 음표는 무엇이 나오는지 예측하는 모델이다.
필자는 다음 음표를 예측하는 방법 2가지를 사용하여 구할 것인데. 이번에 할 것은 퍼셉트론을 이용한 것이다.
import numpy as np from keras.models import Sequential from keras.layers import Dense, Activation, Dropout, MaxPooling2D, Flatten from keras.utils import np_utils import keras import matplotlib.pyplot as plt code2idx = {'c4':0, 'd4':1, 'e4':2, 'f4':3, 'g4':4, 'a4':5, 'b4':6, 'c8':7, 'd8':8, 'e8':9, 'f8':10, 'g8':11, 'a8':12, 'b8':13} idx2code = {0:'c4', 1:'d4', 2:'e4', 3:'f4', 4:'g4', 5:'a4', 6:'b4', 7:'c8', 8:'d8', 9:'e8', 10:'f8', 11:'g8', 12:'a8', 13:'b8'} # 시퀀스 데이터 정의 seq = ['g8', 'e8', 'e4', 'f8', 'd8', 'd4', 'c8', 'd8', 'e8', 'f8', 'g8', 'g8', 'g4', 'g8', 'e8', 'e8', 'e8', 'f8', 'd8', 'd4', 'c8', 'e8', 'g8', 'g8', 'e8', 'e8', 'e4', 'd8', 'd8', 'd8', 'd8', 'd8', 'e8', 'f4', 'e8', 'e8', 'e8', 'e8', 'e8', 'f8', 'g4', 'g8', 'e8', 'e4', 'f8', 'd8', 'd4', 'c8', 'e8', 'g8', 'g8', 'e8', 'e8', 'e4'] class losses_callback(keras.callbacks.Callback): def init(self): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss')) def dataset(seq, window): data = [] for i in range(len(seq)-window): subset = seq[i:i+window+1] data.append([code2idx[i] for i in subset]) return np.array(data) trainData = dataset(seq, 4) print(trainData) X_data = trainData[:, :4]/float(13) Y_data = trainData[:, 4] Y_data = np_utils.to_categorical(Y_data) model = Sequential() model.add(Dense(128, input_dim=4, activation='relu')) model.add(Dense(128, activation='relu')) model.add(Dense(12, activation='softmax')) callBack = losses_callback() callBack.init() model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(X_data, Y_data, batch_size=10, epochs=2000, verbose=2, callbacks=[callBack]) plt.plot(callBack.losses) plt.xlabel('epoch') plt.ylabel('loss') plt.show() score = model.evaluate(X_data, Y_data) print(score) seq_in = ['g8', 'e8', 'e4', 'f8'] seq_out = seq_in seq_in = [code2idx[i]/13 for i in seq_in] for i in range(50): sample_in = np.array(seq_in) sample_in = np.reshape(sample_in, (1, 4)) predict_val = model.predict(sample_in) idx = np.argmax(predict_val) seq_out.append(idx2code[idx]) seq_in.append(idx/float(13)) seq_in.pop(0) print(seq_out)
코드 설명
code2idx = {'c4':0, 'd4':1, 'e4':2, 'f4':3, 'g4':4, 'a4':5, 'b4':6, 'c8':7, 'd8':8, 'e8':9, 'f8':10, 'g8':11, 'a8':12, 'b8':13} idx2code = {0:'c4', 1:'d4', 2:'e4', 3:'f4', 4:'g4', 5:'a4', 6:'b4', 7:'c8', 8:'d8', 9:'e8', 10:'f8', 11:'g8', 12:'a8', 13:'b8'}
도, 레, 미, 파, 솔, 라, 시를 8박자 4박자로 나누어 data를 만든 것이다.
def dataset(seq, window): data = [] for i in range(len(seq)-window): subset = seq[i:i+window+1] data.append([code2idx[i] for i in subset]) return np.array(data)
데이터를 윈도우 개수 + 라벨 만큼 짤라서 러닝할 때 사용할 데이터를 만들었다.
X_data = trainData[:, :4]/float(13) Y_data = trainData[:, 4] Y_data = np_utils.to_categorical(Y_data)
0~3개 까지의 인덱스 값을 13으로 모두 나누어 준다. 13인 이유는 도레미~시 까지는 14개지만 계이름 중에 악보에 사용하지 않는 계이름이 있어서 그렇다.
model = Sequential() model.add(Dense(128, input_dim=4, activation='relu')) model.add(Dense(128, activation='relu')) model.add(Dense(12, activation='softmax'))
위의 사진과 같이 딥러닝 층을 만들었다.
class losses_callback(keras.callbacks.Callback): def init(self): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss'))
하나의 배치가 끝날 때 마다 손실율을 losses에 저장한다.
model.fit(X_data, Y_data, batch_size=10, epochs=2000, verbose=2, callbacks=[callBack])
이런 방식으로 콜백함수를 등록한다.
seq_in = ['g8', 'e8', 'e4', 'f8'] seq_out = seq_in seq_in = [code2idx[i]/13 for i in seq_in] for i in range(50): sample_in = np.array(seq_in) sample_in = np.reshape(sample_in, (1, 4)) predict_val = model.predict(sample_in) idx = np.argmax(predict_val) seq_out.append(idx2code[idx]) seq_in.append(idx/float(13)) seq_in.pop(0) print(seq_out)
첫 시작 4음표로 예측을 시작한다. 첫 음표들을 모두 13으로 나누어서 예측을 하기 위한 값으로 바꾸어주고 2차원 배열형태로 바꾸어준다.
얘측 값 중 가장 적절한 값을 출력하기위한 배열에 등록한다.
손실율과 정확도: [0.14114807188510894, 0.9200000023841858]
예측한 악보: ['g8', 'e8', 'e4', 'f8', 'd8', 'd4', 'c8', 'e8', 'g8', 'g8', 'e8', 'e8', 'e4', 'd8', 'd8', 'd8', 'd8', 'e8', 'f4', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8', 'e8']
'Python-이론 > python-인공지능2' 카테고리의 다른 글
[핸즈온 머신러닝] 3강 scikitLearn Classification를 공부하고 1편 (3) | 2018.07.10 |
---|---|
[Rnn]lstm을 이용해서 악보예측해보기 (0) | 2018.06.11 |
[machineLearning] opencv로 얼굴 인식하기 (0) | 2018.06.09 |
[keras]색 있는 이미지 분류하기2 (0) | 2018.06.03 |
[keras] 색상있는 이미지 분류하기1 (0) | 2018.06.03 |