컴퓨터

GitHub 대용량 모델 파일 관리: 자동 분할 및 병합

Ninestar 2026. 2. 6. 10:39
반응형

목차

  1. 서론
  2. 왜 파일 분할이 필요한가?
  3. 스크립트 구조 및 주요 기능
  4. 사용 방법
  5. 코드 분석 및 개선 사항
  6. 실전 활용 예시
  7. 문제 해결 가이드

서론

딥러닝 모델, 특히 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 터미널에서는 색상 비활성화
  • tputexpr 명령어 존재 여부 확인
  • 에러 출력을 /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 제한