아래 글은 상대 경로로 인한 경로 충돌 문제를 해결하고, 절대 경로 방식을 적용해 음성 데이터(.pcm)와 대응 텍스트(.txt)를 매끄럽게 읽어오는 방법을 정리한 내용입니다. Windows 환경에서 폴더 구조가 여러 단계로 되어 있어도 문제없이 데이터셋을 구성하고 학습을 진행하려는 분들께 도움이 되길 바랍니다.
1. 문제 상황과 배경
보통 PyTorch로 STT(음성 인식) 모델을 학습할 때, 음성 파일(.pcm)과 해당 스크립트(.txt)를 쌍으로 찾아와야 합니다. 예를 들어 “sample_001.pcm
”에 대응하는 “sample_001.txt
”를 읽어서 (waveform, text)
형태로 로딩하는 식입니다.
이 과정을 자동화하려면 os.walk
로 디렉터리를 순회하며 .pcm
파일이 있으면 .txt
를 찾는 로직을 작성하게 됩니다. 코드 상으로는 다음과 같은 방법을 흔히 씁니다:
os.walk
로 모든 폴더를 순회한다..pcm
확장자의 파일을 발견하면,.pcm
를.txt
로 교체해서 대응 파일이 있는지 확인한다.- 둘 다 존재하면
(pcm_path, txt_path)
쌍을 리스트에 저장한다.
문제는 폴더 구조가 깊어졌을 때, 특히 Windows에서 **상대 경로(os.path.relpath
)**와 절대 경로가 뒤섞이면 파일이 제대로 열리지 않거나, 경로가 어긋나는 오류가 발생하기 쉽다는 점입니다.
상대 경로를 다시 os.path.join
으로 합칠 때, 구분자가 역슬래시(\
)와 슬래시(/
)가 섞이거나 “..
”이 들어가는 식으로 꼬이면, 실제로는 존재하는 파일을 “찾을 수 없는” 문제가 생기게 됩니다.
이렇게 경로가 잘못 형성되면 “해당 파일이 없음(No such file or directory)” 에러가 발생하거나, UnicodeDecodeError
등 부수적인 오류가 날 수도 있습니다. 특히 os.path.relpath
가 어떤 경로를 기준으로 상대 경로를 만드는지 확실히 감을 잡지 못하면, 다층 폴더 구조에서 원인을 찾기 훨씬 어렵습니다.
2. 절대 경로 사용의 장점
이를 근본적으로 해결하는 가장 간단한 방법은, 파일을 찾는 순간부터 절대 경로로 관리하는 것입니다. 즉:
root
와pcm
(혹은txt
)를 바로os.path.join(root, pcm)
형태로 합쳐서, 절대 경로를 만든 뒤 리스트에 저장한다.- 학습 시에도 그 절대 경로 그대로
open(...)
해서 읽는다. - 더 이상 “
os.path.join(self.data_dir, rel_path, 파일명)
” 같은 추가 조립 과정을 하지 않는다.
절대 경로를 사용하면, 폴더 구조가 몇 단계로 깊어지든, Windows든 Linux든, 모든 파일을 확실히 찾을 수 있습니다. “rel_path
”에서 “..
”이 몇 번 들어가는지, 슬래시가 섞였는지 등을 신경 쓸 필요가 없습니다.
예를 들어:
pcm_full = os.path.join(root, pcm)
txt_full = os.path.join(root, txt)
all_pairs.append((pcm_full, txt_full))
이렇게 바로 절대 경로로 저장하고,__getitem__
에서는:
pcm_path, txt_path = self.file_pairs[idx]
with open(pcm_path, 'rb') as f:
...
with open(txt_path, 'r') as f:
...
처럼 쓴다면, 추가로 경로를 합치거나 바꾸지 않아도 됩니다.
3. 코드 예시와 수정 포인트
3.1 _get_subset_pairs
에서 절대 경로로 저장
기존 코드에서는 다음과 같이 작성했을 수 있습니다:
rel_path = os.path.relpath(root, self.data_dir)
all_pairs.append((
os.path.join(rel_path, pcm),
os.path.join(rel_path, txt)
))
이 방식은 rel_path
가 여러 단계 폴더(예: D:\korean\part1\subfolder
)를 상대 경로로 만드는 과정에서 꼬일 위험이 큽니다.
대신 아래처럼 수정합니다:
pcm_full = os.path.join(root, pcm)
txt_full = os.path.join(root, txt)
all_pairs.append((pcm_full, txt_full))
이제 all_pairs
리스트에는 (D:\korean\part1\subfolder\sample_001.pcm, D:\korean\part1\subfolder\sample_001.txt)
같은 절대 경로만 저장됩니다.
3.2 __getitem__
에서 경로 합치기 제거
절대 경로가 이미 “pcm_full
”, “txt_full
” 형태로 저장됐으니, __getitem__
에서도:
pcm_path, txt_path = self.file_pairs[idx]
with open(pcm_path, 'rb') as f:
...
with open(txt_path, 'r', encoding='cp949') as f:
...
처럼 그대로 열면 됩니다. 이때 os.path.join(self.data_dir, ...)
가 불필요해집니다.
3.3 나머지 로직은 동일
.pcm
파일을np.frombuffer
로 읽어서FloatTensor
로 변환.txt
파일을 열어 텍스트를 읽고, 토큰화- collate_fn에서 배치 단위로 pad_sequence
- CTC Loss 계산 등
이런 부분은 그대로 두면 됩니다. 경로만 달라졌을 뿐이므로 기존 모델 구조나 학습 루프는 바뀌지 않습니다.
4. 체크해야 할 다른 요소들
- 파일 인코딩
txt 파일이 실제로 UTF-8인지 CP949인지 확실히 알고 있어야 합니다. 파일 인코딩이 다르면UnicodeDecodeError
가 납니다.
“encoding='cp949'
”로 열려는데, 실제 파일은 UTF-8이면 당연히 실패하므로, 필요 시encoding='utf-8'
등으로 바꿔보세요. - .pcm / .txt가 모두 존재하는지
.pcm
는 있는데.txt
파일이 없다면, “이상하게 파일을 못 읽는다”는 에러가 뜰 수도 있습니다. 코드 내에서.pcm → .txt
변환 후, 존재 유무를 반드시 체크해야 합니다. 예제 코드에도 “if txt in files:
” 같은 조건이 있죠. - subset_size
예를 들어subset_size=5000
으로 설정했지만, 실제 데이터가 1000개뿐이라면random.sample
로 1000개만 뽑힙니다. 이 부분은 정상 동작일 수도 있지만, 혹시subset_size
가 너무 커서 “데이터가 거의 없는 것 같다”는 경고가 뜰 가능성은 없습니다.
또한,.pcm/.txt
가 하나도 없는 폴더를 지정하면all_pairs
가 0이 되고, 학습 과정이 제대로 진행되지 않습니다. - Windows vs Linux 경로 구분
윈도우에서는 기본적으로 역슬래시(\
)를 쓰고, 파이썬 내부에서는 슬래시(/
)도 섞여 작동하는 등 혼동이 생길 수 있습니다. 절대 경로로 처리하면,os.path.join
이 알아서 OS별 구분자를 맞춰주기 때문에 오류 발생이 현저히 줄어듭니다.
5. 결론
“os.path.relpath
”로 구한 상대 경로를 다시 os.path.join
으로 합쳐 쓰는 방식은, 멀티 폴더 구조와 Windows 환경에서는 종종 파일 경로가 꼬이는 문제가 생깁니다.
절대 경로를 한 번에 만들어서 저장하고, __getitem__
에서는 그 경로 그대로 열면, 폴더 깊이와 무관하게 .pcm
와 .txt
를 안정적으로 읽어올 수 있습니다.
이렇게 경로 문제를 해결하면, 학습 스크립트에서 더 이상 “파일을 찾을 수 없다”는 에러가 뜨지 않을 것입니다. 실제 STT 모델의 성능은 학습률, 데이터 품질, 토크나이저, Conformer 아키텍처 설계 등 다양한 요소에 좌우되지만, 기본적으로 데이터 파일을 제대로 읽어오는 것이야말로 학습의 첫 걸음입니다.
부디 이 글이, 음성 인식 프로젝트에서 경로 이슈 때문에 시간을 낭비하시는 분들께 도움이 되길 바랍니다.
경로 문제를 깔끔히 해결하고, 더 중요한 모델 구현과 성능 향상에 집중해보세요!
답글 남기기