Skip to content

[2024/07/15/월] 코랩에서 모델 크기 관련 이슈 #8

Description

@SeoMiYoung

🤔 이슈 내용

이전에 작성된 내용 중, 꼭 LM Studio를 사용해야만 할까?라는 글을 보면, 모델 크기와 관련된 이슈가 있는 걸 확인할 수 있다.

관련된 오류는 다음과 같다.

오류 발생:  (Request ID: SAhWo4oPzTAw4Vb-nzaP7)

403 Forbidden: None.
Cannot access content at: https://api-inference.huggingface.co/models/sangthree/0707.
If you are trying to create or update content,make sure you have a token with the `write` role.
The model sangthree/0707 is too large to be loaded automatically (16GB > 10GB). Please use Spaces (https://huggingface.co/spaces) or Inference Endpoints (https://huggingface.co/inference-endpoints).

즉, 우리가 사용하고자 하는 모델 사이즈가 10GB가 넘어서 이런 이슈가 발생하는 것 같다.
이 점을 어떻게 해결해야할지 고민해보기로 했다.

🔶 [방법1] 모델 압축 및 최적화

모델을 양자화(quantization)하거나 프루닝(pruning)하여 크기를 줄일 수 있습니다.

(1-1) 모델 양자화

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# 원본 모델 로드
model_name = "sangthree/meta_0706"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 양자화
quantized_model = torch.quantization.quantize_dynamic(
    model,  # 모델 객체
    {torch.nn.Linear},  # 양자화를 적용할 레이어
    dtype=torch.qint8  # 양자화 데이터 타입
)

# 모델 저장
quantized_model.save_pretrained("quantized_model")
tokenizer.save_pretrained("quantized_model")

이렇게 하면, 원본 모델 크기의 절반이 줄어들 수 있다고 합니다.
image
다만... 무료로 제공되는 gpu정도로는 양자화를 할 수 없나봅니다.
여기서 끊겼습니다.

(1-2) 프루닝(Pruning)

프루닝은 중요하지 않은 가중치를 제거하여 모델의 크기를 줄이는 방법입니다. 프루닝에는 다양한 방식이 있지만, 일반적으로 사용되는 두 가지 방식은 다음과 같습니다.

  • 가지치기(Structured Pruning): 특정 구조(예: 필터, 채널)를 기준으로 가중치를 제거합니다.
  • 비구조적 프루닝(Unstructured Pruning): 개별 가중치 수준에서 중요하지 않은 가중치를 제거합니다.
import torch
import torch.nn.utils.prune as prune
from transformers import AutoModelForCausalLM, AutoTokenizer

# 원본 모델 로드
model_name = "sangthree/meta_0706"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 프루닝 적용
parameters_to_prune = (
    (model.transformer.h[0].attn.c_attn, 'weight'),
    (model.transformer.h[0].attn.c_proj, 'weight'),
    # 모델의 다른 레이어에도 적용 가능
)

for module, param in parameters_to_prune:
    prune.l1_unstructured(module, name=param, amount=0.4)  # 40% 프루닝

# 모델 저장
model.save_pretrained("pruned_model")
tokenizer.save_pretrained("pruned_model")

프루닝 후에도 원본 모델 크기의 절반을 줄일 수 있다고 합니다. 그치만, 이런 프루닝의 양과 방법에 따라 성능과 정확도에 영향을 줄 수 있으므로, 프루닝 후 모델 성능을 재평가해야한다고 합니다.

(1-3) 모델 샤딩(Sharding)

모델을 샤딩하여 저장하기

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# 원본 모델 로드
model_name = "sangthree/meta_0706"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 모델 가중치 추출
model_weights = model.state_dict()

# 가중치 샤딩
num_shards = 4
shard_size = len(model_weights) // num_shards
shards = [dict(list(model_weights.items())[i * shard_size:(i + 1) * shard_size]) for i in range(num_shards)]

# 샤드를 파일로 저장
for i, shard in enumerate(shards):
    torch.save(shard, f"model_shard_{i}.pth")

# 토크나이저 저장
tokenizer.save_pretrained("sharded_model_tokenizer")

샤딩된 모델을 로드하기

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# 빈 모델 생성
model_name = "sangthree/meta_0706"
model = AutoModelForCausalLM.from_pretrained(model_name, state_dict={})
tokenizer = AutoTokenizer.from_pretrained("sharded_model_tokenizer")

# 샤드를 순차적으로 로드하여 모델에 로드
num_shards = 4
for i in range(num_shards):
    shard = torch.load(f"model_shard_{i}.pth")
    model.load_state_dict(shard, strict=False)

# 모델의 나머지 파라미터 업데이트
model.eval()

# 샤딩된 모델 테스트
input_text = "환자분 어디가 아파서 오셨어요?"
inputs = tokenizer.encode(input_text, return_tensors='pt')
outputs = model.generate(inputs, max_length=50)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)

뭐..이런식으로 모델의 가중치를 여러 조각으로 나누어 파일로 저장하는 '샤딩 저장'과, 필요한 시점에 샤드를 순차적으로 로드하여 모델을 완성하는 '샤딩 로드'를 통해 대규모 모델을 로드할 때, 메모리 사용을 최적화할 수 있습니다.

🔶 [방법2] 외부 서버 활용

(2-1) 클라우드 서비스 사용

Colab외에도 Amazon AWS, Google Clould Platform, Microsoft Azure와 같은 클라우드 서비스에서 더 큰 메모리를 제공하는 인스턴스를 사용하여 모델을 로드하고 실행할 수 있습니다.
=> 그치만 이런 서비스는 일정 사용 이상은 다 유료임..

Google Colab, Kaggle, Microsoft Azure, Amazon Web Services(AWS), Google Clould Platform(GCP), Gradient by Paperspace, Colab Alternatives이런것들이 있지만, 다 돈과 관련이 되어있음.

만약 지속적으로 대규모 모델을 실행하야 한다면, 유료 서비스로 전환하는게 의미있을지 몰라도... 이런 단기적인 서비스는 애매함..

(2-2) 자체 서버 사용

회사나 연구기관에서 제공하는 고성능 서버를 활용하는 방식입니다. 해당 서버에서 모델을 실행하고 API를 통해 Colab에서 접근할 수 있습니다.
=> 근데 우리는 고성능 서버가 없다..이건 pass

🔶 [방법3] 모델 로컬 실행

로컬 컴퓨터에 gpu가 깔려있다면 크기가 큰 모델 실행 가능하다.
=> 그치만 없다.

🔊 결론

image
이슈의 내용들을 정리하면 위와 같다.

그리고 우리가 앞으로 모색해야하는 방향은 다음과 같다.

image

image

[ 현재 내가 할 수 있는 것 ]

  • LM Studio를 사용하는 방식으로 찾아보겠다.

[ 요청할 것 ]

  • 유정이한테, 모델 압축을 요청해야겠다.

[ 논의할 것 ]

  • 만약 유료버전 colab에서 16GB모델 작동이 된다면, 지속적인 유료 결제를 할 것인지 여부 (이 의미는 유료결제가 끊기면, 프로젝트가 동작하지 않음을 의미)
    image
    위의 이미지는 유정이의 이슈 캡처내용인데, 아마 유료버전에서는 16GB가 불러와지는 것 같긴 하다. 작동이 제대로 되는지는 만나서 테스트해봐도 될 것 같다.

🤔 유정이한테 한번 다음 코드가 유료버전에서 실행가능한지 요청해봐야겠다.
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

[ colab 코드 ]

# 라이브러리 설치
!pip install pyngrok
!pip install fastapi uvicorn pydantic langchain transformers
!pip install langchain_community

# 모델이 응답을 잘 받아오나 테스트 해보기

from langchain.llms import HuggingFaceHub

# Hugging Face Hub API 토큰 설정
huggingfacehub_api_token = "허깅페이스에서 write용 토큰 가져다가 넣어야해요"

# HuggingFaceHub 객체 생성
llm = HuggingFaceHub(
    repo_id="sangthree/meta_0706",
    task="text-generation",
    model_kwargs={"temperature": 0.7},
    huggingfacehub_api_token=huggingfacehub_api_token
)

# 테스트할 입력 문장
input_message = "안녕하세요. 어디가 아파서 오셨나요?"

# 'prompts' 설정
prompts = [input_message]


# llm.generate 메소드 호출
try:
    response = llm.generate(prompts=prompts)
    print("응답:", response)

    # generations 필드에서 text 추출
    generations_list = response.generations[0]  # generations는 리스트 안에 리스트 형태이므로 첫 번째 원소 선택
    generated_text = generations_list[0].text  # 첫 번째 리스트에서 첫 번째 Generation 객체의 text 필드 추출
    print("생성된 텍스트:", generated_text)
    
except Exception as e:
    print("오류 발생:", e)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions