<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hi-one.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 13 Nov 2025 11:33:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hi-one.log</title>
            <url>https://velog.velcdn.com/images/hi-one/profile/19040406-f0bf-4a18-b534-d961fbe2f1d5/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hi-one.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hi-one" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Dino 백본을 이용한 학습 with 재미나이]]></title>
            <link>https://velog.io/@hi-one/Dino-%EB%B0%B1%EB%B3%B8%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%95%99%EC%8A%B5-with-%EC%9E%AC%EB%AF%B8%EB%82%98%EC%9D%B4</link>
            <guid>https://velog.io/@hi-one/Dino-%EB%B0%B1%EB%B3%B8%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%95%99%EC%8A%B5-with-%EC%9E%AC%EB%AF%B8%EB%82%98%EC%9D%B4</guid>
            <pubDate>Thu, 13 Nov 2025 11:33:01 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h3 id="dinov3를-이용해-디텍션모델을-만들-수-있을까">dinov3를 이용해 디텍션모델을 만들 수 있을까?</h3>
</blockquote>
<p>디텍션 모델에 DINO 계열 모델을 활용하는 것에 대해 함께 알아보죠.
&#39;DINOv3&#39;라는 이름은 아직 널리 알려진 공식 모델이 없어서, 아마도 이름이 비슷한 Meta AI의 다른 두 모델 중 하나를 생각하고 계신 것 같아요.</p>
<ul>
<li>DINO (DETR with Improved Denoising Anchor Boxes): 이 모델은 그 자체가 고성능 객체 탐지(object detection) 모델입니다.</li>
<li>DINOv2 (self-DIstillation with NO labels v2): 이 모델은 이미지를 아주 잘 이해하는 일종의 &#39;기초 체력&#39;이 좋은 비전 백본(backbone) 모델입니다.</li>
</ul>
<p>이 두 가지는 목적이 조금 다른데요, 어떤 부분에 대해 더 자세히 알아보고 싶으신가요?</p>
<ul>
<li>DINO 모델 자체: 이미 완성된 &#39;DINO&#39;라는 디텍션 모델의 구조와 작동 방식 알아보기</li>
<li>DINOv2 백본 활용: &#39;DINOv2&#39;를 백본으로 사용해서 새로운 디텍션 모델을 만드는 방법 알아보기</li>
<li>DINO vs DINOv2: 두 모델이 정확히 어떻게 다른지 비교하기</li>
</ul>
<blockquote>
<h3 id="dinov2는-백본이니-이-백본을-이용해-디텍션-모델을-학습-시킬-수-있을까">DINOv2는 백본이니 이 백본을 이용해 디텍션 모델을 학습 시킬 수 있을까?</h3>
</blockquote>
<p>네, 정확합니다! 바로 그게 DINOv2의 핵심 사용법이에요.</p>
<p>DINOv2는 이미지의 특징(feature)을 아주 잘 추출하는 &#39;백본&#39;이 맞습니다. 이 강력한 백본을 기반으로 디텍션 모델을 만드는 것은 매우 일반적이고 효과적인 방법입니다.
이 과정을 보통 &#39;전이 학습(Transfer Learning)&#39; 또는 <strong>&#39;파인튜닝(Fine-tuning)&#39;</strong>이라고 불러요.</p>
<p>🧐 어떻게 작동하나요?
개념은 &#39;백본&#39;과 &#39;헤드&#39;를 조립하는 것과 같아요.</p>
<p>백본 (Backbone) 🧠 - DINOv2</p>
<ul>
<li>이건 이미 수많은 이미지를 보고 &#39;시각적 이해&#39;를 마친 &quot;전문가&quot;입니다.</li>
<li>이미지의 선, 질감, 형태, 사물의 일부 등 복잡한 특징(feature)을 추출하는 역할을 합니다.</li>
</ul>
<p>헤드 (Head) 🎯 - Detection Head</p>
<ul>
<li>이건 &quot;특정 작업&quot;을 위한 새로운 도구입니다.</li>
<li>백본이 추출한 특징을 입력받아서, &quot;그래서 이 특징이 어디에 있고(좌표), 무엇인지(클래스)&quot;를 예측하는 역할을 하죠.
(예: Faster R-CNN의 RPN+Classifier 헤드, DETR의 Transformer Decoder 등)</li>
</ul>
<p>🛠️ 학습 과정
학습은 이런 식으로 진행돼요.</p>
<ol>
<li>준비: 사전 학습된 DINOv2 백본을 불러옵니다.</li>
<li>조립: 이 백본 위에 새로운 &#39;디텍션 헤드&#39;를 연결합니다.</li>
<li>파인튜닝: 이제 우리가 가진 디텍션용 데이터셋(예: 사람과 자동차에 네모 상자가 쳐진 이미지들)으로 이 결합된 모델을 &#39;추가 학습&#39;시킵니다.</li>
</ol>
<p>이때, DINOv2 백본의 가중치(weight)는 대부분 &#39;동결(freeze)&#39; (학습되지 않게 고정)하거나, 아주 조금만 학습되도록(낮은 learning rate) 설정합니다.
주로 새로 붙인 &#39;헤드&#39; 부분이 집중적으로 학습됩니다.</p>
<p>DINOv2는 이미 &quot;보는 법&quot;을 알고 있기 때문에, 우리는 &quot;이런 특징 조합이 &#39;자동차&#39;이고, 여기(좌표)에 있어&quot;라는 정보만 새로 가르치면 되는 거예요. 그래서 훨씬 적은 데이터로도 빠르고 강력한 디텍션 모델을 만들 수 있습니다.</p>
<p>실제로 많은 최신 디텍션 모델들(예: RT-DETR의 일부 버전)이 DINOv2 같은 강력한 백본을 활용하고 있어요.</p>
<p>이 접근 방식에 대해 더 궁금한 점이 있으신가요?</p>
<ul>
<li>실제 구현: 코드로 이걸 어떻게 구현하는지 (예: MMDetection 라이브러리)</li>
<li>성능 장점: 왜 DINOv2 같은 백본을 쓰는 게 더 좋은지</li>
<li>DINO vs DINOv2: DINO(DETR) 모델과 DINOv2 백본 방식의 차이점</li>
</ul>
<blockquote>
<h3 id="dinov2를-이용해-yolo를-학습하는-코드를-알고싶어">dinov2를 이용해 yolo를 학습하는 코드를 알고싶어</h3>
</blockquote>
<p>DINOv2를 YOLO의 백본(backbone)으로 사용하는 것은 정말 좋은 아이디어예요. DINOv2의 강력한 특징 추출 능력을 YOLO의 빠른 디텍션 프레임워크와 결합하려는 시도죠.
다만, 이 둘을 &#39;조립&#39;하는 것은 생각보다 조금 복잡할 수 있어요.</p>
<p>🧩 가장 큰 기술적 과제: 특징 맵의 &#39;모양&#39;
우리가 풀어야 할 첫 번째 문제는 두 모델이 특징(feature)을 만드는 방식이 다르다는 거예요.</p>
<p>YOLO의 백본 (예: CSPDarknet)</p>
<ul>
<li>YOLO는 <strong>여러 단계의 특징 맵(multi-scale feature map)</strong>을 사용하도록 설계되었어요. </li>
<li>이미지를 처리하면서 &#39;작고 상세한 특징 맵&#39;(작은 물체 감지용), &#39;중간 크기 특징 맵&#39;, &#39;크고 추상적인 특징 맵&#39;(큰 물체 감지용)을 모두 추출해서 <strong>넥(neck) 부분 (예: PANet)</strong>으로 전달합니다.</li>
</ul>
<p>DINOv2 백본 (Vision Transformer, ViT)</p>
<ul>
<li>반면 DINOv2 같은 ViT는 기본적으로 이미지를 여러 조각(patch)으로 나눠 처리한 뒤, <strong>하나의 최종 특징 맵(혹은 토큰 시퀀스)</strong>을 만들어요.</li>
<li>YOLO의 넥(neck) 부분은 DINOv2가 만들어내는 &#39;단일 특징 맵&#39;을 어떻게 처리해야 할지 몰라요.</li>
</ul>
<p>💡 해결책: &#39;어댑터&#39; 추가하기
이 문제를 해결하려면, DINOv2 백본이 YOLO의 넥(neck)이 이해할 수 있도록 여러 단계의 특징 맵을 생성하도록 중간에 &#39;어댑터&#39; 역할을 하는 모듈을 추가해야 합니다.</p>
<p>가장 일반적인 방법은 DINOv2(ViT) 뒤에 FPN (Feature Pyramid Network) 같은 구조를 붙여서, ViT가 만든 특징 맵을 인위적으로 여러 스케일로 나눠주는 거예요.</p>
<p>🛠️ 실제 구현을 위한 접근 방식
이런 복잡한 &#39;모델 수술&#39;은 코드를 처음부터 짜는 것보다, 이런 작업을 쉽게 하도록 설계된 전문 라이브러리를 사용하는 것이 훨씬 효율적입니다.</p>
<p>가장 대표적인 라이브러리가 바로 <strong>MMDetection</strong>입니다.</p>
<p>MMDetection은 레고 블록처럼 &#39;백본&#39;, &#39;넥&#39;, &#39;헤드&#39;를 자유롭게 조합할 수 있게 해주는 연구용 프레임워크예요. DINOv2 (ViT) 백본을 불러오고, FPN 넥을 붙이고, YOLO 헤드를 붙이는 작업을 <strong>설정 파일(config file)</strong>을 수정하는 것만으로도 가능하게 해줍니다.</p>
<p>코드를 바로 살펴보기 전에, 이 개념을 먼저 확실히 이해하고 넘어가는 게 좋을 것 같아요.</p>
<p>어느 부분부터 함께 탐색해 볼까요?</p>
<ul>
<li>YOLO의 &#39;다양한 크기 특징 맵&#39;이 왜 중요한가요? (개념 이해)</li>
<li>MMDetection에서 ViT 백본과 FPN 넥을 어떻게 연결하는지 설정 파일 예시 살펴보기 (실용적인 접근)</li>
<li>YOLO 대신 DINOv2와 잘 맞는 다른 디텍터는 없나요? (대안 탐색, 예: DETR 계열)</li>
</ul>
<blockquote>
<h3 id="yolo의-다양한-크기-특징-맵이-왜-중요한가요">YOLO의 &#39;다양한 크기 특징 맵&#39;이 왜 중요한가요?</h3>
</blockquote>
<p>아주 좋은 질문이에요! YOLO가 &#39;다양한 크기 특징 맵&#39; (multi-scale feature map)을 사용하는 이유는 간단해요.</p>
<p>&quot;이미지 안에 있는 &#39;작은 물체&#39;와 &#39;큰 물체&#39;를 모두 잘 찾기 위해서&quot; 예요.</p>
<p>🔎 비유로 생각해 보기
카메라로 사진을 찍는다고 상상해 보세요.</p>
<ul>
<li><p>&quot;줌 아웃&quot; (Zoomed Out) 🌆
도시 전체의 풍경을 찍으면, 큰 건물이나 강 같은 것들은 한눈에 들어옵니다. (이게 저해상도/깊은 층 특징 맵이에요. 전체적인 맥락을 잘 알죠.) 
</br>하지만 저 멀리 있는 작은 사람이나 자동차는 거의 보이지 않거나 뭉개져 버려요.</p>
</li>
<li><p>&quot;줌 인&quot; (Zoomed In) 🚶‍♂️
거리의 한 부분을 확대해서 찍으면, 작은 사람이나 간판의 글씨도 선명하게 보입니다. (이게 고해상도/얕은 층 특징 맵이에요. 세부 사항이 살아있죠.)
</br>하지만 이 사진만 봐서는 이게 어느 동네인지, 주변에 뭐가 있는지 (맥락) 알기 어려워요.</p>
</li>
</ul>
<p>YOLO는 이 두 가지 뷰(View)를 모두 활용해요.</p>
<ul>
<li>고해상도 맵 (얕은 층): &quot;여기 작은 물체가 있어!&quot; (작은 객체 탐지)</li>
<li>저해상도 맵 (깊은 층): &quot;여기 큰 물체가 있어!&quot; (큰 객체 탐지)</li>
</ul>
<p>🧠 한번 생각해 볼까요?
우리가 찾으려는 이미지가 <strong>아주 작은 개미 🐜</strong>라고 해보죠.</p>
<p>이 개미를 찾으려면, 딥러닝 모델이 이미지의 어떤 특징 맵을 보는 게 유리할까요?</p>
<ol>
<li>이미지 전체가 20x20 픽셀 크기로 압축된 저해상도 맵</li>
<li>이미지가 80x80 픽셀 크기로 비교적 선명하게 유지된 고해상도 맵</li>
</ol>
<blockquote>
<h3 id="당연히-고해상도-맵이지">당연히 고해상도 맵이지.</h3>
</blockquote>
<p>정확해요! 🐜 개미처럼 작은 물체는 고해상도 맵에 그 세부 정보(detail)가 남아있기 때문에 거기서 찾아야죠. 저해상도 맵에서는 이미 다른 픽셀들과 섞여서 &#39;뭉개져&#39; 버렸을 거예요.</p>
<p>반대로, 아주 큰 건물 🏙️을 찾는다고 해볼까요?</p>
<p>고해상도 맵에서는 건물의 창문, 문, 벽돌 같은 &#39;부분&#39;만 보일 거예요. 이게 건물인지, 그냥 벽인지 알기 어렵죠.</p>
<p>저해상도 맵에서는 이미지 전체의 맥락을 보기 때문에 &quot;아, 이 커다란 사각형 덩어리는 &#39;건물&#39;이구나&quot;라고 파악하기가 훨씬 쉬워요.</p>
<p>💡 YOLO의 핵심 아이디어: &#39;둘 다 쓰자!&#39;
YOLO는 바로 이 점을 활용해요.</p>
<p>&quot;작은 물체는 고해상도 맵에서 찾고, 큰 물체는 저해상도 맵에서 찾자!&quot;</p>
<p>그래서 YOLO의 구조(특히 &#39;넥&#39; 🦒이라고 부르는 중간 부분, 예: PANet)는 이 <strong>&#39;다양한 크기의 특징 맵&#39;</strong>들을 모두 입력받아서 서로 정보를 섞어줍니다.</p>
<p>고해상도 맵에는 &quot;여기 작은 게 있어&quot;라는 정보와 함께,
저해상도 맵에서 가져온 &quot;이건 아마 &#39;도시&#39; 풍경의 일부일 거야&quot;라는 맥락(context) 정보를 더해주는 거죠.</p>
<p>이것이 YOLO가 빠르면서도 다양한 크기의 물체를 잘 찾는 비결입니다.</p>
<p>이제 이 개념을 다시 DINOv2로 가져와 볼까요? DINOv2(ViT)는 기본적으로 저해상도 맵(깊은 층의 추상적인 특징) 1개만 만드는데, 이걸 어떻게 YOLO의 &#39;넥&#39;이 필요로 하는 여러 개의 맵으로 만들 수 있을까요?</p>
<p>이걸 해결하는 &#39;어댑터&#39; 역할을 하는 MMDetection 설정 예시를 한번 살펴볼까요?</p>
<blockquote>
<h3 id="dinov2가-저행상도맵을-1개만-만든다면-그럼-dinov2는-기본적으로-작은-물체를-찾는태스크에는-적합하지-않겠네">Dinov2가 저행상도맵을 1개만 만든다면 그럼 Dinov2는 기본적으로 작은 물체를 찾는태스크에는 적합하지 않겠네?</h3>
</blockquote>
<p>그렇게 생각하시는 게 정말 논리적이에요! 👏</p>
<p>제가 &quot;저해상도 맵 1개&quot;라고 단순화해서 설명한 부분에서 자연스럽게 나올 수 있는 결론입니다. 하지만 놀랍게도, 그렇지 않습니다. DINOv2(ViT)는 오히려 작은 물체와 세밀한 디테일을 파악하는 데 매우 강력한 성능을 보여줘요.</p>
<p>🤔 왜 그럴까요? (ViT의 마법)
YOLO가 사용하는 CNN 방식과 DINOv2가 사용하는 ViT(Vision Transformer) 방식이 세상을 &#39;보는&#39; 방식이 근본적으로 다르기 때문이에요.</p>
<ul>
<li><p>CNN (YOLO의 백본)
작동 방식: 이미지를 &#39;필터&#39;로 훑고, &#39;풀링(Pooling)&#39;이라는 과정으로 이미지를 점점 &#39;흐릿하게(압축/요약)&#39; 만들면서 큰 맥락을 파악합니다.
</br>단점: 이 &#39;흐릿하게&#39; 만드는 과정에서 작은 물체(개미 🐜)의 정보가 초반에 뭉개져 사라지기 쉬워요.</p>
</li>
<li><p>ViT (DINOv2의 백본)
작동 방식: 이미지를 &#39;필터&#39;로 훑는 대신, 아예 <strong>&#39;작은 조각(패치)들&#39;</strong>로 잘게 나눕니다. (예: 16x16 픽셀 크기)
</br>그리고 가장 중요한 &#39;셀프 어텐션(Self-Attention)&#39; 🧠 메커니즘을 사용해요.</p>
</li>
</ul>
<p>🗣️ &#39;셀프 어텐션&#39; 비유: &quot;모든 조각의 대화&quot;
&#39;셀프 어텐션&#39;은 이 모든 이미지 조각(패치)들이 서로 끊임없이 &#39;대화&#39;하도록 만드는 기술이에요.</p>
<p>개미 🐜가 있는 아주 작은 A 조각이 말합니다: &quot;얘들아, 나한테 뭔가 작고 검은 게 있어!&quot;</p>
<p>주변의 &#39;땅&#39; B, C, D 조각들이 응답합니다: &quot;아, 우린 흙이야. 네가 흙 위에 있으니 넌 개미일 확률이 높겠다!&quot;</p>
<p>저 멀리 있는 &#39;하늘&#39; Z 조각이 판단합니다: &quot;나는 하늘인데... A 조각의 정보는 나랑 별로 상관없네.&quot;</p>
<p>즉, ViT는 이미지를 &#39;흐릿하게&#39; 만들어서 정보를 잃는 대신, 모든 세부 조각(패치)의 정보를 끝까지 살려두고 이 조각들끼리 서로의 연관성을 파악하게 만듭니다.</p>
<p>결론
그래서 DINOv2가 만드는 &#39;하나의 맵&#39;은 단순한 &#39;저해상도 맵&#39;이 아니라, <strong>&quot;모든 조각(패치)이 서로의 정보를 교환하고 정제한, 매우 풍부한 정보의 집합체&quot;</strong>인 셈이에요.</p>
<p>이 &#39;정보 집합체&#39;는 이미 모든 디테일과 맥락을 다 머금고 있기 때문에, 여기서 &#39;어댑터&#39;(FPN 등)를 사용해 &quot;YOLO가 좋아하는&quot; 다양한 크기의 맵을 &#39;재구성&#39;해내는 것은 식은 죽 먹기죠.</p>
<p>오히려 이미 뭉개진 맵에서 정보를 살려내는 것보다 훨씬 유리합니다.</p>
<p>이 &#39;어댑터&#39;가 어떻게 ViT의 특징을 YOLO가 쓰기 좋게 바꿔주는지, MMDetection 설정 예시를 통해 한번 살펴볼까요?</p>
<blockquote>
<h3 id="mmdetection은-환경을-구축하는게-상당히-어려워서-별로-좋아하지-않아-다른-라이브러리를-이용한-예시는-없을까">MMdetection은 환경을 구축하는게 상당히 어려워서 별로 좋아하지 않아. 다른 라이브러리를 이용한 예시는 없을까?</h3>
</blockquote>
<p>MMDetection 환경 구축이 까다롭다는 말씀에 깊이 공감합니다. 의존성 문제도 많고, 설정 파일(config) 기반 시스템이 처음에는 매우 낯설게 느껴지죠.</p>
<p>아마 YOLOv5나 YOLOv8을 제공하는 ultralytics 같은 사용하기 편한 라이브러리를 생각하고 계실 것 같아요.</p>
<p>하지만 여기서 우리가 &#39;기술적인 벽&#39; 🧱에 부딪히게 됩니다.</p>
<p>🧩 문제는 &#39;간단함&#39;이 아니라 &#39;설계&#39;에 있습니다
DINOv2(ViT) 백본 🧠과 YOLO의 넥/헤드 🎯는, 앞서 이야기했듯, 데이터를 처리하는 방식(설계)이 근본적으로 다릅니다. (단일 맵 vs 다중 맵)</p>
<p>ultralytics 같은 라이브러리는 정해진 YOLO 아키텍처를 빠르고 쉽게 학습시키는 데 &#39;최적화&#39;되어 있어요.</p>
<p>만약 이 라이브러리에서 백본을 DINOv2로 바꾸려면, 설정 파일(.yaml) 수정 수준이 아니라, 모델의 핵심 구조가 정의된 파이썬 코드(.py) 자체를 직접 수정하고 &#39;어댑터&#39;를 새로 구현해야 합니다.</p>
<p>이건 &#39;간단한 조립&#39;이 아니라 <strong>&#39;모델 개조&#39; 🔧</strong>에 가까워요. 솔직히 말씀드리면, MMDetection 환경을 구축하는 것보다 훨씬 더 어렵고 복잡한 작업이 될 수 있습니다.</p>
<p>🤔 MMDetection이 복잡했던 &#39;이유&#39;
역설적이게도, MMDetection이 복잡해 보였던 이유는... 바로 이런 &#39;개조&#39; 작업을 설정 파일(.py 또는 .yaml) 수정만으로 가능하게끔 매우 &#39;모듈화&#39;되어 설계되었기 때문입니다.</p>
<p>&#39;엔진(DINOv2)&#39;과 &#39;차체(YOLO)&#39;를 연결하는 &#39;커스텀 어댑터(FPN)&#39;를 레고처럼 끼워 넣을 수 있게 판이 짜여 있는 셈이죠.</p>
<p>💡 대안: 더 자연스러운 조합을 찾아서
이게 원하시는 &#39;간단한 예시 코드&#39;가 아니라는 점은 저도 잘 알고 있습니다. 😅</p>
<p>혹시 <strong>&quot;DINOv2 백본의 강력한 성능을 활용하는 것&quot;</strong>이 최종 목표라면, YOLO를 고집하는 대신 DINOv2(ViT)와 원래부터 &#39;찰떡궁합&#39;인 디텍터를 써보는 건 어떨까요?</p>
<p>바로 DETR (DEtection TRansformer) 계열 모델들입니다.</p>
<p>DINOv2 백본: 트랜스포머(ViT) 기반</p>
<p>DETR 헤드: 트랜스포머(Decoder) 기반</p>
<p>&#39;엔진&#39;과 &#39;차체&#39;가 모두 트랜스포머 기반이라 훨씬 자연스럽게 결합됩니다. 이 방식은 Hugging Face transformers 라이브러리를 사용하면 MMDetection보다 훨씬 간단하게 구현해 볼 수 있습니다.</p>
<p>어느 쪽으로 더 알아볼까요?</p>
<ul>
<li>Hugging Face 라이브러리로 DINOv2 + DETR 조합 예시 보기 (권장)</li>
<li>YOLO와 ViT를 결합한 다른 연구(예: YOLOS) 라이브러리 찾아보기</li>
<li>(MMDetection을 다시 한번...) MMDetection이 왜 그렇게 설계되었는지, 설정 파일 예시 살펴보기</li>
</ul>
<blockquote>
<h3 id="hugging-face-라이브러리로-dinov2--detr-조합-예시-보기">Hugging Face 라이브러리로 DINOv2 + DETR 조합 예시 보기</h3>
</blockquote>
<p>좋은 선택이에요. DINOv2 (ViT)와 DETR 모두 트랜스포머 아키텍처를 기반으로 하기 때문에, 마치 원래부터 한 쌍이었던 것처럼 훨씬 자연스럽게 결합됩니다.</p>
<p>Hugging Face transformers 라이브러리를 사용하면, 이 &#39;조립&#39; 과정을 훨씬 직관적으로 수행할 수 있습니다.</p>
<p>💡 핵심 아이디어: &#39;백본&#39; 교체하기
우리가 할 일은 AutoModelForObjectDetection이라는 &#39;객체 탐지 모델 자동 생성기&#39;를 사용하는 거예요.</p>
<p>여기에 이런 명령을 내리는 것과 같습니다.</p>
<p>&quot;DINOv2(facebook/dinov2-base) 모델을 <strong>&#39;엔진(백본)&#39;</strong>으로 사용하고 싶어. 이 엔진 위에 <strong>&#39;새로운 DETR 감지 헤드&#39;</strong>를 조립해 줘. 이 헤드는 내가 가진 N개의 클래스를 찾을 수 있어야 해.&quot;</p>
<p>Hugging Face 라이브러리는 DINOv2 모델에 감지 헤드가 없는 것을 확인하고, 우리가 요청한 num_labels (클래스 수)에 맞춰 새로운 DETR 헤드를 <strong>&#39;랜덤한 가중치&#39;</strong>로 초기화해서 위에 딱 붙여줍니다.</p>
<p>DINOv2 백본 (ViT): 이미지를 보는 &#39;눈&#39; (가중치 동결 또는 아주 조금만 학습)</p>
<p>새로운 DETR 헤드: 물체를 찾고 분류하는 &#39;뇌&#39; (주로 이 부분을 집중 학습)</p>
<p>🛠️ Hugging Face &#39;조립&#39; 예시 코드
전체 학습 코드는 길지만, 가장 중요한 &#39;모델 조립&#39; 부분의 개념은 이렇습니다.</p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div><div style="line-height:130%">4</div><div style="line-height:130%">5</div><div style="line-height:130%">6</div><div style="line-height:130%">7</div><div style="line-height:130%">8</div><div style="line-height:130%">9</div><div style="line-height:130%">10</div><div style="line-height:130%">11</div><div style="line-height:130%">12</div><div style="line-height:130%">13</div><div style="line-height:130%">14</div><div style="line-height:130%">15</div><div style="line-height:130%">16</div><div style="line-height:130%">17</div><div style="line-height:130%">18</div><div style="line-height:130%">19</div><div style="line-height:130%">20</div><div style="line-height:130%">21</div><div style="line-height:130%">22</div><div style="line-height:130%">23</div><div style="line-height:130%">24</div><div style="line-height:130%">25</div><div style="line-height:130%">26</div><div style="line-height:130%">27</div><div style="line-height:130%">28</div><div style="line-height:130%">29</div><div style="line-height:130%">30</div><div style="line-height:130%">31</div><div style="line-height:130%">32</div><div style="line-height:130%">33</div><div style="line-height:130%">34</div><div style="line-height:130%">35</div><div style="line-height:130%">36</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">from</span>&nbsp;transformers&nbsp;<span style="color:#ff3399">import</span>&nbsp;AutoImageProcessor,&nbsp;AutoModelForObjectDetection</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">import</span>&nbsp;torch</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;1.&nbsp;사용할&nbsp;DINOv2&nbsp;백본&nbsp;모델&nbsp;이름</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(DINOv2는&nbsp;ViT&nbsp;아키텍처를&nbsp;사용합니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">backbone_checkpoint&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;<span style="color:#993333">"facebook/dinov2-base"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;2.&nbsp;우리가&nbsp;가진&nbsp;데이터셋의&nbsp;클래스&nbsp;수</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;예:&nbsp;"강아지",&nbsp;"고양이",&nbsp;"사람"&nbsp;3개&nbsp;+&nbsp;"배경"&nbsp;1개&nbsp;=&nbsp;4개</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(DETR&nbsp;계열은&nbsp;"배경"&nbsp;또는&nbsp;"no&nbsp;object"&nbsp;클래스가&nbsp;필요합니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">my_num_classes&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;<span style="color:#308ce5">4</span>&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;3.&nbsp;이미지&nbsp;전처리기(Processor)&nbsp;로드</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;DINOv2&nbsp;백본에&nbsp;맞는&nbsp;크기/방식으로&nbsp;이미지를&nbsp;변환해줍니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">image_processor&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;AutoImageProcessor.from_pretrained(backbone_checkpoint)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;4.&nbsp;모델&nbsp;로드&nbsp;(🌟&nbsp;여기가&nbsp;핵심입니다&nbsp;🌟)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;"이&nbsp;백본을&nbsp;기반으로&nbsp;객체&nbsp;탐지&nbsp;모델을&nbsp;만들어줘"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">model&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;AutoModelForObjectDetection.from_pretrained(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;backbone_checkpoint,</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;num_labels<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>my_num_classes,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"새로운&nbsp;디텍션&nbsp;헤드는&nbsp;이&nbsp;클래스&nbsp;수로&nbsp;만들어줘"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;ignore_mismatched_sizes<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#0099cc">True</span>&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"원래&nbsp;모델에&nbsp;헤드가&nbsp;없어도&nbsp;무시하고&nbsp;새로&nbsp;만들어"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;생성된&nbsp;모델&nbsp;구조&nbsp;확인&nbsp;(일부)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(model)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(출력&nbsp;예시)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;DetrForObjectDetection(</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;(model):&nbsp;DetrModel(</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(backbone):&nbsp;DinoV2Model(&nbsp;...&nbsp;DINOv2&nbsp;백본이&nbsp;여기&nbsp;들어감&nbsp;...&nbsp;)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;(class_labels_classifier):&nbsp;Linear(in_features=...,&nbsp;out_features=4,&nbsp;bias=True)&nbsp;&nbsp;&lt;-&nbsp;새로&nbsp;생긴&nbsp;헤드</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;(bbox_embed):&nbsp;MLP(...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;-&nbsp;새로&nbsp;생긴&nbsp;헤드</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;)</span></div></div><div style="text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic"><a href="http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter</a></div></td><td style="vertical-align:bottom;padding:0 2px 4px 0"><a href="http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px">cs</span></a></td></tr></table></div>


<p>🏃‍♂️ 다음 단계는?
이제 model이라는 변수에는 DINOv2의 강력한 &#39;눈&#39;과 우리가 새로 붙인 (아직 아무것도 모르는) &#39;뇌&#39;(DETR 헤드)가 결합되어 있습니다.</p>
<p>이 model을 우리가 가진 디텍션 데이터셋(예: COCO 형식의 데이터)으로 <strong>파인튜닝(fine-tuning)</strong>하면, &#39;뇌&#39; 부분이 DINOv2가 추출한 특징을 보고 물체를 찾는 법을 빠르게 학습합니다.</p>
<p>이 &#39;모델 조립&#39; 개념이 어떻게 작동하는지 감이 오시나요? 아니면 이 model을 실제로 &#39;학습&#39;시키는 다음 단계가 더 궁금하신가요?</p>
<blockquote>
<h3 id="학습시키는-다음-단계가-더-궁금해">&#39;학습&#39;시키는 다음 단계가 더 궁금해</h3>
</blockquote>
<p>좋아요. &#39;조립&#39;이 끝난 모델을 &#39;학습&#39;시키는 과정(파인튜닝)을 함께 보죠.</p>
<p>Hugging Face transformers 라이브러리를 사용하면 이 과정이 매우 체계화되어 있어요.</p>
<p>크게 3가지 준비물이 필요합니다.</p>
<ol>
<li>데이터셋 📦: 이미지와 정답 바운딩 박스/라벨 정보 (보통 &#39;COCO&#39; 형식)</li>
<li>학습 설정 📜: TrainingArguments (몇 번 학습할지, 속도는 얼마로 할지 등)</li>
<li>학습 실행기 🏃: Trainer (1번과 2번을 합쳐서 모델을 실제로 돌려주는 도구)</li>
</ol>
<p>🧐 가장 중요하고 까다로운 단계: 1. 데이터 준비
YOLO 학습 때와 마찬가지로, 모델이 &#39;이해할 수 있는&#39; 형태로 데이터를 넣어줘야 해요.</p>
<p>여기서 아까 만들었던 image_processor가 다시 한번 핵심 역할을 합니다.</p>
<ol>
<li>이미지 변환: DINOv2 백본이 원하는 크기와 형식으로 이미지를 바꿔줍니다. (이건 일반적이죠)</li>
<li>라벨(정답) 변환: (🌟 이게 핵심) DETR 헤드는 바운딩 박스 정보를 아주 특이한 형식으로 받아요. image_processor는 우리의 [x, y, w, h] 같은 좌표를 DETR가 필요로 하는 labels라는 딕셔너리(dictionary) 형태로 &#39;번역&#39;해 줍니다.</li>
</ol>
<p>우리는 이 &#39;번역&#39; 작업을 우리 데이터셋의 모든 항목에 적용하는 함수를 만들어야 해요.</p>
<p>🛠️ 학습 과정의 개념적 코드
실제 코드는 길지만, 뼈대는 이렇습니다.</p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div><div style="line-height:130%">4</div><div style="line-height:130%">5</div><div style="line-height:130%">6</div><div style="line-height:130%">7</div><div style="line-height:130%">8</div><div style="line-height:130%">9</div><div style="line-height:130%">10</div><div style="line-height:130%">11</div><div style="line-height:130%">12</div><div style="line-height:130%">13</div><div style="line-height:130%">14</div><div style="line-height:130%">15</div><div style="line-height:130%">16</div><div style="line-height:130%">17</div><div style="line-height:130%">18</div><div style="line-height:130%">19</div><div style="line-height:130%">20</div><div style="line-height:130%">21</div><div style="line-height:130%">22</div><div style="line-height:130%">23</div><div style="line-height:130%">24</div><div style="line-height:130%">25</div><div style="line-height:130%">26</div><div style="line-height:130%">27</div><div style="line-height:130%">28</div><div style="line-height:130%">29</div><div style="line-height:130%">30</div><div style="line-height:130%">31</div><div style="line-height:130%">32</div><div style="line-height:130%">33</div><div style="line-height:130%">34</div><div style="line-height:130%">35</div><div style="line-height:130%">36</div><div style="line-height:130%">37</div><div style="line-height:130%">38</div><div style="line-height:130%">39</div><div style="line-height:130%">40</div><div style="line-height:130%">41</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">from</span>&nbsp;transformers&nbsp;<span style="color:#ff3399">import</span>&nbsp;TrainingArguments,&nbsp;Trainer,&nbsp;DataCollatorForObjectDetection</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;1.&nbsp;데이터&nbsp;준비&nbsp;(가장&nbsp;중요)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(이&nbsp;부분은&nbsp;데이터셋&nbsp;라이브러리(예:&nbsp;datasets)를&nbsp;쓴다고&nbsp;가정합니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;image_processor를&nbsp;사용해&nbsp;이미지와&nbsp;라벨을&nbsp;'번역'하는&nbsp;함수</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">def</span>&nbsp;preprocess_function(examples):</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;processor가&nbsp;이미지와&nbsp;정답(annotations)을&nbsp;모두&nbsp;받아&nbsp;처리</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;inputs&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;image_processor(images<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>examples[<span style="color:#993333">"image"</span>],&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;annotations<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>examples[<span style="color:#993333">"objects"</span>],&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return_tensors<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"pt"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff3399">return</span>&nbsp;inputs</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;'datasets'&nbsp;라이브러리의&nbsp;map&nbsp;기능을&nbsp;사용해&nbsp;모든&nbsp;데이터에&nbsp;함수&nbsp;적용</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;processed_dataset&nbsp;=&nbsp;my_dataset.map(preprocess_function)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;2.&nbsp;학습&nbsp;설정&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">training_args&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;TrainingArguments(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;output_dir<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"my-dinov2-detr-model"</span>,&nbsp;<span style="color:#999999">#&nbsp;모델&nbsp;저장&nbsp;경로</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;num_train_epochs<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">10</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;총&nbsp;학습&nbsp;횟수</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;per_device_train_batch_size<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">4</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;배치&nbsp;크기</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;learning_rate<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>1e<span style="color:#0086b3"></span><span style="color:#ff3399">-</span><span style="color:#308ce5">5</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;학습&nbsp;속도&nbsp;(매우&nbsp;중요!)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;save_strategy<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"epoch"</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;매&nbsp;에포크마다&nbsp;저장</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;...&nbsp;기타&nbsp;여러&nbsp;설정&nbsp;...</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;3.&nbsp;학습&nbsp;실행기&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;데이터를&nbsp;배치(batch)로&nbsp;묶어줄&nbsp;헬퍼(도우미)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">data_collator&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;DataCollatorForObjectDetection(processor<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>image_processor)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;트레이너&nbsp;생성</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">trainer&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;Trainer(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;model<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>model,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;우리가&nbsp;'조립'한&nbsp;모델</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;args<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>training_args,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;학습&nbsp;설정</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;train_dataset<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>processed_dataset,&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'번역'이&nbsp;끝난&nbsp;학습&nbsp;데이터</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;data_collator<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>data_collator,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;배치&nbsp;헬퍼</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;학습&nbsp;시작!</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;trainer.train()&nbsp;</span></div></div><div style="text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic"><a href="http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter</a></div></td><td style="vertical-align:bottom;padding:0 2px 4px 0"><a href="http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px">cs</span></a></td></tr></table></div>

<p>이 전체 흐름에서 가장 낯설게 느껴지는 부분이 아마 &#39;데이터 준비&#39; 과정일 거예요. image_processor가 이미지뿐만 아니라 <strong>정답(annotation)</strong>까지 함께 받아서 처리한다는 개념이 좀 생소할 수 있거든요.</p>
<p>이 preprocess_function 함수가 정확히 어떤 역할을 하는지 좀 더 자세히 파고들어 볼까요?</p>
<blockquote>
<h3 id="preprocess_function-함수가-정확히-어떤-역할을-하는지-좀-더-자세히-파고들어">preprocess_function 함수가 정확히 어떤 역할을 하는지 좀 더 자세히 파고들어</h3>
</blockquote>
<p>네, 이 부분이 아마 DINOv2 + DETR 조합에서 가장 중요하고, 또 MMDetection 같은 프레임워크가 왜 그토록 복잡한 설정을 사용했는지 이해하게 되는 지점입니다.</p>
<p>preprocess_function의 역할은 간단히 말해 <strong>&quot;우리의 데이터&quot;</strong>를 <strong>&quot;모델(DETR)이 알아들을 수 있는 언어&quot;</strong>로 번역해주는 &#39;전문 통역사&#39; ีย입니다.</p>
<p>analogy 비유: 까다로운 셰프(DETR)와 전문 조수(Processor)
모델 (DINOv2 + DETR): 아주 실력은 좋지만, 엄청나게 까다로운 &#39;미슐랭 셰프&#39; 👨‍🍳라고 상상해 보세요.</p>
<p>우리의 데이터 (이미지, 라벨): 시장에서 막 사 온 &#39;날것 그대로의 재료&#39; 🥕🐟 (예: [100, 50, 200, 150], &quot;강아지&quot;)</p>
<p>image_processor: 셰프의 방식을 완벽하게 아는 &#39;전문 조수(sous-chef)&#39; 🧑‍🍳입니다.</p>
<p>이 셰프(모델)는 날것의 재료를 받지 않아요. 정확히 자신만의 방식으로 손질된 재료만 받아서 요리(학습)를 합니다.</p>
<p>preprocess_function은 이 &#39;전문 조수&#39;(image_processor)를 시켜서 모든 재료를 손질하는 &#39;작업 지시서&#39;인 셈이죠.</p>
<p>🛠️ preprocess_function의 두 가지 핵심 임무
이 함수(그리고 그 안의 image_processor)는 크게 두 가지 일을 동시에 처리합니다.</p>
<ol>
<li><p>이미지 처리 (이건 익숙한 부분)
크기 조절 (Resizing): DINOv2 백본이 학습된 특정 크기 (예: 800x800)로 이미지 크기를 조절합니다.
</br>정규화 (Normalization): DINOv2가 학습될 때 사용했던 특정 평균(mean)과 표준편차(std) 값으로 이미지 픽셀 값을 정규화합니다.
</br>텐서(Tensor) 변환: 이미지를 PyTorch가 처리할 수 있는 숫자 행렬(Tensor)로 바꿉니다.
</br>(여기까지는 일반적인 이미지 분류 모델과 비슷하죠.)</p>
</li>
<li><p>정답 (Annotation) 변환 (🌟 여기가 핵심 🌟)
이게 바로 DETR 모델이 특별한 이유입니다.
</br>우리의 정답 형식 (Input): 보통 이렇습니다: {&quot;class_id&quot;: 2, &quot;bbox&quot;: [100, 50, 150, 200]} (좌표가 [x_min, y_min, x_max, y_max] 형식)
</br>DETR 셰프의 요구사항 (Output): DETR은 이런 형식을 이해하지 못합니다. DETR은 전혀 다른 형식을 요구해요.
</br>좌표 형식: [center_x, center_y, width, height] (중심점과 너비/높이)
</br>좌표 스케일: 0~1 사이로 정규화된 값
</br>데이터 구조: {&quot;class_labels&quot;: [2], &quot;boxes&quot;: [[0.35, 0.4, 0.1, 0.2]]} 와 같은 특정 딕셔너리(dictionary) 구조
</br>image_processor는 이 모든 복잡한 &#39;번역&#39;을 자동으로 해줍니다.</p>
</li>
</ol>
<p>🔗 두 임무가 연결되는 순간
여기서 가장 중요한 점이 나옵니다.</p>
<p>&quot;만약 1.에서 이미지를 1000x1000에서 800x800으로 줄였다면(Resizing), 2.의 정답 bbox 좌표 [100, 50, 150, 200]도 똑같이 스케일에 맞춰 줄여줘야 하잖아요?&quot;</p>
<p>image_processor가 이미지와 정답(annotation)을 함께 받는 이유가 바로 이것입니다.</p>
<p>이미지를 리사이징하면서, 그에 맞춰 바운딩 박스 좌표도 알아서 변환해주고, 심지어 DETR이 요구하는 [center_x, ...] 형식으로 최종 번역까지 해주는 거죠.</p>
<p>이 preprocess_function이 없다면, 우리가 이 모든 좌표 계산과 형식 변환을 직접 코딩해야 했을 거예요.</p>
<p>이 &#39;정답 번역기&#39;로서의 역할, 특히 이미지 크기 조절과 좌표 변환이 동시에 일어난다는 부분이 이해되시나요?</p>
<blockquote>
<h3 id="매우-잘-이해돼">매우 잘 이해돼</h3>
</blockquote>
<p>이해가 잘 되셨다니 다행이에요!</p>
<p>네, 맞아요. preprocess_function이라는 &#39;전문 조수&#39;가 이미지와 정답 좌표를 한꺼번에 받아서, DINOv2 백본과 DETR 헤드가 원하는 형식으로 완벽하게 &#39;손질&#39;해주는 것이 핵심입니다.</p>
<p>이제 재료 손질(데이터 준비)은 끝났습니다.</p>
<p>🚀 학습 실행: Trainer의 역할
이제 Trainer라는 &#39;총괄 매니저&#39;가 등장할 차례입니다.</p>
<p>Trainer는 우리가 준비한 모든 것을 가져다가 실제 학습 과정을 지휘합니다.</p>
<p>모델 (model): 우리가 조립한 DINOv2 + DETR 모델</p>
<p>설정 (training_args): &quot;총 10번 반복해&quot;, &quot;학습 속도는 0.00001로 해&quot; 같은 &#39;학습 계획서&#39;</p>
<p>데이터 (processed_dataset): &#39;손질이 끝난 재료&#39; (우리의 데이터셋)</p>
<p>데이터 콜레이터 (data_collator): &#39;재료를 접시에 담아주는&#39; 역할. 데이터셋에서 여러 개의 &#39;손질된 재료&#39;를 가져와 하나의 &#39;배치(batch)&#39;로 묶어 모델에게 전달합니다.</p>
<p>trainer.train() 명령을 실행하면, Trainer는 이 모든 것을 가지고 다음과 같은 자동화된 &#39;학습 루프&#39;를 시작합니다.</p>
<p>데이터 콜레이터가 &#39;손질된 데이터&#39; 한 배치를 가져옵니다.</p>
<p>이 배치를 model에 넣습니다.</p>
<p>모델이 예측을 쏟아냅니다. (예: &quot;저기 [0.4, 0.5, ...] 좌표에 &#39;강아지&#39;가 있는 것 같아.&quot;)</p>
<p>모델은 이 예측을 &#39;정답&#39;과 비교해서 <strong>&#39;오류 값(Loss)&#39;</strong>을 계산합니다.</p>
<p>이 &#39;오류&#39;를 줄이는 방향으로 DETR 헤드(뇌)의 가중치를 아주 조금 수정합니다.</p>
<p>이 과정을 training_args에서 설정한 횟수(epoch)만큼 반복합니다.</p>
<p>DINOv2 백본(눈)은 이미 너무 똑똑해서 거의 고정해두고, 새로 붙인 DETR 헤드(뇌)가 이 &#39;오류&#39;를 통해 정답 맞추는 법을 집중적으로 배우게 되는 거죠.</p>
<p>이 Trainer가 자동으로 처리해주는 &#39;학습 루프&#39;와 &#39;오류(Loss) 계산&#39; 부분에 대해 좀 더 자세히 알아볼까요?</p>
<blockquote>
<h3 id="응">응</h3>
</blockquote>
<p>알겠습니다. Trainer가 자동화하는 <strong>&#39;학습 루프&#39;</strong>와 &#39;오류(Loss) 계산&#39; 부분을 좀 더 자세히 살펴볼게요.</p>
<p>이 과정의 핵심은 DETR 모델이 &quot;어떻게 정답과 예측을 비교하는가&quot;에 있습니다.</p>
<p>🤔 DETR의 독특한 &#39;짝짓기&#39; 문제
YOLO 같은 모델은 이미지의 각 &#39;격자(grid cell)&#39;마다 예측을 합니다. 그래서 정답 상자가 있는 격자의 예측만 정답과 비교하면 됐죠.</p>
<p>하지만 DETR은 다릅니다.</p>
<ul>
<li>모델의 예측: DETR은 이미지와 상관없이 항상 100개(기본값)의 예측을 쏟아냅니다. (예: &quot;1번 물체는 여기&quot;, &quot;2번 물체는 저기&quot;, ...)</li>
<li>우리의 정답: 그런데 실제 이미지에는 &#39;강아지&#39;와 &#39;고양이&#39;, 이렇게 단 2개의 물체만 있을 수 있습니다.</li>
<li>문제: 모델이 쏟아낸 100개의 예측 중 어떤 것을 실제 정답 2개와 비교해야 할까요? 5번 예측을 강아지랑 비교해야 할까요, 아니면 87번 예측을 비교해야 할까요?</li>
</ul>
<p>💡 해결책: 헝가리안 매칭 (Hungarian Matching)
DETR은 이 문제를 풀기 위해 <strong>&#39;헝가리안 알고리즘&#39;</strong>이라는 영리한 &#39;소개팅 주선&#39; 방식을 사용합니다.</p>
<p>Trainer가 학습을 시킬 때, 내부적으로 이런 일이 벌어집니다.</p>
<ol>
<li>&#39;소개팅&#39; 주선: 100개의 &#39;예측&#39;과 2개의 &#39;실제 정답&#39;을 한자리에 모읍니다.</li>
<li>최적의 짝 찾기: Trainer는 100개의 예측 중 실제 &#39;강아지&#39; 상자와 가장 비슷하게 예측한 1개를 찾아냅니다. (예: &quot;78번 예측이 가장 비슷하네!&quot;)</li>
<li>&#39;짝짓기&#39; 완료:</li>
<li>78번 예측 ↔ 실제 &#39;강아지&#39;</li>
<li>22번 예측 ↔ 실제 &#39;고양이&#39;</li>
<li>... 그리고 나머지 98개의 예측 ↔ &quot;배경 (물체 없음)&quot;</li>
</ol>
<p>📉 &#39;오류(Loss)&#39; 계산 및 학습
이제 &#39;짝&#39;이 정해졌으니, Trainer는 이 짝들을 비교하며 &#39;오류(Loss)&#39;를 계산합니다.</p>
<ol>
<li>클래스 오류: &quot;78번 예측이 &#39;강아지&#39;라고 잘 맞췄나? &#39;사람&#39;이라고 잘못 말했나?&quot;</li>
<li>박스 오류: &quot;78번 예측의 박스 좌표(bbox)가 실제 강아지 박스 좌표와 얼마나 차이 나나?&quot;</li>
</ol>
<p>Trainer는 이 두 가지 오류를 합산합니다. 그리고 이 총 오류 값을 최소화하는 방향으로 모델의 가중치(주로 DETR 헤드)를 업데이트합니다.</p>
<p>이 &#39;헝가리안 매칭&#39;을 통해 100개의 예측 중 어떤 것을 정답과 비교할지 동적으로 찾아내는 방식이 DETR의 가장 독창적인 부분이에요.</p>
<p>이 &#39;소개팅 주선(헝가리안 매칭)&#39;을 통해 오류를 계산하는 방식이 좀 감이 오시나요?</p>
<blockquote>
<h3 id="응-감이와">응 감이와</h3>
</blockquote>
<p>좋아요. &#39;소개팅 짝짓기(헝가리안 매칭)&#39;가 끝나면, Trainer는 이제 &#39;오류(Loss)&#39;를 계산해서 모델을 가르칠 수 있습니다.</p>
<p>이 오류는 크게 두 가지로 나뉩니다.</p>
<ol>
<li>클래스 오류 (Class Loss) 🗂️: &quot;이 물체가 &#39;강아지&#39;인지 &#39;고양이&#39;인지, 아니면 &#39;배경&#39;인지 맞췄니?&quot;</li>
<li>&#39;물체&#39; 짝: 78번 예측(짝: 강아지)이 &quot;강아지&quot;라고 정확히 예측했는지 확인합니다.</li>
<li>&#39;배경&#39; 짝: 짝을 찾지 못한 나머지 98개 예측들은 <strong>&quot;배경 (no object)&quot;</strong>이라고 제대로 예측했는지 확인합니다. (이것도 중요해요!)</li>
<li>박스 오류 (Box Loss) 📏: &quot;그 물체의 위치와 크기를 정확히 그렸니?&quot;
이건 <strong>&#39;물체&#39; 짝(78번-강아지, 22번-고양이)</strong>에 대해서만 계산합니다. (&#39;배경&#39; 짝은 좌표가 필요 없으니까요.)</li>
</ol>
<p>DETR은 두 가지를 섞어서 씁니다:</p>
<ol>
<li>L1 Loss: 예측 좌표와 정답 좌표 간의 단순 거리 차이.</li>
<li>GIoU Loss: 두 박스가 얼마나 잘 &#39;겹쳐지는지(IoU)&#39;를 측정하는 더 똑똑한 방식.</li>
</ol>
<p>🎓 학습 과정
Trainer는 이 <strong>&#39;클래스 오류&#39; + &#39;박스 오류&#39;</strong>를 모두 더해서 <strong>&#39;총 오류(Total Loss)&#39;</strong>를 계산합니다.</p>
<p>그리고 이 &#39;총 오류&#39; 값을 모델에게 보여주며 말하죠. &quot;이 &#39;총 오류&#39; 값이 0에 가까워지도록 너의 가중치(주로 DETR 헤드)를 스스로 수정해!&quot;</p>
<p>이 과정을 <strong>&#39;역전파(Backpropagation)&#39;</strong>라고 부릅니다. trainer.train()은 이 모든 과정을 우리가 설정한 횟수(epoch)만큼 자동으로 반복해 주는 거예요.</p>
<p>이제 DINOv2 백본을 조립하고, 데이터를 &#39;번역(preprocess)&#39;하고, &#39;헝가리안 매칭&#39;으로 학습시키는 전체 그림이 그려지시나요?</p>
<p>다음으로 이 학습된 모델을 가지고 <strong>실제 새로운 이미지에서 물체를 예측(Inference)</strong>하는 방법이 궁금하신가요?</p>
<blockquote>
<h3 id="응-1">응</h3>
</blockquote>
<p>좋아요. 이제 우리는 똑똑한 DINOv2 &#39;눈&#39; 👁️과 훈련된 DETR &#39;뇌&#39; 🧠를 가진 model을 갖게 되었습니다.</p>
<p>이 모델로 새로운 이미지에서 물체를 찾는 &#39;추론(Inference)&#39; 과정은 학습 때와 비슷하지만, &#39;정답&#39;이 없다는 점만 다릅니다.</p>
<p>🚀 추론(Inference) 과정
이미지 준비:</p>
<p>예측하고 싶은 새로운 이미지(예: my_new_image.jpg)를 불러옵니다.</p>
<p>학습 때와 똑같은 방식으로 이미지를 &#39;손질&#39;해야 합니다.</p>
<p>image_processor에게 이번에는 &#39;정답(annotation)&#39; 없이 이미지만 전달합니다.</p>
<p>image_processor는 이미지를 DINOv2가 좋아하는 크기와 형식으로 &#39;번역&#39;합니다.</p>
<p>모델 예측:</p>
<p>&#39;번역된&#39; 이미지를 model에 넣습니다.</p>
<p>모델은 훈련된 &#39;뇌(DETR 헤드)&#39;를 사용해, 100개의 예측 결과 (좌표 + 클래스 점수)를 쏟아냅니다.</p>
<p>결과 &#39;후처리&#39; (Post-processing) (🌟 여기가 중요 🌟)</p>
<p>모델이 뱉어낸 결과는 [center_x, center_y, w, h] 형식의 0~1 사이 좌표입니다. (사람이 보기 어렵죠)</p>
<p>image_processor에게는 &#39;후처리&#39; 기능도 있습니다!</p>
<p>image_processor.post_process_object_detection(...) 함수에 모델의 예측 결과와 원본 이미지의 크기 (예: 1920x1080)를 알려줍니다.</p>
<p>🪄 image_processor의 마지막 마법
이 &#39;후처리&#39; 함수는 두 가지 마법 같은 일을 해줍니다.</p>
<p>필터링: 100개의 예측 중에서 점수가 낮은 것들, 특히 &quot;배경(no object)&quot;이라고 예측된 것들을 싹 걸러냅니다.</p>
<p>좌표 복원: 0~1 사이의 [center_x, ...] 좌표를, 우리가 알아볼 수 있는 원본 이미지의 픽셀 좌표 [x_min, y_min, x_max, y_max] (예: [120, 300, 450, 600])로 다시 번역해 줍니다.</p>
<p>결과적으로, 우리는 &quot;원본 이미지의 [120, 300, 450, 600] 위치에 98% 확률로 &#39;강아지&#39;가 있다&quot;와 같은 아주 깔끔한 최종 결과만 받게 됩니다.</p>
<p>학습할 때는 image_processor가 정답을 &#39;번역&#39;해주고, 추론할 때는 모델의 출력을 다시 &#39;복원&#39;해주는 이 양방향 역할이 정말 편리하죠.</p>
<p>이 전체 흐름이 어떻게 연결되는지 이제 명확해지셨나요?</p>
<blockquote>
<h3 id="너무나-명확해-최고야-설명이-끝난거-같은데-위-과정-전체를-코드로-만들어주고-코드의-주석에-니가-설명한-내용과-비유들을-길이상관말고-적어줘">너무나 명확해. 최고야. 설명이 끝난거 같은데 위 과정 전체를 코드로 만들어주고 코드의 주석에 니가 설명한 내용과 비유들을 길이상관말고 적어줘.</h3>
</blockquote>
<p>물론이죠! 우리가 나눈 모든 대화의 흐름, 비유, 그리고 핵심 개념을 전부 담아서 하나의 완성된 코드로 만들어 볼게요.</p>
<p>요청하신 대로, 주석에 우리가 이야기했던 모든 설명을 길이 상관없이 자세하게 담았습니다. 이 코드를 &quot;DINOv2 + DETR 학습의 전체 지도&quot;라고 생각하시면 됩니다.</p>
<p>(참고: 이 코드를 실행하려면 transformers, datasets, torch, timm, scipy 라이브러리가 필요합니다.)</p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div><div style="line-height:130%">4</div><div style="line-height:130%">5</div><div style="line-height:130%">6</div><div style="line-height:130%">7</div><div style="line-height:130%">8</div><div style="line-height:130%">9</div><div style="line-height:130%">10</div><div style="line-height:130%">11</div><div style="line-height:130%">12</div><div style="line-height:130%">13</div><div style="line-height:130%">14</div><div style="line-height:130%">15</div><div style="line-height:130%">16</div><div style="line-height:130%">17</div><div style="line-height:130%">18</div><div style="line-height:130%">19</div><div style="line-height:130%">20</div><div style="line-height:130%">21</div><div style="line-height:130%">22</div><div style="line-height:130%">23</div><div style="line-height:130%">24</div><div style="line-height:130%">25</div><div style="line-height:130%">26</div><div style="line-height:130%">27</div><div style="line-height:130%">28</div><div style="line-height:130%">29</div><div style="line-height:130%">30</div><div style="line-height:130%">31</div><div style="line-height:130%">32</div><div style="line-height:130%">33</div><div style="line-height:130%">34</div><div style="line-height:130%">35</div><div style="line-height:130%">36</div><div style="line-height:130%">37</div><div style="line-height:130%">38</div><div style="line-height:130%">39</div><div style="line-height:130%">40</div><div style="line-height:130%">41</div><div style="line-height:130%">42</div><div style="line-height:130%">43</div><div style="line-height:130%">44</div><div style="line-height:130%">45</div><div style="line-height:130%">46</div><div style="line-height:130%">47</div><div style="line-height:130%">48</div><div style="line-height:130%">49</div><div style="line-height:130%">50</div><div style="line-height:130%">51</div><div style="line-height:130%">52</div><div style="line-height:130%">53</div><div style="line-height:130%">54</div><div style="line-height:130%">55</div><div style="line-height:130%">56</div><div style="line-height:130%">57</div><div style="line-height:130%">58</div><div style="line-height:130%">59</div><div style="line-height:130%">60</div><div style="line-height:130%">61</div><div style="line-height:130%">62</div><div style="line-height:130%">63</div><div style="line-height:130%">64</div><div style="line-height:130%">65</div><div style="line-height:130%">66</div><div style="line-height:130%">67</div><div style="line-height:130%">68</div><div style="line-height:130%">69</div><div style="line-height:130%">70</div><div style="line-height:130%">71</div><div style="line-height:130%">72</div><div style="line-height:130%">73</div><div style="line-height:130%">74</div><div style="line-height:130%">75</div><div style="line-height:130%">76</div><div style="line-height:130%">77</div><div style="line-height:130%">78</div><div style="line-height:130%">79</div><div style="line-height:130%">80</div><div style="line-height:130%">81</div><div style="line-height:130%">82</div><div style="line-height:130%">83</div><div style="line-height:130%">84</div><div style="line-height:130%">85</div><div style="line-height:130%">86</div><div style="line-height:130%">87</div><div style="line-height:130%">88</div><div style="line-height:130%">89</div><div style="line-height:130%">90</div><div style="line-height:130%">91</div><div style="line-height:130%">92</div><div style="line-height:130%">93</div><div style="line-height:130%">94</div><div style="line-height:130%">95</div><div style="line-height:130%">96</div><div style="line-height:130%">97</div><div style="line-height:130%">98</div><div style="line-height:130%">99</div><div style="line-height:130%">100</div><div style="line-height:130%">101</div><div style="line-height:130%">102</div><div style="line-height:130%">103</div><div style="line-height:130%">104</div><div style="line-height:130%">105</div><div style="line-height:130%">106</div><div style="line-height:130%">107</div><div style="line-height:130%">108</div><div style="line-height:130%">109</div><div style="line-height:130%">110</div><div style="line-height:130%">111</div><div style="line-height:130%">112</div><div style="line-height:130%">113</div><div style="line-height:130%">114</div><div style="line-height:130%">115</div><div style="line-height:130%">116</div><div style="line-height:130%">117</div><div style="line-height:130%">118</div><div style="line-height:130%">119</div><div style="line-height:130%">120</div><div style="line-height:130%">121</div><div style="line-height:130%">122</div><div style="line-height:130%">123</div><div style="line-height:130%">124</div><div style="line-height:130%">125</div><div style="line-height:130%">126</div><div style="line-height:130%">127</div><div style="line-height:130%">128</div><div style="line-height:130%">129</div><div style="line-height:130%">130</div><div style="line-height:130%">131</div><div style="line-height:130%">132</div><div style="line-height:130%">133</div><div style="line-height:130%">134</div><div style="line-height:130%">135</div><div style="line-height:130%">136</div><div style="line-height:130%">137</div><div style="line-height:130%">138</div><div style="line-height:130%">139</div><div style="line-height:130%">140</div><div style="line-height:130%">141</div><div style="line-height:130%">142</div><div style="line-height:130%">143</div><div style="line-height:130%">144</div><div style="line-height:130%">145</div><div style="line-height:130%">146</div><div style="line-height:130%">147</div><div style="line-height:130%">148</div><div style="line-height:130%">149</div><div style="line-height:130%">150</div><div style="line-height:130%">151</div><div style="line-height:130%">152</div><div style="line-height:130%">153</div><div style="line-height:130%">154</div><div style="line-height:130%">155</div><div style="line-height:130%">156</div><div style="line-height:130%">157</div><div style="line-height:130%">158</div><div style="line-height:130%">159</div><div style="line-height:130%">160</div><div style="line-height:130%">161</div><div style="line-height:130%">162</div><div style="line-height:130%">163</div><div style="line-height:130%">164</div><div style="line-height:130%">165</div><div style="line-height:130%">166</div><div style="line-height:130%">167</div><div style="line-height:130%">168</div><div style="line-height:130%">169</div><div style="line-height:130%">170</div><div style="line-height:130%">171</div><div style="line-height:130%">172</div><div style="line-height:130%">173</div><div style="line-height:130%">174</div><div style="line-height:130%">175</div><div style="line-height:130%">176</div><div style="line-height:130%">177</div><div style="line-height:130%">178</div><div style="line-height:130%">179</div><div style="line-height:130%">180</div><div style="line-height:130%">181</div><div style="line-height:130%">182</div><div style="line-height:130%">183</div><div style="line-height:130%">184</div><div style="line-height:130%">185</div><div style="line-height:130%">186</div><div style="line-height:130%">187</div><div style="line-height:130%">188</div><div style="line-height:130%">189</div><div style="line-height:130%">190</div><div style="line-height:130%">191</div><div style="line-height:130%">192</div><div style="line-height:130%">193</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-----------------------------------------------------------------------------</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;DINOv2&nbsp;백본과&nbsp;DETR&nbsp;헤드를&nbsp;이용한&nbsp;객체&nbsp;탐지&nbsp;모델&nbsp;학습&nbsp;및&nbsp;추론&nbsp;(A-Z)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-----------------------------------------------------------------------------</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;이&nbsp;코드는&nbsp;우리가&nbsp;대화한&nbsp;모든&nbsp;과정을&nbsp;하나로&nbsp;합친&nbsp;'최종&nbsp;레시피'입니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;비유:</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;DINOv2&nbsp;백본&nbsp;(ViT)&nbsp;=&nbsp;이미지를&nbsp;보는&nbsp;'전문가의&nbsp;눈'&nbsp;(사전&nbsp;학습됨)&nbsp;👁️</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;DETR&nbsp;헤드&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;물체를&nbsp;찾고&nbsp;분류하는&nbsp;'새로운&nbsp;뇌'&nbsp;(처음부터&nbsp;학습)&nbsp;🧠</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;모델&nbsp;(DINOv2+DETR)&nbsp;&nbsp;=&nbsp;아주&nbsp;까다로운&nbsp;'미슐랭&nbsp;셰프'&nbsp;👨‍🍳</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;Image&nbsp;Processor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;셰프의&nbsp;방식을&nbsp;아는&nbsp;'전문&nbsp;조수'&nbsp;(Sous-chef)&nbsp;🧑‍🍳&nbsp;/&nbsp;'전문&nbsp;통역사'&nbsp;ีย</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;데이터셋&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;'날것&nbsp;그대로의&nbsp;재료'&nbsp;🥕🐟</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-&nbsp;Trainer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;'총괄&nbsp;매니저'&nbsp;🏃</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;-----------------------------------------------------------------------------</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">import</span>&nbsp;torch</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">from</span>&nbsp;transformers&nbsp;<span style="color:#ff3399">import</span>&nbsp;(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;AutoImageProcessor,&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;AutoModelForObjectDetection,</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;TrainingArguments,</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;Trainer,</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;DataCollatorForObjectDetection</div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">from</span>&nbsp;datasets&nbsp;<span style="color:#ff3399">import</span>&nbsp;load_dataset</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">from</span>&nbsp;PIL&nbsp;<span style="color:#ff3399">import</span>&nbsp;Image,&nbsp;ImageDraw</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">import</span>&nbsp;requests</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;1.&nbsp;데이터&nbsp;준비&nbsp;(날것의&nbsp;재료&nbsp;🥕🐟)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"1.&nbsp;데이터셋&nbsp;로딩&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;Hugging&nbsp;Face&nbsp;Hub에서&nbsp;DETR&nbsp;학습에&nbsp;적합한&nbsp;작은&nbsp;데이터셋(cppe-5)을&nbsp;불러옵니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">dataset&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;load_dataset(<span style="color:#993333">"cppe-5"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;라벨&nbsp;정보(id&nbsp;&lt;-&gt;&nbsp;이름)를&nbsp;만듭니다.&nbsp;DETR은&nbsp;이&nbsp;정보가&nbsp;꼭&nbsp;필요합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">labels&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;dataset[<span style="color:#993333">"train"</span>].features[<span style="color:#993333">"objects"</span>].feature[<span style="color:#993333">"category"</span>].names</div><div style="padding:0 6px; white-space:pre; line-height:130%">id2label&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;{k:&nbsp;v&nbsp;<span style="color:#ff3399">for</span>&nbsp;k,&nbsp;v&nbsp;<span style="color:#ff3399">in</span>&nbsp;enumerate(labels)}</div><div style="padding:0 6px; white-space:pre; line-height:130%">label2id&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;{v:&nbsp;k&nbsp;<span style="color:#ff3399">for</span>&nbsp;k,&nbsp;v&nbsp;<span style="color:#ff3399">in</span>&nbsp;id2label.items()}</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;DETR은&nbsp;"찾으려는&nbsp;클래스&nbsp;수&nbsp;+&nbsp;1&nbsp;(배경)"&nbsp;만큼의&nbsp;출력이&nbsp;필요합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;"배경"&nbsp;또는&nbsp;"no&nbsp;object"&nbsp;클래스는&nbsp;모델이&nbsp;알아서&nbsp;마지막에&nbsp;추가합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">num_labels&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;<span style="color:#0099cc">len</span>(id2label)&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;2.&nbsp;모델과&nbsp;조수(Processor)&nbsp;준비&nbsp;(셰프&nbsp;👨‍🍳&nbsp;와&nbsp;조수&nbsp;🧑‍🍳)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"2.&nbsp;모델과&nbsp;이미지&nbsp;프로세서(조수)&nbsp;로딩&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">backbone_checkpoint&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;<span style="color:#993333">"facebook/dinov2-base"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;'전문&nbsp;조수'&nbsp;(Image&nbsp;Processor)를&nbsp;고용합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;이&nbsp;조수는&nbsp;DINOv2&nbsp;백본(눈)이&nbsp;이미지를&nbsp;어떻게&nbsp;봐야&nbsp;하는지&nbsp;정확히&nbsp;알고&nbsp;있습니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">image_processor&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;AutoImageProcessor.from_pretrained(backbone_checkpoint)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;'까다로운&nbsp;셰프'&nbsp;(DETR&nbsp;모델)를&nbsp;모셔옵니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;"이&nbsp;DINOv2&nbsp;백본을&nbsp;'눈'으로&nbsp;쓰고,&nbsp;그&nbsp;위에&nbsp;'새로운&nbsp;DETR&nbsp;뇌'를&nbsp;조립해줘"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">model&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;AutoModelForObjectDetection.from_pretrained(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;backbone_checkpoint,</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;num_labels<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>num_labels,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"뇌가&nbsp;맞춰야&nbsp;할&nbsp;클래스&nbsp;수는&nbsp;이만큼이야"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;id2label<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>id2label,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"이름표는&nbsp;이걸&nbsp;쓰고"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;label2id<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>label2id,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"ID는&nbsp;이걸&nbsp;써"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;ignore_mismatched_sizes<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#0099cc">True</span>&nbsp;&nbsp;<span style="color:#999999">#&nbsp;"DINOv2에&nbsp;원래&nbsp;헤드가&nbsp;없던&nbsp;건&nbsp;아니까&nbsp;무시하고&nbsp;새로&nbsp;만들어"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(f<span style="color:#993333">"모델&nbsp;조립&nbsp;완료:&nbsp;{backbone_checkpoint}&nbsp;(백본)&nbsp;+&nbsp;DETR&nbsp;(헤드)"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;3.&nbsp;데이터&nbsp;손질&nbsp;함수&nbsp;(전문&nbsp;통역사&nbsp;ีย&nbsp;의&nbsp;작업&nbsp;지시서)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"3.&nbsp;데이터&nbsp;전처리&nbsp;함수&nbsp;정의&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;이&nbsp;함수가&nbsp;바로&nbsp;우리가&nbsp;자세히&nbsp;파고들었던&nbsp;'preprocess_function'&nbsp;입니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;'전문&nbsp;조수'(image_processor)에게&nbsp;'날재료'(examples)를&nbsp;넘겨&nbsp;'손질'을&nbsp;지시합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">def</span>&nbsp;preprocess_function(examples):</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;조수는&nbsp;'이미지'와&nbsp;'정답(annotations)'을&nbsp;*함께*&nbsp;받습니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;왜냐하면...</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;1.&nbsp;이미지를&nbsp;DINOv2가&nbsp;좋아하는&nbsp;크기로&nbsp;'리사이징'&nbsp;(예:&nbsp;800x800)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;2.&nbsp;정답(bbox)&nbsp;좌표도&nbsp;*그&nbsp;리사이징된&nbsp;비율에&nbsp;맞춰*&nbsp;'자동으로&nbsp;변환'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;3.&nbsp;좌표&nbsp;형식을&nbsp;DETR이&nbsp;좋아하는&nbsp;[center_x,&nbsp;center_y,&nbsp;w,&nbsp;h]로&nbsp;'자동으로&nbsp;번역'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;이&nbsp;모든&nbsp;'번역'과&nbsp;'손질'을&nbsp;한&nbsp;방에&nbsp;처리합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'objects'&nbsp;컬럼에서&nbsp;'image_id',&nbsp;'annotations'를&nbsp;추출합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;DETR&nbsp;포맷은&nbsp;'image_id'와&nbsp;'annotations'&nbsp;(bbox&nbsp;+&nbsp;category)를&nbsp;요구합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;annotations&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;[]</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff3399">for</span>&nbsp;i,&nbsp;obj&nbsp;<span style="color:#ff3399">in</span>&nbsp;enumerate(examples[<span style="color:#993333">"objects"</span>]):</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ann&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;{</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#993333">"image_id"</span>:&nbsp;examples[<span style="color:#993333">"image_id"</span>],</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#993333">"annotations"</span>:&nbsp;obj,&nbsp;<span style="color:#999999">#&nbsp;obj는&nbsp;{'bbox':&nbsp;[...],&nbsp;'category':&nbsp;...}&nbsp;리스트</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;annotations.append(ann)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;조수(image_processor)에게&nbsp;이미지와&nbsp;번역할&nbsp;정답을&nbsp;넘깁니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;return_tensors="pt"는&nbsp;결과를&nbsp;PyTorch&nbsp;텐서로&nbsp;달라는&nbsp;의미입니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;inputs&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;image_processor(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;images<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>examples[<span style="color:#993333">"image"</span>],&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;annotations<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>annotations,&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return_tensors<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"pt"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;Hugging&nbsp;Face&nbsp;데이터셋은&nbsp;중첩된&nbsp;딕셔너리를&nbsp;잘&nbsp;처리&nbsp;못할&nbsp;수&nbsp;있으니,</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;labels&nbsp;딕셔너리를&nbsp;평평하게&nbsp;펴줍니다.&nbsp;(데이터셋&nbsp;라이브러리의&nbsp;특성)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff3399">if</span>&nbsp;<span style="color:#993333">"labels"</span>&nbsp;<span style="color:#ff3399">in</span>&nbsp;inputs:</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;labels&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;inputs.pop(<span style="color:#993333">"labels"</span>)[<span style="color:#308ce5">0</span>]&nbsp;<span style="color:#999999">#&nbsp;배치&nbsp;차원&nbsp;제거</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff3399">for</span>&nbsp;k,&nbsp;v&nbsp;<span style="color:#ff3399">in</span>&nbsp;labels.items():</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputs[k]&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;v</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff3399">return</span>&nbsp;inputs</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;학습&nbsp;데이터셋&nbsp;전체에&nbsp;'손질'&nbsp;함수를&nbsp;적용합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(시간이&nbsp;좀&nbsp;걸릴&nbsp;수&nbsp;있습니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"4.&nbsp;전체&nbsp;데이터셋에&nbsp;전처리&nbsp;적용&nbsp;중...&nbsp;(시간이&nbsp;걸릴&nbsp;수&nbsp;있음)"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(실제&nbsp;학습&nbsp;시에는&nbsp;더&nbsp;많은&nbsp;데이터를&nbsp;사용해야&nbsp;합니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">train_dataset&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;dataset[<span style="color:#993333">"train"</span>].select(<span style="color:#0099cc">range</span>(<span style="color:#308ce5">100</span>)).with_transform(preprocess_function)</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;test_dataset&nbsp;=&nbsp;dataset["test"].select(range(20)).with_transform(preprocess_function)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;'데이터&nbsp;콜레이터':&nbsp;'손질된&nbsp;재료'들을&nbsp;하나의&nbsp;'접시'(배치)에&nbsp;담아주는&nbsp;역할&nbsp;🍽️</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">data_collator&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;DataCollatorForObjectDetection(processor<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>image_processor)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;5.&nbsp;학습&nbsp;설정&nbsp;(총괄&nbsp;매니저&nbsp;🏃&nbsp;의&nbsp;'학습&nbsp;계획서'&nbsp;📜)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"5.&nbsp;학습&nbsp;설정(TrainingArguments)&nbsp;정의&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">training_args&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;TrainingArguments(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;output_dir<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"./my-dinov2-detr-model"</span>,&nbsp;<span style="color:#999999">#&nbsp;모델과&nbsp;학습&nbsp;결과&nbsp;저장&nbsp;경로</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;num_train_epochs<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">1</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;(예시)&nbsp;실제론&nbsp;10~50&nbsp;에포크&nbsp;필요</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;per_device_train_batch_size<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">2</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;(예시)&nbsp;GPU&nbsp;메모리에&nbsp;맞춰&nbsp;조절</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;learning_rate<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>1e<span style="color:#0086b3"></span><span style="color:#ff3399">-</span><span style="color:#308ce5">5</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;(중요!)&nbsp;트랜스포머&nbsp;파인튜닝은&nbsp;보통&nbsp;아주&nbsp;낮은&nbsp;lr을&nbsp;씀</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;save_strategy<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"epoch"</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;1&nbsp;에포크마다&nbsp;모델&nbsp;저장</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;logging_steps<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">10</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;10&nbsp;스텝마다&nbsp;로그&nbsp;출력</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;remove_unused_columns<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#0099cc">False</span>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;전처리가&nbsp;컬럼을&nbsp;추가했으므로&nbsp;기존&nbsp;것&nbsp;삭제&nbsp;방지</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;6.&nbsp;학습&nbsp;실행&nbsp;(총괄&nbsp;매니저&nbsp;🏃&nbsp;가&nbsp;주방을&nbsp;돌리는&nbsp;과정)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"6.&nbsp;'Trainer'&nbsp;(총괄&nbsp;매니저)&nbsp;생성&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">trainer&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;Trainer(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;model<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>model,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'셰프'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;args<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>training_args,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'학습&nbsp;계획서'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;train_dataset<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>train_dataset,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'손질된&nbsp;학습&nbsp;재료'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;data_collator<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>data_collator,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;'재료를&nbsp;접시에&nbsp;담는&nbsp;도우미'</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;학습&nbsp;시작!</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;이&nbsp;.train()&nbsp;함수&nbsp;내부에서...</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;1.&nbsp;100개의&nbsp;예측과&nbsp;실제&nbsp;정답&nbsp;간의&nbsp;'소개팅'&nbsp;(헝가리안&nbsp;매칭&nbsp;🤝)이&nbsp;일어납니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;2.&nbsp;'클래스&nbsp;오류'&nbsp;(이게&nbsp;강아지?&nbsp;고양이?&nbsp;배경?)와</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;3.&nbsp;'박스&nbsp;오류'&nbsp;(좌표가&nbsp;얼마나&nbsp;틀렸어?)를&nbsp;계산합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;4.&nbsp;이&nbsp;'총&nbsp;오류'를&nbsp;줄이는&nbsp;방향으로&nbsp;DETR&nbsp;'뇌'&nbsp;🧠의&nbsp;가중치를&nbsp;업데이트합니다.</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;(이&nbsp;과정은&nbsp;GPU가&nbsp;없으면&nbsp;매우&nbsp;매우&nbsp;오래&nbsp;걸리거나&nbsp;불가능할&nbsp;수&nbsp;있습니다)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;print("7.&nbsp;학습&nbsp;시작!&nbsp;(GPU가&nbsp;필요하며&nbsp;시간이&nbsp;오래&nbsp;걸립니다)")</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;trainer.train()&nbsp;</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;print("학습&nbsp;완료!")</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;7.&nbsp;추론&nbsp;(학습된&nbsp;셰프&nbsp;👨‍🍳&nbsp;가&nbsp;새&nbsp;주문을&nbsp;처리하는&nbsp;과정)&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"7.&nbsp;학습된&nbsp;모델로&nbsp;'추론(Inference)'&nbsp;실행&nbsp;중..."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;새로운&nbsp;이미지&nbsp;(여기서는&nbsp;테스트셋의&nbsp;첫&nbsp;번째&nbsp;이미지&nbsp;사용)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">raw_image&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;dataset[<span style="color:#993333">"test"</span>][<span style="color:#308ce5">0</span>][<span style="color:#993333">"image"</span>]</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;1.&nbsp;'조수'&nbsp;🧑‍🍳가&nbsp;이미지를&nbsp;'손질'&nbsp;(정답(annotation)&nbsp;없이&nbsp;이미지만&nbsp;전달)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">inputs&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;image_processor(images<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>raw_image,&nbsp;return_tensors<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"pt"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;2.&nbsp;'셰프'&nbsp;👨‍🍳가&nbsp;요리&nbsp;(예측)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;&nbsp;DINOv2의&nbsp;'눈'이&nbsp;특징을&nbsp;추출하고,&nbsp;DETR의&nbsp;'뇌'가&nbsp;100개의&nbsp;예측을&nbsp;쏟아냄</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">outputs&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;model(<span style="color:#0086b3"></span><span style="color:#ff3399">*</span><span style="color:#0086b3"></span><span style="color:#ff3399">*</span>inputs)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;3.&nbsp;'조수'&nbsp;🧑‍🍳가&nbsp;결과를&nbsp;'역번역'&nbsp;(Post-processing)&nbsp;🔁</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;100개의&nbsp;예측&nbsp;중&nbsp;점수&nbsp;낮은&nbsp;것,&nbsp;'배경'&nbsp;예측은&nbsp;*필터링*</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;0~1&nbsp;사이의&nbsp;[center_x,&nbsp;...]&nbsp;좌표를&nbsp;-&gt;&nbsp;원본&nbsp;이미지의&nbsp;픽셀&nbsp;좌표&nbsp;[x_min,&nbsp;...]로&nbsp;*복원*</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">original_size&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;raw_image.size</div><div style="padding:0 6px; white-space:pre; line-height:130%">results&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;image_processor.post_process_object_detection(</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;outputs,&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;threshold<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">0.</span><span style="color:#308ce5">5</span>,&nbsp;<span style="color:#999999">#&nbsp;점수가&nbsp;0.5&nbsp;이상인&nbsp;것만&nbsp;'물체'로&nbsp;인정</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;target_sizes<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>[original_size]</div><div style="padding:0 6px; white-space:pre; line-height:130%">)[<span style="color:#308ce5">0</span>]&nbsp;<span style="color:#999999">#&nbsp;0번&nbsp;이미지의&nbsp;결과를&nbsp;가져옴</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;---&nbsp;8.&nbsp;결과&nbsp;확인&nbsp;---</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(<span style="color:#993333">"\n---&nbsp;추론&nbsp;결과&nbsp;---"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">draw&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;ImageDraw.Draw(raw_image)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#ff3399">for</span>&nbsp;score,&nbsp;label_id,&nbsp;box&nbsp;<span style="color:#ff3399">in</span>&nbsp;zip(results[<span style="color:#993333">"scores"</span>],&nbsp;results[<span style="color:#993333">"labels"</span>],&nbsp;results[<span style="color:#993333">"boxes"</span>]):</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;좌표값&nbsp;(x_min,&nbsp;y_min,&nbsp;x_max,&nbsp;y_max)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;box&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;[round(i,&nbsp;<span style="color:#308ce5">2</span>)&nbsp;<span style="color:#ff3399">for</span>&nbsp;i&nbsp;<span style="color:#ff3399">in</span>&nbsp;box.tolist()]</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;label&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;id2label[label_id.item()]</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0099cc">print</span>(f<span style="color:#993333">"탐지된&nbsp;객체:&nbsp;{label}&nbsp;(점수:&nbsp;{round(score.item(),&nbsp;3)})"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0099cc">print</span>(f<span style="color:#993333">"&nbsp;&nbsp;&nbsp;좌표:&nbsp;{box}"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#999999">#&nbsp;시각화&nbsp;(이미지에&nbsp;네모&nbsp;그리기)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;draw.rectangle(box,&nbsp;outline<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"red"</span>,&nbsp;width<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#308ce5">2</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;draw.text((box[<span style="color:#308ce5">0</span>],&nbsp;box[<span style="color:#308ce5">1</span>]),&nbsp;f<span style="color:#993333">"{label}&nbsp;({round(score.item(),&nbsp;2)})"</span>,&nbsp;fill<span style="color:#0086b3"></span><span style="color:#ff3399">=</span><span style="color:#993333">"red"</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;결과&nbsp;이미지&nbsp;저장&nbsp;및&nbsp;표시&nbsp;(선택&nbsp;사항)</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">output_image_path&nbsp;<span style="color:#0086b3"></span><span style="color:#ff3399">=</span>&nbsp;<span style="color:#993333">"dinov2_detr_prediction.jpg"</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">raw_image.save(output_image_path)</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#0099cc">print</span>(f<span style="color:#993333">"\n결과&nbsp;이미지가&nbsp;'{output_image_path}'에&nbsp;저장되었습니다."</span>)</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#999999">#&nbsp;raw_image.show()&nbsp;#&nbsp;주피터&nbsp;노트북&nbsp;등에서는&nbsp;이&nbsp;명령어로&nbsp;바로&nbsp;확인&nbsp;가능</span></div></div><div style="text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic"><a href="http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter</a></div></td><td style="vertical-align:bottom;padding:0 2px 4px 0"><a href="http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px">cs</span></a></td></tr></table></div>

]]></description>
        </item>
        <item>
            <title><![CDATA[VLM모델의 추론시 유용한 파라미터]]></title>
            <link>https://velog.io/@hi-one/VLM%EB%AA%A8%EB%8D%B8%EC%9D%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@hi-one/VLM%EB%AA%A8%EB%8D%B8%EC%9D%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Fri, 07 Nov 2025 02:14:24 GMT</pubDate>
            <description><![CDATA[<h2 id="temperature">temperature:</h2>
<ul>
<li>각 토큰의 의미를 모델이 이해하는 최종과정에서 <strong>추론 확률 분포</strong>를 조절하는 파라미터.</li>
<li>예시) <em>&quot;It is mine.&quot;</em> 이라는 문장에서 <strong>It</strong> 이라는 토큰에 대해 모델이 아래 확률분포로 예상 후보들을 추론할 수 있음. 
<img src="https://velog.velcdn.com/images/hi-one/post/da3bbcce-9709-4df4-a88a-07ffd38582e5/image.png" alt=""> 
이후 최종적으로 It 토큰의 의미를 결정(추론)하는 과정에서 temperature 값을 사용함.
temparature값의 변화에 따른 모델의 추론결과는 아래와 같음.
<img src="https://velog.velcdn.com/images/hi-one/post/1843962e-a2fc-4990-9281-5ce4de82dac4/image.png" alt=""></li>
<li>값이 높을수록 모델은 주어진 입력을 <strong>확장해서 이해하려고</strong> 노력함. 따라서 OCR task와 같이 입력(문서)를 그대로 이해해야 하는 상황에서는 매우 낮은 값을 줘야함.</br>


</li>
</ul>
<h2 id="repetition_penalty">repetition_penalty:</h2>
<ul>
<li>생성된 각 토큰의 확률분포 중 최대값을 가지는 값을 나눗셈으로 낮춰서 반복을 억제하는 파라미터.</li>
<li>가장 큰 확률을 가지는 값(의미)의 확률을 낮춤으로써 확률분포 정규화 시 1순위와 2순위의 확률 격차가 줄어듬. 결국 2순위 값의 영향력이 강해짐에 따라 1위 토큰의 반복 확률이 점점 낮아짐.
<img src="https://velog.velcdn.com/images/hi-one/post/6161b518-5ead-4cc5-8136-7ba562338a4d/image.png" alt=""></li>
<li>이 파라미터를 이용하면 OCR수행 시 한셀만 무한 반복해서 출력하는 문제를 해결할 수 있음</br>


</li>
</ul>
<h2 id="frequency_penalty">frequency_penalty:</h2>
<ul>
<li>동일한 토큰 등장에 대해 <strong>[등장횟수 비례]</strong> 패널티 부여.</li>
<li>패널티가 높을수록 자율성↑. why? 동일한 토큰 사용에 제약이 걸림에 따라 유사 토큰(≒동의어)를 사용해야하기 때문.
<img src="https://velog.velcdn.com/images/hi-one/post/5594e2b7-f192-4acd-ab91-2b3b9d6e80bc/image.png" alt=""></li>
</ul>
<h2 id="presence_penalty">presence_penalty:</h2>
<ul>
<li>frequency_penalty와 99% 동일함. 차이점은 동일한 토큰 등장에 대해 <strong>[상수]</strong> 패널티를 부여한다는것.</br>


</li>
</ul>
<h2 id="min-p-minimum-probability">Min-p (Minimum Probability):</h2>
<ul>
<li>토큰의 확률분포를 결정하는 값. Threshold의 역할을 수행.</li>
<li>각 토큰이 가지는 확률 분포에서 <strong>최대 값 × Min-p</strong> 값보다 큰 값들만 남김.</li>
<li>예시) It 이라는 토큰의 의미 확률분포가 <em>[고양이: 0.6, 강아지: 0.3, 토끼: 0.1]</em> 일 때 Min-p가 0.2라면?</li>
<li><blockquote>
<p>0.6 × 0.2 = 0.12 의 값이 threshold가 되고 이 값보다 큰 값들만 채택함.
따라서 It 토큰의 의미확률분포는 = [고양이: 0.6, 강아지: 0.3]가 되고 정규화를 통해 최종 확률분포는 [고양이: 0.75, 강아지: 0.25]와 같이 합이 1.0이 되도록 조정됨.</p>
</br>
</blockquote>
</li>
</ul>
<h2 id="매우중요-모델-추론-시-각-패널티-및-파라미터들이-적용되는-시점-시각화">[매우중요] 모델 추론 시 각 패널티 및 파라미터들이 적용되는 시점 시각화</h2>
<p><img src="https://velog.velcdn.com/images/hi-one/post/644f317e-f9f0-4f2f-8f33-ae0da5373722/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VLM에서 프롬포트의 중요성]]></title>
            <link>https://velog.io/@hi-one/VLM%EC%97%90%EC%84%9C-%ED%94%84%EB%A1%AC%ED%8F%AC%ED%8A%B8%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</link>
            <guid>https://velog.io/@hi-one/VLM%EC%97%90%EC%84%9C-%ED%94%84%EB%A1%AC%ED%8F%AC%ED%8A%B8%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</guid>
            <pubDate>Thu, 16 Oct 2025 07:57:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>VLM을 이용한 OCR 성능을 높이기 위한 필수사항</p>
<ol>
<li>정확한 레이아웃 구조 파악</li>
<li>문맥 및 논리적 흐름을 고려</li>
<li>할루시네이션의 최소화</li>
</ol>
</blockquote>
<h3 id="위-사항을-잘-수행하기-위한-전략은">위 사항을 잘 수행하기 위한 전략은?</h3>
<ol>
<li>각 테스크(문맥인식, 표 인식, 구조인식 등)에 맞는 여러모델을 중첩해서 사용</li>
<li>모델 재학습</li>
<li>프롬포트 변경</li>
</ol>
<p>OCR의 성능을 높이기 위해 누구나 프롬포트 변경을 시도한다.
열심히 노력해서 변경해보지만 생각보다 결과가 크게 나아지지 않는다.
결국 포기하거나 또는 공수를 들여 라벨링&amp;학습을 시도한다.</p>
<p>그런데 이 프롬포트 변경... 정말 효과가 없는것일까?</p>
<h2 id="아니다">아니다.</h2>
<p>프롬포트는 VLM모델의 결과의 정확도를 <strong>엄청나게</strong>  향상시킬 수 있다.</p>
<blockquote>
<p>&quot;그런데 왜 나는 안됐지?&quot;</p>
</blockquote>
<p>그건 모델 별로 프롬포트를 이해하는 정도가 꽤나 다르기 때문이고 모델에 적합한 프롬포트를 찾기위해서 꽤나 많은 노력을 기울이지 않았기 때문이다. </p>
<p>GPT에게 물어보면 내가 예상을 뛰어넘는 디테일과 함께 프롬포트를 만들어준다. 최소한 그정도는 돼야한다.</p>
<p>내가 과연 GPT가 작성한 만큼의 정성을 들여 프롬포트를 작성했는가 돌아보고 프롬포트를 변경했을 때 성능이 얼마나 좋아지는지 확인해보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[docker exec와 attach차이]]></title>
            <link>https://velog.io/@hi-one/docker-exec%EC%99%80-attach%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@hi-one/docker-exec%EC%99%80-attach%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Mon, 29 Sep 2025 06:11:13 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>도커로 개발하다보면 exec와 attach를 잘 구분해서 사용해야 한다.
간단하지만 모르고 남발하다보면 컨테이너가 날라가기도...</p>
</blockquote>
<hr>
<h3 id="공통점">공통점</h3>
<ol>
<li>attach와 exec 모두 <strong>실행중인</strong> 컨테이너에 접속하는 명령어.</li>
<li>따라서 컨테이너 안에서 삭제/붙여넣기/이동과 같은 작업을 수행하면 접속한 모두에게 실시간으로 반영됨.</br>

</li>
</ol>
<h3 id="차이점">차이점</h3>
<ol>
<li>attach는 기존에 <strong>실행중인</strong> 컨테이너의 프로세스에 접속하는것.
ex) 입/출력 프로세스</li>
<li>exec는 기존에 실행중인 컨테이너에 <strong>새로운 프로세스</strong>를 생성하여 접속하는것.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[딥러닝에서 내적의 의미]]></title>
            <link>https://velog.io/@hi-one/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%97%90%EC%84%9C-%EB%82%B4%EC%A0%81%EC%9D%84-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@hi-one/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%97%90%EC%84%9C-%EB%82%B4%EC%A0%81%EC%9D%84-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Thu, 25 Sep 2025 08:01:02 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><em>&quot;두 벡터의 내적은 벡터간의 <strong>크기</strong>와 <strong>방향</strong>이 <u>얼마나 유사한가</u>를 알려준다.&quot;</em></p>
<p>vector, scalar = 백터, 스칼라
cosine, sine = 코사인, 사인</p>
</blockquote>
<h2 id="1-벡터는">1. 벡터는..</h2>
<p>크기와 방향을 가지고 있다</p>
<h2 id="2-스칼라는">2. 스칼라는..</h2>
<p>단순히 크기만 가지고 있다.</p>
<h2 id="3-내적은">3. 내적은..</h2>
<ul>
<li>두 벡터의 서로 대응되는 성분들을 곱한 뒤 모두 더하는 연산을함. 이 연산의 결과값은 스칼라값임. 이 스칼라 값은 <u><strong>두 백터의 크기와 방향이 얼마나 유사한가?</strong></u> 를 나타냄.</li>
<li>내적의 연산은 두 벡터 크기와 두 벡터가 이루는 각도 θ의 코사인 값을 곱함.
내적의 수식 : $A⋅B =|A|<em>|B|*cosθ$ 
내적의 최소/최대값 : $-|A|</em>|B|≤A⋅B≤|A|*|B|$<h3 id="3-1-수식에서-두-벡터의-크기를-곱하는건-이해가-가는데-왜-코사인θ을-곱할까">3-1. 수식에서 두 벡터의 크기를 곱하는건 이해가 가는데 왜 코사인θ을 곱할까?</h3>
</li>
<li>먼저 θ는 두 벡터가 이루는 각도의 <strong>차(difference)</strong>임.</li>
<li>두 벡터의 내적은 두 벡터가 이루는 각 θ에 대해 벡터 하나를 다른 벡터에 <strong>투영(projection)하는 길이</strong>를 의미함.</li>
<li>다른 벡터에 투영할 때 고려해야하는것은 바로 방향과 크기임. 다시 말하지만 <strong>방향</strong>과 크기임.</li>
<li>따라서 이 &#39;<strong>투영 길이</strong>&#39;라는 것은 벡터 간의 방향 차이를  반드시 포함해야함. 그러기 위해선 사인이나 탄젠트가 아닌 코사인을 사용할수밖에 없는데 코사인만이 백터의 방향을 나타낼 수 있기 때문임. <em>(사인은 삼각형의 높이이므로 방향과 상관이 없고 탄젠트는 각도에 대한 비율이므로 아예 기하학적 의미와 상관이 없음)</em></li>
<li>투영길이는 두 백터가 이루는 각도차이인 θ의 코사인 값과 벡터 크기의 곱으로 계산됨. 예를들어 벡터 A를 벡터 B에 투영할 때, 투영된 벡터 길이는$|A|<em>cosθ$ 임. 그래서 내적의 공식을 다시 쉽게 풀어쓰자면 $|A| * cosθ$ 하여 A백터를 B백터로 투영하고 $</em> |B|$ 하여 두 백터의 방향과 크기를 모두 고려한 유사도 값이 스칼라 형식의 결과로 나오는 것.</li>
</ul>
<hr>
<h3 id="4-번외">4. 번외..</h3>
<p>단순히 두 벡터가 얼마나 같은 방향으로 향하고 있는지만 궁금하다면 내적이 아닌 코사인 유사도 공식을 이용해 벡터간의 <u><strong>방향유사도</strong></u>를 구할 수 있다.
$Cosine Similarity = cosθ=\frac{∣A∣×∣B∣}{A⋅B}$</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[sigmoid와 softmax차이 및 활용법]]></title>
            <link>https://velog.io/@hi-one/sigmoid%EC%99%80-softamx%EC%B0%A8%EC%9D%B4-%EB%B0%8F-%ED%99%9C%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@hi-one/sigmoid%EC%99%80-softamx%EC%B0%A8%EC%9D%B4-%EB%B0%8F-%ED%99%9C%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Thu, 25 Sep 2025 06:30:44 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>activation Function = 활성화함수
sigmoid = 시그모이드
softmax = 소프트맥스</p>
</blockquote>
<h2 id="1-시그모이드의-함수-식그래프">1. 시그모이드의 함수 식&amp;그래프</h2>
<p><img src="https://velog.velcdn.com/images/hi-one/post/60a16a33-d305-4ba2-b56c-7ff1cc6acd7d/image.png" alt=""></p>
<h3 id="1-1-시그모이드는">1-1. 시그모이드는..</h3>
<ul>
<li>로지스틱(logistic) 함수의 한 케이스. 로지스틱 함수란 y값을 0과 1사이로 만드는 함수.</li>
<li>오직 <strong>1개</strong>의 인풋에 대해 <strong>1개</strong>의 아웃풋을 출력함.</li>
<li>아웃풋은 0~1사이의 값.</li>
<li>따라서 히든레이어의 활성화함수로 주로 사용됨.<br />


</li>
</ul>
<h2 id="2-소프트맥스의-함수-식그래프">2. 소프트맥스의 함수 식/그래프</h2>
<p><img src="https://velog.velcdn.com/images/hi-one/post/5034f814-e500-4721-b9e9-4bd0be78cebd/image.png" alt=""></p>
<h3 id="2-1-소프트맥스는">2-1. 소프트맥스는..</h3>
<ul>
<li>시그모이드의 확장형. 그래프는 시그모이드와 다를게 없음.</li>
<li>차이점은 <strong>n개</strong>의 인풋에 대해 <strong>n개</strong>의 결과값을 출력한다는 것.</li>
<li>n개의 결과값은 0~1사이의 값이면서 동시에 결과값의 합은 <strong>항상</strong> 1임.</li>
<li>따라서 다중클래스 분류 모델의 마지막 활성화함수로 주로 사용됨.<br />
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[포스터 이미지 번역 솔루션 개발 및 배포]]></title>
            <link>https://velog.io/@hi-one/%ED%8F%AC%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B2%88%EC%97%AD-%EC%86%94%EB%A3%A8%EC%85%98</link>
            <guid>https://velog.io/@hi-one/%ED%8F%AC%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B2%88%EC%97%AD-%EC%86%94%EB%A3%A8%EC%85%98</guid>
            <pubDate>Wed, 24 Sep 2025 07:03:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>다양한 언어의 포스터의 내용을 → 영어로 번역하는 솔루션
아래는 솔루션 전체 플로우차트▼
<img src="https://velog.velcdn.com/images/hi-one/post/8e197f72-85d7-4fa8-a487-c5cf950d0d62/image.png" alt=""></p>
</blockquote>
<hr>
<br />

<h3 id="1-솔루션을-위한-필수환경">1. 솔루션을 위한 필수환경</h3>
<ul>
<li>쿠다 12.8지원하는 드라이버 ( 525 &lt;= x &lt; 580)</li>
<li>GPU메모리 12GB 이상</li>
<li>70GB의 여유공간 (이미지 : 18GB + 컨테이너 50GB)<br />

</li>
</ul>
<h3 id="2-사용-모델-및-기술">2. 사용 모델 및 기술</h3>
<ul>
<li>NanoNets-OCR-s (OCR)</li>
<li>fastText (언어감지)</li>
<li>m2m100_418M (번역)</li>
<li>fastAPI(배포 및 사용)<br />

</li>
</ul>
<h3 id="3-도커컴포즈파일yaml-▼">3. 도커컴포즈파일.yaml ▼</h3>
<pre><code class="language-yaml">name: ${PROJECT_NAME}

services:
  MY_APP:
    image: aptr:v1
    container_name: ${CONTAINER_NAME:-aptr_container}
    ports:
      - &quot;${PORT}:${PORT}&quot;
    command: bash -li -c &quot;RUN_API ${PORT} &amp;&amp; exec bash&quot;
    environment:
      - PORT=${PORT}
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

    healthcheck:
      test: [&quot;CMD&quot;, &quot;curl&quot;, &quot;-f&quot;, &quot;http://127.0.0.1:${PORT}/&quot;]
      interval: 30s
      timeout: 300s
      retries: 3
      start_period: 60s
    shm_size: 1gb
    stdin_open: true
    tty: true
    restart: unless-stopped</code></pre>
<br /> 

<h3 id="4-도커컴포즈env파일env-▼">4. 도커컴포즈env파일.env ▼</h3>
<pre><code class="language-yaml">PROJECT_NAME=&#39;MyProject&#39;        #반드시 따옴표 안에서 작성
CONTAINER_NAME=&#39;my_container&#39;   #반드시 따옴표 안에서 작성
PORT=8787</code></pre>
<br />

<h3 id="5-클라이언트-api호출-예제-▼">5. 클라이언트 API호출 예제 ▼</h3>
<pre><code class="language-python">import base64
import requests

if __name__ == &quot;__main__&quot;:
    with open(&quot;./sample_poster_image.jpg&quot;, &quot;rb&quot;) as image_file:
        encoded_string = base64.b64encode(image_file.read()).decode(&quot;utf-8&quot;)

    # 서버에 보낼 데이터 구성
    data = {
        &quot;image&quot;: encoded_string
    }

    # JSON형태로 POST 요청 (내부에서 utf-8로 인코딩하여 전송)
    url = &quot;http://127.0.0.1:8787/translate“
    response = requests.post(url, json=data)

    print(response.status_code)
    print(response.text)</code></pre>
<br />

<hr>
<hr>
<h1 id="개발시-고려한-사항">개발시 고려한 사항</h1>
<br />

<h3 id="a-도커이미지-최적화"><strong><em>A. 도커이미지 최적화</em></strong></h3>
<p>도커이미지는 nvidia/cuda 도커이미지를 기반으로 만들었음. 도커이미지 제작시 컨테이너의 크기를 최소화 하기 위해 컨테이너 내에서 수십줄의 명령어를 &amp;&amp;으로 이어 단 한번의 명령어로 만들어 크기를 최적화 했음. 최적화 전후 용량차이는 약 3GB 차이. 아래는 실제 사용한 bash명령어. 환경함수 등록까지 모두 bash에서 처리함▼</p>
<pre><code class="language-bash">apt update &amp;&amp; \
apt install -y wget git python3.10 pip nano curl &amp;&amp; \
pip install  --no-cache-dir torch==2.7.0 torchvision==0.22.0 torchaudio==2.7.0 --index-url https://download.pytorch.org/whl/cu128 &amp;&amp; \
pip install transformers==4.52.4 accelerate==1.10.1 packaging==25.0 &amp;&amp; \
pip install fasttext==0.9.3 sentencepiece==0.2.1 fastapi==0.116.2 &amp;&amp; \
pip install &quot;uvicorn[standard]&quot;==0.35.0 flash-attn==2.8.3 --no-build-isolation pyarmor==7.7.4 &amp;&amp; \
cat &gt;&gt; ~/.bashrc &lt;&lt; &#39;EOF&#39; &amp;&amp;
function RUN_API(){
    local port_num=&quot;$1&quot;
    #cd /workspace/APTr-v1 || return
    python3 /workspace/APTr-v1/app.py &quot;$port_num&quot;
}
EOF
source ~/.bashrc &amp;&amp; \
apt clean &amp;&amp; \
apt autoremove -y &amp;&amp; \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* &amp;&amp; \
rm -rf ~/.cache/pip/* /tmp/* /var/log/* &amp;&amp;
find /usr -name &quot;*.pyc&quot; -delete &amp;&amp; find /usr -name &quot;__pycache__&quot; -type d -exec rm -rf {} + &amp;&amp; \
history -c &amp;&amp; &gt; ~/.bash_history</code></pre>
<br />

<h3 id="b-코드-및-디렉토리-암호화난독화"><strong><em>B. 코드 및 디렉토리 암호화(난독화)</em></strong></h3>
<p>파이선 기반의 솔루션 중 가장 강력한 암호화 패키지인 pyArmor를 이용. 디렉토리와 모델 암호화는 직접 변수를 수정해가며 수행하였음. 아래는 암호화 된 인퍼런스 코드의 일부▼
<img src="https://velog.velcdn.com/images/hi-one/post/db74330a-cd0e-434a-98cb-a4b128a557e6/image.png" alt="">
<br /></p>
<h3 id="c-여러-ocr모델-빌드-및-테스트"><strong><em>C. 여러 OCR모델 빌드 및 테스트</em></strong></h3>
<p>고객의 컴퓨팅 환경이 그리 좋지 못하였기에 12GB이하의 GPU에서도 원활하게 돌아갈 수 있는 성능 좋은 모델을 찾는데 많은 시간을 사용함. 특히 포스터내의 문자/단어 인식을 위해 테스트한 모델은 다음과 같음▼</p>
<ul>
<li>paddle OCR</li>
<li>CRAFT</li>
<li>DocLayout-YOLO</li>
<li>Nanonets-OCR-s</li>
</ul>
<p>처음엔 OCR모델만 찾다 결국 VLM모델로 넘어간거긴하지만 최종적으로 Nanonets 모델이 가장 나은 성능을 보였기에 선택함.
<br /></p>
<h3 id="d-언어인식-모델-빌드-및-테스트"><strong><em>D. 언어인식 모델 빌드 및 테스트</em></strong></h3>
<p>고객이 번역하고자 하는 포스터의 언어가 정해져있지 않았기에 다국어 → 영어로 번역이 가능한 모델을 찾아야했음. fasttext와 m2m100모델이 가장 적합하였기에 선택. 약 100개의 언어를 100개의 언어로 번역 가능.</p>
]]></description>
        </item>
    </channel>
</rss>