머신러닝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 작동미학
자연철학2024. 2. 12. 09:36

역대의 물리학 혁명을 거론할때 빼놓을 수 없는 주제가 바로 중력이다.

 

 가장 위대한 물리학자를 꼽으라는 투표에서 흔히 등장하는 것이 뉴튼, 맥스웰, 아인슈타인인데, 뉴튼과 아인슈타인이 같이 연결된 것이 바로 중력이다. 물리학이 천문학에서 유래했다면, 별들을 예측하는데 가장 중요한 발견이 중력에 대한 것이다. 그러나 이 중력을 둘러싼 해석은 역사적으로 다양했고, 아인슈타인이 등장한 이후에야 비로소 통일된 해석을 시작했다.

 

 무슨 이야기일까?

 

 다시 한번 숨을 가다듬고 생각해보자. 이 알 수 없는 우리 눈앞에 보이는 예컨데 "공", 다시 말하자면 "질량"이라는 것은 무엇일까?

 

 손으로 잡은 후, 멀리 던지면 땅에 떨어지는 이 무언가에 대한 이야기다. 가만히 생각해보면 우리는 이 존재를 아래 두가지로 인지할 수 있다는 것을 경험상 알고 있다(그리고 이는 뉴튼이 맨 처음 수학적으로 정리한 형태이기도 하다)

 

1. 밀거나 멈추는데 힘이 들어간다(F = ma, 관성질량)

2. 두 질량이 있는 존재는 서로 당긴다(뉴튼의 중력 계산, F = G * m1 * m2 / r^2, 그래서 지구쪽으로 떨어진다. 중력질량)

 

 그리고 당연히 인류는 아인슈타인 이전까지 이 둘을 이렇게 서로 다른 것으로 정의해서 사용하였다. 어떤 이들에게는 사실 같아 보이는데, 사실은 전혀 다른 것이라는 것을 알 수 있다. 어떻게 해도 둘을 같게 해석할 수가 없다. 공을 빠르게 하는데 힘이 들어간다는 사실이, 두 공이 서로 당긴다는 사실과 연관짓기가 힘든 것이다.

 

 이는 물리학자들에게 각기 관성질량과 중력질량으로 구분되었고, 초기에는 이 둘이 같다는 여러가지 증명하려는 시도가 있었다. 피사의 사탑에서 무거운 공과 가벼운 공을 낙하시키는 실험이 그렇다. 중력과 가속도가 동시에 반영되는 상황에서는 그래서 질량에 상관없이 동일한 운동을 보인다. 공기가 없는 와중에 포물선을 그리며 날아가는 공도 그러하다. 그것들은 본래의 질량과 관련이 없다. 관성 질량과 중력 질량은 마치 동일한 것처럼 작동한다는 사실에 늘 과거의 물리학자들은 의아해했다.

 

 그런데 이 둘을 합쳐서 생각해볼 수 있는 방식이 존재한다. 그것은 대체 어떤 것일까? 가속하기 어렵다는 사실과 두 질량이 서로를 당긴다는 사실을 어떻게 하나의 원리로 바라볼 수 있을까?

 

여기에 아인슈타인이 주장했던 등가 원리(equivalance principle)는 그 중요한 열쇠가 된다. 즉, 엘레베이터 안에 갇혀있어서 밖을 볼 수 없는 상황에서는 이 두가지를 구별할 수 없다는 이야기다.

 

 밖에서 엘레베이터를 누가 밀어서 가속하면, 그 안의 내가 뒤로 밀릴텐데 이것이 가속에 의한 것인지, 아니면 지구같은 어떤 큰 질량이 옆에 있어서 중력에 의해 그렇게 되는지 알 수 없다는 사실이다. 이것이 바로 아인슈타인의 깨달음이며 등가원리의 기본이다. 그 둘을 구별할 수가 없다. 질량의 존재가 가속을 방해하거나 질량끼리의 당기는 힘을 만들어내면 된다.

 

 어떻게 이런 것이 가능할까? 놀랍게도 바로 질량이라는 것이 시공간을 휘면 그렇게 된다. 특수 상대성이론 등 여러가지 속에 그 기초를 닦은 아인슈타인은 그렇게 이 질량을 바라보는 시각을 혁신했다.

 

 그렇다. 질량은 시공간을 휜다. 그렇게 두 질량이 시공간을 휘면 서로에게 다가가려고 하는 방향으로 움직인다. 그것이 가장 자연스러운 상태이기 때문이다. 홀로 있을때는 어떠한가, 시공간이 휘면서 질량은 스스로를 감가속이 없는 상태로 유지하고자 하기 때문에(자기 스스로에게 낙하) 가속에는 힘이 들게 된다. 질량이 단독으로 존재 할 때도, 여러 질량이 같이 있을때도, 시공간의 휘어진 형상은 이 질량은 가속하기 어렵게 또한 서로에게 당겨지도록 하는 힘의 장을 만들어낸다. 아인슈타인의 장 방정식(Field Equation)이다.

 

 아래의 계량 텐서는 각 공간의 구조를 결정짓고, 이는 각 요소들간의 미분관계를 담는 리치 텐서와 질량/에너지의 분포를 다룬 스트레스-에너지 텐서를 통해 결정된다.

아인슈타인 장 방정식, 나무위키 발췌, 다양한 형태가 존재한다. 질량으로 인한 휘어진 시공간을 미분으로 나타낸다.

 

 이렇게 통합되어 설명하고 나면, 시공간의 휘어짐이 임계치를 넘는 블랙홀이라던가, 거대 질량 주변의 시간이 느리게 간다던가 하는 효과를 모두 계산할 수 있게 되었고, 지금은 관성질량/중력질량으로 구분해서 이해하던 시기보다도 훨씬 더 대규모의 자연 현상을 정확하게 계산할 수 있게 된 것이다.

 

 즉 관성질량과 중력질량이라는 두가지 관점을 장방정식으로 풀어낸 것이 아인슈타인의 업적이 되겠다. 서로 다른 두개를 하나의 틀에서 볼 수 있게 되자 기존의 상황이 더 명확해졌고, 훨씬 더 극단적인 상황에서의 예측이 가능해지게 된 것이다.그곳에는 공간의 휨뿐만 아니라 시간까지도 고려되어야 한다는 것이 그의 결론이 된 셈이다. 그렇게 그의 업적을 바라볼 수가 있다. 인류 역사의 기록에 남겨진, 기막힌 통찰의 순간 중의 하나이다. 우리가 향후에 또다른 통합된 이론을 가지게 된다면 왜 그때는 이것이 서로 같다는 것을 몰랐을까 라고 한탄할 주제에 대한 사전 예시가 아닌가.

 

 장방정식 관련해서는 아래 차동우 교수의 짧은 강의를 참고해보자.

https://www.youtube.com/watch?v=E3o1KahfWMw&t=1204s

 

반응형
Posted by 작동미학
자연철학2024. 2. 12. 09:35

 일반인에게는 조금 낯설 수도 있지만, 세기의 천재를 지칭할때, 물리학자들은 제임스 맥스웰(James Clerk Maxwell, 1831~1879)을 빼놓지 않는다. 그는 이 블로그에 있는 맥스웰의 도깨비를 창조해낸 인물이기도 하지만, 전자기학의 수학적 체계를 완성한 시조격으로 불리기도 한다.

 

 결론적으로 이야기하면 그는 전자기와 빛에 관한 이론 통합된 관점을 제공했다.

 

 맥스웰이 활동하던 시기는, 전기와 자기, 그리고 빛은 모두 서로 다른 존재였다. 자석으로 나침반을 만들었고, 특정 상황에서 발생하는 전기에 대해 연구하였고, 따로 광학이 연구되었지만 서로간의 그 상관관계가 있다는 것은 정확히 알지 못했다.  그런 와중에 맥스웰은 아래와 같은 방정식으로 전기와 자기의 성질에 대해 과거 학자들의 내용을 미적분으로된 방정식으로 정리했다. 패러데이가 실험만으로 전자기 유도 현상을 설명한 것과 다르게 이론 체계를 잡은 것이다.

 

 그리고 그 내용은 아래와 같다.

 

https://ko.wikipedia.org/wiki/%EC%A0%9C%EC%9E%84%EC%8A%A4_%ED%81%B4%EB%9F%AC%ED%81%AC_%EB%A7%A5%EC%8A%A4%EC%9B%B0

 

1. 어떤 전하를 둘러싼 닫힌 곡면을 통해 나가는 전기력선 수는 그 전하에 의해 결정된다(전기력, 쿨롱의 법칙, E는 전기장, 전하는 음극이나 양극 단독으로 존재해서 힘을 발휘한다)

2. 임의의 폐곡면을 나가는 자기 선속이 0이다(자기력, N극이나 S극은 독립해서 존재하지 않는다. 자기력은 나가면 다시 돌아온다. B는 자기장)

3. 자속 밀도의 시간에 따른 변화는 전기장을 생성한다(패러데이의 유도 법칙, E와 B의 관계)

4. 시간에 따라 변화하는 전기장과, 전류에 의해 자기장 변화를 나타낸다(from 앙페르의 법칙, 외르스테드)

 

 재미있는 것은 이 법칙들에 의해서 공간 속에서 전기와 자기가 서로를 유도하며 전파되는, 전자기파 파동방정식이 유도된다는 사실이다. 그리고 그 전자기파의 진행 속도는 '광속'과 같다. 이 모든 것을 단순한 방정식으로 정리하고 증명한 것이 맥스웰의 업적이다.

 

 그이전에 인류는 자석과, 전기, 빛이 서로 독립적으로 움직인다고 생각했는데, 맥스웰은 상기 4개의 방정식으로 정리한 후 이를 통해 전자기 파동의 파동방정식을 유도해내고, 그것이 서로 영향을 주는 얽혀있는 현상이라는 것을 입증하고 수학적으로 나타낸것이다. 그리고 이 결과에 의해 전자기파 파동이 존재하고, 그 속도는 광속인 것. 즉 빛이라는 것이 전자기파 현상이라는 것을 입증한 셈이다.

 

 그렇게 인류는 이 알 수 없는 현상들을 하나로 설명해낼 수 있게 되었고, 이는 모든 무선 통신과 전기/자기의 제어에 대한 예측이나 계산을 할 수 있게 된 것이다. 리처드 파인만은 이러한 맥스웰의 업적을 인류 문명의 발견 중에 가장 중요한 것 중의 하나로 꼽았다. 아인슈타인의 중력에 대한 해석과 함께, 인류사의 자연에 대한 통합 해석에 한 획을 그은 사건이라고 볼 수 있다.


리처드 파인만 (1964): "인류의 역사를 장기적으로 보면, 예를 들어 지금으로부터 10,000년 후로 볼 때 19세기의 가장 중요한 사건이 맥스웰의 전기역학의 법칙 발견으로 평가될 것이라는 데는 의심의 여지가 없다. 미국 남북 전쟁은 같은 10년 동안 일어난 맥스웰의 중요한 과학적 사건과 비교할 때 변방의 무의미한 사건으로 변할 것이다.", 인용 : https://ko.wikipedia.org/wiki/%EC%A0%84%EA%B8%B0%EC%99%80_%EC%9E%90%EA%B8%B0%EC%97%90_%EA%B4%80%ED%95%9C_%EB%85%BC%EB%AC%B8%EC%A7%91


 

아래는 관련해서 김갑진 교수의 설명을 담은 youtube영상이다. 그의 업적을 살펴보자.

https://www.youtube.com/watch?v=OTF-oP7io_M&t=710s

 

반응형
Posted by 작동미학