머신러닝AI2024. 4. 6. 01:05

이 문서는 ubuntu 22.04 + NVidia RTX 4080 H/W 하에서 진행하였다.

 

Stable Diffusion을 웹인터페이스 학습시킬 수 있는 kohya_ss 프로젝트가 존재한다. 여러가지 보조 기구를 제공해주고, 이미지가 있으면 자동으로 설정을 하고 학습까지 시켜준다. 단 아래는 전체 학습은 아니고 LoRA 즉 소규모의 부분 튜닝만 해주는 방법이다.

(그정도만으로도 꽤 성능이 향상된다고 알려져있다.)

 

https://github.com/bmaltais/kohya_ss

 

0. 아래를 먼저 진행한다

 

우선 다음을 준비할 필요가 있으며, CUDA와 cudnn은 아래 링크를 참조하여 설치한다. https://infoengineer.tistory.com/96

 

  1. CUDA 11.8

  2. python 3.10.9이상~3.11미만

  3. cudnn 8.7.0

 

따라서 용량이 충분한 디렉토리에서 아래와 같이 입력한다.

 

$ conda create -n kohya_ss python=3.10

$ conda activate kohya_ss

$ git clone https://github.com/bmaltais/kohya_ss

$ cd kohya_ss

$ sudo apt update -y && sudo apt install -y python3-tk               #python3-tk를 필요로 하는데 일반적으로 미설치되어있다

$ ./setup.sh

Skipping git operations.
Ubuntu detected.
Python TK found...
Switching to virtual Python environment.
22:33:35-474863 INFO     Python version is 3.10.14 (main, Mar 21 2024, 16:24:04) [GCC 11.2.0]                                                                                                                   

..

22:36:35-016860 INFO     Configuring accelerate...                                                                                                     
22:36:35-017576 WARNING  Could not automatically configure accelerate. Please manually configure accelerate with the option in the menu or with:       
                         accelerate config. 

 

위와 같은 accelerate warning이 뜨면 직접 실행해준다.

 

$ cd venv/bin

$ ./accelerate config

------------------------------------------------------------------------------------------------------------------------------------------------------In which compute environment are you running?
This machine                                                                                                                                           
-------------------------------------------------------------------------------------------------------------------------------------------------------Which type of machine are you using?                                                                                                                   
No distributed training                  #GPU가 여러개일 경우만 분산선택                                                                                                          
Do you want to run your training on CPU only (even if a GPU / Apple Silicon / Ascend NPU device is available)? [yes/NO]:  #계속엔터입력                           
Do you wish to optimize your script with torch dynamo?[yes/NO]:                                                                                        
Do you want to use DeepSpeed? [yes/NO]:                                                                                                                
What GPU(s) (by id) should be used for training on this machine as a comma-seperated list? [all]:all                                                   
-------------------------------------------------------------------------------------------------------------------------------------------------------Do you wish to use FP16 or BF16 (mixed precision)?                                                                                                     
fp16                                                                                                                                                   
accelerate configuration saved at /home/xxxx/.cache/huggingface/accelerate/default_config.yaml                                                        

 

$ cd ../..

 

/*------- 이때 Stable Diffusion의 최신 버전인 Flux.dev를 학습시키려고 하면 아래를 실행 후 다시 setup.sh를 실행하고 아니면 이 다음으로 ./gui.sh 실행으로 넘어간다.

 

$ git fetch origin

$ git checkout -b sd3-flux.1 origin/sd3-flux.1

$ git branch

  master
* sd3-flux.1 <-- 확인

$ pip install --use-pep517 -r requirements.txt

$ ./setup.sh

 이후 동일진행하되 이제는 나중에 fp16대신 bf16을 사용하고, nvidia이며 numa efficiency를 yes로 설정한다.

 

-------------------------------------------------------------------------------------*/

 

 

 

 

 

$ ./gui.sh

22:53:19-311775 INFO     Kohya_ss GUI version: v23.0.15                                                                                                
22:53:19-399403 INFO     Submodule initialized and updated.                                                                                            
22:53:19-402531 INFO     nVidia toolkit detected                                                                                                       
22:53:20-026297 INFO     Torch 2.1.2+cu118                                                                                                             
22:53:20-029252 ERROR    Could not load torch: cuDNN version incompatibility: PyTorch was compiled  against (8, 7, 0) but found runtime version (8, 5, 
                         0). PyTorch already comes bundled with cuDNN. One option to resolving this error is to ensure PyTorch can find the bundled    
                         cuDNN.Looks like your LD_LIBRARY_PATH contains incompatible version of cudnnPlease either remove it from the path or install  
                         cudnn (8, 7, 0)      

 

---------------------------------------------------------------------------------------------------------------------------

혹시 위와 같은 cudnn 라이브러리 오류가 나면 cudnn 8.7.0 for CUDA11.8을 NVIDIA에서 다운받아 설치해주자.

CUDA 폴더에 cudnn의 파일만 잘 복사해주면 된다.

 

$ tar xvfz cudnn-linux-x86_64-8.7.0.84_cuda11-archive.tar.xz       #nvidia 사이트에서 cudnn archive 다운로드가능

#아래와 같이 파일을 복사하여 설치한다.

$ sudo cp -P cudnn-linux-x86_64-8.7.0.84_cuda11-archive/include/cudnn.h /usr/local/cuda-11.8/include/
$ sudo cp -P cudnn-linux-x86_64-8.7.0.84_cuda11-archive/lib/libcudnn* /usr/local/cuda-11.8/lib64/
$ sudo chmod a+r /usr/local/cuda-11.8/lib64/libcudnn*

---------------------------------------------------------------------------------------------------------------------------

cudnn 버전 오류가 없다면 아래와 같이 gui.sh를 실행해서 웹서버를 띄우고, 웹에 접속한다.

 

$ ./gui.sh

0:35:53-556439 INFO     Kohya_ss GUI version: v23.0.15                                                                                                
00:35:53-578951 INFO     Submodule initialized and updated.                                                                                            
00:35:53-579987 INFO     nVidia toolkit detected                                                                                                       
00:35:54-373093 INFO     Torch 2.1.2+cu118                                                                                                             
00:35:54-377101 INFO     Torch backend: nVidia CUDA 11.8 cuDNN 8700                                                                                    
...                                                                                         
Running on local URL:  http://127.0.0.1:7860

실행 상태에서 브라우저를 띄워 http://127.0.0.1:7860 에 접속한다.

드디어 kohya_ss의 web UI가 뜬다.

kohya_ss의 GUI

 

이제 본격적인 학습을 위해 이미지를 준비하고 이 이미지의 script를 구할 차례다.

 

1. 학습에 추가시킬 이미지를 마련한다.

 

  대략 500*500 이상 해상도로 준비해두면, 자동으로 caption을 생성해서 학습에 사용할 수 있다. 특정 폴더에 모아두고, 시험목적이라면 10장 정도면 되겠다.

 

2. 자동으로 captioning(이미지별 설명을 담은 txt 파일 자동 생성)을 해보자.

 

 아래와 같이 Utilities->Captioning의 BLIP Captioning에서 image folders를 선택 한 후 맨 오른쪽 아래 Caption Images를 실행한다. 해당 폴더에 이미지와 같은 이름의 txt파일이 생겼음을 알 수 있다.

image captioning
생성된 이미지 captioning 파일 예시 (원래는 이미지만 있었는데 txt가 추가됨)

 

3. 이제 LoRA탭/Training중간의 Dataset Preparation으로 가보자. 오른쪽 화살표를 클릭해서 열자.

LoRA/Training 메뉴의 하단 Dataset Preparation을 설정하자

 

 Dataset Preparation설정 들 중에서 Instance prompt에는 이 LoRA를 활성할 특이한 이름을 넣고, Class prompt는 이 훈련을 하는 이미지들의 적당한 보통 명사를 지정한다. 그리고 가장 중요한 학습할 이미지의 폴더를 입력해주고, 이 모든 학습의 중간 데이터 등을 저장할 폴더를 하나 추가로 지정해주자(Destination training directory).

 그리고 차례로 하단의 'Prepare training data'버튼과 'Copy info to Folder Tab'버튼을 각기 차례대로 누르면, 학습할 이미지가 해당 destination folder로 이동되어 준비되고, 이 설정들이 상단의 Traing정보로 복사된다(캡춰 화면에서는 보이지 않는 위쪽에 반영된다)

Instant Prompt/Class prompt, trainging images 폴더 등 정의하자

 

 

3. Parameters를 변경한다

 그 다음은 이제 Parameters 를 열어서(Dataset Preparation바로 위) 아래와 같이 Presets를 sd15 - EDG_LoraOptiSettings로 예시 선택해보자. Epoch을 필요하면 약간 늘려준다. 4080으로 1 epoch당 몇분이 소요됨을 가정하자. 학습 진행 중에 대략 10GB전후의 GPU메모리가 사용되었다.

Presets를 선택해준다.

 

 

4. 맨 상단의 설정을 최종으로 정하자.

 그리고 맨 상단의 Pretrained model name은 적절히 기본 모델을 선택하자. 여기서는 sd-v1-5.safetensors 를 복사해두고 적용했다. 이 모델은 Stable Diffusion 유명한 기본 모델이며. 다른 모델을 써도 당연히 된다.

 

Pretrained model name을 선택하자 / safetensors와 fp16도 선택해주었다.

 

이제 맨 하단의 Start training을 누르면 학습이 시작된다.

 

한 epoch씩 학습이 진행된다.

 

 상기 케이스의 경우는 destination folder(/work2/kohya_ss/dest/)의 model 폴더에 75mb정도 크기의 safetensors형태의 LoRA모델이 생겼음을 알 수 있다. 이 만들어진 LoRA는 이제 Stable Diffusion에 잘 알려진 방법대로 원래 모델(여기서는 sd-v1-5.safetensors)과 함께 넣어 사용하면 되겠다. civit.ai의 LoRA들이 모두 이런 방식의 학습에 의해서 제공된다.

 

 

5. Flux.1 은 아래를 참고하자

 

반응형
Posted by 작동미학
머신러닝AI2024. 3. 1. 09:32

 

개인비서 서비스가 LLM덕분에 가시권에 들어왔다. Siri도 그렇고 많은 사실은 많은 회사들이 이 개인비서를 꿈꿔왔다. 바쁜 현대인들은 대신 해줬으면 하는게 많기 때문이다. 인공지능이라는 이름으로 그동안 많은 서비스들이 이를 지향했는데, 사실 잘 안되었다. if-then 으로는 처리에 한계가 있었기 때문이다. 곧 사람들이 외면하기가 일쑤였다.

ChatGPT 생성


 그런데 LLM은 이미 OpenAI를 통해 어느정도의 사용자 경험을 인식시키고 있다. 청소년 정도의 응대만 가능해도 맡기고 싶은 일이 얼마나 많은가.

 

 하루를 한번 돌이켜보자. 몇시에 일어나서 밤사이 특별한 일은 없었는지(특히 해외 등), 날씨는 어떻고 우산을 가져갈지 말아야할지, 출근길에 특이한 정체나 사건은 없는지, 출근해서는 업무를 수행하기 위한 수많은 것들도 그렇고(임원들의 비서가 처리하는 수많은 것), 식당을 알아보고 일정을 조절하고는 기본이다.

 

 내 생활에서는 자녀를 위한 여러가지 교육 정보도 아쉽다. 내가 사는 지역에 특이한 일은 없는지, 내가 관심있는 주제는 어떤 변화가 있는지, 내 자산에는 알아야할 특이 정보는 없을지, 고민에 대한 상담, 여러가지 장기적인 관점의 진단은 특정 품질 이상으로 이런 것을 모두 챙겨줄 수 있다면 몇만원의 돈이 무엇이 아깝겠는가. 따라서 이 분야의 대형 서비스가 나올 수 있다고 생각한다.

 

 GPTs가 이런 비서 시장을 노릴테지만 여러가지 각각의 주제별로 조금더 전문화하고 다듬는 일이 필요하다. 그러다보면 각 전문분야별로 실제 정보나 컨텐츠가 부족하게 된다. 이러다보면 세상의 검색이나 여러가지 서비스가 API형태로 LLM이 쓸 수 있도록 변형되는 일이 가속화될것이다. 그렇게 더 발전하면 사람들이 직접 그 웹사이트에 들어가는 것보다는 API화 되어 LLM이 쓰는 양이 더 많아지고, 이제 사람들이 직접 사이트에 들어가는 것은 구식으로 느껴질 날이 올지도 모르겠다.

 

 이런 기술 환경의 핵심에는 Langchain같은 LLM을 다양하게 agent형으로 활용하는 오픈소스와 기존의 각종 서비스를 크롤링하고 API화되어가는 세상이 오는것. 비서 역할을 할 수 있는 사람이 있는 회사 임원들은 업무 사이트에 잘 들어가지 않는다. 사이트를 배우는 일도 큰 부담이기 때문이다. 이런 일을 LLM이 대신 해주는 세상이 곧 펼쳐지겠다.

 

 이런 변화가 오고있다. 영화 Her의 비서가 곧 세상을 점령해나갈 태세다.

반응형
Posted by 작동미학
머신러닝AI2024. 2. 23. 01:32

Gemma 공개후 곧바로 파인튜닝 가능한 가이드가 공개되었다.

https://adithyask.medium.com/a-beginners-guide-to-fine-tuning-gemma-0444d46d821c

 

A Beginner’s Guide to Fine-Tuning Gemma

A Comprehensive Guide to Fine-Tuning Gemma

adithyask.medium.com

 

gemma-2b-it 모델의 quantized 버전 정도는 16GB GPU로도 파인튜닝 테스트를 해볼 수 있다.

 

상기 가이드대로 GPU환경에서 python을 설치한다.

$ conda create -n gemma python=3.11

$ conda activate gemma

$ pip install bitsandbytes==0.42.0
$ pip install peft==0.8.2
$ pip install trl==0.7.10
$ pip install accelerate==0.27.1
$ pip install datasets==2.17.0
$ pip install transformers==4.38.0

 

아래 소스를 통해 샘플 데이터 셋을 허깅페이스에서 다운받아 파인튜닝해서 결과를 얻어볼 수 있다.

이때 허깅 페이스에 미리 계정을 만든 후 WRITE 가능한 token으로 로그인을 미리 해두자. WRITE 권한으로 생성한 토큰으로는 모델을 huggingface에 업로드 하는 것도 가능하다(아래 소스의 맨 마지막 두줄)

 

$ huggingface-cli login
...
Token: 

$ huggingface-cli whoami
Justik (필자의 profile이다)

 

아래 코드를 실행한다. LORA를 통한 경량형 튜닝 정도는 할 수 있게 된다. gemma-7b-it의 경우는 16gb에서는 메모리가 부족하다. (본래 글에서는 A100을 추천하고 있다.) gemma-2b-it의 경우는 아래의 코드로 10~14gb정도의 메모리를 소모한다.

import json
import pandas as pd
import torch
from datasets import Dataset, load_dataset
from huggingface_hub import notebook_login
from peft import LoraConfig, PeftModel
from peft import LoraConfig, get_peft_model
lora_config = LoraConfig(
    r=64,
    lora_alpha=32,
    target_modules=['o_proj', 'q_proj', 'up_proj', 'v_proj', 'k_proj', 'down_proj', 'gate_proj'],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
) 
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments,
    pipeline,
    logging,
)
from trl import SFTTrainer

notebook_login()

#model_id = "google/gemma-7b-it"
# model_id = "google/gemma-7b"
model_id = "google/gemma-2b-it"
#model_id = "google/gemma-2b"

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

#model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=lora_config, device_map={"":0})
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map={"":0})
#model = AutoModelForCausalLM.from_pretrained(model_id, device_map={"":0})
tokenizer = AutoTokenizer.from_pretrained(model_id, add_eos_token=True)
{
    "instruction": "Create a function to calculate the sum of a sequence of integers.",
    "input":"[1, 2, 3, 4, 5]",
    "output": "# Python code def sum_sequence(sequence): sum = 0 for num in sequence: sum += num return sum"
}

dataset = load_dataset("TokenBender/code_instructions_122k_alpaca_style", split="train")

def generate_prompt(data_point):
    """Gen. input text based on a prompt, task instruction, (context info.), and answer

    :param data_point: dict: Data point
    :return: dict: tokenzed prompt
    """
    prefix_text = 'Below is an instruction that describes a task. Write a response that appropriately completes the request.\\n\\n'
    # Samples with additional context into.
    if data_point['input']:
        text = f"""<start_of_turn>user {prefix_text} {data_point["instruction"]} here are the inputs {data_point["input"]} <end_of_turn>\\n<start_of_turn>model{data_point["output"]} <end_of_turn>"""
    # Without
    else:
        text = f"""<start_of_turn>user {prefix_text} {data_point["instruction"]} <end_of_turn>\\n<start_of_turn>model{data_point["output"]} <end_of_turn>"""
    return text

# add the "prompt" column in the dataset
text_column = [generate_prompt(data_point) for data_point in dataset]
dataset = dataset.add_column("prompt", text_column)
dataset = dataset.shuffle(seed=1234)  # Shuffle dataset here
dataset = dataset.map(lambda samples: tokenizer(samples["prompt"]), batched=True)

dataset = dataset.train_test_split(test_size=0.2)
train_data = dataset["train"]
test_data = dataset["test"]

model = get_peft_model(model, lora_config)
trainable, total = model.get_nb_trainable_parameters()
print(f"Trainable: {trainable} | total: {total} | Percentage: {trainable/total*100:.4f}%")

import transformers

from trl import SFTTrainer

tokenizer.pad_token = tokenizer.eos_token
torch.cuda.empty_cache()
trainer = SFTTrainer(
    model=model,
    train_dataset=train_data,
    eval_dataset=test_data,
    dataset_text_field="prompt",
    peft_config=lora_config,
    args=transformers.TrainingArguments(
        per_device_train_batch_size=1,
        gradient_accumulation_steps=4,
        warmup_steps=0.03,
        max_steps=100,
        learning_rate=2e-4,
        logging_steps=1,
        output_dir="outputs",
        optim="paged_adamw_8bit",
        save_strategy="epoch",
    ),
    data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),
)

# Start the training process
trainer.train()

new_model = "gemma-2b-it-finetune" #Name of the model you will be pushing to huggingface model hub
# Save the fine-tuned model
trainer.model.save_pretrained(new_model)

# Merge the model with LoRA weights
base_model = AutoModelForCausalLM.from_pretrained(
    model_id,
    low_cpu_mem_usage=True,
    return_dict=True,
    torch_dtype=torch.float16,
    device_map={"": 0},
)
merged_model= PeftModel.from_pretrained(base_model, new_model)
merged_model= merged_model.merge_and_unload()

# Save the merged model
merged_model.save_pretrained("merged_model",safe_serialization=True)
tokenizer.save_pretrained("merged_model")
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"


def get_completion(query: str, model, tokenizer) -> str:
  device = "cuda:0"
  prompt_template = """
  <start_of_turn>user
  Below is an instruction that describes a task. Write a response that appropriately completes the request.
  {query}
  <end_of_turn>\\n<start_of_turn>model
  
  """
  prompt = prompt_template.format(query=query)
  encodeds = tokenizer(prompt, return_tensors="pt", add_special_tokens=True)
  model_inputs = encodeds.to(device)
  generated_ids = model.generate(**model_inputs, max_new_tokens=1000, do_sample=True, pad_token_id=tokenizer.eos_token_id)
  # decoded = tokenizer.batch_decode(generated_ids)
  decoded = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
  return (decoded)

result = get_completion(query="code the fibonacci series in python using reccursion", model=merged_model, tokenizer=tokenizer)
print(result)


# Push the model and tokenizer to the Hugging Face Model Hub
# merged_model.push_to_hub(new_model, use_temp_dir=False)
# tokenizer.push_to_hub(new_model, use_temp_dir=False)

 

이렇게 hugging face hub에 올려진 모델은 아래와 같다.

https://huggingface.co/Justik/gemma-2b-it-finetune

 

Justik/gemma-2b-it-finetune · Hugging Face

Model Card for Model ID Finetune model of Google Gemma 2b it Model Details Model Description This is the model card of a 🤗 transformers model that has been pushed on the Hub. This model card has been automatically generated. Developed by: Justin Kim Fin

huggingface.co

 

반응형
Posted by 작동미학