<jupyter_start><jupyter_text>2-1. MLP (나비야 음계 학습)  모듈 임포트- os (디렉토리 생성)- tensorflow (학습, 내부 케라스 모듈)- numpy (데이터 핸들링)<jupyter_code>import os
import tensorflow as tf
import numpy as np<jupyter_output><empty_output><jupyter_text>Logging Directory 설정<jupyter_code>CKPT_DIR = "../generated_output/MLP"<jupyter_output><empty_output><jupyter_text>Logging Directory 생성<jupyter_code>if not os.path.exists(CKPT_DIR):
    os.makedirs(CKPT_DIR)<jupyter_output><empty_output><jupyter_text>재현 위한 랜덤 시드 부여<jupyter_code>tf.set_random_seed(1234)<jupyter_output><empty_output><jupyter_text>'나비야' 악보 코드<jupyter_code>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']<jupyter_output><empty_output><jupyter_text>코드를 integer label로 인코딩 하는 매퍼 딕셔너리 label을 코드로 디코딩 하는 매퍼 딕셔너리<jupyter_code>note2idx = {'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}

idx2note = {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'}

note_num = 14<jupyter_output><empty_output><jupyter_text>데이터셋 생성 함수- window size만큼씩 옮겨 가면서 window size + 1개의 노트 수집 (feature + label)- 반복적으로 append하여 2차원 array로 변환<jupyter_code>def seq2dataset(seq, window_size):
    dataset = []
    for i in range(len(seq)-window_size):
        subset = seq[i:(i+window_size+1)]
        dataset.append([note2idx[item] for item in subset])
    return np.array(dataset)<jupyter_output><empty_output><jupyter_text>데이터셋 생성- 데이터: 나비야 코드, window size = 4- 5개씩 코드 수집하여 4개는 feature로 이용, 1개는 label로 이용<jupyter_code>dataset = seq2dataset(seq, window_size = 4)<jupyter_output><empty_output><jupyter_text>Feature, Label 추출- 데이터셋에서 4개 컬럼 추출하여 feature- 마지막 5번째 컬럼 추출하여 label- feature normalization- label one-hot encoding<jupyter_code>x_train = dataset[:,0:4]
y_train = dataset[:,4]
max_idx_value = 13
x_train = x_train / float(max_idx_value)<jupyter_output><empty_output><jupyter_text>Network 설계[batch_size, 4]$\rightarrow$ Dense(4, 128) $\rightarrow$ relu $\rightarrow$ [batch_size, 128]  $\rightarrow$ Dense(128, 128) $\rightarrow$ relu $\rightarrow$ [batch_size, 128]  $\rightarrow$ Dense(128, 14) $\rightarrow$ softmax $\rightarrow$ [batch_size, 14]<jupyter_code>model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(128, input_dim=4, activation='relu'))
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dense(note_num, activation='softmax'))<jupyter_output><empty_output><jupyter_text>Model 컴파일- loss function: sparse categorical crossentropy    - 레이블에 one-hot encoding 하지 않아도 됨- optimizer: ADAM optimizer- metrics: 학습간 로그에 표시할 메트릭<jupyter_code>model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])<jupyter_output><empty_output><jupyter_text>학습- 전체 데이터 1500회 이용- 10개 샘플씩 학습<jupyter_code>model.fit(x_train, y_train, epochs=1500, batch_size=10, verbose=1)<jupyter_output><empty_output><jupyter_text>평가<jupyter_code>scores = model.evaluate(x_train, y_train)
print("%s: %.2f%%" %(model.metrics_names[1], scores[1]*100))<jupyter_output><empty_output><jupyter_text>One step Prediction<jupyter_code>pred_count = 50
note_onestep = ['g8', 'e8', 'e4', 'f8']
# 결과 리스트 초기 4개 레이블로 초기화
pred_out = model.predict(x_train)
# x_train 전체 데이터로 prediction 진행

for i in range(pred_count):
    
    idx = np.argmax(pred_out[i])
    # one-hot encoding된 상태로 나온 prediction 자연수 레이블로 변환
    note_onestep.append(idx2note[idx])
    # 레이블 코드로 변환하여 결과 리스트에 추가<jupyter_output><empty_output><jupyter_text>Full song Prediction<jupyter_code>seq_in = ['g8', 'e8', 'e4', 'f8']
# 초기 4개 인풋값 리스트 설정
note_fullsong = seq_in
# 결과 리스트 초기 4개 레이블로 초기화
seq_in = [note2idx[it] / float(max_idx_value) for it in seq_in]
# 초기 4개 인풋값 Network에 투입 가능한 형태로 전처리

for i in range(pred_count):
    
    sample_in = np.array(seq_in)
    # input array 인풋 리스트값으로 초기화
    sample_in = np.reshape(sample_in, (1, 4))
    # (4,)형태의 input array를 (1, 4)형태로 변환
    pred_out = model.predict(sample_in)
    # 1개 batch (4개 코드에 대한 결과) prediction
    idx = np.argmax(pred_out)
    # one-hot encoding된 상태로 나온 prediction 자연수 레이블로 변환
    note_fullsong.append(idx2note[idx])
    # 레이블 코드로 변환하여 결과 리스트에 추가
    seq_in.append(idx / float(max_idx_value))
    # 인풋 리스트에 prediction 결과 전처리하여 추가
    seq_in.pop(0)
    # 인풋 리스트에서 맨 앞의 값 제거<jupyter_output><empty_output><jupyter_text>Prediction 결과<jupyter_code>print("one step prediction : ", note_onestep)
print("full song prediction : ", note_fullsong)<jupyter_output><empty_output><jupyter_text>코드 MIDI파일로 컴파일하여 저장<jupyter_code>import music21 as m21

def writeMIDI(key,instr,bpm,notes,fname):

    # start stream
    stream = m21.stream.Stream()

    # Add tempo to stream
    bpm = m21.tempo.MetronomeMark(number = bpm)
    stream.append(bpm)

    # Add key to stream
    k = m21.key.Key(key)
    stream.append(k)

    # Add instrument
    ins = m21.instrument.fromString(instr)
    stream.append(ins)

    # Add notes to stream at different offsets
    for tup in notes:
        note = m21.note.Note(tup[0])
        offset = tup[1]
        note.quarterLength = tup[2]
        note.volume.velocity = tup[3]
        stream.insert(offset,note)

    # convert stream to midi and write out
    mf = m21.midi.translate.streamToMidiFile(stream)
    mf.open(fname+'.mid', 'wb')
    mf.write()
def note2midi(notes, num):    # input : seq_out
    n = []
    global start
    start = 0    # 맨 첫 note의 시작 위치
    for i in range(len(notes)):
        #print(notes[i][0], notes[i][1])
        timing = int(8/int(notes[i][1]))
        
        if timing == 1: n.append((notes[i][0]+'5',start+i,1,120))
        else :
            n.append((notes[i][0]+'5',start+i,1*timing,120))
            start += 1
        
        # Output MIDI (Root, Inst., BPM, Notes, File_name)
        if not os.path.exists(CKPT_DIR+'/Midi'):
            os.makedirs(CKPT_DIR+'/Midi')
        writeMIDI('C','piano', 130, n, (CKPT_DIR+'/Midi/MLP_result_%d' % num))
        
    return print("MLP result_%d export complete!" % num)


note2midi(note_onestep, 1)
note2midi(note_fullsong, 2)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16001877053026747, 'fraction_numerical': 0.04192085093070546, 'mean_word_length': 4.437074829931973, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '261554', 'license': 'MIT', 'n_tokens_mistral': 3125, 'n_tokens_neox': 3318, 'n_words': 555, 'path': 'study2/2_sequential/2_2_1_mlp.ipynb', 'repo_name': 'github2ygl/learn-choki0715-', 'size': '6393'}