<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dayoung20</title>
    <link>https://dayoung20.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 25 Aug 2026 04:41:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dayoung20</managingEditor>
    <image>
      <title>dayoung20</title>
      <url>https://tistory1.daumcdn.net/tistory/5678144/attach/a78c2ce00ec0412392f857a03a053759</url>
      <link>https://dayoung20.tistory.com</link>
    </image>
    <item>
      <title>[클라우드] 클라우드컴퓨팅 - Docker 개념과 실습</title>
      <link>https://dayoung20.tistory.com/29</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker 실습: Container 및 Docker 기초&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅 수업에서 Containerization과 Docker의 기본 개념을 학습하고, Ubuntu 환경에서 Docker Engine을 설치한 후 다양한 Docker 명령어를 통해 실습해보았다. 이 글은 해당 실습에서 배운 개념과 명령어들을 정리해보았다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Containerization이란?&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Container : Container는 프로세스 수준의 가벼운 가상화 환경이다. Linux의 chroot, namespace, cgroup 등의 기능을 활용하여 실행 환경을 격리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 호스트 OS의 커널을 공유하면서도 각각 독립된 실행 환경을 제공한다. 가상머신처럼 별도의 운영체제 전체를 실행하는 것이 아니기 때문에 상대적으로 성능 오버헤드가 작고, 필요한 라이브러리와 바이너리만 포함하여 빠르게 시작할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Containerization의 장점 : 컨테이너를 사용하면 개발 환경과 실행 환경을 독립적으로 구성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 컨테이너 내부에서 특정 소프트웨어를 설치하거나 설정을 변경하더라도 호스트 OS에 직접적인 영향을 주지 않는다. 작업이 완료된 컨테이너를 Image로 저장하면 필요한 의존성까지 함께 패키징하여 다른 환경에 그대로 배포할 수 있다. 따라서 개발자마다 환경이 달라 발생하는 &lt;b&gt;&quot;내 컴퓨터에서는 잘 되는데?&quot; 문제를 줄일 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Microservice Architecture&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Containerization과 함께 MSA에 대해서도 학습했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MSA는 하나의 큰 애플리케이션을 하나의 프로세스로 구성하는 Monolithic Architecture와 달리, 애플리케이션을 여러 개의 독립적인 서비스로 분리하는 구조다. 각 서비스는 API를 통해 서로 통신하며 독립적으로 개발하고 배포할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MSA의 주요 장점은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스별로 독립적인 유지보수가 가능하다.&lt;/li&gt;
&lt;li&gt;필요한 서비스만 독립적으로 확장할 수 있다.&lt;/li&gt;
&lt;li&gt;서비스마다 서로 다른 프로그래밍 언어를 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 서비스 간 결합도를 낮추고 각각의 컴포넌트를 독립적으로 관리할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Docker란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 컨테이너를 이용해 애플리케이션을 Build, Ship, Run할 수 있도록 지원하는 오픈소스 플랫폼이다. Docker를 이용하면 애플리케이션과 실행에 필요한 환경을 Image 형태로 패키징하고, 이를 기반으로 동일한 환경의 Container를 실행할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker의 주요 구성 요소는 Docker Engine, Docker CLI, Docker Hub등이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker Engine&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Engine은 Docker의 핵심 실행 환경으로, 실제 Container를 생성하고 실행 및 관리하는 역할을 한다. 내부적으로 dockerd라는 Docker daemon이 동작한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker CLI&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker CLI는 터미널에서 Docker 명령어를 실행하기 위한 인터페이스다. 예를 들어 다음과 같은 명령어를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;docker run
docker pull
docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker Hub&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Hub는 Docker Image를 저장하고 공유하는 Registry다. GitHub가 소스 코드를 공유하는 공간이라면, Docker Hub는 Docker Image를 공유하는 공간이라고 이해할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. Docker Engine 설치&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 실습에서는 Ubuntu 환경에서 Docker Engine을 설치했다. 먼저 Docker 공식 GPG Key를 추가하고 Docker의 공식 Apt Repository를 등록했다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 Docker Repository를 추가하고 패키지 목록을 업데이트했다. Docker Engine과 CLI, containerd, buildx plugin을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;sudo apt-get install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되면 Docker 서비스가 정상적으로 실행되고 있는지 확인한다.&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;sudo systemctl status docker
sudo docker --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Docker daemon이 자동으로 실행되지 않는다면 다음 명령어를 이용해 직접 시작할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;sudo systemctl start docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. Docker 설치 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker가 제대로 설치되었는지 확인하기 위해 hello-world Image를 실행했다.&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;sudo docker run hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hello-world Image가 로컬에 존재하지 않는 경우 Docker는 Docker Hub에서 해당 Image를 가져온 후 Container를 생성하여 실행한다. 정상적으로 실행되면 Hello from Docker! 메시지가 출력된다. 이를 통해 Docker Engine이 정상적으로 설치되고 실행되고 있는지 확인할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. Docker의 기본 명령어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 실습에서는 Docker의 기본적인 명령어인 docker run, docker pull, docker ps, docker images 등을 사용했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;docker run&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker run은 특정 Image를 기반으로 새로운 Container를 생성하고 실행하는 명령어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념적으로는 다음 세 가지 작업이 결합된 명령어라고 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;docker pull
    &amp;darr;
docker create
    &amp;darr;
docker start
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 필요한 Image가 로컬에 없다면 먼저 가져오고, 해당 Image를 기반으로 Container를 생성한 후 실행한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;docker pull&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker pull은 Docker Hub와 같은 원격 Registry에서 Image를 로컬로 가져오는 명령어다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;sudo docker pull python:3.9.25-slim
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Hub에는 다양한 공식 Image가 저장되어 있으며, 이번 실습에서는 nginx와 python Image를 사용했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;docker images&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 로컬에 저장되어 있는 Docker Image를 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;sudo docker images
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker pull을 통해 다운로드한 Image가 정상적으로 로컬에 저장되었는지 확인할 때 사용할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7. Nginx Container 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 이용하면 별도의 복잡한 설치 과정 없이 Nginx 서버를 Container로 실행할 수 있다. 다음 명령어를 실행한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;sudo docker run -p 81:80 -d nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 옵션은 다음과 같은 의미를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nginx: 실행할 Image&lt;/li&gt;
&lt;li&gt;-d: Detached mode로 실행하여 백그라운드에서 실행&lt;/li&gt;
&lt;li&gt;-p 81:80: 호스트의 81번 포트를 Container의 80번 포트에 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 외부에서 호스트의 81번 포트로 들어온 요청을 Container의 80번 포트에서 실행 중인 Nginx로 전달하도록 설정한 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8. 실행 중인 Container 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 실행 중인 Container는 docker ps를 이용해 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;sudo docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령어는 현재 실행 중인 Container만 보여준다. 중지된 Container까지 포함하여 생성된 모든 Container를 확인하려면 -a 옵션을 사용한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;sudo docker ps -a
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;9. Python Container 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 Python 공식 Image를 이용해 Container를 실행했다. 먼저 Python 3.9.25 slim Image를 Docker Hub에서 가져온다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;sudo docker pull python:3.9.25-slim
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 로컬 Image 목록을 확인한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;sudo docker images
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드한 Image를 기반으로 Interactive Container를 실행한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;sudo docker run -it python:3.9.25-slim
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 -it 옵션은 Container의 터미널에 직접 연결하여 Interactive하게 사용할 수 있도록 한다. 따라서 Container 내부에서 Python 환경을 직접 실행하고 명령어를 입력할 수 있다. 실습 과정에서는 Image 이름을 정확하게 입력하는 것도 중요하다는 점을 확인했다. Docker Image는 이름과 Tag에 따라 구분되기 때문에 python:3.9.25-slim과 같이 정확한 Image 이름을 사용해야 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;10. 실습을 통해 정리한 Docker 명령어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 실습에서 사용한 주요 명령어를 정리하면 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;docker run&lt;/td&gt;
&lt;td&gt;Image를 기반으로 Container를 생성하고 실행한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docker pull&lt;/td&gt;
&lt;td&gt;원격 Registry에서 Image를 가져온다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docker images&lt;/td&gt;
&lt;td&gt;로컬에 저장된 Image를 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docker ps&lt;/td&gt;
&lt;td&gt;실행 중인 Container를 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docker ps -a&lt;/td&gt;
&lt;td&gt;모든 Container를 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>클라우드</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/29</guid>
      <comments>https://dayoung20.tistory.com/29#entry29comment</comments>
      <pubDate>Mon, 24 Aug 2026 18:16:16 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 택배상자 - Python</title>
      <link>https://dayoung20.tistory.com/28</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 택배상자 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131704&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/131704&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787560937048&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131704&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dkVdb1/dJMb887qhbN/KtTEiE00y2DGEDmHX0vIV1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/o2JqD/dJMb8WMHiNV/khrmPSMurcaMcky5MsGZZK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131704&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131704&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dkVdb1/dJMb887qhbN/KtTEiE00y2DGEDmHX0vIV1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/o2JqD/dJMb8WMHiNV/khrmPSMurcaMcky5MsGZZK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2701&quot; data-origin-height=&quot;1104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sCLHR/dJMcacqPC8f/qNBo6FPhiKKkzR55kidy10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sCLHR/dJMcacqPC8f/qNBo6FPhiKKkzR55kidy10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sCLHR/dJMcacqPC8f/qNBo6FPhiKKkzR55kidy10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsCLHR%2FdJMcacqPC8f%2FqNBo6FPhiKKkzR55kidy10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2701&quot; height=&quot;1104&quot; data-origin-width=&quot;2701&quot; data-origin-height=&quot;1104&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 컨테이너를 설명하는 과정에서 &quot;보조 컨테이너 벨트는 앞 뒤로 이동이 가능하지만 입구 외에 다른 면이 막혀 있어서 맨 앞의 상자만 뺄 수 있습니다. &quot;라고 쓰여있었다. 이 문자을 보자마자 스택을 돌려서 표현한 것이라는 생각이 들었다. (백준의 스택 문제 중 유사한 문제가 있는거 같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 스택을 두 개 활용해야 했기 때문에 무작정 코드부터 쓰면 헷갈릴거 같았다. 그래서 먼저 코드 작성을 하기에 앞서서 변수와 스택이 여러개가 들어가기 때문에 정리를 해보았다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prior 딕셔너리 : 각 택배가 트럭에 실어져야하는 순서 딕셔너리&lt;/li&gt;
&lt;li&gt;container 배열 : 메인 컨테이너 배열로 설정하였고, 여기서 만약 순서에 맞지 않는다면 보조 컨테이너로 뺄 수 있다. 스택으로 활용할 예정이다.&lt;/li&gt;
&lt;li&gt;sub_cont 배열 : 보조 컨테이너 배열이다. 메인과 마찬가지로 스택으로 활용할 예정이다.&lt;/li&gt;
&lt;li&gt;visit 딕셔너리 : 해당 인덱스의 택배가 메인과 보조 컨테이너 중 어디에 해당하는지 나타낸 딕셔너리이다. 편의상 메인에 있으면 True, 보조에 있으면 False로 설정했다.&lt;/li&gt;
&lt;li&gt;i 인덱스 : 트럭에 실어야하는 택배의 인덱스&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 변수들을 바탕으로 구현한 코드는 아래와 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787561357822&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(order):
    answer = 0
    prior={}
    container=[]
    sub_cont=[]
    visit={}
    i=1
    for i in range(len(order)):
        prior[order[i]]=i+1
        visit[order[i]]=True
   
    for i in range(len(order),0,-1):
        container.append(prior[i])
   
    while i&amp;lt;=len(order):
        if visit[i]:
            if container[-1]==i:
                container.pop()
                answer+=1
                i+=1
            else:
                sub_cont.append(container[-1])
                visit[container[-1]]=False
                container.pop()
        elif sub_cont[-1]==i:
            sub_cont.pop()
            answer+=1
            i+=1
        else:
            break
    
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;while 반복문 안에 조건이 많아서 읽기 어려운 점이 조금 아쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복문을 설명하자면 먼저 트럭에 실어야 하는 인덱스의 택배가 메인과 보조 컨테이너 중 어디에 해당하는지 파악한다. 그 후 메인에 있다면 conatiner 스택에서 top 원소와 비교를 한다. top 원소와 같을 때는 그대로 pop을 하고 인덱스와 answer를 증가하면 된다. 반면 top 요소와 다를 때는 top 요소를 빼내서 보조 컨테이너로 옮겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 인덱스에 해당하는 택배가 보조 컨테이너에 위치한다면 top 원소와 비교를 해보고 같으면 answer와 인덱스 증가, 다르면 바로 반복문을 중단한다. 왜냐하면 container는 스택이기 때문에 top 원소를 제거하지 않고는 그 안의 요소를 꺼내지 못하기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 시간 복잡도는 O(n)으로 시간 초과 없이 해결할 수 있었다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/28</guid>
      <comments>https://dayoung20.tistory.com/28#entry28comment</comments>
      <pubDate>Mon, 24 Aug 2026 17:54:10 +0900</pubDate>
    </item>
    <item>
      <title>[AI 논문 리뷰] 인공지능 연구실 회고 (2) - Direct Preference Optimization of Video Large Multimodal Models from Language Model Reward</title>
      <link>https://dayoung20.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 리뷰할 논문의 제목은 Direct Preference Optimization of Video Large Multimodal Models from Language Model Reward 이다. 2025년 NAACL 논문으로 64회의 인용수를 가지고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mlyrf/dJMcabFjnuh/T4WN2sddjqoOtyZZYRWPV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mlyrf/dJMcabFjnuh/T4WN2sddjqoOtyZZYRWPV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mlyrf/dJMcabFjnuh/T4WN2sddjqoOtyZZYRWPV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmlyrf%2FdJMcabFjnuh%2FT4WN2sddjqoOtyZZYRWPV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;632&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문을 한 문장으로 이해해보자면 &quot;영상의 내용을 자세히 설명한 caption을 이용해서 LMM의 답변을 평가하고 좋은답변과 나쁜 답변을 만들어 DPO로 Video LMM을 학습시킨다&quot; 이다. 전체적인 흐름을 살펴보면 영상 -&amp;gt; caption -&amp;gt; Reward -&amp;gt; Preference Pair -&amp;gt; DPO의 흐름이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Contribution&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문의 핵심 contribution은 크게 3가지로 볼 수 있다.&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;large-scale, detailed video caption dataset 생성&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;cost-effective method로 비디오의 instruction-following 평가&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;language model feedback을 reward로서 DPO를 video LMM에 적용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Pipeline&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1083&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYV7OZ/dJMcadXuBKJ/UnQEO0oT5yXURt5eFRLfL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYV7OZ/dJMcadXuBKJ/UnQEO0oT5yXURt5eFRLfL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYV7OZ/dJMcadXuBKJ/UnQEO0oT5yXURt5eFRLfL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYV7OZ%2FdJMcadXuBKJ%2FUnQEO0oT5yXURt5eFRLfL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1083&quot; height=&quot;577&quot; data-origin-width=&quot;1083&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프라인은 논문에서 위의 피규어로 설명을 하고 있다. 비디오 -&amp;gt; caption 생성 -&amp;gt; SFT -&amp;gt; 여러 답변 생성 -&amp;gt; chatGPT 평가 -&amp;gt; DPO 순서이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피규어의 위쪽을 보면 비디오를 frame sequence로 표현하고 있다. 이 프레임들을 하나의 sequence로 concatenate해서 video llm이 영상 전체를 볼 수 있도록 만든다. 그 후 비디오의 캡션을 생성한다. 영상 frame sequence와 prompt를 GPT-4V에 입력한다. 그리고 단순한 한 문장이 아니라 영상의 세부적인 내용을 포함한 caption을 생성하도록 한다. 이 떄 상세한 caption을 만드는 이유는 뒷 과정에서 chatGPT가 모델의 답변이 영상과 일치하는지 평가해야 하기 때문이다. 따라서 캡션을 영상의 textual evidence로 사용하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU5c4t/dJMcaidv0Db/QJmrjkBBYWTIyIzkt6EHN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU5c4t/dJMcaidv0Db/QJmrjkBBYWTIyIzkt6EHN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU5c4t/dJMcaidv0Db/QJmrjkBBYWTIyIzkt6EHN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU5c4t%2FdJMcaidv0Db%2FQJmrjkBBYWTIyIzkt6EHN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;827&quot; height=&quot;727&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 피규어는 appendix에 있었던걸로 기억한다. chatgpt로 상세 캡션을 사용해서 instruction 데이터를 생성하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;219&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;SFT를 통해 Video LLM이 영상과 질문에 적절하게 답변하도록 학습한다. 학습된 모델에 영상과 질문을 입력해 여러 개의 답변을 생성하고, ChatGPT가 앞서 생성한 상세 캡션을 참고하여 각 답변이 영상의 내용과 일치하는지 평가한다. 이를 바탕으로 영상과 일치하는 답변을 chosen response, 부정확한 답변을 rejected response로 구성한다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;397&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로 이 preference data를 활용해 DPO를 수행한다. 이를 통해 영상의 내용과 일치하는 답변은 더 선호하고, 사실과 다른 답변은 생성하지 않도록 모델을 학습시켜 factuality를 높이고 hallucination을 줄인다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;397&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DPO with Feedback from Language Model as Reward&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCxiXK/dJMcahS1hBe/zNIS1FlhOglauEb9G9P3p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCxiXK/dJMcahS1hBe/zNIS1FlhOglauEb9G9P3p1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCxiXK/dJMcahS1hBe/zNIS1FlhOglauEb9G9P3p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCxiXK%2FdJMcahS1hBe%2FzNIS1FlhOglauEb9G9P3p1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1078&quot; height=&quot;640&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 크게 3가지로 설명할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 첫번째로, instruction pairs random sampling으로 SFT 모델이 각 입력당 6개의 답변을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째로, chatGPT가 캡션을 기반으로 각 답변을 평가한다. 1~5점 척도로 하고 explanation을 함께 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, reward 점수로 positive/negative를 구성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/As3vm/dJMcaaTYBeL/Pi0I9PvIYMbNZQ6tgpj5a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/As3vm/dJMcaaTYBeL/Pi0I9PvIYMbNZQ6tgpj5a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/As3vm/dJMcaaTYBeL/Pi0I9PvIYMbNZQ6tgpj5a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAs3vm%2FdJMcaaTYBeL%2FPi0I9PvIYMbNZQ6tgpj5a0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1606&quot; height=&quot;120&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식을 보면 이렇게 DPO 표현식으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;assessing evaluator quality using captions in place of frames&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vU0tb/dJMcafnxoFY/kFlWfsXchZtGKYr98yRti1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vU0tb/dJMcafnxoFY/kFlWfsXchZtGKYr98yRti1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vU0tb/dJMcafnxoFY/kFlWfsXchZtGKYr98yRti1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvU0tb%2FdJMcafnxoFY%2FkFlWfsXchZtGKYr98yRti1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1038&quot; height=&quot;309&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 실험은 영상 전체를 직접 보여준 GPT-4V의 평가와 영상의 캡션만 보여준 ChatGPT의 평가가 얼마나 비슷한지를 검증하고 있다. 이 실험의 결과를 보았을 때 75.33%는 chatGPT의 점수가 GPT-4V의 점수에서 1 표준편차 범위 안에 들어오는 비율을 나타낸다. 따라서 약 75.53%가 GPT-4V평가와 평가와 크게 벗어나지 않았다는 의미이다. 또한, 데이터셋 별로 ChatGPT와 GPT4V의 평가의 일치율을 비교했을 떄도 70% 이상이 일치한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 영상의 Frame을 직접 보지 않더라도, Detailed Video Caption을 이용하면 ChatGPT가 GPT-4V와 상당히 유사하게 답변의 factuality를 평가할 수 있다. 이 논문에서는 비용이 많이 드는 GPT-4V 평가 대신, 영상에서 미리 생성한 caption을 활용한 chatGPT 평가를 DPO의 evaluator로 사용할 수 있다고 보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Experiments&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deA4PS/dJMcajcfREU/cIk7pjvm5vyAw5t3iiKBuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deA4PS/dJMcajcfREU/cIk7pjvm5vyAw5t3iiKBuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deA4PS/dJMcajcfREU/cIk7pjvm5vyAw5t3iiKBuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeA4PS%2FdJMcajcfREU%2FcIk7pjvm5vyAw5t3iiKBuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1082&quot; height=&quot;682&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마무리로 실험 결과이다. Hound-dpo 방식을 사용하면 다른 베이스 대비 뚜렷한 성능 향상이 일어난 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;느낀점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상 자체를 직접 평가하지 않고 상세 캡션을 활용해 저렴하게 평가하는 방법이 인상적이었다. 특히 ChatGPT의 캡션 기반 평가가 GPT-4V의 프레임 기반 평가와 70% 이상 일치한다는 점에서, 비용과 효율성을 고려하면서도 Video LLM의 hallucination을 줄일 수 있는 방법이라고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 DPO 수식을 보았을 때 Video LLM에 맞는 DPO를 적용한 논문이라고 생각되어 흥미로웠다.&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/27</guid>
      <comments>https://dayoung20.tistory.com/27#entry27comment</comments>
      <pubDate>Sat, 22 Aug 2026 22:50:31 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 여행경로 - Python</title>
      <link>https://dayoung20.tistory.com/26</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 여행경로 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43164&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787388354186&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dVrG24/dJMb9llobkz/JwFdmrR6dIUwixVSmUmzKK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/cBBpR0/dJMb9efvaPp/kYYhYoS3hKJEtJaCF16aqk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dVrG24/dJMb9llobkz/JwFdmrR6dIUwixVSmUmzKK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/cBBpR0/dJMb9efvaPp/kYYhYoS3hKJEtJaCF16aqk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2662&quot; data-origin-height=&quot;1069&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sEbsE/dJMcaazJBlY/nwrZU4JZxXHA6KnDoF9sSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sEbsE/dJMcaazJBlY/nwrZU4JZxXHA6KnDoF9sSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sEbsE/dJMcaazJBlY/nwrZU4JZxXHA6KnDoF9sSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsEbsE%2FdJMcaazJBlY%2FnwrZU4JZxXHA6KnDoF9sSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2662&quot; height=&quot;1069&quot; data-origin-width=&quot;2662&quot; data-origin-height=&quot;1069&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 파이썬 문법을 정확히 알아야겠다고 생각하게 된 계기가 되었다. 먼저 문제를 보자마자 그래프, dfs가 떠올랐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 구현한 방법은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787388606436&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(tickets):
    answer=[]
    ans=[]
    dict={}
    ticket=0
    for i in tickets:
        ticket+=1
        if i[0] in dict:
            dict[i[0]].append([i[1],0])
            dict[i[0]].sort()
        else:
            dict[i[0]]=[[i[1],0]]
    
    def dfs(loc):
        nonlocal ans
        if len(answer)==ticket+1:
            if len(ans)==0 : 
                ans = answer[:]
            
            return answer
            
        elif loc in dict:
            for i in dict[loc]:
                if i[1]==0:
                    i[1]=1
                    answer.append(i[0])
                    dfs(i[0])
                    i[1]=0
                    answer.pop()
    answer.append(&quot;ICN&quot;)
    dfs(&quot;ICN&quot;)
    return ans&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 변수들을 설명해보겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dict : tickets를 딕셔너리로 만든 것이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1787388735881&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{'ICN': [['ATL', 0], ['SFO', 0]], 'SFO': [['ATL', 0]], 'ATL': [['ICN', 0], ['SFO', 0]]}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ICN에서 출발하는 티켓은 총 2개이고, 각 티켓 리스트의 2번째 요소인 0은 해당 티켓을 사용했는지를 나타낸 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ans : 최종 경로를 저장하는 리스트&lt;/li&gt;
&lt;li&gt;answer : dfs를 하면서 경로를 저장하는 리스트&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 ans와 answer의 차이는 answer는 dfs를 거치면서 초기화되지만, ans는 만약 경로가 완성되었다면 다시 초기화되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 ans를 초기화하지 않고, 처음 완성된 경로 그대로 할 수 있었던 이유는 먼저 dictionary를 sort해주었기 때문이다. 가장 첫 for 반복문을 보면 티켓을 하나 추가할 때마다 sort를 하는 것을 볼 수 있다. 따라서 가장 처음 방문한 경로가 알파벳 순으로 정렬된 것을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs에서 중요한 것은 방문 여부와 answer 경로를 dfs를 수행했다가 나올 때 다시 초기화하는 것이다. 따라서 코드에 보면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787389097963&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i[1]=1
answer.append(i[0])
dfs(i[0])
i[1]=0
answer.pop()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs를 방문하기 전에 i[1]을 1로 수정하여 방문 표시를 해주고, answer 배열에 경로를 추가한다. 그리고 dfs를 나온 이후에는 다시 dfs i[1]은 0으로, answer에서 경로는 삭제해준다. 이렇게 되면 문제가 dfs가 모두 완료된 이후에 answer를 보면 빈 배열이라는 것이다. 따라서 만약 경로가 완성되면 그걸 저장해둘 배열이 필요하다. 그게 바로 ans 배열인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++을 사용하다가 파이썬으로 오면서 아직 미숙한 점이 많은 것 같다. 그래서 정리를 해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파이썬에서는 def 함수 안에서 변수를 사용할 때, nonlocal 선언을 해야한다. 다만, 두가지 경우가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nonlocal 선언을 하지 않아도 되는 경우 : 값을 수정만 하는 경우 (이 코드에서는 answer 배열은 수정만 하기 때문에 nonlocal 선언이 필요 없음)&lt;/li&gt;
&lt;li&gt;nonlocal 선언을 해야하는 경우 : 값을 재할당해주는 경우 (&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 코드에서는&lt;span&gt; &lt;/span&gt;&lt;/span&gt;ans는 재할당하기 때문에 nonlocal 선언이 필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열을 복사할 떄는 두 가지가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 변수가 같은 배열을 가리키는 경우 : ans = answer&lt;/li&gt;
&lt;li&gt;하나의 변수가 가진 배열 그대로를 복사하는 경우 : ans = answer[:]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 후자를 선택했다. 전자를 선택할 경우 answer가 계속해서 초기화되는 동안 ans도 영향을 받기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787389631767&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(tickets):
    answer=[]
    ans=[]
    dict={}
    visit={}
    ticket=0
    for i in tickets:
        ticket+=1
        if i[0] in dict:
            dict[i[0]].append([i[1],0])
            dict[i[0]].sort()
            visit[i[0]].append(0)
        else:
            dict[i[0]]=[[i[1],0]]
            visit[i[0]]=[0]
    
    def dfs(loc):
        if len(answer)==ticket+1:
            return answer
            
        elif loc in dict:
            for i in dict[loc]:
                if i[1]==0:
                    i[1]=1
                    answer.append(i[0])
                    temp=dfs(i[0])
                    if temp: return temp
                    i[1]=0
                    answer.pop()
    answer.append(&quot;ICN&quot;)
    ans = dfs(&quot;ICN&quot;)
    return ans&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 ans 변수 없이 temp를 활용하여 이렇게 구하는 방법도 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs 구현은 금방 하지만, 자잘한 문제들이 있어서 시간이 꽤 소요되었던 문제이다..&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/26</guid>
      <comments>https://dayoung20.tistory.com/26#entry26comment</comments>
      <pubDate>Sat, 22 Aug 2026 18:07:50 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 보석 쇼핑 - Python</title>
      <link>https://dayoung20.tistory.com/25</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 보석&amp;nbsp;쇼핑 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67258#&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/67258#&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787302485173&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67258#&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Lu3KP/dJMb8ZvSHwN/1nYkQaYbAjFkNpCktooFf0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bpaIra/dJMb8WeQ6P7/XhipgWDyKDb1TuFnQ6bOVK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67258#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67258#&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Lu3KP/dJMb8ZvSHwN/1nYkQaYbAjFkNpCktooFf0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bpaIra/dJMb8WeQ6P7/XhipgWDyKDb1TuFnQ6bOVK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2608&quot; data-origin-height=&quot;1252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhOyWL/dJMcadbZQRk/AWFn6kMV5nKAgQcvDlyKW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhOyWL/dJMcadbZQRk/AWFn6kMV5nKAgQcvDlyKW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhOyWL/dJMcadbZQRk/AWFn6kMV5nKAgQcvDlyKW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhOyWL%2FdJMcadbZQRk%2FAWFn6kMV5nKAgQcvDlyKW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2608&quot; height=&quot;1252&quot; data-origin-width=&quot;2608&quot; data-origin-height=&quot;1252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 봤을 때, 하나의 배열이 주어지고 이 배열을 탐색해 나가야 하기 때문에 이중 for문 혹은 투포인터로 해결할 수 있을거라고 생각했다. 그래서 두 가지 모두를 해보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이중 for문을 사용한 풀이이다.&lt;/p&gt;
&lt;pre id=&quot;code_1787302683063&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(gems):
    answer = []
    cnt=len(set(gems))
    min_len=len(gems)
    for i in range(len(gems)):
        dict={}
        for j in range(i,len(gems)):
            
            if gems[j] in dict:
                dict[gems[j]]+=1
            else:
                dict[gems[j]]=1
            if len(dict)==cnt :
                if min_len &amp;gt; j-i+1:
                    answer=[i+1,j+1]
                    min_len=j-i+1
                elif min_len==j-i+1 and len(answer)==0:
                    answer=[i+1,j+1]
            
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현하기 전부터 시간 초과가 날 것 같다는 생각을 했는데 역시 시간초과가 났다. 그래도 풀이를 설명해보자면 먼저 cnt 값은 중복을 제거한 보석의 개수, min_len는 보석 배열의 길이이고 이 변수에 가장 짧은 구간의 길이를 저장한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for문을 돌면서 매번 새로 set을 선언해서 중복을 제거한 보석의 개수를 셀 수도 있지만, 이렇게 하면 효율성이 더 떨어지기에 dict라는 dictionary를 하나 선언했다. 여기에 i와 j를 변화하면서 보석을 하나씩 추가해나가며 dict의 길이로 중복을 제거한 보석 개수를 판단했다. 이 풀이로는 테스트 케이스는 모두 통과를 했지만, 효율성 테스트에서 모두 시간초과가 났기 때문에 효율이 낮다고 생각하여 투포인터로 넘어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투포인터를 활용하여 문제를 푸는 과정에서 시간이 꽤 소요되었다. 먼저 처음 투포인터로 작성한 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1787303048118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(gems):
    answer = []
    l,r=0,0
    cnt=len(set(gems))
    dict={}
    part=gems[0:1]
    for i in part:
        if i in dict:
            dict[i]+=1
        else:
            dict[i]=1
    while l&amp;lt;=r:
        if len(dict)==cnt:
            l+=1
            dict[gems[l-1]]-=1
            if dict[gems[l-1]]==0: 
                del dict[gems[l-1]]
                return [l, r+1]
        else:
            r+=1
            if gems[r] in dict:
                dict[gems[r]]+=1
            else:
                dict[gems[r]]=1
        
        
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나름 투포인터를 활용해서 다양한 엣지케이스도 반영했다고 생각했는데, 시간초과는 나지 않지만, 여러 테스트 케이스를 통과하지 못했다. 그래서 테스트 케이스를 추가해가며 예외 상황을 찾아나갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 가장 크게 문제가 된 상황은 &quot;가장 짧은 구간&quot;을 반환해야한다는 점이다. 이 코드에서는 가장 짧은지 여부는 검토하지 않고, 첫 인덱스부터 중복을 제거한 보석의 개수가 전체 보석의 종류와 같기만 하면 바로 return을 해버렸다. 이 상황을 검증할 수 있는 테스트 케이스는 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ls2pE/dJMcadiWphw/OUXZAyla0fafgidTH9n1l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ls2pE/dJMcadiWphw/OUXZAyla0fafgidTH9n1l1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ls2pE/dJMcadiWphw/OUXZAyla0fafgidTH9n1l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLs2pE%2FdJMcadiWphw%2FOUXZAyla0fafgidTH9n1l1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1034&quot; height=&quot;372&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지 경우에서 통과를 하기 위해서는 바로 return을 해버리는 부분의 코드를 수정할 필요가 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787303259804&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(gems):
    answer = []
    l,r=0,0
    cnt=len(set(gems))
    dict={}
    min_len=len(gems)+1
    part=gems[0:1]
    for i in part:
        if i in dict:
            dict[i]+=1
        else:
            dict[i]=1
    while r&amp;lt;len(gems):
        if len(dict)==cnt:
            if min_len &amp;gt; r-l+1:
                answer=[l+1, r+1]
                min_len=r-l+1
                
            l+=1
            dict[gems[l-1]]-=1
            if dict[gems[l-1]]==0: 
                del dict[gems[l-1]]
        else:
            r+=1
            if r&amp;lt;len(gems):
                if gems[r] in dict:
                    dict[gems[r]]+=1
                else:
                    dict[gems[r]]=1
        
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정된 부분이 조금씩 있다. 먼저 min_len 값을 추가했다. 이 변수를 사용하면 조건을 만족하는 구간 중 가장 짧은 구간의 길이를 저장할 수 있다. 그리고 while문의 조건도 수정했다. 기존에는 l&amp;lt;=r 이면 r이 배열의 밖으로 나가는 경우를 막을 수 없기에 r&amp;lt;len(gems)로 수정을 해주고, while문 안에서도 조건을 추가해주었다. 또한, min_len로 구간의 길이를 기록해두면서 배열의 끝까지 검사할 수 있도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 한 결과, 테스트 케이스와 효율성 테스트를 모두 만족할 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 한번 느낀 점은 투포인터를 구현할 때는 인덱스가 범위 안에 있는지 검증하는게 중요하다는 것과, 문제를 꼼꼼히 읽는 것이 중요하다는 점이다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/25</guid>
      <comments>https://dayoung20.tistory.com/25#entry25comment</comments>
      <pubDate>Fri, 21 Aug 2026 18:10:55 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 부대복귀 - Python</title>
      <link>https://dayoung20.tistory.com/24</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 부대복귀 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/132266&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787234324075&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dddqcu/dJMb9iIXFQS/NnqRlGzvDIfRAEQgnATuJ1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/crxUZU/dJMb9aKVXks/dAWh8fGtHMZKKXIYRFVirK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dddqcu/dJMb9iIXFQS/NnqRlGzvDIfRAEQgnATuJ1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/crxUZU/dJMb9aKVXks/dAWh8fGtHMZKKXIYRFVirK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2620&quot; data-origin-height=&quot;1230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbTB99/dJMcajwD4yy/qsoaIvpguu3Dmz4yg9u5MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbTB99/dJMcajwD4yy/qsoaIvpguu3Dmz4yg9u5MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbTB99/dJMcajwD4yy/qsoaIvpguu3Dmz4yg9u5MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbTB99%2FdJMcajwD4yy%2FqsoaIvpguu3Dmz4yg9u5MK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2620&quot; height=&quot;1230&quot; data-origin-width=&quot;2620&quot; data-origin-height=&quot;1230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 기본적인 그래프 dfs/bfs 문제이다. 구현을 하는 과정에서 bfs를 사용하였고, 그래프는 answer 배열을 활용하여 표현해보았다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787234438344&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque
def solution(n, roads, sources, destination):
    answer = [[]*(n+1) for _ in range(n+1)]
    
    for i in range(len(roads)):
        answer[roads[i][0]].append(roads[i][1])
        answer[roads[i][1]].append(roads[i][0])
    
    def bfs(location):
        q=deque()
        q.append(location)
        visit=[0]*(n+1)
        visit[location]=1
        while q:
            cur_loc=q[0]
            q.popleft()
            if len(answer[cur_loc])&amp;gt;0:
                for i in answer[cur_loc]:
                    if visit[i]==0:
                        visit[i]=visit[cur_loc]+1
                        if i==destination:
                            return visit[i]-1
                        q.append(i)
        
        return -1
    temp=[]
    for i in sources:
        if i==destination: 
            temp.append(0)
        else: temp.append(bfs(i))
        
        
    return temp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bfs의 경우에는 따로 함수를 만들어서 사용하였다. location을 입력받으면 그 위치에서부터 그래프를 bfs로 탐색해나가는 것이다. visit 배열은 먼저 0으로 n+1의 크기만큼 초기화를 해둔다. 이 배열의 역할은 크게 두가지이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드에 방문했는지 여부 확인 (0이면 방문하지 않은 노드, 0 초과이면 방문한 노드)&lt;/li&gt;
&lt;li&gt;시작 노드로부터 해당 노드까지 거리 (시작점을 방문하고 1로 초기화를 했기 때문에 이 값에 -1을 한게 거리가 된다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 시간초과가 발생한다. 그 이유는 bfs를 sources 배열의 원소 개수만큼 하기 때문이다. 단순하게 sources 배열에 있는 원소 개수만큼 매번 bfs를 돌리는 것이 아니라 한번 bfs를 하고 그 결과를 sources 배열을 순회하면서 사용하면 시간복잡도 측면에서 효율이 올라간다는 것을 알았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 이 코드에서는 추가로 개선해야하는 점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작점을 sources의 원소, 끝점을 destination으로 지정하여 bfs안에서 destination을 만나면 종료를 하도록 해두었다. 이 부분도 만약, bfs 1회로 수정을 하게된다면 개선해야 하는 부분이었다. 그리고 이 코드에서는 visit 배열에서 해당 노드를 방문했는지 여부를 판단하기 위해 시작점을 1로 설정해두었다. (0이면 방문하지 않은것으로 설정해두었기 때문) 다만, 이렇게 하게 되면 리턴할 때 -1을 해야해서 번거롭다. 이 부분도 개선이 필요하다고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개선점들을 반영하여 수정한 코드는 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787235507350&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque
def solution(n, roads, sources, destination):
    answer = [[]*(n+1) for _ in range(n+1)]
    
    for i in range(len(roads)):
        answer[roads[i][0]].append(roads[i][1])
        answer[roads[i][1]].append(roads[i][0])
    visit=[0]*(n+1)
    def bfs(location):
        q=deque()
        q.append(location)
        
        visit[location]=1
        while q:
            cur_loc=q[0]
            q.popleft()
            if len(answer[cur_loc])&amp;gt;0:
                for i in answer[cur_loc]:
                    if visit[i]==0:
                        visit[i]=visit[cur_loc]+1
                        q.append(i)
        return -1
    temp=[]
    bfs(destination)
    
    for i in sources:
        temp.append(visit[i]-1)
    
    return temp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드도 훨씬 간결해졌다. 총 1회의 bfs만으로 destination으로부터 모든 노드까지의 거리를 구하고 바로 답을 구할 수 있기 때문이다. 또한, 만약 도달하지 못한 경우는 -1을 리턴하도록 해야하는데 이 부분도 도달하지 못한 경우에는 0이 노드 값이기 때문에 -1을 해서 표현할 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도는 bfs를 1회하면서 O(n)으로 개선이 되었다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/24</guid>
      <comments>https://dayoung20.tistory.com/24#entry24comment</comments>
      <pubDate>Thu, 20 Aug 2026 23:21:34 +0900</pubDate>
    </item>
    <item>
      <title>[클라우드] 클라우드컴퓨팅 (이론)</title>
      <link>https://dayoung20.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라우드컴퓨팅 수업을 수강하며 배웠던 개념들을 정리하고자 한다. 이번 글을 시작으로 이론과 실습을 하며 했던 프로젝트들을 정리하며 작성할 예정이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이번 글은 클라우드 이론에 대해서 정리를 해보았다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 클라우드 컴퓨팅이란?&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p id=&quot;p-rc_2655d0afab377d69-184&quot; data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-path-to-node=&quot;10,0&quot;&gt;클라우드 컴퓨팅의 핵심 개념은 IT 자원의 유틸리티화이다&lt;/span&gt;&lt;span data-path-to-node=&quot;10,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;10,2&quot;&gt;. 전기나 수도를 사용한 만큼 요금을 내고 필요할 때 언제든 사용하는 것처럼, IT 인프라&amp;middot;플랫폼&amp;middot;소프트웨어를 인터넷을 통해 필요한 만큼 빌려 쓰고 사용한 만큼 비용을 지불하는 모델이다&lt;/span&gt;&lt;span data-path-to-node=&quot;10,3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;10,4&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;11,0,0,0&quot;&gt;주요 특징: 서버의 물리적 위치나 관리 주체에 신경 쓸 필요 없이, 인터넷에 연결된 모든 기기에서 언제 어디서나 서비스에 접근할 수 있다&lt;/span&gt;&lt;span data-path-to-node=&quot;11,0,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;11,0,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 역할 및 경계 (Roles and Boundaries)&lt;/b&gt;&lt;/h4&gt;
&lt;p id=&quot;p-rc_2655d0afab377d69-186&quot; data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-path-to-node=&quot;14,0&quot;&gt;클라우드 생태계를 구성하는 주요 역할과 경계 개념이다&lt;/span&gt;&lt;span data-path-to-node=&quot;14,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;14,2&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 주요 역할 (Roles)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0,0&quot;&gt;Cloud Provider&lt;/b&gt;: 클라우드 기반 IT 자원을 제공하는 주체이다 (예: AWS, Google Cloud, Azure)&lt;/span&gt;&lt;span data-path-to-node=&quot;16,0,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;16,0,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0,0&quot;&gt;Cloud Consumer&lt;/b&gt;: 계약을 맺고 클라우드 인프라 및 서비스를 이용하는 조직 또는 개인이다&lt;/span&gt;&lt;span data-path-to-node=&quot;16,1,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;16,1,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,0,0&quot;&gt;Cloud Service Owner&lt;/b&gt;: 클라우드 서비스의 법적 소유권을 가진 주체이다&lt;/span&gt;&lt;span data-path-to-node=&quot;16,2,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;16,2,0,2&quot;&gt;.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,2,1,0,0,0&quot;&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,1,0,0,0&quot;&gt;Cloud Consumer가 소유자인 경우&lt;/i&gt;: 클라우드 위에 자체 서비스를 배포하여 운영&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,2,1,1,0,0&quot;&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,1,1,0,0&quot;&gt;Cloud Provider가 소유자인 경우&lt;/i&gt;: 자사가 직접 만든 서비스를 타인에게 제공&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,3,0,0&quot;&gt;Cloud Resource Administrator&lt;/b&gt;: 클라우드 자원(가상 서버, 서비스 등)의 관리 및 운영을 담당하는 주체&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;16,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,4,0,0&quot;&gt;Cloud Broker&lt;/b&gt;: 여러 Cloud Provider의 서비스를 중개하고 통합, 관리, 협상해주는 역할&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 주요 경계 (Boundaries)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;18,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0,0&quot;&gt;Organizational Boundary (조직 경계)&lt;/b&gt;: 한 조직이 소유하고 관리하는 물리적 자원의 경계&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;18,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0,0&quot;&gt;Trust Boundary (신뢰 경계)&lt;/b&gt;: 신뢰할 수 있는 IT 자원의 논리적 범위를 의미하며, 보통 물리적 경계를 넘어 클라우드 영역까지 확장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 클라우드의 핵심 특징&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0,0,0&quot;&gt;On-Demand Usage &lt;/b&gt;: 사용자가 필요할 때 자율적으로 IT 자원을 할당받아 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,1,0,0&quot;&gt;Ubiquitous Access &lt;/b&gt;: 다양한 기기(모바일, PC 등)와 네트워크를 통해 어디서나 접근 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,2,0,0&quot;&gt;Multitenancy &amp;amp; Resource Pooling &lt;/b&gt;: 하나의 인프라/인스턴스를 여러 고객(Tenant)이 공유하여 사용하되, 각 사용자의 데이터와 환경은 철저히 격리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,3,0,0&quot;&gt;Elasticity &lt;/b&gt;: 트래픽이나 워크로드 변동에 맞춰 IT 자원을 유연하고 투명(Transparent)하게 확장/축소할 수 있는 능력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,4,0,0&quot;&gt;Measured Usage &lt;/b&gt;: 실제 사용한 자원의 양과 시간만큼만 측정하여 요금&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;21,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,5,0,0&quot;&gt;Resiliency &lt;/b&gt;: 장애 발생 시 다른 가용 영역/서버로 Failover되어 서비스의 Availability과 Reliability을 보장&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 클라우드 서비스 전달 모델 (Cloud Delivery Models)&lt;/b&gt;&lt;/h4&gt;
&lt;p id=&quot;p-rc_2655d0afab377d69-202&quot; data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-path-to-node=&quot;24,0&quot;&gt;클라우드 서비스는 제공하는 자원의 수준에 따라 대표적으로 3가지 모델로 나뉜다&lt;/span&gt;&lt;span data-path-to-node=&quot;24,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;24,2&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiX_ea38KyWAxUAAAAAHQAAAAAQsAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;+--------------------------------------------------------+
|  SaaS (Software as a Service)                          | -&amp;gt; 최상위 애플리케이션 제공
+--------------------------------------------------------+
|  PaaS (Platform as a Service)                          | -&amp;gt; 개발 및 배포 환경/API 제공
+--------------------------------------------------------+
|  IaaS (Infrastructure as a Service)                    | -&amp;gt; 가상화된 하드웨어/인프라 제공
+--------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) IaaS (Infrastructure as a Service)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;27&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;27,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,0,0,0&quot;&gt;개념&lt;/b&gt;: 가상 서버, 스토리지, 네트워크 등 기초 인프라 자원을 제공하는 모델&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;27,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,1,0,0&quot;&gt;특징&lt;/b&gt;: 제어 권한이 가장 높으며, 사용자가 OS 및 소프트웨어 설정을 직접 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;27,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,2,0,0&quot;&gt;대표 예시&lt;/b&gt;: Amazon EC2, Amazon S3, GoGrid&lt;/span&gt;&lt;span data-path-to-node=&quot;27,2,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;28&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) PaaS (Platform as a Service)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;29,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,0,0,0&quot;&gt;개념&lt;/b&gt;: 애플리케이션을 개발, 실행, 배포할 수 있는 런타임 환경과 플랫폼을 제공&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;29,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,0,0&quot;&gt;특징&lt;/b&gt;: 하드웨어 및 OS 관리의 복잡성을 덜어주고, 개발 및 서비스 구성에만 집중 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;29,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,2,0,0&quot;&gt;대표 예시&lt;/b&gt;: Google App Engine, Microsoft Azure, AWS Elastic Beanstalk&lt;/span&gt;&lt;span data-path-to-node=&quot;29,2,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) SaaS (Software as a Service)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;31&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;31,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,0,0,0&quot;&gt;개념&lt;/b&gt;: 완성된 형태의 웹 기반 애플리케이션을 인터넷을 통해 제공&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;31,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,1,0,0&quot;&gt;특징&lt;/b&gt;: 별도의 설치 과정 없이 웹 브라우저나 전용 앱으로 바로 이용 가능하며, Multitenant 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;31,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,2,0,0&quot;&gt;대표 예시&lt;/b&gt;: Salesforce.com, Google Apps (Workspace)&lt;/span&gt;&lt;span data-path-to-node=&quot;31,2,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;31&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;33,0,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;33,0,0,0&quot;&gt;IaaS&lt;/b&gt;: 높은 수준의 제어 권한 (가상 인프라 전반 제어)&lt;/span&gt;&lt;span data-path-to-node=&quot;33,0,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;33,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;33,1,0,0&quot;&gt;PaaS&lt;/b&gt;: 중간 수준의 제어 권한 (배포된 앱 및 관련 플랫폼 설정 제어)&lt;/span&gt;&lt;span data-path-to-node=&quot;33,1,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-path-to-node=&quot;33,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;33,2,0,0&quot;&gt;SaaS&lt;/b&gt;: 제한된 제어 권한 (사용자 인터페이스 및 일부 앱 내 설정만 제어)&lt;/span&gt;&lt;span data-path-to-node=&quot;33,2,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;35&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 클라우드 배포 모델 (Cloud Deployment Models)&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;36&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,0,0&quot;&gt;Public Cloud : &lt;/b&gt;&lt;span data-path-to-node=&quot;36,0,1,0,0,0&quot;&gt;인터넷을 통해 누구나 접근 가능한 형태이다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,0,1,0,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;36,0,1,0,0,2&quot;&gt;. &lt;/span&gt;&lt;span data-path-to-node=&quot;36,0,1,1,0,0&quot;&gt;초기 구축 비용이 적어 스타트업이나 소규모 기업에 유용하며 &lt;/span&gt;대표적인 특징은 Multitenancy이다&lt;span style=&quot;letter-spacing: 0px;&quot; data-path-to-node=&quot;36,0,1,2,0,1&quot;&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot; data-path-to-node=&quot;36,0,1,2,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,1,0&quot;&gt;Private Cloud (프라이빗 클라우드) :&amp;nbsp;&lt;/b&gt;&lt;span data-path-to-node=&quot;36,1,1,0,0,0&quot;&gt;단일 기업/기관 내부(On-Premise)에서 전용으로 구축하여 사용하는 형태이다. &lt;/span&gt;&lt;span data-path-to-node=&quot;36,1,1,1,0,0&quot;&gt;높은 보안성과 데이터 커스텀, 엄격한 SLA 보장이 필요한 정부, 금융, 군 기관 등에 적합하다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,1,1,1,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;36,1,1,1,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,2,0&quot;&gt;Hybrid Cloud (하이브리드 클라우드) :&amp;nbsp;&lt;/b&gt;&lt;span data-path-to-node=&quot;36,2,1,0,0,0&quot;&gt;Private Cloud와 Public Cloud를 조합한 형태이다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,2,1,0,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;36,2,1,0,0,2&quot;&gt;. &lt;/span&gt;&lt;span data-path-to-node=&quot;36,2,1,1,0,0&quot;&gt;민감한 데이터는 Private 환경에 두고, 트래픽 폭주 시 Public Cloud 자원을 동적으로 끌어와 확장(Cloud Bursting)하는 용도로 활용한다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,2,1,1,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;36,2,1,1,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,3,0&quot;&gt;Multi-cloud (멀티 클라우드) :&amp;nbsp;&lt;/b&gt;&lt;span data-path-to-node=&quot;36,3,1,0,0,0&quot;&gt;서로 다른 Provider의 Public Cloud를 2개 이상 복수로 조합하여 사용하는 형태이다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,3,1,0,0,2&quot;&gt;. &lt;/span&gt;&lt;span data-path-to-node=&quot;36,3,1,1,0,0&quot;&gt;특정 벤더에 종속되는 것을 방지하고, 각 플랫폼의 최선 서비스를 활용하거나 백업/redundancy를 극대화한다&lt;/span&gt;&lt;span data-path-to-node=&quot;36,3,1,1,0,1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span data-path-to-node=&quot;36,3,1,1,0,2&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>클라우드</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/23</guid>
      <comments>https://dayoung20.tistory.com/23#entry23comment</comments>
      <pubDate>Wed, 19 Aug 2026 23:25:12 +0900</pubDate>
    </item>
    <item>
      <title>[AI 논문 리뷰] 인공지능 연구실 회고 (1) -&amp;nbsp;Hallucination Augmented Contrastive Learning&amp;nbsp;for Multimodal Large Language&amp;nbsp;Model</title>
      <link>https://dayoung20.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지난 2025년 7월부터 2026년 2월까지 8개월간 인공지능 연구실에서 관련 논문을 읽고 연구를 진행해보았다. 그 과정에서 인상 깊게 읽었던 논문들을 정리하고 공유하고자 한다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 주로 멀티모달에 관심을 가졌었고, 이미지-텍스트, 비디오-텍스트 모델의 할루시네이션 관련 논문을 읽었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 첫번째로 리뷰할 논문은&amp;nbsp;&lt;b&gt;Hallucination Augmented Contrastive Learning&amp;nbsp;for Multimodal Large Language Model&lt;/b&gt; 이다. 해당 논문으로 세미나 발표도 했기 때문에 깊이있게 공부했던거 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnQHBs/dJMcacYxqxu/ufpx9CZVRlwefVs572CuJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnQHBs/dJMcacYxqxu/ufpx9CZVRlwefVs572CuJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnQHBs/dJMcacYxqxu/ufpx9CZVRlwefVs572CuJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnQHBs%2FdJMcacYxqxu%2Fufpx9CZVRlwefVs572CuJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1232&quot; height=&quot;642&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 인용수만 보더라도 굉장히 많은 것을 볼 수 있다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 논문은 CVPR 2024에 채택된 논문으로, MLLM의 Hallucination 문제를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Representation Learning의 관점&lt;/span&gt;에서 분석하고 해결 방법을 제안한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;1. Introduction&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최근 Multimodal Large Language Model(MLLM)은 이미지와 텍스트를 함께 이해하고 처리할 수 있게 되면서 다양한 Vision-Language Task에서 뛰어난 성능을 보여주고 있다. &lt;/span&gt;&lt;span&gt;하지만 MLLM은 여전히 &lt;/span&gt;&lt;span&gt;Hallucination&lt;/span&gt;&lt;span&gt;이라는 중요한 문제를 가지고 있다. 실제 이미지에는 존재하지 않는 객체를 있다고 설명하거나, 이미지와 일치하지 않는 잘못된 정보를 생성하는 현상이 대표적인 예다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 기존 Contrastive Learning에 hallucination이 포함된 caption을 추가적인 negative example로 활용하는 &lt;/span&gt;&lt;span&gt;HACL(Hallucination Augmented Contrastive Learning)​&lt;/span&gt;&lt;span&gt;을 제안한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;2. MLLM의 Hallucination 문제&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 MLLM은 시각적인 정보와 자연어 정보를 통합하여 다양한 멀티모달 task를 수행하고 있다. &lt;/span&gt;&lt;span&gt;하지만 모델이 이미지에 존재하지 않는 정보를 생성하거나 이미지와 다른 내용을 설명하는 Hallucination 문제가 여전히 존재한다. &lt;/span&gt;&lt;span&gt;이 논문에서는 이러한 문제를 단순히 모델의 생성 과정에서 발생하는 오류로 바라보지 않고, &lt;/span&gt;&lt;span&gt;Representation Learning의 관점&lt;/span&gt;&lt;span&gt;에서 분석한다. &lt;/span&gt;&lt;span&gt;논문에서는 기존 MLLM의 representation을 분석하면서 크게 두 가지 문제를 발견한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sN35y/dJMcadXsgIA/x2KZ8tqomEUXrq4X3JE851/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sN35y/dJMcadXsgIA/x2KZ8tqomEUXrq4X3JE851/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sN35y/dJMcadXsgIA/x2KZ8tqomEUXrq4X3JE851/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsN35y%2FdJMcadXsgIA%2Fx2KZ8tqomEUXrq4X3JE851%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;551&quot; height=&quot;444&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;2.1 Text와 Visual Representation 사이의 Gap&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 문제는 &lt;/span&gt;&lt;span&gt;text representation과 visual representation 사이에 gap이 존재한다는 것&lt;/span&gt;&lt;span&gt;이다. 논문의 피규어 (a)를 보면 확인 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MLLM에서는 이미지와 텍스트라는 서로 다른 modality를 하나의 모델에서 처리해야 하기 때문에 두 modality의 representation을 효과적으로 alignment하는 것이 중요하다. &lt;/span&gt;&lt;span&gt;하지만 기존 MLLM에서는 visual representation과 text representation 사이에 차이가 존재하기 때문에 모델이 시각 정보를 충분히 활용하지 못할 가능성이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;2.2 Hallucination과 Ground Truth Representation의 혼재&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째 문제는 &lt;/span&gt;&lt;span&gt;hallucination을 포함한 text representation과 실제 정답인 ground-truth text representation이 서로 얽혀 있다는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;즉, 모델의 representation space에서 이미지와 일치하는 문장과 이미지와 일치하지 않는 hallucination 문장이 명확하게 분리되지 않는다. &lt;/span&gt;&lt;span&gt;따라서 모델 입장에서는 이미지에 근거한 올바른 문장과 hallucination 문장을 구분하기 어려울 수 있다. &lt;/span&gt;&lt;span&gt;논문에서는 이러한 문제를 해결하기 위해 MLLM의 pretraining 과정에 &lt;/span&gt;&lt;span&gt;Contrastive Learning을 적용&lt;/span&gt;&lt;span&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 기존 Contrastive Learning과 달리 &lt;/span&gt;&lt;span&gt;hallucination이 포함된 caption을 추가적인 negative example로 활용&lt;/span&gt;&lt;span&gt;한다는 것이 핵심적인 아이디어다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;3. MLLM의 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MLLM은 이미지와 텍스트처럼 서로 다른 modality를 하나의 언어 모델에서 처리할 수 있도록 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적인 MLLM의 구조를 살펴보면 크게 다음과 같은 구성 요소를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Pretrained Vision Encoder&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Learnable Interface Module&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Large Language Model&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Vision Encoder는 이미지에서 visual information을 추출하고, 이를 LLM이 이해할 수 있는 형태의 representation으로 변환한다. &lt;/span&gt;&lt;span&gt;이때 Vision Encoder와 LLM 사이에서 서로 다른 modality를 연결하는 역할을 하는 것이 &lt;/span&gt;&lt;span&gt;Learnable Interface Module&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;이 논문에서 집중하는 부분도 바로 이 &lt;/span&gt;&lt;span&gt;interface를 어떻게 효과적으로 학습할 것인가&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;MLLM이 서로 다른 modality를 연결하는 과정에서 visual representation과 textual representation 사이에 충분한 alignment가 이루어지지 않는다면 LLM이 시각 정보를 오해하거나 무시할 수 있다. &lt;/span&gt;&lt;span&gt;그리고 이러한 현상이 Hallucination으로 이어질 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;4. 기존 MLLM의 Representation 분석&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;논문에서는 기존 MLLM의 representation을 시각화하여 앞서 설명한 문제를 보여준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;논문에서는 LLaVA의 representation을 Vicuna LLM space로 projection한 결과를 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 representation은 다음과 같이 구분된다. (피규어 (a), (b))&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;파란색 별: 이미지에서 추출한 visual information인 visual token&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;초록색 원: Ground-truth caption&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;빨간색 삼각형: Hallucination이 포함된 caption&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 가장 눈에 띄는 특징은 &lt;/span&gt;&lt;span&gt;visual representation과 text representation이 서로 명확하게 분리되어 있다는 점&lt;/span&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지에서 추출된 representation과 텍스트 representation 사이에 상당한 gap이 존재한다. &lt;/span&gt;&lt;span&gt;두 번째 문제는 &lt;/span&gt;&lt;span&gt;hallucination caption과 ground-truth caption이 서로 얽혀 있다는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;Hallucination을 포함하고 있는 텍스트와 실제 이미지에 대한 정답 텍스트가 representation space에서 명확하게 구분되지 않는다. &lt;/span&gt;&lt;span&gt;이를 통해 기존 MLLM의 interface가 visual representation을 LLM의 textual representation space로 효과적으로 매핑하지 못하고 있다는 점을 확인할 수 있다. &lt;/span&gt;&lt;span&gt;그리고 이러한 representation의 문제는 모델이 이미지와 일치하지 않는 hallucination text를 생성할 가능성을 높이는 원인이 될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;5. HACL이란?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 문제를 해결하기 위해 논문에서는 &lt;/span&gt;&lt;span&gt;HACL(Hallucination Augmented Contrastive Learning)​&lt;/span&gt;&lt;span&gt;을 제안한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL의 핵심 아이디어는 간단하다. &lt;span&gt;Hallucination이 포함된 텍스트를 Contrastive Learning의 negative example로 사용하는 것이다.&lt;/span&gt; &amp;nbsp;&lt;/span&gt;&lt;span&gt;일반적인 Contrastive Learning에서는 서로 대응되는 image-text pair를 positive로 설정하고 대응되지 않는 pair를 negative로 설정한다. &lt;/span&gt;&lt;span&gt;HACL에서는 여기에 한 가지를 추가한다. &lt;/span&gt;&lt;span&gt;바로 &lt;/span&gt;&lt;span&gt;같은 이미지에서 생성되었지만 실제 이미지와 일치하지 않는 hallucination caption을 negative example로 활용하는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;이를 통해 모델이 단순히 image와 text representation을 가깝게 만드는 것뿐만 아니라,&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;이미지와 일치하는 text representation은 가까이 배치&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이미지와 일치하지 않는 hallucination representation은 멀리 배치&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;학습할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;6. HACL의 전체 과정&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL의 전체적인 학습 과정은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 COCO 데이터셋에서 이미지와 ground-truth caption을 가져온다. &lt;/span&gt;&lt;span&gt;이 image-caption pair가 Contrastive Learning의 기본적인 positive pair가 된다. &lt;/span&gt;&lt;span&gt;이미지는 Vision Encoder를 통해 처리하여 &lt;/span&gt;&lt;span&gt;visual token&lt;/span&gt;&lt;span&gt;을 생성하고, caption은 LLM tokenizer를 통해 &lt;/span&gt;&lt;span&gt;text token&lt;/span&gt;&lt;span&gt;으로 변환한다. &lt;/span&gt;&lt;span&gt;그리고 GPT-4를 활용하여 해당 이미지에 대한 &lt;/span&gt;&lt;span&gt;hallucination caption&lt;/span&gt;&lt;span&gt;을 생성한다. &lt;/span&gt;&lt;span&gt;결과적으로 하나의 학습 데이터는 다음과 같은 구조를 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Image
   │
   ├── Vision Encoder ──&amp;gt; Visual Representation
   │
   ├── Ground Truth Caption ──&amp;gt; Positive Text
   │
   └── Hallucination Caption ──&amp;gt; Negative Text&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 생성된 hallucination caption을 Contrastive Learning의 negative example로 사용하여 모델이 이미지와 일치하지 않는 representation을 구분하도록 학습한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;7. HACL의 목표&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MLLM에서는 다양한 modality를 연결하는 &lt;/span&gt;&lt;span&gt;Learnable Interface&lt;/span&gt;&lt;span&gt;가 중요한 역할을 한다. &lt;/span&gt;&lt;span&gt;따라서 이 논문에서의 핵심 목표는 이 interface를 더욱 효과적으로 학습시키는 것이다. &lt;/span&gt;&lt;span&gt;구체적으로는 두 가지 목표를 동시에 달성하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLKkpt/dJMcafAYeMs/CPMRCZG4BxpIZfl5JiolR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLKkpt/dJMcafAYeMs/CPMRCZG4BxpIZfl5JiolR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLKkpt/dJMcafAYeMs/CPMRCZG4BxpIZfl5JiolR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLKkpt%2FdJMcafAYeMs%2FCPMRCZG4BxpIZfl5JiolR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1886&quot; height=&quot;468&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;7.1 Visual Representation과 Ground-truth Text의 Alignment&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Visual representation과 Ground-truth text representation 사이의 거리를 줄인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, Image &amp;harr; Ground Truth Caption&amp;nbsp;&lt;/span&gt;&lt;span&gt;의 alignment를 강화한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;7.2 Visual Representation과 Hallucination Text의 Separation&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Visual representation과 Hallucination text representation 사이의 거리를 증가시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, Image &amp;harr; Hallucination Caption&amp;nbsp;&lt;/span&gt;&lt;span&gt;은 서로 구분되도록 학습한다. &lt;/span&gt;&lt;span&gt;결과적으로 모델의 representation space에서 올바른 caption과 hallucination caption을 더욱 명확하게 분리할 수 있도록 만드는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;8. HACL의 Input과 Representation&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL의 input은 크게 세 가지다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;Image&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Ground-truth Caption&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Hallucination Caption&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지는 여러 개의 image patch로 나뉘어 Vision Encoder를 통과한다. &lt;/span&gt;&lt;span&gt;이를 통해 visual token sequence가 생성되고, 이후 interface를 통해 LLM의 입력 공간으로 projection된다. &lt;/span&gt;&lt;span&gt;한편 Ground-truth caption과 hallucination caption 역시 LLM에 입력된다. &lt;/span&gt;&lt;span&gt;각 sequence를 LLM에 통과시키면 최종적으로 각 sequence를 나타내는 hidden representation을 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;논문에서는 이때 sequence의 마지막 토큰인 &lt;/span&gt;&lt;span&gt;&amp;lt;EOS&amp;gt;&lt;/span&gt;&lt;span&gt; token의 hidden representation&lt;/span&gt;&lt;span&gt;을 사용한다. &lt;/span&gt;&lt;span&gt;그 이유는 일반적인 LLM이 decoder-only 구조를 가지고 있기 때문이다. &lt;/span&gt;&lt;span&gt;Decoder-only LLM은 입력 sequence를 순차적으로 받아들이며 자기 자신보다 이전에 등장한 토큰만 볼 수 있다. &lt;/span&gt;&lt;span&gt;따라서 각 토큰의 hidden state에는 이전까지 등장한 모든 토큰의 정보가 누적된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과적으로 마지막 토큰인 &lt;/span&gt;&lt;span&gt;&amp;lt;EOS&amp;gt;&lt;/span&gt;&lt;span&gt;의 hidden representation에는 전체 sequence의 정보가 포괄적으로 반영될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 이를 visual/text sequence를 대표하는 global representation으로 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;9. Visual Token과 Text Token&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 visual token sequence와 text token sequence는 각각 길이 (m), (n)을 가지며, 추가적으로 global vector 역할을 하는 &lt;/span&gt;&lt;span&gt;&amp;lt;EOS&amp;gt;&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span&gt;을 가지고 있다. &lt;/span&gt;&lt;span&gt;이미지와 텍스트를 각각 LLM layer에 통과시키면 최종적으로 hidden representation을 얻을 수 있다. &lt;/span&gt;&lt;span&gt;그리고 이 representation을 Contrastive Learning에 사용한다. &lt;/span&gt;&lt;span&gt;즉, HACL에서는 이미지와 텍스트를 단순히 generation task에 사용하는 것이 아니라, 각각의 representation을 추출하여 서로의 관계를 학습하는 데 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sy5Nh/dJMcacqL67J/loBmWQGApK4wU8DAWsnmmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sy5Nh/dJMcacqL67J/loBmWQGApK4wU8DAWsnmmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sy5Nh/dJMcacqL67J/loBmWQGApK4wU8DAWsnmmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSy5Nh%2FdJMcacqL67J%2FloBmWQGApK4wU8DAWsnmmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1886&quot; height=&quot;830&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;944&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAHzaP/dJMcabrNekZ/VpANhCQk4KGqktTsQOsWGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAHzaP/dJMcabrNekZ/VpANhCQk4KGqktTsQOsWGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAHzaP/dJMcabrNekZ/VpANhCQk4KGqktTsQOsWGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAHzaP%2FdJMcabrNekZ%2FVpANhCQk4KGqktTsQOsWGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;759&quot; height=&quot;592&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;944&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;10. Contrastive Learning&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL을 이해하기 위해 먼저 기본적인 Contrastive Learning의 방식을 살펴볼 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Contrastive Learning에서는 positive pair와 negative pair를 설정하여 representation 사이의 관계를 학습한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;Text-to-Image Contrastive Learning&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Text representation을 anchor로 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 text와 쌍을 이루는 image를 &lt;/span&gt;&lt;span&gt;positive&lt;/span&gt;&lt;span&gt;로 사용하고, 다른 image들을 &lt;/span&gt;&lt;span&gt;negative&lt;/span&gt;&lt;span&gt;로 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Text
 ├── Matching Image &amp;rarr; Positive
 └── Other Images   &amp;rarr; Negative&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;Image-to-Text Contrastive Learning&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반대로 Image representation을 anchor로 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 image와 쌍을 이루는 text를 &lt;/span&gt;&lt;span&gt;positive&lt;/span&gt;&lt;span&gt;로 사용하고, 다른 text를 &lt;/span&gt;&lt;span&gt;negative&lt;/span&gt;&lt;span&gt;로 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Image
 ├── Matching Text &amp;rarr; Positive
 └── Other Texts  &amp;rarr; Negative&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 HACL에서는 여기에 추가로 &lt;/span&gt;&lt;span&gt;hallucination caption을 negative example로 사용&lt;/span&gt;&lt;span&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;11. Contrastive Loss&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적인 Contrastive Learning의 목적은 positive pair의 similarity를 높이고 negative pair의 similarity를 낮추는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배치 사이즈를 (B)라고 하면 Text-to-Image Contrastive Loss에서는 text embedding을 anchor로 두고 같은 쌍의 image embedding을 positive로 사용한다. &lt;/span&gt;&lt;span&gt;그리고 다른 image embedding들을 negative로 사용하여 loss를 계산한다. &lt;/span&gt;&lt;span&gt;반대로 Image-to-Text Contrastive Loss에서는 image embedding을 anchor로 두고 같은 쌍의 text embedding을 positive로 사용한다. &lt;/span&gt;&lt;span&gt;다른 text embedding들은 negative로 사용한다. &lt;/span&gt;&lt;span&gt;HACL에서는 이러한 기존 방식에 &lt;/span&gt;&lt;span&gt;hallucination caption을 추가적인 negative example로 사용&lt;/span&gt;&lt;span&gt;한다. &lt;/span&gt;&lt;span&gt;중요한 점은 hallucination caption을 활용한 contrastive loss가 &lt;/span&gt;&lt;span&gt;Image-to-Text 방향에서만 적용&lt;/span&gt;&lt;span&gt;된다는 것이다. &lt;/span&gt;&lt;span&gt;Text-to-Image Contrastive Loss는 기존의 식을 그대로 사용한다. &lt;/span&gt;&lt;span&gt;결과적으로 모델은 하나의 이미지에 대해 다음과 같은 representation 관계를 학습한다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;12. Pretraining 과정&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckoqEs/dJMcacYxq3Z/0kdP6b6etq0XIV4VBkapR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckoqEs/dJMcacYxq3Z/0kdP6b6etq0XIV4VBkapR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckoqEs/dJMcacYxq3Z/0kdP6b6etq0XIV4VBkapR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckoqEs%2FdJMcacYxq3Z%2F0kdP6b6etq0XIV4VBkapR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1416&quot; height=&quot;702&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;논문에서는 pretraining enhancement를 위해 pretraining을 두 개의 stage로 나누어 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 &lt;/span&gt;&lt;span&gt;HACL은 첫 번째 stage의 pretraining에서만 적용&lt;/span&gt;&lt;span&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 stage에서는 일반적인 generation loss인 (L_G)와 함께 image-to-text, text-to-image contrastive loss를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 전체적인 optimization objective는 다음과 같은 형태로 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;L = LG + Contrastive Loss&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 (LG)는 텍스트를 생성하는 task에서의 일반적인 generation loss를 의미한다. &lt;/span&gt;&lt;span&gt;두 번째 stage에서는 기존 MLLM과 동일한 방식으로 fine-tuning을 진행한다. &lt;/span&gt;&lt;span&gt;따라서 두 번째 stage에서는 contrastive learning을 사용하지 않고 일반적인 generation loss인 (LG)만 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;13. Hallucination Caption 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dz6kls/dJMcabSPqiY/F1TM1Cu1ToXlpFs6Konak1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dz6kls/dJMcabSPqiY/F1TM1Cu1ToXlpFs6Konak1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dz6kls/dJMcabSPqiY/F1TM1Cu1ToXlpFs6Konak1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdz6kls%2FdJMcabSPqiY%2FF1TM1Cu1ToXlpFs6Konak1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2016&quot; height=&quot;812&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL에서 중요한 역할을 하는 것이 바로 &lt;/span&gt;&lt;span&gt;Hallucination Caption&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;Contrastive Learning에서 hallucination을 효과적인 negative example로 사용하기 위해서는 다양한 hallucination caption이 필요하다. &lt;/span&gt;&lt;span&gt;논문에서는 이를 위해 &lt;/span&gt;&lt;span&gt;GPT-4를 활용하여 hallucination caption을 생성&lt;/span&gt;&lt;span&gt;한다. &lt;/span&gt;&lt;span&gt;Ground-truth caption과 비교해보면 실제 이미지에 존재하지 않는 객체나 잘못된 속성 등의 hallucination이 포함된 것을 확인할 수 있다. &lt;/span&gt;&lt;span&gt;이렇게 생성된 hallucination caption이 HACL에서는 negative example로 사용된다. &lt;/span&gt;&lt;span&gt;결국 모델은 단순히 다른 image의 caption을 negative로 학습하는 것이 아니라, &lt;/span&gt;&lt;span&gt;같은 image를 설명하지만 실제로는 잘못된 caption을 negative로 학습&lt;/span&gt;&lt;span&gt;하게 된다. &lt;/span&gt;&lt;span&gt;이 점이 기존 Contrastive Learning과 HACL의 가장 중요한 차이점이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;14. 실험 환경&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;논문에서는 대표적으로 다음과 같은 MLLM을 활용하여 HACL의 효과를 검증했다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MiniGPT-4&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;LLaVA&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;LLaVA-1.5&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모델별로 pretraining에 사용되는 데이터셋의 규모가 다르기 때문에 hallucination caption을 생성하는 비용 역시 달라진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MiniGPT-4의 경우 pretraining 단계에서 사용한 데이터셋이 방대한 규모이기 때문에 전체 데이터에 대해 hallucination caption을 생성하는 것은 비용적인 부담이 크다. &lt;/span&gt;&lt;span&gt;따라서 MiniGPT-4에서는 전체 데이터 중 &lt;/span&gt;&lt;span&gt;10%에 해당하는 샘플만 추출하여 HACL을 적용&lt;/span&gt;&lt;span&gt;했다. &lt;/span&gt;&lt;span&gt;반면 LLaVA와 LLaVA-1.5는 MiniGPT-4에 비해 상대적으로 pretraining 데이터셋이 가볍기 때문에 모든 데이터에 대해 hallucination caption을 생성하여 HACL을 적용했다. &lt;/span&gt;&lt;span&gt;흥미로운 점은 MiniGPT-4에서 전체 데이터의 10%만 활용했음에도 불구하고 성능 향상이 뚜렷하게 나타났다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TZfkP/dJMcahyMRbr/Vqn963Dve5XoKSDyWKNTx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TZfkP/dJMcahyMRbr/Vqn963Dve5XoKSDyWKNTx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TZfkP/dJMcahyMRbr/Vqn963Dve5XoKSDyWKNTx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTZfkP%2FdJMcahyMRbr%2FVqn963Dve5XoKSDyWKNTx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1968&quot; height=&quot;740&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H1Wd8/dJMcaaTWjrO/fpKpAWGjPe90sXW8aU1Gd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H1Wd8/dJMcaaTWjrO/fpKpAWGjPe90sXW8aU1Gd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H1Wd8/dJMcaaTWjrO/fpKpAWGjPe90sXW8aU1Gd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH1Wd8%2FdJMcaaTWjrO%2FfpKpAWGjPe90sXW8aU1Gd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1958&quot; height=&quot;728&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;15. Multimodal Hallucination Benchmark&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 HACL의 hallucination 완화 효과를 확인하기 위한 실험이 진행됐다. &lt;/span&gt;&lt;span&gt;MiniGPT-4에 HACL을 적용한 모델은 HACL을 적용하지 않은 모델에 비해 전체 score가 눈에 띄게 증가했다. &lt;/span&gt;&lt;span&gt;또한 hallucination 비율 역시 크게 감소했다. &lt;/span&gt;&lt;span&gt;이를 통해 HACL이 실제 MLLM의 hallucination 발생을 줄이는 데 효과적이라는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;16. POPE Benchmark&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음으로는 &lt;/span&gt;&lt;span&gt;POPE benchmark&lt;/span&gt;&lt;span&gt;를 이용하여 객체 hallucination을 평가했다. &lt;/span&gt;&lt;span&gt;POPE에서는 질문 유형에 따라 크게 세 가지 설정을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Random :&amp;nbsp;무작위 샘플에서 객체에 대한 질문을 하는 설정이다.&lt;/li&gt;
&lt;li&gt;Popular :&amp;nbsp;데이터셋에서 자주 등장하는 객체에 대해 질문하는 설정이다.&lt;/li&gt;
&lt;li&gt;Adversarial :&amp;nbsp;모델이 헷갈리기 쉬운 질문을 사용하는 설정이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;19. Ablation Study&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Toce4/dJMcaiqSKpg/cLZpD0HXYGfOt7ESzhhZRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Toce4/dJMcaiqSKpg/cLZpD0HXYGfOt7ESzhhZRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Toce4/dJMcaiqSKpg/cLZpD0HXYGfOt7ESzhhZRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FToce4%2FdJMcaiqSKpg%2FcLZpD0HXYGfOt7ESzhhZRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1804&quot; height=&quot;718&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL의 핵심 요소인 hallucination caption이 실제 성능 향상에 기여하는지 확인하기 위해 Ablation Study를 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실험에서는 다음 세 가지 모델을 비교했다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;Contrastive Learning을 사용하지 않은 모델&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;일반적인 Contrastive Learning을 적용한 모델&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Hallucination Caption을 추가한 HACL 모델&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 pretraining 과정에서 Contrastive Learning을 적용하지 않은 기존 모델과 비교했을 때, 일반적인 Contrastive Learning만 적용해도 성능이 어느 정도 향상되는 것을 확인할 수 있다. &lt;/span&gt;&lt;span&gt;하지만 성능 향상에는 한계가 있었다. &lt;/span&gt;&lt;span&gt;여기에 hallucination caption을 추가한 HACL을 적용하면 더욱 뚜렷한 성능 향상이 나타났다. &lt;/span&gt;&lt;span&gt;이를 통해 단순히 image-text representation의 alignment를 개선하는 것뿐만 아니라, &lt;/span&gt;&lt;span&gt;hallucination caption을 명시적인 negative example로 사용하는 것이 성능 향상에 중요한 역할을 한다는 것&lt;/span&gt;&lt;span&gt;을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;20. Representation Visualization&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 논문에서는 HACL을 적용했을 때 representation space가 어떻게 변화하는지를 시각화했다. &lt;/span&gt;&lt;span&gt;세 가지 경우를 비교할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;(a) HACL을 적용하지 않은 경우&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Hallucination과 ground truth가 서로 섞여 있기 때문에 모델이 hallucination과 정답을 구별하기 어려운 상태다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 visual representation과 text representation 사이에도 modality gap이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;(b) 일반적인 Contrastive Learning만 적용한 경우&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Contrastive Learning을 적용하면서 visual representation과 text representation 사이의 modality gap은 확실하게 줄어든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 hallucination과 ground-truth representation 사이의 구분은 여전히 명확하지 않다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;(c) HACL을 적용한 경우&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HACL을 적용하면 visual representation과 text representation 사이의 alignment가 향상된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동시에 hallucination representation과 ground-truth representation도 명확하게 분리된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 논문에서 처음 문제로 제시했던 두 가지 문제가 동시에 개선되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;21. Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 논문에서는 MLLM에서 발생하는 hallucination 문제를 &lt;/span&gt;&lt;span&gt;Representation Learning의 관점에서 분석하고 HACL(Hallucination Augmented Contrastive Learning)​&lt;/span&gt;&lt;span&gt;을 제안했다. &lt;/span&gt;&lt;span&gt;기존 MLLM에서는 크게 두 가지 문제가 존재했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째는 &lt;/span&gt;&lt;span&gt;visual representation과 text representation 사이에 modality gap이 존재한다는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;두 번째는 &lt;/span&gt;&lt;span&gt;hallucination text와 ground-truth text가 representation space에서 명확하게 분리되지 않는다는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;논문에서는 이러한 문제를 해결하기 위해 hallucination caption을 생성하고 이를 &lt;/span&gt;&lt;span&gt;Contrastive Learning의 negative example로 활용&lt;/span&gt;&lt;span&gt;했다. &lt;/span&gt;&lt;span&gt;이를 통해 다음과 같은 representation 관계를 학습하도록 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Visual Representation
        &amp;darr;
Ground Truth Text와 가까워짐
        +
Hallucination Text와 멀어짐&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실험 결과 HACL을 적용한 모델은 hallucination benchmark와 POPE에서 hallucination이 감소했을 뿐만 아니라 VQA, MME와 같은 일반적인 multimodal benchmark에서도 성능이 향상됐다. &lt;/span&gt;&lt;span&gt;또한 Ablation Study를 통해 단순한 Contrastive Learning보다 &lt;/span&gt;&lt;span&gt;Hallucination Caption을 negative example로 활용하는 것이 성능 향상에 중요한 역할을 한다는 것&lt;/span&gt;&lt;span&gt;도 확인했다. &lt;/span&gt;&lt;span&gt;결국 이 논문의 핵심 아이디어는 모델에게 정답만 보여주는 것이 아니라, &lt;/span&gt;&lt;span&gt;이미지와 맞지 않는 hallucination을 명시적인 negative example로 함께 제공하여 무엇이 잘못된 정보인지 구분하도록 학습시키는 것&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;이를 통해 MLLM의 visual-text alignment를 향상시키면서 동시에 hallucination을 완화할 수 있다는 점에서 의미가 있는 연구라고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;22. 논문을 읽고 느낀 점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 논문에서 특히 흥미로웠던 부분은 hallucination을 단순히 generation 단계에서 발생하는 오류로 바라보지 않고 &lt;/span&gt;&lt;span&gt;representation space의 문제로 분석했다는 점&lt;/span&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;기존에는 hallucination을 줄이기 위해 생성 결과를 평가하거나 decoding 과정에서 모델의 출력을 제어하는 방법을 생각하기 쉽다. &lt;/span&gt;&lt;span&gt;하지만 이 논문에서는 그보다 앞선 단계인 &lt;/span&gt;&lt;span&gt;representation alignment 자체를 개선&lt;/span&gt;&lt;span&gt;하려고 했다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;특히 hallucination caption을 직접 negative example로 사용했다는 점이 인상적이었다. &lt;/span&gt;&lt;span&gt;일반적인 Contrastive Learning에서는 서로 다른 image-text pair를 negative로 사용하는 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반면 HACL에서는 &lt;/span&gt;&lt;span&gt;같은 이미지에 대해 생성된 hallucination caption을 negative로 사용&lt;/span&gt;&lt;span&gt;한다. &lt;/span&gt;&lt;span&gt;따라서 모델 입장에서는 단순히 &quot;다른 이미지에 대한 문장&quot;을 구분하는 것이 아니라, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;같은 이미지에 대해서도 어떤 문장은 올바른 설명이고 어떤 문장은 잘못된 설명인지&lt;/span&gt;를 학습할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;또한 HACL을 적용한 결과 hallucination benchmark뿐만 아니라 VQA와 MME 같은 일반적인 multimodal task에서도 성능이 향상됐다는 점도 흥미로웠다. &lt;/span&gt;&lt;span&gt;결과적으로 이 논문은 &lt;/span&gt;&lt;span&gt;MLLM의 hallucination 문제를 해결하기 위해서는 단순히 모델의 생성 결과를 수정하는 것뿐만 아니라, 모델 내부에서 visual information과 textual information이 어떻게 표현되고 정렬되는지를 함께 고려해야 한다는 점​&lt;/span&gt;&lt;span&gt;을 보여주는 연구라고 생각한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>AI</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/22</guid>
      <comments>https://dayoung20.tistory.com/22#entry22comment</comments>
      <pubDate>Wed, 19 Aug 2026 22:59:52 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 롤케이크 자르기 - Python</title>
      <link>https://dayoung20.tistory.com/21</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 롤케이크&amp;nbsp;자르기 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132265&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/132265&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787135052195&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132265&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cPz0nU/dJMb87gntLe/0XJSxIrJeFBLk4QQXgAyJ0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/b3FFL0/dJMb81HeuGx/iaKFAjmvqbK9fSEbGvkYt0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132265&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132265&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cPz0nU/dJMb87gntLe/0XJSxIrJeFBLk4QQXgAyJ0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/b3FFL0/dJMb81HeuGx/iaKFAjmvqbK9fSEbGvkYt0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2690&quot; data-origin-height=&quot;1254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iv0gk/dJMcaafotMw/wkoXW1etW4EjkjIf7e9irk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iv0gk/dJMcaafotMw/wkoXW1etW4EjkjIf7e9irk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iv0gk/dJMcaafotMw/wkoXW1etW4EjkjIf7e9irk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIv0gk%2FdJMcaafotMw%2FwkoXW1etW4EjkjIf7e9irk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2690&quot; height=&quot;1254&quot; data-origin-width=&quot;2690&quot; data-origin-height=&quot;1254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 중복을 포함하지 않고 배열에서 요소를 세는 것이 가장 중요하다고 생각했다. 중복 제거를 위해서는 set을 이용하도록 했다. 가장 단순하게 구현한 코드는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787135128834&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(topping):
    answer = 0
    for i in range(1,len(topping)-1):
        cake_1=set(topping[:i+1])
        cake_2=set(topping[i+1:])
        if len(cake_1)==len(cake_2):
            answer+=1
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 슬라이싱을 직접 해가면서 각 케이크에 있는 중복 제거 토핑 개수를 비교하는 방법이다.&amp;nbsp;문제점은 매 반복마다 topping을 슬라이싱하고 그걸 set으로 지정한다는 것이다. 따라서 시간 복잡도는 슬라이싱에 O(n), set에서 O(n)이 발생하므로 O(n&amp;sup2;)이 된다. 따라서 이 방법 대신 dictionary를 활용할 방법을 생각해보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787144589272&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(topping):
    answer = 0
    dict={}
    for i in topping:
        if i in dict:
            dict[i]+=1
        else:
            dict[i]=1
    temp=set()
    for i in range(len(topping)):
        temp.add(topping[i])
        dict[topping[i]]-=1
        if dict[topping[i]]==0: del dict[topping[i]]
        if len(dict)==len(temp):
            answer+=1
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dictionary인 dict를 선언해주고 그 안에 전체 topping의 개수를 넣는다. 그리고 temp라는 set을 두어 슬라이싱을 해가면서 왼쪽 케이크의 토핑 중 중복을 제거한 토핑 집합을 유지한다. 그리고 오른쪽으로 인덱스 i를 옮겨 가며 dict에서 해당 토핑 개수를 1 빼준다. 만약 dict에서 해당 요소가 0이 되면 그 요소를 제거해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우의 시간 복잡도를 생각해보면 topping을 dict에 넣는 과정에서 dictionary에서 in, 조회, 삽입 모두 O(1)이므로 첫번째 반복문의 시간복잡도는 O(1)이다. 두번째 반복문에서는 set에 add, dict의 삭제 모두 O(1)이기 때문에 n회 반복에서는 시간 복잡도 O(n)이다. 따라서 최종적으로는 O(n)을 만족한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이 문제를 풀며 파이썬 문법 중 헷갈리는 것을 정리해보았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;set 삭제 : s.remove(a)&lt;/li&gt;
&lt;li&gt;dictionary 삭제 : del dict['a']&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/21</guid>
      <comments>https://dayoung20.tistory.com/21#entry21comment</comments>
      <pubDate>Wed, 19 Aug 2026 22:16:25 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 프로그래머스 H-Index - Python</title>
      <link>https://dayoung20.tistory.com/20</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 : 프로그래머스 H-Index 문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42747#&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42747#&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787128008543&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42747#&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b2c9QT/dJMb8WMGDna/WYOPgLLCkPS5112KRCta21/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/BoHtl/dJMb9fZL43L/V6PuYfUdmIea419fGYIsFK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42747#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42747#&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b2c9QT/dJMb8WMGDna/WYOPgLLCkPS5112KRCta21/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/BoHtl/dJMb9fZL43L/V6PuYfUdmIea419fGYIsFK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT80j0/dJMcagGIvTL/LWcNLTGOwLHCdUpHCtuzIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT80j0/dJMcagGIvTL/LWcNLTGOwLHCdUpHCtuzIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT80j0/dJMcagGIvTL/LWcNLTGOwLHCdUpHCtuzIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT80j0%2FdJMcagGIvTL%2FLWcNLTGOwLHCdUpHCtuzIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2498&quot; height=&quot;990&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;990&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 봤을 때 가장 먼저 생각난 것은 주어진 citations 배열을 정렬하는 것이었다. 정렬을 먼저 하고, 이후에 for 반복문을 돌면서 h회 이상 인용된 논문의 개수를 세어나가는 것으로 코드를 작성했다. 처음 작성한 코드는 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787128218852&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(citations):
    answer = 0
    citations.sort()
    l=len(citations)
    for i in range(l):
        paper=l-i
        if citations[i]==paper:
            return paper
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 코드에서 간과했던 문제는 citations[i]==paper일때만 paper를 리턴하는 것이다. 따라서 예외 상황을 생각해보았을 때 citations=[0, 0, 5, 3], result : 2 인 경우가 있다. 이 케이스에서 위의 코드로는 답이 0으로 나오게 된다. 하지만, H-index의 정의를 보면 정확히 h 이상 인용된 논문이 정확히 h편일 필요는 없고, h편 이상이면 되는 것이다. 따라서 아래와 같이 수정을 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1787128379784&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(citations):
    answer = 0
    citations.sort()
    l=len(citations)
    for i in range(l):
        paper=l-i
        if citations[i]&amp;gt;=paper:
            return paper
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 했을 때는 예외상황 없이 모두 테스트 케이스를 통과했다. == 비교를 &amp;gt;=로 변경하면서 H-index의 결과가 항상 citations 배열에 있을 필요는 없는 상황을 반영해준 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 코드의 시간 복잡도를 생각해보았다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;citations 배열 정렬하는 과정 : O(n log n)&lt;/li&gt;
&lt;li&gt;for문 반복하는 과정 : O(n)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 효율적인 코드를 짜기 위해서는 시간복잡도를 먼저 작성해보고 코드에 반영하는 것이 중요하다는 것을 알게되었다. 이번 글부터는 시간 복잡도를 함께 작성하도록 하겠다.&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Python</category>
      <author>dayoung20</author>
      <guid isPermaLink="true">https://dayoung20.tistory.com/20</guid>
      <comments>https://dayoung20.tistory.com/20#entry20comment</comments>
      <pubDate>Wed, 19 Aug 2026 17:36:33 +0900</pubDate>
    </item>
  </channel>
</rss>