Skip to main content

TinyLLaVA로 LLM 앱 구축

TinyLLaVA, LangChain, W&B, Transformers, Gradio로 LLM 기반 앱 만들기! 이 글은 AI로 번역되었습니다. 오역이 의심되는 부분이 있으면 댓글로 알려주세요.
Created on September 15|Last edited on September 15

소개

이 글의 목적은 TinyLLaVA, LangChain, W&B, Transformers, Gradio를 활용해 LLM 기반 앱을 만드는 것입니다! 같이 따라 해 보려면 다음을 참고하세요 이 노트북 그리고 이 저장소. W&B 프로젝트는 여기를 클릭하세요 여기.
다음에서 영감을 받았습니다 Darek Kłeczek의 W&B 코스, 다음과 같이 활용하는 방법을 보여줍니다 W&B 와 함께 LangChain, Transformers, 그리고 Gradio LLM 기반 앱을 만들기 위해. 진심으로 감사드립니다 다렉 클레체크, 바라트 라마나탄, 토마스 카펠레그리고 이 과정을 가능하게 해 주신 모든 초청 연사분들께 감사드립니다!
먼저 다룰 내용은 다음과 같습니다 시각 지시 튜닝 LLaVA (언어 a그리고 비전 A그 다음으로, 그 후속작을 살펴보겠습니다. 시각 지시 튜닝으로 개선된 기준 모델 (LLaVA-1.5). 이 두 논문은 모두 다음에서 쉽게 찾을 수 있습니다 논문의 웹사이트마지막으로, LLaVA-1.5 데이터셋으로 파인튜닝되어 TinyLLaVA를 만들어낸 백본인 TinyLlama도 다루겠습니다!
마지막으로, LLaVA를 활용한 파인튜닝에 대해 조금 더 읽어보고 싶다면, 이 보고서를 참고하세요:

참고: 원한다면 이 세 가지 섹션(LLaVA, LLaVA-1.5, TinyLlama)은 건너뛰어도 됩니다. 이 섹션들은 논문을 풀어서 설명하며 우리가 다루는 내용에 대한 더 깊은 이해를 제공합니다.
💡

목차



🗻LLaVA란 무엇인가요?

서두에서 언급했듯이, LLaVA는 다음의 약자입니다 언어 a그리고 비전 A어시스턴트. 좀 더 자세히 말하면, LLaVA는 다음을 제공합니다:"
  • 이미지-텍스트 쌍을 적절한 이미지-텍스트 지시 튜닝 데이터로 변환하는 데이터셋 구축 파이프라인
  • 미세 튜닝 데이터셋, LLaVA-Instruct-150K, 이미지-텍스트 지시 따르기용과 CC3M을 걸러 축약한 사전학습 버전인 LLaVA-CC3M-Pretrain-595K
  • 두 개의 LLaVA 모델은 모두 다음의 후속작입니다 Vicuna-13B (lmsys/FastChat 또한 Vicuna 모델도 제공하며), 하나는 다음에 대해 미세 튜닝되었습니다 ScienceQA 그리고 다른 하나는 이 논문에서 선별한 이미지-텍스트 지시 따르기 데이터에 기반합니다 (LLaVA-Instruct-150K)
  • 2개의 소규모 평가 벤치마크인 LLaVA-Bench (COCO)와 LLaVA-Bench (In-the-Wild)

GPT 보조 시각 지시 데이터 생성

데이터 생성 방법을 몇 가지 살펴보겠습니다. 잠시 후에 이 내용이 중요해집니다.

단순한 방법

이미지의 경우 XvX_v 및 해당 캡션 XcX_c, 질문 세트를 만들고 XqX_q 아마도 GPT-4를 통해서입니다. 따라서 입력 프롬프트를 다음과 같이 구성하세요:
사람: XqXvX_q X_v중지 도우미: XcX_c중지"
이미지와 캡션이 주어졌을 때, 이 방법은 본질적으로 GPT-4에게 캡션으로 답할 수 있는 이미지 관련 질문을 생성하도록 프롬프트하는 방식입니다. 위와 같은 형식으로 턴 기반 대화가 되도록 구조화되어 있습니다. 저자들은 이 방법이 다양성과 심층적 추론이 부족하다고 주장하며, 자신들의 데이터셋 구성 방식으로 이러한 한계를 완화할 수 있다고 말합니다.

LLaVA 방법

저자들은 …을 사용했다 마이크로소프트 공통 객체 MS COCO 데이터셋을 출발점으로 사용했다. 각 이미지마다 캡션과 바운딩 박스 정보를 이미지 없이 GPT-4에 전달하는 프롬프트에 포함했다. 구체적으로, MS COCO의 각 이미지에 대해 GPT-4가 세 가지 유형의 지시 따르기 결과를 생성하도록 프롬프트를 설계했다.
인컨텍스트 학습을 위해 아래 3개 범주별로 시드 예시를 개발했다:
  • 대화이미지의 시각적 내용에 대한 다중 턴 질문-응답 쌍
  • 상세 설명이미지에 대해 묻는 질문/지시 목록에서 무작위로 하나를 선택해 단일 턴 프롬프트로 GPT-4에 보낸다.
  • 복잡한 추론이미지에 대해 단일 턴으로 진행되는 질문-응답 추론 쌍
최종 결과 데이터셋은 언어-이미지 지시 따르기 인스턴스 158K개로 구성되며, 이에는 대화 58K개, 상세 설명 23K개, 복잡한 추론 77K개가 포함된다. 참고로 HF 데이터셋에는 LLaVa-Instruct-150K로 표기되어 있는데, 아마도 편의상 반올림한 것으로 보인다.
아래는 상세 설명 범주에 대한 지시문 표와, 데이터셋 구축 과정에서 나온 입력/출력 예시이다.



시각 지시 튜닝

이제 실제 모델과 학습으로 넘어가 봅시다! 저자들은 동일한 LLaVA 모델 두 개를 만들었는데, 하나는 ScienceQA (과학 질문-응답)과 지시 따르기(챗봇)용으로 각각 하나씩.
ScienceQA 예시.

실제 네트워크 아키텍처는 다음과 같다. Vicuna-13B 기반 LLM으로 사용했으며(게시 시점에는 공개된 LLM 체크포인트 중 지시 따르기 성능이 가장 뛰어난 모델이었다).
이들이 사용한 비전 인코더는 CLIP 비주얼 인코더 ViT-L/14이 결합 시스템은 입력으로 이미지를 받습니다. XvX_v 그리고 언어 관련 질문/지시 XqX_q이미지는 먼저 CLIP으로 인코딩되어 출력됩니다 ZvZ_v, 그런 다음 프로ジェクト/선형 레이어 WW 이를 CLIP의 비주얼 임베딩 공간에서 단어 임베딩 공간으로 사상하여, 다음을 생성합니다 HvH_v.

1단계: 특징 정렬을 위한 사전학습

이 단계에서는 프로젝션 레이어만 학습하고 LLM과 비전 인코더는 고정합니다. 이들은 단순한 방법을 사용해 595K로 필터링된 데이터로 프로젝션 레이어를 사전 학습합니다. CC3M 데이터셋.

2단계: 엔드 투 엔드 미세 조정

여기서는 비전 인코더를 고정한 채 프로젝션 레이어와 LLM을 미세 조정합니다. 저자들은 ScienceQA와 LLaVA-Instruct-150K, 두 가지 데이터셋으로 미세 조정하고 평가했습니다.
다음은 LLaVA-Instruct-150K에서 발췌한 데이터 인스턴스의 한 턴입니다:
이미지의 경우 XvX_v, 우리는 TT 대화의 턴 수(대화는 멀티턴, 상세 설명과 복잡한 추론은 단일 턴). 따라서, XinstructtX_{instruct}^t 단일 턴입니다 (턴 tt) 하나의 데이터 인스턴스에 대해. 질문의 순서를 무작위로 바꾼다고 가정합니다. XqX_q 및 이미지 XvX_v 순서를 다양화하기 위해
Xinstructt={Randomly choose [Xq1,Xv] or [Xv,Xq1],the first turn t=1Xqt,the remaining turns t>1X_{\text{instruct}}^{t} = \begin{cases} \text{Randomly choose } [X_{q}^{1}, X_{v}] \text{ or } [X_{v}, X_{q}^{1}], & \text{the first turn } t = 1 \\ X_{q}^{t}, & \text{the remaining turns } t > 1 \end{cases}

순전파의 수식은 다음과 같습니다:
p(XaXv,Xinstruct)=i=1Lpθ(xiXv,Xinstruct,x<i,Xa,<i),p(X_a | X_v, X_{instruct}) = \prod_{i=1}^{L} p_{\theta}(x_i | X_v, X_{instruct}, x_{<i}, X_{a,<i}),

정답의 확률입니다 XaX_a 이미지가 주어졌을 때 XvX_v 그리고 전체 대화/상세 설명/복잡한 추론 문자열 XinstructX_{instruct}이 확률은 이전 확률들의 곱입니다
  • LL 인스턴스의 길이입니다 XinstructX_{instruct}
  • θ={W,ϕ}\theta = \{W, \phi\} 어디에서 ϕ\phi LLM의 모델 가중치입니다
  • xix_i 입니다 ii-n번째 토큰
  • XvX_v 이미지입니다
  • Xinstruct,<iX_{instruct, <i} 이전에 나온 모든 대화/상세 설명/복잡한 추론 문자열 토큰입니다 ii-n번째 토큰
  • Xa,<iX_{a, <i} 앞에 나온 모든 답변 토큰입니다 ii-n번째 토큰
이 내용을 한 문장으로 어떻게 요약할 수 있을까요?
요약하면, LLaVA가 정답을 맞힐 예측 확률은 주어진 질문(시각적 내용 또는 복잡한 추론에 관한 것)과 주어진 이미지에 조건화되어 있으며, 이 확률은 예측된 토큰 확률들의 시퀀스 곱으로서 자기회귀적으로 계산됩니다.

실험

논문에 실린 학습 실행 결과를 간단히 요약하면 다음과 같습니다:
모든 모델은 Vicuna의 하이퍼파라미터[9]를 따라 A100 8개로 학습했습니다. 필터링된 CC-595K 하위셋에서 학습률 2e-3, 배치 크기 128로 1 에포크 사전 학습을 진행했고, 제안된 LLaVA-Instruct-158K 데이터셋에서 학습률 2e-5, 배치 크기 32로 3 에포크 미세 조정했습니다.
그들은 이 대표적인 예시에서 GPT-4, BLIP-2, OpenFlamingo와 비교 테스트를 진행했습니다!

정량적 평가에는 이미지, 시각 정보에 대한 정답 텍스트 설명, 그리고 질문으로 이루어진 삼중항을 사용했습니다. 후보 모델인 LLaVA는 질문과 이미지를 바탕으로 답을 예측하고, 이 예측된 답을 정답 텍스트 설명과 함께 판정자 역할의 GPT-4에 입력합니다. 판정자인 GPT-4는 LLaVA의 답변에 1점부터 10점 사이의 점수를 부여합니다.
실험에서 그들은 소규모 평가 벤치마크 두 개를 만들었습니다: LLaVA-Bench (COCO)와 LLaVA-Bench (In-the-Wild).
LLaVA-Bench (COCO)
세부 정보
  • COCO-Val-2014에서 무작위로 선택한 이미지 30장으로, 각 이미지마다 대화, 상세 설명, 복잡한 추론의 3가지 질문 유형이 있어 총 90개의 질문으로 구성됩니다.
  • 일관된 시각 입력으로 모델의 정렬 행동과 능력을 테스트합니다. 본질적으로 대화, 상세 설명, 복잡한 추론의 세 가지 축에서 후보 모델을 평가합니다.
  • 세 가지 축의 데이터를 모두 사용했을 때 점수가 가장 크게 향상됨을 보여 주었으며, 이는 세 가지 질문 범주를 활용하는 방식이 단순한 방법보다 더 큰 개선을 이끈다는 점을 시사합니다.

LLaVA-Bench (In-the-Wild)
  • 실내외 환경에서의 복잡한 일반화 과제를 평가하기 위해 구성된 다양한 24장 이미지와 총 60개의 질문으로, 시각-언어 모델을 실제 환경(in-the-wild) 조건에서 테스트하는 데 목적이 있습니다.
  • 앞서 언급한 세 가지 범주 각각에서 질문을 포함합니다.
  • LLaVA가 실제 환경 시나리오에서 강력한 성능을 보임을 입증했습니다.
  • 이미지에서 복잡한 의미를 파악하지 못하는 LLaVA의 흥미로운 한계를 발견했습니다.

아래에서 도전적인 예시와 한계를 확인하세요:

이들은 다음으로 ScienceQA에서 실험을 진행했습니다. ScienceQA는 3개 과목과 26개 주제를 포괄하는 2.1만 개 규모의 멀티모달 데이터셋으로, 학습 12,726개, 검증 4,241개, 테스트 4,241개 샘플로 구성되어 있습니다.
ScienceQA로 파인튜닝한 LLaVA를 Chain-of-Thought(CoT) 사용 여부에 따른 GPT-3.5, LLaMA-Adapter, 그리고 현재 SOTA인 멀티모달 CoT와 비교 평가했습니다. LLaVA 단독 성능은 90.92%로, SOTA인 91.68%에 근접합니다. 저자들은 두 가지 방법으로 LLaVA와 GPT-4를 결합했습니다. 첫 번째 결합 방법은, 보완하다에서는 GPT-4가 답을 내지 못할 때에만 LLaVA를 사용합니다. 두 번째 방법은, 판단하다, GPT-4와 LLaVA의 답이 다를 경우, 두 가지 결과와 해당 질문을 바탕으로 GPT-4에 다시 프롬프트합니다.

이들은 다음 요소를 검증하기 위한 어블레이션 연구도 수행했습니다.
  • 시각적 특징 (CLIP의 마지막 레이어 vs 끝에서 두 번째 레이어): 마지막 레이어의 성능이 끝에서 두 번째 레이어보다 0.96% 낮은 것으로 확인했습니다. 마지막 레이어가 더 지역적인 특징보다 전역적인 특징을 산출하기 때문일 수 있다고 가정합니다.
  • 사고 사슬 LLaVA 내부의 LLM이 답변을 생성하는 순서가 성능에 영향을 주는지 실험했습니다. 순서를 바꿔도 전체 성능은 개선되지 않았지만, 먼저 추론을 제시하고 그다음에 최종 답을 제공하는 방식(제로샷 CoT와 유사)은 개선 효과가 있을 수 있음이 확인되었습니다. 수렴
  • 사전 학습 (사전 학습 옵트인/옵트아웃): 사전 학습을 건너뛰고 ScienceQA에 바로 LLaVA 모델을 학습했더니 85.81%로, 성능이 5.11% 하락했습니다. (프로젝션 레이어가 학습되지 않았으니 당연한 결과입니다!)
  • 모델 크기 (13B 원본 vs 신규 7B): 더 큰 모델은 90.92%를, 7B 모델은 89.84%를 기록했습니다 → 더 큰 모델일수록 성능이 더 좋습니다

LLaVA-1.5란 무엇인가요?

한눈에 보기: LLaVA-1.5 = 더 나은 모델(CLIP-ViT-L-336px), 더 많은 데이터(VQA).

위 표는 성능을 더 끌어올리기 위해 LLaVA에 단계적으로 추가한 개선 사항을 보여줍니다. 그 결과, LLaVA는 단순한 프레임워크와 적은 연산 자원으로도 더 적은 데이터로 최고의 성능을 달성한다는 점을 입증합니다.
LLaVA는 단문과 장문의 시각 질의응답에서 어려움을 보였습니다. 저자들은 그 원인을 모호한 프롬프트 때문일 수 있다고 가정합니다. 즉, 모델이 어떤 형태로 답해야 하는지 알지 못한다는 뜻입니다. 이를 해결하기 위해 프롬프트 끝에 다음과 같은 짧은 문장을 덧붙였습니다. “한 단어 또는 구절로 질문에 답하십시오.”

단일 선형 레이어를 2개 레이어의 다층 퍼셉트론(MLP)으로, 즉 선형 레이어 2개로 바꾸면서 성능이 향상되었습니다.

다음과 같은 VQA 및 OCR 관련 학술 과제용 VQA 데이터셋을 추가로 포함했습니다: 오픈 지식 기반 VQA(OKVQA), 증강 OKVQA (A-OKVQA), OCRVQA, 그리고 텍스트캡스연구진은 InstructBLIP의 학습 데이터 중 일부만 추가해도, LLaVA가 표 1의 세 가지 모든 과제에서 이미 InstructBLIP를 능가한다고 보고합니다.

또한 이미지의 해상도를 높이고 이를 사용합니다 GQA 데이터셋. 이들은 ShareGPT의 데이터를 포함하고 LLM 규모를 7B에서 13B로 확장합니다(이전 LLaVA 논문처럼 처음부터 13B로 시작하지 않은 이유는 불분명합니다).
요약하면, 이러한 모든 추가 요소와 성능에 미치는 영향은 표 1에서 확인할 수 있습니다.
LLaVA-1.5가 가장 단순한 아키텍처, 학술용 연산 자원, 공개 데이터셋만으로 최고 성능을 달성하고, 향후 연구를 위한 완전 재현 가능하고 비용 효율적인 기준점을 제공한다는 점은 고무적입니다.
아래는 12개 벤치마크 전반에서의 결과입니다.

이들은 몇 가지 특성과 한계를 지적합니다:
  • LLaVA-1.5는 ShareGPT 데이터 덕분에 어느 정도 다국어를 지원합니다.
  • 이미지 해상도를 높여(현재 336px) 8개의 A100에서 학습 시간이 두 배로 늘어, 사전 학습은 약 6시간, 시각 지시 튜닝은 무려 약 20시간 걸립니다.
  • LLaVA-1.5는 전체 이미지 패치를 사용해 학습이 길어지며, 표본 효율적인 시각 리샘플러가 도움이 될 수 있습니다.
  • LLaVA-1.5는 한 번에 여러 이미지를 처리할 수 없습니다. 그렇게 학습되지 않았기 때문입니다.
  • 다른 분야에서는 숙련도가 제한적임

TinyLLaVA란 무엇인가요?

TinyLLaVA는 LLaVA-1.5의 학습 체계와 데이터, 그리고 TinyLlama의 모델을 기반으로 구축되었습니다. 간단히 TinyLlama와 TinyLLaVA를 살펴보겠습니다.
TinyLlama 은 11억 개 파라미터의 LlaMA 모델을 3조 토큰으로 학습하는 데 초점을 맞춘 인기 프로젝트입니다! 토크나이저와 모델은 LLaMA-2를 기반으로 합니다. 아래는 README.md에 있는 학습 로지스틱 요약 표입니다.

TinyLlama는 휴대성, 속도, 효율성을 자랑합니다.
TinyLLaVA 은 LLaVA 모델의 11억 파라미터 소형 버전입니다. 참고로 TinyLLaVA의 백본은 원 논문처럼 Vicuna나 다른 LLM이 아니라 TinyLlama입니다. TinyLLaVA는 LLaVA-1.5와 동일한 방식으로 학습되었습니다.

🚧코드로 들어가 봅시다!

우리 앱 전체는 다음 위치에 있습니다 이 노트북 그리고 이 저장소!
💡
코드를 단계별로 살펴보겠습니다:

🔩 설정

우리는 필요합니다:
  • wandb
  • transformers (사용할 최신 버전 TinyLLaVA)
  • gradio 실제 앱을 구축하기 위해
  • chromadb 대화를 저장하기 위해
  • openai 그리고 tiktoken 우리 Chroma 벡터 데이터베이스에서 사용하는 임베딩 함수용
  • langchain Chroma를 감싸는 LLM 프레임워크 래퍼(편의용)
  • accelerate 그리고 bitsandbytes 양자화된 로딩을 위해
!pip install wandb -qqq
!pip install git+https://github.com/huggingface/transformers -qqq
!pip install --upgrade gradio -qqq
!pip install chromadb -qqq
!pip install openai -qqq
!pip install tiktoken -qqq
!pip install langchain -qqq
!pip install accelerate -qqq
!pip install bitsandbytes -qqq
다음으로 필요한 모듈을 가져오겠습니다.
import os
import requests
import numpy as np
import torch
import datetime

# For loading in the tiny-LLaVA-v1-hf model in a transformers pipeline.
import transformers
from transformers import pipeline
from transformers import BitsAndBytesConfig

# For converting input images to PIL images.
from PIL import Image

# For creating the gradio app.
import gradio as gr

# For creating a simple prompt (open to extension) to our model.
from langchain.prompts import PromptTemplate

# Our vector database of choice: Chroma!
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings.openai import OpenAIEmbeddings

import chromadb
from chromadb.utils.embedding_functions import OpenCLIPEmbeddingFunction
from chromadb.utils.data_loaders import ImageLoader

# For loading in our OpenAI API key.
from google.colab import userdata

# For logging.
import wandb
from wandb.sdk.data_types.trace_tree import Trace
wandb.login()

# Required for us to load in our pipeline for TinyLLaVA.
assert transformers.__version__ >= "4.35.3"

🧬Chroma: OpenAI와 함께 사용하는 벡터 데이터베이스

우선, 코드를 보기 전에 기본부터 짚고 넘어가죠. 벡터 데이터베이스란 무엇일까요? 또는 벡터 스토어는 무엇일까요? Pinecone(벡터 데이터베이스 제공업체)의 정의에 따르면… 페이지 훌륭한 설명이 있습니다:
벡터 데이터베이스는 빠른 검색과 유사도 탐색을 위해 벡터 임베딩을 색인하고 저장하는 데이터베이스로, CRUD 연산, 메타데이터 필터링, 수평 확장 같은 기능을 제공합니다.
일반적인 데이터베이스와 거의 동일하지만, 모든 작업을 벡터로 수행한다는 점만 다릅니다. 검색은 어떤 형태로든 유사도 탐색으로 이루어집니다. Vector store와 vector database는 종종 같은 의미로 쓰이며, vector store는 포괄적인 vector database의 더 가벼운 버전이라고 생각하면 됩니다.
자연스럽게 떠오르는 다음 질문은 이것입니다. 왜 이들이 유용할까요?
벡터 데이터를 다루는 데 따르는 어려움은, 전통적인 스칼라 기반 데이터베이스가 이러한 데이터의 복잡성과 규모를 따라가지 못해 인사이트를 도출하고 실시간 분석을 수행하기가 어렵다는 데 있습니다. 이때 벡터 데이터베이스가 필요합니다. 벡터 데이터베이스는 이러한 유형의 데이터를 처리하도록 의도적으로 설계되어, 데이터에서 최대한의 가치를 끌어낼 수 있도록 성능, 확장성, 유연성을 제공합니다.
소스.
# Use OpenAI's embeddings for our Chroma collection.
embeddings = OpenAIEmbeddings(
model="text-embedding-ada-002",
openai_api_key=userdata.get("OPENAI_API_KEY"),
)
collection = Chroma("conversation_memory", embeddings)
코드를 간단히 설명해 보겠습니다.
OpenAIEmbeddings 최근 번역 기록: 원문: CLIP-ViT-L-14: 번역: CLIP-ViT-L-14 원문: https://huggingface.co/sentence-transformers/clip-ViT-L-14 번역: https://huggingface.co/sentence-transformers/clip-ViT-L-14 원문: CC3M: 번역: CC3M: 원문: https://github.com/rom1504/img2dataset/blob/main/dataset_examples/cc3m.md 번역: https://github.com/rom1504/img2dataset/blob/main/dataset_examples/cc3m.md 원문: LLaVA 번역: LLaVA 원문: LLaVA: 번역: LLaVA: 원문: https://arxiv.org/abs/2304.08485 번역: https://arxiv.org/abs/2304.08485 원문: LLaVA-CC3M-Pretrain-595K: 번역: LLaVA-CC3M-Pretrain-595K: LangChain이 제공하는 수많은 임베딩 프로바이더 중 하나입니다. 그들 중 어떤 것이든 지정할 수 있습니다. 임베딩 모델. 저는 선택했습니다 text-embedding-ada-002. 우리는 Chroma를 직접 사용하기보다 LangChain을 편리한 인터페이스로 활용합니다(원한다면 직접 사용할 수도 있습니다). 데이터베이스 이름과 임베딩 함수를 지정하여 Chroma 벡터 데이터베이스/컬렉션을 정의합니다. LangChain의 Chroma가 지원하는 전체 연산 목록은 다음을 클릭하세요 여기.

🧪 파이프라인

다음으로 모델 추론 파이프라인을 초기화합니다. 큰 감사를 전합니다 저우 바이촨 Tiny-LLaVA-v1-hf 릴리스를 축하합니다!
# Ref: https://huggingface.co/bczhou/tiny-llava-v1-hf
model_id = "bczhou/tiny-llava-v1-hf"

bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)

pipe = pipeline(
"image-to-text",
model=model_id,
device_map="auto",
use_fast=True,
model_kwargs={"quantization_config": bnb_config}
)
코드를 함께 살펴보겠습니다. 이어서 모델 페이지, 이 모델로 추론 파이프라인을 초기화하는 방법은 두 가지가 있습니다. 저는 다음을 선택했습니다 pipeline 접근 방식.
우리는 …을(를) 정의합니다 BitsAndBytesConfig 에서 이중 양자화를 적용한 4비트 로딩을 위해 nf4 데이터 타입. 우리의 컴퓨트 dtype 이(가) 될 것입니다 torch.bfloat16자세한 내용은 이 훌륭한 양자화 페이지 Hugging Face에서! 자세한 내용은 BitsAndBytesConfig, 클릭 여기.
추론 파이프라인을 설정하는 일도 매우 간단합니다. 우리는 Transformer를 정의합니다 pipeline 작업을 다음과 같이 설정하여 "image-to-text" 그리고 이를 전달해 model_id 우리가 앞에서 정의한 것입니다. 우리는 설정합니다 device_map="auto" 가능한 경우 자동으로 GPU를 사용하도록 합니다. use_fast=True 빠른 토크나이저를 사용하도록 지정합니다. 우리의 model_kwargs 에 전달되는 값입니다 .from_pretrained(...) 는 파이프라인을 인스턴스화할 때 내부적으로 호출됩니다. 즉, 우리 bnb_config 에 전달됩니다 .from_pretrained(...)양자화는 추론 시간과 메모리 사용량을 크게 개선합니다. 처음에 실수로 CPU에서 앱을 실행했더니 파이프라인 포워드 패스 한 번에 무려 80초가 걸렸습니다. Colab T4 GPU로 실행하자 총 소요 시간이 4배 빨라져 포워드 패스당 20초로 줄었습니다. 여기에 추가로 양자화를 적용하면 20초 걸리던 생성이 5초로 단축됩니다.

앱 만들기

앱을 만들어 봅시다!
첫 번째 코드 조각은 두 개의 이미지를 가져오는 데 사용됩니다. 하나는 사용자용, 다른 하나는 챗봇용입니다. 나중에 Gradio 앱에서 프로필 사진으로 사용됩니다. 저는 기본 프로필 사진 두 장을 제공했는데, 하나는 기린이고 다른 하나는 돼지입니다!
try:
assert user_avatar_image_path
except:
img_data = requests.get("https://imgur.com/QehpHeV.png").content
with open('user_avatar.png', 'wb') as handler:
handler.write(img_data)
user_avatar_image_path = "user_avatar.png"

try:
assert chatbot_avatar_image_path
except:
img_data = requests.get("https://imgur.com/ki4hPhZ.png").content
with open('chatbot_avatar.png', 'wb') as handler:
handler.write(img_data)
chatbot_avatar_image_path = "chatbot_avatar.png"
테스트 실행을 위해 샘플 이미지를 가져오는 짧은 코드 조각도 제공합니다(대표적인 예시는 다음에서 가져옵니다). LLaVA).
# Let's get a sample image to use. You can download it and pass it into the app!
# The prompt is: What's unusual about this image?
img_data = requests.get("https://imgur.com/Ca6gjuf.png").content
with open('sample_image.png', 'wb') as handler:
handler.write(img_data)
이 이미지에서 이상한 점이 무엇인가요?
다음으로 정의해 봅시다 max_new_tokens (모델이 생성할 수 있는 최대 새 토큰 수)와 사용자가 업로드한 이미지를 저장할 폴더.
max_new_tokens = 200

# Path for storing images.
IMG_ROOT_PATH = "data/"
os.makedirs(IMG_ROOT_PATH, exist_ok=True)
우리가 사용하고 있으므로 gr.ChatInterface로, 다음 시그니처를 가진 함수가 필요합니다 message: str, history: list그럼 그것을 정의해 봅시다.
def generate_output(message: str, history: list, img: np.ndarray) -> str:
"""Generates an output given a message and image."""
우리 모델은 멀티모달이므로, 결국 추가 입력을 지정하게 됩니다 gr.ChatInterface그래서 그 추가 입력을 함수에 별도 매개변수로 전달해야 합니다. generate_output우리는 사용합니다 LangChain 프롬프트를 만들기 위해
status = "success"

# Get detailed description of the image for Chroma.
query = "Please provide a detailed description of the image."
prompt = PromptTemplate.from_template(
"USER: <image>\n" +
"{query}" +
"\n" +
"ASSISTANT: "
)

start_time_ms = datetime.datetime.now().timestamp() * 1000
try:
outputs = pipe(Image.fromarray(img), prompt=prompt.format(query=query), generate_kwargs={"max_new_tokens": max_new_tokens})
img_desc = outputs[0]["generated_text"].split("ASSISTANT:")[-1]
status_message = (None,)
except Exception as e:
status = "error"
status_message = str(e)
img_desc = ""
end_time_ms = round(datetime.datetime.now().timestamp() * 1000)
첫 번째 코드 스니펫입니다. 우리는 status 오류가 발생하면 "error"로 바뀌는 변수입니다. 우리 모델의 추론 파이프라인은 각 입력마다 두 번 실행되며, 한 번은 이미지를 설명하고 한 번은 사용자의 질문에 답합니다.
첫 번째 실행에서는 지정한 질의와 프롬프트를 함께 사용합니다. 이는 우리의 파이프라인을 통해 다음과 같이 전달됩니다 max_new_tokens 의 일부로 generate_kwargs 매개변수입니다. status_message 는 상태에 대한 자세한 설명일 뿐입니다. 또한 로깅을 위해 생성 시작 시각과 종료 시각도 기록합니다. 코드 곳곳을 직접 살펴보고 실험해 보면서 동작 방식을 확실히 이해해 보세요!
# Create a span in wandb.
root_span = Trace(
name="img_desc_span",
kind="llm", # kind can be "llm", "chain", "agent" or "tool"
status_code=status,
status_message=status_message,
metadata={
"max_new_tokens": max_new_tokens,
"model_name": model_id,
},
start_time_ms=start_time_ms,
end_time_ms=end_time_ms,
inputs={"system_prompt": prompt.format(query=query), "query": query},
outputs={"response": img_desc},
)

# Log the span to wandb.
root_span.log(name="img_desc_trace")
다음으로 우리는 W&B 트레이스이는 입력부터 출력까지 챗봇에 포함하고자 하는 모든 메타데이터를 담습니다. 앞서 파이프라인을 처음 실행하며 얻은 모든 유용한 데이터가 여기에 로깅됩니다.
  • 트레이스 이름
  • 종류
  • 상태 및 상태 메시지
  • 메타데이터
  • 시작/종료 시각
  • 입력/출력
사용자 정의 옵션은 훨씬 더 많지만, 위 설정들이 가장 간단합니다. 자세한 내용은 여기를 클릭하세요. 여기.
이제 사용자의 질의를 파이프라인에 실행하겠습니다. 로깅 절차는 첫 번째 실행과 동일합니다.
유일한 신규 구성 요소는 Chroma 벡터 데이터베이스를 통합한다는 점입니다! 우리 collection 사용자의 메시지로 질의하면 컬렉션에서 관련 문서가 상위 2개까지 추출됩니다. 이 문서들이 프롬프트의 문맥으로 사용됩니다.
# Visual Question-Answering!
prompt = PromptTemplate.from_template(
"Context: {context}\n\n"
"USER: <image>\n" +
"{message}" +
"\n" +
"ASSISTANT: "
)
context = collection.similarity_search(query=message, k=2)
context = "\n".join([doc.page_content for doc in context])

# Forward pass through the model with given prompt template.
start_time_ms = datetime.datetime.now().timestamp() * 1000
try:
outputs = pipe(
Image.fromarray(img),
prompt=prompt.format(
context=context,
message=message
),
generate_kwargs={"max_new_tokens": max_new_tokens}
)
response = outputs[0]["generated_text"].split("ASSISTANT:")[-1]
status_message = (None,)
except Exception as e:
status = "error"
status_message = str(e)
response = ""
end_time_ms = round(datetime.datetime.now().timestamp() * 1000)

# Create a span in wandb.
root_span = Trace(
name="response_span",
kind="llm", # kind can be "llm", "chain", "agent" or "tool"
status_code=status,
status_message=status_message,
metadata={
"max_new_tokens": max_new_tokens,
"model_name": model_id,
},
start_time_ms=start_time_ms,
end_time_ms=end_time_ms,
inputs={
"system_prompt": prompt.format(
context=context,
message=message
),
"query": message
},
outputs={"response": response},
)

# Log the span to wandb.
root_span.log(name="response_trace")
이 함수의 끝에서 두 번째 구성 요소는 모델이 생성한 내용을 벡터 데이터베이스에 업데이트하는 것입니다. 이미지 설명, 사용자 메시지, 그리고 모델의 응답을 하나의 문자열로 묶어 데이터베이스에 추가합니다.
# Add (img_desc, message, response) 3-tuple to Chroma collection.
text = f"Image Description: {img_desc}\nUSER: {message}\nASSISTANT: {response}\n"
collection.add_texts(texts=[text])
이 함수의 마지막 구성 요소는 반환문이며, 이는 Gradio 앱에 표시됩니다. 이미지 설명을 먼저 보여주고, 그다음에 모델의 응답을 제공합니다.
# Return model output.
return img_desc + "\n\n" + response
이제 W&B 프로젝트를 초기화하고, Gradio 앱 자체를 만들어 봅시다!
wandb.init(project="building_llm_app")

# Define the ChatInterface, customize, and launch!
gr.ChatInterface(
generate_output,
chatbot=gr.Chatbot(
label="Chat with me!",
show_label=True,
container=False,
scale=5,
height=300,
show_share_button=True,
show_copy_button=True,
avatar_images=(user_avatar_image_path, chatbot_avatar_image_path),
likeable=False,
layout="bubble",
bubble_full_width=False
),
textbox=gr.Textbox(
lines=1,
max_lines=5,
placeholder="Message ...",
container=False,
scale=7,
info="Input your textual response in the text field and your image below!"
),
additional_inputs="image",
additional_inputs_accordion=gr.Accordion(
open=True,
),
title="Language-Image Question Answering with bczhou/TinyLLaVA-v1-hf!",
description="""
This simple gradio app internally uses a Large Language-Vision Model (LLVM) and the Chroma vector database for memory.
Note: this minimal app requires both an image and a text-based query before the chatbot system can respond.
""",
theme="soft",
submit_btn="Submit ▶",
retry_btn=None,
undo_btn="Delete Previous",
clear_btn="Clear",
).launch(debug=True, share=True)
우리의 …을/를 확인해 보세요 generate_output 함수는 …을 생성할 때 첫 번째 인자입니다 gr.ChatInterface또한 우리는 …을/를 정의합니다 gr.Chatbot 일부 디자인 매개변수와 함께 설정합니다. Gradio에는 “share”와 “copy”처럼 유용한 기능이 있습니다. 앞서 정의한 아바타 이미지도 사용합니다! 텍스트 박스 gr.Textbox 한 줄로 구성되며 최대 다섯 줄까지 가능합니다. 우리는 추가 입력인 “image”를 더합니다. 추가 입력에 대한 자세한 내용은 에서 확인할 수 있습니다. gr.ChatInterface마지막으로 제목, 설명, 테마, 그리고 몇 가지 버튼 설정을 추가합니다. 마지막 단계는 호출하는 것입니다. .launch()!
자, 됐습니다방금 Transformers의 소형 멀티모달 LLM, 프롬프트 템플릿과 Chroma 벡터 데이터베이스를 위한 LangChain, 로깅을 위한 Weights & Biases(W&B), 앱 제작을 위한 Gradio를 활용해 LLM 기반 로컬 앱을 완성했습니다! 🥳


토론 및 향후 과제

방금 우리가 만든 앱에는 한계가 많습니다. 이제 여러분의 차례입니다. 이 앱을 더 나아지게 만들어 주세요!

👋 결론

여기까지 읽어 주셔서 감사합니다! 연구 논문까지 함께 살펴보셨다면 특히나 꽤 밀도 높은 글이었을 거예요. 이제 여러분은 다양한 기술을 활용해 LLM 기반 앱을 직접 만들어 보셨습니다! 더 깊이 살펴보고 싶다면 다음을 확인해 보세요 다른 강좌 W&B에서 제공합니다! 읽어 주셔서 감사합니다! 👋😎

참고 문헌

개발자 도구
W&B 사이트: https://wandb.ai/site
크로마 멀티모달 https://docs.trychroma.com/multi-modal
W&B 코스
W&B 코스 저자 소셜 채널
라마나탄(바라트) 파라메스와란 https://www.linkedin.com/in/param-bharat/
안톤 트로이니코프 https://www.linkedin.com/in/antontroynikov/
관련 자료
LLaVA
LLaVA-CC3M-Pretrain-595K: 최근 번역 기록: 원문: CLIP-ViT-L-14: 번역: CLIP-ViT-L-14 원문: https://huggingface.co/sentence-transformers/clip-ViT-L-14 번역: https://huggingface.co/sentence-transformers/clip-ViT-L-14 원문: CC3M: 번역: CC3M: 원문: https://github.com/rom1504/img2dataset/blob/main/dataset_examples/cc3m.md 번역: https://github.com/rom1504/img2dataset/blob/main/dataset_examples/cc3m.md 원문: LLaVA 번역: LLaVA 원문: LLaVA: 번역: LLaVA: 원문: https://arxiv.org/abs/2304.08485 번역: https://arxiv.org/abs/2304.08485 원문: LLaVA-CC3M-Pretrain-595K: 번역: LLaVA-CC3M-Pretrain-595K: https://huggingface.co/datasets/liuhaotian/LLaVA-CC3M-Pretrain-595K
LLaVA/LLaVA-1.5 논문 웹사이트: https://llava-vl.github.io/
LLaVA-1.5
TinyLLaVA 및 관련 자료
저우 바이촨: https://huggingface.co/bczhou



이 글은 AI로 번역되었습니다. 오역이 있을 수 있으니 댓글로 알려주세요. 원문 보고서는 아래 링크에서 확인할 수 있습니다: 원문 보고서 보기