๐โโ๏ธ ํด๋น ๊ธ์ Tensorflow๋ฅผ ์ฌ์ฉํ๊ธฐ์ ํ๊ฒฝ์ด ๊ตฌ์ถ๋์ด์ผ ํฉ๋๋ค.
Anaconda3 + tensorflow ํค์๋๋ก ๊ตฌ๊ธ๋งํด์ ๋์ค๋ ๋ธ๋ก๊ทธ๋ค์ ์ฐธ๊ณ ๋ฐ๋๋๋ค!
00. ๋ชฉํ
๋๋ผ ์๋ฆฌ ํ์ผ์ ๋ฃ์์ ๋, ๋ฌด์จ ๋ถ์ ์ณค๋ ์ง ๊ตฌ๋ถํ๋ ๋ชจ๋ธ์ ๋ง๋ญ๋๋ค.

input :
output : Tom
01. ๊ธฐ๋ณธ ์ง์
์ํฅ์ ํน์ฑ์ ๋ํ ๊ธฐ๋ณธ ์ง์
๐ ์คํํธ๋ผ(Spectrum)
์๋ฆฌ ์ ํธ๋ฅผ ์ฃผํ์์ ์งํญ์ผ๋ก ๋ถ์
ํธ๋ฆฌ์ ๋ณํ์ ์ ์ฉํ์ฌ ์๊ฐ ์์ญ์ ์ ํธ๋ฅผ ์ฃผํ์ ์์ญ์ผ๋ก ๋ณํ์๊ฐ ์์ญ & ์ฃผํ์ ์์ญ ์๊ฐํ (X์ถ: ์ฃผํ์, Y์ถ: ์งํญ) https://ratsgo.github.io/speechbook/docs/fe/ft ๐ ๋ฉ ์คํํธ๋ก๊ทธ๋จ(Mel Spectrogram)
์ธ๊ฐ์ ์ฒญ๊ฐ ์์ญ์ ๋ฐ์ํ Mel scale์ ์ ์ฉ
- ์ธ๊ฐ์ ๋ณดํต ์ ์ฃผํ๋ฅผ ๋ ์ ์ธ์ํจ
๐ MFCC(Mel-Frequency Cepstral Coefficient)
์ค๋์ค ์ ํธ์์ ์ถ์ถํ ์ ์๋ feature๋ก, ์๋ฆฌ์ ๊ณ ์ ํ ํน์ง์ ๋ํ๋ด๋ ์์น
์คํํธ๋ก๊ทธ๋จ ์์ฑ โก๏ธ Mel scale ์ ์ฉ โก๏ธ ๋ฉ ์คํํธ๋ก๊ทธ๋จ ์์ฑ โก๏ธ ์บก์คํธ๋ด(Cepstral) ๋ถ์ โก๏ธ MFCC ํน์ฑ ์ถ์ถ
02. ์ํฅ์ ํน์ฑ ์ถ์ถ
์ํฅ์ ํน์ฑ์ ๋ถ์ํด์ฃผ๋ ์ ์ฉํ ํ์ด์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ librosa๊ฐ ์์ต๋๋ค.

librosa โ librosa 0.10.1 documentation
ยฉ Copyright 2013--2023, librosa development team.
librosa.org
librosa๋ฅผ ํตํด mfcc๋ฅผ ์ถ์ถ ํ, numpy๋ฅผ ์ด์ฉํด์ ํน์ง์ width๋ฅผ ์กฐ์ ํด์ค๋๋ค.
โจ ์ฐ๋ฆฌ๊ฐ ์ถ์ถํ๋ ๋ฐ์ดํฐ์ shape์ (40, 174) ์ด๊ณ , ์ด shape์ ์ผ๋ง๋ ์ง ์กฐ์ ํ ์ ์์ต๋๋ค.
์ฝ๋ ๊ทธ๋๋ก 2์ฐจ์์ผ๋ก ์ถ์ถํด๋ ๋๊ณ shape์ ์กฐ์ ํด์ 1์ฐจ์์ผ๋ก ๋์ด๋จ๋ ค๋ ๋ฉ๋๋ค.
root = wav_ํ์ผ์ด_์๋_ํด๋_path
test = root + .wav_name
max_pad_len = 174
def extract_feature(file_name):
try:
audio, sample_rate = librosa.load(file_name, res_type='kaiser_fast')
mfccs = librosa.feature.mfcc(y=audio, sr=sample_rate, n_mfcc=40)
pad_width = max_pad_len - mfccs.shape[1]
mfccs = np.pad(mfccs, pad_width=((0,0), (0, pad_width)), mode='constant')
print(mfccs.shape)
except Exception as e:
print("Error encountered while parsing file: ", file_name)
print(e)
return None
return mfccs
extract_feature(test) # ํ์ธ

ํ wav ํ์ผ์ ํ ์คํธ ํด๋ณด๊ณ shape (40, 174) ์ด ๋์ค๋ ๊ฑธ ํ์ธํฉ๋๋ค!
์ด์ ์ฌ๋ฌ wav ํ์ผ์ ๋์์ผ๋ก ํน์ฑ์ ์ถ์ถํ๊ฒ ์ต๋๋ค.
์ฐ์ ์ ๋ Overhead, Snare, Tom, Bass ๋ฐ์ดํฐ์ ์ 40๊ฐ์ฉ ์ค๋นํ์์ต๋๋ค.
data๋ ๋ฆฌ๋ธ๋ก์ฌ๋ก ์ถ์ถํ ํน์ฑ mfcc
class_label์ ๊ทธ ๋๋ผ์ ์ข ๋ฅ (Overhead:1, Snare:2, Tom:3, Bass:4 ์์๋ก ์ ํจ)
โก๏ธ ์ฆ, ๋ฅ๋ฌ๋์ด ๋ถ๋ฅํ ํด๋์ค๋ 4๊ฐ์ง
root_path = wav_ํ์ผ๋ค์ด_์๋_ํด๋_path
wav_list = os.listdir(root_path)
wav_files = [os.path.join(root_path, file) for file in wav_list if file.endswith('.wav')]
print(len(wav_files))
features = []
for wav_file in wav_files:
# data๋ ๋ฆฌ๋ธ๋ก์ฌ๋ก ์ถ์ถํ mfccs๋ผ๋ ํน์ฑ์ด๊ณ
# class_label์ ๊ทธ ๋๋ผ์ ์ข
๋ฅ๋ฅผ ๋ํ๋ธ๋ค.
data = extract_feature(wav_file)
class_label = 0
if 'Overhead' in wav_file:
class_label = 1
elif 'Snare' in wav_file:
class_label = 2
elif 'Tom' in wav_file:
class_label = 3
elif 'Bass' in wav_file:
class_label = 4
else:
class_label = 0
features.append([data, class_label])
# Convert into a Panda dataframe
featuresdf = pd.DataFrame(features, columns=['feature','class_label'])
featuresdf์ Panda ํํ๋ก ์ ์ฅ๋์์ต๋๋ค!
03. ํ๋ จ(Train), ๊ฒ์ฆ(Test) Dataset ์์ฑ
featuresdf์ feature๋ X๋ก, class_label์ y๋ก ์ ์ฅํฉ๋๋ค.
โจ ์ฌ๊ธฐ์ y๋ one-hot-encoding ๋ณํ์ ํด์ผ ํฉ๋๋ค.
๐one-hot-encoding
์๋ฅผ ๋ค์ด, ์์ฐ์ 1, 2, 3 ์์ ๋ 1:[1.0.0] / 2:[0.1.0] / 3:[0.0.1] ์ด๋ฐ ์์ผ๋ก ๋ณํ
์ด๋ ๊ฒ ๋ณํํ๋ ์ด์ ๋, ํด๋น ๊ธ์์์ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ด ๋ฉํฐ ํด๋์ค(3~ ๊ฐ์ง) ๋ถ๋ฅ๋ฅผ ํ๊ธฐ ๋๋ฌธ
โก๏ธ ์ฌ๋์ด ์ดํดํ๊ธฐ ์ฌ์ด ๋ฐ์ดํฐ๋ฅผ ์ปดํจํฐ๊ฐ ์ดํดํ๊ธฐ ์ฌ์ด ๋ฐ์ดํฐ๋ก ๋ณํํ๋ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ
from keras.utils import to_categorical
X = np.array(featuresdf.feature.tolist())
y = np.array(featuresdf.class_label.tolist())
le = LabelEncoder()
yy = to_categorical(le.fit_transform(y))
ํ๋ จ, ๊ฒ์ฆ Dataset ๋น์จ์ 8:2๋ก ๋ถ๋ฅํ์ต๋๋ค.
x_train, x_test, y_train, y_test = train_test_split(X, yy, test_size=0.2, random_state = 42)
# ํ์ธ
print(x_train.shape)
print(x_test.shape)
print(y[:10])
print(yy[:10])
print(y_test[:10])

๋ง์ง๋ง์ผ๋ก ํ๋ จ, ๊ฒ์ฆ Dataset ๊ฐ๊ฐ์ input x ๋ฐ์ดํฐ์ ๋ํด shape์ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ๋ฃ๊ธฐ ์ํ ๋ชจ์ต์ผ๋ก ๋ณํํด ์ค๋๋ค.
n_columns = 174
n_row = 40
n_channels = 1
n_classes = 4
# input shape ์กฐ์
# cpu๋ฅผ ์ฌ์ฉํด์ ์ํ
with tf.device('/cpu:0'):
x_train = tf.reshape(x_train, [-1, n_row, n_columns, n_channels])
x_test = tf.reshape(x_test, [-1, n_row, n_columns, n_channels])
04. ๋ฅ๋ฌ๋ ๋ชจ๋ธ ์์ฑ
CNN์ด๋ผ๋ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค.
model = keras.Sequential()
model.add(layers.Conv2D(input_shape=(n_row, n_columns, n_channels), filters=16, kernel_size=2, activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.2))
model.add(layers.Conv2D(kernel_size=2, filters=32, activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.2))
model.add(layers.Conv2D(kernel_size=2, filters=64, activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.2))
model.add(layers.Conv2D(kernel_size=2, filters=128, activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.2))
model.add(layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(units=n_classes, activation='softmax'))
model.summary() # ๋ชจ๋ธ ํ์ธ

05. ํ๋ จ
ํ๋ จ...
training_epochs = 72
num_batch_size = 128
learning_rate = 0.001
opt = keras.optimizers.Adam(learning_rate=learning_rate)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=num_batch_size, epochs=training_epochs) # ํ๋ จ

trainํ, ๋ฐํํ history๋ฅผ ๊ทธ๋ํ๋ก ํ์ธํ๊ฒ ์ต๋๋ค.
accuracy, loss ๋ฑ ์ ๋ํ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
import matplotlib.pyplot as plt
def vis(history, key):
x = np.arange(0, training_epochs)
y = list(history.history[key])
plt.plot(x, y)
plt.title(key)
def plot_history(history) :
# 0 accuracy, 1 loss
key_value = list(set([i.split("val_")[-1] for i in list(history.history.keys())]))
plt.figure(figsize=(12, 4))
for idx , key in enumerate(key_value) :
plt.subplot(1, len(key_value), idx+1)
vis(history, key)
plt.tight_layout()
plt.show()
plot_history(history)

์์ฃผ ๊ตฟ์ ๋๋ค.
06. ๋ชจ๋ธ ๊ฒ์ฆ
print('\n# Evaluate on test data')
results = model.evaluate(x_test, y_test, batch_size=128)
print('test loss, test acc:', results)

๊ฒ์ฆ ๊ฒฐ๊ณผ accuracy 80!
๋ฐ์ดํฐ๊ฐ ๊ทธ๋ ๊ฒ ๋ง์ง ์๊ณ , ์ํ ์ ๋๋ก๋ง ์์ด์ ๊ทธ๋ฆฌ ์ ๋ขฐ์ฑ ์๋ ๋ชจ๋ธ์ ์๋์ง๋ง..
07. ์์ธก
root = ์์ธกํ _wav_ํ์ผ์ด_์๋_ํด๋_path
test = root + ์์ธกํ _.wav_name
n_columns = 174
n_row = 40
n_channels = 1
# input shape ์กฐ์
# cpu๋ฅผ ์ฌ์ฉํด์ ์ํํ๋ค
test = np.array(extract_feature(test))
with tf.device('/cpu:0'):
test = tf.reshape(test, [-1, n_row, n_columns, n_channels])
# Overhead:1, Snare:2, Tom:3, Bass:4
model.predict(test, batch_size=128)

๐ array([[overhead์ผ ํ๋ฅ , Snare์ผ ํ๋ฅ , Tom์ผ ํ๋ฅ , Bass์ผ ํ๋ฅ ]], dtype=float32)
Overhead.wav ํ์ผ์ ๋ฃ์์ ๋, ๊ฐ์ฅ ๋์ ํ๋ฅ ๋ก Overhead๋ก ์์ธกํ์ต๋๋ค!
๊ฐ์ฌํฉ๋๋ค.
'๐ป My Work > ๐ง AI' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ฅ๋ฌ๋] Optical Music Recognition(OMR) ๋๋ผ ์ ๋ณด ์ธ์ ๋ชจ๋ธ (0) | 2024.05.20 |
---|---|
[MiniHack] ํ๊ฒฝ ์ธํ (0) | 2023.01.04 |
[์ธ๊ณต์ง๋ฅ/ํผ๊ณต๋จธ์ ] 07-1. ์ธ๊ณต ์ ๊ฒฝ๋ง (3) (0) | 2023.01.02 |
[์ธ๊ณต์ง๋ฅ/ํผ๊ณต๋จธ์ ] 07-1. ์ธ๊ณต ์ ๊ฒฝ๋ง (2) (0) | 2023.01.01 |
[์ธ๊ณต์ง๋ฅ/ํผ๊ณต๋จธ์ ] 07-1. ์ธ๊ณต ์ ๊ฒฝ๋ง (1) (0) | 2022.12.17 |