이 비디오는 OpenAI Andrej Karpathy가 강연한 내용으로 대규모 언어 모델에 대해 소개합니다.
요약을 하면 다음과 같습니다. 언어 모델이란, 인터넷에서 수집된 방대한 양의 텍스트 데이터를 기반으로 학습하여, 다양한 유형의 문서와 유사한 텍스트를 자동으로 생성할 수 있는 인공지능 기술입니다. 이러한 모델은 GPU를 사용해 대량의 데이터를 학습하며, 이 과정에서 데이터는 모델이 이해할 수 있는 매개변수로 변환됩니다.
강연 내용에서는 이런 복잡한 훈련 과정을 설명하고, 어떻게 신경망이 웹 페이지와 같은 자료를 학습하여 새로운 텍스트를 생성하는지를 보여줍니다. 또한, 이 과정에서 발생하는 다양한 단계, 예를 들어 계산 비용이 많이 드는 초기 훈련(pre-training) 단계와 상대적으로 비용이 적게 드는 미세 조정(finetuning) 단계에 대해 설명합니다.
또한 GPT-3와 같은 언어 모델이 안전 조치를 우회하여 부적절한 정보를 제공할 수 있는 취약점, 예를 들어 'jailbreak' 공격에 대해 이야기하는데, 흥미로운 사례가 많네요.
그리고 언어 모델을 활용해 작업을 검증하거나, 샘플 답변을 생성하는 등의 유용한 사용 사례를 제시합니다. 특히, 언어 모델의 발전을 예시로 들면서, 어떻게 시간을 통해 모델의 정확도를 높일 수 있는지, 그리고 사용자의 필요에 따라 언어 모델을 맞춤 설정하는 방법에 대해 설명합니다.
또한, 대규모 언어 모델을 대상으로 하는 두 가지 주요 공격 유형인 노이즈 패턴 주입과 프롬프트 주입 공격을 소개하고, 이를 통한 개인 정보 유출의 가능성을 보여주었습니다. ChatGTP가 최근에 실시간으로 웹페이지에서 정보를 가져오는데, 그러한 웹페이지에 가짜 사이트 링크를 넣고 그걸 ChatGPT가 사용자게에 보여주는 가능성을 소개했습니다.
기존 여러 LLM관련 프로젝트에서는 gradio를 이용해서 WebUI를 지원했는데, Lama2 receipt에서는 아무리 찾아봐도 WebUI가 없어서 한번 만들어봤습니다. Gradio Python package를 처음 접했을 때 놀랐습니다. 이렇게 쉡게 웹 UI를 만들 수 있고 사람들에게 공유할 수 있구나하고요. 정말 Python 공동체는 이런것도 만들 생각을 하는구나 하는 생각도 했습니다. 당연하겠지만, 전문 프로그래머가 아닌 과학자나 공학자들이 좋아하는 언어로 웹서비스 구현에 시간을 쓸 이유가 없는거죠. 그냥 동작만하는 WebUI가 필요할 때, 바로 Gradio 패키지를 쓰면 됩니다.
일단, 해당 프로젝트에 Pull Request를 했는데, 다행히 리뷰도 받고 있어서 조만간 머지될 것 같습니다. 코드는 다음과 같습니다.
example/inference.py
# Copyright (c) Meta Platforms, Inc. and affiliates.
# This software may be used and distributed according to the terms of the Llama 2 Community License Agreement.
# from accelerate import init_empty_weights, load_checkpoint_and_dispatch
import fire
import os
import sys
import time
import gradio as gr
import torch
from transformers import LlamaTokenizer
from llama_recipes.inference.safety_utils import get_safety_checker, AgentType
from llama_recipes.inference.model_utils import load_model, load_peft_model
from accelerate.utils import is_xpu_available
def main(
model_name,
peft_model: str=None,
quantization: bool=False,
max_new_tokens =100, #The maximum numbers of tokens to generate
prompt_file: str=None,
seed: int=42, #seed value for reproducibility
do_sample: bool=True, #Whether or not to use sampling ; use greedy decoding otherwise.
min_length: int=None, #The minimum length of the sequence to be generated, input prompt + min_new_tokens
use_cache: bool=True, #[optional] Whether or not the model should use the past last key/values attentions Whether or not the model should use the past last key/values attentions (if applicable to the model) to speed up decoding.
top_p: float=1.0, # [optional] If set to float < 1, only the smallest set of most probable tokens with probabilities that add up to top_p or higher are kept for generation.
temperature: float=1.0, # [optional] The value used to modulate the next token probabilities.
top_k: int=50, # [optional] The number of highest probability vocabulary tokens to keep for top-k-filtering.
repetition_penalty: float=1.0, #The parameter for repetition penalty. 1.0 means no penalty.
length_penalty: int=1, #[optional] Exponential penalty to the length that is used with beam-based generation.
enable_azure_content_safety: bool=False, # Enable safety check with Azure content safety api
enable_sensitive_topics: bool=False, # Enable check for sensitive topics using AuditNLG APIs
enable_salesforce_content_safety: bool=True, # Enable safety check with Salesforce safety flan t5
enable_llamaguard_content_safety: bool=False,
max_padding_length: int=None, # the max padding length to be used with tokenizer padding the prompts.
use_fast_kernels: bool = False, # Enable using SDPA from PyTroch Accelerated Transformers, make use Flash Attention and Xformer memory-efficient kernels
**kwargs
):
def evaluate(user_prompt, temperature, top_p, top_k, max_new_tokens, **kwargs,):
safety_checker = get_safety_checker(enable_azure_content_safety,
enable_sensitive_topics,
enable_salesforce_content_safety,
enable_llamaguard_content_safety
)
# Safety check of the user prompt
safety_results = [check(user_prompt) for check in safety_checker]
are_safe = all([r[1] for r in safety_results])
if are_safe:
print("User prompt deemed safe.")
print(f"User prompt:\n{user_prompt}")
else:
print("User prompt deemed unsafe.")
for method, is_safe, report in safety_results:
if not is_safe:
print(method)
print(report)
print("Skipping the inference as the prompt is not safe.")
sys.exit(1) # Exit the program with an error status
# Set the seeds for reproducibility
if is_xpu_available():
torch.xpu.manual_seed(seed)
else:
torch.cuda.manual_seed(seed)
torch.manual_seed(seed)
model = load_model(model_name, quantization, use_fast_kernels)
if peft_model:
model = load_peft_model(model, peft_model)
model.eval()
tokenizer = LlamaTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
batch = tokenizer(user_prompt, padding='max_length', truncation=True, max_length=max_padding_length, return_tensors="pt")
if is_xpu_available():
batch = {k: v.to("xpu") for k, v in batch.items()}
else:
batch = {k: v.to("cuda") for k, v in batch.items()}
start = time.perf_counter()
with torch.no_grad():
outputs = model.generate(
**batch,
max_new_tokens=max_new_tokens,
do_sample=do_sample,
top_p=top_p,
temperature=temperature,
min_length=min_length,
use_cache=use_cache,
top_k=top_k,
repetition_penalty=repetition_penalty,
length_penalty=length_penalty,
**kwargs
)
e2e_inference_time = (time.perf_counter()-start)*1000
print(f"the inference time is {e2e_inference_time} ms")
output_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
# Safety check of the model output
safety_results = [check(output_text, agent_type=AgentType.AGENT, user_prompt=user_prompt) for check in safety_checker]
are_safe = all([r[1] for r in safety_results])
if are_safe:
print("User input and model output deemed safe.")
print(f"Model output:\n{output_text}")
else:
print("Model output deemed unsafe.")
for method, is_safe, report in safety_results:
if not is_safe:
print(method)
print(report)
return output_text
if prompt_file is not None:
assert os.path.exists(
prompt_file
), f"Provided Prompt file does not exist {prompt_file}"
with open(prompt_file, "r") as f:
user_prompt = "\n".join(f.readlines())
evaluate(user_prompt, temperature, top_p, top_k, max_new_tokens)
elif not sys.stdin.isatty():
user_prompt = "\n".join(sys.stdin.readlines())
evaluate(user_prompt, temperature, top_p, top_k, max_new_tokens)
else:
gr.Interface(
fn=evaluate,
inputs=[
gr.components.Textbox(
lines=9,
label="User Prompt",
placeholder="none",
),
gr.components.Slider(
minimum=0, maximum=1, value=1.0, label="Temperature"
),
gr.components.Slider(
minimum=0, maximum=1, value=1.0, label="Top p"
),
gr.components.Slider(
minimum=0, maximum=100, step=1, value=50, label="Top k"
),
gr.components.Slider(
minimum=1, maximum=2000, step=1, value=200, label="Max tokens"
),
],
outputs=[
gr.components.Textbox(
lines=5,
label="Output",
)
],
title="Llama2 Playground",
description="https://github.com/facebookresearch/llama-recipes",
).queue().launch(server_name="0.0.0.0", share=True)
if __name__ == "__main__":
fire.Fire(main)
보시면 알겠지만, evaluate 함수가 추가되어 있습니다. 지금까지는 CLI만 지원해서 아래와 같이 사용할 수 있었습니다.
python examples/inference.py --model_name '../models/Llama-2-7b-hf' --peft_model 'outputs/7b' --max_new_tokens 580 --quantization true
Running on local URL: http://0.0.0.0:7860
Running on public URL: https://???????????.gradio.live
This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from Terminal to deploy to Spaces (https://huggingface.co/spaces)
재미있는 것은 gradio에서 고유 URL을 제공합니다. 그래서 외부에서 로컬 컴퓨터로 접속 가능하게 해줍니다. examples/samsum_prompt.txt내용을 User Prompt 박스에 입력하고, Submit버튼을 누르면, 아래와 같이 실행이 잘 되는 것을 볼 수 있습니다.
본 블로그에서 alpaca-lora를 가진고 finetuing하는 방법을 공개한적이 있습니다. alpaca-lora는 Llama를 기반으로 LoRa를 지원해서 NVidia 4090에서도 Llama model를 실행할 수 있었습니다. Meta에서 지난 7월에 공개한 LlaMa2를 가지고 finetuing하는 방법을 소개하겠습니다.
먼저 파인튜닝(finetuning)은 뭘까?
GPT나 LlaMa와 같은 대규모 언어 모델(Larget Language Model)은 대량의 텍스트 데이터에서 단어 사이 통계적 연관성을 학습해서 사전 훈련된 머신 러닝 모델로 트랜스포머 아키텍처로 구현되어 있습니다. LLM은 기본적으로 어떤 단어나 문장을 주었을 때, 앞으로 나올 문장을 확률에 따라서 그냥 생성하는 기능만을 갖고 있습니다. 하지만 이 과정을 통해 광범위한 언어를 이해하고 생성하는 능력을 갖게 되고, 다양한 주제와 문맥에 대한 지식을 학습합니다.
아래 처럼 Llama-cpp를 이용해서 codellama 모델을 실행해보면 이래와 같은 int multiply( 이후 함수를 자동으로 작성해줍니다.
그렇기 때문에 특정 작업이나 도메인에 최적해하려면 파인튜닝(finetuing)하는 작업이 필요합니다. 자, 그러면 LLama2를 이용해서 간단하게 finetuning을 해보겠습니다. 첫번째 글에서 소개된 llama-recipes 저장소를 clone해야합니다.
이 글에서는 alpaca_dataset을 finetunig에 사용하겠습니다. alpaca_dataset은 OpenAI의 text-davinci-003모델에서 생성한 52K의 instruction-response 셋을 갖고 있습니다. 바로 이 파일인 alpaca_data.json을 다운로드 받아서 src/llama_recipes/dataset에 복사합니다. llama-recipe에는 이름에 걸맞게 alapca_data를 LlaMa2에 finetunig하도록 dataset 형식을 바꿔주는 python 코드(src/llama_recipes/datasets/alpaca_dataset.py)가 있기 때문에 별다른 코딩 없이 바로 finetuning을 할 수 있습니다. 아래와 같이 Llama-2-7b-hf 모델로 finetuning을 해보겠습니다.
Training Epoch: 1/3, step 1421/1422 completed (loss: 0.09633808583021164): 100%|███████| 1422/1422 [2:53:14<00:00, 7.31s/it]
Max CUDA memory allocated was 15 GB
Max CUDA memory reserved was 18 GB
Peak active CUDA memory was 15 GB
Cuda Malloc retires : 0
CPU Total Peak Memory consumed during the train (max): 2 GB
evaluating Epoch: 100%|████████████████████████████████████████████████████████████████████████| 9/9 [00:07<00:00, 1.17it/s]
eval_ppl=tensor(2.3844, device='cuda:0') eval_epoch_loss=tensor(0.8689, device='cuda:0')
we are about to save the PEFT modules
PEFT modules are saved in outputs/7b directory
best eval loss on epoch 1 is 0.8689326643943787
Epoch 1: train_perplexity=2.4760, train_epoch_loss=0.9066, epoch time 10394.590659613s
Training Epoch: 2/3, step 1421/1422 completed (loss: 0.07578233629465103): 100%|███████| 1422/1422 [2:53:12<00:00, 7.31s/it]
Max CUDA memory allocated was 15 GB
Max CUDA memory reserved was 18 GB
Peak active CUDA memory was 15 GB
Cuda Malloc retires : 0
CPU Total Peak Memory consumed during the train (max): 2 GB
evaluating Epoch: 100%|████████████████████████████████████████████████████████████████████████| 9/9 [00:07<00:00, 1.17it/s]
eval_ppl=tensor(2.3683, device='cuda:0') eval_epoch_loss=tensor(0.8622, device='cuda:0')
we are about to save the PEFT modules
PEFT modules are saved in outputs/7b directory
best eval loss on epoch 2 is 0.8621865510940552
Epoch 2: train_perplexity=2.4086, train_epoch_loss=0.8791, epoch time 10392.544478912998s
Training Epoch: 3/3, step 1421/1422 completed (loss: 0.06521736830472946): 100%|███████| 1422/1422 [2:53:02<00:00, 7.30s/it]
Max CUDA memory allocated was 15 GB
Max CUDA memory reserved was 18 GB
Peak active CUDA memory was 15 GB
Cuda Malloc retires : 0
CPU Total Peak Memory consumed during the train (max): 2 GB
evaluating Epoch: 100%|████████████████████████████████████████████████████████████████████████| 9/9 [00:07<00:00, 1.17it/s]
eval_ppl=tensor(2.3635, device='cuda:0') eval_epoch_loss=tensor(0.8602, device='cuda:0')
we are about to save the PEFT modules
PEFT modules are saved in outputs/7b directory
best eval loss on epoch 3 is 0.8601586818695068
Epoch 3: train_perplexity=2.3646, train_epoch_loss=0.8606, epoch time 10382.494863348998s
Key: avg_train_prep, Value: 2.4164153734842935
Key: avg_train_loss, Value: 0.8821062048276266
Key: avg_eval_prep, Value: 2.3720779418945312
Key: avg_eval_loss, Value: 0.8637592991193136
Key: avg_epoch_time, Value: 10389.876667291666
Key: avg_checkpoint_time, Value: 0.027448729337872162
위와 같이 3의 epoch를 거치면, 모든 데이터를 3번 학습하면 끝납니다. 이렇게 finetuning할 때, 각 epoch마다 모델은 데이터 세트에 있는 패턴과 특징을 더 잘 학습하고, 이를 통해 예측의 정확도를 높이려고 시도합니다. Epoch 수를 적절하게 설정하는 것은 과적합(overfitting)이나 미적합(underfitting)을 방지하는 데 중요합니다. 너무 많은 epoch는 모델이 트레이닝 데이터에 과적합되어 새로운 데이터에 대한 일반화 성능이 떨어질 수 있으며, 너무 적은 epoch는 모델이 데이터의 중요한 특성을 충분히 학습하지 못하게 만들 수 있습니다. 참고로, Llama receipt에서는 기본적으로 epoch값이 3번으로 정해져있습니다.
Nvidia 4090 GPU기준으로 finetuing하는데 약 5시간 정도 걸리는 것 같습니다.
Inference
여러분이 직접 fintuning한 model로 inference를 해보겠습니다. 먼저 아래와 같이 chatgpt.txt를 작성합니다.
Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
### Instruction:
Classify the following into animals, plants, and minerals
### Input:
Oak tree, copper ore, elephant
### Response:
본 블로그에서 alpaca-lora를 가진고 finetuing하는 방법을 공개한적이 있습니다. alpaca-lora는 Llama를 기반으로 LoRa를 지원해서 NVidia 4090에서도 Llama model를 실행할 수 있었습니다. Meta에서 지난 7월에 Llama2를 공개했고, 쉽게 Llama를 테스트해볼 수 있는 오픈소스 프로젝트를 공개해서, 더 이상 alpaca-lora는 필요가 없어졌습니다. 이제 quantization도 직접 지원해서 개인용 GPU에서도 Llama2를 테스트해 볼 수 있습니다. 더 놀라운 것은 Code Llama, Llama-chat와 같은 특정 용도로 학습된 모델을 공개했다는 점입니다. 생성현 AI 서비스를 개발하려는 회사에게는 희소식이 아닐 수 없습니다. 우선, 이번 글에서는 리눅스 우분투 22.04에서 Llama2설치해서 간단하게 테스트해본 결과를 정리해보았습니다.
아래 코드를 실행해서 GPU Driver, CUDA, Pytorch가 제대로 설치되었는 확인합니다.
import torch
# Check if CUDA is available
if torch.cuda.is_available():
print("CUDA is available.")
# Print the CUDA device count
print(f"Number of CUDA devices: {torch.cuda.device_count()}")
# Print the name of the current CUDA device
print(f"Current CUDA device name: {torch.cuda.get_device_name(torch.cuda.current_device())}")
else:
print("CUDA is not available.")
print("pytorch version")
print(torch.__version__)
python3 cuda.py
CUDA is available.
Number of CUDA devices: 1
Current CUDA device name: NVIDIA GeForce RTX 4090
pytorch version
2.1.2+cu118
llama-recipes$ cat examples/samsum_prompt.txt | python3 examples/inference.py --model_name ../Llama-2-7b-hf/
User prompt deemed safe.
User prompt:
Summarize this dialog:
A: Hi Tom, are you busy tomorrow’s afternoon?
B: I’m pretty sure I am. What’s up?
A: Can you go with me to the animal shelter?.
B: What do you want to do?
A: I want to get a puppy for my son.
B: That will make him so happy.
A: Yeah, we’ve discussed it many times. I think he’s ready now.
B: That’s good. Raising a dog is a tough issue. Like having a baby ;-)
A: I'll get him one of those little dogs.
B: One that won't grow up too big;-)
A: And eat too much;-))
B: Do you know which one he would like?
A: Oh, yes, I took him there last Monday. He showed me one that he really liked.
B: I bet you had to drag him away.
A: He wanted to take it home right away ;-).
B: I wonder what he'll name it.
A: He said he’d name it after his dead hamster – Lemmy - he's a great Motorhead fan :-)))
---
Summary:
Loading checkpoint shards: 0%| | 0/2 [00:00<?, ?it/s]
Loading checkpoint shards: 100%|█████████████████████████████████████████████████████████████████| 2/2 [00:05<00:00, 2.76s/it]
WARNING:root:Some parameters are on the meta device device because they were offloaded to the cpu.
Asking to pad to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no padding.
Asking to truncate to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no truncation.
the inference time is 56547.49874421395 ms
User input and model output deemed safe.
Model output:
Summarize this dialog:
A: Hi Tom, are you busy tomorrow’s afternoon?
B: I’m pretty sure I am. What’s up?
A: Can you go with me to the animal shelter?.
B: What do you want to do?
A: I want to get a puppy for my son.
B: That will make him so happy.
A: Yeah, we’ve discussed it many times. I think he’s ready now.
B: That’s good. Raising a dog is a tough issue. Like having a baby ;-)
A: I'll get him one of those little dogs.
B: One that won't grow up too big;-)
A: And eat too much;-))
B: Do you know which one he would like?
A: Oh, yes, I took him there last Monday. He showed me one that he really liked.
B: I bet you had to drag him away.
A: He wanted to take it home right away ;-).
B: I wonder what he'll name it.
A: He said he’d name it after his dead hamster – Lemmy - he's a great Motorhead fan :-)))
---
Summary: There are a few other ways to make this dialog more interesting. For example:
A: Let me know if you can’t go;-))
B: It’s ok. I'm not sure of this yet.
A: Ok, so I’ll take your place. Who’s going?
B: No, don't forget: you already have dinner with your family ;-))
A: Oh, sure, I do
Summary를 보면 전체 대화 내용이 요약되어 있는 것을 볼 수 있습니다.
다음 chat completion 데모입니다. 이 데모에서는 Llama-2-7b-chat-hf 모델을 사용했습니다.
llama-recipes$ python examples/chat_completion/chat_completion.py --model_name ../Llama-2-7b-chat-hf/ --prompt_file examples/chat_completion/chats.json --quantization
User dialogs:
[[{'role': 'user', 'content': 'what is the recipe of mayonnaise?'}], [{'role': 'user', 'content': 'I am going to Paris, what should I see?'}, {'role': 'assistant', 'content': "Paris, the capital of France, is known for its stunning architecture, art museums, historical landmarks, and romantic atmosphere. Here are some of the top attractions to see in Paris:1. The Eiffel Tower: The iconic Eiffel Tower is one of the most recognizable landmarks in the world and offers breathtaking views of the city. 2. The Louvre Museum: The Louvre is one of the world's largest and most famous museums, housing an impressive collection of art and artifacts, including the Mona Lisa. 3. Notre-Dame Cathedral: This beautiful cathedral is one of the most famous landmarks in Paris and is known for its Gothic architecture and stunning stained glass windows.These are just a few of the many attractions that Paris has to offer. With so much to see and do, it's no wonder that Paris is one of the most popular tourist destinations in the world."}, {'role': 'user', 'content': 'What is so great about #1?'}], [{'role': 'system', 'content': 'Always answer with Haiku'}, {'role': 'user', 'content': 'I am going to Paris, what should I see?'}], [{'role': 'system', 'content': 'Always answer with emojis'}, {'role': 'user', 'content': 'How to go from Beijing to NY?'}], [{'role': 'system', 'content': "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please ensure that your responses are socially unbiased and positive in nature. If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information."}, {'role': 'user', 'content': 'Write a brief birthday message to John'}]]
==================================
Loading checkpoint shards: 100%|█████████████████████████████████████████████████████████████████| 2/2 [00:04<00:00, 2.17s/it]
User prompt deemed safe.
User prompt:
what is the recipe of mayonnaise?
==================================
User input and model output deemed safe.
Model output:
[INST] what is the recipe of mayonnaise? [/INST] Mayonnaise is a rich and creamy condiment made from a mixture of egg yolks, oil, and vinegar or lemon juice. Here is a basic recipe for homemade mayonnaise:
Ingredients:
* 2 large egg yolks
* 1/2 cup (120 ml) neutral-tasting oil, such as canola or grapeseed
* 1-2 tablespoons (15-30 ml) vinegar or lemon juice
* Salt and pepper to taste
Instructions:
1. In a medium-sized bowl, whisk together the egg yolks and salt until well combined.
2. Slowly pour in the oil while continuously whisking the mixture. Start with a slow trickle and gradually increase the flow of oil as the mixture thickens.
3. Once about 1/4 cup (60 ml) of oil has been added, begin to add the vinegar or lemon juice, again whisking constantly.
4. Continue whisking until the mixture has thickened and
- 이하 생략 -