Gemini 라벨 9달러로 459M NER 모델을 파인튜닝한 개인 개발자

Hacker News23일 전조회 2

레딧 댓글에서 셰프용 칼의 브랜드·모델·강종 이름만 뽑아내려던 개인 개발자가, 댓글마다 상용 API를 호출하던 구조를 자체 파인튜닝한 소형 모델로 갈아치운 과정을 공개했다. 핵심은 Gemini 3.1 Pro에게 4,290개 댓글을 단 한 번 라벨링하게 하고(비용 9달러), 그 출력을 정답 삼아 오픈 NER 모델 GLiNER large v2.5(459M 파라미터)를 학습시켜 0.83 F1을 확보했다는 점이다.

수치를 정리하면 이렇다. 라벨링되지 않은 상태의 zero-shot GLiNER는 Gemini 답변 대비 약 0.65 F1에 그쳤다. 파인튜닝 후에는 0.83 F1까지 올라갔고, 더 작은 209M medium 모델은 0.800이었다. 학습은 Tesla T4에서 24분 걸렸고 GPU 비용은 약 2.50달러였다. 라벨 비용은 댓글당 0.0021달러로, 같은 길이의 댓글이 계속 들어오고 이미 가진 GPU에서 돌린다는 전제 아래 4,291번째 댓글부터 본전을 뽑는 셈이다.

배경에는 오래된 문제의식이 있다. 문장에서 제품명 같은 개체를 찾아내는 NER은 소형 모델로도 10년 넘게 다뤄온 작업이지만, 특정 도메인의 라벨이 없으면 zero-shot 성능은 실사용에 못 미친다. 여기서는 비싼 모델을 한 번만 돌려 라벨을 만들고, 그 라벨로 저렴한 모델을 길들이는 증류 패턴이 쓰였다. 스크레이퍼가 새 댓글을 계속 긁어오는 구조에서 비용이 게시량에 비례해 늘어나는 문제를, 호출 횟수를 0으로 만드는 방식으로 끊은 것이다.

구현에서 눈에 띄는 선택도 있다. Gemini에게는 텍스트 오프셋이 아니라 문자열 자체를 받아내고, 위치 계산은 코드에서 처리했다. 제품이 언급되지 않은 댓글은 부정 예시로 넣어 학습 데이터의 약 30%를 차지하게 했고, 두 번째 실행 전에 225개 댓글을 검증셋으로 못 박아 이후 손대지 않았다.

문제는 학습 파이프라인이었다. 열 번의 시도 중 다섯 번은 쓸 만한 모델을 내놓지 못했다. 세 번은 설정 문제였다. GLiNER의 기본 max_steps=10000이 num_train_epochs=3을 덮어써 39 에폭을 돌린 것, eval_strategy 없이 load_best_model_at_end를 쓴 것, 저장 시 state-dict 키에 GLiNER 로더가 기대하는 "model." 접두사가 빠진 것, 부정 예시에 ner_labels가 없던 것이 차례로 걸렸다.

나머지 두 번은 words_mask라는 텐서 하나 때문이었다. 이름도 모양도 attention mask와 같아서 실제 토큰은 1, 패딩은 0으로 채웠는데, 이 텐서는 마스크가 아니라 단어 인덱스였다. 특수 토큰·프롬프트·패딩은 0, 각 실제 단어의 첫 서브토큰은 1, 2, 3처럼 증가하는 값이 들어가야 한다. 전부 1로 채우면 댓글 전체가 단어 하나라는 뜻이 되어, 모델은 거대한 토큰 하나 안에서 브랜드와 재질 스팬을 찾으라는 요구를 받는다. 결과는 크래시도 경고도 NaN도 없이 loss가 70~130에서 평평하게 멈추고 eval F1이 0에 가까워지는 조용한 실패였다.

인덱스를 고친 뒤에는 튜닝이 빠르게 진행됐다. 클래스마다 임계값을 따로 두자 material 재현율이 0.787에서 0.911로 뛰었다. MagnaCut, S35VN, HAP40 같은 강종 이름이 브랜드보다 낮은 신뢰도로 나오는데 전역 컷오프 하나로는 다 걸러졌기 때문이다. 반대로 적대적 부정 예시를 51개에서 510개로 10배 늘리면 F1이 0.799로 떨어졌다. 큰 모델은 에폭 2에서 바닥을 찍고 이후 과적합했으며, 2,000개 수준의 데이터 규모에서는 조기 종료가 답이었다.

실무적으로 이 사례가 주는 신호는 두 가지다. 첫째, 상용 LLM 라벨링과 소형 오픈 모델 증류의 조합은 반복 호출 비용을 없애는 현실적인 선택지이며, 손익분기점이 수천 건 수준으로 꽤 낮다. 둘째, 이런 소규모 파인튜닝에서 발목을 잡는 것은 모델이나 데이터가 아니라 그 사이의 코드다. 잘못 채운 입력 텐서 하나가 만드는 평평한 loss는 어려운 데이터가 만드는 평평한 loss와 구분되지 않는다. 저자는 더 나은 라벨셋과 직접 만든 텐서에 대한 assertion 중 하나를 고르라면 assertion을 택하겠다고 적었다.

전제도 분명히 밝혀져 있다. 라벨을 사람이 검수하지 않았기 때문에 모든 점수는 정답 대비가 아니라 Gemini 출력과의 일치도다. Gemini가 틀린 곳을 모델이 그대로 따라 하면 정답으로, 바로잡으면 오답으로 채점된다. 랜덤 스플릿에서 0.879가 나온 실행도 결과로 인정하지 않았는데, 검증셋에 어떤 댓글이 들어가느냐만으로 F1이 2포인트씩 흔들렸기 때문이다.

관련 글