스펙트로그램, Mel 스케일과 오디오 피처

신경망(Neural Network)은 원시 파형(raw waveform)을 그대로 잘 소화하지 못합니다. 스펙트로그램(spectrogram)은 그보다 낫고, 멜 스펙트로그램(mel spectrogram)은 한층 더 잘 받아들입니다. 2026년의 모든 음성 인식(ASR), 음성 합성(TTS), 오디오 분류기(audio classifier)는 결국 이 전처리(preprocessing) 선택 하나에 따라 성패가 갈립니다.

유형: Build 언어: Python 선수 강의: Phase 6 · 01 (오디오 기초 — 파형, 샘플링, 푸리에 변환) 예상 시간: 약 45분

학습 목표

  • 단시간 푸리에 변환(Short-Time Fourier Transform; STFT)이 파형을 시간 × 주파수 행렬(time × frequency matrix)로 변환하는 과정을 설명합니다.
  • 멜 스케일(Mel scale)과 멜 필터뱅크(mel filterbank)가 인간의 청각 지각(human perception)에 맞춰 주파수 축을 휘게 만드는 방식을 이해합니다.
  • 로그-멜 스펙트로그램(log-mel spectrogram)과 멜 주파수 켑스트럼 계수(Mel-Frequency Cepstral Coefficients; MFCC)의 차이를 구분합니다.
  • 대상 모델(target model)에 맞춰 프레임(frame), 홉(hop), 멜 개수(mel count), 정규화(normalization)를 선택합니다.

문제

10초짜리 16 kHz 클립(clip)을 떠올려 봅시다. 이는 160,000개의 부동소수점(float)이며, 모두 [-1, 1] 범위에 들어 있지만, "dog barking"이나 "the word cat" 같은 레이블(label)과는 거의 무상관에 가깝습니다. 원시 파형은 정보를 담고 있지만, 모델이 쉽게 뽑아낼 수 있는 형태가 아닙니다. 같은 음소(phoneme)라도 100 ms 차이로 발화하면 원시 샘플(raw sample) 값은 완전히 달라집니다.

스펙트로그램은 이 문제를 줄여 줍니다. 사람이 듣지 못하는 마이크로초 수준의 미세한 흔들림(microsecond jitter)은 접어 버리고, 사람이 주목하는 구조, 즉 약 10–25 ms의 시간 창(time window) 동안 어떤 주파수가 강하게 나타나는지를 보존합니다.

멜 스펙트로그램은 한 걸음 더 나아갑니다. 사람은 음높이(pitch)를 로그적으로 인지합니다. 100 Hz와 200 Hz의 거리는 1000 Hz와 2000 Hz의 거리와 "같은 정도로" 느껴집니다. 멜 스케일은 이 지각에 맞도록 주파수 축을 휘게 만듭니다. 멜로 스케일링된 스펙트로그램(mel-scaled spectrogram)은 2010년부터 2026년에 이르기까지 음성 머신러닝(speech ML)에서 가장 중요한 피처(feature)입니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.멜 스케일(Mel scale)이 1 kHz 이상에서 주파수 축을 선형이 아닌 로그적으로 휘게 만드는 이유는 무엇인가요?

2.로그-멜 스펙트로그램(log-mel spectrogram)과 MFCC를 음성 모델의 입력 피처로 쓸 때 핵심 차이점은 무엇인가요?

0/2 답변 완료

개념

the four-step ladder every audio model climbs 1. waveform T samples in [-1, 1] 10 s at 16 kHz = 160,000 frame+FFT 2. STFT |FFT| per 25 ms frame, 10 ms hop filterbank 3. log-mel 80 mels, log scale, [T, 80] DCT (opt) 4. model input Whisper: log-mel Parakeet: log-mel ECAPA: log-mel KWS tiny: MFCC-13 tensor: [batch, T, 80] mel scale is log-perception of pitch mel Hz 0 1 kHz 4 kHz 8 kHz m = 2595 · log10(1 + f / 700) triangular mel filterbank Hz (linear) — triangles widen with frequency each mel bin = weighted sum of FFT bins

STFT(Short-Time Fourier Transform). 파형을 겹치는 프레임으로 잘라 냅니다. 16 kHz 기준으로 25 ms 윈도우(window)와 10 ms 홉(hop), 즉 400 샘플 / 160 샘플이 일반적입니다. 각 프레임에는 윈도우 함수를 곱합니다(기본은 Hann 윈도우이며, Hamming은 약간 다른 트레이드오프를 갖습니다). 그런 다음 각 프레임에 고속 푸리에 변환(Fast Fourier Transform; FFT)을 적용합니다. 크기 스펙트럼(magnitude spectrum)을 쌓으면 (n_frames, n_freq_bins) 형태의 행렬이 되며, 이것이 스펙트로그램입니다.

로그-크기(Log-magnitude). 원시 크기는 5~6자릿수의 동적 범위(dynamic range)를 갖습니다. log(|X| + 1e-6) 또는 20 * log10(|X|)로 압축합니다. 모든 프로덕션 파이프라인은 원시 크기가 아니라 로그-크기를 사용합니다.

멜 스케일(Mel scale). Hz 단위 주파수 fm = 2595 * log10(1 + f / 700)을 통해 멜 값 m으로 변환됩니다. 1 kHz 아래에서는 거의 선형(linear)이고 그 위에서는 거의 로그적(logarithmic)입니다. 0–8 kHz를 덮는 80개의 멜 빈(mel bin)이 ASR 입력의 표준입니다.

멜 필터뱅크(Mel filterbank). 멜 스케일에서 등간격으로 배치된 삼각 필터(triangular filter) 모음입니다. 각 필터는 인접한 FFT 빈의 가중합(weighted sum)입니다. STFT 크기에 필터뱅크 행렬을 곱하면 단 한 번의 행렬곱(matmul)으로 멜 스펙트로그램이 만들어집니다.

로그-멜 스펙트로그램(Log-mel spectrogram). log(mel_spec + 1e-10)입니다. Whisper의 입력이고, Parakeet의 입력이며, SeamlessM4T의 입력입니다. 2026년의 보편적인 오디오 프론트엔드(audio frontend)입니다.

MFCC(Mel-Frequency Cepstral Coefficients). 로그-멜 스펙트로그램에 이산 코사인 변환(Discrete Cosine Transform; DCT) Type II를 적용한 뒤 앞쪽 13개의 계수를 남깁니다. 피처를 서로 비상관화(decorrelate)하고 더 압축합니다. 2015년 무렵 CNN/Transformer가 원시 로그-멜을 잘 다루기 전까지 지배적인 피처였으며, 화자 인식(speaker recognition) 분야에서는 x-vectors와 ECAPA 같은 곳에서 지금도 쓰입니다.

해상도 트레이드오프(Resolution trade). FFT가 클수록 주파수 해상도(frequency resolution)는 좋아지지만 시간 해상도(time resolution)는 나빠집니다. 오디오 머신러닝의 기본은 25 ms / 10 ms이고, 음악(music)에는 50 ms / 12.5 ms, 트랜지언트 감지(transient detection; 드럼 타격, 파열음 등)에는 5 ms / 2 ms가 쓰입니다.

직접 만들기

Step 1: 파형을 프레임으로 자르기

def frame(signal, frame_len, hop):
    n = 1 + (len(signal) - frame_len) // hop
    return [signal[i * hop : i * hop + frame_len] for i in range(n)]

10초 16 kHz 클립을 frame_len=400, hop=160으로 자르면 998개의 프레임이 나옵니다.

Step 2: Hann 윈도우

import math

def hann(N):
    return [0.5 * (1 - math.cos(2 * math.pi * n / (N - 1))) for n in range(N)]

FFT 적용 전에 원소별(element-wise)로 곱합니다. 양 끝이 0이 아닌 지점에서 잘려 나가면서 발생하는 스펙트럼 누설(spectral leakage)을 줄여 줍니다.

Step 3: STFT 크기

def stft_magnitude(signal, frame_len=400, hop=160):
    win = hann(frame_len)
    frames = frame(signal, frame_len, hop)
    return [magnitudes(dft([w * s for w, s in zip(win, f)])) for f in frames]

실제 프로덕션에서는 FFT 기반으로 벡터화된 torch.stft 또는 librosa.stft를 사용합니다. 여기에 있는 반복문은 학습 목적이며, code/main.py에 있는 짧은 클립에서 실행됩니다.

Step 4: 멜 필터뱅크

def hz_to_mel(f):
    return 2595.0 * math.log10(1.0 + f / 700.0)

def mel_to_hz(m):
    return 700.0 * (10 ** (m / 2595.0) - 1)

def mel_filterbank(n_mels, n_fft, sr, fmin=0, fmax=None):
    fmax = fmax or sr / 2
    mels = [hz_to_mel(fmin) + (hz_to_mel(fmax) - hz_to_mel(fmin)) * i / (n_mels + 1)
            for i in range(n_mels + 2)]
    hzs = [mel_to_hz(m) for m in mels]
    bins = [int(h * n_fft / sr) for h in hzs]
    fb = [[0.0] * (n_fft // 2 + 1) for _ in range(n_mels)]
    for m in range(n_mels):
        for k in range(bins[m], bins[m + 1]):
            fb[m][k] = (k - bins[m]) / max(1, bins[m + 1] - bins[m])
        for k in range(bins[m + 1], bins[m + 2]):
            fb[m][k] = (bins[m + 2] - k) / max(1, bins[m + 2] - bins[m + 1])
    return fb

0–8 kHz를 덮는 80개의 멜 빈을 n_fft=400으로 만들면 (80, 201) 행렬이 됩니다. (n_frames, 201) STFT 크기에 이 행렬의 전치(transpose)를 곱하면 (n_frames, 80) 형태의 멜 스펙트로그램이 만들어집니다.

Step 5: 로그-멜

def log_mel(mel_spec, eps=1e-10):
    return [[math.log(max(v, eps)) for v in frame] for frame in mel_spec]

흔히 사용되는 대안으로는 librosa.power_to_db(기준값 기반 dB 정규화)와 10 * log10(power + eps)가 있습니다. Whisper는 클리핑과 정규화를 함께 적용하는 더 정교한 루틴을 사용합니다(Whisper의 log_mel_spectrogram 참고).

Step 6: MFCC

def dct_ii(x, n_coeffs):
    N = len(x)
    return [
        sum(x[n] * math.cos(math.pi * k * (2 * n + 1) / (2 * N)) for n in range(N))
        for k in range(n_coeffs)
    ]

각 로그-멜 프레임에 DCT를 적용한 뒤 앞쪽 13개의 계수를 남기면 MFCC 행렬이 됩니다. 보통 첫 번째 계수는 전체 에너지(overall energy)를 담기 때문에 떨어내고 사용합니다.

사용해 보기

2026년 기준 표준 스택은 다음과 같습니다.

작업피처
ASR (Whisper, Parakeet, SeamlessM4T)80개 로그-멜, 10 ms 홉, 25 ms 윈도우
TTS 음향 모델 (VITS, F5-TTS, Kokoro)80개 멜, 정밀한 시간 제어를 위해 5–12 ms 홉
오디오 분류 (AST, PANNs, BEATs)128개 로그-멜, 10 ms 홉
화자 임베딩 (ECAPA-TDNN, WavLM)80개 로그-멜 또는 원시 파형 기반 SSL
음악 (MusicGen, Stable Audio 2)EnCodec 이산 토큰(mel이 아님)
키워드 스포팅(keyword spotting)초소형 디바이스용 40개 MFCC

경험 법칙(rule of thumb)은 단순합니다. 음악 작업이 아니라면 80개의 로그-멜에서 시작하십시오. 거기서 벗어나려면 그만한 근거가 있어야 합니다.

2026년에도 여전히 출하되는 함정들

  • 멜 개수 불일치. 학습은 80개 멜로 했는데 추론은 128개 멜로 진행하면 조용히 실패합니다. 양쪽 끝에서 피처의 shape를 로깅하십시오.
  • 상류단의 샘플링 레이트 불일치. 22.05 kHz에서 계산한 멜은 16 kHz의 멜과 다릅니다. 피처를 만들기 전에 샘플링 레이트(SR)를 맞추십시오.
  • dB vs log. Whisper는 dB-멜이 아니라 로그-멜을 기대합니다. 일부 Hugging Face 파이프라인은 자동으로 감지하지만, 직접 작성한 코드는 그렇게 해 주지 않습니다.
  • 정규화 표류(Normalization drift). 학습에서는 발화 단위(per-utterance) 정규화를 쓰고, 추론에서는 전역(global) 정규화를 쓰면 WER(단어 오류율)이 두 배가 되는 프로덕션 버그가 됩니다.
  • 패딩에서 누설. 클립 끝을 0으로 패딩하면 마지막 프레임에 평탄한 스펙트럼이 생깁니다. 대칭으로 패딩(pad symmetrically)하거나 복제(replicate)하십시오.

산출물 만들기

outputs/skill-feature-extractor.md로 저장합니다. 이 스킬은 주어진 대상 모델에 맞춰 피처 타입, 멜 개수, 프레임/홉, 정규화 전략을 골라 줍니다.

연습문제

  1. 쉬움. code/main.py를 실행합니다. 200 Hz에서 4000 Hz로 올라가는 처프(chirp)를 합성하고, 프레임별 argmax 멜 빈을 출력합니다. (선택) 그래프로 그려 스윕(sweep)과 일치하는지 확인합니다.
  2. 중간. n_mels{40, 80, 128}, frame_len{200, 400, 800}으로 바꿔 다시 실행합니다. 시간축에서 날카로운 피크의 대역폭(sharp-peak bandwidth)을 측정해, 어떤 조합이 처프를 가장 잘 분해하는지 확인합니다.
  3. 어려움. power_to_db를 구현하고, AudioMNIST에서 작은 CNN 분류기로 (a) 원시 로그-멜, (b) ref=max 기반 dB-멜, (c) MFCC-13 + delta + delta-delta의 top-1 정확도를 비교해 보고서로 정리합니다.

핵심 용어

용어흔한 설명실제 의미
프레임(Frame)한 조각하나의 FFT에 들어가는 25 ms 길이의 파형 덩어리입니다.
홉(Hop)스트라이드(stride)연속된 프레임 사이의 샘플 수이며, ASR 기본값은 10 ms입니다.
윈도우(Window)Hann/Hamming 같은 것프레임의 양끝을 0에 가깝게 감쇠시키는 원소별 곱셈자입니다.
STFT스펙트로그램 생성기프레이밍 + 윈도잉 후 FFT를 적용해 시간 × 주파수 행렬을 만듭니다.
멜(Mel)휘어진 주파수청각 지각에 맞춘 로그 스케일이며, m = 2595·log10(1 + f/700)입니다.
필터뱅크(Filterbank)그 행렬STFT를 멜 빈으로 사영하는 삼각 필터들의 모음입니다.
로그-멜(Log-mel)Whisper 입력log(mel_spec + eps)이며 2026년의 표준입니다.
MFCC옛날식 피처로그-멜의 DCT 계수이며, 13개 계수로 비상관화됩니다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

feature-extractor

Pick feature type, mel count, frame/hop, and normalization to match a downstream audio model.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.ASR 모델을 80개 멜 빈(mel bin)으로 학습했는데, 추론 파이프라인에서 실수로 128개 멜 빈을 사용했습니다. 모델은 에러 없이 실행되지만 WER이 두 배로 올라갑니다. 이 조용한 실패는 왜 일어나나요?

2.STFT 파라미터를 선택할 때, FFT 윈도우 크기를 키우면 주파수 해상도(frequency resolution)는 좋아지지만 시간 해상도(time resolution)는 나빠집니다. 짧은 윈도우(예: 5 ms)가 가장 유리한 상황은 어느 쪽인가요?

3.TTS 모델을 발화 단위(per-utterance) 정규화된 멜 피처로 학습했는데, 추론 시에는 전체 데이터셋에서 구한 전역(global) 정규화를 적용했더니 오디오 품질이 크게 떨어졌습니다. 무엇이 원인인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다