목차
서론
딥러닝 모델, 특히 YOLO(You Only Look Once) 계열의 객체 탐지 모델은 점점 더 커지고 있습니다. YOLOv8, YOLO11, YOLO12 등의 대형 모델(12x, 24x)은 파일 크기가 수백 MB에서 수 GB에 달하며, 이는 다음과 같은 문제를 야기합니다:
- Git/GitHub 업로드 제한: GitHub는 100MB 이상의 단일 파일 업로드를 제한합니다
- 네트워크 전송 실패: 대용량 파일 전송 시 네트워크 오류로 인한 재시작 필요
- 스토리지 관리 어려움: 클라우드 스토리지 서비스의 파일 크기 제한
- 버전 관리 효율성: Git LFS를 사용하더라도 분할된 파일이 관리에 유리
본 가이드에서는 이러한 문제를 해결하기 위한 Bash 기반 자동 파일 분할 및 병합 스크립트를 소개하고, 실무에 바로 적용할 수 있는 노하우를 공유합니다.
왜 파일 분할이 필요한가?
1. GitHub 파일 크기 제한 우회
문제: GitHub에서 100MB 이상 파일 push 불가능
해결: 50MB 단위로 분할하여 각각 커밋
2. 네트워크 안정성 향상
대용량 파일을 한 번에 전송하면 네트워크 오류 시 처음부터 다시 시작해야 합니다. 분할된 파일은 개별적으로 전송 가능하여 복원력이 높습니다.
3. 병렬 처리 가능
# 여러 파일을 동시에 업로드
parallel -j 4 aws s3 cp {} s3://bucket/ ::: model.part*
4. 스토리지 효율성
일부 클라우드 서비스는 작은 파일에 대해 더 나은 중복 제거 및 압축을 제공합니다.
스크립트 구조 및 주요 기능
전체 스크립트 구조
#!/bin/bash
set -e
# 1. 설정 영역
SPLIT_FILES="
yolo12x.pt
"
# 2. 유틸리티 함수 (컬러 출력)
check_fancy_output()
# 3. 핵심 기능 함수
merge_one() # 단일 파일 병합
merge() # 전체 파일 병합
part_one() # 단일 파일 분할
part() # 전체 파일 분할
help() # 도움말
# 4. 실행 로직
주요 기능
1. 컬러 출력 지원
터미널 환경을 자동 감지하여 색상 출력을 결정합니다:
check_fancy_output() {
TPUT=/usr/bin/tput
EXPR=/usr/bin/expr
if [ "x$TERM" != "xdumb" ] && [ -x $TPUT ] && [ -x $EXPR ] && \
$TPUT hpa 60 > /dev/null 2>&1; then
RED=`$TPUT setaf 1`
YELLOW=`$TPUT setaf 3`
NORMAL=`$TPUT op`
else
RED=""
YELLOW=""
NORMAL=""
fi
}
핵심 포인트:
dumb터미널에서는 색상 비활성화tput및expr명령어 존재 여부 확인- 에러 출력을
/dev/null로 리다이렉트하여 조용한 실패 처리
2. 파일 분할 (split)
part_one() {
local FILE_NAME="${1}"
if [ ! -f "${FILE_NAME}" ]; then
echo "file '${FILE_NAME}' doesn't exist"
exit 1
fi
echo_status "Split '${FILE_NAME}' into multiple parts"
split --verbose -b 50M -x "${FILE_NAME}" "${FILE_NAME}.part"
}
split 명령어 옵션 설명:
-b 50M: 50MB 단위로 분할-x: 16진수 접미사 사용 (part00, part01, part02...)--verbose: 진행 상황 출력
출력 예시:
creating file 'model.bin.part00'
creating file 'model.bin.part01'
creating file 'model.bin.part02'
3. 파일 병합 (cat)
merge_one() {
local FILE_NAME="${1}"
if [ -f "${FILE_NAME}" ]; then
echo "File '${FILE_NAME}' already exists"
return 0
fi
echo_status "Merge multiple parts into '${FILE_NAME}'"
cat "${FILE_NAME}.part"* > "${FILE_NAME}"
}
중요: cat 명령어는 파일을 알파벳 순서로 연결하므로 part00, part01, part02... 순서가 보장됩니다.
사용 방법
기본 사용법
1. 스크립트 권한 설정
chmod +x split_merge.sh
2. 파일 분할
# 설정된 모든 파일 분할
./split_merge.sh part
# 특정 파일만 분할
./split_merge.sh part yolo12x.pt
3. 파일 병합
# 설정된 모든 파일 병합
./split_merge.sh merge
# 특정 파일만 병합
./split_merge.sh merge yolo12x.pt
코드 분석 및 개선 사항
원본 코드의 문제점
1. 함수 명명 규칙
# 문제: 대문자 함수명 (환경변수와 혼동)
ECHO() {
echo "${RED}###${YELLOW} ${1} ..."
}
# 개선: 소문자 함수명 사용
echo_status() {
echo "${RED}###${YELLOW} ${1} ...${NORMAL}"
}
2. 타이포 수정
# 원본
echo "file '${FILE_NAME}' dosen't exist"
# 수정
echo "file '${FILE_NAME}' doesn't exist"
3. exit vs return
# 문제: 서브쉘이 아닌 함수에서 exit 사용
merge_one() {
if [ -f "${FILE_NAME}" ]; then
exit 0 # 전체 스크립트 종료!
fi
}
# 개선: return 사용
merge_one() {
if [ -f "${FILE_NAME}" ]; then
echo "File '${FILE_NAME}' already exists"
return 0 # 함수만 종료
fi
}
4. 명령어 실행 구문 오류
# 문제: 공백 없음
hash ${COMMAND} &> /dev/null || help${COMMAND} ${@}
# 수정: 적절한 공백과 인용
hash "${COMMAND}" &> /dev/null || help
"${COMMAND}" "${@}"
개선된 최종 버전
#!/bin/bash
set -euo pipefail # 추가: -u (미정의 변수 에러), -o pipefail
SPLIT_FILES="
yolo12x.pt
"
# 색상 초기화
RED=""
YELLOW=""
NORMAL=""
check_fancy_output() {
local TPUT=/usr/bin/tput
local EXPR=/usr/bin/expr
if [ "x$TERM" != "xdumb" ] && [ -x "$TPUT" ] && [ -x "$EXPR" ] && \
"$TPUT" hpa 60 > /dev/null 2>&1; then
RED=$($TPUT setaf 1)
YELLOW=$($TPUT setaf 3)
NORMAL=$($TPUT op)
fi
}
check_fancy_output
echo_status() {
echo "${RED}###${YELLOW} ${1} ...${NORMAL}"
}
merge_one() {
local FILE_NAME="${1}"
if [ -f "${FILE_NAME}" ]; then
echo "File '${FILE_NAME}' already exists, skipping merge"
return 0
fi
if ! ls "${FILE_NAME}.part"* 1> /dev/null 2>&1; then
echo "No parts found for '${FILE_NAME}'"
return 1
fi
echo_status "Merge multiple parts into '${FILE_NAME}'"
cat "${FILE_NAME}.part"* > "${FILE_NAME}"
echo "✓ Merged successfully"
}
merge() {
local FILE_NAME="${1:-}"
if [ -z "${FILE_NAME}" ]; then
for f in ${SPLIT_FILES}; do
merge_one "${f}"
done
else
merge_one "${FILE_NAME}"
fi
}
part_one() {
local FILE_NAME="${1}"
if [ ! -f "${FILE_NAME}" ]; then
echo "Error: file '${FILE_NAME}' doesn't exist"
return 1
fi
echo_status "Split '${FILE_NAME}' into multiple parts"
split --verbose -b 50M -x "${FILE_NAME}" "${FILE_NAME}.part"
echo "✓ Split successfully"
}
part() {
local FILE_NAME="${1:-}"
if [ -z "${FILE_NAME}" ]; then
for f in ${SPLIT_FILES}; do
part_one "${f}"
done
else
part_one "${FILE_NAME}"
fi
}
show_help() {
local PROG
PROG=$(basename "${0}")
echo "Usage:"
echo " ${YELLOW}${PROG} ${RED}merge${NORMAL} [file] # Merge part files"
echo " ${YELLOW}${PROG} ${RED}part${NORMAL} [file] # Split file into parts"
echo " ${YELLOW}${PROG} ${RED}help${NORMAL} # Show this help"
echo ""
echo "Examples:"
echo " ${PROG} part # Split all configured files"
echo " ${PROG} part model.bin # Split specific file"
echo " ${PROG} merge # Merge all configured files"
echo " ${PROG} merge model.bin # Merge specific file"
}
# 메인 실행 로직
main() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local COMMAND="${1}"
shift
case "${COMMAND}" in
merge)
merge "${@}"
;;
part)
part "${@}"
;;
help|--help|-h)
show_help
;;
*)
echo "Error: Unknown command '${COMMAND}'"
show_help
exit 1
;;
esac
}
main "${@}"
개선 사항 요약
| 항목 | 원본 | 개선 |
|---|---|---|
| 에러 처리 | set -e |
set -euo pipefail |
| 함수명 | ECHO |
echo_status |
| 종료 방식 | exit 0 |
return 0 |
| 파일 존재 확인 | 없음 | ls 패턴 매칭 검증 |
| 성공 피드백 | 없음 | ✓ Successfully 메시지 |
| 도움말 | 기본 | 예시 포함 상세 도움말 |
| case 문 | hash + 동적 실행 |
명시적 case 문 |
문제 해결 가이드
Q1: "command not found: split" 에러
원인: coreutils 패키지 미설치
해결:
# Ubuntu/Debian
sudo apt-get install coreutils
# macOS
brew install coreutils
Q2: 병합 후 파일 크기가 다름
원인: 분할 파일 일부 누락 또는 손상
해결:
# 모든 part 파일 확인
ls -lh model.bin.part*
# 예상 크기 계산
du -sh model.bin.part* | awk '{sum+=$1}END{print sum}'
# 재다운로드 및 재시도
Q3: Git에서 "file too large" 경고
해결 방법:
# 이미 커밋된 대용량 파일 제거
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch experiment/model.bin" \
--prune-empty --tag-name-filter cat -- --all
# 재분할 및 커밋
./split_merge.sh part experiment/model.bin
git add experiment/*.part*
git commit -m "Replace large file with split chunks"
Q4: 병합 시 "Permission denied"
원인: 대상 디렉토리 쓰기 권한 없음
해결:
# 권한 확인
ls -ld experiment/
# 권한 부여
chmod u+w experiment/
Q5: 분할 파일 순서가 잘못됨
원인: 알파벳 정렬 문제 (part1, part10, part2...)
해결: 스크립트에서 -x 옵션 사용 (이미 적용됨)
# 16진수 접미사로 올바른 정렬 보장
split -b 50M -x file.bin file.bin.part
# 생성: part00, part01, ..., part0a, part0b, ...
성능 최적화 팁
1. SSD 환경에서 버퍼 크기 조정
# 기본 50MB 대신 100MB 블록 사용
split -b 100M -x "${FILE_NAME}" "${FILE_NAME}.part"
2. 압축과 함께 사용
# 분할 전 압축
gzip -k model.bin # model.bin.gz 생성
split -b 50M model.bin.gz model.bin.gz.part
# 병합 후 압축 해제
cat model.bin.gz.part* > model.bin.gz
gunzip model.bin.gz
3. 병렬 압축 (pigz)
# pigz 설치
sudo apt-get install pigz
# 빠른 압축
pigz -k model.bin
split -b 50M model.bin.gz model.bin.gz.part
결론
대용량 YOLO 모델 파일 관리는 딥러닝 실무에서 자주 마주치는 문제입니다. 본 가이드에서 소개한 자동 분할/병합 스크립트는:
✅ GitHub 업로드 제한 우회
✅ 네트워크 안정성 향상
✅ 클라우드 스토리지 최적화
위 스크립트를 프로젝트에 맞게 커스터마이징하여 사용하시면, 대용량 모델 파일 관리의 어려움을 크게 줄일 수 있습니다.
추가 자료
키워드: YOLO, 모델 파일 분할, Bash 스크립트, Git 대용량 파일, 딥러닝 모델 관리, split 명령어, 파일 병합, GitHub 100MB 제한
'컴퓨터' 카테고리의 다른 글
| 리눅스 터미널 환경 구성 (3) | 2025.06.19 |
|---|---|
| i9-13900k 언더볼팅 ASRock (274) | 2023.12.05 |
| [키보드] Monsgeek m3w 풀알루 3모드 텐키리스 키보드 (404) | 2023.11.06 |
| [디즈니+] 멤버십 환불 신청하기 (196) | 2023.11.01 |
| [KVM] 여러대의 PC를 하나의 키보드, 마우스로 쓰기, 윈도우-리눅스 지원 (226) | 2023.10.31 |