DevChoco

실전 코드와 디버깅 맥락을 남기는 개발 지식 아카이브

AI
조회 108분 읽기

GPU 한 대로 끝내는 멀티모달 미세조정의 현실

Gemma 4와 serverless GPU 조합은 대형 멀티모달 모델 fine-tuning의 진입장벽을 낮춘다. Cloud Run Jobs, QLoRA, LoRA 타깃 전략, VRAM 관리까지 함께 짚으며 실전 적용 시의 기대와 함정을 균형 있게 풀어낼 글에 어울리는 메타데이터다.

#Gemma 4#Fine-Tuning#Cloud Run Jobs#Serverless GPU#QLoRA#LoRA#Multimodal AI#Google Cloud

멀티모달 미세조정이 늘 비싸고 복잡한 일처럼 보였던 이유는 모델이 커서가 아니라, 큰 모델을 다루는 인프라의 문턱이 유난히 높았기 때문이다. 텍스트만 다루는 작은 실험은 노트북에서도 돌아가지만, 이미지가 들어오고 모델 파라미터가 수십억 단위를 넘어가는 순간 이야기가 달라진다. GPU를 확보해야 하고, 드라이버를 맞춰야 하고, 학습이 한 번 실패했을 때 어디서 메모리가 터졌는지부터 추적해야 한다. 그래서 많은 팀이 “우리도 멀티모달 파인튜닝을 해볼까”라는 말까지만 하고, 실제로는 API 호출이나 프롬프트 엔지니어링 선에서 멈춘다.

그런 맥락에서 Gemma 4와 serverless GPU의 조합이 던지는 메시지는 꽤 선명하다. 거대한 멀티모달 모델을 다루는 방식이 점점 “클러스터 운영”에서 “작업 단위 실행”으로 옮겨가고 있다는 점이다. 특히 Cloud Run Jobs처럼 배치성 워크로드에 맞는 실행 모델은, 학습이 끝나면 인프라까지 같이 사라지는 구조를 전제로 한다. 웹 서비스처럼 늘 켜둘 필요가 없는 미세조정 작업에는 이 발상이 잘 맞는다. GPU를 소유하거나 장기 예약하지 않아도 되고, 한 번의 Job 실행으로 데이터셋을 태우고 결과만 남기면 된다. 비용과 운영 복잡도가 동시에 내려가는 이유다.

정말로 GPU 한 대면 충분한가요

짧게 답하면, “조건부로 그렇다”가 가장 정확하다. 여기서 핵심은 한 대의 GPU가 얼마나 큰가가 아니라, 어떤 방식으로 모델을 올리고 무엇만 학습하느냐다. Gemma 4처럼 대형 open model을 그대로 full fine-tuning 하겠다고 덤비면 단일 GPU는 금세 한계에 부딪힌다. 하지만 QLoRA로 베이스 모델을 4-bit로 압축해 메모리 점유를 낮추고, 실제로는 adapter만 학습하는 구조로 바꾸면 판이 달라진다.

이때 자주 오해되는 부분이 있다. 많은 사람이 VRAM 계산을 모델 파라미터 크기만 보고 끝낸다. 하지만 학습에서 무서운 것은 모델 weight만이 아니다. activation, gradient, optimizer state가 한꺼번에 밀려드는 순간이 진짜 병목이다. 멀티모달은 여기에 이미지 처리용 표현까지 끼어든다. 그래서 “31B 모델이 96GB VRAM에 들어간다”는 말과 “그 모델이 안정적으로 fine-tuning 된다”는 말은 전혀 같은 뜻이 아니다.

QLoRA가 중요한 이유는 바로 이 차이를 메워주기 때문이다. 베이스 weight를 저정밀도로 눌러 담아 공간을 만들고, 그 남은 여유를 activation과 학습 안정성에 쓴다. 이 여유가 있어야 batch size를 억지로 1 이하의 체감으로 줄이지 않고도 실험을 이어갈 수 있다. 여기에 gradient checkpointing까지 켜면 계산은 조금 더 느려지지만 VRAM은 훨씬 덜 쓴다. 단일 GPU 전략은 결국 “속도를 조금 양보하고 메모리를 사는” 방식이라고 보는 편이 맞다.

왜 멀티모달 파인튜닝은 텍스트 LoRA 감각으로 접근하면 자주 실패하나요

텍스트 모델만 다뤄본 팀이 가장 자주 빠지는 함정은 LoRA target을 너무 익숙한 이름들에만 묶는 것이다. 예컨대 attention의 q_proj, v_proj 몇 군데만 건드리면 충분할 것이라는 감각 말이다. 이 방식은 많은 텍스트 모델에서 통하지만, 멀티모달 구조에서는 종종 지나치게 낙관적이다. 이유는 두 가지다.

하나는 vision tower가 따로 있다는 점이다. 이미지를 읽는 쪽이 거의 얼어붙은 상태로 남아 있으면, 텍스트 응답부만 조금 더 영리해져 봐야 시각적 분별력이 기대만큼 오르지 않는다. 반려동물 품종 분류처럼 얼핏 쉬워 보여도 실제로는 미세한 패턴 차이를 읽어야 하는 과제에서는 더 그렇다. 귀 모양, 털 무늬, 얼굴 비율 같은 특징은 언어적 reasoning보다 시각적 적응이 먼저 받쳐줘야 한다.

다른 하나는 모델 내부의 custom wrapper다. 최신 모델은 단순한 Linear 층만 깔끔하게 늘어선 구조가 아니다. 안정화를 위한 clipping이나 wrapper가 끼어 있는 경우가 있고, 이때 PEFT가 너무 좁은 타깃만 집으면 의도한 경로에 adapter가 붙지 않거나 forward path의 안정성이 흐트러질 수 있다. 그래서 어떤 모델에서는 “정교한 selective LoRA”보다 “all-linear에 가깝게 넓게 잡는 전략”이 더 현실적인 선택이 된다. 메모리 여유가 있는 GPU라면 이 판단은 더 합리적이다. 작은 GPU에서는 아껴야 해서 수술하듯 잘라 붙였다면, 큰 단일 GPU에서는 오히려 넓게 잡아 아키텍처 충돌을 줄이는 편이 낫다.

Cloud Run Jobs가 학습에 어울린다는 말은 무슨 뜻인가요

serverless라는 단어는 대개 추상화의 편의성으로 이해되지만, 학습 워크로드에서는 실패 방식 자체를 바꾼다. 상시 구동 서버에서는 인스턴스 안의 상태에 무심해지기 쉽다. 로그도 남아 있고, 디스크도 붙어 있고, 중간 체크포인트도 대충 로컬 경로에 저장해 놓으면 될 것처럼 느껴진다. 하지만 Job 기반 실행은 그런 습관을 허용하지 않는다. 실행은 시작되고 끝나며, 재시도는 언제든 다른 인스턴스에서 일어날 수 있다. 이 환경은 학습 코드를 더 정직하게 만든다.

즉, 체크포인트 저장 위치를 처음부터 외부 스토리지로 강제하게 되고, 모델 weight 다운로드 시간을 실행 시간의 일부로 본격적으로 계산하게 되며, 재시작 가능성을 전제로 데이터 로더와 저장 주기를 설계하게 된다. 이것이 귀찮아 보일 수 있지만, 운영 관점에서는 오히려 이득이다. 학습이 끝난 뒤 인프라가 남아 비용을 갉아먹지 않고, 실패했을 때도 “어떤 상태를 외부에 남겼는가”만 보면 된다.

다만 여기에는 역설도 있다. serverless GPU가 모든 문제를 지워주지는 않는다. cold start는 웹 API보다 학습에서 덜 아프지만, 모델이 큰 경우 weight staging이 느리면 실행 시간 대부분을 다운로드에 쓰게 된다. 그래서 Cloud Storage나 비슷한 인접 스토리지에 모델을 미리 올려두고 마운트하거나, 적어도 네트워크 홉을 줄이는 구성이 중요해진다. 학습 시간만 보지 말고 “실행 준비 시간”을 함께 봐야 하는 이유다.

왜 반려동물 품종 분류 같은 예제가 의미가 있나요

겉보기에는 장난감 데이터셋처럼 보일 수 있다. 하지만 멀티모달 파인튜닝의 위험 지점을 드러내기에는 이런 과제가 오히려 적당하다. 텍스트 생성이 아니라 시각 입력에 대한 짧고 명확한 정답을 요구하므로, 어떤 부분이 실제로 성능에 영향을 줬는지 읽기 쉽다. 모델의 reasoning 능력이 좋아졌는지, 아니면 vision adaptation이 잘 됐는지, 혹은 prompt 구조가 학습을 헷갈리게 만드는지 비교하기도 좋다.

더 중요한 점은 “쉽게 보이는 과제가 실제 운영 요구와 닮아 있다”는 사실이다. 전자상거래 상품 분류, 손상 여부 판별, 문서 이미지에서 특정 필드 추출, 설비 사진 이상 징후 분류 같은 작업들은 대부분 길고 창의적인 텍스트를 요구하지 않는다. 이미지와 짧은 정답 사이의 매핑이 안정적으로 형성되느냐가 핵심이다. 이런 과제에서는 멀티모달 대형 모델을 범용 추론기로만 두는 것보다, 작은 데이터셋이라도 도메인에 맞게 adapter를 입히는 편이 더 실용적일 수 있다.

자주 터지는 문제는 어디서 시작되나요

가장 흔한 문제는 학습이 아예 안 되는 것이 아니라, 되는 것처럼 보이는데 결과가 이상한 경우다. 손실은 내려가는데 정확도가 오르지 않거나, validation에서 특정 클래스만 과하게 맞히는 현상이다. 이때 많은 팀이 learning rate나 epoch 수를 먼저 의심한다. 그런데 멀티모달 파인튜닝에서는 입력 템플릿과 label masking이 더 근본 원인인 경우가 많다.

이미지가 포함된 대화 템플릿은 텍스트만 있을 때보다 훨씬 까다롭다. 이미지 토큰이 어디에 삽입되는지, assistant 응답의 시작 위치를 무엇으로 판별하는지에 따라 loss가 엉뚱한 위치에 걸릴 수 있다. 특히 prompt 길이를 텍스트 기준으로만 계산해 마스킹하면, 실제 assembled input에서 경계가 어긋나 성능이 조용히 무너질 수 있다. 겉으로는 학습이 정상 진행되지만 모델은 정작 답변 구간이 아니라 프롬프트 일부를 베끼는 쪽으로 업데이트될 수 있다.

이 문제는 멀티모달이 텍스트보다 더 “조립된 입력”에 가깝기 때문에 생긴다. 이미지, 특수 토큰, role marker, text가 섞인 뒤 최종 시퀀스가 만들어진다. 그래서 안전한 구현은 “정답 문자열이 실제 input sequence 안에서 어디에 놓였는지”를 역추적해 마스크를 잡는 쪽에 가깝다. 이런 세부 구현 하나가 성능 그래프보다 더 큰 차이를 만들기도 한다.

어떤 설정이 현실적인 출발점이 되나요

과하게 복잡한 스크립트보다, 왜 이 값이 들어가는지 설명되는 설정이 오래 간다. 멀티모달 Gemma 계열을 단일 GPU에서 다룰 때는 대개 아래 정도의 방향성이 무난한 출발점이 된다.

from peft import LoraConfig from transformers import BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", ) lora_config = LoraConfig( r=64, lora_alpha=64, target_modules="all-linear", lora_dropout=0.05, bias="none", )

이 코드의 포인트는 화려하지 않다. 4-bit quantization으로 weight를 눌러 담고, LoRA 타깃을 지나치게 좁히지 않는다는 점이 핵심이다. r=64 같은 값은 텍스트 미세조정보다 다소 공격적으로 보일 수 있지만, 시각 특징까지 적응시켜야 하는 과제에서는 표현 여유를 넉넉히 주는 편이 나을 때가 있다. 반대로 데이터셋이 아주 작다면 이 설정이 곧바로 과적합으로 이어질 수도 있다. 결국 중요한 것은 “작은 adapter니까 무조건 안전하다”는 믿음을 버리는 일이다. adapter도 충분히 큰 모델이다.

운영에서는 무엇을 신호로 봐야 하나요

학습이 끝난 뒤 accuracy 하나만 보는 팀은 대개 두 번 같은 실수를 반복한다. 운영에서 먼저 봐야 할 신호는 세 가지다. 첫째는 시작 시간이다. Job이 뜨고 첫 step까지 도달하는 시간이 지나치게 길다면, 학습 알고리즘보다 weight staging과 컨테이너 준비가 병목일 가능성이 높다. 이 구간은 GPU 비용이 이미 발생하고 있다는 점에서 특히 민감하다.

둘째는 step time의 들쑥날쑥함이다. 데이터 로딩, 이미지 전처리, 스토리지 I/O가 불안정하면 GPU utilization은 낮은데도 실행 시간만 길어진다. 이때 사람들은 batch size를 줄이며 메모리 문제로 오해하지만, 실제로는 CPU와 스토리지 경로가 흔들리는 경우도 많다. serverless 환경에서는 이 구간을 더 냉정하게 봐야 한다. “GPU 한 대가 느리다”가 아니라 “GPU가 기다리고 있다”일 수 있기 때문이다.

셋째는 체크포인트의 크기와 저장 주기다. adapter만 저장하는지, merge된 전체 모델을 저장하는지에 따라 비용과 복구 시간이 크게 달라진다. 짧은 실험에서는 adapter만 남겨도 되지만, serving까지 곧바로 이어질 계획이라면 어느 시점에서 merge artifact를 만들지 미리 정해야 한다. 학습 성공 후 변환 단계에서 다시 메모리가 터지는 경우도 적지 않다. 학습과 배포를 별개 단계로 본다면 이 지점에서 자주 발목이 잡힌다.

그럼에도 왜 사람들은 여전히 full fine-tuning을 떠올리나요

이유는 단순하다. full fine-tuning이 더 “진짜 학습”처럼 보이기 때문이다. 하지만 실무에서 중요한 것은 파라미터를 얼마나 많이 건드렸느냐가 아니라, 목표 과제에 맞는 적응을 얼마나 싸고 빠르게 얻었느냐다. 특히 멀티모달 업무는 데이터 품질이 들쭉날쭉하고, 클래스 정의도 자주 바뀌며, 모델 업데이트 주기도 짧다. 이런 환경에서 매번 거대한 학습 파이프라인을 돌리는 것은 대개 비용과 민첩성 모두에서 손해다.

QLoRA와 단일 GPU 전략의 진짜 장점은 “실패해도 다시 시도할 수 있는 크기”로 문제를 축소해준다는 데 있다. 이것은 기술적 미덕이자 조직적 미덕이다. 작은 팀도 실험을 반복할 수 있고, 모델 선택과 데이터 라벨링의 문제를 분리해 생각할 수 있으며, 배포 전후 비교도 빠르게 수행할 수 있다. 한 번의 거대한 학습보다 열 번의 작은 실험이 더 많은 통찰을 주는 일이 많다.

가장 현실적인 기대치는 어디에 두어야 하나요

여기서 가장 경계해야 할 환상은 “대형 멀티모달 모델을 단일 GPU에 올렸으니 이제 모든 비전 태스크가 쉽게 풀린다”는 기대다. 실제로는 반대에 가깝다. 큰 모델은 출발점이 좋을 뿐, 데이터셋의 설계와 라벨 정의가 모호하면 더 큰 혼란을 정교하게 학습할 뿐이다. 품종 분류든 상품 분류든, 클래스 경계가 애매하면 모델의 reasoning은 그 모호함을 해결해주지 못한다.

또 하나의 오해는 멀티모달 모델이 범용적일수록 파인튜닝이 덜 필요할 것이라는 생각이다. 범용성이 높을수록 평균적인 성능은 좋아질 수 있지만, 운영에서는 평균보다 꼬리 분포가 더 중요하다. 특정 품종 조합, 특정 촬영 각도, 특정 배경 조건에서 일관되게 흔들린다면 그 시스템은 현장에서 신뢰를 잃는다. 파인튜닝은 최고 점수를 노리는 기술이 아니라, 실패 패턴을 도메인 쪽으로 눌러주는 기술에 가깝다.

한 대의 GPU가 남긴 더 큰 변화는 무엇인가요

진짜 변화는 성능표가 아니라 팀의 사고방식에 있다. 멀티모달 미세조정을 거대한 연구 작업이 아니라 반복 가능한 제품 개발 단계로 옮겨왔다는 점이다. Cloud Run Jobs 같은 실행 모델은 GPU를 서비스처럼 빌려 쓰게 만들고, Gemma 4 같은 open model은 모델 내부를 만질 수 있게 해준다. 이 둘이 만나면 “우리에게는 클러스터가 없어서 못 한다”는 변명이 힘을 잃는다.

남는 질문은 더 구체적이다. 어떤 데이터가 adapter 학습의 가치가 있는가. vision tower까지 열어야 할 정도로 시각 차이가 중요한가. 4-bit 양자화로 얻는 메모리 이득이 품질 저하보다 큰가. 체크포인트와 서빙 포맷을 어디서 분기할 것인가. 이런 질문들은 훨씬 생산적이다. 인프라 장벽을 넘은 뒤에야 비로소 할 수 있는 질문들이기 때문이다.

멀티모달 파인튜닝의 현실은 여전히 까다롭다. 메모리는 쉽게 찬다. 입력 템플릿은 쉽게 어긋난다. LoRA 타깃은 생각보다 모델 구조에 민감하다. serverless는 편하지만 상태를 잊게 두지 않는다. 그런데 바로 그 까다로움 속에서 희망적인 장면이 보인다. 이제는 GPU 여러 대와 전용 학습 서버가 없어도, 제대로 설계된 단일 GPU 실험으로 충분히 의미 있는 적응을 얻을 수 있다. 대형 모델 시대의 진짜 진입장벽은 점점 “하드웨어 보유”가 아니라 “어디를 건드려야 하는지 아는 감각”으로 옮겨가고 있다.

같이 읽으면 좋은 글

같은 주제이거나 태그가 겹치는 글을 연결해 탐색 흐름을 강화했습니다.

AI 전체 보기

이전 글

공개 AMA를 채용·이민 운영 가이드로 오해할 때: 스타트업을 위한 Immigration Pitfall Playbook

다음 글

GPU 클러스터 대신 Job 하나: Gemma 4 커스터마이징이 서버리스로 넘어가는 순간

댓글

불러오는 중…