AI 기반 음악 생성의 핵심 원리와 구현 방법
최근 몇 년간 딥러닝 기술의 발전은 예술 창작 영역에도 큰 변화를 가져왔으며, 특히 음악 생성 분야에서 인상적인 성과를 보여주고 있습니다. 본 문서는 머신러닝을 이용해 음악을 자동 생성하는 시스템을 직접 개발하는 과정을 단계별로 안내합니다. MIDI 데이터 처리부터 신경망 설계, 모델 훈련 및 결과물 평가까지 실용적인 파이썬 코드와 함께 설명하며, 음악 정보 추출, 순차 데이터 모델링, 생성형 네트워크 설계 등 핵심 기술 요소를 다룹니다.
대상 독자
- 머신러닝과 음악 기술의 융합에 관심 있는 소프트웨어 개발자
- 자동 작곡 도구를 탐색 중인 프로듀서 또는 작곡가
- 음악 정보 검색(MIR) 또는 AI 아트 관련 연구를 수행하는 대학원생
- 게임, 영화, 광고 산업에서 새로운 배경 음악 생성 방식을 고려하는 크리에이터
기본 개념 이해
디지털 음악 데이터 표현 방식
AI가 음악을 학습하려면 음원 파일을 기계가 해석할 수 있는 형식으로 변환해야 합니다. 가장 일반적으로 사용되는 포맷은 MIDI(Musical Instrument Digital Interface)이며, 실제 소리를 담고 있진 않지만 음표의 높이, 길이, 강도, 시점 등의 연주 정보를 정확히 기록합니다.
MIDI 데이터는 다음과 같은 구성 요소로 이루어집니다:
- 트랙 (Track): 하나의 악기나 채널에 해당하는 연주 데이터
- 이벤트 (Event): 특정 시간에 발생하는 동작 (예: 음표 시작, 종료, 템포 변경)
- 메시지 (Message): 이벤트의 세부 값들 (예: 음높이 60 = C4, 강도 100)
예시로, 아래 바이너리 스트림은 C4음을 5틱 후에 트리거하고 10틱 후에 끝내는 시퀀스를 나타냅니다:
05 90 3C 64 ; 5틱에서 C4(60) 음 재생 시작 (강도 100)
10 80 3C 00 ; 10틱에서 C4 음 종료
음악 특징 벡터화 방법
모델 입력을 위해 MIDI 이벤트는 다음 중 하나의 형태로 전처리됩니다:
- 피아노 롤(Piano Roll): 시간-음고 축의 2D 그리드. 각 셀은 해당 음이 연주되었는지를 이진값으로 표시
- 이벤트 시퀀스(Event Sequence): (음표, 지속시간, 벨로시티) 튜플의 리스트
- 양자화된 시계열(Qualized Time Steps): 전체 곡을 고정된 시간 간격(예: 16분음표 단위)으로 나누어 벡터화
생성 모델 아키텍처 비교
LSTM 기반 음악 생성기
순차적 패턴 학습에 강점을 가진 RNN 계열 모델 중, 장기 의존성을 효과적으로 처리할 수 있는 LSTM이 널리 사용됩니다. 음악은 시간에 따라 전개되는 구조이므로, 이전 음들의 흐름을 기억하면서 다음 음을 예측하는 것이 자연스럽습니다.
기본 네트워크 흐름:
입력 시퀀스 → 임베딩 레이어 → LSTM ×2 → 완전 연결층 → Softmax 출력
각 음표는 임베딩 벡터로 인코딩되며, 두 개의 LSTM 계층을 거쳐 다음 음표의 확률 분포를 예측합니다.
GAN을 통한 고품질 음악 생성
GAN은 생성기(Generator)와 판별기(Discriminator)의 경쟁적 학습을 통해 현실감 있는 샘플을 만들어냅니다.
- 생성기: 임의의 노이즈 벡터 z를 입력받아 MIDI 시퀀스를 생성
- 판별기: 입력된 시퀀스가 실제 곡인지, 생성된 곡인지 판단
목적 함수는 다음과 같이 설정됩니다:
\[ \min_G \max_D V(D, G) = \mathbb{E}_{x \sim p_{data}}[\log D(x)] + \mathbb{E}_{z \sim p_z}[\log(1 - D(G(z)))] \]이 방식은 단순한 확률 기반 모델보다 더 복잡하고 다이나믹한 음악 구조를 생성할 수 있는 잠재력을 지닙니다.
실제 구현: LSTM 기반 멜로디 생성기
단계 1: MIDI 데이터 로드 및 정제
music21 라이브러리를 사용하여 MIDI 파일에서 음표와 화음 정보를 추출합니다.
from music21 import converter, note, chord
def extract_notes_from_midi(file_path):
midi_stream = converter.parse(file_path)
notes_list = []
for element in midi_stream.flat:
if isinstance(element, note.Note):
notes_list.append(str(element.pitch.midi))
elif isinstance(element, chord.Chord):
# 화음은 점으로 연결된 음 높이 문자열로 저장 (예: "60.64.67")
notes_list.append(".".join(str(p.midi) for p in element.pitches))
return notes_list
단계 2: 학습 데이터 준비
음표 시퀀스를 정수 인덱스로 매핑하고, 입력-출력 쌍을 생성합니다.
def prepare_training_data(note_symbols, sequence_length=32):
unique_notes = sorted(set(note_symbols))
note_to_idx = {note: i for i, note in enumerate(unique_notes)}
idx_to_note = {i: note for i, note in enumerate(unique_notes)}
input_seq = []
target_notes = []
for i in range(len(note_symbols) - sequence_length):
seq_in = note_symbols[i:i + sequence_length]
seq_out = note_symbols[i + sequence_length]
input_seq.append([note_to_idx[n] for n in seq_in])
target_notes.append(note_to_idx[seq_out])
return input_seq, target_notes, unique_notes
단계 3: 신경망 모델 구성
Keras를 사용해 다층 LSTM 기반 분류기 구축:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout
def create_composer_network(vocab_size, seq_len, embedding_dim=128, lstm_units=512):
model = Sequential()
model.add(Embedding(vocab_size, embedding_dim, input_length=seq_len))
model.add(LSTM(lstm_units, return_sequences=True, dropout=0.3))
model.add(LSTM(lstm_units, dropout=0.3))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(vocab_size, activation='softmax'))
model.compile(
loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
return model
단계 4: 모델 훈련 및 샘플 생성
훈련 후, 초기 시퀀스를 제공하면 모델이 다음 음들을 순차적으로 예측하여 새로운 곡을 생성합니다.
import numpy as np
def generate_melody(model, seed_sequence, idx_to_note_map, length=100):
generated = seed_sequence.copy()
current_seq = seed_sequence[-32:] # 최근 32개 유지
for _ in range(length):
prediction_input = np.reshape(current_seq, (1, len(current_seq)))
predicted_probs = model.predict(prediction_input, verbose=0)[0]
predicted_idx = np.random.choice(len(predicted_probs), p=predicted_probs)
generated.append(predicted_idx)
current_seq.append(predicted_idx)
current_seq = current_seq[1:] # 슬라이딩 윈도우
return [idx_to_note_map[idx] for idx in generated]
응용 사례 및 한계
AI 작곡 기술은 다음과 같은 분야에서 활용되고 있습니다:
- 영화/드라마 배경 음악 자동 생성
- 비디오 게임 내 상황에 맞는 다이나믹 사운드트랙
- 광고용 짧은 테마곡 제작
- 장애 아티스트를 위한 음악 창작 보조 도구
하지만 여전히 감정 표현, 문화적 맥락 이해, 스타일 일관성 유지 등의 문제는 해결되지 않았으며, 인간 작곡가의 직관과 감성적 깊이를 완전히 대체하기는 어렵습니다.