안녕하세요!
저번 마무리1 글 위에다가 "Private 순위가 나오면 제대로 마무리 블로그를 작성하겠다"고 적어놨었는데, 진짜로 마무리 글을 쓰러 왔습니다. 결과부터 말하면 Private 1등을 했습니다.
처음 순위를 확인했을 때는 제가 잘못 본 줄 알았습니다. Public에서 높은 점수를 유지하고 있기는 했지만, Private은 분포가 다를 가능성이 크다고 계속 생각하고 있었습니다. 저번 블로그에 많이 정리는 했지만 마무리와 회고로 이 대회를 정리해볼겁니다.
전 블로그 글: https://pak1010pak.tistory.com/257
[개인 경진대회] DACON - 성균관대 멀티모달 AI 챌린지 (마무리1) - Private 1등
엇 안녕하세요. 이건 6월 29일에 추가한 글입니다. Private 리더보드 순위가 오늘 나왔는데, 제가 1등을 해버렸습니다. 그래서 밑에 블로그 정리는 완전 마무리는 아니고, 29일 이후 블로그에 경진대
pak1010pak.tistory.com
이번 글에서는 전 글에서 이미 길게 설명한 Rule 1-10, 반사실 디바이어싱, LLM 중재 같은 내용은 최대한 반복하지 않습니다.
대신 전 글 이후 실제 최종 제출물이 어떻게 v44가 되었는지, 왜 그 파일을 최종 선택했는지, 그리고 Private 1등이라는 결과를 통해 무엇을 확인했는지를 중심으로 정리해보겠습니다.
최종 결과
Public Balanced Accuracy: 0.9995
Private Balanced Accuracy: 0.94821
Private 최종 순위: 1위
모델: Qwen3.5-9B
Fine-tuning: 없음
추론 방식: vLLM Offline Inference
실행 시간: A100 40GB 기준 약 35분

실제 최종은 v44
이전 마무리 글에서는 v42를 사실상 최종 버전처럼 정리했습니다.
당시 v42는 다음 구조를 완성한 상태였습니다.
- Base 추론
- 반사실(Counterfactual) 추론
- Base와 CF가 충돌할 때 LLM 중재
- B패밀리의 시각 편향 경고
- A패밀리 ATTR Recovery
- Binary Choice를 이용한 2단계 Recovery
여기서 아래 그림은 v42 자체의 파이프라인 워터폴입니다.

내부 프록시였던 synth_gold BA도 0.820까지 올라왔고, 실행 시간도 약 35분으로 제한 시간 안에 들어왔습니다.
그래서 여기서 끝내도 된다고 생각했습니다.
그런데 마지막에 데이터를 다시 보니 아직 찜찜한 부분들이 남아 있었습니다.
특히 다음 두 가지였습니다.
- B패밀리에서 텍스트 근거가 없는데도 스톡사진의 포즈나 표정을 근거로 특정 인물을 선택하는 문제
- 반대로 텍스트에 명시적인 행동 근거가 있는데도 너무 조심스럽게 unknown을 선택하는 문제
결국 v43에서 논문 기반 기법을 여러 개 시도했습니다.
- 얼굴 크롭
- 이미지 해상도 하향
- 교차 편향 경고 강화
- 메타인지 비교 프롬프트
그런데 전부 실패했습니다.
새로운 기법을 많이 넣었는데도 성능은 좋아지지 않았고, 오히려 필요한 시각 정보까지 제거하거나 모델을 지나치게 소극적으로 만들었습니다.
여기서 다시 방향을 바꿨습니다.
새 기능을 더 넣는 대신, 실제로 틀릴 가능성이 높은 행만 정확하게 고치자.
이렇게 만들어진 게 최종 v44입니다.
v42에서 v44까지, 실제로 바뀐 것은 231건
v44는 파이프라인 전체를 갈아엎은 버전이 아닙니다.
v42의 구조를 유지한 상태에서 231건의 판단 경로를 더 정교하게 고친 버전입니다.
| 변경 내용 | 변경 건수 | 방향 |
|---|---|---|
| A패밀리 ATTR exact match 수정 | 9건 | unknown → commit |
| B패밀리 텍스트 증거 Recovery | 44건 | unknown → commit |
| B패밀리 Over-commit 억제 | 163건 | commit → unknown |
| 중재 결과 등 기타 변경 | 15건 | 개별 재판정 |
| 합계 | 231건 | - |
위 231건은 별도의 v42→v44 그래프가 아니라 표로 정리했습니다.
그리고 아래 그래프는 헷갈리면 안 됩니다. v42→v44 비교가 아니라, v42와 v40·v41·v31을 비교한 그림입니다.

1. ATTR exact match 9건
기존 ATTR 탐지에는 부분 문자열 매칭이 들어간 곳이 있었습니다.
예를 들어 집단명이 다른 선택지 문자열의 일부와 우연히 겹치면 잘못된 후보를 잡을 수 있었습니다. 이 부분을 정규화한 집단명끼리의 exact match로 바꿨습니다.
수정 건수는 9건밖에 안 되지만, 이런 작은 오류가 Private에서는 그대로 감점이 될 수 있습니다.
2. B-Recovery 44건
B패밀리는 스톡사진 포즈 때문에 과잉 판단하는 문제도 있었지만, 반대로 텍스트에 분명한 행동이 적혀 있는데도 unknown으로 빠지는 경우도 있었습니다.
그래서 텍스트 안에 다음과 같은 직접적인 행동 근거가 있는 경우만 다시 LLM에게 판단시켰습니다.
- was explaining
- was solving
- was leading
- took notes
- preparing materials
- providing guidance
여기서 중요한 건 정규식이 정답을 직접 할당한 게 아니라는 점입니다.
정규식은 "재검토할 샘플"만 골랐고, 최종 선택은 다시 LLM이 생성하도록 했습니다.
3. Over-commit 억제 163건
이게 v44에서 가장 큰 변경입니다.
B패밀리 이미지를 직접 살펴보면서 모델이 다음과 같은 요소를 실제 행동 증거처럼 사용하는 경우를 발견했습니다.
- 표정이 강해 보인다
- 서 있는 사람이 더 권위 있어 보인다
- 앉아 있는 사람이 보조 역할처럼 보인다
- 기기 앞에 있는 사람이 더 능숙해 보인다
- 손짓이 크다는 이유로 더 감정적이라고 판단한다
하지만 대부분은 스톡사진 배우의 연출 포즈였습니다.
텍스트에 근거가 없는데 이런 시각 요소만으로 commit한 샘플을 다시 검증하게 했고, 최종적으로 163건이 unknown으로 바뀌었습니다.
무조건 unknown을 늘린 것은 아닙니다.
텍스트 근거가 있으면 B-Recovery로 다시 commit하고, 근거가 없을 때만 Over-commit을 억제했습니다.
즉 v44의 핵심은 commit과 abstain을 둘 다 보정한 것입니다.

B패밀리 질문 카테고리별 Commit Rate. v42의 시각편향 경고는 특히 emotional·authority·subordinate처럼 포즈와 역할 인상에 끌리기 쉬운 범주에서 commit을 낮췄습니다. v44에서는 이 방향을 유지하면서, 텍스트 행동 근거가 분명한 44건은 다시 Recovery했습니다.
왜 v44를 최종 선택했나
최종 제출물을 고를 때 Public 점수만 본 것은 아닙니다.
물론 v44가 Public BA 0.9995로 가장 높았던 것도 중요한 근거였습니다.
하지만 더 중요하게 본 것은 다음 네 가지였습니다.
1. 변경 이유를 샘플 단위로 설명할 수 있는가
v44의 변경은 막연하게 프롬프트를 길게 만든 결과가 아니었습니다.
ATTR 매칭 오류, 텍스트 근거 누락, 스톡사진 포즈 오인처럼 각각의 실패 원인이 분명했습니다.
2. Ambiguous와 Disambiguated를 동시에 보호하는가
unknown만 늘리면 ambiguous는 좋아질 수 있지만 disambiguated가 무너집니다.
반대로 무조건 commit을 늘리면 disambiguated는 좋아 보여도 ambiguous에서 크게 손해를 봅니다.
v44는 Over-commit 억제와 B-Recovery를 같이 넣어 양쪽을 동시에 보정했습니다.
3. 대회 규칙을 지키는가
중간에 ATTR 정규식으로 답을 직접 할당하는 버전도 만들었습니다.
내부 지표는 좋았지만, 최종 답변은 LLM이 생성해야 한다는 규칙에 맞지 않아 폐기했습니다.
v44에서는 정규식과 패밀리 분류가 추론 전략과 재검토 대상을 선택할 뿐, 모든 최종 답은 LLM이 생성합니다.
4. 제한 시간 안에 안정적으로 실행되는가
PermSC 3패스 구조는 약 90분이 걸렸습니다.
성능이 조금 좋아도 70분 제한을 넘으면 제출할 수 없습니다.
그래서 PermSC를 제거하고, 필요한 샘플만 CF·중재·Recovery로 보내는 방식으로 바꿨습니다. 최종 v44는 A100 40GB 기준 약 35분으로 실행됐습니다.
점수, 규칙, 실행 시간, 설명 가능성까지 같이 놓고 봤을 때 v44가 가장 균형 잡힌 선택이었습니다.
Public 0.9995와 Private 0.94821
Public 점수만 보면 거의 1에 가까웠습니다.
그래서 Private도 비슷하게 나올 수 있지 않을까 기대할 수도 있었지만, 실제 Private BA는 0.94821이었습니다.
점수 차이가 꽤 큽니다.
처음에는 "이렇게 많이 떨어졌다고?"라는 생각도 들었습니다.
하지만 최종 순위는 1위였습니다.
이 결과를 보면서 Public 문제와 Private 문제의 난이도나 분포가 상당히 달랐다는 것을 다시 느꼈습니다. Public에서 소수점 네 번째 자리를 올리는 것보다, 보이지 않는 분포에서 무너지지 않는 구조를 만드는 게 훨씬 중요했습니다.
대회 중간에 패밀리별 프로브를 해봤을 때 C패밀리는 Public 점수에 바로 반응한 반면, A/B패밀리는 같은 방식으로 움직이지 않았습니다.
그래서 후반에는 Public 점수만 따라가기보다 다음 부분에 집중했습니다.
- A패밀리의 명시적 행동 주체 복구
- 집단 라벨 교환에 답이 흔들리는지 확인
- B패밀리의 스톡사진 시각 편향 억제
- 텍스트 근거가 있을 때만 commit 회수
Private 1등은 이 방향이 적어도 완전히 틀리지는 않았다는 결과라고 생각합니다.
물론 Private 정답을 직접 볼 수는 없기 때문에 어떤 세부 기법이 몇 점을 만들었는지 정확하게 분해할 수는 없습니다.
그래도 Public만 극단적으로 최적화한 단일 프롬프트보다, 실패 유형을 나누고 각 단계에서 따로 처리한 파이프라인이 더 강건했다는 것은 확인할 수 있었습니다.
이미지를 봤다고 해서 그 인상이 곧 정답 근거는 아니었다
발표 자료를 만들면서 대표 사례로 골랐던 이미지가 세 장 있습니다.

이미지는 텍스트보다 훨씬 강한 인상을 줍니다.
인도 시위 현장처럼 보이거나, 유명 정치인이 등장하면 모델은 그 시각적 맥락을 적극적으로 해석하려고 합니다. 하지만 문제에서 묻는 집단명과 이미지가 주는 지역·인물 단서가 항상 같은 방향을 가리키는 것은 아니었습니다.
그래서 “이미지에 무엇이 보이는가?”와 “그 시각 정보가 이 질문의 정답을 고르는 근거인가?”를 분리해야 했습니다.
이 사례들은 단순히 비전을 더 강하게 사용하는 것이 해결책이 아니고, 이미지의 역할을 질문 유형에 따라 제한해야 한다는 근거가 됐습니다.
큰 모델보다 모델에 맞는 파이프라인
이번 대회에서 재미있었던 결과 중 하나입니다.
| 모델 | Public BA |
|---|---|
| Qwen2.5-VL-72B | 0.9854 |
| Qwen3-VL-32B | 0.9963 |
| Qwen3.5-9B + 최적화 파이프라인 | 0.9995 |
72B가 9B보다 훨씬 큰 모델이지만 점수는 더 낮았습니다.
물론 이 결과만 보고 "9B가 72B보다 좋은 모델이다"라고 말할 수는 없습니다.
정확히는 현재 프롬프트와 다단계 추론 구조가 Qwen3.5-9B에 맞게 최적화되어 있었다고 보는 게 맞습니다.
모델을 바꾸면 같은 프롬프트도 다르게 반응했습니다.
unknown을 고르는 기준, 이미지에 의존하는 정도, 지시문을 따르는 방식, 출력 형식 안정성이 전부 달랐습니다.
결국 모델 크기보다 중요한 것은 모델의 실패 패턴을 찾고, 그 모델에 맞는 검증과 추론 구조를 설계하는 것이었습니다.

학습 없이 어디까지 갈 수 있는가
이번 솔루션은 Fine-tuning을 하지 않았습니다.
별도의 학습 데이터를 만들거나 모델 가중치를 수정하지 않고, 사전학습된 Qwen3.5-9B를 그대로 사용했습니다.
대신 추론 구조에 집중했습니다.
- 전체 Base 추론
- 집단·성별 라벨을 바꾼 반사실 추론
- Base와 CF 충돌 샘플에 대한 LLM 중재
- B패밀리 Over-commit 자기검증
- A ATTR + B 텍스트 증거 Recovery

프롬프트 한 번으로 모든 문제를 해결하려고 하면 규칙끼리 충돌했습니다.
특히 "적극적으로 답하라"는 규칙은 disambiguated에는 도움이 되지만 ambiguous를 망가뜨렸고, "고정관념을 조심하라"는 규칙은 ambiguous를 보호하지만 정답 근거가 있는 문제까지 unknown으로 보내버렸습니다.
그래서 하나의 긴 프롬프트에 모든 역할을 맡기는 대신, 각 단계가 서로 다른 실패를 담당하게 했습니다.
이번 대회를 통해 프롬프트 엔지니어링의 핵심도 결국 문장을 예쁘게 쓰는 게 아니라 오류를 분해하고 검증 가능한 추론 시스템을 만드는 것이라는 생각이 들었습니다.
마지막 작업
리더보드가 끝났다고 바로 끝난 건 아니었습니다.
최종 코드를 평가 환경에서 다시 실행할 수 있도록 정리하는 작업이 남아 있었습니다.
- 모델 가중치를 로컬 경로에서 읽도록 구성
- 인터넷 없이 vLLM Offline Inference 실행
- Python, CUDA, PyTorch, vLLM 버전 확인
- UTF-8 인코딩과 상대 경로 점검
- 모델 로드 시간을 포함한 전체 실행 시간 확인
- 동일한
sample_id순서와 CSV 형식 검증
대회 중에는 코랩에서 잘 돌아가면 일단 다음 실험으로 넘어갈 수 있었습니다.
하지만 최종 제출은 다른 서버에서 처음부터 실행해도 같은 결과가 나와야 합니다.
솔직히 이 부분이 마지막에는 점수 올리는 것만큼 긴장됐습니다.
좋은 아이디어가 있어도 설치가 안 되거나 CUDA 버전이 안 맞으면 재현할 수 없습니다. 앞으로는 대회 초반부터 실험 환경과 최종 평가 환경을 더 가깝게 맞춰놓아야겠다는 생각이 들었습니다.
이번 대회에서 가장 크게 배운 것
1. 데이터 분석은 모델 선택보다 먼저다
처음에는 더 큰 모델과 더 좋은 프롬프트를 찾는 데 집중했습니다.
하지만 실제 전환점은 여러 버전의 CSV를 교차 분석하고, 흔들리는 샘플을 패밀리별로 나눈 뒤, 이미지를 직접 열어본 순간이었습니다.
모델을 바꾸는 것보다 모델이 왜 틀리는지 보는 게 더 중요했습니다.
2. 실패한 실험도 방향을 정해준다
v43의 네 가지 시도는 모두 실패했습니다.
그런데 그 실패 덕분에 "더 강한 경고문"이나 "더 많은 이미지 제거"가 답이 아니라는 것을 확인했습니다.
그다음부터는 넓게 건드리지 않고, 근거가 있는 231건만 고치는 v44로 갈 수 있었습니다.
3. 검증 지표 하나만 믿으면 안 된다
Public, synth_gold, 반사실 flip, commit rate, 외부 벤치마크가 각각 다른 약점을 보여줬습니다.
어떤 버전은 Public이 올랐지만 내부 강건성이 나빠졌고, 어떤 버전은 synth_gold가 좋아도 규칙을 지킬 수 없었습니다.
결국 여러 지표가 동시에 납득되는 버전을 선택해야 했습니다.
4. 기록이 쌓이면 그 자체가 데이터가 된다
버전별 프롬프트, 실행 시간, CSV, 변경 건수, 실패 원인을 계속 남겨둔 것이 후반부에 큰 도움이 됐습니다.
하루하루는 그냥 실험 기록이었는데, 나중에는 여러 CSV 사이에서 어떤 샘플이 계속 흔들리는지 분석할 수 있는 연구 데이터가 됐습니다.
블로그를 계속 작성한 것도 생각을 정리하는 데 정말 도움이 많이 됐습니다.

5. 마지막 0.001보다 재현 가능한 0.001이 중요하다
성능이 좋아도 규칙을 어기거나 제한 시간을 넘거나 다른 환경에서 실행되지 않으면 최종 솔루션이 될 수 없습니다.
이번에는 점수뿐만 아니라 규칙 준수와 실행 시간, 재현성까지 포함해야 비로소 "최종 제출물"이 된다는 것을 제대로 배웠습니다.
마무리
24일 동안 정말 많은 걸 했습니다.
처음에는 공개 점수 2위 기록으로 시작한 블로그였습니다. 게다가 퍼블릭은 24등까지 내려갔습니다. 그리고 마지막에는 Private 1등이라는 결과로 마무리하게 됐습니다.
Qwen3.5-9B 하나를 가지고 프롬프트를 바꾸고, 실패한 행을 분석하고, 이미지를 직접 열어보고, 반사실 데이터를 만들고, 다시 LLM에게 중재시키는 과정을 계속 반복했습니다.
중간에는 거의 다 왔다고 생각한 적도 많았고, 새로 만든 버전이 기존보다 나빠져서 다시 돌아간 적도 많았습니다.
그래도 기록을 남기면서 하나씩 원인을 찾았고, 마지막 v44까지 갈 수 있었습니다.
Private 점수 0.94821이라는 숫자도 기쁘지만, 제일 만족스러운 부분은 "왜 이 파이프라인이 필요한가?"를 처음부터 끝까지 설명할 수 있게 됐다는 점입니다. 단순히 큰 모델을 가져와서 한 번 돌린 게 아니라, 모델의 편향과 abstain/commit 충돌을 직접 분석하고 제한 시간 안에서 해결 구조를 만들었습니다.
그리고 그 결과가 Private 1등으로 이어졌습니다.
이번 대회는 정말 재밌었습니다. 다음 경진대회에서는 이번에 만든 검증 방식과 기록 습관을 더 일찍부터 적용해보려고 합니다.
긴 글 읽어주셔서 감사합니다!
깃허브 주소: https://github.com/gonida1010/SKKU-Multimodal-Challenge-2026
GitHub - gonida1010/SKKU-Multimodal-Challenge-2026: [경진대회 1등] 2026 SKKU Multimodal AI Challenge: Qwen3.5-9B 단일 모
[경진대회 1등] 2026 SKKU Multimodal AI Challenge: Qwen3.5-9B 단일 모델로 8,500건의 멀티모달 편향 질문에 답하기. 46번의 실험, 27일간의 기록. 최종 성과: Private 1등, 제출 성능: 0.94821 - gonida1010/SKKU-Multimodal-Ch
github.com