Skip to content

필사 모드: torchaudio 완전 가이드 — 오디오 처리부터 음성인식, TTS, 음악 분석까지

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

`torchaudio`는 PyTorch의 공식 오디오 처리 라이브러리입니다. 오디오 I/O, 스펙트로그램 변환, 사전학습 모델(Wav2Vec2, HuBERT, Whisper), 그리고 실시간 스트리밍까지 지원합니다.

pip install torch torchaudio

Part 1: 오디오 기초

오디오 로드 및 저장

오디오 로드

waveform, sample_rate = torchaudio.load("speech.wav")

print(f"Shape: {waveform.shape}") # [channels, samples]

print(f"Sample Rate: {sample_rate}") # 16000

print(f"Duration: {waveform.shape[1] / sample_rate:.2f}s")

채널: 모노(1) vs 스테레오(2)

if waveform.shape[0] == 2:

mono = waveform.mean(dim=0, keepdim=True) # 스테레오 → 모노

리샘플링 (44100Hz → 16000Hz)

resampler = torchaudio.transforms.Resample(

orig_freq=44100, new_freq=16000

)

waveform_16k = resampler(waveform)

저장

torchaudio.save("output.wav", waveform_16k, 16000)

지원 포맷: wav, flac, mp3, ogg, opus, sphere

백엔드: sox, soundfile, ffmpeg

print(torchaudio.list_audio_backends())

오디오 시각화

파형 (Waveform)

fig, axes = plt.subplots(3, 1, figsize=(12, 8))

1. 시간 도메인 (파형)

time_axis = torch.arange(0, waveform.shape[1]) / sample_rate

axes[0].plot(time_axis, waveform[0])

axes[0].set_title("Waveform")

axes[0].set_xlabel("Time (s)")

axes[0].set_ylabel("Amplitude")

2. 스펙트로그램

spectrogram = torchaudio.transforms.Spectrogram(n_fft=1024)(waveform)

axes[1].imshow(

spectrogram[0].log2().numpy(),

aspect='auto', origin='lower', cmap='magma'

)

axes[1].set_title("Spectrogram")

3. Mel 스펙트로그램

mel_spec = torchaudio.transforms.MelSpectrogram(

sample_rate=sample_rate, n_fft=1024, n_mels=80

)(waveform)

axes[2].imshow(

mel_spec[0].log2().numpy(),

aspect='auto', origin='lower', cmap='magma'

)

axes[2].set_title("Mel Spectrogram")

plt.tight_layout()

plt.savefig("audio_analysis.png", dpi=150)

Part 2: 핵심 변환 (Transforms)

스펙트로그램 계열

STFT (Short-Time Fourier Transform)

시간 → 시간+주파수 영역으로 변환

spectrogram_transform = torchaudio.transforms.Spectrogram(

n_fft=1024, # FFT 윈도우 크기 (주파수 해상도)

hop_length=256, # 윈도우 이동 간격 (시간 해상도)

win_length=1024, # 윈도우 길이

power=2.0, # 2.0=파워, 1.0=진폭

)

spec = spectrogram_transform(waveform)

shape: [channels, n_freq_bins, time_frames]

n_freq_bins = n_fft // 2 + 1 = 513

n_fft와 hop_length의 트레이드오프:

n_fft ↑ → 주파수 해상도 ↑, 시간 해상도 ↓

n_fft ↓ → 주파수 해상도 ↓, 시간 해상도 ↑

일반적인 설정:

├── 음성: n_fft=400~512, hop=160 (16kHz 기준)

├── 음악: n_fft=2048, hop=512 (44.1kHz 기준)

└── 범용: n_fft=1024, hop=256

Mel 스펙트로그램 — 왜 Mel인가?

사람의 귀는 저주파에 민감, 고주파에 둔감

Mel 스케일 = 인간 청각을 반영한 주파수 스케일

mel_transform = torchaudio.transforms.MelSpectrogram(

sample_rate=16000,

n_fft=1024,

hop_length=256,

n_mels=80, # Mel 필터 개수 (보통 40~128)

f_min=0, # 최소 주파수

f_max=8000, # 최대 주파수 (Nyquist)

)

mel_spec = mel_transform(waveform)

shape: [1, 80, time_frames]

dB 스케일 변환 (로그 압축)

amplitude_to_db = torchaudio.transforms.AmplitudeToDB(stype='power', top_db=80)

mel_spec_db = amplitude_to_db(mel_spec)

Mel 주파수 변환 공식:

mel = 2595 × log10(1 + freq / 700)

주파수 → Mel:

100 Hz → 150 mel (저주파: 조밀)

1000 Hz → 1000 mel

4000 Hz → 2146 mel

8000 Hz → 2840 mel (고주파: 성긴)

→ 저주파는 세밀하게, 고주파는 뭉뚱그려서 분석

→ 사람이 듣는 것과 비슷한 표현!

MFCC (Mel-Frequency Cepstral Coefficients)

MFCC = Mel 스펙트로그램 + DCT (이산 코사인 변환)

음성의 "형태"를 나타내는 핵심 특성

mfcc_transform = torchaudio.transforms.MFCC(

sample_rate=16000,

n_mfcc=13, # MFCC 계수 개수 (보통 13~40)

melkwargs={

'n_fft': 1024,

'n_mels': 80,

'hop_length': 256,

}

)

mfcc = mfcc_transform(waveform)

shape: [1, 13, time_frames]

Delta (1차 미분) + Delta-Delta (2차 미분)

→ 음성의 변화율 정보 추가

delta = torchaudio.functional.compute_deltas(mfcc)

delta_delta = torchaudio.functional.compute_deltas(delta)

최종 특성: [MFCC, Delta, Delta-Delta] 연결

features = torch.cat([mfcc, delta, delta_delta], dim=1)

shape: [1, 39, time_frames]

어디에 쓰이나?

├── MFCC: 전통 음성인식 (HMM-GMM), 화자 인식

├── Mel Spectrogram: 딥러닝 음성인식 (Wav2Vec2, Whisper)

├── Spectrogram: 음악 분석, 환경음 분류

└── Raw Waveform: End-to-end 모델 (최신 트렌드)

Part 3: 오디오 Augmentation

시간 마스킹 (SpecAugment)

time_masking = torchaudio.transforms.TimeMasking(

time_mask_param=30 # 최대 30 프레임 마스킹

)

주파수 마스킹 (SpecAugment)

freq_masking = torchaudio.transforms.FrequencyMasking(

freq_mask_param=15 # 최대 15 채널 마스킹

)

SpecAugment (음성인식 정확도 크게 향상!)

augmented_spec = time_masking(freq_masking(mel_spec))

시간 늘리기/줄이기

time_stretch = torchaudio.transforms.TimeStretch()

stretched = time_stretch(complex_spec, overriding_rate=1.2) # 20% 빠르게

피치 변환

pitch_shift = torchaudio.transforms.PitchShift(

sample_rate=16000, n_steps=4 # 4 반음 올리기

)

shifted = pitch_shift(waveform)

노이즈 추가

def add_noise(waveform, snr_db=10):

"""SNR dB 기준으로 백색 노이즈 추가"""

noise = torch.randn_like(waveform)

signal_power = waveform.norm(p=2)

noise_power = noise.norm(p=2)

snr = 10 ** (snr_db / 20)

scale = signal_power / (snr * noise_power)

return waveform + scale * noise

Part 4: 사전학습 모델

Wav2Vec 2.0 (음성인식)

from torchaudio.pipelines import WAV2VEC2_ASR_BASE_960H

파이프라인 로드

bundle = WAV2VEC2_ASR_BASE_960H

model = bundle.get_model()

labels = bundle.get_labels() # 토큰 목록

추론

waveform, sr = torchaudio.load("speech.wav")

if sr != bundle.sample_rate:

waveform = torchaudio.transforms.Resample(sr, bundle.sample_rate)(waveform)

with torch.no_grad():

emissions, _ = model(waveform)

CTC 디코딩 (Greedy)

def greedy_decode(emissions, labels):

indices = torch.argmax(emissions, dim=-1)[0]

tokens = []

prev = -1

for idx in indices:

if idx != prev and idx != 0: # 0 = blank

tokens.append(labels[idx])

prev = idx

return "".join(tokens).replace("|", " ").strip()

text = greedy_decode(emissions, labels)

print(f"인식 결과: {text}")

HuBERT (자기지도 음성 표현)

from torchaudio.pipelines import HUBERT_BASE

bundle = HUBERT_BASE

model = bundle.get_model()

with torch.no_grad():

features, _ = model(waveform)

features: [1, time_frames, 768]

→ 음성의 의미적 표현 벡터

→ 화자 인식, 감정 분석, 음성 분류에 활용

Forced Alignment (자막 동기화)

음성과 텍스트의 시간 정렬!

→ 자막 생성, 가사 동기화에 필수

from torchaudio.pipelines import MMS_FA # Multilingual!

bundle = MMS_FA

model = bundle.get_model()

tokenizer = bundle.get_tokenizer()

aligner = bundle.get_aligner()

transcript = "안녕하세요 반갑습니다"

tokens = tokenizer(transcript)

with torch.no_grad():

emissions, _ = model(waveform)

token_spans = aligner(emissions[0], tokens)

각 토큰의 시작/끝 시간을 프레임 단위로 반환!

for span, token in zip(token_spans, transcript):

start_time = span.start * model.hop_length / sample_rate

end_time = span.end * model.hop_length / sample_rate

print(f" '{token}': {start_time:.3f}s ~ {end_time:.3f}s")

Part 5: 오디오 이펙트

torchaudio.functional — GPU 가속 오디오 처리

볼륨 조절

loud = F.gain(waveform, gain_db=6.0) # +6dB

quiet = F.gain(waveform, gain_db=-6.0) # -6dB

하이패스/로우패스 필터

highpass = F.highpass_biquad(waveform, sample_rate, cutoff_freq=300)

lowpass = F.lowpass_biquad(waveform, sample_rate, cutoff_freq=3000)

이퀄라이저

eq = F.equalizer_biquad(

waveform, sample_rate,

center_freq=1000, # 1kHz 부근

gain=5.0, # +5dB 부스트

Q=0.707

)

리버브 (잔향)

rir, _ = torchaudio.load("room_impulse_response.wav") # RIR 파일

reverb = F.fftconvolve(waveform, rir)

페이드 인/아웃

fade = torchaudio.transforms.Fade(

fade_in_len=sample_rate, # 1초 페이드 인

fade_out_len=sample_rate * 3 # 3초 페이드 아웃

)

faded = fade(waveform)

VAD (Voice Activity Detection)

vad = torchaudio.transforms.Vad(sample_rate=16000)

speech_only = vad(waveform) # 무음 구간 제거

Part 6: 실전 프로젝트

환경음 분류 (Audio Classification)

class AudioClassifier(nn.Module):

def __init__(self, n_classes=10):

super().__init__()

self.mel = torchaudio.transforms.MelSpectrogram(

sample_rate=16000, n_fft=1024, n_mels=64

)

self.db = torchaudio.transforms.AmplitudeToDB()

Mel 스펙트로그램을 "이미지"처럼 CNN에 입력!

self.cnn = nn.Sequential(

nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),

nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),

nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(),

nn.AdaptiveAvgPool2d((1, 1)),

)

self.fc = nn.Linear(128, n_classes)

def forward(self, waveform):

[B, 1, samples] → [B, 1, n_mels, time]

x = self.mel(waveform)

x = self.db(x)

x = self.cnn(x)

x = x.view(x.size(0), -1)

return self.fc(x)

Mel 스펙트로그램 = 오디오의 "이미지"

→ CNN(ResNet, EfficientNet)으로 분류 가능!

실시간 스트리밍 처리

from torchaudio.io import StreamReader

마이크 입력 실시간 처리

reader = StreamReader(src=":0", format="avfoundation") # macOS

reader.add_basic_audio_stream(

frames_per_chunk=16000, # 1초 단위

sample_rate=16000,

)

for (chunk,) in reader.stream():

chunk: [1, 16000]

mel = mel_transform(chunk)

with torch.no_grad():

prediction = model(mel)

print(f"감지: {labels[prediction.argmax()]}")

**Q1.** Mel 스케일이 필요한 이유는?

||인간의 청각은 저주파에 민감하고 고주파에 둔감. Mel 스케일은 이를 반영하여 저주파는 세밀하게, 고주파는 뭉뚱그려서 분석. 딥러닝 모델에 인간 청각 특성 반영||

**Q2.** n_fft를 키우면 어떤 해상도가 올라가고, 어떤 해상도가 내려가나?

||n_fft ↑ → 주파수 해상도 ↑ (세밀한 주파수 구분), 시간 해상도 ↓ (시간 변화 파악 어려움). 불확정성 원리와 유사한 트레이드오프||

**Q3.** SpecAugment의 두 가지 마스킹은?

||Time Masking: 시간 축에서 연속 프레임을 0으로 마스킹. Frequency Masking: 주파수 축에서 연속 채널을 0으로 마스킹. 데이터 augmentation으로 음성인식 정확도 크게 향상||

**Q4.** MFCC와 Mel Spectrogram의 차이와 각각의 용도는?

||MFCC: Mel Spectrogram에 DCT를 적용해 계수 추출 (13~40차원). 전통 음성인식, 화자 인식에 사용. Mel Spectrogram: 주파수-시간 2D 표현. 딥러닝 모델에 직접 입력 (최신 트렌드)||

**Q5.** Forced Alignment의 활용 사례는?

||음성과 텍스트의 시간 정렬. 자막 생성 (정확한 타이밍), 가사 동기화 (노래방), 발음 평가 (언어 학습 앱)||

**Q6.** Wav2Vec 2.0에서 CTC 디코딩의 blank 토큰 역할은?

||연속된 같은 토큰을 구분하고, 아무 출력도 없는 시간 구간을 표현. Greedy 디코딩에서 blank(index 0)과 연속 중복을 제거하여 최종 텍스트 생성||

**Q7.** Mel Spectrogram을 CNN에 넣을 수 있는 이유는?

||Mel Spectrogram은 2D 이미지와 같은 구조 (주파수 축 × 시간 축). 1채널 grayscale 이미지로 취급하여 ResNet, EfficientNet 등 이미지 분류 모델을 그대로 활용 가능||

📖 관련 시리즈 & 추천 포스팅

- [torchvision 완전 가이드](/blog/ai-platform/2026-03-03-torchvision-complete-guide) — 이미지 AI (자매편)

- [AI를 위한 수학 완전 가이드](/blog/ai/2026-03-03-math-for-ai-complete-guide) — 푸리에 변환, 확률 (오디오 이해 필수)

- [나만의 GPT 만들기](/blog/ai/2026-03-03-build-your-own-gpt-from-scratch) — Wav2Vec2의 기반 Transformer

GitHub

- [torchaudio 공식](https://github.com/pytorch/audio)

- [Whisper](https://github.com/openai/whisper) — OpenAI 음성인식

- [ESPnet](https://github.com/espnet/espnet) — 종합 음성처리 툴킷

현재 단락 (1/218)

`torchaudio`는 PyTorch의 공식 오디오 처리 라이브러리입니다. 오디오 I/O, 스펙트로그램 변환, 사전학습 모델(Wav2Vec2, HuBERT, Whisper), 그...

작성 글자: 0원문 글자: 8,524작성 단락: 0/218