Preview:

Machine Learning vs Deep Learning

머신러닝: 인공지능의 한 분야로 data의 Pattern을 학습. (이때, 비교적 적은 양의 구조화된 data로도 작동가능)

딥러닝: 머신러닝의 한 분야로 복잡한 구조, 많은 계산리소스 및 데이터를 필요로 함.

 

 

 

Transformer(Attention is All You Need-2017)

Transformer 모델의 핵심:

 input sequence 병렬처리

 Only Use Attention Mechanism (Self Attention)
 순차적처리, 반복연결, 재귀 모두 사용❌


Transformer 모델구조:

 Embedding: token2dense-vector (이때, 단어간의 의미적 유사성을 보존하는 방향으로 모델이 학습된다.)
 Positional Encoding: input sequence의 token위치정보를 추가로 제공
 Encoder&Decoder: Embedding+PE라는 학습된 vector를 Input으로 받음(벡터 값은 Pretrained weight or 학습과정중 최적화됨.)
- MHA & FFN: token간 관계를 학습, FFN으로 각 단어의 특징벡터 추출 (이때, 각 Head값은 서로 다른 가중치를 가져 input sequence의 다양한 측면 포착가능.) 
- QKV: Query(현재위치에서 관심있는부분의 벡터), Key(각 위치에 대한 정보의 벡터), Value(각 위치에 대한 값 벡터)

ex) The student studies at the home 
query: student
 --> Q: student정보를 얻기 위한 벡터값
 --> K: The, studies, at, the, home 벡터값
 --> V: 문맥, 의미등의 관련정보에 대한 벡터값
 --> 3-Head라면: 각 헤드별 역할이 Syntax, Semantics, Pragmatics 등에 집중할 수 있다는 것.

 

Huggingface Transformers

Library 소개

Tokenizer 

보통 subword로 token화(token으로 분할)하는 과정을 진행.
부수적으로 "텍스트 정규화, 불용어제거, Padding, Truncation 등" 다양한 전처리 기능도 제공한다.


Diffusers Library

txt-img생성관련 작업을 위한 라이브러리로 Stable Diffusion, DALL-E, LDM 등 다양한 생성모델을 지원.
- DDPM, DDIM, LDM등 다양한 Diffusion기반 알고리즘 제공
- Batch Inference, 병렬, 혼합정밀도학습 등 지원


Accelerate

분산전략을 간단히 추상화해 API로 제공, FP16 및 BF16등의 낮은 혼합정밀도학습을 "자동지원"
- 분산학습 지원: Data Parallel, Model Parallel 등 지원.
- Automatic Mixed Precision지원: FP16, FP32 등 data형식을 자동으로 혼합, 메모리사용량
, 속도

- Gradient Accumulation: 여러 미니배치의 그래디언트를 누적하여 큰 배치 효과를 내는 기법
- Gradient Checkpointing: 중간 activation계산을 저장하는 대신, 필요할 때 재계산하는 방법

Model 설정

모델 설정 클래스는 모델구조와 hyperparameter값을 "딕셔너리"형태로 JSON파일에 저장한다.
따라서 모델을 불러오면 모델가중치와 함께 이 값이 불러와진다. (아래 사진처럼)




PretrainedConfig & ModelConfig

마찬가지로 모델구조, hyperparameter를 저장하는 딕셔너리를 포함
[예시인자 설명]: 
 - vocab_size: 모델이 인식가능한 고유토큰 수
 - output_hidden_states: 모델의 모든 hidden_state를 출력할지 여부
 - output_attentions: 모델의 모든 attention값을 출력할지 여부
 - return_dict: 모델이 일반 튜플대신, ModelOutput객체를 반환할지 결정.
각 모델 구조별 PretrainedConfig를 상속받은 전용 모델 설정 클래스가 제공된다.
(ex. BertConfig, GPT2Config 혹은 아래 사진처럼...)

InternVisionConfig를 직접 인스턴스화해 설정하는 예시

이때, 설정값이 잘못되면 모델성능이 크게 떨어질 수 있기에 보통 "from_pretrained"를 이용해 검증된 pretrained학습설정값을 불러온다.



PreTrainedTokenizer & ModelTokenizer & PretrainedTokenizerFast

[예시인자 설명]: 
 - max_model_input_sizes: 모델의 최대입력길이

 - model_max_length: tokenizer가 사용하는 모델의 최대입력길이
(즉, 토크나이저의 model_max_length는 모델의 max_model_input_sizes보다 크지 않도록 설정해야 모델이 정상적으로 입력을 처리할 수 있다.

 - padding_side/truncation_side: padding/truncation위치(left/right) 결정

 - model_input_names: 순전파시 입력되는 tensor목록(ex. input_ids, attention_mask, token_type_ids)

cf) decode메서드를 사용하면 token_id 문장을 원래 문장으로 복원한다.
cf) PretrainedTokenizerFast는 Rust로 구현된 버전으로 Python Wrapper를 통해 호출되는, 더 빠른 tokenizer다.




Datasets

Dataset Upload 예제:

images 디렉토리 구조:
images
⎿ A.jpg
⎿ B.jpg
  ...

import os
from collections import defaultdict
from datasets import Dataset, Image, DatasetDict

data = defaultdict(list)
folder_name = '../images'

for file_name in os.listdir(folder_name):
    name = os.path.splittext(file_name)[0]
    path = os.path.join(folder_name, file_name)
    data['name'].append(name)
    data['image'].append(path)

dataset = Dataset.from_dict(data).cast_column('image', Image())
# print(data, dataset[0]) # 확인용

dataset_dict = DatasetDict({
    'train': dataset.select(range(5)),
    'valid': dataset.select(range(5, 10)),
    'test': dataset.select(range(10, len(dataset)))
    }
)

hub_name = "<user_name>/<repo_name>" # dataset저장경로
token = "hf_###..." # huggingface token입력
datasetdict.push_to_hub(hub_name, token=token)

 





🤗 Embedding과정 완전정리!!

from transformers import BertTokenizer, BertModel

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained("bert-base-uncased")

txt = "I am laerning about tokenizers."
input = tokenizer(txt, return_tensors="pt")
output = model(**input)

print('input:', input)
print('last_hidden_state:', output.last_hidden_state.shape)
input: {'input_ids': tensor([[  101,  1045,  2572,  2474, 11795,  2075,  2055, 19204, 17629,  2015,  1012,   102]]), 
        'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 
        'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
        
last_hidden_state: torch.Size([1, 12, 768])
  1. input 딕셔너리
    • input_ids:
      • 각 단어와 특수 토큰이 BERT의 어휘 사전에 매핑된 고유한 정수 ID로 변환된 결과입니다.
      • 예시: 101은 [CLS] 토큰, 102는 [SEP] 토큰.
      • 전체 시퀀스: [CLS] I am laerning about tokenizers. [SEP]
      • 길이: 12개의 토큰 (문장 전체와 특수 토큰 포함)
    • token_type_ids:
      • 문장 내의 각 토큰이 어느 segment에 속하는지를 나타냄.
      • BERT는 기본적으로 두 개의 세그먼트(예: 문장 A와 문장 B)를 구분가능.
      • 여기서는 단일 문장이므로 모든 값이 0이다.
    • attention_mask:
      • 모델이 각 토큰에 주의를 기울여야 하는지를 나타낸다.
      • 1은 해당 토큰이 실제 데이터임을 의미하고, 0은 패딩 토큰을 의미.
      • 여기서는 패딩이 없으므로 모든 값이 1이다.
  2. last_hidden_state
    • Shape: [1, 12, 768]
      • Batch Size (1): 한 번에 하나의 입력 문장을 처리.
      • Sequence Length (12): 입력 시퀀스의 토큰 수 (특수 토큰 포함).
      • Hidden Size (768): BERT-base 모델의 각 토큰에 대해 768차원의 벡터 표현을 생성한다.
    • 의미:
      • last_hidden_state는 모델의 마지막 은닉 계층에서 각 토큰에 대한 벡터 표현을 담고 있다.
      • 이 벡터들은 문맥 정보를 포함하고 있으며, 다양한 NLP 작업(예: 분류, 개체명 인식 등)에 활용될 수 있다.

설명)


cf) Embedding코드

class BertEmbeddings(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.word_embeddings = nn.Embedding(config.vocab_size, config.emb_size, padding_idx=config.pad_token_id)
        self.position_embeddings = nn.Embedding(config.max_seq_length, config.emb_size)
        self.token_type_embeddings = nn.Embedding(2, config.emb_size)
        self.LayerNorm = nn.LayerNorm(config.emb_size, eps=config.layer_norm_eps)
        self.dropout = nn.Dropout(config.dropout)
        
        # position ids (used in the pos_emb lookup table) that we do not want updated through backpropogation
        self.register_buffer("position_ids", torch.arange(config.max_seq_length).expand((1, -1)))

    def forward(self, input_ids, token_type_ids):
        word_emb = self.word_embeddings(input_ids)
        pos_emb = self.position_embeddings(self.position_ids)
        type_emb = self.token_type_embeddings(token_type_ids)

        emb = word_emb + pos_emb + type_emb
        emb = self.LayerNorm(emb)
        emb = self.dropout(emb)

        return emb

 

 

 

 

 

NLP

BERT - Classification

NER (Named Entity Recognition)

Token Classification, 즉 문장을 구성하는 각 token에 label을 할당하는 Task이다.
먼저 예시로 BIO Tagging을 들면 아래와 같다:
ex) 인공지능(AI)에서 딥러닝은 머신러닝의 한 분야입니다.
--> <인공지능:B-Tech> <(:I-Tech> <AI:I-Tech> <):I-Tech> <에서:O> <딥러닝:B-Tech> <은:O> <머신러닝:B-Tech> <의:O> <한:O> <분야:O> <입니다:O> <.:O>
이때, B는 Begin(개체명의 시작)을, I는 Inside(개체명의 연속)를, O는 Outside(개체명이 아닌것)를 의미한다.
이런 NER에서 자주사용되는 모델이 바로 BERT이다.

BERT - MLM, NSP

문장간 관계(요약 등)를 이해하기 위해 활용되는 [CLS]토큰이 사용된다.
BERT에서는 총 3가지 Embedding이 Embedding Layer에서 활용된다:
1. Token Embedding:
 - 입력문장 embedding
2. Segment Embedding:
 - 모델이 인식하도록 각 문장에 고정된 숫자 할당.
3. Position Embedding:
 - input을 한번에 모두 밀어넣기에(= 순차적으로 넣지 않음)
 - Transformer Encoder는 각 token의 시간적 순서를 알지 못함
 - 이를 위해 위치정보를 삽입하기위해 sine, cosine을 사용한다.
추천강의) https://www.youtube.com/watch?app=desktop&v=CiOL2h1l-EE

BART - Summarization

Abstractive & Extractive Summarization

추상요약: 원문을 완전히 이해 --> 새로운 문장을 생성해 요약하는 방식.
추출요약: 원문에서 가장 중요하고 관련성 높은 문장들만 선택해 그대로 추출.
(요약문이 부자연스러울 수는 있으며, 중복제거능력이 필요함.)


BART (Bidirectional & Auto Regressive Transformers)

Encoder-Decoder 모두 존재하며, 특히나 Embedding층을 공유하는 Shared Embedding을 사용해 둘간의 연결을 강화한다.
Encoder는 Bidirectional Encoder 각 단어가 문장 전체의 좌우 context를 모두 참조가능하며,
Decoder에서 Auto-Regressive방식으로 이전에 생성한 단어를 참조해 다음 단어를 예측한다.
또한, Pre-Train시 Denoising Auto Encoder로 학습하는데, 임의로 noising후, 복원하게 한다.

RoBERTa, T5- TextQA

Abstractive & Extractive QA

추상질의응답: 주어진 지문 내에서 답변이 되는 문자열 추출 (질문-지문-지문내답변추출)
추출질의응답: 질문과 지문을 입력받아 새로운 답변 생성 (질문-지문-답변)


RoBERTa

max_len, pretrain-dataset양이 늘어났으며, Dynamic Masking기법 도입이 핵심.
Dynamic Masking: 각 에폭마다 다른 마스킹패턴 생성. (NSP는 없앰.)
BPE Tokenization 사용: BERT는 wordpiece tokenize.

T5- Machine Translation

SMT & NMT

통계적 기계번역: 원문-번역쌍 기반, 단어순서 및 언어패턴을 인식 --> 대규모 data필요
신경망 기계번역: 번역문과 단어시퀀스간 관계를 학습


T5 (Text-To-Text Transfer Transformer)

tast별 특정 Prompt형식을 사용해 적절한 출력을 생성하게 유도가능하다.
즉, 단일 모델로 다양한 NLP Task를 처리가능한 seq2seq구조를 기반으로 한다.

T5의 독특한점은 모델구조차제가 아닌, "입출력 모두 Txt형태로 취급하는 seq2seq로 접근해 Pretrain과정에서 "Unsupervised Learning"을 통해 대규모 corpus(약 75GB)를 사용한다는 점이다." 이를 통해 언어의 일반적 패턴과 지식을 효과적으로 습득한다.


LLaMA - Text Generation

Seq2Seq & CausalLM

Seq2Seq: Transformer, BART, T5 등 Encoder-Decoder구조
CausalLM: 단일 Decoder로 구성


LLaMA-3 Family

2024년 4월, LLaMA-3가 출시되었는데, LLaMA-3에서는 GQA(Grouped Query Attention)이 사용되어 Inference속도를 높였다.
LLaMA-3는 Incontext-Learning, Few-Shot Learning 모두 뛰어난 성능을 보인다.
Incontext-Learning: 모델이 입력텍스트를 기반으로 새로운 작업을 즉석에서 수행하는 능력



추가적으로 2024년 7월, LLaMA-3.1이 공개되었다. LLaMA-3.1은 AI안정성 및 보안관련 도구가 추가되었는데, Prompt Injection을 방지하는 Prompt Guard를 도입해 유해하거나 부적절한 콘텐츠를 식별하게 하였다.
추가적으로 LLaMA-3 시리즈는 다음과 같은 주요 특징이 존재한다:
- RoPE(Rotary Position Embedding): Q, K에 적용
- GQA(Grouped Query Attention): K, V를 여러 그룹으로 묶어 attention연산수행 --> 효율적 추론

- RMS Norm: 안정적 학습 및 계산의 효율성
- KV cache: 추론시 K,V를 cache에 저장 --> 연산의 효율성


LLaMA-3 최적화기법: SFT . RLHF  . DPO

SFT(Supervised Fine-Tuning): 사람이 작성한 고품질QA쌍으로 모델을 직접 학습시키는 방법
RLHF: PPO알고리즘기반, 모델이 생성한 여러 응답에 대해 사람이 순위를 매기고 이를 바탕으로 재학습.
DPO(Direct Preference Optimization): RLHF의 복잡성을 줄이면서 효과적 학습을 가능케함.(사람이 매긴 응답순위를 직접학습; 다만 더욱 고품질 선호도 data를 필요로함.)

 

 

 

 

Computer Vision

주로 CV(Computer Vision)분야에선 CNN기법이 많이 활용되었다.(VGG, Inception, ResNet, ...)
다만, CNN based model은 주로 국소적(local) pattern을 학습하기에 전역적인 관계(global relation)모델링에 한계가 존재한다.
추가적으로 이미지 크기가 커질수록 계산복잡도 또한 증가한다.

이를 해결하기 위해 ViT(Vision Transformer)가 제안되었으며, 대규모 dataset으로 효율적으로 학습한다.
ViT의 가장 대표적인 격인 CLIP, OWL-ViT, SAM에 대해 알아보자.

Zero shot classification

Zero Shot Classification: CLIP, ALIGN, SigLIP

사실 CLIP은 다양한 Task에서 많이 활용되나 본 글은 Train dataset에 없는 Label에 대해 Image Classification을 수행하는 기술에 활용되는 방법으로 알아보고자 한다.
새로운 Label이 추가될 때마다 재학습이 필요한데, 이를 피하려면 Zero shot기법은 반필수적이기 때문이다.


CLIP (Contrastive Language-Image Pre-training)

Model Architecture Input_Size Patch_Size #params
openai/clip-vit-base-patch32 ViT-B/32 224×224 32×32 1.5B
openai/clip-vit-base-patch16 ViT-B/16 224×224 16×16 1.5B
openai/clip-vit-large-patch14 ViT-L/14 224×224 14×14 4.3B
openai/clip-vit-large-patch14-336 ViT-L/14 336×336 14×14 4.3B

작은 patch_size: 더 세밀한 특징추출, 메모리 사용량 및 계산시간 증가

큰 patch_size: 비교적 낮은 성능, 빠른 처리속도
파란블록: Positive Sample , 흰블록: Negative Sample

기존 Supervised Learning과 달리 2가지 특징이 존재한다:
1.별도의 Label없이 input으로 image-txt쌍만 학습.
 - img, txt를 동일한 embedding공간에 사영(Projection)
 - 이를 통해 두 Modality간 의미적 유사성을 직접적으로 측정 및 학습가능
 - 이 때문에 CLIP은 img-encoder, txt-encoder 모두 갖고있음

2. Contrastive Learning:
 - "Positive Sample": 실제img-txt쌍 --> img-txt간 의미적 유사성 최대화
 - "Negative Sample": random하게 pair된 불일치img-txt쌍 --> 유사성 최소화
 - 이를 위해 Cosine Similarity기반의 Contrastive Learning Loss를 사용.


Zero-Shot Classification 예시

from datasets import load_dataset
from transformers import CLIPProcessor, CLIPModel
import torch

model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
dataset = load_dataset("sasha/dog-food")
images = dataset['test']['image'][:2]
labels = ['dog', 'food']
inputs = processor(images=images, text=labels, return_tensors="pt", padding=True)

print('input_ids: ', inputs['input_ids'])
print('attention_mask: ', inputs['attention_mask'])
print('pixel_values: ', inputs['pixel_values'])
print('image_shape: ', inputs['pixel_values'].shape)
# =======================================================
# input_ids:  tensor([[49406,  1929, 49407], [49406,  1559, 49407]])
# attention_mask:  tensor([[1, 1, 1], [1, 1, 1]])
# pixel_values:  tensor([[[[-0.0113, ...,]]]])
# image_shape:  torch.Size([2, 3, 224, 224])

CLIPProcessor에는 CLIPImageProcessor와 CLIPTokenizer가 내부적으로 포함되어 있다.
input_ids에서 49406과 49407은 각각 startoftext와 endoftext를 나타내는 특별한 값이다.
attention_mask는 변환된 token_types로
값이 1이면 해당위치토큰이 실제데이터값을 나타내고, 0은 [PAD]를 의미한다.

with torch.no_grad():
  outputs = model(**inputs)
  logits_per_image = outputs.logits_per_image
  probs = logits_per_image.softmax(dim=1)
  print('outputs:', outputs.keys())
  print('logits_per_image:', logits_per_image)
  print('probs: ', probs)

for idx, prob in enumerate(probs):
  print(f'- Image #{idx}')
  for label, p in zip(labels, prob):
    print(f'{label}: {p.item():.4f}')

# ============================================
# outputs: odict_keys(['logits_per_image', 'logits_per_text', 'text_embeds', 'image_embeds', 'text_model_output', 'vision_model_output'])
# logits_per_image: tensor([[23.3881, 18.8604], [24.8627, 21.5765]])
# probs:  tensor([[0.9893, 0.0107], [0.9640, 0.0360]])
# - Image #0
# dog: 0.9893
# food: 0.0107
# - Image #1
# dog: 0.9640
# food: 0.0360

Zero shot Detection

자연어적 설명에는 이미지 내 객체와 개략적 위치정보를 암시적으로 포함한다.
CLIP에서 img-txt쌍으로 시각적특징과 텍스트간 연관성을 학습가능함을 보였기에, 
추론 시, 주어진 txt prompt만 잘 설계한다면 객체의 위치를 예측할 수 있게된다.
따라서 zero-shot object detection에서는 전통적인 annotation정보 없이도 시각과 언어간의 상관관계를 학습하여 새로운 객체클래스를 검출할 수 있게 해준다.
OWL-ViT의 경우, Multi-Modal Backbone모델로 CLIP모델을 사용한다.

OWLv2 (OWL-ViT)

OWL-ViT구조, OWLv2는 객체검출헤드에 Objectness Classifier추가함.
OWL-ViT는 img-txt쌍으로 pretrain하여 Open-Vocabulary객체탐지가 가능하다.
OWLv2는 Self-Training기법으로 성능을 크게 향상시켰다.
즉, 기존 Detector로 Weak Supervision방식으로 가상의 Bbox-Annotation을 자동생성한다.
ex) input: img-txt pair[강아지가 공을 가지고 노는]
기존 detector: [강아지 bbox] [공 bbox] 자동예측, annotation생성
--> 모델 학습에 이용 (즉, 정확한 위치정보는 없지만 부분적 supervision signal로 weak signal기반, 모델이 객체의 위치 및 클래스를 추론, 학습하게 함)

Zero-Shot Detection 예시

import io
from PIL import Image
from datasets import load_dataset
from transformers import Owlv2Processor, Owlv2ForObjectDetection

processor = Owlv2Processor.from_pretrained("google/owlv2-base-patch16")
model = Owlv2ForObjectDetection.from_pretrained("google/owlv2-base-patch16")
dataset = load_dataset('Francesco/animals-ij5d2')
print(dataset)
print(dataset['test'][0])

# ==========================================================
# DatasetDict({
#     train: Dataset({
#         features: ['image_id', 'image', 'width', 'height', 'objects'],
#         num_rows: 700
#     })
#     validation: Dataset({
#         features: ['image_id', 'image', 'width', 'height', 'objects'],
#         num_rows: 100
#     })
#     test: Dataset({
#         features: ['image_id', 'image', 'width', 'height', 'objects'],
#         num_rows: 200
#     })
# })
# {'image_id': 63, 'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x640 at 0x7A2B0186E4A0>, 'width': 640, 'height': 640, 'objects': {'id': [96, 97, 98, 99], 'area': [138029, 8508, 10150, 20624], 'bbox': [[129.0, 291.0, 395.5, 349.0], [119.0, 266.0, 93.5, 91.0], [296.0, 280.0, 116.0, 87.5], [473.0, 284.0, 167.0, 123.5]], 'category': [3, 3, 3, 3]}}

 

- Label 및 Image 전처리
images = dataset['test']['image'][:2]
categories = dataset['test'].features['objects'].feature['category'].names
labels = [categories] * len(images)
inputs = processor(text=labels, images=images, return_tensors="pt", padding=True)

print(images)
print(labels)
print('input_ids:', inputs['input_ids'])
print('attention_mask:', inputs['attention_mask'])
print('pixel_values:', inputs['pixel_values'])
print('image_shape:', inputs['pixel_values'].shape)

# ==========================================================
# [<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x640 at 0x7A2ADF7CF790>, <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x640 at 0x7A2ADF7CCC10>]
# [['animals', 'cat', 'chicken', 'cow', 'dog', 'fox', 'goat', 'horse', 'person', 'racoon', 'skunk'], ['animals', 'cat', 'chicken', 'cow', 'dog', 'fox', 'goat', 'horse', 'person', 'racoon', 'skunk']]
# input_ids: tensor([[49406,  4995, 49407,     0],
#         [49406,  2368, 49407,     0],
#         [49406,  3717, 49407,     0],
#         [49406,  9706, 49407,     0],
#         [49406,  1929, 49407,     0],
#         [49406,  3240, 49407,     0],
#         [49406,  9530, 49407,     0],
#         [49406,  4558, 49407,     0],
#         [49406,  2533, 49407,     0],
#         [49406,  1773,  7100, 49407],
#         [49406, 42194, 49407,     0],
#         [49406,  4995, 49407,     0],
#         [49406,  2368, 49407,     0],
#         [49406,  3717, 49407,     0],
#         [49406,  9706, 49407,     0],
#         [49406,  1929, 49407,     0],
#         [49406,  3240, 49407,     0],
#         [49406,  9530, 49407,     0],
#         [49406,  4558, 49407,     0],
#         [49406,  2533, 49407,     0],
#         [49406,  1773,  7100, 49407],
#         [49406, 42194, 49407,     0]])
# attention_mask: tensor([[1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0],
#         [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 1], [1, 1, 1, 0], 
#          [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0],
#           [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 1], [1, 1, 1, 0]])
# pixel_values: tensor([[[[ 1.5264, ..., ]]]])
# image_shape: torch.Size([2, 3, 960, 960])

- Detection & Inference
import torch

model.eval()
with torch.no_grad():
    outputs = model(**inputs)

print(outputs.keys()) # odict_keys(['logits', 'objectness_logits', 'pred_boxes', 'text_embeds', 'image_embeds', 'class_embeds', 'text_model_output', 'vision_model_output'])

- Post Processing
import matplotlib.pyplot as plt
from PIL import ImageDraw, ImageFont

# 예측확률이 높은 객체 추출
shape = [dataset['test'][:2]['width'], dataset['test'][:2]['height']]
target_sizes = list(map(list, zip(*shape))) # [[640, 640], [640, 640]]
results = processor.post_process_object_detection(outputs=outputs, threshold=0.5, target_sizes=target_sizes)
print(results)

# Post Processing
for idx, (image, detect) in enumerate(zip(images, results)):
    image = image.copy()
    draw = ImageDraw.Draw(image)
    font = ImageFont.truetype("arial.ttf", 18)

    for box, label, score in zip(detect['boxes'], detect['labels'], detect['scores']):
        box = [round(i, 2) for i in box.tolist()]
        draw.rectangle(box, outline='red', width=3)

        label_text = f'{labels[idx][label]}: {round(score.item(), 3)}'
        draw.text((box[0], box[1]), label_text, fill='white', font=font)

    plt.imshow(image)
    plt.axis('off')
    plt.show()
    
# ==============================================
# [{'scores': tensor([0.5499, 0.6243, 0.6733]), 'labels': tensor([3, 3, 3]), 'boxes': tensor([[329.0247, 287.1844, 400.3372, 357.9262],
#         [122.9359, 272.8753, 534.3260, 637.6506],
#         [479.7363, 294.2744, 636.4859, 396.8372]])}, {'scores': tensor([0.7538]), 'labels': tensor([7]), 'boxes': tensor([[ -0.7799, 173.7043, 440.0294, 538.7166]])}]

 

Zero shot Semantic segmentation

Image Segmentation은 보다 정밀한, 픽셀별 분류를 수행하기에 높은 계산비용이 들며, 광범위한 train data와 정교한 알고리즘을 필요로 한다.
전통적 방법으로는 threshold기반 binary classification, Edge Detection등이 있으며
최신 방법으로는 딥러닝모델을 이용해 Image Segmentation을 진행한다.
전통적 방법은 단순하고 빠르지만 복잡하거나 다양한 조명조건 등에서 성능이 크게 저하되는 단점이 존재한다.


SAM (Segment Anything Model)

Model Architecture Input_Size Patch_Size #params
facebook/sam-vit-base ViT-B/16 1024×1024 16×16 0.9B
facebook/sam-vit-large ViT-L/16 1024×1024 16×16 3.1B
facebook/sam-vit-huge ViT-H/16 1024×1024 16×16 6.4B

 

SAM구조: img-encoder, prompt-encoder, mask-decoder

SAM은 Meta에서 개발한 다양한 도메인에서 수집한 1100만개 이미지를 이용해 학습한 모델이다.

그렇기에 다양한 환경에서 image segmentation작업을 고수준으로 수행가능하다.
SAM을 이용하면 많은경우, 추가적인 Fine-Tuning없이, 다양한 Domain image에 대한 segmentation이 가능하다.

SAM은 prompt를 받을수도 있고, 받지 않아도 되는데, prompt는 좌표, bbox, txt 등 다양하게 줄 수 있다.
추가적으로 prompt를 주지 않으면 img 전체에 대한 포괄적인 Segmentation을 진행한다.
다만, Inference결과로 Binary Mask는 제공하지만 pixel에 대한 구체적 class정보는 포함하지 않는다.

SAM 활용 예시

import io
from PIL import Image
from datasets import load_dataset
from transformers import SamProcessor, SamModel

def filter_category(data):
    # 16 = dog
    # 23 = giraffe
    return 16 in data["objects"]["category"] or 23 in data["objects"]["category"]

def convert_image(data):
    byte = io.BytesIO(data["image"]["bytes"])
    img = Image.open(byte)
    return {"img": img}

model_name = "facebook/sam-vit-base"
processor = SamProcessor.from_pretrained(model_name) 
model = SamModel.from_pretrained(model_name)

dataset = load_dataset("s076923/coco-val")
filtered_dataset = dataset["validation"].filter(filter_category)
converted_dataset = filtered_dataset.map(convert_image, remove_columns=["image"])
import numpy as np
from matplotlib import pyplot as plt


def show_point_box(image, input_points, input_labels, input_boxes=None, marker_size=375):
    plt.figure(figsize=(10, 10))
    plt.imshow(image)
    ax = plt.gca()
    
    input_points = np.array(input_points)
    input_labels = np.array(input_labels)

    pos_points = input_points[input_labels[0] == 1]
    neg_points = input_points[input_labels[0] == 0]
    
    ax.scatter(
        pos_points[:, 0],
        pos_points[:, 1],
        color="green",
        marker="*",
        s=marker_size,
        edgecolor="white",
        linewidth=1.25
    )
    ax.scatter(
        neg_points[:, 0],
        neg_points[:, 1],
        color="red",
        marker="*",
        s=marker_size,
        edgecolor="white",
        linewidth=1.25
    )

    if input_boxes is not None:
        for box in input_boxes:
            x0, y0 = box[0], box[1]
            w, h = box[2] - box[0], box[3] - box[1]
            ax.add_patch(
                plt.Rectangle(
                    (x0, y0), w, h, edgecolor="green", facecolor=(0, 0, 0, 0), lw=2
                )
            )

    plt.axis("on")
    plt.show()


image = converted_dataset[0]["img"]
input_points = [[[250, 200]]]
input_labels = [[[1]]]

show_point_box(image, input_points[0], input_labels[0])
inputs = processor(
    image, input_points=input_points, input_labels=input_labels, return_tensors="pt"
)

# input_points shape : torch.Size([1, 1, 1, 2])
# input_points : tensor([[[[400.2347, 320.0000]]]], dtype=torch.float64)
# input_labels shape : torch.Size([1, 1, 1])
# input_labels : tensor([[[1]]])
# pixel_values shape : torch.Size([1, 3, 1024, 1024])
# pixel_values : tensor([[[[ 1.4612,  ...]]])

input_points: [B, 좌표개수, 좌표] -- 관심갖는 객체나 영역지정 좌표
input_labels: [B, 좌표B, 좌표개수] -- input_points에 대응되는 label정보
 - input_labels종류:

번호 이름 설명
1 foreground 클래스 검출하고자 하는 관심객체가 포함된 좌표
0 not foreground 클래스 관심객체가 포함되지 않은 좌표
-1 background 클래스 배경영역에 해당하는 좌표
-10 padding 클래스 batch_size를 맞추기 위한 padding값 (모델이 처리X)

[Processor로 처리된 이후 출력결과]
input_points
: [B, 좌표B, 분할마스크 당 좌표개수, 좌표위치] 
input_labels: [B, 좌표B, 좌표개수] 


import torch


def show_mask(mask, ax, random_color=False):
    if random_color:
        color = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)
    else:
        color = np.array([30 / 255, 144 / 255, 255 / 255, 0.6])
    h, w = mask.shape[-2:]
    mask_image = mask.reshape(h, w, 1) * color.reshape(1, 1, -1)
    ax.imshow(mask_image)


def show_masks_on_image(raw_image, masks, scores):
    if len(masks.shape) == 4:
        masks = masks.squeeze()
    if scores.shape[0] == 1:
        scores = scores.squeeze()

    nb_predictions = scores.shape[-1]
    fig, axes = plt.subplots(1, nb_predictions, figsize=(30, 15))

    for i, (mask, score) in enumerate(zip(masks, scores)):
        mask = mask.cpu().detach()
        axes[i].imshow(np.array(raw_image))
        show_mask(mask, axes[i])
        axes[i].title.set_text(f"Mask {i+1}, Score: {score.item():.3f}")
        axes[i].axis("off")
    plt.show()


model.eval()
with torch.no_grad():
    outputs = model(**inputs)

masks = processor.image_processor.post_process_masks(
    outputs.pred_masks.cpu(),
    inputs["original_sizes"].cpu(),
    inputs["reshaped_input_sizes"].cpu(),
)

show_masks_on_image(image, masks[0], outputs.iou_scores)
print("iou_scores shape :", outputs.iou_scores.shape)
print("iou_scores :", outputs.iou_scores)
print("pred_masks shape :", outputs.pred_masks.shape)
print("pred_masks :", outputs.pred_masks)

# iou_scores shape : torch.Size([1, 1, 3])
# iou_scores : tensor([[[0.7971, 0.9507, 0.9603]]])
# pred_masks shape : torch.Size([1, 1, 3, 256, 256])
# pred_masks : tensor([[[[[ -3.6988, ..., ]]]]])

iou_scrores: [B, 좌표개수, IoU점수] 
pred_masks: [B, 좌표B, C, H, W] 


input_points = [[[250, 200], [15, 50]]]
input_labels = [[[0, 1]]]
input_boxes = [[[100, 100, 400, 600]]]

show_point_box(image, input_points[0], input_labels[0], input_boxes[0])
inputs = processor(
    image,
    input_points=input_points,
    input_labels=input_labels,
    input_boxes=input_boxes,
    return_tensors="pt"
)

model.eval()
with torch.no_grad():
    outputs = model(**inputs)

masks = processor.image_processor.post_process_masks(
    outputs.pred_masks.cpu(),
    inputs["original_sizes"].cpu(),
    inputs["reshaped_input_sizes"].cpu(),
)

show_masks_on_image(image, masks[0], outputs.iou_scores)​

 



Zero shot Instance segmentation

Zero shot Detection + SAM

SAM의 경우, 검출된 객체의 클래스를 분류하는 기능이 없다.
즉, 이미지 내 객체를 픽셀단위로 구분하는 instance segmentation작업에는 어려움이 존재한다.

이런 한계극복을 위해 zero-shot detection model과 SAM을 함께 활용할 수 있다:
1) zero shot detection모데로 객체 클래스와 bbox영역 검출
2) bbox영역내 SAM모델로 semantic segmentation 진행.

from transformers import pipeline

generator = pipeline("mask-generation", model=model_name)
outputs = generator(image, points_per_batch=32)

plt.imshow(np.array(image))
ax = plt.gca()
for mask in outputs["masks"]:
    show_mask(mask, ax=ax, random_color=True)
plt.axis("off")
plt.show()

print("outputs mask의 개수 :", len(outputs["masks"]))
print("outputs scores의 개수 :", len(outputs["scores"]))

# outputs mask의 개수 : 52
# outputs scores의 개수 : 52

detector = pipeline(
    model="google/owlv2-base-patch16", task="zero-shot-object-detection"
)

image = converted_dataset[24]["img"]
labels = ["dog", "giraffe"]
results = detector(image, candidate_labels=labels, threshold=0.5)

input_boxes = []
for result in results:
    input_boxes.append(
        [
            result["box"]["xmin"],
            result["box"]["ymin"],
            result["box"]["xmax"],
            result["box"]["ymax"]
        ]
    )
    print(result)

inputs = processor(image, input_boxes=[input_boxes], return_tensors="pt")

model.eval()
with torch.no_grad():
    outputs = model(**inputs)

masks = processor.image_processor.post_process_masks(
    outputs.pred_masks.cpu(),
    inputs["original_sizes"].cpu(),
    inputs["reshaped_input_sizes"].cpu()
)

plt.imshow(np.array(image))
ax = plt.gca()

for mask, iou in zip(masks[0], outputs.iou_scores[0]):
    max_iou_idx = torch.argmax(iou)
    best_mask = mask[max_iou_idx]
    show_mask(best_mask, ax=ax, random_color=True)

plt.axis("off")
plt.show()

#{'score': 0.6905778646469116, 'label': 'giraffe', 'box': {'xmin': 96, 'ymin': 198, 'xmax': 294, 'ymax': 577}}
#{'score': 0.6264181733131409, 'label': 'giraffe', 'box': {'xmin': 228, 'ymin': 199, 'xmax': 394, 'ymax': 413}}

 

Image Matching

image matching은 디지털 이미지간 유사성을 정량화, 비교하는 방법이다.
이를 image의 feature vector를 추출하여 각 image vector간 유사도(거리)를 측정하여 계산한다.
그렇기에 이미지 매칭의 핵심은 "이미지 특징을 효과적으로 포착하는 feature vector의 생성"이다.
(보통 특징벡터가 고차원일수록 더 많은 정보를 포함하며, 이 특징벡터는 classification layer와 같은 층을 통과하기 직전(= Feature Extractor의 결과값 = Classifier 직전값) 벡터를 보통 의미한다.)

ex) ViT를 이용한 특징벡터 추출 예제
import torch
from datasets import load_dataset
from transformers import ViTImageProcessor, ViTModel

dataset = load_dataset("huggingface/cats-image")
image = dataset["test"]["image"][0]

model_name = "google/vit-base-patch16-224"
processor = ViTImageProcessor.from_pretrained(model_name)
model = ViTModel.from_pretrained(model_name)

inputs = processor(image, return_tensors="pt")
with torch.no_grad():
    outputs = model(inputs["pixel_values"])

print("마지막 특징 맵의 형태 :", outputs["last_hidden_state"].shape)
print("특징 벡터의 차원 수 :", outputs["last_hidden_state"][:, 0, :].shape)
print("특징 벡터 :", outputs["last_hidden_state"][:, 0, :])

# 마지막 특징 맵의 형태 : torch.Size([1, 197, 768])
# 특징 벡터의 차원 수 : torch.Size([1, 768])
# 특징 벡터 : tensor([[ 2.9420e-01,  8.3502e-01,  ..., -8.4114e-01,  1.7990e-01]])

ImageNet-21K라는 방대한 사전Dataset으로 학습되어 미세한 차이 및 복잡한 패턴을 인식할 수 있게 된다.
ViT에서 feature vector추출 시, 주목할점은 last_hidden_state 키 값이다:
출력이 [1, 197, 768]의 [B, 출력토큰수, feature차원]을 의미하는데, 197개의 출력토큰은 다음을 의미한다.
224×224 --> 16×16(patch_size) --> 196개 patches,
197 = [CLS] + 196 patches로 이루어진 출력토큰에서 [CLS]를 특징벡터로 사용한다.


FAISS (Facebook AI Similarity Search)

FAISS는 메타에서 개발한 고성능 벡터유사도검색 라이브러리이다.
이는 "대규모 고차원 벡터 데이터베이스에서 유사한 벡터를 검색"가능하게 설계되었다.


cf) [벡터 저장 및 관리방식]

  • 로컬 저장 장치: SSD나 NVMe같은 고속저장장치를 사용해 빠른 데이터 접근이 가능.
  • 데이터베이스 시스템: PstgreSQL, pgvector확장이나 MongoDB의 Atlas Vector Search같은 벡터검색기능을 지원하는 데이터베이스를 활용
  • 클라우드 벡터 데이터베이스: Amazon OpenSearch, Ggogle Vetex AI등 클라우드 서비스는 대규모 벡터데이터의 저장 및 검색을 위한 특화된 솔루션을 제공
  • 벡터검색엔진: Milvus, Qdrant, Weaviate, FAISS 등의 벡터 데이터 베이스는 대규모 벡터 dataset의 효율적 저장 및 고성능 검색을 위해 최적화되어 ANN(Approximate Nearest Neighbor)알고리즘으로 빠른 유사도검색을 지원, 실시간 검색이 필요한 경우 특히나 적합하다.


ex) CLIP을 이용한 이미지 특징벡터 추출 예제

import torch
import numpy as np
from datasets import load_dataset
from transformers import CLIPProcessor, CLIPModel

dataset = load_dataset("sasha/dog-food")
images = dataset["test"]["image"][:100]

model_name = "openai/clip-vit-base-patch32"
processor = CLIPProcessor.from_pretrained(model_name)
model = CLIPModel.from_pretrained(model_name)

vectors = []
with torch.no_grad():
    for image in images:
        inputs = processor(images=image, padding=True, return_tensors="pt")
        outputs = model.get_image_features(**inputs)
        vectors.append(outputs.cpu().numpy())

vectors = np.vstack(vectors)
print("이미지 벡터의 shape :", vectors.shape)

# 이미지 벡터의 shape : (100, 512)

dog-food dataset에서 100개 이미지를 선택  각 이미지 벡터를 추출
 vectors리스트에 저장 → ndarray형식으로 변환

이런 특징벡터를 유사도 검색을 위한 인덱스 생성에 활용가능하다:
생성된 인덱스에 이미지 벡터를 등록하기 위해 add를 사용하는데, 이때 입력되는 이미지 벡터는 반드시 numpy의 ndarray형식의 [벡터개수, 벡터차원수] 형태로 구성되어야 한다!!

import faiss

dimension = vectors.shape[-1]
index = faiss.IndexFlatL2(dimension)
if torch.cuda.is_available():
    res = faiss.StandardGpuResources()
    index = faiss.index_cpu_to_gpu(res, 0, index)

index.add(vectors)


import matplotlib.pyplot as plt

search_vector = vectors[0].reshape(1, -1)
num_neighbors = 5
distances, indices = index.search(x=search_vector, k=num_neighbors)

fig, axes = plt.subplots(1, num_neighbors + 1, figsize=(15, 5))

axes[0].imshow(images[0])
axes[0].set_title("Input Image")
axes[0].axis("off")

for i, idx in enumerate(indices[0]):
    axes[i + 1].imshow(images[idx])
    axes[i + 1].set_title(f"Match {i + 1}\nIndex: {idx}\nDist: {distances[0][i]:.2f}")
    axes[i + 1].axis("off")

print("유사한 벡터의 인덱스 번호:", indices)
print("유사도 계산 결과:", distances)

# 유사한 벡터의 인덱스 번호: [[ 0  6 75  1 73]]
# 유사도 계산 결과: [[ 0.       43.922516 44.92473  46.544144 47.058586]]

위 과정을 통해 100개의 벡터를 저장한 FAISS 인덱스가 생성되며, 검색하고자하는 이미지의 특징벡터를 입력으로 인덱스 내에서 가장 유사한 벡터를 효율적으로 추출가능하다.
다만, 인덱스에 저장된 벡터에 대해서만 검색이 가능하기에 검색범위를 확장하고자 한다면 더 많은 벡터를 인덱스에 추가해야한다.

위 코드를 보면 아래와 같은 코드가 있는데, FAISS 라이브러리에서는 다양한 인덱스유형들을 제공한다:

index = faiss.IndexFlatL2(dimension)

 

이름 정확도 속도 특징
IndexFlatL2 가장 높음 가장 느림 모든 벡터에 대한 완전탐색을 수행
IndexHNSW 높음 보통 그래프 구조를 사용해 효율적 검색
IndexIVFlat 보통 가장 빠름 벡터간 clustering으로 탐색범위를 줄여 검색

 

 

 

 

 

 

Multi-Modal

Image Captioning (img2txt)

BLIP

BLIP의 핵심아이디어는 "img와 Txt의 상호작용을 모델링하는 것"이다.
이를 위해 img-encoder, txt-encoder로 각각의 feature vector를 연결해 통합 표현을 생성한다.

BLIP-2 구조

BLIP2는 Q-Former를 도입해 img-txt간 상호작용과 정보교환을 향상시켰다:
[img-txt대조학습, ITM, img기반 txt생성] --> 동시에 하나의 Encode-Decoder구조로 수행
Q-Former는 입력으로 고정된 이미지 feature embedding을 받은 후
img-txt관계가 잘 표현된 Soft visual prompt Embedding을 출력한다.

DocumentQA

DQA(DocumentQA)는 자연어처리 + 정보검색기술을 융합해 QA를 진행하는 것이다.
DQA는 시각적 구조와 Layout을 고려해야하는데, 이 중 가장 주목받는 모델 중 하나가 바로 LayoutLM이다.

LayoutLM (Layout-aware Language Model)

LayoutLM은 Microsoft에서 문서 이미지의 txt뿐만아니라 Layout정보까지 함께 Pre-Train된 모델이다.

[
LayoutLMv1]

LayoutLM-v1

BERT를 기반으로 txt와 함께 txt의 위치정보를 입력으로 사용한다.
Faster R-CNN같은 OCR모델로 txt와 bbox경계를 추출, position embedding으로 추가하며 단어의 image patch(feature)도 model에 입력한다. 다만, LayoutLMv1은 image feature가 맨 마지막에 추가되어 Pretrain시 실제로 활용할 수 없다는 단점이 존재한다.




[LayoutLMv2]

LayoutLMv2는 image embedding을 추가로 도입해 문서의 시각적 정보를 효과적으로 반영한다.
LayoutLMv2에서 visual embedding이 ResNeXT-FPN으로 추출된다.
즉, txt, img-patch, layout정보를 동시에 입력으로 받아 Self-Attention을 수행한다.
- 학습 주요 목표:
i) Masked Visual-Language Modeling: 문장의 빈칸 예측
ii) ITM: 특정 텍스트와 해당 이미지간의 연관성 학습
iii)Text-Image Alignment: 이미지에서 특정 단어가 가려졌을 때, 그 위치를 식별하는 능력


[LayoutLMv3]

좌)DocFormer , 우)LayoutLMv3

LayoutLMv3는 Faster R-CNN, CNN등의 Pre-Trained Backbone에 의존하지 않는 최초의 통합 MLLMs이다.
이를 위해 전과 달리 새로운 사전학습전략 및 과제를 도입하였다:
i) Masked Language Modeling(MLM): 일부 단어 token 마스킹
ii) Masked Image Modeling(MIM): 마스킹된 token에 해당하는 이미지 부분을 마스킹
iii) Word Patch Alignment(WPA): img token과 대응되는 Txt token의 마스킹여부를 이진분류, 두 모달리티간 정렬을 학습

<LayoutLMv3 구조>: embedding계층, patch_embedding모듈, encoder
1) embedding층은 다양한 유형의 Embedding을 통합:
 - word_embed + token_type_emb + pos_emb + (x_pos_emb , y_pos_emb, h_pos_emb, w_pos_emb)

2) patch_embedding모듈은 이미지를 처리:
 - patch로 분할하고 각 patch를 embedding으로 변환하는 ViT역할

3) encoder
 - 여러 Transformer층으로 구성.

 

VQA

VQA process: 시각적 특징 추출 → Q의미파악 →시각적특징과 Q의 txt정보를 통합해 의미있는 표현(A)생성
이를 위해 등장한 것이 바로 ViLT이다.

ViLT (Vision-and-Language Transformer)

시각적 입력을 txt입력과 동일한 방식으로 처리하는 단일모델구조로 구성되어 있다.
이때, 두 모달리티 구분을 위해 모달타입 embedding이 추가되며,
학습과정에서 3가지 손실함수를 통해 이뤄진다:
- ITM: 주어진 Image와 Text가 서로 연관되어있는지 판단.
- MLM: 단어단위의 Masking으로 전체 단어맥락 파악
- WPA: img-txt간 벡터 유사도 최대화


결과적으로 img+txt를 효과적으로 결합해, 단일 embedding공간에 표현한다.

cf) collate_fn은 pytorch의 dataloader로 batch를 구성할 때, 각 sample을 어떻게 결합할 것인지 정의하는 함수다.

Image Generation

이미지 생성은 prompt를 기반으로 이해하여 GAN이나 Diffusion Model을 이용해 prompt의 세부적 특징을 잘 잡아내 새로운 img를 생성하는 기술을 의미한다.

Diffusion Model

[Forward process]: src_img에 점진적 정규분포 Noise 추가
[Reverse process]: pure_noise에서 원본으로 복원(by 평균과 표준편차 갱신)


[Stable-Diffusion 1]
- 512×512 img 생성
- txt2img, img2img, inpainting 등의 기능


[Stable-Diffusion 2]
- 768×768 img 생성
- OpenCLIP으로 더 나은 WPA 제공, 세부적 묘사 개선


[Stable-Diffusion 3]
- 더욱 고해상도 이미지 생성
- Rectified flow기반의 새로운 모델구조
- txt와 img token간 양방향 정보흐름을 가능하게하는 새로운 모델구조

 

 

 

 

 

 

 

etc

Hyperparameter Tuning - ray tune

raytune은 분산 hypereparameter 최적화 framework이다.
대규모 분산컴퓨팅 환경에서 다양한 hyperparameter 탐색 알고리즘(random, greedy 등)을 지원하며, Early Stopping 또한 제공한다.
추가적으로 실험결과 추적 및 시각화 도구 또한 제공하며, 최적의 hyperparameter 조합 또한 효과적으로 식별할 수 있게 도와준다.
!pip3 install ray[tune] optuna


ex) NER RayTune 예제

i) 학습 준비

from datasets import load_dataset
from transformers import AutoModelForTokenClassification, AutoTokenizer

def preprocess_data(example, tokenizer):
    sentence = "".join(example["tokens"]).replace("\xa0", " ")
    encoded = tokenizer(
        sentence,
        return_offsets_mapping=True,
        add_special_tokens=False,
        padding=False,
        truncation=False
    )

    labels = []
    for offset in encoded.offset_mapping:
        if offset[0] == offset[1]:
            labels.append(-100)
        else:
            labels.append(example["ner_tags"][offset[0]])
    encoded["labels"] = labels
    return encoded

dataset = load_dataset("klue", "ner")
labels = dataset["train"].features["ner_tags"].feature.names

model_name = "Leo97/KoELECTRA-small-v3-modu-ner"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(
    model_name,
    num_labels=len(labels),
    ignore_mismatched_sizes=True
)

processed_dataset = dataset.map(
    lambda example: preprocess_data(example, tokenizer),
    batched=False,
    remove_columns=dataset["train"].column_names
)


ii) hyperparameter 탐색

from ray import tune
from functools import partial
from transformers import Trainer, TrainingArguments
from transformers.data.data_collator import DataCollatorForTokenClassification

def model_init(model_name, labels):
    return AutoModelForTokenClassification.from_pretrained(
        model_name, num_labels=len(labels), ignore_mismatched_sizes=True
    )

def hp_space(trial):
    return {
        "learning_rate": tune.loguniform(1e-5, 1e-4),
        "weight_decay": tune.loguniform(1e-5, 1e-1),
        "num_train_epochs": tune.choice([1, 2, 3])
    }

def compute_objective(metrics):
    return metrics["eval_loss"]

training_args = TrainingArguments(
    output_dir="token-classification-hyperparameter-search",
    evaluation_strategy="epoch",
    per_device_train_batch_size=32,
    per_device_eval_batch_size=32,
    # learning_rate=1e-4,
    # weight_decay=0.01,
    # num_train_epochs=5,
    seed=42
)

trainer = Trainer(
    model_init=partial(model_init, model_name=model_name, labels=labels),
    args=training_args,
    train_dataset=processed_dataset["train"],
    eval_dataset=processed_dataset["validation"],
    data_collator=DataCollatorForTokenClassification(tokenizer=tokenizer, padding=True)
)

best_run = trainer.hyperparameter_search(
    backend="ray",
    n_trials=5,
    direction="minimize",
    hp_space=hp_space,
    compute_objective=compute_objective,
    resources_per_trial={"cpu": 2, "gpu": 1},
    trial_dirname_creator=lambda trial: str(trial)
)
print(best_run.hyperparameters)


model_init 함수: 모델 인스턴스 생성 (여러 실험을 통해 최적의 hyperparameter 탐색하게 할당됨.)
즉, 각 실험마다 일관된 초기상태를 보장함.

hp_space 함수: 최적화 과정에서 탐색할 hyperparameter 종류와 값의 범위 지정.

compute_objective 함수: 최적화 과정에서 사용할 "평가지표"로 보통 eval_loss나 eval_acc를 기준으로 설정.

TrainingArguments 함수: lr, weight_decay, train_epochs가 hp_space에서 탐색되기에 따로 할당X

Trainer 함수: 고정된 모델인스턴스가 아닌, model_init을 사용.

출력 예시)

+-------------------------------------------------------------------+
| Configuration for experiment     _objective_2024-11-18_05-44-18   |
+-------------------------------------------------------------------+
| Search algorithm                 BasicVariantGenerator            |
| Scheduler                        FIFOScheduler                    |
| Number of trials                 5                                |
+-------------------------------------------------------------------+

View detailed results here: /root/ray_results/_objective_2024-11-18_05-44-18
To visualize your results with TensorBoard, run: `tensorboard --logdir /tmp/ray/session_2024-11-18_05-44-11_866890_872/artifacts/2024-11-18_05-44-18/_objective_2024-11-18_05-44-18/driver_artifacts`

Trial status: 5 PENDING
Current time: 2024-11-18 05:44:18. Total running time: 0s
Logical resource usage: 0/2 CPUs, 0/1 GPUs (0.0/1.0 accelerator_type:T4)
+-------------------------------------------------------------------------------------------+
| Trial name               status       learning_rate     weight_decay     num_train_epochs |
+-------------------------------------------------------------------------------------------+
| _objective_27024_00000   PENDING        2.36886e-05       0.0635122                     3 |
| _objective_27024_00001   PENDING        6.02131e-05       0.00244006                    2 |
| _objective_27024_00002   PENDING        1.43217e-05       1.7074e-05                    1 |
| _objective_27024_00003   PENDING        3.99131e-05       0.00679658                    2 |
| _objective_27024_00004   PENDING        1.13871e-05       0.00772672                    2 |
+-------------------------------------------------------------------------------------------+

Trial _objective_27024_00000 started with configuration:
+-------------------------------------------------+
| Trial _objective_27024_00000 config             |
+-------------------------------------------------+
| learning_rate                             2e-05 |
| num_train_epochs                              3 |
| weight_decay                            0.06351 |
+-------------------------------------------------+

...

GPTQ (Generative Pre-trained Transformer Quantization)

GPTQ는 모델 최적화방식으로 LLM의 효율성을 크게 향상가능하다.
모델의 가중치를 낮은 bit정밀도로 양자화해 모델크기를 줄이고 추론속도를 높인다.
아래 예제의 출력결과를 보면 알 수 있듯, 모델 크기를 상당히 큰 폭으로 줄일 수 있는데, 
GPTQ방법은 GPT계열뿐만 아니라 다른 Transformer 기반 모델들 모두 적용 가능하다.

GPTQ를 이용한 모델 양자화 예제

from transformers import GPTQConfig
from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_name)

quantization_config = GPTQConfig(
    bits=4,
    dataset="c4",
    tokenizer=tokenizer
)

quantized_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    device_map="auto",
    quantization_config=quantization_config
)
from transformers import pipeline

origin_generator = pipeline("text-generation", model="facebook/opt-125m")
quantized_generator = pipeline("text-generation", model=quantized_model, tokenizer=tokenizer)

input_text_list = [
    "In the future, technology wil",
    "What are we having for dinner?",
    "What day comes after Monday?"
]

print("원본 모델의 출력 결과:")
for input_text in input_text_list:
    print(origin_generator(input_text))
print("양자화 모델의 출력 결과:")
for input_text in input_text_list:
    print(quantized_generator(input_text))
    
# 원본 모델의 출력 결과:
# [{'generated_text': 'In the future, technology wil be used to make the world a better place.\nI think'}]
# [{'generated_text': 'What are we having for dinner?\n\nWe have a great dinner tonight. We have a'}]
# [{'generated_text': "What day comes after Monday?\nI'm guessing Monday."}]
# 양자화 모델의 출력 결과:
# [{'generated_text': 'In the future, technology wil be able to make it possible to make a phone that can be'}]
# [{'generated_text': "What are we having for dinner?\n\nI'm not sure what to do with all this"}]
# [{'generated_text': "What day comes after Monday?\nI'm not sure, but I'll be sure to check"}]

출력결과, 정확도가 다소 떨어지긴 하나 원본모델과 큰 차이가 없음을 확인할 수 있다.

import time
import numpy as np

def measure_inference_time(generator, input_text, iterations=10):
    times = []
    for _ in range(iterations):
        start_time = time.time()
        generator(input_text)
        end_time = time.time()
        times.append(end_time - start_time)
    avg_time = np.mean(times)
    return avg_time

def calculate_model_size(model):
    total_params = sum(p.numel() for p in model.parameters())
    total_memory = sum(p.numel() * p.element_size() for p in model.parameters())
    total_memory_mb = total_memory / (1024 ** 2)
    return total_memory_mb, total_params

test_input = "Once upon a time in a land far, far away, there was a small village."

size_original, total_params_original = calculate_model_size(origin_generator.model)
avg_inference_time_original = measure_inference_time(origin_generator, test_input)

size_quantized, total_params_quantized = calculate_model_size(quantized_generator.model)
avg_inference_time_quantized = measure_inference_time(quantized_generator, test_input)

print("원본 모델:")
print(f"- 매개변수 개수: {total_params_original:,}")
print(f"- 모델 크기: {size_original:.2f} MB")
print(f"- 평균 추론 시간: {avg_inference_time_original:.4f} sec")

print("양자화 모델:")
print(f"- 매개변수 개수: {total_params_quantized:,}")
print(f"- 모델 크기: {size_quantized:.2f} MB")
print(f"- 평균 추론 시간: {avg_inference_time_quantized:.4f} sec")

# 원본 모델:
# - 매개변수 개수: 125,239,296
# - 모델 크기: 477.75 MB
# - 평균 추론 시간: 0.1399 sec
# 양자화 모델:
# - 매개변수 개수: 40,221,696
# - 모델 크기: 76.72 MB
# - 평균 추론 시간: 0.0289 sec

추론 과정에 대한 출력결과를 보면, 원본에 비해 모델에 비해 크기가 크게 줄며 더 빠른 처리를 통해 실시간 응답에 대해 매우 효율적일 수 있음을 확인가능하다.

'HuggingFace🤗' 카테고리의 다른 글

HuggingFace(🤗)-Tutorials  (1) 2024.07.31
[Data Preprocessing] - Data Collator  (1) 2024.07.14
QLoRA 실습 & Trainer vs SFTTrainer  (0) 2024.07.12
[QLoRA] & [PEFT] & deepspeed, DDP  (0) 2024.07.09

Transformers

pipeline()

모델 inference를 위해 사용
from transformers import pipeline
pipe = pipeline("text-classification")
pipe("This restaurant is awesome")
# [{'label': 'POSITIVE', 'score': 0.9998743534088135}]

from transformers로 Github(🐈‍⬛) transformer에서 함수를 불러올 수 있다:

transformers의 함수를 import하는 경우, 위 사진의 src/transformers에 모두 구현이 되어있다.

불러오는 함수의 경우, __init__.py를 확인하면 알 수 있는데, 아래 사진처럼 pipeline이 from .pipelines import pipeline이라 적혀있음을 확인가능하다.


위 좌측사진에서 확인할 수 있듯, pipelines폴더에 pipeline함수를 불러오는것을 확인할 수 있으며,
실제로 해당 폴더에 들어가보면 우측처럼 pipeline함수가 정의되고, 이 형태는 transformers.pipeline docs내용과 일치함을 확인가능하다.



Auto Classes

from_pretrained() Method로 추론이 가능하며, AutoClasses는 이런 작업을 수행, 사전훈련된  AutoConfig, AutoModel, AutoTokenizer중 하나를 자동으로 생성가능하다:
 ex)

from transformers import AutoConfig, AutoModel

model = AutoModel.from_pretrained("google-bert/bert-base-cased")




 AutoConfig

generic Cofiguration클래스로 from_pretrained()라는 클래스메서드 라이브러리 설정클래스 중 하나로 인스턴스화된다.
이 클래스는 '__init__()'을 사용해 직접 인스턴스할 수 없다!!

위 사진을 보면, transformers/src파일을 따고 들어간 결과, 최종적으로 from_pretrained()함수를 찾을 수 있었다.
해당 깃헙코드(가장 우측사진)를 보면, __init__()함수에 대해 raise EnvironmentError가 걸려있음이 확인가능하다.

config = AutoConfig.from_pretrained("bert-base-uncased")
print(config)


# BertConfig {
#   "_name_or_path": "bert-base-uncased",
#   "architectures": [
#     "BertForMaskedLM"
#   ],
#   "attention_probs_dropout_prob": 0.1,
#   "classifier_dropout": null,
#   "gradient_checkpointing": false,
#   "hidden_act": "gelu",
#   "hidden_dropout_prob": 0.1,
#   "hidden_size": 768,
#   "initializer_range": 0.02,
#   "intermediate_size": 3072,
#   "layer_norm_eps": 1e-12,
#   "max_position_embeddings": 512,
#   "model_type": "bert",
#   "num_attention_heads": 12,
#   "num_hidden_layers": 12,
#   "pad_token_id": 0,
#   "position_embedding_type": "absolute",
#   "transformers_version": "4.41.2",
#   "type_vocab_size": 2,
#   "use_cache": true,
#   "vocab_size": 30522
# }

위 코드를 보면, Config는 모델 학습을 위한 json파일로 되어있음을 확인가능하다.
batch_size, learning_rate, weight_decay 등 train에 필요한 것들과
tokenizer의 특수토큰들을 미리 설정하는 등 설정관련 내용이 들어있다.
또한, save_pretrained()를 이용하면 모델의 checkpoint화 함께 저장된다!
그렇기에, 만약 설정을 변경하고 싶거나 Model Proposal등의 상황에서는 config파일을 직접 불러와야한다!




 AutoTokenizer, (blobs, refs, snapshots)

generic Tokenizer클래스로 AutoTokenizer.from_pretrained()라는 클래스메서드.
생성 시, 라이브러리 토크나이저클래스 중 하나로 인스턴스화된다.
참고)https://chan4im.tistory.com/#%E2%88%99input-ids
이 클래스는 '__init__()'을 사용해 직접 인스턴스할 수 없다!!

위 사진을 보면, transformers/src파일을 따고 들어간 결과, 최종적으로 from_pretrained()함수를 찾을 수 있었다.
해당 깃헙코드(가장 우측사진)를 보면, __init__()함수에 대해 raise EnvironmentError가 걸려있음이 확인가능하다.

from transformers import AutoTokenizer

# Download vocabulary from huggingface.co and cache.
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")

# If vocabulary files are in a directory 
# (e.g. tokenizer was saved using *save_pretrained('./test/saved_model/')*)
tokenizer = AutoTokenizer.from_pretrained("./test/bert_saved_model/")

# Download vocabulary from huggingface.co and define model-specific arguments
tokenizer = AutoTokenizer.from_pretrained("FacebookAI/roberta-base", add_prefix_space=True)

tokenizer
# BertTokenizerFast(name_or_path='google-bert/bert-base-uncased', vocab_size=30522, model_max_length=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True),  added_tokens_decoder={
# 	0: AddedToken("[PAD]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
# 	100: AddedToken("[UNK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
# 	101: AddedToken("[CLS]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
# 	102: AddedToken("[SEP]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
# 	103: AddedToken("[MASK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
# }

그런데 한가지 궁금하지 않은가?

tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")

위 코드를 작성후 실행하면 콘솔창에 아래와 같은 화면이 나오는 것일까?????

미리 설명:
tokenizer_config.json에는 token에 대한 설정들이,
config.json에는 모델관련 설정이,
vocab.txt는 subword들이 들어있고,
tokenizer.json은 config된 값들에 대해 나열한 것이다.


본인의 경우, 아래와 같이 cache_dir에 지정을 하면, 해당 디렉토리에 hub라는 파일이 생기며, 그안에 모델관련 파일이 생긴다.

parser.add_argument('--cache_dir', default="/data/huggingface_models")

타고 들어가다 보면 총 3가지 폴더가 나온다: blobs, refs, snapshots
blobs: 해시값으로 나타나져 있음을 확인가능하다. 해당파일에는 아래와 같은 파일이 존재한다:
Config클래스관련파일, Model관련 클래스파일들, tokenizer설정관련 json파일, weight관련 파일들 등등 아래 사진과 같이 많은 파일들이 코드화되어 들어있다:


 
refs: 단순히 main이라는 파일만 존재한다:

해당 파일에는 snapshots안에 있는 디렉토리의 이름과 동일한 이름이 적혀있다.


snapshots: 바로 이곳에!! tokenizer_config.json, config.json, vocab.txt, tokenizer.json파일이 있음을 확인할 수 있다!!!



그런데 뭔가 이상하지 않은가??
위의 blobs에 나와있는 사진의 코드와 snapshots의 코드가 모두 일치한다는 사실!!

그렇다! 즉, blobs는 snapshots 내용을 해시값형태로 저장한 것이었다!!!
사실 이짓한다음에 구글에 치니까 바로 있긴했었다..(https://huggingface.co/docs/huggingface_hub/v0.16.3/en/guides/manage-cache)
허깅페이스 설명 요약:

Refs refs 폴더는 주어진 참조의 최신 리비전을 나타내는 파일을 포함합니다. 예를 들어, 이전에 리포지토리의 메인 브랜치에서 파일을 가져온 경우, refs 폴더에는 main이라는 파일이 있으며, 현재 헤드의 커밋 식별자를 포함합니다.

만약 최신 커밋이 aaaaaa라는 식별자를 가지고 있다면, 해당 파일은 aaaaaa를 포함할 것입니다.

동일한 브랜치가 새로운 커밋 bbbbbb로 업데이트된 경우, 해당 참조에서 파일을 다시 다운로드하면 refs/main 파일이 bbbbbb로 업데이트됩니다.

Blobs blobs 폴더는 실제로 다운로드된 파일을 포함합니다. 각 파일의 이름은 해당 파일의 해시입니다.

Snapshots snapshots 폴더는 위의 blobs에서 언급한 파일에 대한 심볼릭 링크를 포함합니다. 자체적으로 알려진 각 리비전에 대해 여러 폴더로 구성됩니다.

cf) 또한 cache는 아래와 같은 tree구조를 가짐:

    [  96]  .
    └── [ 160]  models--julien-c--EsperBERTo-small
        ├── [ 160]  blobs
        │   ├── [321M]  403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        │   ├── [ 398]  7cb18dc9bafbfcf74629a4b760af1b160957a83e
        │   └── [1.4K]  d7edf6bd2a681fb0175f7735299831ee1b22b812
        ├── [  96]  refs
        │   └── [  40]  main
        └── [ 128]  snapshots
            ├── [ 128]  2439f60ef33a0d46d85da5001d52aeda5b00ce9f
            │   ├── [  52]  README.md -> ../../blobs/d7edf6bd2a681fb0175f7735299831ee1b22b812
            │   └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
            └── [ 128]  bbc77c8132af1cc5cf678da3f1ddf2de43606d48
                ├── [  52]  README.md -> ../../blobs/7cb18dc9bafbfcf74629a4b760af1b160957a83e
                └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd

 


AutoModel

당연히 위와 같이, 아래사진처럼 찾아갈 수 있다.

먼저 AutoModel.from_config함수를 살펴보자.

from transformers import AutoConfig, AutoModel

# Download configuration from huggingface.co and cache.
config = AutoConfig.from_pretrained("google-bert/bert-base-cased")
model = AutoModel.from_config(config)


@classmethod
def from_config(cls, config, **kwargs):
    trust_remote_code = kwargs.pop("trust_remote_code", None)
    has_remote_code = hasattr(config, "auto_map") and cls.__name__ in config.auto_map
    has_local_code = type(config) in cls._model_mapping.keys()
    trust_remote_code = resolve_trust_remote_code(
        trust_remote_code, config._name_or_path, has_local_code, has_remote_code
    )

    if has_remote_code and trust_remote_code:
        class_ref = config.auto_map[cls.__name__]
        if "--" in class_ref:
            repo_id, class_ref = class_ref.split("--")
        else:
            repo_id = config.name_or_path
        model_class = get_class_from_dynamic_module(class_ref, repo_id, **kwargs)
        if os.path.isdir(config._name_or_path):
            model_class.register_for_auto_class(cls.__name__)
        else:
            cls.register(config.__class__, model_class, exist_ok=True)
        _ = kwargs.pop("code_revision", None)
        return model_class._from_config(config, **kwargs)
    elif type(config) in cls._model_mapping.keys():
        model_class = _get_model_class(config, cls._model_mapping)
        return model_class._from_config(config, **kwargs)

    raise ValueError(
        f"Unrecognized configuration class {config.__class__} for this kind of AutoModel: {cls.__name__}.\n"
        f"Model type should be one of {', '.join(c.__name__ for c in cls._model_mapping.keys())}."

 


Data Collator

Data Collator

일련의 sample list를 "single training mini-batch"의 Tensor형태로 묶어줌
Default Data Collator이는 아래처럼 train_dataset이 data_collator를 이용해 mini-batch로 묶여 모델로 들어가 학습하는데 도움이 된다.
trainer = Trainer(
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    data_collator=data_collator,​





batch["input_ids"] , batch["labels"] ?

다만, 위와 달리 대부분의 Data Collator함수를 보면 아래와 같은 코드의 형태를 띠는데, 여기서 input_ids와 label이라는 조금 생소한 단어가 있다:
class MyDataCollator:
    def __init__(self, processor):
        self.processor = processor

    def __call__(self, examples): 
        texts = []
        images = []
        for example in examples:
            image, question, answer = example 
            messages = [{"role": "user", "content": question},
                        {"role": "assistant", "content": answer}] # <-- 여기까지 잘 들어가는것 확인완료.
            text = self.processor.tokenizer.apply_chat_template(messages, add_generation_prompt=False)
            texts.append(text)
            images.append(image)

        batch = self.processor(text=text, images=image, return_tensors="pt", padding=True)
        labels = batch["input_ids"].clone()
        if self.processor.tokenizer.pad_token_id is not None:
            labels[labels == self.processor.tokenizer.pad_token_id] = -100
        batch["labels"] = labels
        return batch

data_collator = MyDataCollator(processor)​

과연 batch["input_ids"]와 batch["labels"]가 뭘까?

전술했던 data_collator는 아래와 같은 형식을 띠는데, 여기서도 보면 inputs와 labels가 있는 것을 볼 수 있다.

모든 모델은 다르지만, 다른모델과 유사한점을 공유한다
= 대부분의 모델은 동일한 입력을 사용한다!

∙Input IDs

Input ID는 모델에 입력으로 전달되는 "유일한 필수 매개변수"인 경우가 많다.
Input ID는 token_index로, 사용할 sequence(문장)를 구성하는 token의 숫자표현이다.
각 tokenizer는 다르게 작동하지만 "기본 메커니즘은 동일"하다.

ex)

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

sequence = "A Titan RTX has 24GB of VRAM"


tokenizer는 sequence(문장)를 tokenizer vocab에 있는 Token으로 분할한다:

tokenized_sequence = tokenizer.tokenize(sequence)


token은 word나 subword 둘중 하나이다:

print(tokenized_sequence)
# 출력: ['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']
# 예를 들어, "VRAM"은 모델 어휘에 없어서 "V", "RA" 및 "M"으로 분할됨.
# 이러한 토큰이 별도의 단어가 아니라 동일한 단어의 일부임을 나타내기 위해서는?
# --> "RA"와 "M" 앞에 이중해시(##) 접두사가 추가됩


inputs = tokenizer(sequence)


이를 통해 token은 모델이 이해가능한 ID로 변환될 수 있다.
이때, 모델내부에서 작동하기 위해서는 input_ids를 key로, ID값을 value로 하는 "딕셔너리"형태로 반환해야한다:

encoded_sequence = inputs["input_ids"]
print(encoded_sequence)
# 출력: [101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102]

또한, 모델에 따라서 자동으로 "special token"을 추가하는데, 
여기에는 모델이 가끔 사용하는 "special IDs"가 추가된다.

decoded_sequence = tokenizer.decode(encoded_sequence)
print(decoded_sequence)
# 출력: [CLS] A Titan RTX has 24GB of VRAM [SEP]





∙Attention Mask

Attention Mask는 Sequence를 batch로 묶을 때 사용하는 Optional한 인수로 
"모델이 어떤 token을 주목하고 하지 말아야 하는지"를 나타낸다.

ex)
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."

encoded_sequence_a = tokenizer(sequence_a)["input_ids"]
encoded_sequence_b = tokenizer(sequence_b)["input_ids"]

len(encoded_sequence_a), len(encoded_sequence_b)
# 출력: (8, 19)
위를 보면, encoding된 길이가 다르기 때문에 "동일한 Tensor로 묶을 수가 없다."
--> padding이나 truncation이 필요함.
padded_sequences = tokenizer([sequence_a, sequence_b], padding=True)

padded_sequences["input_ids"]
# 출력: [[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]

padded_sequences["attention_mask"]
# 출력: [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
attention_mask는 tokenizer가 반환하는 dictionary의 "attention_mask" key에 존재한다.


∙Token Types IDs

어떤 모델의 목적은 classification이나 QA이다.
이런 모델은 2개의 "다른 목적을 단일 input_ids"항목으로 결합해야한다.
= [CLS], [SEP] 등의 특수토큰을 이용해 수행됨.

ex)
# [CLS] SEQUENCE_A [SEP] SEQUENCE_B [SEP]

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"

encoded_dict = tokenizer(sequence_a, sequence_b)
decoded = tokenizer.decode(encoded_dict["input_ids"])

print(decoded)
# 출력: [CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]
위의 예제에서 tokenizer를 이용해 2개의 sequence가 2개의 인수로 전달되어 자동으로 위와같은 문장을 생성하는 것을 볼 수 있다.
이는 seq이후에 나오는 seq의 시작위치를 알기에는 좋다.

다만, 다른 모델은 token_types_ids도 사용하며, token_type_ids로 이 MASK를 반환한다.
encoded_dict['token_type_ids']
# 출력: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]

 

질문에 사용되는 context는 모두 0으로, 
질문에 해당되는 sequence는 모두 1로 설정된 것을 확인할 수 있다.


∙Position IDs

RNN: 각 토큰의 위치가 내장. 
Transformer: 각 토큰의 위치를 인식 ❌


∴ position_ids는 모델이 각 토큰의 위치를 list에서 식별하는 데 사용되는 optional 매개변수.

모델에 position_ids가 전달되지 않으면, ID는 자동으로 Absolute positional embeddings으로 생성:

Absolute positional embeddings은 [0, config.max_position_embeddings - 1] 범위에서 선택.

일부 모델은 sinusoidal position embeddings이나 relative position embeddings과 같은 다른 유형의 positional embedding을 사용.




∙Labels 

Labels는 모델이 자체적으로 손실을 계산하도록 전달될 수 있는 Optional인수이다.
즉, Labels는 모델의 예상 예측값이어야 한다: 표준 손실을 사용하여 예측값과 예상값(레이블) 간의 손실을 계산.


이때, Labels는 Model Head에 따라 다르다:

  • AutoModelForSequenceClassification: 모델은 (batch_size)차원텐서를 기대하며, batch의 각 값은 전체 시퀀스의 예상 label에 해당.

  • AutoModelForTokenClassification: 모델은 (batch_size, seq_length)차원텐서를 기대하며, 각 값은 개별 토큰의 예상 label에 해당

  • AutoModelForMaskedLM: 모델은 (batch_size, seq_length)차원텐서를 기대하며, 각 값은 개별 토큰의 예상 레이블에 해당: label은 마스킹된 token_ids이며, 나머지는 무시할 값(보통 -100).

  • AutoModelForConditionalGeneration: 모델은 (batch_size, tgt_seq_length)차원텐서를 기대하며, 각 값은 각 입력 시퀀스와 연관된 목표 시퀀스를 나타냅니다. 훈련 중에는 BART와 T5가 적절한 디코더 입력 ID와 디코더 어텐션 마스크를 내부적으로 만들기에 보통 제공할 필요X. 이는 Encoder-Decoder 프레임워크를 사용하는 모델에는 적용되지 않음. 각 모델의 문서를 참조하여 각 특정 모델의 레이블에 대한 자세한 정보를 확인하세요.

기본 모델(BertModel 등)은 Labels를 받아들이지 못하는데, 이러한 모델은 기본 트랜스포머 모델로서 단순히 특징들만 출력한다.




∙ Decoder input IDs

이 입력은 인코더-디코더 모델에 특화되어 있으며, 디코더에 입력될 입력 ID를 포함합니다.
이러한 입력은 번역 또는 요약과 같은 시퀀스-투-시퀀스 작업에 사용되며, 보통 각 모델에 특정한 방식으로 구성됩니다.

대부분의 인코더-디코더 모델(BART, T5)은 레이블에서 디코더 입력 ID를 자체적으로 생성합니다.
이러한 모델에서는 레이블을 전달하는 것이 훈련을 처리하는 선호 방법입니다.

시퀀스-투-시퀀스 훈련을 위한 이러한 입력 ID를 처리하는 방법을 확인하려면 각 모델의 문서를 참조하세요.



∙Feed Forward Chunking

트랜스포머의 각 잔차 어텐션 블록에서 셀프 어텐션 레이어는 보통 2개의 피드 포워드 레이어 다음에 위치합니다.
피드 포워드 레이어의 중간 임베딩 크기는 종종 모델의 숨겨진 크기보다 큽니다(예: bert-base-uncased).

크기 [batch_size, sequence_length]의 입력에 대해 중간 피드 포워드 임베딩을 저장하는 데 필요한 메모리 [batch_size, sequence_length, config.intermediate_size]는 메모리 사용량의 큰 부분을 차지할 수 있습니다.

Reformer: The Efficient Transformer의 저자들은 계산이 sequence_length 차원과 독립적이므로 두 피드 포워드 레이어의 출력 임베딩 [batch_size, config.hidden_size]_0, ..., [batch_size, config.hidden_size]_n을 개별적으로 계산하고 n = sequence_length와 함께 [batch_size, sequence_length, config.hidden_size]로 결합하는 것이 수학적으로 동일하다는 것을 발견했습니다.

이는 메모리 사용량을 줄이는 대신 계산 시간을 증가시키는 거래를 하지만, 수학적으로 동일한 결과를 얻을 수 있습니다.

apply_chunking_to_forward() 함수를 사용하는 모델의 경우, chunk_size는 병렬로 계산되는 출력 임베딩의 수를 정의하며, 메모리와 시간 복잡성 간의 거래를 정의합니다. chunk_size가 0으로 설정되면 피드 포워드 청킹은 수행되지 않습니다.

 

 


Optimization

AdamW

흔히들 아묻따 Adam만 사용해라! 라는 격언이 있을정도로 만능 optimizer같지만, 
CV일부 Task에서는 SGD가 더 나은 성능을 보이는 경우가 상당히 존재한다.
AdamW논문에서는 L2 Regularization과 Weight Decay관점에서 SGD에 비해 Adam이 일반화 능력이 떨어지는 이유를 설명한다.
서로다른 초기 decay rate와 lr에 따른 Test Error
L2 Regularization: weight가 비정상적으로 커짐을 방지. (weight값이 커지면 손실함수도 커지게 됨.)
= weight가 너무 커지지 않는 선에서 기존 손실함수를 최소로 만들어주는 weight를 모델이 학습.

weight decay: weight update 시, 이전 weight크기를 일정비율 감소시켜 overfitting방지.

SGD: L2 = weight_decay
Adam: L2 ≠ weight_decay (adaptive learning rate를 사용하기 때문에 SGD와는 다른 weight update식을 사용함.)
∴ 즉, L2 Regularization이 포함된 손실함수로 Adam최적화 시, 일반화 효과를 덜 보게 된다. (decay rate가 더 작아지게됨.)
저자는 L2 regularzation에 의한 weight decay 효과 뿐만 아니라 weight 업데이트 식에 직접적으로 weight decay 텀을 추가하여 이 문제를 해결한다. L2 regularization과 분리된 weight decay라고 하여 decoupled weight decay라고 말하는 것이다.

SGDW와 AdamW의 알고리즘:
지금까지 설명하지 않았던
𝜂가 있는데, 이는 매 weight 업데이트마다 learning rate를 일정 비율 감소시켜주는 learning rate schedule 상수를 의미한다.

초록색으로 표시된 부분이 없다면 L2 regularization을 포함한 손실함수에 SGD와 Adam을 적용한 것과 똑같다.
하지만 초록색 부분을 직접적으로 weight 업데이트 식에 추가시켜 weight decay 효과를 볼 수 있게 만들었다.
optimizer = AdamW(model.parameters(),lr=1e-3, eps=(1e-30, 1e-3),weight_decay=0.0,)

 

cf) model.parameters()는 weight와 bias를 돌려줌.
이제 github 코드를 통해 위의 수식에 대해 살펴보도록 하자:
class AdamW(Optimizer):
    """
    Implements Adam algorithm with weight decay fix as introduced in [Decoupled Weight Decay
    Regularization](https://arxiv.org/abs/1711.05101).

    Parameters:
        params (`Iterable[nn.parameter.Parameter]`):
            Iterable of parameters to optimize or dictionaries defining parameter groups.
        lr (`float`, *optional*, defaults to 0.001):
            The learning rate to use.
        betas (`Tuple[float,float]`, *optional*, defaults to `(0.9, 0.999)`):
            Adam's betas parameters (b1, b2).
        eps (`float`, *optional*, defaults to 1e-06):
            Adam's epsilon for numerical stability.
        weight_decay (`float`, *optional*, defaults to 0.0):
            Decoupled weight decay to apply.
        correct_bias (`bool`, *optional*, defaults to `True`):
            Whether or not to correct bias in Adam (for instance, in Bert TF repository they use `False`).
        no_deprecation_warning (`bool`, *optional*, defaults to `False`):
            A flag used to disable the deprecation warning (set to `True` to disable the warning).
    """

    def __init__(
        self,
        params: Iterable[nn.parameter.Parameter],
        lr: float = 1e-3,
        betas: Tuple[float, float] = (0.9, 0.999),
        eps: float = 1e-6,
        weight_decay: float = 0.0,
        correct_bias: bool = True,
        no_deprecation_warning: bool = False,
    ):
        if not no_deprecation_warning:
            warnings.warn(
                "This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch"
                " implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this"
                " warning",
                FutureWarning,
            )
        require_version("torch>=1.5.0")  # add_ with alpha
        if lr < 0.0:
            raise ValueError(f"Invalid learning rate: {lr} - should be >= 0.0")
        if not 0.0 <= betas[0] < 1.0:
            raise ValueError(f"Invalid beta parameter: {betas[0]} - should be in [0.0, 1.0)")
        if not 0.0 <= betas[1] < 1.0:
            raise ValueError(f"Invalid beta parameter: {betas[1]} - should be in [0.0, 1.0)")
        if not 0.0 <= eps:
            raise ValueError(f"Invalid epsilon value: {eps} - should be >= 0.0")
        defaults = {"lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay, "correct_bias": correct_bias}
        super().__init__(params, defaults)

    @torch.no_grad()
    def step(self, closure: Callable = None):
        """
        Performs a single optimization step.

        Arguments:
            closure (`Callable`, *optional*): A closure that reevaluates the model and returns the loss.
        """
        loss = None
        if closure is not None:
            loss = closure()

        for group in self.param_groups:
            for p in group["params"]:
                if p.grad is None:
                    continue
                grad = p.grad
                if grad.is_sparse:
                    raise RuntimeError("Adam does not support sparse gradients, please consider SparseAdam instead")

                state = self.state[p]

                # State initialization
                if len(state) == 0:
                    state["step"] = 0
                    # Exponential moving average of gradient values
                    state["exp_avg"] = torch.zeros_like(p)
                    # Exponential moving average of squared gradient values
                    state["exp_avg_sq"] = torch.zeros_like(p)

                exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"]
                beta1, beta2 = group["betas"]

                state["step"] += 1

                # Decay the first and second moment running average coefficient
                # In-place operations to update the averages at the same time
                exp_avg.mul_(beta1).add_(grad, alpha=(1.0 - beta1))
                exp_avg_sq.mul_(beta2).addcmul_(grad, grad, value=1.0 - beta2)
                denom = exp_avg_sq.sqrt().add_(group["eps"])

                step_size = group["lr"]
                if group["correct_bias"]:  # No bias correction for Bert
                    bias_correction1 = 1.0 - beta1 ** state["step"]
                    bias_correction2 = 1.0 - beta2 ** state["step"]
                    step_size = step_size * math.sqrt(bias_correction2) / bias_correction1

                p.addcdiv_(exp_avg, denom, value=-step_size)

                # Just adding the square of the weights to the loss function is *not*
                # the correct way of using L2 regularization/weight decay with Adam,
                # since that will interact with the m and v parameters in strange ways.
                #
                # Instead we want to decay the weights in a manner that doesn't interact
                # with the m/v parameters. This is equivalent to adding the square
                # of the weights to the loss with plain (non-momentum) SGD.
                # Add weight decay at the end (fixed version)
                if group["weight_decay"] > 0.0:
                    p.add_(p, alpha=(-group["lr"] * group["weight_decay"]))

        return loss
cf) optimizer의 state_dict()의 형태는 아래와 같다:
{
                'state': {
                    0: {'momentum_buffer': tensor(...), ...},
                    1: {'momentum_buffer': tensor(...), ...},
                    2: {'momentum_buffer': tensor(...), ...},
                    3: {'momentum_buffer': tensor(...), ...}
                },
                'param_groups': [
                    {
                        'lr': 0.01,
                        'weight_decay': 0,
                        ...
                        'params': [0]
                    },
                    {
                        'lr': 0.001,
                        'weight_decay': 0.5,
                        ...
                        'params': [1, 2, 3]
                    }
                ]
            }
이를 통해 살펴보면, Optimizer라는 클래스로부터 AdamW는 상속을 받은 이후, 
위의 state_dict형태를 보면 알 수 있듯, if len(state) == 0이라는 뜻은 state가 시작을 하나도 하지 않았음을 의미한다.
exp_avg는 m을, exp_avg_sq는 vt를 의미하며 p.addcdiv_와 if group["weight_decay"]쪽에서 최종 parameter에 대한 update가 됨을 확인할 수 있다.

 


LR-Schedules &. Learning rate Annealing

LR Schedule: 미리 정해진 스케줄대로 lr을 바꿔가며 사용.

훈련 도중 learning rate를 증가시켜주는게 차이점!
warmup restart로 그림처럼 local minimum에서 빠져나올 기회를 제공한다.


LR Annealing: lr schedule과 혼용되어 사용되나 iteration에 따라 monotonic하게 감소하는것을 의미.
직관적으로는 처음에는 높은 learning rate로 좋은 수렴 지점을 빡세게 찾고,
마지막에는 낮은 learning rate로 수렴 지점에 정밀하게 안착할 수 있게 만들어주는 역할을 한다.

 


Model Outputs

ModelOutput

모든 모델은 ModelOutput의 subclass의 instance출력을 갖는다.
from transformers import BertTokenizer, BertForSequenceClassification
import torch

tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")
model = BertForSequenceClassification.from_pretrained("google-bert/bert-base-uncased")

inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
labels = torch.tensor([1]).unsqueeze(0)  # 배치 크기 1
outputs = model(**inputs, labels=labels)

# SequenceClassifierOutput(loss=tensor(0.4267, grad_fn=<NllLossBackward0>), 
#                           logits=tensor([[-0.0658,  0.5650]], grad_fn=<AddmmBackward0>), 
#                           hidden_states=None, attentions=None)
outputs객체는 필히 loss와 logits를 갖기에 (outputs.loss, outputs.logits) 튜플을 반환한다.

Cf)
CuasalLM의 경우:
loss: Language modeling loss (for next-token prediction).

logits: Prediction scores of the LM_Head (scores for each vocabulary token before SoftMax)
= raw prediction values and are not bounded to a specific range

transformers output word를 위해선 : project linearly->apply softmax 단계를 거침.
이때, LM_Head는 pre-training이 아닌, Fine-Tuning에서 사용됨.
LM_Head란, 모델의 출력 hidden_state를 받아 prediction을 수행하는 것을 의미.
ex) BERT
from transformers import BertModel, BertTokenizer, BertForMaskedLM
import torch

tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertForMaskedLM.from_pretrained("bert-base-uncased")

inputs = tokenizer("The capital of France is [MASK].", return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits
print(f'logits: {logits}') # `torch.FloatTensor` of shape `(batch_size, sequence_length, vocab_size)

# [MASK] 토큰에 대한 예측 결과를 확인합니다.
masked_index = (inputs.input_ids == tokenizer.mask_token_id).nonzero(as_tuple=True)[1]
print(f'masked_index: {masked_index}') # `torch.LongTensor` of shape `(1,)

MASK_token = logits[0, masked_index] # batch의 첫문장에서 MASK token을 가져옴.
print(f'MASK_Token: {MASK_token}')

predicted_token_id = MASK_token.argmax(axis=-1) # 주어진 차원에서 가장 큰 값의 index를 반환. = 모델이 해당위치에서 얘측한 단어의 token_id
print(f'predicted_token_id: {predicted_token_id}')


predicted_token = tokenizer.decode(predicted_token_id)
print(predicted_token)  # paris 출력


# logits: tensor([[[ -6.4346,  -6.4063,  -6.4097,  ...,  -5.7691,  -5.6326,  -3.7883],
#          [-14.0119, -14.7240, -14.2120,  ..., -11.6976, -10.7304, -12.7618],
#          [ -9.6561, -10.3125,  -9.7459,  ...,  -8.7782,  -6.6036, -12.6596],
#          ...,
#          [ -3.7861,  -3.8572,  -3.5644,  ...,  -2.5593,  -3.1093,  -4.3820],
#          [-11.6598, -11.4274, -11.9267,  ...,  -9.8772, -10.2103,  -4.7594],
#          [-11.7267, -11.7509, -11.8040,  ..., -10.5943, -10.9407,  -7.5151]]],
#        grad_fn=<ViewBackward0>)
# masked_index: tensor([6])
# MASK_Token: tensor([[-3.7861, -3.8572, -3.5644,  ..., -2.5593, -3.1093, -4.3820]],
#        grad_fn=<IndexBackward0>)
# predicted_token_id: tensor([3000])
# paris


cf) 참고로 argmax가 반환한 index는 vocabulary의 Index임을 아래를 통해 확인할 수 있다.

for word, idx in list(vocab.items())[:5]:  # 어휘의 처음 10개 항목 출력
    print(f"{word}: {idx}")
for word, idx in list(vocab.items())[2990:3010]:  # 어휘의 처음 10개 항목 출력
    print(f"{word}: {idx}")
    
# [PAD]: 0
# [unused0]: 1
# [unused1]: 2
# [unused2]: 3
# [unused3]: 4
# jack: 2990
# fall: 2991
# raised: 2992
# itself: 2993
# stay: 2994
# true: 2995
# studio: 2996
# 1988: 2997
# sports: 2998
# replaced: 2999
# paris: 3000
# systems: 3001
# saint: 3002
# leader: 3003
# theatre: 3004
# whose: 3005
# market: 3006
# capital: 3007
# parents: 3008
# spanish: 3009

 


Trainer

Trainer

Trainer클래스는 🤗 Transformers 모델에 최적화되어 있다
= 모델이 항상 tuple(= 첫요소로 loss반환) , ModelOutput의 subclass를 반환해야함을 의미
= labels인자가 제공되면 Loss를 계산할 수 있음.

Trainer는 TrainingArguments로 필요인자를 전달해주면, 사용자가 직접 train_loop작성할 필요없이 학습을 시작할 수 있다.
또한, TRL 라이브러리의 SFTTrainer의 경우, 이 Trainer클래스를 감싸고 있으며, LoRA, Quantizing과 DeepSpeed 등의 기능을 통해 어떤 모델 크기에도 효율적인 확장이 가능하다.

먼저, 시작에 앞서 분산환경을 위해서는 Accelerate라이브러리를 설치해야한다!
pip install accelerate
pip install accelerate --upgrade

Basic Usage

"hugㅇㅇㄹㄴ


Checkpoints

"hugㅇㅇㄹㄴ


Customizing

"hugㅇㅇㄹㄴ


Callbacks & Logging

"hugㅇㅇㄹㄴ


Accelerate & Trainer

"hugㅇㅇㄹㄴ


TrainingArguments

참고)
output_dir (str): 모델 예측과 체크포인트가 작성될 출력 디렉토리입니다.
eval_strategy (str 또는 [~trainer_utils.IntervalStrategy], optional, 기본값은 "no"): 훈련 중 채택할 평가 전략을 나타냅니다. 가능한 값은 다음과 같습니다:
•	"no": 훈련 중 평가를 하지 않습니다.
•	"steps": eval_steps마다 평가를 수행하고 기록합니다.
•	"epoch": 각 에포크가 끝날 때마다 평가를 수행합니다.
per_device_train_batch_size (int, optional, 기본값은 8): 훈련 시 GPU/XPU/TPU/MPS/NPU 코어/CPU당 배치 크기입니다.
per_device_eval_batch_size (int, optional, 기본값은 8): 평가 시 GPU/XPU/TPU/MPS/NPU 코어/CPU당 배치 크기입니다.
gradient_accumulation_steps (int, optional, 기본값은 1): 역전파/업데이트를 수행하기 전에 그래디언트를 누적할 업데이트 단계 수입니다.
eval_accumulation_steps (int, optional): 결과를 CPU로 이동시키기 전에 출력 텐서를 누적할 예측 단계 수입니다. 설정하지 않으면 전체 예측이 GPU/NPU/TPU에서 누적된 후 CPU로 이동됩니다(더 빠르지만 더 많은 메모리가 필요합니다).
learning_rate (float, optional, 기본값은 5e-5): [AdamW] 옵티마이저의 초기 학습률입니다.
weight_decay (float, optional, 기본값은 0): [AdamW] 옵티마이저에서 모든 레이어에(바이어스 및 LayerNorm 가중치는 제외) 적용할 가중치 감쇠입니다.
max_grad_norm (float, optional, 기본값은 1.0): 최대 그래디언트 노름(그래디언트 클리핑을 위한)입니다.
num_train_epochs(float, optional, 기본값은 3.0): 수행할 총 훈련 에포크 수입니다(정수가 아닌 경우 마지막 에포크의 백분율을 수행한 후 훈련을 중지합니다).
max_steps (int, optional, 기본값은 -1): 양의 정수로 설정된 경우, 수행할 총 훈련 단계 수입니다. num_train_epochs를 무시합니다. 유한한 데이터 세트의 경우, max_steps에 도달할 때까지 데이터 세트를 반복합니다.
eval_steps (int 또는 float, optional): eval_strategy="steps"인 경우 두 평가 사이의 업데이트 단계 수입니다. 설정되지 않은 경우, logging_steps와 동일한 값으로 기본 설정됩니다. 정수 또는 [0,1) 범위의 부동 소수점 수여야 합니다. 1보다 작으면 전체 훈련 단계의 비율로 해석됩니다.
lr_scheduler_type (str 또는 [SchedulerType], optional, 기본값은 "linear"): 사용할 스케줄러 유형입니다. 모든 가능한 값은 [SchedulerType]의 문서를 참조하세요.
lr_scheduler_kwargs ('dict', optional, 기본값은 {}): lr_scheduler에 대한 추가 인수입니다. 각 스케줄러의 문서를 참조하여 가능한 값을 확인하세요.
warmup_ratio (float, optional, 기본값은 0.0): 0에서 learning_rate로의 선형 웜업에 사용되는 총 훈련 단계의 비율입니다.
warmup_steps (int, optional, 기본값은 0): 0에서 learning_rate로의 선형 웜업에 사용되는 단계 수입니다. warmup_ratio의 영향을 무시합니다.
logging_dir (str, optional): TensorBoard 로그 디렉토리입니다. 기본값은 output_dir/runs/CURRENT_DATETIME_HOSTNAME입니다.
logging_strategy (str 또는 [~trainer_utils.IntervalStrategy], optional, 기본값은 "steps"): 훈련 중 채택할 로깅 전략을 나타냅니다. 가능한 값은 다음과 같습니다:
•	"no": 훈련 중 로깅을 하지 않습니다.
•	"epoch": 각 에포크가 끝날 때마다 로깅을 합니다.
•	"steps": logging_steps마다 로깅을 합니다.
logging_first_step (bool, optional, 기본값은 False): 첫 번째 global_step을 로깅할지 여부를 나타냅니다.
logging_steps (int 또는 float, optional, 기본값은 500): logging_strategy="steps"인 경우 두 로그 사이의 업데이트 단계 수입니다. 정수 또는 [0,1) 범위의 부동 소수점 수여야 합니다. 1보다 작으면 전체 훈련 단계의 비율로 해석됩니다.
run_name (str, optional, 기본값은 output_dir): 실행에 대한 설명자입니다. 일반적으로 wandb 및 mlflow 로깅에 사용됩니다. 지정되지 않은 경우 output_dir과 동일합니다.
save_strategy (str 또는 [~trainer_utils.IntervalStrategy], optional, 기본값은 "steps"): 훈련 중 체크포인트를 저장할 전략을 나타냅니다. 가능한 값은 다음과 같습니다:
•	"no": 훈련 중 저장하지 않습니다.
•	"epoch": 각 에포크가 끝날 때마다 저장합니다.
•	"steps": save_steps마다 저장합니다. "epoch" 또는 "steps"가 선택된 경우, 항상 훈련이 끝날 때 저장이 수행됩니다.
save_total_limit (int, optional): 값이 전달되면 체크포인트의 총 수를 제한합니다. output_dir에 있는 오래된 체크포인트를 삭제합니다. load_best_model_at_end가 활성화되면 metric_for_best_model에 따라 "최고" 체크포인트는 항상 가장 최근의 체크포인트와 함께 유지됩니다.
예를 들어, save_total_limit=5 및 load_best_model_at_end인 경우, 마지막 네 개의 체크포인트는 항상 최고 모델과 함께 유지됩니다. save_total_limit=1 및 load_best_model_at_end인 경우, 마지막 체크포인트와 최고 체크포인트가 서로 다르면 두 개의 체크포인트가 저장될 수 있습니다.
save_safetensors (bool, optional, 기본값은 True): state_dict를 저장하고 로드할 때 기본 torch.load 및 torch.save 대신 safetensors를 사용합니다.
save_on_each_node (bool, optional, 기본값은 False): 멀티노드 분산 훈련을 수행할 때, 모델과 체크포인트를 각 노드에 저장할지 여부를 나타냅니다. 기본적으로 메인 노드에만 저장됩니다.
seed (int, optional, 기본값은 42): 훈련 시작 시 설정될 랜덤 시드입니다. 실행 간 일관성을 보장하려면 모델에 무작위로 초기화된 매개변수가 있는 경우 [~Trainer.model_init] 함수를 사용하여 모델을 인스턴스화하세요.
data_seed (int, optional): 데이터 샘플러에 사용할 랜덤 시드입니다. 설정되지 않은 경우 데이터 샘플링을 위한 Random sampler는 seed와 동일한 시드를 사용합니다. 이 값을 사용하면 모델 시드와는 독립적으로 데이터 샘플링의 일관성을 보장할 수 있습니다.
bf16 (bool, optional, 기본값은 False): 32비트 훈련 대신 bf16 16비트(혼합) 정밀도 훈련을 사용할지 여부를 나타냅니다. Ampere 이상 NVIDIA 아키텍처 또는 CPU(사용_cpu) 또는 Ascend NPU를 사용해야 합니다. 이는 실험적 API이며 변경될 수 있습니다.
fp16 (bool, optional, 기본값은 False): 32비트 훈련 대신 fp16 16비트(혼합) 정밀도 훈련을 사용할지 여부를 나타냅니다.
half_precision_backend (str, optional, 기본값은 "auto"): 혼합 정밀도 훈련을 위한 백엔드입니다. "auto", "apex", "cpu_amp" 중 하나여야 합니다. "auto"는 감지된 PyTorch 버전에 따라 CPU/CUDA AMP 또는 APEX를 사용하며, 다른 선택지는 요청된 백엔드를 강제로 사용합니다.
bf16_full_eval (bool, optional, 기본값은 False): 32비트 대신 전체 bfloat16 평가를 사용할지 여부를 나타냅니다. 이는 더 빠르고 메모리를 절약하지만 메트릭 값에 악영향을 줄 수 있습니다. 이는 실험적 API이며 변경될 수 있습니다.
fp16_full_eval (bool, optional, 기본값은 False): 32비트 대신 전체 float16 평가를 사용할지 여부를 나타냅니다. 이는 더 빠르고 메모리를 절약하지만 메트릭 값에 악영향을 줄 수 있습니다.
tf32 (bool, optional): Ampere 및 최신 GPU 아키텍처에서 사용할 TF32 모드를 활성화할지 여부를 나타냅니다. 기본값은 torch.backends.cuda.matmul.allow_tf32의 기본값에 따릅니다. 자세한 내용은 TF32 문서를 참조하세요. 이는 실험적 API이며 변경될 수 있습니다.
local_rank (int, optional, 기본값은 -1): 분산 훈련 중 프로세스의 순위를 나타냅니다.
ddp_backend (str, optional): 분산 훈련에 사용할 백엔드를 나타냅니다. "nccl", "mpi", "ccl", "gloo", "hccl" 중 하나여야 합니다.
dataloader_drop_last (bool, optional, 기본값은 False): 데이터 세트의 길이가 배치 크기로 나누어떨어지지 않는 경우 마지막 불완전한 배치를 삭제할지 여부를 나타냅니다.
dataloader_num_workers (int, optional, 기본값은 0): 데이터 로딩에 사용할 하위 프로세스 수입니다(PyTorch 전용). 0은 데이터가 메인 프로세스에서 로드됨을 의미합니다.
remove_unused_columns (bool, optional, 기본값은 True): 모델의 forward 메서드에서 사용되지 않는 열을 자동으로 제거할지 여부를 나타냅니다.
label_names (List[str], optional): input dictionary에서 label에 해당하는 키의 목록입니다. 기본값은 모델이 사용하는 레이블 인수의 목록입니다.
load_best_model_at_end (bool, optional, 기본값은 False): 훈련이 끝날 때 최상의 모델을 로드할지 여부를 나타냅니다. 이 옵션이 활성화되면, 최상의 체크포인트가 항상 저장됩니다. 자세한 내용은 save_total_limit를 참조하세요.
<Tip>
            When set to `True`, the parameters `save_strategy` needs to be the same as `eval_strategy`, and in
            the case it is "steps", `save_steps` must be a round multiple of `eval_steps`.
</Tip>
metric_for_best_model (str, optional): load_best_model_at_end와 함께 사용하여 두 모델을 비교할 메트릭을 지정합니다. 평가에서 반환된 메트릭 이름이어야 합니다. 지정되지 않은 경우 기본값은 "loss"이며, load_best_model_at_end=True인 경우 eval_loss를 사용합니다. 이 값을 설정하면 greater_is_better의 기본값은 True가 됩니다. 메트릭이 낮을수록 좋다면 False로 설정하세요.
greater_is_better (bool, optional): load_best_model_at_end 및 metric_for_best_model과 함께 사용하여 더 나은 모델이 더 높은 메트릭을 가져야 하는지 여부를 지정합니다. 기본값은 다음과 같습니다:
•	metric_for_best_model이 "loss"로 끝나지 않는 값으로 설정된 경우 True입니다.
•	metric_for_best_model이 설정되지 않았거나 "loss"로 끝나는 값으로 설정된 경우 False입니다.

fsdp (bool, str 또는 [~trainer_utils.FSDPOption]의 목록, optional, 기본값은 ''): PyTorch 분산 병렬 훈련을 사용합니다(분산 훈련 전용).
fsdp_config (str 또는 dict, optional): fsdp(Pytorch 분산 병렬 훈련)와 함께 사용할 설정입니다. 값은 fsdp json 구성 파일의 위치(e.g., fsdp_config.json) 또는 이미 로드된 json 파일(dict)일 수 있습니다.
deepspeed (str 또는 dict, optional): Deepspeed를 사용합니다. 이는 실험적 기능이며 API가 변경될 수 있습니다. 값은 DeepSpeed json 구성 파일의 위치(e.g., ds_config.json) 또는 이미 로드된 json 파일(dict)일 수 있습니다.
accelerator_config (str, dict, 또는 AcceleratorConfig, optional): 내부 Accelerator 구현과 함께 사용할 설정입니다. 값은 accelerator json 구성 파일의 위치(e.g., accelerator_config.json), 이미 로드된 json 파일(dict), 또는 [~trainer_pt_utils.AcceleratorConfig]의 인스턴스일 수 있습니다.
label_smoothing_factor (float, optional, 기본값은 0.0): 사용할 레이블 스무딩 팩터입니다. 0은 label_smoothing을 사용하지 않음을 의미, 다른 값은 원핫 인코딩된 레이블을 변경합니다.
optim (str 또는 [training_args.OptimizerNames], optional, 기본값은 "adamw_torch"): 사용할 옵티마이저를 나타냅니다. adamw_hf, adamw_torch, adamw_torch_fused, adamw_apex_fused, adamw_anyprecision, adafactor 중에서 선택할 수 있습니다.
optim_args (str, optional): AnyPrecisionAdamW에 제공되는 선택적 인수입니다.
group_by_length (bool, optional, 기본값은 False): 훈련 데이터 세트에서 대략 같은 길이의 샘플을 그룹화할지 여부를 나타냅니다(패딩을 최소화하고 효율성을 높이기 위해). 동적 패딩을 적용할 때만 유용합니다.
report_to (str 또는 List[str], optional, 기본값은 "all"): 결과와 로그를 보고할 통합 목록입니다. 지원되는 플랫폼은 "azure_ml", "clearml", "codecarbon", "comet_ml", "dagshub", "dvclive", "flyte", "mlflow", "neptune", "tensorboard", "wandb"입니다. "all"은 설치된 모든 통합에 보고하며, "none"은 통합에 보고하지 않습니다.
ddp_find_unused_parameters (bool, optional): 분산 훈련을 사용할 때, DistributedDataParallel에 전달되는 find_unused_parameters 플래그의 값을 나타냅니다. 기본값은 그래디언트 체크포인팅을 사용하는 경우 False, 그렇지 않은 경우 True입니다.
ddp_bucket_cap_mb (int, optional): 분산 훈련을 사용할 때, DistributedDataParallel에 전달되는 bucket_cap_mb 플래그의 값을 나타냅니다.
ddp_broadcast_buffers (bool, optional): 분산 훈련을 사용할 때, DistributedDataParallel에 전달되는 broadcast_buffers 플래그의 값을 나타냅니다. 기본값은 그래디언트 체크포인팅을 사용하는 경우 False, 그렇지 않은 경우 True입니다.
dataloader_persistent_workers (bool, optional, 기본값은 False): True로 설정하면 데이터 로더는 데이터 세트가 한 번 소비된 후에도 작업자 프로세스를 종료하지 않습니다. 이는 작업자 데이터 세트 인스턴스를 유지할 수 있습니다. 훈련 속도를 높일 수 있지만 RAM 사용량이 증가합니다. 기본값은 False입니다.
push_to_hub (bool, optional, 기본값은 False): 모델이 저장될 때마다 모델을 허브로 푸시할지 여부를 나타냅니다. 이 옵션이 활성화되면 output_dir은 git 디렉토리가 되어 저장이 트리거될 때마다 콘텐츠가 푸시됩니다(save_strategy에 따라 다름). [~Trainer.save_model]을 호출하면 푸시가 트리거됩니다.
resume_from_checkpoint (str, optional): 모델에 유효한 체크포인트가 있는 폴더의 경로입니다. 이 인수는 직접적으로 [Trainer]에서 사용되지 않으며, 대신 훈련/평가 스크립트에서 사용됩니다. 자세한 내용은 예제 스크립트를 참조하세요.
hub_model_id (str, optional): 로컬 output_dir과 동기화할 저장소의 이름입니다. 단순한 모델 ID일 수 있으며, 이 경우 모델은 네임스페이스에 푸시됩니다. 그렇지 않으면 전체 저장소 이름이어야 합니다(e.g., "user_name/model"). 기본값은 user_name/output_dir_name입니다. 기본값은 output_dir의 이름입니다.
hub_strategy (str 또는 [~trainer_utils.HubStrategy], optional, 기본값은 "every_save"): 허브로 푸시할 범위와 시점을 정의합니다. 가능한 값은 다음과 같습니다:
•	"end": 모델, 구성, 토크나이저(전달된 경우), 모델 카드 초안을 푸시합니다.
•	"every_save": 모델, 구성, 토크나이저(전달된 경우), 모델 카드 초안을 저장할 때마다 푸시합니다. 푸시는 비동기적으로 수행되며, 저장이 매우 빈번한 경우 이전 푸시가 완료되면 새로운 푸시가 시도됩니다. 훈련이 끝날 때 최종 모델로 마지막 푸시가 수행됩니다.
•	"checkpoint": "every_save"와 유사하지만 최신 체크포인트도 last-checkpoint라는 하위 폴더에 푸시하여 trainer.train(resume_from_checkpoint="last-checkpoint")으로 훈련을 쉽게 재개할 수 있습니다.
•	"all_checkpoints": "checkpoint"와 유사하지만 최종 저장소에서 나타나는 대로 모든 체크포인트를 푸시합니다(따라서 최종 저장소에는 폴더마다 하나의 체크포인트 폴더가 있습니다).
hub_token (str, optional): 모델을 허브로 푸시할 때 사용할 토큰입니다. 기본값은 huggingface-cli login으로 얻은 캐시 폴더의 토큰입니다.
hub_private_repo (bool, optional, 기본값은 False): True로 설정하면 허브 저장소가 비공개로 설정됩니다.
hub_always_push (bool, optional, 기본값은 False): True가 아닌 경우, 이전 푸시가 완료되지 않으면 체크포인트 푸시를 건너뜁니다.
gradient_checkpointing (bool, optional, 기본값은 False): 메모리를 절약하기 위해 그래디언트 체크포인팅을 사용할지 여부를 나타냅니다. 역전파 속도가 느려집니다.
auto_find_batch_size (bool, optional, 기본값은 False): 메모리에 맞는 배치 크기를 자동으로 찾아 CUDA 메모리 부족 오류를 피할지 여부를 나타냅니다. accelerate가 설치되어 있어야 합니다(pip install accelerate).
ray_scope (str, optional, 기본값은 "last"): Ray를 사용한 하이퍼파라미터 검색 시 사용할 범위입니다. 기본값은 "last"입니다. Ray는 모든 시도의 마지막 체크포인트를 사용하여 비교하고 최상의 체크포인트를 선택합니다. 다른 옵션도 있습니다. 자세한 내용은 Ray 문서를 참조하세요.
ddp_timeout (int, optional, 기본값은 1800): torch.distributed.init_process_group 호출의 타임아웃입니다. 분산 실행 시 GPU 소켓 타임아웃을 피하기 위해 사용됩니다. 자세한 내용은 PyTorch 문서를 참조하세요.
torch_compile (bool, optional, 기본값은 False): PyTorch 2.0 torch.compile을 사용하여 모델을 컴파일할지 여부를 나타냅니다. 이는 torch.compile API에 대한 기본값을 사용합니다. torch_compile_backend 및 torch_compile_mode 인수를 사용하여 기본값을 사용자 지정할 수 있지만, 모든 값이 작동할 것이라고 보장하지 않습니다. 이 플래그와 전체 컴파일 API는 실험적이며 향후 릴리스에서 변경될 수 있습니다.
torch_compile_backend (str, optional): torch.compile에서 사용할 백엔드입니다. 값을 설정하면 torch_compile이 True로 설정됩니다. 가능한 값은 PyTorch 문서를 참조하세요. 이는 실험적이며 향후 릴리스에서 변경될 수 있습니다.
torch_compile_mode (str, optional): torch.compile에서 사용할 모드입니다. 값을 설정하면 torch_compile이 True로 설정됩니다. 가능한 값은 PyTorch 문서를 참조하세요. 이는 실험적이며 향후 릴리스에서 변경될 수 있습니다.
split_batches (bool, optional): 분산 훈련 중 데이터 로더가 생성하는 배치를 장치에 분할할지 여부를 나타냅니다. True로 설정하면 사용된 실제 배치 크기는 모든 종류의 분산 프로세스에서 동일하지만, 사용 중인 프로세스 수의 정수 배여야 합니다.




 


DeepSpeed

trust_remote_code=True

중국모델에서 흔히보이는 trust_remote_code=True 설정, 과연 이건 뭘까?
이는 "huggingface/transformers"에 Model Architecture가 아직 추가되지 않은경우:
from transformers import AutoTokenizer, AutoModel
model = AutoModel.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True, device='cuda')
"huggingface repo 'internlm/internlm-chat-7b'에서 모델 코드를 다운로드하고, 가중치와 함께 실행한다"는 의미이다.
만약 이 값이 False라면, 라이브러리는 huggingface/transformers에 내장된 모델 아키텍처를 사용하고 가중치만 다운로드
하는것을 의미한다.

rue

중국모델에서 흔히ollator함수를 보면 아래와 같은 코드의 형태를 띠는데, 여기서 input_ids와 label이라는 조금 생소한 단

 

Collate: 함께 합치다.

이에서 유추가능하듯, Data Collator는 다음과 같은 역할을 수행한다.

 

 

Data Collator

Data Collator

일련의 sample list를 "single training mini-batch"의 Tensor형태로 묶어줌
Default Data Collator
이는 아래처럼 train_dataset이 data_collator를 이용해 mini-batch로 묶여 모델로 들어가 학습하는데 도움이 된다.
trainer = Trainer(
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    data_collator=data_collator,​





batch["input_ids"] , batch["labels"] ?

다만, 위와 달리 대부분의 Data Collator함수를 보면 아래와 같은 코드의 형태를 띠는데, 여기서 input_ids와 label이라는 조금 생소한 단어가 있다:
class MyDataCollator:
    def __init__(self, processor):
        self.processor = processor

    def __call__(self, examples): 
        texts = []
        images = []
        for example in examples:
            image, question, answer = example 
            messages = [{"role": "user", "content": question},
                        {"role": "assistant", "content": answer}] # <-- 여기까지 잘 들어가는것 확인완료.
            text = self.processor.tokenizer.apply_chat_template(messages, add_generation_prompt=False)
            texts.append(text)
            images.append(image)

        batch = self.processor(text=text, images=image, return_tensors="pt", padding=True)
        labels = batch["input_ids"].clone()
        if self.processor.tokenizer.pad_token_id is not None:
            labels[labels == self.processor.tokenizer.pad_token_id] = -100
        batch["labels"] = labels
        return batch

data_collator = MyDataCollator(processor)​

과연 batch["input_ids"]와 batch["labels"]가 뭘까?

전술했던 data_collator는 아래와 같은 형식을 띠는데, 여기서도 보면 inputs와 labels가 있는 것을 볼 수 있다.

모든 모델은 다르지만, 다른모델과 유사한점을 공유한다
= 대부분의 모델은 동일한 입력을 사용한다!

∙Input IDs

Input ID는 모델에 입력으로 전달되는 "유일한 필수 매개변수"인 경우가 많다.
Input ID는 token_index로, 사용할 sequence(문장)를 구성하는 token의 숫자표현이다.
각 tokenizer는 다르게 작동하지만 "기본 메커니즘은 동일"하다.

ex)

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

sequence = "A Titan RTX has 24GB of VRAM"


tokenizer는 sequence(문장)를 tokenizer vocab에 있는 Token으로 분할한다:

tokenized_sequence = tokenizer.tokenize(sequence)


token은 word나 subword 둘중 하나이다:

print(tokenized_sequence)
# 출력: ['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']
# 예를 들어, "VRAM"은 모델 어휘에 없어서 "V", "RA" 및 "M"으로 분할됨.
# 이러한 토큰이 별도의 단어가 아니라 동일한 단어의 일부임을 나타내기 위해서는?
# --> "RA"와 "M" 앞에 이중해시(##) 접두사가 추가됩


inputs = tokenizer(sequence)


이를 통해 token은 모델이 이해가능한 ID로 변환될 수 있다.
이때, 모델내부에서 작동하기 위해서는 input_ids를 key로, ID값을 value로 하는 "딕셔너리"형태로 반환해야한다:

encoded_sequence = inputs["input_ids"]
print(encoded_sequence)
# 출력: [101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102]

또한, 모델에 따라서 자동으로 "special token"을 추가하는데, 
여기에는 모델이 가끔 사용하는 "special IDs"가 추가된다.

decoded_sequence = tokenizer.decode(encoded_sequence)
print(decoded_sequence)
# 출력: [CLS] A Titan RTX has 24GB of VRAM [SEP]





∙Attention Mask

Attention Mask는 Sequence를 batch로 묶을 때 사용하는 Optional한 인수로 
"모델이 어떤 token을 주목하고 하지 말아야 하는지"를 나타낸다.

ex)
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."

encoded_sequence_a = tokenizer(sequence_a)["input_ids"]
encoded_sequence_b = tokenizer(sequence_b)["input_ids"]

len(encoded_sequence_a), len(encoded_sequence_b)
# 출력: (8, 19)
위를 보면, encoding된 길이가 다르기 때문에 "동일한 Tensor로 묶을 수가 없다."
--> padding이나 truncation이 필요함.
padded_sequences = tokenizer([sequence_a, sequence_b], padding=True)

padded_sequences["input_ids"]
# 출력: [[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]

padded_sequences["attention_mask"]
# 출력: [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
attention_mask는 tokenizer가 반환하는 dictionary의 "attention_mask" key에 존재한다.


∙Token Types IDs

어떤 모델의 목적은 classification이나 QA이다.
이런 모델은 2개의 "다른 목적을 단일 input_ids"항목으로 결합해야한다.
= [CLS], [SEP] 등의 특수토큰을 이용해 수행됨.

ex)
# [CLS] SEQUENCE_A [SEP] SEQUENCE_B [SEP]

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"

encoded_dict = tokenizer(sequence_a, sequence_b)
decoded = tokenizer.decode(encoded_dict["input_ids"])

print(decoded)
# 출력: [CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]
위의 예제에서 tokenizer를 이용해 2개의 sequence가 2개의 인수로 전달되어 자동으로 위와같은 문장을 생성하는 것을 볼 수 있다.
이는 seq이후에 나오는 seq의 시작위치를 알기에는 좋다.

다만, 다른 모델은 token_types_ids도 사용하며, token_type_ids로 이 MASK를 반환한다.
encoded_dict['token_type_ids']
# 출력: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]

 

질문에 사용되는 context는 모두 0으로, 
질문에 해당되는 sequence는 모두 1로 설정된 것을 확인할 수 있다.


∙Position IDs

RNN: 각 토큰의 위치가 내장. 
Transformer: 각 토큰의 위치를 인식 ❌


∴ position_ids는 모델이 각 토큰의 위치를 list에서 식별하는 데 사용되는 optional 매개변수.

모델에 position_ids가 전달되지 않으면, ID는 자동으로 Absolute positional embeddings으로 생성:

Absolute positional embeddings은 [0, config.max_position_embeddings - 1] 범위에서 선택.

일부 모델은 sinusoidal position embeddings이나 relative position embeddings과 같은 다른 유형의 positional embedding을 사용.




∙Labels 

Labels는 모델이 자체적으로 손실을 계산하도록 전달될 수 있는 Optional인수이다.
즉, Labels는 모델의 예상 예측값이어야 한다: 표준 손실을 사용하여 예측값과 예상값(레이블) 간의 손실을 계산.


이때, Labels는 Model Head에 따라 다르다:

  • AutoModelForSequenceClassification: 모델은 (batch_size)차원텐서를 기대하며, batch의 각 값은 전체 시퀀스의 예상 label에 해당.

  • AutoModelForTokenClassification: 모델은 (batch_size, seq_length)차원텐서를 기대하며, 각 값은 개별 토큰의 예상 label에 해당

  • AutoModelForMaskedLM: 모델은 (batch_size, seq_length)차원텐서를 기대하며, 각 값은 개별 토큰의 예상 레이블에 해당: label은 마스킹된 token_ids이며, 나머지는 무시할 값(보통 -100).

  • AutoModelForConditionalGeneration: 모델은 (batch_size, tgt_seq_length)차원텐서를 기대하며, 각 값은 각 입력 시퀀스와 연관된 목표 시퀀스를 나타냅니다. 훈련 중에는 BART와 T5가 적절한 디코더 입력 ID와 디코더 어텐션 마스크를 내부적으로 만들기에 보통 제공할 필요X. 이는 Encoder-Decoder 프레임워크를 사용하는 모델에는 적용되지 않음. 각 모델의 문서를 참조하여 각 특정 모델의 레이블에 대한 자세한 정보를 확인하세요.

기본 모델(BertModel 등)은 Labels를 받아들이지 못하는데, 이러한 모델은 기본 트랜스포머 모델로서 단순히 특징들만 출력한다.




∙ Decoder input IDs

이 입력은 인코더-디코더 모델에 특화되어 있으며, 디코더에 입력될 입력 ID를 포함합니다.
이러한 입력은 번역 또는 요약과 같은 시퀀스-투-시퀀스 작업에 사용되며, 보통 각 모델에 특정한 방식으로 구성됩니다.

대부분의 인코더-디코더 모델(BART, T5)은 레이블에서 디코더 입력 ID를 자체적으로 생성합니다.
이러한 모델에서는 레이블을 전달하는 것이 훈련을 처리하는 선호 방법입니다.

시퀀스-투-시퀀스 훈련을 위한 이러한 입력 ID를 처리하는 방법을 확인하려면 각 모델의 문서를 참조하세요.



∙Feed Forward Chunking

트랜스포머의 각 잔차 어텐션 블록에서 셀프 어텐션 레이어는 보통 2개의 피드 포워드 레이어 다음에 위치합니다.
피드 포워드 레이어의 중간 임베딩 크기는 종종 모델의 숨겨진 크기보다 큽니다(예: bert-base-uncased).

크기 [batch_size, sequence_length]의 입력에 대해 중간 피드 포워드 임베딩을 저장하는 데 필요한 메모리 [batch_size, sequence_length, config.intermediate_size]는 메모리 사용량의 큰 부분을 차지할 수 있습니다.

Reformer: The Efficient Transformer의 저자들은 계산이 sequence_length 차원과 독립적이므로 두 피드 포워드 레이어의 출력 임베딩 [batch_size, config.hidden_size]_0, ..., [batch_size, config.hidden_size]_n을 개별적으로 계산하고 n = sequence_length와 함께 [batch_size, sequence_length, config.hidden_size]로 결합하는 것이 수학적으로 동일하다는 것을 발견했습니다.

이는 메모리 사용량을 줄이는 대신 계산 시간을 증가시키는 거래를 하지만, 수학적으로 동일한 결과를 얻을 수 있습니다.

apply_chunking_to_forward() 함수를 사용하는 모델의 경우, chunk_size는 병렬로 계산되는 출력 임베딩의 수를 정의하며, 메모리와 시간 복잡성 간의 거래를 정의합니다. chunk_size가 0으로 설정되면 피드 포워드 청킹은 수행되지 않습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

QLoRA 실습 with MLLMs(InternVL)

Step 1. 필요 Library import:

import os

import torch
import torch.nn as nn
import bitsandbytes as bnb
import transformers

from peft import (
    LoraConfig,
    PeftConfig,
    PeftModel, 
    get_peft_model,
)
from transformers import (
    AutoConfig,
    AutoModel,
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    set_seed,
    pipeline,
    TrainingArguments,
)​


Step 2. 모델 불러온 후 prepare_model_for_kbit_training(model) 진행

devices = [0]#[0, 3]
max_memory = {i: '49140MiB' for i in devices}

model_name = 'OpenGVLab/InternVL2-8B'


model = AutoModelForCausalLM.from_pretrained(
    model_name, 
    cache_dir='/data/huggingface_models',
    trust_remote_code=True,
    device_map="auto",
    max_memory=max_memory,
    quantization_config=BitsAndBytesConfig(
            load_in_4bit=True,
            bnb_4bit_compute_dtype=torch.bfloat16,
            bnb_4bit_use_double_quant=True,
            bnb_4bit_quant_type='nf4'
        ),
)

# 모델 구조 출력
print(model)

# get_input_embeddings 메서드를 모델에 추가
def get_input_embeddings(self):
    if hasattr(self, 'embed_tokens'):
        return self.embed_tokens
    elif hasattr(self, 'language_model') and hasattr(self.language_model.model, 'tok_embeddings'):
        return self.language_model.model.tok_embeddings
    else:
        raise NotImplementedError("The model does not have an attribute 'embed_tokens' or 'language_model.model.tok_embeddings'.")

model.get_input_embeddings = get_input_embeddings.__get__(model, type(model))

# prepare_model_for_kbit_training 함수를 직접 구현
def prepare_model_for_kbit_training(model):
    for param in model.parameters():
        param.requires_grad = False  # 모든 파라미터의 기울기 계산을 비활성화

    if hasattr(model, 'model') and hasattr(model.model, 'tok_embeddings'):
        for param in model.model.tok_embeddings.parameters():
            param.requires_grad = True  # 임베딩 레이어만 기울기 계산 활성화
    elif hasattr(model, 'embed_tokens'):
        for param in model.embed_tokens.parameters():
            param.requires_grad = True  # 임베딩 레이어만 기울기 계산 활성화
    
    # 필요한 경우 다른 특정 레이어들도 기울기 계산을 활성화할 수 있음
    # 예시: 
    # if hasattr(model, 'some_other_layer'):
    #     for param in model.some_other_layer.parameters():
    #         param.requires_grad = True

    return model

model = prepare_model_for_kbit_training(model)​


Step 3. QLoRA를 붙일 layer 선택:

def find_all_linear_names(model, train_mode):
    assert train_mode in ['lora', 'qlora']
    cls = bnb.nn.Linear4bit if train_mode == 'qlora' else nn.Linear
    lora_module_names = set()
    for name, module in model.named_modules():
        if isinstance(module, cls):
            names = name.split('.')
            lora_module_names.add(names[0] if len(names) == 1 else names[-1])

    if 'lm_head' in lora_module_names:  # LLM의 Head부분에 속하는 애들 pass
        lora_module_names.remove('lm_head')
    
    return list(lora_module_names)


print(sorted(config.target_modules)) # ['1','output', 'w1', 'w2', 'w3', 'wo', 'wqkv']
config.target_modules.remove('1') # LLM의 Head부분에 속하는 애들 제거


config = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=find_all_linear_names(model, 'qlora'),
    lora_dropout=0.05,
    bias="none",
    task_type="QUESTION_ANS" #CAUSAL_LM, FEATURE_EXTRACTION, QUESTION_ANS, SEQ_2_SEQ_LM, SEQ_CLS, TOKEN_CLS.
)

model = get_peft_model(model, config)

이후 trainer로 train진행.

QLoRA 붙인 결과:

 

 

 

 

 

 

 

trainer 종류? Trainer vs SFTTrainer

Trainer  v.s. SFTTrainer

Trainer  v.s. SFTTrainer

 - 일반 목적의 훈련: 텍스트 분류, 질의응답, 요약 등의 지도 학습 작업에서 모델을 처음부터 훈련시키는 데 사용됩니다.
 - 높은 커스터마이징 가능성: hyperparameter, optimizer, scheduler, logging, metric 등을 미세 조정할 수 있는 다양한 구성 옵션을 제공합니다.
 - 복잡한 훈련 워크플로우 처리: 그래디언트 축적, 조기 종료, 체크포인트 저장, 분산 훈련 등의 기능을 지원합니다.
 - 더 많은 데이터 요구: 효과적인 훈련을 위해 일반적으로 더 큰 데이터셋이 필요합니다.



 SFTTrainer

 - 지도 학습 미세 조정 (SFT): 작은 데이터셋으로 PLMs Fine-Tuning에 최적화.
 - 간단한 인터페이스: 더 적은 configuration으로 간소화된 workflow를 제공.
 - 효율적인 메모리 사용: PEFT와 패킹 최적화와 같은 기술을 사용하여 훈련 중 메모리 소비를 줄입니다.
 - 빠른 훈련: 작은 데이터셋과 짧은 훈련 시간으로도 유사하거나 더 나은 정확도를 달성합니다.



Trainer와 SFTTrainer 선택 기준:

 - Trainer 사용:
큰 데이터셋이 있고, 훈련 루프 또는 복잡한 훈련 워크플로우에 대한 광범위한 커스터마이징이 필요한 경우.
Data preprocessing, Datacollator는 사용자가 직접 설정해야 하며, 일반적인 데이터 전처리 방법을 사용

 - SFTTrainer 사용:
PLMS와 상대적으로 작은 데이터셋을 가지고 있으며, 효율적인 메모리 사용과 함께 더 간단하고 빠른 미세 조정 경험을 원할 경우.
PEFT를 기본적으로 지원, `peft_config`와 같은 설정을 통해 효율적인 파인 튜닝을 쉽게 설정할 수 있다.
Data preprocessing, Datacollator도 효율적인 FT를 위해 최적화되어 있음.
`dataset_text_field`와 같은 필드를 통해 텍스트 데이터를 쉽게 처리할 수 있음.



Feature Trainer SFTTrainer
목적 Gerneral Purpose training Supervised Fine-Tuning of PLMs
커스텀 용도 Highly Customizable Simpler interface with fewer options
Training workflow Handles complex workflows Streamlined workflow
필요 Data Large Datsets Smaller Datasets
Memory 사용량 Higher Lower with PEFT & packing optimization
Training speed Slower Faster with smaller datasets

[PEFT]: Parameter Efficient Fine-Tuning


PEFT란?

PLMs를 specific task에 적용할 때, 대부분의 Parameter를 freeze❄️, 소수의 parameter만 FT하는 기법.
PEFT는 모델 성능을 유지 + #parameter↓가 가능함.
또한, catastrophic forgetting문제 위험도 또한 낮음.
🤗Huggingface에서 소개한 혁신적 방법으로 downstream task에서 FT를 위해 사용됨.

Catastrophic Forgetting이란?

새로운 정보를 학습하게 될때, 기존에 학습한 일부의 지식에 대해서는 망각을 하게 되는 현상



Main Concept

  • Reduced Parameter Fine-tuning(축소된 파라미터 파인튜닝)
    사전 학습된 LLM 모델에서 대다수의 파라미터를 고정해 소수의 추가적인 파라미터만 파인튜닝하는 것이 중점
    선택적 파인튜닝으로 계산적 요구가 급격하게 감소하는 효과
  • Overcoming Catastrophic Forgetting(치명적 망각 문제 극복)
    Catastrophic Forgetting 문제는 LLM 모델 전체를 파인 튜닝하는 과정에서 발생하는 현상인데, PEFT를 활용하여 치명적 망각 문제를 완화할 수 있음
    PEFT를 활용하면 사전 훈련된 상태의 지식을 보존하며 새로운 downstream task에 대해 학습할 수 있음
  • Application Across Modalities(여러 모달리티 적용 가능)
    PEFT는 기존 자연어처리(Natural Language Process: NLP) 영역을 넘어서 다양한 영역으로 확장 가능함
    스테이블 디퓨전(stable diffusion) 혹은 Layout LM 등의 포함된 컴퓨터 비전(Computer Vision: CV) 영역,
    Whisper나 XLS-R이 포함된 오디오 등의 다양한 마달리티에 성공적으로 적용됨
  • Supported PEFT Methods(사용 가능한 PEFT)
    라이브러리에서 다양한 PEFT 방법을 지원함
    LoRA(Low-Rank Adaption), Prefix Tuning, 프롬프트 튜닝 등 각각의 방법은 특정한 미세 조정 요구 사항과 시나리오에 맞게 사용할 수 있도록 설계됨

 

 

 

The output activations original (frozen) pretrained weights (left) are augmented by a low rank adapter comprised of weight matrics A and B (right).

사전학습가중치(❄️)의 output activation은 weight matrix인 A, B로 구성된 LoRA에 의해 증가된다.

 

[Q-LoRA]: Quantized-LoRA

Q-LoRA란?

2023년 5월 NeurIPS에서 양자화와 LoRA를 합쳐 "A6000 단일 GPU로 65B모델 튜닝이 가능"한 방법론을 발표함.
QLoRA는 결국 기존의 LoRA에 새로운 quantization을 더한 형태이다.
베이스 모델인 PLM의 가중치를 얼리고(frozen), LoRA 어댑터의 가중치만 학습 가능하게(trainable)하는 것은 LoRA와 동일하며, frozen PLM의 가중치가 '4비트로 양자화'되었다는 정도가 다른 점이다.
때문에, QLoRA에서 주요히 새로 소개되는 기술(Main Contribution)은 양자화 방법론이 주가 된다는 사실이다.

양자화란?

weight와 activation output을 더 작은 bit단위로 표현하도록 변환하는 것.
즉, data정보를 약간줄이고, 정밀도는 낮추지만
"저장 및 연산에 필요한 연산을 감소시켜 효율성을 확보"하는 경량화 방법론이다.



How to Use in MLLMs...?

그렇다면 어떻게 MLLMs에 적용할 수 있을까? MLLMs는 매우 종류가 많지만, 가장 쉬운 예제로 VLMs를 들어보자면,
Q-LoRA 및 LoRA는 PEFT방법론이기에 이는 LLMs, MLLMs모두 통용되는 방법이다.
그렇기에 VLMs(Vision Encoder + LLM Decoder)를 기준으로 설명해보자면:

  • 언어적 능력을 강화시키고 싶다면, LLM만 PEFT를 진행.
  • 시각적 능력을 강화시키고 싶다면, Vision Encoder만 PEFT를 진행.
  • 두 능력 모두 강화시키고 싶다면, Encoder, Decoder 모두 PEFT를 진행하면 된다.

Reference Code:

 

A Definitive Guide to QLoRA: Fine-tuning Falcon-7b with PEFT

Unveiling the Power of QLoRA: Comprehensive Explanation and Practical Coding with 🤗 PEFT

medium.com

 

 

Finetuning Llama2 with QLoRA — TorchTune documentation

Finetuning Llama2 with QLoRA In this tutorial, we’ll learn about QLoRA, an enhancement on top of LoRA that maintains frozen model parameters in 4-bit quantized precision, thereby reducing memory usage. We’ll walk through how QLoRA can be utilized withi

pytorch.org

 

 

참고: https://github.com/V2LLAIN/Transformers-Tutorials/blob/master/qlora_baseline.ipynb

 

Transformers-Tutorials/qlora_baseline.ipynb at master · V2LLAIN/Transformers-Tutorials

This repository contains demos I made with the Transformers library by HuggingFace. - V2LLAIN/Transformers-Tutorials

github.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Deepspeed란?

# finetune_qlora.sh

deepspeed ovis/train/train.py \
        --deepspeed scripts/zero2.json \
        ...​


물론 나만의 방법을 고수하는것도 좋지만, 대부분의 user들이 이 방법을 사용하는걸 봐서는 일단 알아놓는게 좋을 것 같기에 알아보고자한다.


deepspeed...?

모델의 training, inference속도를 빠르고 효율적으로 처리하게 도와주는 Microsoft사의 딥러닝 최적화 라이브러리이다.

학습 device 종류:

  • CPU
    Single GPU
    1 Node, Multi GPU
    Multi Node, Multi GPU --> 매우 큰 GPT4 등의 학습을 위해 사용됨.

분산학습 방식:

  • Data Parallel: 하나의 device가 data를 나누고, 각 device에서 처리결과를 모아 계산
    --> 하나의 device가 다른 device에 비해 메모리 사용량이 많아지는, 메모리 불균형 문제가 발생한다!
  • Distributed Data Parallel: 각각의 device를 하나의 Process로 보고, 각 process에서 모델을 띄워서 사용.
    이때, 역전파에서만 내부적으로 gradient를 동기화 --> 메모리 불균형문제❌


cf) Requirements:

- PyTorch must be installed before installing DeepSpeed.
- For full feature support we recommend a version of PyTorch that is >= 1.9 and ideally the latest PyTorch stable release.
- A CUDA or ROCm compiler such as nvcc or hipcc used to compile C++/CUDA/HIP extensions.
- Specific GPUs we develop and test against are listed below, this doesn't mean your GPU will not work if it doesn't fall into this category it's just DeepSpeed is most well tested on the following:
        NVIDIA: Pascal, Volta, Ampere, and Hopper architectures
        AMD: MI100 and MI200



pip install deepspeed

로 설치가 가능하며, 사용방법은 아래와 같다.


사용방법:
Step1)
deepspeed사용을 위한 Config.json파일 작성

{
	"train_micro_batch_size_per_gpu": 160,
    "gradient_accumulation_steps": 1,
    "optimizer":
    {
    	"type": "Adam",
        "params":
        {
        	"lr": 0.001
        }
    },
    "zero_optimization":
    {
        "stage": 1,
        "offload_optimizer":
        {
            "device": "cpu",
            "pin_memory":true
        },
        "overlap_comm": false,
        "contiguous_gradients": false
    }
}

config Args:https://www.deepspeed.ai/docs/config-json/

Step2) import & read json

import deepspeed
from deepspeed.ops.adam import DeepSpeedCPUAdam

with open('config.json', 'r') as f:
	deepspeed_config = json.load(f)



Step3) optimizer 설정 & model,optimizer 초기화

optimizer = DeepSpeedCPUAdam(model.parameters(), lr=lr)

model, optimizer, _, _ = deepspeed.initialize(model=model,
                                            model_parameters=model.parameters(),
                                            optimizer=optimizer,
                                            config_params=deepspeed_config)


cf) ArgumentParser에 추가하는것도 가능함!

parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', type=int, default=-1)

parser = deepspeed.add_config_arguments(parser)




Step4) Train!

# >> train.py
deepspeed --num_gpus={gpu 개수} train_deepspeed.py
# train.sh
deepspeed --num_gpus={gpu 개수} train_deepspeed.py

# >> bash train.sh


주의 !)

DeepSpeed는 CUDA_VISIBLE_DEVICES로 특정 GPU를 제어할 수 없다!
아래와 같이 --include로만 특정 GPU를 사용할 수 있다.

deepspeed —inlcude localhost:<GPU_NUM1>, <GPU_NUM2> <python_file.py>


  • gpu node의 개수가 많아질수록 deepspeed의 장점인 학습 속도가 빨라진다!
 

DeepSpeed Configuration JSON

DeepSpeed is a deep learning optimization library that makes distributed training easy, efficient, and effective.

www.deepspeed.ai

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

🐦‍🔥강화학습[Reinforcement Learning]

 

 

 

🤔 강화학습이란?

Agent가 환경에서 누적보상💰을 최대화하는 Action을 취하는 "순차적 의사결정"

∙ Sequential Decision Process: 몇단계를 가봐야 reward를 얻음 = cumulated rewards
state → action & reward  →  state  →  ...


🔍 Exploitation & Exploration

Exploitation: 경험기반 최선행동 (short term benefit)
Exploration: 안알려진행동을 시도, 새로운정보를 획득 (long term benefit)
ex) Exploitation: 늘 가던 단골식당에 간다. / Exploration: 안 가본 식당에 가본다



🔍 Reward Hypothesis: 강화학습이론의 기반.

Agent가 어떤 Action을 취했을 때, 해당 Action이 얼마나 좋은 Action인지 알려주는 "feedback signal"
적절한 보상함수로 "Agent는 누적보상 기댓값 최대화(Cumulated Rewards Maximization)"의 목표를 달성한다.



🔍 RL의 궁극적인 목표는?

Model: Markov Decision Process
궁극적인 목표: 해당 목표(= max cum_Reward)를 위한 Optimal Policy를 찾는 것이 목표임.
cf) 강화학습의 supervision은 사람이 reward를 주는것.





🤔 Markov Property

🔍 MDP (Markov Decision Process)

Markov Property: 현재 state만으로 미래를 예측 (과거 state에 영향X
ex) 오늘의 날씨 -> 내일의 날씨


RL은 Markov Property를 전제로 하는데, 특히 Discrete time를 따를 때 "Markov Chain"을 전제로 함!

즉, markov process는 markov property를 따르는 discrete time을 전제로 하며, 이런 markov process를 markov chain이라함.
cf) Discrete time: 시간이 이산적으로 변함
cf) Stochastic time: 시간에 따라 어떤 사건이 발생할 확률이 변화하는 과정.


MDP(Markov Decision Process)는 <S,A,P,R,γ>라는 Tuple로 정의됨.


🔍 Episode와 Return

Episode: Start State ~ Terminal State

Return: Episode 종료시 받는 모든 Reward
∴ Maximize Return = Agent의 Goal
∴ Maximize Cumulated Reward Optimal Policy = RL의 Goal






🔍 Continuing Task의 Return...?

무한급수Discounting Factor(γ)를 이용.
--> γ=0: 단기보상관심 Agent
--> γ=1: 장기보상관심 Agent






🔍 Discounted Return 

현재 받은 reward와 미래에 받을 reward에 차이를 두기 위해 discount factor γ∈[0,1]를 고려한 이득(Return)

 

 

 

 

🤔 Policy와 Value

🔍 Policy & Value Function

Policy: 어떤 state에서 어떤 action을 취할지 결정하는 함수
Value Function: Return을 기준, 각 state나 action이 얼마나 "좋은지" 알려주는 함수 (즉, reward → return value)

Deterministic Policy: one state - one action (학습이 끝났을때 도달하는 상태.)
Stochastic Policy: one state → 어떤 action? 취할지 확률을 이용. (학습에 적절.)

State-Value Function: 정책이 주어질때, 임의의 s에서 시작, 끝날때까지 받은 return G의 기댓값
Action-Value Function: state에서 어떤 action이 제일 좋은가를 action에 대한 value를 구하는 것으로 Q-Value라고도 함.




🔍 Bellman Equation

Bellman Equationepisode를 다 완료안하고 state가 좋은지 예측할 수 없을까?
State-value Bellman Equation: 즉각적인 reward와 discount factor를 고려한 미래 state values를 합한 식
Action-value Bellman Equation: 즉각적인 reward와 discount factor를 고려한 미래 action values를 합한 식


Bellman Expectation Equation: policy가 주어질 때, 특정 state와 value를 구하는 식.


Bellman Optimality Equation: RL의 goal은 최대 reward의 optimal policy를 찾는게 목표.
Optimal Policy
= Agent가 Goal을 달성했을 때의 policy
= 각 state에서 가장 좋은 policy를 구해서 얻어진 policy




🔍 Value Function Estimation (Planning과 Learning)

Planning: 모델을 알고 이를 이용해 최적의 action을 찾는것 - ex) Dynamic Programming
Learning: Sample base로 (= 모델을 모르고) 학습하는 것 -ex) MC, TD

 









https://arxiv.org/abs/2404.19756

 

KAN: Kolmogorov-Arnold Networks

Inspired by the Kolmogorov-Arnold representation theorem, we propose Kolmogorov-Arnold Networks (KANs) as promising alternatives to Multi-Layer Perceptrons (MLPs). While MLPs have fixed activation functions on nodes ("neurons"), KANs have learnable activat

arxiv.org

 

 

 

🤔 Background: 

Kolmogorov-Arnold Representation Theorem

1. Summary

실해석학 및 근사이론에서 Kolmogorov-Arnold Representation Theorem (or Superposition Theorem)는 모든 다변량 연속함수 f: [0,1]n→R 를 단일변수의 연속함수의 두 인수 덧셈 중첩(superposition)으로 표현될 수 있다고 한다.
해당 이론은 더 제한된 Hilbert의 13번째 문제를 풀었기에, 기존 Hilbert의 13번째 문제는 당연한 추론이 가능하다.

Kolmogorov-Arnold의 연구는 f가 다변량 연속 함수라면 f는 단변량 연속 함수와 덧셈의 이항 연산의 유한한 구성으로 쓰여질 수 있다는 것을 확립했는데, 좀 더 구체적으로 살펴보면 다음과 같다:
즉, 진정한 다변량 함수는 합뿐임을 알 수 있다.



2. History

Kolmogorov-Arnold Representation Theorem(KART)는 Hilbert의 13번째 문제와 밀접한 관련이 있다.
cf) Hilbert의 13번째 문제란, 1900년 국제파리수학자회의에서 제시한 23문제중 하나로 일반 고차방정식의 해법에 관한 문제임.
이때, 4차 방정식의 해는 근호와 산술 연산만으로 계산할 수 있지만,
고차 방정식의 경우 일반적인 대수적 연산으로는 해를 구할 수 없다.

[Tschirnhaus Transformation]: 일반적인 대수방정식을 특정형태로 변환가능

n차 방정식에 대해,
n < 7인 경우: 두 변수의 함수로 표현가능
n ≥ 7인 경우: n-4개 변수의 함수로 표현가능

특히나 n = 7인 경우, 해는 아래와 같은 방정식의 해의 조합으로 표현될 수 있다:

Hilbert의 추측에 따르면, 7차 이상의 일반 방정식은 두 변수의 연속 함수의 조합으로 표현할 수 없다고 하였다.
이는 다차원 함수를 낮은 차원의 함수들의 중첩으로 나타내는 것과 관련이 있음을 시사한다.
기계 학습 분야에서 이 정리는 MLP의 보편 근사 정리(universal approximation)와 유사한 역할을 함.



3. Variants (활용)




4. Limitation

① 복소수 다변량함수에 대해서는 일반적으로 적용❌

내부함수가 매끄럽지 않고 'wild behavior(예측불가능한 행동)'로 인해 표현을 실제 응용에 제한.




Summary

고차 방정식의 경우 일반적인 대수적 연산으로는 해를 구할 수 없음.
[Tschirnhaus Transformation]: 일반적인 대수방정식을 특정형태로 변환가능

n차 방정식에 대해,
n < 7인 경우: 두 변수의 함수로 표현가능
n ≥ 7인 경우: n-4개 변수의 함수로 표현가능

특히나 n = 7인 경우, 해는 아래와 같은 방정식의 해의 조합으로 표현될 수 있다:

7차 이상의 일반 방정식은 두 변수의 연속 함수의 조합으로 표현할 수 없음.
= 다차원 함수를 낮은 차원의 함수들의 중첩으로 나타내는 것과 관련이 있음
기계 학습 분야: MLP의 보편 근사 정리(universal approximation)와 유사한 역할.

 

 

 

 

 

 

 

 

🤔 Main Contribution

1. 

21개의nchmark.

 

 

 

[Summary]:

입.

 

 

 

 

🤔 논문 읽기! by. Andrew Ng.

① Title / Abstract / Figure 및 Experiment 1~2개

∙ Title:

KAN : Kolmogorov-Arnold Networks

MLP의 보편 근사 정리(universal approximation)와 유사한 역할을 하는
Kolmogorov-Arnold Representation Theorem을 기반으로 하는 것을 알 수 있음.




∙ Abstract:

[MLP  vs  KAN]:

MLP: nodes("neurons")에 고정된 활성화 함수를 갖고있음.
KAN: edges("weights")에 학습 가능한 활성화 함수를 가지고 있음.
또한, KAN에는 선형 가중치가 전혀 없는데, 모든 w는 스플라인으로 매개변수화된 단변량 함수로 대체된다.

KAN이 정확도와 해석 가능성 측면에서 MLP를 능가한다는 것을 보여주는데, 정확도를 위해 훨씬 작은 KAN은 데이터 피팅 및 PDE 해결에서 훨씬 큰 MLP와 비슷하거나 더 나은 정확도를 달성할 수 있으며, 이론적 및 경험적으로 KAN은 MLP보다 더 빠른 신경 스케일링 법칙을 가지고 있다.

솔직히 2023년 5월에 해당 아이디어 관련, activation을 학습해서 가장 적절한 activation function을 배치할 수는 없을까? 라는 아이디어를 떠올려서 연구하려했던 생각이 있었는데, 이런 Background도 없었고, 그때 당시에는 구현능력도 떨어졌었기에 현재 이 논문을 읽으면서 많이 아쉽긴 했다.



 



cf) Background & 용어설명: Kolmogorov-Arnold

고차 방정식의 경우 일반적인 대수적 연산으로는 해를 구할 수 없음.
 [Tschirnhaus Transformation]: 일반적인 대수방정식을 특정형태로 변환가능

n차 방정식에 대해,
n < 7인 경우: 두 변수의 함수로 표현가능
n ≥ 7인 경우: n-4개 변수의 함수로 표현가능

특히나 n = 7인 경우, 해는 아래와 같은 방정식의 해의 조합으로 표현될 수 있다:

7차 이상의 일반 방정식은 두 변수의 연속 함수의 조합으로 표현할 수 없음.
= 다차원 함수를 낮은 차원의 함수들의 중첩으로 나타내는 것과 관련이 있음
기계 학습 분야: MLP의 보편 근사 정리(universal approximation)와 유사한 역할.

 

 

 

 

 

 

 

 

 

∙ Introduction:

[MLP]

MLP는 Full Connected Feedforward Neural Net으로완전 연결 전방향 신경망으로 보편적 근사 정리(universal approximation theorem)에 의해 보장된 표현력 덕분에 비선형 함수를 근사하기 위한 기본 모델이다.

[🤔 MLP is  the best nonlinear regressors?]

MLP는 널리 사용되고 있지만, 몇 가지 중요한 단점이 있다:
Transformers에서 MLP가 거의 모든 non-embedding parameters를 소비함.
주로 해석 가능성 측면에서 attention layers에 비해 덜 해석 가능하다.


[KANs: Kolmogorov-Arnold Networks]

MLP: 보편적 근사 정리에 영감을 받았으며, MLP가 노드(“뉴런”)에 고정된 활성화 함수를 배치함.
KAN: MLP와 마찬가지로 KAN도 완전 연결 구조를 가지고 있으며, Kolmogorov-Arnold 표현 정리에 영감을 받음.
KAN은 엣지(“가중치”)에 학습 가능한 활성화 함수를 배치함.
→ 선형 가중치 행렬이 전혀 없음
각 가중치 매개변수는 학습 가능한 1D 함수로 대체됨.
KAN의 노드는 들어오는 신호를 단순히 합산하며, 비선형성을 적용하지 않음.


[KAN is Cost Expensive?]

MLP의 가중치 매개변수가 KAN의 스플라인 함수로 대체되므로, KAN이 매우 비쌀 것이라는 걱정이 있을 수 있음.
다행히도 KAN은 일반적으로 MLP보다 훨씬 작은 계산 그래프를 사용함.
ex) PDE(편미분) 풀이: KAN(2-Layer width-10
)은 MLP(4-Layer width-100)보다
100배 더 정확하고(10-7 대 10-5 MSE), 100배 더 매개변수 효율적(102 대 104 매개변수).



[선행 연구 & Main Contribution]

대부분의 작업은 원래의 Depth-2  Width-(2n + 1)표현에 머물렀으며, train을 위해 최신 기술(예: 역전파)을 활용할 기회❌.

Main Contribution:
Kolmogorov-Arnold 표현을 임의의 폭과 깊이로 일반화하여 오늘날의 딥러닝 세계에서 다시 활력을 불어넣고 맥락화하는 것
또한, KAN의 정확성과 해석 가능성 덕분에 AI + 과학의 기초 모델로서의 잠재적 역할을 강조하는 광범위한 실험을 사용하는 것.

KAN은 수학적으로 우아한 해석에도 불구하고, 단지 스플라인과 MLP의 조합일 뿐입니다. 
스플라인:
저차원 함수에 대해 정확 / 로컬에서 조정하기 쉬움 / 서로 다른 해상도 간 전환이 가능.
다만, 구성 구조를 활용할 수 없기 때문에(= 외부자유도❌) 심각한 차원의 저주(COD) 문제를 가지고 있다.

MLP는 COD 문제가 덜하지만, 저차원에서는 스플라인보다 덜 정확함.
MLP는 일반화된 덧셈구조를 잠재적으로 학습가능하지만 ReLU로 인해 exp와 sin함수를 근사화하는데 매우 비효율적임.
예를들어, 우측같은 고차원 스플라인 함수는 COD로 인해 큰 N에 대해 실패한다. 
대조적으로 KAN은 구성구조와 단변량함수를 모두 매우 잘 학습하기에 MLP를 큰 차이로 능가한다.



[함수를 정확하게 학습하려면?]

구성 구조(외부 자유도)를 학습하고 단변량 함수(내부 자유도)를 잘 근사해야 함.
 - 외부적으로는 MLP와 유사하여 기능을 학습할 수 있고,
 - 내부적으로는 스플라인과 유사하여 학습된 기능을 최적화할 수 있음.


2장: KAN의 아키텍처와 수학적 기초를 소개하고, KAN을 해석 가능하게 만드는 네트워크 단순화 기법을 소개하며, KAN을 점점 더 정확하게 만드는 그리드 확장 기법을 소개.
3장: KAN이 데이터 적합 및 PDE 풀이에서 MLP보다 더 정확함을 보여줌.
4장: KAN이 해석 가능하며 과학적 발견에 사용할 수 있음을 보여줌.
5장: 관련 연구를 요약.
6장: 광범위한 영향과 미래 방향을 논의하면서 결론.
코드는 https://github.com/KindXiaoming/pykan 사용할 수 있으며, pip install pykan을 통해 설치할 수 있다.



∙ Discussion:

[수학적 측면]

KAN 대한 초기 수학적 분석(Theorem 2.1) 제시했지만, KAN 대한 수학적 이해는 여전히 제한적. 
Kolmogorov-Arnold
표현 정리는 수학적으로 철저히 연구되었지만, 정리는 [n, 2n + 1, 1] 형태의 KAN 해당하며 이는 매우 제한된 하위 클래스이기에, 깊은 KAN에서의 경험적 성공은 수학적으로 근본적인 무언가를 암시하는걸까?

이에 대해 매력적인 일반화된 Kolmogorov-Arnold 정리는 Depth-2 Composition 너머의 깊은” Kolmogorov-Arnold 표현을 정의하고 활성화 함수의 매끄러움을 깊이와 관련시킬 있음을 시사한다.
가설적으로, 원래의 (Depth-2) Kolmogorov-Arnold 표현에서는 매끄럽게 표현할 없는 함수들이 Depth-3 또는 이상의 표현으로 매끄럽게 표현될 있다. 우리는 “Kolmogorov-Arnold 깊이개념을 사용하여 함수 클래스를 특성화할 있을까?

 

[알고리즘적 측면]

1. 정확성: 아키텍처 설계 훈련에서 여러 선택지가 충분히 조사되지 않았기 때문에 대안이 정확성을 더욱 향상시킬  있음.
 예를 들어, 스플라인 활성화 함수는 radial basis함수 또는 local kernel 대체될  있으며, 
Adaptive Grid
전략이 사용될 있다.

 

2. 효율성: KAN이 느리게 실행되는 주요 이유 하나는 다른 활성화 함수가 배치 계산(큰 데이터를 동일한 함수로 처리)을 활용❌.
실제로, 활성화 함수가 모두 동일한 경우(MLP) 모두 다른 경우(KAN) 사이를 보간하여 활성화 함수를 여러 그룹(multi-head)으로 묶을 있는데, 여기서 그룹 내의 구성원은 동일한 활성화 함수를 공유합니다.

3. KAN과 MLP의 하이브리드: KAN은 MLP와 비교할 때 두 가지 주요 차이점이 있다:
 (i). 활성화 함수가 노드가 아닌 엣지에 배치됩니다.
 (ii). 활성화 함수가 고정된 것이 아닌, 학습 가능함.
KAN의 이점을 설명하기 위해 어떤 변화가 더 중요한지 알아보기 위해, Appendix B에서 (ii)를 갖춘 모델을 연구한 예비 결과를 제시한다. 즉, 활성화 함수는 학습 가능하지만 (i)를 갖추지 않은 모델, 즉 활성화 함수가 노드에 위치한 모델이며, 더 나아가 고정된 활성화 함수(MLP처럼)를 가지지만 엣지에 위치한 모델(KAN처럼)을 구성할 수도 있다.

4. 적응성: 스플라인 기저 함수의 본질적인 locality 덕분에, 우리는 KAN의 설계 및 훈련에서 적응성을 도입하여 정확도와 효율성을 모두 향상시킬 수 있다.


 

[응용적 측면]

KAN 응용 가능성을 논의하며, KAN 다양한 실세계 문제에서 어떻게 적용될 있는지에 대해 탐구하는데, 물리학, 수학 과학적 발견의 기초 모델로서 KAN 잠재력을 강조한다.

 

논문은 KAN 수학적 기초, 알고리즘적 개선 다양한 응용 분야에서의 잠재력을 탐구함으로써 KAN 한계를 극복하고 미래 방향을 제시합니다. KAN 코드는 [https://github.com/KindXiaoming/pykan](https://github.com/KindXiaoming/pykan)에서 사용할 있으며, `pip install pykan` 통해 설치할 있다.





∙ Related Works

Kolmogorov-Arnold Theorem과 신경망

Kolmogorov-Arnold 정리(KAT) 신경망 간의 관계는 완전히 새로운 것은 아님.
다만, 내부함수의 pathological behavior(비정상적 행동)으로 KAT가 유망하지 않게 보였음.

[대부분의 이전연구들]  
2-layer width-(2n+1) 신경망에 머물렀음. (= 표현력이 제한적, 역전파개념 이전에 연구가 많이들 진행되었었음.)
∴ 대부분연구들이 제한적&인위적 toy 실험에 머물렀었음.

[Contribution]:
1. 신경망을 임의의 폭과 깊이로 일반화
2. 현재의 딥러닝흐름에 재활성화 & 맥락화
3. AI + Science의 기반모델(foundation model)로서의 잠재적인 역할을 강조.

 

 

Neural Scaling Laws (NSLs)

[NSL이란?]
모델 크기, 데이터, 계산 등에 대해 test Loss가 거듭제곱 법칙으로 나타나는 현상.
NSL 기원은 여전히 불가사의하지만, 아래와 같은 유력이론이 존재:
 ∙ intrinsic dimensionality
 ∙ quantization of tasks
 ∙ resource theory
 ∙ random features
 ∙ compositional sparsity
 ∙ maximuarity

[본 논문의 Contribution]:
Smooth Kolmogorov-Arnold 표현을 갖는 고차원 함수가 1차원 함수(이는 기대할  있는 최고의 경계)처럼 스케일링될 있음. 
즉, 가장 빠른 스케일링 지수를 보장해서 신경망의 스케일링 법칙에 새로운 관점을 가져옴.

 

Machanistic Interpretability (MI)

MI 신경망의 내부 작동을 기계적으로 이해하려는 신흥 분야; 수동MI연구 / 능동MI연구로 나뉨.
본 논문은 모델과 훈련 방법이 설계상 해석 가능한 두 번째 범주 속함.


 

Learnable Activations

신경망에서 학습 가능한 활성화 함수의 아이디어는 기계 학습에서 완전히 새로운 것이 아님.
학습 가능한 활성화 함수는 미분 가능한 방식으로 학습되거나 이산적으로 검색됨.
활성화 함수는 다음과 같이 매개변수화됨: 다항식, 스플라인, sigmoid linear unit, neural net

여기서, KAN은 B-스플라인을 사용하여 활성화 함수를 매개변수화함.

 

Symbolic Regression

기존 방법:
Genetic알고리즘(Eureka, GPLearn, PySR) 
Neural-Net기반알고리즘(EQL, OccamNet)
 
물리학영감받은 방법(AI Feynman)
강화 학습 기반 방법.

KAN은 신경망 기반 방법과 가장 유사하지만, 활성화 함수는 수동으로 고정되지 않고 기호 스냅핑 전에 지속적으로 학습된다는 점에서 이전 작업과 다름.

 


Physics-Informed Neural Networks (PINNs)
Physics-Informed Neural Operators (PINOs)

3.4절에서 KAN PDE 해결할 PDE 손실을 부과하기 위해 MLP 사용하는 패러다임을 대체할 있음을 보여줌.
PDE 해결을 위한 Deep Ritz Method, PINNs, 연산자 학습 방법의 솔루션 맵을 학습하는 Fourier Neural Operator, PINOs, DeepONet 참조하며, 언급된 모든 네트워크에서 MLP를 KAN으로 대체할 가능성이 있음.

 


AI for Mathematics

4.3처럼, AI는 최근 매듭 이론(Knot Theory)의 여러 문제에 적용된다.
여기에는 매듭이 풀린 매듭인지 리본 매듭인지 감지하고,
매듭 불변량을 예측하고 그들 사이의 관계를 발견하는 작업이 포함된다.

수학 이론 물리학의 데이터 세트에 대한 데이터 과학 응용 프로그램 요약은 [90, 91] 참조하고,
이러한 분야에서 ML 기술을 사용하여 엄격한 결과를 얻는 방법에 대한 아이디어는 [92] 참조하십시오.

[90] Fabian Ruehle. Data science applications to string theory. Phys. Rept., 839:1–117, 2020.

[91] Y.H. He. Machine Learning in Pure Mathematics and Theoretical Physics. G - Reference,Information and Interdisciplinary Subjects Series. World Scientific, 2023.

[92] Sergei Gukov, James Halverson, and Fabian Ruehle. Rigor with machine learning from field theory to the poincaréconjecture. Nature Reviews Physics, 2024.

 

 

 

 

 

 

 

 

③ Main Method, Math , etc 이해안되는 것  → Skim or Skip

∙ KAN

다층 퍼셉트론(MLP) 보편적 근사 정리에 영감을 받았습니다. 반면, 우리는 Kolmogorov-Arnold 표현 정리에 초점을 맞추어, Kolmogorov-Arnold 네트워크(KAN)라는 새로운 유형의 신경망을 제안합니다. 2.1절에서는 Kolmogorov-Arnold 정리를 검토하여 2.2절에서 Kolmogorov-Arnold 네트워크의 설계에 영감을 줍니다. 2.3절에서는 KAN 표현력과 신경 스케일링 법칙에 대한 이론적 보장을 제공합니다. 2.4절에서는 KAN 점점 정확하게 만드는 그리드 확장 기법을 제안합니다. 2.5절에서는 KAN 해석 가능하게 만드는 단순화 기법을 제안합니다.



 Kolmogorov-Arnold Representation theorem

Vladimir Arnold Andrey Kolmogorov f 유계 영역에서 다변수 연속 함수인 경우, f 단일 변수의 연속 함수와 덧셈 이항 연산의 유한 합성으로 표현할 있음을 입증했습니다. 구체적으로, 매끄러운

 함수에 대해,

여기서 Φ𝑞:𝑅→𝑅입니다. 어떤 의미에서는 모든 다변수 함수가 단변수 함수와 합으로 작성될 있기 때문에 진정한 다변수 함수는 덧셈뿐임을 보여주었습니다. 이는 기계 학습에 있어 고차원 함수를 학습하는 것이 다항식 수의 1D 함수를 학습하는 것으로 귀결되므로 희소식일 있습니다. 그러나 이러한 1D 함수들이 매끄럽지 않거나 심지어 프랙탈일 있기 때문에 실제로 학습하기 어려울 있습니다. 이러한 병리학적 특성 때문에 Kolmogorov-Arnold 표현 정리는 기계 학습에서 이론적으로는 타당하지만 실질적으로는 쓸모없다고 여겨졌습니다.

 

그러나 우리는 Kolmogorov-Arnold 정리가 기계 학습에 유용할 것이라는 점에 대해 낙관적입니다. 첫째, 우리는 은닉층에서 2n+1개의 항을 가지는 2 비선형성을 가지는 원래의 방정식(2.1) 고수할 필요가 없습니다. 네트워크를 임의의 폭과 깊이로 일반화할 것입니다. 둘째, 과학과 일상 생활에서 대부분의 함수는 종종 매끄럽고 희소한 구성 구조를 가지며, 이는 매끄러운 Kolmogorov-Arnold 표현을 촉진할 있습니다. 여기서 철학은 물리학자들의 사고방식과 가깝습니다. 물리학자들은 최악의 경우보다 일반적인 경우에 관심을 가집니다. 결국, 우리의 물리적 세계와 기계 학습 작업은 물리학과 기계 학습이 유용하거나 일반화 가능하게 만들기 위해 구조를 가져야 합니다.



 KAN Architecture

지도 학습 작업에서 입력-출력 쌍 (𝑥𝑖,𝑦𝑖)(xi​,yi​)가 주어졌을 때, 모든 데이터 포인트에 대해 𝑦𝑖≈𝑓(𝑥𝑖)yi​≈f(xi​)를 만족하는 f를 찾는 것이 목표입니다. 방정식 (2.1)은 적절한 단변량 함수 𝜑𝑞,𝑝φq,p​와 Φ𝑞Φq​를 찾으면 된다는 것을 의미합니다. 이는 방정식 (2.1)을 명시적으로 매개변수화하는 신경망을 설계하도록 영감을 줍니다. 학습할 모든 함수가 단변량 함수이므로, 각 1D 함수를 B-스플라인 곡선으로 매개변수화하고, 국소 B-스플라인 기저 함수의 학습 가능한 계수를 사용합니다. 이제 KAN의 프로토타입이 있으며, 그 계산 그래프는 방정식 (2.1)에 의해 정확하게 지정됩니다.

기본적으로, KAN 계층은 𝑛𝑖𝑛nin​-차원 입력과 𝑛𝑜𝑢𝑡nout​-차원 출력을 가지는 1D 함수의 행렬로 정의될 수 있습니다. Kolmogorov-Arnold 정리에서는 내부 함수가 𝑛𝑖𝑛=𝑛nin​=n 및 𝑛𝑜𝑢𝑡=2𝑛+1nout​=2n+1을 가지는 KAN 계층을 형성하고, 외부 함수는 𝑛𝑖𝑛=2𝑛+1nin​=2n+1 및 𝑛𝑜𝑢𝑡=1nout​=1을 가지는 KAN 계층을 형성합니다. 따라서 방정식 (2.1)에서의 Kolmogorov-Arnold 표현은 두 KAN 계층의 합성으로 구성됩니다. 이제 더 깊은 Kolmogorov-Arnold 표현이 무엇을 의미하는지 명확해졌습니다: 더 많은 KAN 계층을 쌓으면 됩니다.

일반 KAN 네트워크는 L 계층의 합성으로 구성됩니다: 입력 벡터 𝑥0∈𝑅𝑛0x0​∈Rn0​가 주어졌을 때, KAN의 출력은 다음과 같습니다:

𝐾𝐴𝑁(𝑥)=(Φ𝐿−1∘Φ𝐿−2∘⋯∘Φ1∘Φ0)𝑥KAN(x)=(ΦL−1​∘ΦL−2​∘⋯∘Φ1​∘Φ0​)x

KAN 계층의 모양은 정수 배열 [𝑛0,𝑛1,⋅⋅⋅,𝑛𝐿][n0​,n1​,⋅⋅⋅,nL​]로 표현됩니다. 각 계층에서 (l, i)-뉴런의 활성화 값은 𝑥𝑙,𝑖xl,i​로 표시됩니다. 계층 l과 l+1 사이에는 𝑛𝑙⋅𝑛𝑙+1nl​⋅nl+1​ 활성화 함수가 있으며, 활성화 함수는 𝜑𝑙,𝑗,𝑖φl,j,i​로 표시됩니다. (l, i)-뉴런과 (l+1, j)-뉴런을 연결하는 활성화 함수의 사전 활성화 값은 단순히 𝑥𝑙,𝑖xl,i​이며, 후 활성화 값은 𝑥~𝑙,𝑗,𝑖≡𝜑𝑙,𝑗,𝑖(𝑥𝑙,𝑖)x~l,j,i​≡φl,j,i​(xl,i​)입니다. (l+1, j)-뉴런의 활성화 값은 모든 들어오는 후 활성화 값의 합입니다:

𝑥𝑙+1,𝑗=∑𝑖=1𝑛𝑙𝜑𝑙,𝑗,𝑖(𝑥𝑙,𝑖),𝑗=1,⋯ ,𝑛𝑙+1xl+1,j​=∑i=1nl​​φl,j,i​(xl,i​),j=1,⋯,nl+1​

MLP와 KAN의 주요 차이점은 MLP는 선형 변환과 비선형성을 별도로 취급하는 반면, KAN은 이를 모두 비선형 함수로 통합하여 처리한다는 점입니다. KAN은 모든 연산이 미분 가능하므로 역전파로 훈련할 수 있습니다【40†source】.
 

 



 KAN's Approximation Abilities and Scaling Laws

2층 폭-(2n + 1) 표현은 매끄럽지 않을 수 있습니다. 그러나 더 깊은 표현은 매끄러운 활성화를 제공할 수 있습니다. 예를 들어, 4변수 함수
𝑓(𝑥1,𝑥2,𝑥3,𝑥4)=exp(sin(x12+x 22)+sin(x32+x42)) 는 3층 [4, 2, 1, 1] KAN으로 매끄럽게 표현될 수 있지만, 매끄러운 활성화로 2층 KAN으로는 표현되지 않을 수 있습니다. 우리는 활성화의 매끄러움을 가정하지만, 표현은 임의의 폭과 깊이를 가질 수 있도록 허용합니다.

Theorem 2.1에 따르면, 매끄러운 Kolmogorov-Arnold 표현이 존재하면, KAN은 차원의 저주를 극복할 수 있으며, 이는 고차원 함수를 구성 구조와 단변량 함수로 나눌 수 있기 때문입니다. 이는 데이터 적합 및 PDE 해결에서 KAN이 MLP보다 훨씬 우수한 성능을 보임을 의미합니다.


 For Accuracy: Grid Extension

원칙적으로, 스플라인은 그리드를 세밀하게 만들어 목표 함수를 임의로 정확하게 근사할 수 있습니다. 이 좋은 특징은 KAN이 상속합니다. 반면, MLP는 "세분화" 개념이 없습니다. KAN은 적은 매개변수로 먼저 훈련하고, 스플라인 그리드를 세밀하게 만들어 더 많은 매개변수를 가지는 KAN으로 확장할 수 있습니다. 이는 더 큰 모델을 처음부터 다시 훈련할 필요 없이 가능합니다.

그리드 확장 수행 방법
1D 함수 f를 유한한 구간 [a, b]에서 B-스플라인으로 근사하려면, coarse-grained 그리드와 fine-grained 그리드를 사용하여 f를 나타냅니다. coarse-grained 그리드에서의 f는 B-스플라인 기저 함수의 선형 조합으로 표현됩니다. fine-grained 그리드에서의 f는 새로운 B-스플라인 기저 함수의 선형 조합으로 표현됩니다. 이때, coarse-grained 그리드의 매개변수를 fine-grained 그리드의 매개변수로 최소 제곱 알고리즘을 사용하여 초기화합니다.

이 방법을 사용하여, KAN은 더 작은 네트워크로 시작하여 더 큰 네트워크로 확장할 수 있습니다. 이는 KAN이 매우 효율적이고 효과적으로 정확성을 높일 수 있음을 보여줍니다.


 For Interpretability: Simplifying KANs and Making them interactive

KAN을 데이터셋 구조에 가장 잘 맞추는 모양을 선택하는 방법을 모르는 경우, 충분히 큰 KAN에서 시작하여 희소성 정규화를 사용하여 훈련한 후 가지치기를 통해 작은 서브 네트워크로 단순화합니다. 이러한 가지치기된 KAN은 비 가지치기된 KAN보다 훨씬 더 해석 가능합니다. KAN을 최대한 해석 가능하게 만들기 위해 몇 가지 단순화 기법을 제안합니다.

 

### 2.5.1 단순화 기법

 

1. **희소화**: MLP 경우, 선형 가중치의 L1 정규화를 사용하여 희소성을 촉진합니다. KAN 이러한 고수준 아이디어를 적용할 있지만, 가지 수정이 필요합니다:

   (1) KAN에는 선형 "가중치" 없습니다. 선형 가중치는 학습 가능한 활성화 함수로 대체되므로 이러한 활성화 함수의 L1 노름을 정의해야 합니다.

   (2) KAN 희소화를 위해 L1 충분하지 않으며, 추가로 엔트로피 정규화가 필요합니다(자세한 내용은 부록 C 참조).

 

2. **시각화**: KAN 시각화할 크기의 감각을 얻기 위해 활성화 함수 ϕl,i,j 투명도를 tanh(βAl,i,j) 비례하도록 설정합니다. 여기서 β = 3입니다. 따라서 작은 크기의 함수는 중요하지 않게 나타나서 중요한 함수에 집중할 있습니다.

 

3. **Pruning**: 희소화 페널티로 훈련한 , 네트워크를 작은 서브네트워크로 가지치기할 있습니다. 우리는 KAN 엣지 수준이 아닌 노드 수준에서 희소화합니다. 노드(: l층의 i번째 뉴런) 대해, 들어오는 점수와 나가는 점수를 다음과 같이 정의합니다:

그리고 점수 모두 임계값 하이퍼파라미터 θ = 10^{-2}(기본값)보다 경우 해당 노드를 중요하다고 간주합니다. 모든 중요하지 않은 뉴런은 가지치기됩니다.

 

4. **심볼화**: 어떤 활성화 함수가 사실 기호적이라고 의심되는 경우(: cos 또는 log), 이를 지정된 기호적 형태로 설정할 있는 인터페이스를 제공합니다. fix_symbolic(l,i,j,f) (l, i, j) 활성화를 f 설정할 있습니다. 그러나 활성화 함수를 정확한 기호 공식으로 단순히 설정할 수는 없습니다. 입력과 출력이 이동 스케일링될 있기 때문입니다. 따라서 우리는 샘플에서 사전 활성화 x 활성화 y 얻고, y ≈ cf(ax + b) + d 되도록 아핀 매개변수(a, b, c, d) 맞춥니다. 적합은 반복적 그리드 검색 선형 회귀로 수행됩니다.

 

#### 2.5.2 장난감 예제: KAN과의 상호작용

 

위에서 KAN 단순화하기 위한 여러 기술을 제안했습니다. 이러한 단순화 선택은 클릭할 있는 버튼으로 있습니다. 사용자가 이러한 버튼을 클릭하여 KAN 해석 가능하게 만드는 가장 유망한 버튼을 결정할 있습니다. 아래 예제를 사용하여 사용자가 KAN 상호작용하여 최대한 해석 가능한 결과를 얻는 방법을 보여줍니다.

 

회귀 작업을 다시 고려해 보겠습니다:

주어진 데이터 포인트

 

가설적 사용자 Alice 기호 수식을 알아내는 관심이 있습니다. Alice KAN과의 상호작용 단계는 아래에 설명되어 있습니다(Figure 2.4 설명되어 있습니다):

 

**1단계: 희소화로 훈련**: 완전히 연결된 [2, 5, 1] KAN에서 시작하여 희소화 정규화로 훈련하면 상당히 희소화될 있습니다. 은닉층의 5개의 뉴런 4개가 쓸모없어 보이므로, 이를 제거하고자 합니다.

 

**2단계: Pruning**: 자동 가지치기는 마지막 하나를 제외한 모든 은닉 뉴런을 삭제하여 [2, 1, 1] KAN 남깁니다. 활성화 함수는 알려진 기호 함수인 같습니다.

 

**3단계: 기호 함수 설정**: 사용자가 KAN 플롯을 보고 이러한 기호 공식을 올바르게 추측할 있다고 가정하면, 다음과 같이 설정할 있습니다:

사용자가 도메인 지식이 없거나 이러한 활성화 함수가 어떤 기호 함수인지 전혀 모르는 경우, 우리는 기호 후보를 제안하는 함수를 제공합니다.

 

**4단계: 추가 훈련**: 네트워크의 모든 활성화 함수를 기호화한 , 남은 매개변수는 아핀 매개변수뿐입니다. 아핀 매개변수를 계속 훈련하며, 손실이 머신 정밀도로 떨어지는 것을 올바른 기호 표현을 찾았다는 것을 있습니다.

 

**5단계: 기호 수식 출력**: Sympy 사용하여 출력 노드의 기호 수식을 계산합니다. 사용자는 1.0e1.0y^2 + 1.0sin(3.14x) 얻으며, 이는 진정한 답입니다 대해 자리만 표시했습니다).

 


 

 

∙ KANs are accurate

섹션에서는 KANs 다양한 작업(회귀 PDE 해결)에서 MLPs보다 효과적으로 함수를 표현할 있음을 보여줍니다. 모델군을 비교할 , 정확도(손실) 복잡성(매개변수 ) 공정하게 비교하는 것이 중요합니다. 우리는 KANs MLPs보다 유리한 파레토 프론티어를 나타낸다는 것을 보여줄 것입니다. 또한, 3.5절에서는 KANs 연속 학습에서도 재난적 망각 없이 자연스럽게 작동할 있음을 보여줍니다.

 

#### 3.1 장난감 데이터셋

 

KANs 고차원 함수의 구성 구조와 단변량 함수를 모두 학습할 있어 MLPs보다 훨씬 우수한 성능을 발휘합니다.

 

Figure 3.1: KANs MLPs 다섯 가지 장난감 예제에서 비교합니다. KANs 이론적으로 예측된 가장 빠른 스케일링 법칙(α = 4) 거의 포화시킬 있는 반면, MLPs 느리게 스케일링되고 빠르게 정체됩니다.

 

#### 3.2 특수 함수

 

특수 함수의 경우, KANs MLPs보다 효율적이고 정확합니다. 우리는 수학 물리학에서 흔히 사용되는 15개의 특수 함수를 수집했으며, 이들은 Table 2 요약되어 있습니다. 데이터셋과 모델군(KANs 또는 MLPs) 대해, 파라미터 수와 RMSE 손실로 구성된 평면에 파레토 프론티어를 그렸습니다(Figure 3.2 참조). KANs 성능이 MLPs보다 일관되게 우수함을 보여줍니다.

 

#### 3.3 파인만 데이터셋

 

파인만 데이터셋에 대한 많은 결과는 부록 D 포함되어 있습니다. Figure D.1 파인만 데이터셋에 대한 KANs MLPs 파레토 프론티어를 보여줍니다. Figure D.2 D.3 파인만 방정식 맞춤 작업에 대한 최소 KAN 최상의 KAN 시각화합니다.

 

#### 3.4 편미분 방정식(PDE) 해결

 

우리는 제로 디리클렛 경계 데이터를 가진 포아송 방정식을 고려합니다. 예를 들어, Ω = [−1, 1]²에서 PDE 고려합니다.

#### 3.5 연속 학습

 

재난적 망각은 현재 기계 학습의 심각한 문제입니다. 인간이 작업을 익히고 다른 작업으로 전환할 , 번째 작업을 수행하는 방법을 잊지 않습니다. 불행히도, 신경망은 그렇지 않습니다. 신경망이 작업 1 대해 훈련된 작업 2 대해 훈련되면, 작업 1 수행하는 방법을 잊어버립니다. 이는 아마도 인공 신경망과 인간 두뇌의 주요 차이점 하나일 것입니다.

 

우리는 KANs 국부적 가소성을 가지고 있으며 스플라인의 국부성을 활용하여 재난적 망각을 피할 있음을 보여줍니다. 아이디어는 간단합니다. 스플라인 기반은 국부적이기 때문에 샘플은 가지 인접한 스플라인 계수에만 영향을 미치며, 곳의 계수는 그대로 남아 있습니다.



### 그림 설명

- **Figure 3.1**: KANs MLPs 다섯 가지 장난감 예제에서 비교합니다.



- **Figure 3.2**: 특수 함수를 맞추는 있어 KANs MLPs 파레토 프론티어를 보여줍니다.


- **Figure 3.3**: PDE 예제. 예측 솔루션과 실제 솔루션 간의 L2 제곱 H1 제곱 손실을 플로팅합니다.



- **Table 2**:
특수 함수의 정의 이들에 대한 KANs MLPs 성능을 요약합니다.

이로써, KANs 다양한 작업에서 MLPs보다 높은 정확도를 제공할 있음을 보여줍니다 .

 

 

 

∙ KANs are interpretable

섹션에서는 KANs 해석 가능하고 상호작용할 있음을 보여줍니다. 우리는 KANs 합성 작업(4.1 4.2)뿐만 아니라 실제 과학 연구에도 적용해보고자 합니다. KANs 매듭 이론(4.3) 응축 물질 물리학의 상전이 경계(4.4)에서 매우 비정상적인 관계를 ()발견할 있음을 증명합니다. KANs 정확성(이전 섹션) 해석 가능성( 섹션) 덕분에 AI + 과학의 기초 모델이 있습니다.

 

#### 4.1 지도 학습 장난감 데이터셋

 

우리는 먼저 KANs 기호 수식에서 구성적 구조를 밝히는 능력을 조사합니다. 여섯 가지 예가 아래 나열되어 있으며, 해당 KANs Figure 4.1 시각화되어 있습니다. KANs 수식들에 존재하는 구성적 구조를 밝히고, 올바른 단변량 함수를 학습할 있습니다.

 

(a) 곱셈 f(x, y) = xy. [2, 5, 1] KAN [2, 2, 1] KAN으로 가지치기됩니다. 학습된 활성화 함수는 선형 2 함수입니다. 계산 그래프에서 xy 계산하는 방법은 2xy = (x + y)^2 - (x^2 + y^2) 활용하는 것입니다.

 

(b) 양수의 나눗셈 f(x, y) = x/y. [2, 5, 1] KAN [2, 1, 1] KAN으로 가지치기됩니다. 학습된 활성화 함수는 로그 지수 함수이며, KAN x/y 로그와 지수 함수를 이용해 계산합니다.

 

(c) 수치에서 범주로 변환. 작업은 [0, 1] 범위의 실수를 번째 소수 자리로 변환합니다(: 0.0618 → [1, 0, 0, 0, 0, ··· ], 0.314 → [0, 0, 0, 1, 0, ··· ]). 활성화 함수는 해당 소수 자리에 위치한 스파이크로 학습됩니다.

 

(d) 특수 함수 f(x, y) = exp(J0(20x) + y^2). 기호 회귀의 한계 하나는 사전 지식으로 제공되지 않은 특수 함수의 정확한 수식을 찾지 못한다는 것입니다. KANs 특수 함수를 학습할 있으며, 여기서는 매우 파형이 많은 Bessel 함수 J0(20x) 수치적으로 학습합니다.

 

#### 4.2 해석 가능한 과학적 발견

 

KANs 해석 가능성 덕분에, 우리는 KANs 복잡한 과학적 문제를 해결하는 어떻게 도움이 되는지 보여줍니다. 예를 들어, KANs 매듭 이론과 응축 물질 물리학에서 새로운 통찰을 제공할 있습니다.

 

#### 4.3 수학에의 응용: 매듭 이론

 

매듭 이론은 저차원 위상수학의 분야로, 생물학 위상 양자 컴퓨팅을 포함한 다양한 응용 분야를 가지고 있습니다. 매듭 K S^1 S^3 임베딩한 것입니다. 매듭 K K' 하나를 다른 것으로 변형할 있으면 위상적으로 동등합니다. 매듭은 다양한 변형 불변 특성을 가지고 있으며, 이를 통해 매듭이 위상적으로 다름을 보여줄 있습니다. 예를 들어, 하이퍼볼릭 매듭 K 하이퍼볼릭 부피를 가지며, 이는 매듭의 위상적 불변량입니다.

 

KANs 사용하여 매듭 이론의 데이터셋에서 지도 학습을 통해 새로운 결과를 도출할 있는지 연구합니다. 주요 결과는 다음과 같습니다:

 

1. 서명 σ 주로 메리디안 거리 µ(실수 µr, 허수 µi) 종단 거리 λ 의존한다는 것을 발견했습니다.

2. σ 경사와 높은 상관관계를 가지며, 이를 통해 |2σ - slope| 경계를 도출했습니다.

 

KANs 이러한 결과를 훨씬 작은 네트워크와 많은 자동화를 통해 다시 발견할 있습니다. KANs 매듭 이론에서 새로운 관계를 발견하는 매우 직관적이고 편리한 도구임을 증명합니다.

 

#### 4.4 물리학에의 응용: 앤더슨 국소화

 

앤더슨 국소화는 양자 시스템에서 무질서가 전자의 파동 함수를 국소화시켜 모든 전도를 중단시키는 현상입니다. 3차원에서는 임계 에너지가 국소화 상태와 확장 상태를 분리하는 상전이 경계를 형성합니다. KANs 사용하여 준주기적 타이트 바인딩 모델에서 이동성 가장자리를 추출할 있습니다. 여기서는 가지 모델: 모자이크 모델(MM), 일반화된 오브리-안드레 모델(GAAM), 수정된 오브리-안드레 모델(MAAM) 조사합니다. KANs 이들 모델에서 이동성 가장자리를 정확하게 추출할 있음을 보여줍니다.

 

이로써 KANs 매듭 이론과 응축 물질 물리학에서 새로운 과학적 발견을 돕는 유용한 도구가 있음을 증명합니다 .

 

 

 

 

 

cf) Acknowledgement

 

 

 

cf) Appendix.

A. KAN의 기능들

Table 7 사용자가 유용하게 사용할 있는 일반적인 기능들을 포함합니다.

 

 

 

B. Learnable Activation Networks (LANs)

B.1 Architecture

KAN 외에도, 스플라인으로 매개변수화된 학습 가능한 활성화 함수가 있는 거의 MLP와 유사한 또 다른 유형의 네트워크(LAN)를 제안했습니다. KAN은 표준 MLP와 비교하여 두 가지 주요 변경 사항이 있습니다: (1) 활성화 함수가 고정되지 않고 학습 가능하며; (2) 활성화 함수가 노드가 아닌 엣지에 배치됩니다. 이 두 요소를 분리하기 위해, 노드에 여전히 학습 가능한 활성화 함수가 있는 학습 가능한 활성화 네트워크(LAN)를 제안합니다. 이는 Figure B.1에 나와 있습니다.

 

폭 N, 깊이 L, 그리드 포인트 수 G인 LAN의 경우, 매개변수의 수는 N^2L + NLG입니다. 여기서 N^2L은 가중치 행렬의 매개변수 수, NLG는 스플라인 활성화 함수의 매개변수 수를 나타냅니다. 일반적으로 G ≪ N이기 때문에 NLG ≪ N^2L입니다. LAN은 MLP와 유사하므로 사전 훈련된 MLP에서 초기화하고 학습 가능한 활성화 함수를 허용하여 미세 조정할 수 있습니다. 예제로는 LAN을 사용하여 SIREN을 개선하는 것이 Section B.3에 제시되어 있습니다.

 

**LAN과 KAN의 비교:**

LAN의 장점:

1. LAN은 개념적으로 KAN보다 더 단순합니다. 표준 MLP에 더 가깝습니다(유일한 변경 사항은 활성화 함수가 학습 가능해진 것입니다).

2. LAN은 KAN보다 더 잘 확장됩니다. LAN/KAN은 각각 노드/엣지에 학습 가능한 활성화 함수를 가지므로, LAN/KAN의 활성화 매개변수는 모델 폭 N에 따라 각각 N/N^2로 확장됩니다.

 

LAN의 단점:

1. LAN은 해석 가능성이 떨어집니다(가중치 행렬은 MLP와 마찬가지로 해석하기 어렵습니다).

2. LAN은 KAN보다 덜 정확한 것으로 보이지만 여전히 MLP보다는 더 정확합니다. LAN도 스플라인으로 매개변수화된 활성화 함수가 있는 경우 그리드 확장을 허용합니다.

 

 

B.2 LAN interpretability results

Figure B.1: 장난감 예제 f(x, y) = exp(sin(πx)+y^2)에 대한 학습 가능한 활성화 네트워크(LAN)의 훈련

Figure B.2: 합성 예제에서의 LAN. LAN은 매우 해석 가능성이 없는 것으로 보입니다. 우리는 가중치 행렬이 너무 많은 자유도를 남긴다고 추측합니다.

저희는 그림 B.2에서 LAN의 예비 해석 가능성 결과를 제시합니다. KAN이 완벽하게 해석 가능한 그림 4.1의 동일한 예에서 LAN은 가중치 행렬의 존재로 인해 훨씬 덜 해석 가능해 보입니다. 첫째, 가중치 행렬은 학습 가능한 활성화 함수보다 쉽게 해석할 수 없습니다. 둘째, 가중치 행렬은 너무 많은 자유도를 가져와 학습 가능한 활성화 함수를 너무 제약하지 않게 만듭니다. LAN에 대한 예비 결과는 선형 가중치 행렬을 제거하는 것이 (KAN과 같이 가장자리에 학습 가능한 활성화를 가짐으로써) 해석 가능성에 필요하다는 것을 의미하는 것으로 보입니다.

 

 

B.3 Fitting Images(LAN)

암시적 신경 표현은 이미지를 2D 함수 f(x,y)로 보고, 여기서 픽셀 값 f는 픽셀 x와 y의 두 좌표에 대한 함수입니다. 이미지를 압축하기 위해 이러한 암시적 신경 표현(f는 신경망)은 거의 원본 이미지 품질을 유지하면서 매개 변수를 인상적으로 압축할 수 있습니다. 사이렌[96]은 함수 f에 맞추기 위해 주기적인 활성화 함수가 있는 MLP를 사용할 것을 제안했습니다. LAN에서 허용되는 다른 활성화 함수를 고려하는 것은 당연합니다. 그러나 LAN 활성화를 원활하게 초기화하지만 사이렌에는 고주파 기능이 필요하기 때문에 LAN은 즉시 작동하지 않습니다. LAN의 각 활성화 함수는 기본 함수와 스플라인 함수(즉, φ(x) = b(x) + 스플라인(x)의 합)이며, b(x)는 사이렌에서와 동일한 설정으로 사인 함수로 설정하지만 스플라인(x)은 훈련할 수 있도록 합니다. MLP와 LAN 모두의 모양은 [2,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,1]입니다. 학습률 10-3이 있는 5000 단계와 학습률 10-4가 있는 5000 단계에 대해 Adam 최적화기인 배치 크기 4096으로 학습합니다. 그림 B.3에서 볼 수 있듯이 활성화 함수를 미세 조정할 수 있는 LAN의 유연성으로 인해 LAN(orange)이 MLP(파란색)보다 더 높은 PSNR을 달성할 수 있습니다. 저희는 MLP에서 LAN을 초기화하고 더 나은 PSNR을 위해 LAN(녹색)을 추가로 미세 조정하는 것도 가능하다는 것을 보여줍니다. 저희는 실험에서 G = 5를 선택했기 때문에 추가 파라미터 증가는 원래 파라미터보다 약 G/N = 5/128 ≈ 4%입니다.

 

 

 

 

 

C. 하이퍼파라미터 의존성

Figure C.1에서는 f(x, y) = exp(sin(πx) + y^2) 사례에서 하이퍼파라미터의 효과를 보여줍니다. 해석 가능한 그래프를 얻기 위해 활성화 함수의 수를 가능한 한 적게(이상적으로 3개) 유지하고자 합니다.

1. 활성화 함수 수를 줄이기 위해 엔트로피 페널티가 필요합니다. 엔트로피 페널티가 없으면 중복된 함수가 많이 발생합니다.

2. 결과는 랜덤 시드에 따라 달라질 수 있습니다. 운이 나쁜 시드를 사용할 경우, 가지치기된 네트워크가 필요 이상으로 클 수 있습니다.

3. 전체 페널티 강도 λ는 희소성을 효과적으로 제어합니다.

4. 그리드 수 G는 해석 가능성에 미묘한 영향을 미칩니다. G가 너무 작으면 각 활성화 함수가 표현력이 떨어지기 때문에 네트워크가 앙상블 전략을 사용하여 해석이 어려워집니다.

5. 조각별 다항식 차수 k는 해석 가능성에 미묘한 영향을 미칩니다. 그러나 이 장난감 예제에서는 랜덤 시드처럼 명확한 패턴을 보이지 않습니다.

 

D. Feynman KANs

섹션 3.3의 파인만 데이터셋에 대한 더 많은 결과를 포함합니다.

Figure D.1은 각 파인만 데이터셋에 대한 KAN과 MLP의 파레토 프론티어를 보여줍니다.

Figure D.3 및 D.2는 각 파인만 방정식 맞춤 작업에 대한 최소 KAN(테스트 RMSE < 10−2 제약 조건) 및 최상의 KAN(가장 낮은 테스트 RMSE 손실)을 시각화합니다.

 

E. 그리드 크기에 대한 주석

PDE 및 회귀 작업 모두에서, 훈련 데이터를 균일 그리드에서 선택할 때, 그리드 크기가 큰 수준(한 방향에서 다른 훈련 포인트와 비교 가능한 크기)으로 업데이트될 때 훈련 손실이 갑자기 증가하는 현상이 나타납니다. 이는 고차원에서 B-스플라인의 구현과 관련이 있을 수 있으며 추가 조사가 필요합니다.

 

F. 특수 함수용 KAN

섹션 3.2의 특수 함수 데이터셋에 대한 더 많은 결과를 포함합니다.

Figure F.2와 F.1은 각 특수 함수 맞춤 작업에 대한 최소 KAN(테스트 RMSE < 10−2 제약 조건) 및 최상의 KAN(가장 낮은 테스트 RMSE 손실)을 시각화합니다.

 

🤔 논문 읽는법 by. Andrew Ng.

 

1. 논문 읽는법.

새로운 분야를 익히기 위한 논문을 읽을 때, 한 분야에서 15~20개 정도의 논문을 읽으면 작업이 가능하다.

다만, 이 15~20개를 처음에는 10%만 읽고 good/bad를 판단하면서 점점 찾아서 읽는다.

이때 만약 50~100여개 정도라면 해당 분야에서 깊은 지식을 알고있다 해도 될 것이다.

 


2. 최신 논문 읽기.

① Title / Abstract / Figure 및 Experiment 1~2개

Abstract, Figure(구조) 등으로 어느정도 파악가능.

 

② Intro / Conclusion / Figure / Related Works Skim(속독)

Accept을 위한 설득력을 갖추기 위해 Intro와 Conclusion을 아주 신중하고 깔끔히 요약한다.

Related Works는 해당분야의 중요논문을 알기위해 중요. 따라서 Skim(속독) or Skip이 추천됨.

 

③ Math , etc 이해안되는 것  → Skim or Skip

해당 논문이 내 연구에 필요하면 반드시 꼼꼼히 읽을 것 (구현될 정도까지 포함)

다만, 많은 research논문을 읽어야 한다면, skim or skip

 


3.  그럼 어느정도 수준이 이해됐다 보는거지?

아래 질문에 대답가능하다? 그럼 마음놓고 다른논문 읽으러 가보자.

❗️저자의 성취요소 (Main Contribution)

❗️Main Method와 접근방식

❗️이 논문에서 내가 활용할 수 있는 바는 무엇인가?

❗️다른 Reference를 볼만한 가치가 있는가?

 


4. 기타

① 논문 정보 얻는법

본인: 웹검색, 블로그 등등

Ng: Twitter / ML Subreddit / NIPS,ICML,ICLR등 Top Confer / ArXiv Sanity

 

arxiv-sanity

 

arxiv-sanity-lite.com

 

 

② 수식..🫠

간단한 수식은 모르겠으나 Batch Norm, DDPM 등 수식이 많거나 어려운 경우, 어떻게 잘 이해할 수 있을까?

 

❗️처음부터 다시 유도해보기

  • 정말 잘 이해하고 싶다면, theoretical science나 mathematics 인데 결과를 따로 적어놓고 빈 종이에다가 유도하는 과정을 다시 해본다. 그걸 하면 정말 잘 이해한 것.
  • 그리고 이걸 할 수 있게 되면 새롭게 일반화를 할 수 있게 되고 새로운 아이디어를 얻는 데 도움이 된다. 시간은 많이 걸리지만 그만큼 도움이 될 것이다.

 

③ Code

  • 오픈소스 코드를 받아 실행해보기
  • 처음부터 코드를 재현해보기

 


📌 선형대수(Linear Algebra)

1. Baseline

i)

 

 


📌 확률통계(Probability & Statistics)

참고): https://chan4im.tistory.com/229 , https://chan4im.tistory.com/233 ,

Uncertainty: 양적표현으로 다루기 위해 "확률론"등장

 ∙ Epistemic(인식론적)

= systematic
→ 유한한 dataset에 적절

 ∙ Aleotoric(우연성)

= intrinsic = stochastic = noise
→ 세상 일부만 관찰하기에 noise가 발생
→ 다른종류의 data수집으로 noise 완화가능


 ∙ 합과 곱의 법칙

합∙곱법칙 + 결정이론(decision theory)를 이용하면,
모호한 정보( = uncertainty)더라도 optimal prediction에 도달가능

p(X,Y) : X와 Y의 결합확률(joint probability)

p(Y|X) : X에 대한 Y의 조건부확률 (X만 고려시, Y일 확률)
p(X) : 주변확률(marginal probability), 단순 X확률
p(X,Y) = p(X)p(Y) : 독립




Expectation & Covariance

 ∙ Expectation: 확률분포 하 함수의 가중평균

E[f] : 다른 x값들이 상대적 확률에 따라 "가중"되는데, 이는 곧 "확률분포 p(x)하에서 함수 f(x)의 가중평균"을 의미.

이산변수의 기댓값의 경우, sample이 많아질수록 실제함수의 가중평균에 더욱 수렴하게 된다.
cf) 분산: Var[f] = E[f(x)2] - E[f(x)]2. (feat. 제평평제)


 ∙ Covariance: 두 변수가 함께 얼마나 변하는지를 측정.


만약 x와 y가 독립이라면: Cov[x,y]=0


두 벡터 x와 y에 대해, 그들의 공분산은 다음과 같은 행렬이다:

만약 벡터 x의 구성 요소들 간의 공분산을 고려한다면,
더 간단한 표기법으로 cov[x] ≡ cov[x, x]를 사용한다.




Gaussian Distribution

 ∙ Gaussian 분포 (최대entropy와 CLT)

Maximum Entropy 중심 극한 정리(CLT)의 관점에서 자연스레 나타난다.
cf) 최댓값=최빈값이며, precision = 1/σ2

 ∙ Likelihood 함수


우측 그래프는 Gaussian의 Likelihood함수:
회색점: Gaussian분포에서 i.i.d인 Dataset
파란점: 각 dataset에 대한 관측값, p(x)
Likelihood함수: p(x)와 PDF의 곱으로 "특정 data관찰 확률을 의미"

 

 ∙ Maximum Likelihood 

이때 관찰된 Dataset으로 Likelihood Function을 최대화하는 확률분포의 매개변수를 결정하는 방법.

좌측 값은 평균과 분산에 대해 위 likelihood함수를 최대화 시,
각각에 대한 Maximum Likelihood 해를 얻을 수 있다.

Maximum Likelihood의 제한사항이 존재한다:
(MLE는 모집단 추정에 완벽하지 않은데, 이는 bias로 인해 발생한다)
μML   =  μ의 불편 추정량  ,  σML2 ≠  σ2의 불편 추정량. (N-1 / N)

[Bias발생원인]:
분산 데이터에 맞게 조정된 MLE기준으로 측정되기 때문.
아래 그림은 MLE로 Gaussian의 평균과 분산을 결정할 때,
bias가 어떻게 발생하는지에 대한 직관적인 이해가 가능하다.

빨간곡선: Gaussian분포
파란곡선: 2개의 녹색 data point로 이뤄진 3개의 dataset에 ML로 얻은 Gaussian분포.


위 그림을 통해 다음 사실을 알 수 있다.
3개의 dataset을 평균화하면 평균을 동일하다.
하지만, 분산은 실제 평균과 비교❌  , 표본평균과 비교 → 다소 과소평가(N-1/N)된다.

다만, 신경망처럼 복잡한 모델에서는 ML의 bias보정이 쉽지 않다.
또한, MLE의 bias는 Data point N이 많아지면, 덜 중요해지진다.(lim N → ∞)

Gaussian의 경우, 너무 N이 적지 않은 이상 이 bias가 큰 문제가 되진 않지만
본 저서는 Deep Learning 즉, 많은 parameter를 갖는 모델에 초점을 두었기에
ML과 관련된 bias문제는 보다 심각하다.(Overfitting문제와 밀접한 관련성을 가짐.)

변수간 비선형변환: 

 ∙ Density 변환방법:

모든 밀도 p(y)는 모든곳에서 0이아닌 고정된 밀도 q(x)를 얻을 수 있기 때문.
이때, q(x)는 x=f(y)인 비선형변수변환으로 얻어진 값.

빨간곡선
: x에 대한 정규분포 p(x)
이 분포에서 N=5만개 점 추출, histogram을 그림.
→ p(x)와 거의 일치할 것.


x→y로의 비선형변수변환을 고려해보면:
x = g(y) = ln(y)-ln(1-y)+5
이 함수의 역함수는 Sigmoid함수로 파란곡선이다.

px(g(y)): 만약 단순히 px(x)를 x의 함수로 변환한다면 얻는 분포, 곡선의 mode가 변환된 것을 확인가능.
y에 대한 밀도는 좌측 식에 의해 변형되기에

좌측의 핑크 곡선(right-skewed)으로 나타난다.

이 식을 다변량에 대해 적용하려면 Jacobian Matrix를 이용하면 된다.

x, y가 다변량분포일 때, 비선형변환을 적용하려면Jacobian Matrix를 사용 (py(y) = px(x) |det J|).


해당 그래프를 보면 y의 주변분포로 떨어지는데 이를 공간상으로 확장한 것.
즉, "주변 영역"으로 변환 된다는 것을 의미.


cf) J의 역할: 
공간의 일부를 확장하고 다른 부분을 압축하는 것
(= 해당 변수의 변화량이 다른 변수에 얼마나 영향을 주는지를 의미;
이를 모든 영역에 대해 고려하면 전체 공간이 어떻게 변화하는지 알 수 있음)



정보이론: Entropy

 ∙ Entropy: 특정값 관찰 시 얻는 정보량

물리학에서의 entropy보단, 정보이론 중심의 "정보량"기준으로 살펴보자.

정보내용의 측정은 확률 분포 p(x)에 의존, 따라서 h(x)를 찾는것이 목표.
h(x)
: 
p(x)의 단조 함수인 정보 내용을 나타내는 양

[정리]: 두 독립사건 x,y에 대해 아래가 성립.
  ∙ h(x,y) = h(x) + h(y)
  ∙ p(x,y) = p(x)p(y)
h p의 정보량이기에 위 식이 만족하려면 h log로 주어진다.
 h(x) = -log₂p(x)로 주어진다.

정보론: log가 관례적, 이는 곧 h(x)의 단위가 bit('binary digits')임을 의미.

이때, entropy를 좀 더 정보론적으로 접근해보자.
먼저 log 사용이유이다. 
정보 전달 시, encoding을 하여 압축을 시켜야 하는데, log는 자릿수를 쉽게 표현가능하다.
ex) log100 = 2, log1000 = 3

즉, Entropy는 random변수의 상태를 전송 시,
전송 가능한 가장 짧은, encoding길이 최솟값을 의미한다.

추가적으로 전송내용은 필히 손실이 발생하는데, 우리가 갖는 data는 이산형이기 때문이다.
즉, 매우 정밀하게 지정하려면 많은 bit가 필요함을 의미한다.


 ∙ H[x] : x의 entropy (= p(x)의 기댓값 = 평균정보량)

H[x]는 x의 entropy로 평균정보량 즉, p(x)의 기댓값을 의미

cf) H[x, y] = H[y|x] + H[x]를 만족.
즉, x와 y를 설명하는데 필요한 정보 = 주어진 조건에서 y를 지정하는데 필요한 추가정보 + x만을 설명하는데 필요한 정보.


∙ KL Divergence : 두 분포간의 비유사도 측정.

모르는 분포 p(x)와 근사분포 q(x)에 대해 q(x)를 이용해 x값을 수신자에게 전송한다.
이때, q(x)는 실제분포 p(x)대신 x값 지정 시 필요한 "평균추가정보량"을 의미한다.
(즉, 추가로 전송해야할 정보 = 두 분포간의 KL-Divergence)
쉽게 설명하자면, Cross Entropy - Entropy가 바로 KL Divergence식이다.

cf) Deep Learning에서 Loss function으로 KL Divergence를 사용해야하는 것 아닌가요?
왜 KL Divergence가 아닌 Cross Entropy를 사용하는지 의문이 들 수 있다.
KL-Divergence는 cross entropy에서 최소량인 entropy를 빼니까 이 오차값,
즉, cross entropy가 optimal(= entropy)해지도록 평균추가정보량을 줄이는 방향으로 학습하는 것이 맞다는 생각이 들 것이다.

하지만 오차함수 미분 시, Entropy가 상수가 되어버리기 때문에 
결국 KL-Divergence = Cross Entropy가 되어버린다.
결국 Cross Entropy를 편의상 사용하지만, 실상은 KL-Divergence를 사용하는 것과 마찬가지라 생각하면 된다.

Bayes' Theorem: 불확실성의 양적표현

 ∙ Frequentist 확률:

휜 동전의 경우 동전이 오목한 면으로 떨어질 확률처럼 무작위, 반복 가능한 사건의 빈도에 대한 확률.
[p(D|w)에 대한 접근방식]: 
w'estimator'의 일종에 의해 결정되는고정된 매개변수로 간주
[기계학습에 대한 적용방식]: 정규화된 MSE같은 Loss function을 최적화해 얻은 parameter지점의 추정치를 사용


 ∙ Bayesian 확률

[p(D|w)에 대한 접근방식]: 하나의 dataset D만 존재하며 (즉, 실제로 관측된 데이터), 매개변수에 대한 불확실성은 w에 대한 확률 분포를 통해 표현
[기계학습에 대한 적용방식]: 데이터의 확률이 가장 높은 모델을 선택 → 더 복잡한 모델을 선호 → Overfitting
그렇기에 Bayesian기반 기계학습 모델은 적은 dataset일수록 더 좋은 성능을 낸다.


불확실성의 양적표현, prior가 자연스레 발생하여 포함된다.
"불확실성 표현을 위해 확률을 사용하지 않으면, 이성적이고 일관된 추론을 할 수 없다."

ex) 불확실성 = 동전의 오목한 면이 어느면인지 파악하는 것
예를 들어, 동전이 뒷면으로 더 많이 떨어지는 횟수가 많다면?
동전이 오목한 면이 뒷면일 가능성이 더 높다는 증거를 제시하고,
실제로 이런 직관은 맞기에 이를 확률규칙으로 사용해 양적으로 표현가능하다
 Bayes정리에 의해 동전 던지기로 제공된 데이터를 통합하여 오목한 면이 앞면일 사전 확률을 사후 확률로 변환할 수 있다.
과정이 반복가능하기에, 새로운 동전 던지기에서의 데이터를 통합하는 데에는 이전의 사후 확률이 사전으로 사용된다.


D
 : train dataset

p(D|w) : Likelihood ; 주어진 parameter에서 관측된 data가 발생할 확률
p(w) : prior ; 선험적 지식이나 믿음.
p(w|D) : posterior ; 제공되는 update된 parameter확률분포
p(D) : Marginal Likelihood ; p(D|w)∙p(w)의 적분값 ; 모델전체의 적합도.



이를 통해 train data에 대한 우리의 불확실성을 반영이를 기반으로 new data에 대한 예측 수행이 가능하다.
이렇게 Bayesian접근은 model parameter에 대한 불확실성을 고려한 확률적 추론을 제거, 불확실성 update를 통한 model개선이 가능하다.

 

 

 


📌 기계학습(Machine Learning)

1. Baseline

i)

 

 

 

 


📌 심층학습(Deep Learning)

1. Baseline

i)

 

 

 

 

 


📌 컴퓨터비전(Computer Vision)

1. Baseline

i) Logit과 Softmax, Cross Entropy

class에 대해 예측한 값(-∞,)으로 sigmoid-1 값을 갖는다.
즉, 사건이 일어날 odds = P(사건발생⭕️) / P(사건발생)의 자연로그값이다.


보통 이 logit값에 softmax를 취한다.

🤔 Softmax란?
먼저 KL발산에 대해 간단히 되짚어보자.
KL발산은 2개의 분포를 비교하는 방법으로 실제분포 P와 임의분포 Q를 비교하는 것이다.

KL발산과 Softmax함수 사이의 관계는 Cross Entropy와 연관되어 있다.
Cross Entropy란 실제분포와 예측분포간의 차이를 측정하는데 사용된다.
즉, Softmax함수는 Cross Entropy손실함수를 최소화하는데 사용되며, KL발산과 관련된 Cross Entropy손실을 최소화 하는 방향으로 학습이 진행된다.

🤔 One-Hot Encoding과 Softmax
최적화 진행 시, 둘 사이 유클리드거리(=MSE) 계산보다는 Cross Entropy가 더 적합한데, 
Cross Entropy의 경우, 수치적 안정화를 위해 log를 사용한다. (소수점에 가까운 확률들을 처리하기가 용이하기 때문.)

 

 

 

ii) Batch∙image크기, 정확도와 비생산성

 batch_size = 128
∙ 128개 img에 대해 ∇를 계산 후 update한다는 의미

🚩 병렬화를 통해 solution에 더 빠르게 수렴할 가능성이 존재.

GPU는 RAM제한이 있기에, img가 클수록 batch로 묶을 수 있는 img가 적어진다.
또한, 더 큰 img로 훈련하려면 모델도 그만큼 커야하기에 그에 비례하게 가중치 수도 조절해야한다.

batch_size가 클수록 train곡선이 더 부드러워지기에 큰 img는 정확도측면에서 비생산적일 수 있다.
HR-img는 Noise가 두드러지는데, 특히 야외나 저조도 환경의 영상은 더욱 그렇다.
(즉, 해상도를 낮추면 img가 부드러워져 train속도 및 정확도가 높아진다.)

∴ 결론: img의 noise특성이 보장되고 예산감당가능 선에서 최고해상도 사용이 권장.
restoring시, computing보다 저렴해 JPEG같은 해상도를 낮춰 저장할 것이 권장됨.
🧐 Batch size에 대하여
Data나 Model의 종류에 따라 적절한 Batch_size가 존재하기에
batch_size를 너무 작은값이나 큰값을 쓰면 오히려 학습이 잘 안되는 경향이 존재한다.

cf) 특정한 가설하에 연역적으로 증명가능할 때,
batch size를 2배 증가시키면 step size는 √2배 증가시켜야한다. 

cf) batch size를 증가시켰는데도 총 epoch수를 그대로 두면
한 epoch당 iteration수가 줄어들기에
그만큼 gradient로 parameter update를 덜 시키는 것이므로
Loss감소속도가 느려져 학습이 잘 안될 수도 있다.

 

 

 

 

iii) Regularization

즉, Softmax함수는 Cross Entropy손실함수를 최소화하는데 사용되며, KL발산과 관련된 Cross Entropy손실을 최소화 하는 방향으로 학습이 진행된다.

🤔 One-Hot Encoding과 Softmax
최적화 진행 시, 둘 사이 유클리드거리(=MSE) 계산보다는 Cross Entropy가 더 적합한데, 
Cross Entropy의 경우, 수치적 안정화를 위해 log를 사용한다. (소수점에 가까운 확률들을 처리하기가 용이하기 때문.)

 

 

 

 

iv) Optimizer & Scheduler

🤔 Optimizer
∙ SGD: Default Optimizer로 사용되었었음.
 Adam: 더 빠르고 안정된 수렴을 위해 사용됨.
F-trl: 극도로 희소한 dataset에 잘 작동하는 경향이 존재.

AdamW: Differential LR을 이용해 학습
(pretrain에는 낮은 lr)
(classifier에는 보통의 lr)

LR: 극소값들을 그냥 지나침
lr: 극소값을 벗어나지 못함

🤔 Scheduler
학습률을 동적으로 조정하는 기법.
학습률은 모델이 각 반복(iteration)에서 가중치를 업데이트할 때 사용되는 스케일링된 값
네트워크가 최적의 솔루션으로 수렴하는 속도와 안정성에 영향을 미친다.


Step Decay: 일정한 간격(epoch 또는 iteration 수)마다 학습률을 감소.

Exponential Decay: 매 step마다 LR을 지수적으로 감소 (by. decay factor을 곱함).

Cosine Annealing: cos을 이용해 max-min 사이를 주기적으로 진동시켜 학습률을 조절.

ReduceOnPlateau: val_loss가 더 이상 개선되지 않을 때마다 학습률을 감소.
모델이 최적값에 가까이 수렴할수록 학습률을 줄여 빠르게 수렴하도록 돕는다.

 

 

 

 

v) Layer (Conv, Maxpool)

Covolution Layer: 중요한 검출값의 feature map 반환
  additive bias를 사용하며, ReLU는 이 bias를 작은 양수값으로 초기화한다.
  활성화 이후 0이 아닌 값 출력 및 0이 아닌 gradient를 갖게 한다.

Maxpooling Layer: 최대강도의 feature만 남김,
 feature map의 해상도↓ = Receptive Field크기

 

 

 

 

 

vi) Video

Frame별 처리: 동영상은 frame으로 구성됨.
따라서 동영상 처리를 위해 개별 frame에 대해
image처리를 수행한 결과를 종합→전체영상을 분석
(다만, 이 접근방식은 인접한 frame간의 상관성이 높다.)

3D CNN: 동영상 처리시, 한번에 한 frame씩 처리하는 위의 방식과 달리 프레임간의 상관관계를 이용하는
"frame의 이동평균(rolling average)를 계산"하는 방식이다.
이 방식은 화면에 noise가 많을 때 특히나 유용하다.
동영상 클립을 [B,C,T,H,W]의 5차원 Tensor로 읽고, 필요에 따라 동영상을 짧은 클립으로 나눈다.

RNN 계열: RNN 등의 sequence방법을 사용하는 방법
(이는 훈련이 매우 어려워 3D-CNN접근방법이 더 실용적이다)

 

 

 

vii) Data Preprocessing

Train-Serving Skew:
inference time에서 client가 제공한 img에 대해 train시 적용한 모든 연산(디코딩, 크기조정, 등등)을 수행해야한다.
연산을 빠뜨리거나 train과 inference간에 약간이라도 다르게 수행한다면, 잠재적으로 잘못된 결과를 초래할 수 있다.
즉, "훈련 중에는 나타나지 않던 예상치 못한 결과가 추론 시 일어나는 것"이다.

Sol) 훈련과 추론에서 동일한 코드를 재사용.

Data Augmentation: 가중치가 많을수록 모델훈련에 데이터가 많이 필요하다.
이를 해결하기 위해 사용되는 데이터 증강은 "Data space Solution"으로 Dataset의 크기와 품질향상에 도움을 준다.
대표적으로 아래 3가지 범주로 나눌 수 있다.

 ❗️ 공간적 변환: Flip, Rotate, Crop, Zoom, ...

 ❗️ 색상 왜곡: 밝기, 색조변환

 ❗️ 공간적 변환: Cutout, Mixup, ...

 


viii) TFRecords (Tensorflow Record)

이름에서 tensorflow라 적혀있는 것과는 달리? pytorch에서도 활용가능하다. (아래 링크 참조.)

사용 이유:
img를 JPEG파일로 "저장"하는 것은 ML관점에서 효율적❌
→ 효율적인 저장 메커니즘인 TFRecord를 사용

보통 파일크기는 10~100MB가 이상적이다.
(다수의 worker(in GPU)에서 image를 읽는 기능과
많은 batch에서 latency를 상쇄할만큼 각 파일을 충분히 길게 열어야하기 때문.)

TFRecord를 작성하기 전, 미리 처리하는 것이 많아지면 훈련파이프라인에서의 처리량↓
따라서 훈련속도와 효율성, 데이터처리량 모두를 늘릴 수 있다.

병렬화: cs상 가상 CPU(= vCPU)가 2개 이상일 때
 ❗️ tensorflow에 dataset생성 시, 읽기를 자동으로 interleave하게 요청가능
tf.data.TFRecordDataset(pattern, num_parallel_reads=AUTO)

 ❗️ 두 map()연산을 병렬화 가능.
.map(preproc.read_from_tfr, num_parallel_calls=AUTOTUNE)


조금 더 상세한 Train pipeline에 대한 내용은 아래 링크를 참조.
(https://www.oreilly.com/library/view/practical-machine-learning/9781098102357/)
 

Practical Machine Learning for Computer Vision

This practical book shows you how to employ machine learning models to extract information from images. ML engineers and data scientists will learn how to solve a variety of image … - Selection from Practical Machine Learning for Computer Vision [Book]

www.oreilly.com

 

TFRecordLoader — TorchData main documentation

Shortcuts

pytorch.org

 

 

 

 

 

 

 

cf) Metric

① Confusion Matrix

Confusion Matrix:

 ❗️Accuracy = (TP+TN) / n
    → 데이터불균형, 편향된 모델 등에서는 좋지않은 평가지표.

 ❗️ Precision = TP / (TP+FP) = PR의 정확성

 ❗️ Recall(= Sensitivity) = TP / (TP+FN) = positive 구분가능성

 ❗️Specificity= TN / (TN+FP)


 ❗️ F1-score = 2*(p×r)/(p+r)
    → 정밀도와 재현율간의 "조화평균"

 ❗️ Fβ-score = (1+β2) * (p×r)/(β2×p+r)
    → F1 score에 β를 추가, P와 R에 대한 중요성을 확장시킬 수 있음.

🚩 Sensitivity and Specificity (민감도 / 특이도) --> 의학분야에서 사용

Sensitivity : True Positive Rate (TPR) = TP / (TP + FN) --> positive 구분 성능

Specificity : True Negative Rate(TNR) = TN / (TN + FP)

🚩 Precision and Recall (정밀도 / 재현율) --> information retrieval 에서 사용

Recall = Sensitivity

Precision = TP / (TP + FP) --> positive rate 의 정확성 (ex. 보안분야)

 

 

② ROC-AUC & PR Curve


ROC-Curve: Recall을 y축, FPR을 x축으로 갖는다. (FPR = FP / (FP+TN))

cf) AUC: ROC곡선의 아래면적(Area Under Curve): 이 값을 계산해 단일 숫자로 정보를 요약할 수 있다.

PR-Curve
: Precision을 y축, Recall을 x축으로 갖는다.

 ❗️AUC는 기본적으로 0.5이상이어야 하는데, AUC=0.5라는 뜻은 모델이 Random Classifier와 같다는 것이기 때문이다.

 ❗️Data가 균형잡혀 있을때는 AUC-ROC를 계산하는 것이 추천된다.
 ❗️Class Imbalanced, Biased된 경우 AUC-PR이 권장된다.

 

 

cf) Macro와 Micro Average

F1- Score의 3가지 종류
∙ Macro Avg: Label별 F1-score 산술평균(= 모든 data가 동일한 가중치=중요도)

∙ Micro Avg:
전체 TP,FN,FP를 평균한 것 = Accuracy

∙ Weighted Avg:
Label별 F1-score를 샘플수의 비중에 따라 가중평균

 

cf) EMR과 Hamming Score, Hamming Loss

EMR: Exact Match Ratio
최대화하기 가장 까다로운 지표는 부분집합정확도(subset Acc)라도도 부르는
정확한 일치비율(EMR: Exact Match Ratio)이다.
EMR은 "모든"라벨이 정확히 맞는 예의 백분율을 측정한다.
즉, img에 100개의 class가 있고, 99개만 예측했다면 정확히 일치하는 것으로 치지 않는다.

 Hamming Score
EMR보다 덜 엄격한 지표의 다중라벨정확도를 나타내는 점수지표이다.
각 예에 대해 총 라벨수와 올바로 예측된 라벨의 비율을 측정해 평균한 것이다.
(사실 IoU나 Jaccard Index와 상당히 유사하다.)

 Hamming Loss
0과 1 범위의 손실함수로 Hamming Score와 달리
잘못예측된 클래스 라벨에 대한 example의 관련성을 측정, 다음 해당 측정의 평균을 구한다.
이는 XOR연산과 유사한데, example n의 수와 클래스 L에 대해 이 두 수로 이중합을 정규화한다.

 

 

 

③ Regression Metric (MSE,MAE,Huber)

∙ MSE : mean-unbiased 추정량
제곱오차평균으로 2차항으로 인해 감도가 큰 평균편향추정치이다.
즉, 큰 감도는 몇가지 이상치에 과도하게 영향을 미칠 수 있음을 의미한다.

cf) RMSE라는 MSE에 루트를 씌워 사용되는 지표도 존재.
cf) 추정량(estimator)의 표본평균이 분포평균과 같음 (= mean-unbiased추정량)

∙ MAE : median-unbiased 추정량
좀 더 단순하고 해석하기 쉬운 지표로 절대차값을 이용.
제곱지수가 있는 MSE, RMSE에 비해 이상치 몇개로 왜곡되는 현상은 덜하다.

cf) 추정량이 과대평가하는 빈도가 과소평가하는 빈도와 같음 (= median-unbiased추정량)

∙ Huber Loss
MSE, MAE장점을 한번에 취할 수 있다.
절대오차값이 threshold(δ)보다 작으면 제곱항을 사용하고 그렇지 않으면 선형항을 사용한다.
0에 가까운 값에 대해 2차 항의 제곱평균불편추정량의 민감도
0에 더 먼 값에 대해 선형 항의 중위불편추정량의 견고성
모두 누릴 수 있게 해준다.

 

 

④ IoU (Intersection Over Union)

∙Detection:
Detection에서 사용되는 지표 중 하나로 이름에서 알 수 있듯, 교집합 / 합집합 이다.
이 IoU를 이용해 Detection에서는 해당 객체가 Detect된 것인지 아닌지에 대한 판별지표로 사용하기 때문에 
특정 IoU값을 threshold로 정해 객체검출여부를 판별한다.
일반적으로 사용되는 임계값: 50, 75, 95%
TP = 올바르게 검출된 것.
FP = 잘못 검출 될 것.
FN = 실제 Bbox를 전혀 검출하지 못한 것 (= 검출 누락)
(cf. TN은 Detection에서 사용되지 않는다.)

❗️ precision = TP / All_Detections

❗️ Recall = TP / All_Actual_Bbox

❗️  Pinterpolated = maxR'≥R[P(R')] = Avg Recall

 

 

AP와 mAP

∙ AP (Average Precision)
보간을 위해 모든 고유한 재현율을 선택하는 "평균정밀도"는 보간된 PR-Curve의 아래면적이다.

AP는 위와 같은 상황(Bbox가 여럿 나타나는 상황)에서 계산한다.
AP계산을 위해 TP, FP, FN을 세야한다. cf) True = 맞춘것을 의미

AP 계산알고리즘:
① 신뢰도 임계값을 넘는 Bbox만 선택, 예측목록을 생성
② 예측목록에 있는 Bbox를 신뢰도로 정렬
③ Confidence값이 큰 순서대로 처리.
현재 Bbox가 IoU 임계값을 넘으면 TP로 판정, 아니면 FP로 판정


❗️이때, 2개 이상의 물체에 하나의 Bbox가 겹치게 된다면?
IoU가 최대인 쌍을 사용한다.
TP발생 시, 참값목록에서 TP_Bbox를 제거, 이중의 쌍을 맺는 것을 방지한다.
이때, 예측목록에 있는 Bbox를 모두처리후, 쌍을 맺지못한 채 남아있는 TP_Bbox는 FN으로 판정한다.


∙ mAP (mean Average Precision)
AP를 각 물체 class에 대해 계산 → 이 AP를 모든 class에 대해 평균한 값이다.

하나의 클래스는 AP를 구하면 된다.
하지만, Detection에서는 종종 검출성능이 다른 여러 클래스가 있기에
각 클래스의 평균 정밀도평균(mAP)를 계산하는 것이 유용하다.


아래 예시를 살펴보자.
먼저, Precision과 Recall은 아래수식처럼 구할 수 있다.

 

즉, True = 맞춘것을 의미하므로 Precision과 Recall은 아래처럼 설명할 수 있다.
∙ Precision = (맞춘것=TP) / (예측한 것 중 = ?P)
∙ Recall = (맞춘것=TP) / (실제 중)

먼저 mAP를 구하는 순서에 대해 설명해보겠다.

 

⓪ Confidence=0.6  &  IoU=0.5 로 설정

① Confidence임계값을 넘긴 Bbox로 예측목록 {a,b,d}를 생성

② 예측목록을 Confidence순으로 정렬 → {b,d,a}

③ 신뢰도가 가장 높은 b먼저 처리.
 ∙ b는 2,3과 겹침 → IoU가 더 큰 2와 쌍을 맺음
 ∙ b-2쌍을 TP로 판정 후, 2는 참값(Ground_Truth)목록에서 제외.

④ 2번째 신뢰도를 갖는 d를 처리
 ∙ d는 4와 IoU가 0.12(<임계IoU)이므로 FP로 판정

⑤ 마지막 Bbox예측목록원소 a를 처리
 ∙ a는 1과 IoU가 0.6(=임계IoU)이므로 TP로 판정 

⑥ Bbox로 생성한 예측목록을 모두 처리하였다.

⑦ 예측 Bbox 처리 후, 쌍을 못맺은 3과 4는 FN으로 판정.

⑧ 최종적인 Precision과 Recall은 다음과 같다.
 ∙ TP=2 , FP=1 , FN=2
 	∴ Precision = 2/3
 	∴ Recall = 2/4

⑨ Confidence임계값을 0.5로 낮추면, Precision과 Recall은 다음과 같다.
 ∙ TP=3 , FP=2 , FN=1
 	∴ Precision = 3/5
 	∴ Recall = 3/4

∙ AR과 mAR
AR(Average Recall)은 AP에 사용되는 PR-Curve대신 Recall-IoU곡선을 사용한다.
이는 모든 IoU(특히 50%이상)에 대해 평균한 Recall값으로 AUC값이 2배가 된다.

mAR은 mAP처럼 다중클래스 Object Detection을 위한 것으로 전체 클래스의 AR을 구하기 위한 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

cf) weights 분포와 NaN, Normalization

🤔 가중치 분포는 어떤 모습이어야 할까?

신경망의 각 층에는 수천~수백만개의 가중치를 가지며, 이런 가중치값들의 큰 집합은 분포(Distribution)를 생성한다.
훈련 시작과 끝의 가중치 분포는 매우 다를 수 있기에, 일반적으로 초기 분포는 가중치 초기화전략에 따라 결정된다.
이는 정규분포나 균등분포에서 무작위로 추출되고, 정규화 요인이 있거나 없는 등 다양한 방식이 사용된다.

중심극한정리(CLT: Central Limit Theorem)에 따르면, 가중치분포는 모델이 훈련되고 수렴됨에 따라 더 Gauss적으로 보이기 시작한다.
즉, 평균 μ와 표준편차 σ를 갖는 모집단에 대해,
 ∙충분히 많은 수의 무작위 표본이 주어지면 → 표본평균분포는 Gaussian Distribution에 가까워진다.

But❗️모델에 system적인 문제가 있다면?
가중치가 해당 문제를 반영해
∙ 0값 (입력값의 scale이 제대로 조정되지 않은경우 발생하는 'Dying Layer Problem')
∙ 매우 큰값 (Overfitting)으로 치우칠 수 있다.
weight분포를 보고 문제가 있는지 진단이 가능하다!

즉, Gaussian분포를 따르지 않는 가중치분포에 대해 몇가지 방법을 시도할 수 있다.

🚩 분포가 0에 치우쳐 있는 경우:
∙ 입력값의 범위를 [0, 1] → [-1. 1]로 scaling

∙ 중간 Layer에 문제가 있다면, Batch Normalization을 추가.

🚩 분포가 큰 쪽에 치우쳐 있는 경우:
∙ Regularization or Dataset↑

🚩 가중치가 가우스분포에서 벗어난 경우:
이는 우리의 초기화전략이 부적절했기에 가중치가 작고 정규분포를 이루는 표준system을 따르기 어려웠음을 의미한다.
→ Gradient문제이므로 Clipping, Regularization, Penalty 등을 추가.

신경망의 가중치는 일정범위안에서 유지되어야 한다.
이때, 값이 갑자기 커진다면 Gradient Exploding문제이다.
특히 Loss값이 NaN을 반환하면 weight가 overflow오류를 발생시킬 만큼 커졌다는 것을 의미한다.

보통, scale이 조정되지 않은 입력은 큰 activation을 만들어 기울기폭발가능성이 있다.
그렇기에 입력층을 0~255픽셀이 아닌, -1~1이나 0~1사이의 scale로 변경하는 것이다.

이런 scale조정은 초기에만 안정되는데, weight값이 random한 초기값과 멀어지기 때문이다.
이를 Covariate Shift(공변량 변화)라 부르는데, 이를 위해 Batch Normalization을 사용한다.

Batch Normalization은 이를 위해 scale parameter(γ)와 shift parameter(β)를 사용한다.
(입력을 γ로 조정, β로 이동시켜 출력.)
훈련과정에서 BN층은 채널별 평균∙표준편차의 이동평균(moving average)를 계산해 저장한다.

cf) Batch Norm v.s Layer Norm

Transformer는 학습과정안정성을 위해 Layer Normalization을 사용한다.


Batch Norm: 각 채널의 출력의 평균이 0, 표준편차가 1이 되도록 정규화하는 방법.
(이때, batch차원과 공간차원에 걸쳐 정규화 통계치가 계산된다.)

Layer Norm: 채널차원에 대해 정규화 통계치가 계산된다.
따라서 batch에 있는 각 sequence위치마다 정규화한다.
(이때, 정규화 통계치 계산방식이 BN과 완전히 반대이다.)

 

 

 

 

 

 

 

cf) Bias

특정 예가 dataset이 너무 적거나 많아 해당 시나리오에 대한 정확도가 떨어진다면,

이는 문제가 되는데 이에 대해 dataset이 biased(편향)된 것이라 한다.

 

 

원인

🤔 Bias vs Imbalanced
예를 들어 사파리 촬영 시, 재규어가 있을 가능성은 1% 미만일 것이다. (밀림에 있거든...)
이 Dataset에 매우 적은 비율로 재규어가 있을텐데, 균형이 맞지는 않지만 편향의 증거라 할 수는 없다.
(즉, Imbalanced는 맞으나 Bias라고는 하기는 애매하다는 것.)


🤔 Bias의 원인
- Selection Bias
- Measurement Bias
- Confirmation Bias

 

 

 

 

선택 편향(selection bias)

모델이 production에서 접할 시나리오의 편향된 하위집합에 대해 학습 시 발생.

발생이유: 

  1. 특정 범주가 제외되거나 제대로 샘플링 되지 않도록 실수로 데이터 소스를 제한한 결과로 발생하는 불완전한 데이터수집
  2. 특정유형의 데이터가 다른 유형보다 수집하기 쉬울 때.
  3. 이상치 가지치기 및 데이터셋 정리시 발생가능

Sol)  production 시스템에서부터 작업, 이미지를 사전에 수집

 

 

 

측정 편향(measurement bias)

훈련과 production간에 image수집방식이 다를 때 발생

발생이유:

  1. 훈련을 위한 이미지수집방식과 production에서의 수집방식의 차이로 발생.
  2. data를 제공하는 사람이 달라지거나 labeling을 여러사람이 수행할 때

, 측정편향은 매우 미묘 수도 있다.

 

 

 

확증 편향(confirmation bias)

실생활에서 값의 분포가 원치않는 행동을 강화하는 모델로 이어질 때 발생

발생이유:

앞서 편향과 불균형의 구분이 중요하다 했는데, 확증편향과 관련해 둘 사이의 차이점과 상호관계는 특히나 중요하다.

(Dataset이 imbalance한 실제 분포를 정확하게 나타내더라도 편향될 수 있기 때문!)


데이터 수집당시에는 드러나지 않으나, dataset에서 훈련된 모델에 혼란을 일으킬 수 있다.

Ex) 특정학벌에 유리 학습된 모델 →  모델이 이를 학습해 따라하게 됨.

즉 편향되지 않은 모델은 이제 극도로 편향되어 handler의 편견을 확증하고 지속시키게 된다.

 

Sol) ‘모르는 모름’에 속한것들을 ‘아는 앎’이나 ‘아는 모름’의 범주로 의식적으로 끌어내야한다.

🤔 지식이란?
‘아는 앎’: 우리가 어떤 지식을 안다는 사실을 스스로 자각하는 것.
‘아는 모름’: 우리가 모른다는 사실을 아는 것
‘모르는 모름’: 해당 지식을 알지못한다는 사실조차 모르는 것.

-Donald Rumsfeld, 전 美 국방부 장관-

 

 

 

 

 

편향감지

편향감지를 위해 슬라이스 평가(Sliced Evaluation)을 할 수 있는데, 슬라이스 평가에서는 모델의 목적함수를 그룹 구성원에 대해 계산해서 그것을 비구성원에 대한 지표와 비교한다.
그 후, 다음 슬라이스 지표가 전체 dataset의 지표와 매우 다른 그룹을 조사한다.

또한, Bayes 접근방식을 적용해 해당 확률에 대한측정값을 계산할 수 있다.

 

 

 

귀납편향(Inductive Bias) feat. Transformer

머신 러닝이나 통계학에서 모델이 선택하는 가설 공간을 제한하거나 선호하는 성격
즉, 모델이 학습하고 일반화하는 데 사용하는 가정이나 선입견을 의미합니다.

이러한 귀납 편향은 모델이 특정 유형의 함수 또는 구조를 더 선호하도록 유도하여, 
학습 알고리즘이 특정 유형의 가설에 더 가깝게 수렴하도록 돕는다.

이는 모델이 학습 데이터를 기반으로 일반화를 수행할 때, 특정 가정이나 가설 공간을 우선적으로 고려하도록 유도함으로써
모델의 복잡성을 제어하거나 학습을 도와주는 역할을 한다.


발생이유:
1. 알고리즘 선택에 따른 편향

: 특정 알고리즘은 특정 유형의 모델을 더 선호하는 경향.
ex) 결정 트리 알고리즘은 데이터의 특징을 기반으로 트리 구조로 분할하는 경향이 있습니다.


2. 가정에 따른 편향:
모델이 특정 가정을 가지고 학습하는 경향이 있습니다.
ex) 선형 회귀는 데이터가 선형 관계에 있다는 가정하에 학습됩니다.


3. 하이퍼파라미터 설정에 따른 편향


다만, 잘못된 귀납 편향은 모델의 성능을 제한할 수 있기 때문에 주의해야 합니다.

 

cf) 모든 기계학습모델은 귀납편향(inductive bias)이 존재한다.
ex) CNN의 경우 이웃한 pixel과 비슷한 특성을 갖는다는 "locality"와
물체가 이동하면 이동한 위치에 동일한 특징이 추출된다는 "translation-equivalent" 등이 대표적.

 CNN의 경우 이런 귀납편향이 강한 편으로 이를 만족하지 못하는 자연어와 같은 다른 modality-data에 적용은 부자연스러운 결과가 나온다. (물론, RNN도 시간축과 관련된 강한 귀납편향을 갖는다.)

cf) 귀납편향: 기계학습모델이 학습단계에 보지않았던 새로운 sample로 옳게 추론하기 위해 사용하는 가정

- 하지만 transformer의 경우, 귀납편향이 약한 편으로
가장 중요하게 활용되는 "Self-Attention"은 image, text를 포함해 대부분의 signal에서 나타나서
여러 input형태 (multi-modal data)에 적용할 여지가 존재한다.
ex) 자연어->그림의 DALL-E 등등 vision과 NLP를 동시에 처리하는 여러 응용에서 backbone으로 활용할 수 있다.

 

 

 

 

 

 


2. Classification

i) Deeper = Why High Accuracy?

1. Expressivity 가설
비선형 활성화함수로 이루어진 층을 많이 쌓아 비선형성이 발생
→ 고도로 복잡한 작용에 근접가능❗️

2. Generalization 가설
MLP는 입력을 의미론적으로 분해, feature의 hierarchical구조를 생성한다.
shallow ----> deeper
detail    ----> global feature
저수준   ----> 고수준
으로 갈 수록 classifier가 더 일반화된다는 것이다.

3. Perceptive Field 가설
image전체를 포착하려면 N×N filter가 필요하다.
But❗️ 충분히 깊게 쌓으면 1×1, 3×3으로도 N×N영역을 "볼 수 있게"된다는 것이다.

 

 

 

 

ii) Deeper Network

🤔 Filter 분해
3×3 filter 2번 5×5 filter
𝛉 = 18(2×3×3) 𝛉 = 25
즉, 더 적은 파라미터의 수를 갖지만 2번의 비선형성을 통해 모델을 깊게 만들 수 있다.

🤔 GAP (Global Average Pooling)
GAP은 학습가능한 가중치가 없다는 Pooling의 특징을 이용.
각 channel값을 평균화해 출력한다.
다만, 이미지상 위치가 중요한 Detection에서는 부적절한 방법이다.

🤔 1×1 filter
그냥 이미지를 이동하며 상수를 곱하는 쓸데없어 보이지 않나?
"다중 channel에서 channel별 가중치를 달리"하여 의미가 발생!
+ data의 channel조정은 덤! (학습가능𝛉 수를 줄일 수 있다.)

cf) DenseNet의 경우, 이를 활용해 학습가능𝛉 를 경제적으로 조절한다.
(DenseNet은 Conv의 단계수에 따라 channel수가 선형적으로 증가하기 때문)

 

 

 

 

 

iii) Module식 구조 (Skip-Connection이 왜 좋은가?)

Module식 구조는 여러 선택사항을 만든 후 어느것이 가장 좋은지 신경망이 학습하게 하는 것에서 출발한다.
Inception module, Residual blocks, inverted residual bottlenecks 등이 있으나 ResNet위주로 다룰 것이다.

🤔 ResNet

신경망 깊이가 깊어지면 전체 layer gradient가 흩어져 느리게 수렴하거나 수렴X
→ layer사이 skip-connection을 추가, 신호를 그대로 전달한다.
즉, element-wise addition을 비선형성이 추가된 signal과 진행하는 것이다.

 

 

🤔 Skip Connection이 BP최적화 단계에서 Gradient Flow에 왜 도움을 주는가?

1. Addition 연산
∙ 보통의 DNN목표: 원하는 출력을 위해 내부 w를 update
∙ Skip Connection: input과 output사이  Δ or residue를 출력하는것이 목표

2. Residual연결이 실제로 신경망을 더 shallow하게 만든다는 것.
(= 최상의 경로를 스스로 선택, 실제로는 그닥 깊지 않아 효율적인 수렴가능.)


3. Training 중 최적화된 J(w)의 topology환경

 

 

 

 

 

 

 

iv) MobileNet: 저차원의 ReLU는 너무많은 정보를 파괴한다.

📌 Depth-wise Seperable Convolution
기존 filter는 똑같은 공간을 재창조하기에 𝛉를 비효율적으로 사용한다.


Filter는 H×W×C로 spatial filtering(H×W)과 Channel과의 선형재조합 과정으로 이루어진다.
이 두연산이 성능에 영향을 주지않으며 "독립"(= 분리가능)하면, 적은 𝛉 로 학습할 수 있다.


🤔 Depth-wise Seperable Convolution은 다음 특징을 갖는다.
∙ 독립적인 filter set으로 channel별 입력을 filtering
∙ 이후 1x1 convolution으로 개별적인 출력을 결합 (= channel별 가중합)
(∵ channel은 추출할 "모양정보"가 아니기 때문)
(다만, img는 "모양정보"이기에 3x3 filter를 사용한다.)
🤔 Inverted Residual Bottlenecks
cf) latency란, inference time에서 지연시간을 의미

 

 

 

 

v) EfficientNet

최적화 목표: 예측정확도 > 추론 latency
3가지 방법으로 convolution구조를 확장.
∙ layer 추가
∙ layer별 channel 추가
∙ input img 해상도↑
이때, 위 3가지 방법은 서로에게 영향을 준다.
(∵ Receptive Field를 키우려면 layer가 더 필요.)
( 더 큰 img의 미세패턴포착을 위해 channel도 많이 필요.)
EfficientNet군은 Overfitting방지를 위해 B0~B7까지 Dropout을 0.2~0.5로 늘린다.
또한, AutoAugment와 SiLU(= Swish-1)를 사용한다.

 

 

 

 

 

vi) Vision Transformer with Self-Attention Mechanism

Transformer의 경우, Self Attention Mechanism을 사용한다.

[Self Attention Mechanism]: 입력사이 의미론적 관계(Semantic Relation)을 인식, 특정 patch가 다른 patch에 비해 더 중요한 정보를 담고 있는 경우, 이를 . 더강조해 새로운 표현을 생성한다.

 

Convolution은 Dataset이 증가할 때, 가중치 수를 줄여야 한다.

ViT는 image를 patch단위로 쪼개 patch의 픽셀값과 position을 이어붙여 표현한다.

다만, ViT의 경우, Convolution보다 더 많은 Dataset을 요구하기에

대량의 Data로 pretrain한 후 더 작은 Dataset으로 Fine-tuning하는 것이 권장된다.

 

 

 

 

vii) Ensembles & 권장 학습전략.

핵심은 약점보완을 위해 "최대한 다른 모델을 선택"하는 것ex) DenseNet + Xception + EfficientNet

∙ Dataset이 매우 작을때: Transfer Learning
∙ Dataset이 보통일 때: Fine-Tuning
∙ Dataset이 매우 클 때: 처음부터 학습

 

 

 

 

 

 

 


3. Detection

좀 더 상세한 설명은 가장 하단목록을 참조.

RetinaNet(FPN, AnchorBox, NMS)

🤔 FPN (Feature Pyramid Network)
비선형성❌ 신경망
Conv층: Feature map의 의미정보를 점차 다듬는다.
Pool층: 공간(x,y)차원에서 feature map을 축소한다.

🤔 Anchor Box
Bbox는 기본적으로 차이값(Δ)으로 계산되는데, 이는 단순히 사물과 겹쳐진 것을 의미한다.
∙ pred = Δ of Anchor 크기&위치
목표: 신경망이 0주변의 작은 값으로 예측하게 돕는 것.
(∵ 0 부근에서만 비선형성을 갖는 활성화 함수를 사용하는 이유.)
Loss 계산시, 실측박스(N) Anchor Box(M) 쌍 별 IoU행렬(N×M)을 계산,
이때, 유의미하지 않은 값 = Background로 간주해 아무것도 검출하지 않게 훈련된다.


🚩 (클래스 분류): Focal Loss
Background Box에 해당하는 손실이 전체 손실 압도 가능
→ 이를 방지하고자 RetinaNet논문에서 손실함수를 조정(BCE with γ)
→ 빈 배경에 훨씬 더 작은 Loss값을 생성하게 한다!


🚩 (박스 회귀): Smooth L1 Loss
L1: 경사가 모든곳에서 동일하다는 문제
L2: pred와 target값이 멀수록 오차값이 커져 outlier에서 문제가 발생
이에 대한 절충안으로 등장한 Smooth L1 Loss (수정된 Huber Loss)는 아래와 같은 느낌으로 사용된다.
∙ 오차가 작은 값 → L2
∙ 오차가 큰 값 → L1

🤔 NMS (Non-Maximum Suppression)
다수의 Anchor Box 후보에서 IoU와 Confidence를 이용해 객체별 1개씩만 선택하기 위한 "Greedy-Algorithm"
Step 1: Greedy로 IoU > Threshold인 Box를 찾음
Step 2: 더 높은 class confidence를 갖는 Box를 살림.

이를 알고리즘으로 나타내면 아래와 같다.
def NMS(Boxes, Confidence):
	res_box = []
    for b1 in Boxes:
    	버림 = False
        for b2 in Boxes:
        	if IoU(b1, b2) > threshold:
            	if Confidence[b2] > Confidence[b1]:
                	버림 = True
		if not 버림:
        	res_box.append(b1)
            
return res_box

 

 

 

 

 

 

 

 

 

 

 

 

 


4. Segmentation

i) Semantic Segmentation 

instance segmentation의 경우, 개별 instance가 분리되지 않는다.

semantic segmentation의 경우, 같은 segment의 "pixel"로 구분하는 것이다.

U-Net의 경우, Encoder to Decoder구조로 "직접적인" Skip connection을 진행한다.

이를 통해 Semantic granularity정보를 Encoder에서 Decoder로 직접 가져온다.

 

 

 

 

ii) Instance Segmentation (Atrous Convolution, Mask R-CNN)

🤔 Transposed Convolution
= Atrous Convolution
= Deconvolution
이라고도 불리며, 이는 기존 Upsampling방법과 달리 "학습가능한 가중치를 포함하는 Upsampling"연산이라는 점에서 유용하다.
자세한 설명은 이 링크 참조.

🤔 Instance Segmentation with Mask R-CNN
Detection: Object 주변 Bbox를 찾아 분류하는 것.
Instance Segmentation: Detection된 모든 객체에 대해 각 객체모양에 맞는 pixel mask를 추가.


🚩 Mask R-CNN
Mask R-CNN과 기타 RPN은 한번에 한 곳의 RoI에서 작동하기에 이는 실제로 Interest일 확률이 높고, 즉 RoI마다 더 많은 작업을 더 높은 정밀도로 수행할 수 있다.

Instance Segmentation Head: detection된 객체의 Feature map을 Transposed Convolution으로 Upsampling한다.
이때, Mask-Head는 클래스당 1개의 mask만 생성한다.


Segmentation Loss는 단순 pixel by pixel에 대한 BCE Loss를 사용한다.
(예측된 클래스에 대해 예측된 mask만 Loss값을 계산한다.)

 

 

 

 

 

 

 

 

 

 

 

5. Pose Estimation

🤔 Pose Estimation이란?
사람의 자세를 식별하기 위해 팔꿈치, 무릎, 얼굴 등을 식별하는 것. 
사람이 앉아있는지, 서있는지 등의 자세판별이 가능해 다음과 같은 곳에서 활용가능하다.

Papandreous et al; 2018

🤔 PoseNet

[1단계]
∙ Detection모델을 사용해 Interest point의 Heatmap을 식별
(일반적인 Interest point: 관절(joint or landmark), 눈, 코 등)
(Heatmap: Detection모델 classifier head에서 출력되는 점수 = threshold지정 이전값)

[2단계]
∙ Detect된 각 joint를 기준, 근처 joint의 가장 가능성있는 위치 식별.

[3단계]
∙ Hough Transform이라는 Weighted Voting Mechanism으로 1,2단계에 따라 선택된 Joint기반, pose검출.
이때, 2,3단계는 다양한 joint탐지를 위해 단순 detection모델로는 충분치 않기에 필수적이다.
그렇기에 joint와 joints사이의 offset도 예측하는 것이다.

 

🤔 다중객체의 pose estimation
단일 이미지에서 여러사람의 pose estimation을 위해 위의 step에 몇가지 기술추가가 필요하다.

1. segmentation모델을 활용, 사람에 해당하는 모든 pixel 식별
2. joint조합을 참고해 가장 가능성 높은 신체부위 식별
3. 각 사람에게 사람 pixel을 할당.
(1에서 찾은 mask의 Pixel과 2에서 식별한 가능성높은 joint를 이용.)

 

🧐 Human Pose Estimation 방식

1) Top-Down 방식

: 사람을 먼저 Detect → Detect된 자세를 추정.

정확도가 Bottom-up방식보다 높음.
검출된 사람들을 순회하며 joint들을 찾기에 속도가 Bottom-up방식보다 느리다
보통 저해상도에서 고해상도로 과정이 수행

즉, object detector를 사용해, 개별 instance를 식별(identifying), localizing → 한 사람의 포즈를 추정. 

ex) AlphaPose, Mask-RCNN


2) Bottom-Up 방식

joint를 먼저 Detect → 서로 연결해 자세를 추정.
정확도는 Top-down 방식에 비해 떨어짐.

Object Detection 과정이 없어 속도가 빨라 실시간 처리에 사용 가능
보통 고해상도에서 저해상도로 과정이 수행

즉, 확인되지 않은(identity-free) 의미론적 실체(semantic entities)를 지역화→사람 인스턴스로 그룹화

ex) OpenPose

cf) Pose Estimation Guideline

 

Pose Estimation Guide - Fritz ai

Almost everything you need to know about how pose estimation works Pose estimation is a computer vision technique that predicts and tracks the location of a person or object. This is done by looking at a combination of the pose… Continue reading Pose Est

fritz.ai

 

 

 

 

 

 

 

 

 

 


📌 생성 AI (Generation AI)

1. Baseline

현재까지 총 6가지의 흐름으로 Vision Generation은 분류가능하다:
∙ VAE
∙ GAN
∙ Auto-Regressive
∙ Normalizing Flow
∙ Energy-Based Model
∙ Diffusion

이에 대해 간단히 특징을 정리하면 아래와 같다.

∙ VAE

d
s

∙ GAN

s
s

∙ Auto-Regressive

s
s

∙ Normalizing Flow

s
s

∙ Energy-Based Model

s
s

∙ Diffusion Model

s
s

2. Advanced GAN

ls
s

3. RL & World Model

ls
s

4. Multi-Modal

ls
s

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


📌 Detection 상세설명


1.  R-CNN 계열 (RCNN, Fast R-CNN, Faster R-CNN)

1.1  R-CNN

R-CNN은 후보영역을 영역제안[Region Proposal]이라한다.
2-stage를 순차적으로 처리하기에 RCNN계열방법들을 2-stage방법이라 부른다.

 영역제안과정

물체가 있을 가능성이 높은 영역을 찾는단계.
RCNN은 Selective Search Algorithm으로  후보영역을 생성한다.
Selective Search는 image를 super pixel로 분할 후, clustering과정으로 영역을 생성.

생성된 영역을 227×227크기로 정규화,CNN에 입력, 특징벡터를 추출한다.


 영역분류과정

Binary-classifier인 SVM이 각 클래스확률을 계산, 클래스확률벡터를 출력.
후보영역에 대해 위치와 클래스정보를 확보 후, 위치와 클래스를 최종적으로 출력한다.

즉, "Selective Search알고리즘 → RoI 생성 → CNN으로 특징벡터 추출 → SVM" 순.

 

 

 

 

 

1.2  Fast-RCNN

 영역제안단계: Selective Search Algorithm 사용.
 영역분류단계: SVM을 Neural Net으로 대체.


 RoI  투영

Conv특징맵에서 후보영역에 해당하는곳을 RoI(Region Of Interest)로 지정하는, RoI투영을 진행.
그림에서 좌측선수에 해당하는 RoI가 노란색인데, RoI에 RoI풀링층을 적용해 고정크기맵(녹색 7×7맵)을 출력한다.


 RoI  특징벡터추출

이 특징맵을 2개의 FC층을 통과시켜 4096차원의 RoI특징벡터로 변환한다.
RoI특징벡터는 2갈래로 나뉜다.


 분류 및 회귀과정을 모든 RoI에 적용

한곳은 분류를 담당하는 FC층을 통과, 클래스확률벡터를 출력하고
한곳은 회귀를 담당하는 FC층을 통과, 클래스별 박스정보(x,y,h,w)가 된다.

즉, "RoI투영 → RoI 특징벡터추출 → 분류 및 회귀과정을 모든 RoI에 적용" 한다.
물체없음으로 판정된 RoI는 버리고, 나머지는 후처리 후 박스정보와 클래스정보를 최종 Detection결과로 출력한다.

 


Fast-RCNN은 박스정보를 알아내는 회귀와 클래스를 알아내는 classification을 동시에 수행하기 때문에 하나의 Loss function으로 두 task를 달성해야한다.
∙ 손실함수: J = Jclassification + λJregression 형식
이런 손실함수를 다중과업손실함수(Multi-task Loss function)라 한다.

 

 

 

1.3   Faster-RCNN

∙ 영역제안단계: 영역제안모듈, RPN(Region Proposal Network)신경망 사용.
∙ 영역분류단계: Fast R-CNN 사용.

 RPN

Pre-Trained VGG16을 앞에 배치해 특징맵을 추출(노란색 H×W맵)한다.
RPN은 이 특징맵의 각 pixel에서 3×3 filter로 512차원의 특징벡터를 추출한다.

 특징맵에 서로 다른 2개의 1×1 convolution을 적용해 6개의 값들을 추출한다.
 ∙ 물체여부를 나타내는 2개의 값
 ∙ 박스정보를 나타내는 4개의 값.

위의 연산을 9번 적용해 크기와 가로세로비율이 다른 9개의 박스 (= Anchor)를 생성.
Anchor: 여러크기의 물체를 표현하는 Anchor를 생성함으로써 다중크기의 물체탐지능력을 갖춘다.

결과적으로 H×W의 pixel마다 9개의 Anchor가 생성되므로 H×W×9개의 Anchor가 생성된다.
여기서 NMS를 적용해 2,000여개의 Anchor만 남긴다.


즉, CNN으로 특징맵 추출 → 1×1 conv로 6개값 추출 9회 진행 → Anchor Box생성 순이다.


 Fast R-CNN

 Anchor들을 RoI으로 간주해 위 그림의 신경망의 뒷부분에 있는 Fast-RCNN으로 입력한다.
Fast-RCNN은 후보영역 각각에 대해 RoI투영 → RoI 특징벡터추출 → 분류 및 회귀과정을 적용한다.

물체없음으로 판정된 후보영역은 버리고, 나머지 후처리 후, 박스정보와 클래스정보를 최종 Detection결과로 출력한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 


2. YOLO 계열

 

YOLO v1의 특징

image를 s×s격자로 나눈다.
(실제 구현은 아래그림의 노란격자처럼 s=7로 설정해  총 49개의 칸이 존재한다; 빨간박스는 dataset에 라벨링된 참값이다.)

아래그림에서 검은칸을 예로들어 90차원의 벡터로 표현해보자.
빨간색의 좌측선수를 표시한 빨간박스의 중심은 검은칸에 놓이기에 검은칸이 이 박스를 책임진다.
벡터는 90차원인데 앞의 5개요소(x1, y1, w1, h1, o1)는 이 박스의 위치와 크기, 신뢰도를 의미한다.

박스의 위치와 크기는 영상좌표계를 [0,1]사이로 정규화하고 정규화좌표를 중심으로 표현한다.
x2,y2,w2,h2,o2는 또다른 박스를 표현할 수 있기에 한칸은 박스를 2개까지 책임질 수 있다.

p0~p80은 해당박스가 어떤객체클래스에 속하는지 나타내는 one-hot코드이다.
YOLO가 물체의 위치와 클래스를 표현하는 방식

YOLO는 RCNN계열에 비해 상당히 단순한데, 아래 그림은 YOLO가 사용하는 CNN의 구조이다.
∙ Conv층: 24개 / MaxPool층: 4개 / FC층: 2개 로 구성되며
  - input은 448×448크기로 변환되어 입력되고
  - output은 7×7×90의 출력텐서를 갖는다.
위 그림에서 신경망은 image를 입력으로 받아 7×7×90의 출력텐서를 참값으로 주어 통째로 학습한다.

참값텐서에 [float으로 표시되는 Bbox정보], [OneHot코드로 표현되는 클래스정보]가 섞여있기에 classification과 regression이 동시에 일어난다. 

 

 

 

YOLO v3

YOLO v3은 (object, class)의 85차원 벡터를 추출하는 층을 신경망 3곳에 배치한다.

∙ yolo_82층에서는 14×14격자로 나눠 14×14×85×3텐서를 출력한다. 따라서 14×14의 각 요소는 박스를 3개까지 출력한다.
∙ yolo_94층에서는 28×28격자로 나눠 28×28×85×3텐서를 출력한다. 
∙ yolo_106층에서는 56×56격자로 나눠 56×56×85×3텐서를 출력한다.

이 층들이 출력한 텐서를 객체정보로 변환하면, 여러 scale의 객체를 탐지할 수 있다.

 

 

Loss Function

정답으로 Ground truth box와 클래스가 주어진다.

∙ 1, 2항은 각 박스의 위치오류와 크기오류를 측정하는 Regression Loss이다.
∙ 3항은 물체가 있지만 없다고한 FN오류를 측정하는 Confidence Loss이고,
∙ 4항은 물체가 없지만 있다고한 FP오류를 측정하는 Confidence Loss이다.
∙ 5항은 class를 나타내는 OneHot코드의 오류를 측정하는 Classification Loss이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


3. Transformer : DETR , SETR

고안 배경)

고안 배경)Transformer를 사용하면,
∙ 후보영역(RoI)을 생성하는 중간단계없이 Box집합을 직접예측할 수 있을까?
∙ 중복현상이 아예 일어나지 않게 할 수 있을까?
∙ Convolution기반의 Faster-RCNN이나 YOLO보다 좋은 성능을 얻을 수 없을까?

CNN은 유연하기에 Faster-RCNN과 YOLO v3의 구조를 자유자재로 설계가능하였다.

하지만 Transformer는 다소 고정적인데, 이유는 아래와 같다.
 T × dmodel 크기의 tensor가 여러 encoder블록과 decoder블록을 흐르며 연산이 진행


Encoder만 사용되는 ViT와 달리 DETR는 영상을 입력으로 박스집합을 출력해야하기에 Encoder와 Decoder 모두 사용한다.
Decoder에 붙은 출력층은 T × dmodel tensor를 Box집합으로 변환해야한다.

손실함수는 Transformer가 예측한 Box집합과 label박스집합이 일치하는 정도를 측정하는 능력을 가져야한다.
∙ Box는 직사각형을 표현하는 4개의 좌표(coordinate)와
∙ 물체 클래스를 나타내는 Class확률벡터(softmax)로 표현.

 

 

3.1 DETR (DEtection TRansformer)

Faster-RCNN같은 CNN기반 신경망 Box집합을 바로 예측하기 어렵기에
RoI를 생성 후, 영역을 분류
하는 일종의 우회하는 방식을 사용한다.
즉, 기존문제를 대리문제로 바꾸고 대리문제를 푸는 셈이라 볼 수 있다.

DETR은 RoI생성단계가 없고, NMS라는 후처리단계가 없는, End-to-End 학습이 가능하다.
위의 그림은 DETR모델구조로 DETR은 ~로 표시한 3가지 모듈로 구성된다.

 모듈 

CNN을 통해 Feature Extraction을 진행.
또한, 1×1 convolution을 적용 channel을 C에서 dmodel로 줄여 h×w×dmodel의 tensor로 변환한다.
이후 Flatten으로 pixel을 이어붙여 행에 배치한 hw×dmodel 행렬을 얻는다.
위 그림에서는 hw를 T로 표기하는데, 이는 최종적으로 transformer의 input으로 입력할 T×dmodel행렬을 얻음을 의미한다.

이 행렬의 각 행은 축소된 image의 pixel에 해당하며, Self-Attention계산 시 행이 Query로 참여하기에
축소된 pixel(= patch)간의 attention정보를 추출하는 셈이다.
즉, DETR은 Self-Attention을 반영한다 볼 수 있다.


 

 모듈 

Encoder-Decoder로 구성된 Transformer로
모듈 에서 입력된 T×dmodel 행렬에 Position Encoding을 적용해 Encoder블록1에 입력한다.

Encoder블록1, ... , Encoder블록M을 통해 변환된 행렬은


Decoder의 MHA에 입력되어 Key와 Value의 역할을 한다.


Decoder를 좀 더 살펴보자.

기존 Transformer에서는 Decoder가 Auto-Regressive방식으로 작동한다.
즉, NLP에서 <SOS>토큰을 주면 첫번째 단어가 생성되고 
<SOS>토큰과 첫번째 단어를 주면 두번째 단어가 생성된다.
이런 AR방식을 객체탐지에 적용할 수 있을까?? → ❌ 
(Bbox는 순서없이 집합으로만 표현하기 때문.)


Decoder 입력을 보면 object queries라 표시된 K개 벡터가 있다.
K×dmodel크기의 행렬이 입력된다는 의미로 K는 탐지가능한 물체의 최대개수이다.
출력층은 물체가 아닌경우, 를 출력할 수 있기에 가변개수의 객체탐지가 가능하다.

그림의 예시에서는 2개의 박스와 3개의 를 출력했다.
Decoder의 최초 입력인 object queries는 Box에 대한 아무런 정보❌ 
Position Encoding, P를 갖고 출발해야하는데, DETR은 학습을 통해 알아낸 P를 사용한다.


 모듈 

Decoder블록이 출력한 K×dmodel행렬의 각 행을 Feed-Foward에 통과시켜 박스정보로 변환한다.
이렇게 모델이 예측한 박스집합을 ŷ라 하고
정답에 해당하는 Ground_Truth Box집합을 y라 하자.

y에 박스를 추가해 ŷ처럼 K개 박스를 갖게 한다. 
ŷ과 y에 Hungarian Algorithm을 사용해 최적매칭쌍을 구한다.



📌 Loss Function
매칭된 참값박스 i와 예측박스 j쌍을 이용해 아래 처럼 손실함수를 정의한다.

첫번째 항은 class를 맞췄는지 측정한다. (p̂j(ci)는 class확률벡터에서 참값class에 해당하는 확률.)
두번째, 세번째 항은 물체위치를 얼마나 정확히 맞혔는지 측정한다. (2번째항: IoU ; 3번째항: L1 Distance)




Self-Attention Matrix식 = softmax(QKT / √dkey).
이 행렬은 image를 구성하는 여러 Q벡터가 상호주목하는 정도를 표현.

전술했듯, DETR에서 모듈 이 m×n크기의 기존image를 h×w로 축소하고
축소된 특징맵에서 화소각각을 Q벡터로 취하기에 Self-Attention Matrix는 축소된 pixel (= patch)가 상호주목하는 정도를 측정.

위의 그림에서 주황색 표시된 코끼리의 경우, 코와 발, 등, 꼬리에 주목하고 있는데, 이는 Bbox의 경계에 주목하고 있다는 사실을 확인할 수 있다.

이 사실을 바탕으로 Decoder의 역할을 추론해보면, Decoder는 Bbox를 제대로 알아내기위해 Self-Attention Matrix를 통해 물체의 상하좌우 경계에 주목한다고 할 수 있다.

 

 

 

 

 

 

 

3.2 SETR (SEgmentation TRansformer)

DETR는 Object Detection의 목적으로 고안되었다.
이때, Transformer의 특성으로인해 분할을 할 수 있도록 쉽게 확장할 수 있다.
DETR Architecture
위의 DETR모델의 모듈 ③은 출력행렬을 해석해 Box정보로 변환하는, Detection용도의 Head이다.
따라서, Segmentation용도의 Head를 붙이면, SETR이 된다.
즉, 요약하면 SETR은 Encoder(Transformer) - Decoder(CNN)의 구조를 띈다.


Segmentation Head 축소된 해상도를 원래 해상도로 복구하기위해 UpSampling을 위한 Convolution층이 포함된다.
SETR Architecture
(a). 먼저 image(m×n×3)를 고정된 크기의 patch로 나누고
각 patch를 선형 임베딩한 다음 Position Embedding을 추가한 후,
결과 벡터 시퀀스를 표준 트랜스포머 인코더에 공급한다.
(이때, 픽셀 단위 분할을 수행하기 위해 다양한 디코더를 도입한다)


(b) Decoder는 점진적 UpSampling(resulting in a variant called SETRPUP)으로
여러 단계의 Convolution층을 쌓아 피라미드 형태로 쌓은 Decoder를 제안한다.

(c) multi-level feature aggregation (a variant called SETR-MLA).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


4. Swin Transformer

4.1 Backbone Transformer

CNN transfer learning은 DNN의 큰 이점이다.
보통 전이학습(transfer learning)에 널리 사용되는 Backbone model로는 VGG, GoogLeNet, ResNet, DenseNet121 등이 있었으며, 최근에는 EfficientNet 등이 있다.

Backbone model은 주로 input data에서 feature map을 추출하는 역할을 한다. 
주로 pretrained model을 사용하며, 다양한구조(CNNs, Transformers, ResNets)를 사용할 수 있다.

기존 NLP에서 Transformer가 사용이 되었기에(GPT, BERT), 초반에는 transformer도 transfer learning을 위한 Backbone model로 쓸 수 있을까? 라는 의문에서 출발했다.

지역정보를 추출하는 Convolution연산에 의존하는 CNN에 비해 Self-Attention에 의존하는 Transformer가 Transfer Learning에 훨씬 유리하다는 실험적 입증이 많이 발표되었는데,
Backbone으로 쓸 수 있는 Vision Transformer를 제작할 수 없을까? 라는 의문에서 Swin Transformer로 답을 해준다.

Backbone이 되려면 image의 feature를 충분히 반영한 구조를 설계해야한다.
기존 transformer는 문장처리목적으로 설계되었기에, 조금의 변형이 필요하다.
Backbone모델이 되려면 아래의 특성들을 잘 반영해 처리할 수 있어야 한다.
(문장을 구성하는 단어는 scale변화가 없으나 image를 구성하는 Object는 아주 다양한 크기로 나타나기에 scale변화가 심한편.)
(또한, 한 문장을 구성하는 단어는 수십∙수백개에 불과하지만, image를 구성하는 pixel은 수만~수백만 개이다.)
(문장의 단어는 띄어쓰기로 잘 분할되어있지만, image는 Object끼리 혹은 배경이 심하게 섞여있다.)

 

 

4.2 Hierarchical Feature map. &. Shifted Window

Swin Transformer는 image특성을 반영하기위한 핵심아이디어를 2가지로 설명한다.

 Hierarchical  ViT

아래 그림(a)은 Hierarchical ViT(= Hierarchical Featuremap)을 사용해 객체의 scale변환에 대응하는 방법을 설명한다.
모든 window는 M×M개의 patch로 구성된다. (여기서 M=4)
맨 아래층은 작은 patch_size로 window가 4×4개가 있다.
가운데 층은 patch_size가 2배로 커져 2×2개의 window가 있고, 맨 윗층은 1개의 window가 있다.
이렇게 작은 patch부터 큰 patch로 구분해 처리하면, 여러 크기의 객체를 분류하거나 탐지할 수 있다.

그림 (b)의 ViT의 경우, 영상을 분류하는데 사용할 수는 있지만 객체탐지 및 분할에는 한계가 있다.


계층적 특징맵은 계산효율상에도 큰 이점이 존재한다.

단일해상도를 사용하는 ViT의 경우)
224×224 image를 16×16 patch(= 14×14개)로 나눈다 가정하자.
이 경우, T = 196인 행렬이 입력되는데, MHA는 T개 patch끼리 Self-Attention을 계산하기에 T2번 연산을 수행한다.
이때, 연산은 QKT의 행렬곱으로 이뤄진다.
Q와 K가 T×dkey행렬이므로 T2×dkey만큼 곱셈이 수행된다. 

다중해상도를 사용하는 Swin의 경우)
window별로 self-attention을 적용한다.
window는 M×M개의 patch로 구성되기에 한 window는 M2×dkey만큼 곱셈을 수행한다.

즉, ViT에비해 (T×T) / (M×M×window개수)배 빠르게 계산된다.
예를 들면 그림(a)의 맨 아래층에서는 window가 16개이므로 49배 빠르다.


 Shifted Window

Swin Transformer의 이름이 Shifted WINdow에서 유래되었을 정도로 핵심아이디어이다.
ℓ번째 layer에서 이전처럼 window를 나누는데,
그 다음 ℓ+1층에서는 window를 절반크기만큼 수평과 수직방향으로 이동해 나눈다.


shifted window를 사용하면 window간의 연결성강화 및 다양한 크기의 객체를 처리할 수 있고,
객체의 상대적인 위치정보를 저장하는 등 이를 통한 성능향상이 가능하다.

 

 

 

 

4.3 Swin Transformer Architecture

아래그림은 Swin Transformer의 구조이다.
좌측에서 우측으로 흐르는 단계 1~4는
좌측그림의 (a)의 아래에서 위로 진행하며 patch는 커지고
window개수는 작아지는 방향에 해당한다.




예를들어, C=96으로 하고, m×n = 448×448 image가 입력될 때,
단계1) input tensor: 112×112×48 // output tensor: 112×112×96
단계2) input tensor: 112×112×96 // output tensor: 56×56×192
단계3) input tensor: 56×56×192 // output tensor: 28×28×384
단계4) input tensor: 28×28×384 // output tensor: 14×14×768

위 그림의 (a)는 이런 tensor변환을 어떻게 수행하는지 설명한다.
단계 2에서 patch합치기 적용시, 맨 아래층에서 맨 위층으로 진행하는 과정에 해당하는 것으로 단순히 이웃한 4개 patch를 하나의 patch로 합치는 과정을 의미한다.

모든 단계를 거쳐 얻은 특징맵에 classification을 위한 head를 붙이면 classifier가 되고,
Detection을 위한 head를 붙이면 detector가,
Segmentation을 위한 head를 붙이면 segmentor가 된다.
이런 방식으로 Swin Transformer는 Backbone 모델로 작용한다.

이제 단계 1~4에 노랜색 표시된 Swin Transformer Block의 동작을 그림 (b)를 통해 살펴보자.
(b)는 Encoder Block을 2개 쌓은 상황으로 현재 Block ℓ은 ℓ-1번째 Block에서 xℓ-1 tensor를 받아 Layer Normalization을 거쳐 W-MHSA층으로 Self-Attention을 적용한다.
이후, Add와 Norm, FF, Add를 적용해 x을 출력한다.

ℓ+1번째 Block은 x을 입력으로 받아 같은 과정을 거쳐 xℓ+1 tensor를 출력한다.
ℓ Block과 ℓ+1 Block의 Self-Attention을 W-MHA, SW-MHA로 표기했다.
W-MHA는 window를 분할하고 SW-MHA는 Shifted Window로 분할한다.

Backbone모델로써의 Swin Transformer

Swin Transformer는 Backbone으로 쓰이는 CNN인 ResNet등과 호환되도록 tensor모양을 설정했기에
기존 딥러닝모델에서 CNN-Backbone을 들어내고 Swin-Transformer로 쉽게 대치할 수 있다.

 

 

5. ETC

cf) InternImage

 

[논문 review] - InternImage(2023): Exploring Large-Scale Vision Foundation Models withDeformable Convolutions

📌 InternImage [CVPR 2023] InternImage: Exploring Large-Scale Vision Foundation Models with Deformable Convolutions Paperswithcode 홈페이지에서 Detection, Segmentation 등 많은 Benchmark Dataset에서 최고의 성능(SOTA)를 달성한 (무친

chan4im.tistory.com

 

 

cf) W&B

 

'Deep Learning : Vision System/MLOps Tool: Weights & Biass' 카테고리의 글 목록

컴퓨터과학, 인공지능에 대한 공부를 열심히 하는 공대생

chan4im.tistory.com

  1. 41OTI4NT
  2. 40OTk0Nj
  3. 43MTg2OD

 

 

https://arxiv.org/abs/2304.00690

 

3D Semantic Segmentation in the Wild: Learning Generalized Models for Adverse-Condition Point Clouds

Robust point cloud parsing under all-weather conditions is crucial to level-5 autonomy in autonomous driving. However, how to learn a universal 3D semantic segmentation (3DSS) model is largely neglected as most existing benchmarks are dominated by point cl

arxiv.org

 

 

🤔 Main Contribution

1. SemanticSTF

21개의 Semantic category에 대한 고품질 point별 annotation을 제공하는 대규모 악천후 point cloud Benchmark.


2. PointDR

향후 전천후조건에서 3DSS연구 및 Benchmark에 활용가능한 point cloud domain randomization의 baseline

3. Leveraging SemanticSTF

SemanticSTF를 활용해 아래 2가지 까다로운 작업에서 활용.

① Domain Adaptive 3DSS: DA를 3DSS에 적용한 첫 사례.

② Domain Generalization 3DSS

cf) Leveraging = 효과적으로 활용하다 (leverage는 지렛대를 활용하다라는 의미로 효과적으로 활용함을 의미함..)

 

 

[Summary]:

① Level-5 자율주행을 위해 악조건 point cloud에서의 일반화모델(= Robust한 전천후 3DSS모델) 학습이 목표.

이를 위해 악천후 날씨에서의 Robust point cloud parsing을 위한 밀도높은 3DSS point-wise annotation Dataset이 필요.

→ SemanticSTF Benchmark를 제공.

 

Robust한 전천후 3DSS모델가 필요한데, 2가지 문제점이 존재함. (perturbation invariant해야함.)

  Problem 1) LiDAR point cloud는 sparse, incomplete, 기하학적 변형 및 의미론적 모호성의 영향을 받음.
  Problem 2) 눈보라, 빛방울 등으로 인해 악천후에서 더 많은 Noise가 도입됨

 

③ Sol) PointDR: Domain Randomization Technique의 한 방식.

 목표 1) 다양한 기상조건에서 동일한 범주의 point를 안정적으로 표현
 목표 2) 범주간의 구별가능한 강력한 3D Representation을 학습.

 

④ PointDR설계방식:

i) Geometry Style Randomization: 다양한 공간 증강하에 point cloud의 기하학적 분포를 확장.
ii) Embedding Aggregation: 무작위로 증강된 point cloud의 encoded embedding을 집계하기 위해 contrastive learning을 도입.

 

 

 

 

🤔 논문 읽기! by. Andrew Ng.

① Title / Abstract / Figure 및 Experiment 1~2개

∙ Title:

3D Semantic Segmentation in the Wild: Learning Generalized Models for Adverse-Condition Point Clouds

3D Semantic Segmentation을 활용.
악조건 point cloud에서의 일반화모델 학습이 목표인 것을 알 수 있음.





∙ Abstract:

[개념] Robust Point Cloud Parsing:

전천후 환경에서 level-5의 자율주행에 매우 중요함.

[선행 연구]

다만, 기존 Benchmark는 정상날씨에서 포착된 Point Cloud였음.

 

[본 연구]:

1. SemanticSTF Dataset

Robust Point Cloud Parsing을 위해 밀도높은 point-level(= point-wise) annotation 및 악천후의 3DSS를 연구하기 위한 SemanticSTF Dataset을 제안.

① Domain Adaptive 3DSS: 정상날씨 data → 악천후 data

② Domain Generalizable 3DSS: 정상에서 전천후 3DSS모델을 학습, 악천후에 적용

 

2. [PointDR]: Domain Randomization Techique  

① Geometry Style Randomization: point cloud의 기하학적 스타일을 다른방식으로 random화.

② Embedding Aggregation: 위의 embedding을 모으고, 궁극적으로 일반화가능한 모델을 도출함.

∴ 다양한 악천후에서 효과적인 3DSS!



cf) Background & 용어설명.

∙ 3DSS: 3D Semantic Segmentation

 Point Cloud: sensor등으로 물체의 표면을 측정해 x, y, z로 물체의 앞뒤,좌우,위아래 (최소 3차원)의 point로 나타내는 것.
즉, 비행시간으로 이동거리와 등록된 센서와 표적간 각도정보를 결합해 3D모양을 포착, 표면의 3D좌표를 계산하는 방식.

 Perturbation Invariance: 섭동불변 = 시스템이 외부 변동에 대해 얼마나 민감한지를 나타내는 것.
즉, "perturbation invariant" = "외부변동에 민감하지 않음" 을 의미.

 All Weather: 전천후 날씨를 의미.


[Adverse Weather]: --> 지면유형을 식별하기 어렵게해 무효영역이 상당부분 포함됨.
- Snow: 두꺼운 눈 덮인 범위가 물체 변형으로 이어질 수 있음.
- Rain: 지상의 물에서 Laser Signal의 "정반사"를 유발할 수 있음.

- Dense Fog: LiDAR 센서의 작동범위를 크게 감소시킴.
- Light Fog: 보통날씨와 유사한 특성을 가짐.

 

 

 

 

 

 

 

 

∙ Introduction:

선행연구들: 거의 다 정상날씨 or Detection Benchmark로 point-wise annotation이 없었음.
point-wise annotation은 매우 어려운 작업: 무효영역이 상당부분 포함되게됨.
 i) 3D view change
ii) point cloud와 사람간의 인식차이
iii) point sparsity
iv) sweeping occlusion

Contribution 1. SemanticSTF

이를 위해 SemanticSTF를 제공→자율주행에 자주 발생하는 4가지 악천후(짙은/옅은안개, 눈, 비)조건으로 포착.
아래 그림처럼 21개의 Semantic Category에 대한 point-wise annotations를 제공.
SemanticSTF는 악천후조건에서 3DSS와 Robust point cloud parsing을 위한 Benchmark를 제공.

[활용방안]: 기상에 강한 3DSS연구에 활용가능.
 i) 정상날씨 Data → 악천후 Data로의 DA 3DSS
ii) 정상날씨에서 전천후조건에 대해 학습하는 DG 3DSS모델.


Contribution 2. PointDR

Robust한 전천후 3DSS가 필요 --> 2가지 문제점이 존재함.
  Problem 1) LiDAR point cloud는 sparse, incomplete, 기하학적 변형 및 의미론적 모호성의 영향을 받음.
  Problem 2) 눈보라, 빛방울 등으로 인해 악천후에서 더 많은 Noise가 도입됨
이를 위해 아래와 같은 해결책을 도입함

[How to Solve? & Make Robust All Weather 3DSS] -> Domain Randomization Technique
sol) [PointDR]: 전천후 3DSS연구 및 Benchmarking을 위한 새로운 Framework.
 목표 1) 다양한 기상조건에서 동일한 범주의 point를 안정적으로 표현
 목표 2) 범주간의 구별가능한 강력한 3D Representation을 학습.

[PointDR 설계방식]
i) Geometry Style Randomization: 다양한 공간 증강하에 point cloud의 기하학적 분포를 확장.
ii) Embedding Aggregation: 무작위로 증강된 point cloud의 encoded embedding을 집계하기 위해 contrastive learning을 도입.



∙ Conclusion:

본논문: SemanticSTF(악천후조건 = 짙은∙옅은안개, 눈, 비)에서 LiDAR Point Cloud와 Annotation으로 Semantic Segmentation을 위한 대규모 Benchmark Dataset을 소개.

PointDR의 설계: Domain Randomization Technique
 - 목표: 
   i) 정상날씨 point cloud를 사용해
  ii) 악천후 point cloud에서 잘 작동할 수 있는
 iii) Domain Generalizable 3DSS Model을 훈련하는 것.

- 설계방식: 
  i) Geometry Style Randomization
 ii) Embedding Aggregation
→ 다양한 새로운 point cloud domain에서 "잘 일반화 되는" "섭동불변표현"을 공동으로 학습.



∙ Related Works

3D Semantic Segmentation

선행연구:
 - CNN기반, projection-based method
 - MLP기반 신경망
 - 3D Voxel CNN기반 신경망
 - Hybrid 신경망

기존의 3DSS신경망:
주로 정상날씨 point cloud대상으로 평가.
SemanticSTF: 해당 간극(정상,악천후)을 메우고, 전천후 3DSS의 연구 및 평가를 위한 견고한 baseline을 제공함.


Vision Recognition under Adverse Conditions

최근: 2D는 많으나 3D, 특히 point cloud학습은 포괄적 Benchmark의 부재로 충분한 탐구X
최근 제안된 STF, CADC같은 Dataset은 악천후 LiDAR point cloud를 포함하긴하나
Bbox같은 Detection task에 중점. --> point별 Annotation을 제공X
∴ 악천후 LiDAR point cloud로 이뤄진 첫 대규모 Dataset!

 

Domain Generalization

목표: Tgt Data가 모델학습중에 접근불가한 Src Domain Generalizable Model을 학습하는것.
(이때, Src의 경우, 단일 혹은 여러 관련성있는 서로다른 Source임.)

최근: Vector Field를 통해 point cloud를 변형, 3D Detection의 DA를 연구함.
본 논문은 3DSS의 DA를 탐구한 첫 시도!


Unsupervised Domain Adaptation

Label이 지정된 Src Domain에서 학습한 지식을 활용 → Label이 없는 Tgt Domain에 전달하는 방법.
이는 Src Domain의 지식을 Tgt Domain으로 확장하는 방법임.
최근: DA 3D-LiDAR Segmentation이 point별 Annotation으로 점점 주목을 받음.

 

 

 

 

 

 

 

 

 

 

 

 

③ Main Method, Math , etc 이해안되는 것  → Skim or Skip

∙ Main Method: SemanticSTF Dataset

이때, train/val/test 모두 다양한 악천후에 대한 LiDAR스캔의 비율이 거의 동일함.

또한, 식별이 불가능하거나 20개 클래스에 속하지 않거나 ignore(무시된 것)인 point는 invalid로 label을 지정함.
이때, invalid는 training&evaluation에 활용되지 않음.


∙ SemanticSTF의 Class Imbalance

road, sidewalk, building, vegetation, terrain 클래스는 발생빈도가 높지만
motor, motorcyclist, bicyclist 클래스는 명백히 발생빈도가 낮음.

[이런 Class Imbalance의 발생이유는?]

① 주로 교통장면에서 다양한 객체크기와 객체 카테고리의 불균형한 분포.

② 이는 기존의 많은 Benchmark에서도 매우 일반적임.




[Dataset 예시]:

∙ Main Method: PointDR

∙ Point Cloud Domain Randomization

전천후조건에서 DG를 살펴보자.
정상날씨 point cloud에서 일반화가능한 segmentation 모델훈련시 도움이 되는 Domain Randomization기법PointDR을 설계.

[Domain Generalization의 목표]:



∙ PointDR의 설계: Domain Randomization Technique

[목표]: 정상날씨 point cloud를 사용 → 악천후 point cloud에서 잘 작동할 수 있는 DG-3DSS모델 훈련하는 것.
[설계방식]: 2가지 보완설계로 구성: Geometry Style Randomization & Embedding Aggregation:
다양한 새로운 point cloud domain에서 잘 일반화되는 perturbation-invariant representation을 공동으로 학습.

 


 

∙ Loss Function



 

 

 

 

cf) Experiments

 

 

 

 

 

 

🤔 SemanticSTF 논문 구현 testing

1. 배운점.

처음에는 내가 임의대로 아래 깃헙 링크를 바탕으로 파일을 구성했었음:
00~08파일만 SemanticKITTI파일에 넣었었음.



2. 교수님 Feedback

Github만으로 내가 임의로 판단하지 말 것.
정확하게 Data Statistics(데이터 통계)를 파악하고, 실험을 진행해야함!!
Data Statistics란, 아래와 같이 논문에 나타나야함.

SemanticKITTI Dataset





3. How? 정확하게 Data가 구축되어있는지 파악?

train data만 00~08로 존재한다고? 좀 이상한데? valid는 없나?
위를 보고, 아! train.py구조를 먼저 확인해 봐야겠구나! 생각할 것!!

dataset을 split해서 사용하는걸 보니 train, val로 쪼개는것 같은데...
dataset구조를 확인해봐야할것 같다!

아! dataset을 보니까 train과 test(= valid)로 쪼개는구나!
근데, get_kitti도 있으니까 그 함수도 확인해보자.

이제, 마지막으로 core.datasets의 SemanticKITTI클래스를 살펴보면 최종 확인이 가능할 것이다.

import os

import numpy as np
from torchsparse import SparseTensor
from torchsparse.utils.collate import sparse_collate_fn
from torchsparse.utils.quantize import sparse_quantize
from torchpack.utils.logging import logger

__all__ = ['SemanticKITTI']

label_name_mapping = {
    0: 'unlabeled',
    1: 'outlier',
    10: 'car',
    11: 'bicycle',
    13: 'bus',
    15: 'motorcycle',
    16: 'on-rails',
    18: 'truck',
    20: 'other-vehicle',
    30: 'person',
    31: 'bicyclist',
    32: 'motorcyclist',
    40: 'road',
    44: 'parking',
    48: 'sidewalk',
    49: 'other-ground',
    50: 'building',
    51: 'fence',
    52: 'other-structure',
    60: 'lane-marking',
    70: 'vegetation',
    71: 'trunk',
    72: 'terrain',
    80: 'pole',
    81: 'traffic-sign',
    99: 'other-object',
    252: 'moving-car',
    253: 'moving-bicyclist',
    254: 'moving-person',
    255: 'moving-motorcyclist',
    256: 'moving-on-rails',
    257: 'moving-bus',
    258: 'moving-truck',
    259: 'moving-other-vehicle'
}

kept_labels = [
    'road', 'sidewalk', 'parking', 'other-ground', 'building', 'car', 'truck',
    'bicycle', 'motorcycle', 'other-vehicle', 'vegetation', 'trunk', 'terrain',
    'person', 'bicyclist', 'motorcyclist', 'fence', 'pole', 'traffic-sign'
]


class SemanticKITTI(dict):

    def __init__(self, root, voxel_size, num_points, **kwargs):
        submit_to_server = kwargs.get('submit', False)
        sample_stride = kwargs.get('sample_stride', 1)
        google_mode = kwargs.get('google_mode', False)

        logger.info("SKT")

        if submit_to_server:
            super().__init__({
                'train':
                    SemanticKITTIInternal(root,
                                          voxel_size,
                                          num_points,
                                          sample_stride=1,
                                          split='train',
                                          submit=True),
                'test':
                    SemanticKITTIInternal(root,
                                          voxel_size,
                                          num_points,
                                          sample_stride=1,
                                          split='test')
            })
        else:
            super().__init__({
                'train':
                    SemanticKITTIInternal(root,
                                          voxel_size,
                                          num_points,
                                          sample_stride=1,
                                          split='train',
                                          google_mode=google_mode),
                'test':
                    SemanticKITTIInternal(root,
                                          voxel_size,
                                          num_points,
                                          sample_stride=sample_stride,
                                          split='val')
            })


class SemanticKITTIInternal:

    def __init__(self,
                 root,
                 voxel_size,
                 num_points,
                 split,
                 sample_stride=1,
                 submit=False,
                 google_mode=True):
        if submit:
            trainval = True
        else:
            trainval = False
        self.root = root
        self.split = split
        self.voxel_size = voxel_size
        self.num_points = num_points
        self.sample_stride = sample_stride
        self.google_mode = google_mode
        self.seqs = []
        if split == 'train':
            self.seqs = [
                '00', '01', '02', '03', '04', '05', '06', '07', '09', '10'
            ]
            if self.google_mode or trainval:
                self.seqs.append('08')
        elif self.split == 'val':
            self.seqs = ['08']
        elif self.split == 'test':
            self.seqs = [
                '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21'
            ]
...

해당 코드를 보면, 00~07, 09, 10은 train으로
08은 valid로, 11~21은 SemanticKITTI처럼 test로 사용하는 것을 확인할 수 있었다.
따라서 최종적으로 나의 SemanticSTF파일 dataset구조를 아래와 같이 설정할 수 있었다.

 

 

② Domain Generalization 3DSS

cf) Leveraging = 효과적으로 활용하다 (leverage는 지렛대를 활용하다라는 의미로 효과적으로 활용함을 의미함..)

 

https://arxiv.org/abs/2010.14701

 

Scaling Laws for Autoregressive Generative Modeling

We identify empirical scaling laws for the cross-entropy loss in four domains: generative image modeling, video modeling, multimodal image$\leftrightarrow$text models, and mathematical problem solving. In all cases autoregressive Transformers smoothly impr

arxiv.org

 

 

 

 

0. 핵심 & Main Contribution + 후기

F

 

 

 

 

Abstract

4가지 Domain에서 AR-Transformer의 CE손실에 대해 scaling law를 확인:
이때, Cross Entropy = S(True) + D_KL(True || Model)
로 해석.
∙ 이미지 생성 모델링
∙ 비디오 생성 모델링
∙ 멀티모달 Img-Txt 모델링: 상호정보량에 대한 scaling law
∙ 수학문제해결: 학습분포를 extrapolating하는 성능에 대한 scaling law
이에 대해 모델크기와 계산예산이 증가함에 따라 성능이 점진적으로 향상되며, 이는 power law를 따른다

추가적인 실험: Downstream task에서 scaling law가 중요한 함의점을 가짐.

용어:

Cross Entropy Loss: L

Cost Budget: C

Dataset Size: D

Model Size: N

 

 

 

 

1. Intro

Cross Entropy Loss: L

Cost Budget: C

Dataset Size: D

Model Size: N


이때, L이 C,D,N 중 하나에 의해 "제한"되면, 각각의 양에 대해 L이 단순한 power함수로 변화한다!
이에 대해 여러 의문점이 있다.

이 결과가 모든 데이터 양상에 적용되는가?
손실 개선이 표현 품질과 하위 작업 성능으로 어떻게 이어지는가?
모델 성능이 상한에 도달했음을 어떻게 알 수 있으며, 추가적인 스케일링이 수확 체감을 겪게 되는 이유는 무엇인가?
이 추세의 정밀성과 보편성은 무엇을 설명하며, 이로부터 무엇을 더 배울 수 있는가?


본 논문은 폭, 깊이, 학습률 등의 하이퍼파라미터를 최소한의 변경으로도 일관된 성능을 나타냄을 보여준다.




Summary of the Results

모든 Domain에서 아래와 같은 결과가 나타났다:
  • 위 식의 Scaling Law가 일관되게 적용, 환원 가능한 손실이 매우 작은 경우에도 성립함.
  • 주어진 C에 대한 최적 모델 크기 N_opt를 동일한 멱함수 관계 N_opt ∝ C^(-ξ)로 모델링가능.
    이는 지수 ξ ≈ 0.7로 모든 도메인에서 유사, D가 모델 크기 N의 0.4승 보다 느리게 증가해야함을 시사함.
  • 각 도메인마다 트랜스포머의 최적 종횡비 d_model/n_layer가 다르며, 언어 모델보다 더 작은 값이 선호됨.
  • 언어이외의 도메인에서는 명확한 불일치가 관찰

특정 Domain에서 아래와 같은 결과가 나타났다:
  • 이미지생성모델을 ImageNet 분류에 fine-tuning:
    생성 손실이 수렴하더라도 분류 손실이 모델 크기에 따른 지수함수 추세로 계속 향상됨.
    이는 생성 손실의 수렴이 표현 품질이나 의미적 내용에 대한 수확 체감을 의미하지 않음을 시사.
  • 개별 이미지 및 손실 분포 백분위수에 대한 확장 추세를 탐구했으며, 전체 분포에 대한 평균 손실 추세와 유사함.
  • 다양한 이미지 해상도와 VQ 인코딩 방식에 대해 실험했으며, 각각 구분되는 스케일링 지수와 비환원 손실을 발견.
  • 멀티모달 모델에서 캡션-이미지 상호 정보량과 정보 이득 척도의 모델 크기에 따른 점진적 향상.
  • 수학 문제 해결에서 학습 분포를 외삽하는 성능은 주로 학습 분포 성능에 의존하며, 모델 크기에 따른 이점은 없다는 것을 보였다.

 

 

 

 

 

2. Central Empirical Scaling Laws in Each Domain

2.1 Domain Descriptions and Training Setups

모든 Domain에서 AR Cross Entropy Loss를 사용해 학습시킨 Transformer Decoder를 사용.
이때, 실험적으로
d_model/n_layer ≈ 10이 대략적으로 최적이라고 발견


2.1.2 Images

10M개의 Web Img Dataset을 8x8, 16x16, 32x32로 축소해 사용.

2.1.3 Video

7만여개의 동영상(약 100시간)분량의 Web Data사용.
Frame은 64x64해상도로 축소해 사용.

2.1.5 Mutlimodal Txt and Imgs

txt_token과 img_token을 순차적으로 AR적으로 예측하게 훈련.
txt: BPE tokenizer로 tokenize
img: RGB pixel값으로 tokenize

 

2.2 Model Size Scaling and Aspect Ratios

각 Domain에 대해 Converge된 모델로 N에 대한 L을 측정.
Img&Video: 1만개이하 parameter의 작은모델은 추세를 벗어나는 성능
각 모델은 최적의 d_model/n_layer가 존재:



2.3 Compute Scaling and Optimal Model Sizes

모델이 수렴할때까지 학습시키는 대신, 주어진 C로 달성가능한 L을 살펴볼 수 있다:
여기서 N_opt ∝ C^(-ξ)관계를 따르며, 지수ξ=0.7로 계산한다.
또한, D = C/6N * E 관계에 의하면, 계산 최적 학습 시 데이터셋 크기 D는 N^(2/3) 보다 느리게 증가해야한다.




2.4 Loss versus Position in Context Depends on the Structure of the Data

Language & Video는 power law를 따르나
Img는 전혀 다른 패턴이 나타나기에 Data특성에 의존적으로 보편적이지 않다.

다만, C와 N에 따른 Scaling Law는 Data분포에 거의 독립적이다.

 

 

 

 

 

3. Image & Video Modeling, the Reducible Loss, Downstream Tasks

매우 낮은 해상도(8x8)에서 환원 가능한 손실의 지수함수 추세를 약수 nats/image 수준까지 따라갈 수 있으며, 이는 10억 단위의 파라미터를 가진 모델로 달성할 수 있다.
즉, 더 큰 이미지에 대해서도 유사한 추세를 외삽할 수 있다는 이유를 제공한다.
또한 식 (1.1)의 멱함수 plus 상수 형태가 매우 정확한 근사임을 강력히 시사한다.

또한 생성 손실이 비환원 손실에 접근하더라도 미세 조정 분류 성능이 계속해서 점진적으로 향상되는 것을 보일 것이다. 이 결과는 생성 손실 추세가 수렴하는 것처럼 보여도 표현 품질이 계속 개선됨을 강력히 시사한다.



3.1 Varing the Image Resolution and Encoding

우리는 YFCC100m 데이터셋에서 8x8, 16x16, 32x32 픽셀 해상도로 축소된 이미지와, 64x64 이미지를 16x16 및 32x32 VQ 코드[vdOVK18]로 인코딩한 데이터로 트랜스포머를 학습시켰다. 그림 8에 계산 예산에 따른 환원 가능한 손실(= 개선을 통해 줄일 수 있는 손실의 양) 추세를, 그림 7에 모델 크기에 따른 추세를 보였다.

가장 작은 모델들은 8x8 해상도를 제외하고는 추세에서 벗어나는 성능을 보였는데, 이는 상대적 Positional Encoding을 활용하는 데 어려움을 겪기 때문으로 추정된다.

표 3에는 각 해상도별 환원 가능한 손실과 비환원 손실의 계산 예산 의존성 추세를 정리했다. 8x8 pixel이미지의 경우 10억 단위 파라미터 모델로도 거의 완벽한 모델링이 가능하지만, 더 큰 이미지에서는 훨씬 더 큰 모델과 계산 자원이 필요할 것으로 예상된다.

cf) nats: 로그의 밑이 e인 entropy단위.




3.2 Video Modeling and Individual Frames

비디오 모델링의 경우, 전체 추세를 개별 프레임으로 확장하는 것이 자연스럽다.

그림 9에서 모델 크기와 계산 예산에 따른 마지막 프레임의 환원 가능한 손실 추세를 보였다. 이미지 모델링과 마찬가지로 지수함수 추세가 관찰되며, 이를 통해 약 10^13 파라미터와 10^4 PF-day 규모의 모델이 각 프레임당 수 nats 수준의 손실을 달성할 수 있음을 예측할 수 있다.

 






3.3 Scaling Trends for Individual Images

3.3 개별 이미지에 대한 확장 추세

우리는 다양한 데이터 양상에서 매우 일관된 확장 추세를 관찰했다. 이는 개별 데이터 샘플에 대해서도 동일한 추세가 나타나는지, 아니면 분포 수준의 추세가 많은 개별 추세의 집합인지에 대한 의문을 제기한다.

이를 확인하기 위해 32x32 이미지 테스트셋에서 1000개 샘플을 선택하여 모든 모델의 손실을 평가했다. 그림 10에서 볼 수 있듯이, 손실 분포의 각 백분위수 역시 식 (1.1)의 멱함수 plus 상수 추세를 따르며, 개별 랜덤 샘플에서도 동일한 패턴이 관찰된다(그림 17, 20, 21).

이러한 발견은 다른 데이터 양상에서도 적용될 것으로 기대된다.

 






3.4 Finetuning on ImageNet at 32x32 Resolution

3.4 32x32 ImageNet에 대한 미세 조정

생성 모델을 이미지 분류 작업에 미세 조정하면 모델 크기에 따른 성능 확장을 또 다른 관점에서 살펴볼 수 있다. 32x32 해상도의 ImageNet[CLH17] 데이터셋을 사용하여 이를 실험했다.

그림 11에서 볼 수 있듯이, 사전 학습된 생성 모델을 미세 조정한 경우 순수한 지수함수 추세를 따르며,
심지어 생성 손실이 수렴하는 지점을 훨씬 넘어서까지 성능이 계속 향상된다. 이는 생성 손실의 수렴이 표현 품질이나 의미적 내용에 대한 수확 체감을 의미하지 않는다는 것을 강력히 시사한다.


 

 

 

 

 

 

4. Multimodal Models and Information Gain ()

img-txt 간 상호 정보량으로 멀티모달 모델의 성능을 평가할 수 있습니다.

🤔 How to get 상호정보량?
txt2img모델의 경우)
빈 caption의 Img손실 - caption있을때의 Img손실 = txt-img상호 정보량

문제점) 모델이 멀티모달 데이터로만 학습되었다면?빈 캡션이나 빈 이미지는 분포 바깥일 수 있음.
Sol)이 문제를 최소화하기 위해 캡션이 있거나 없는 데이터를 반반씩 섞어 10,000 스텝 파인튜닝한 뒤 상호 정보량을 측정
cf) 이 과정 없이 측정하면 상호 정보량이 약 2배 더 크게 나옴.

결과) txt2img가 img2txt보다 상호정보량 및 정보이득이 큼
= img에서 semantic정보를 추출하는데 더 많은 처리가 필요하기 때문이라는 추측.

cf) 한장의 img가 몇개의 단어에 해당할까?
가장 큰 img2txt모델) txt토큰당 약 2.6 nats로 단어 당 약 3.4 nats의 loss
img2txt상호정보량이 8 nats인 것을 고려하면, 32x32 이미지는 우리 최고 모델에 대해 약 2-3개 단어에 해당한다고 볼 수 있습니다.

 

 

 

 

 

 

5. Mathematical Problem Solving and Extrapolation

기계 학습에서 일반화는 대개 테스트와 학습 성능의 격차를 의미합니다. 하지만 개념적으로는 훈련 분포를 더 큰 또는 다양한 분포로 외삽할 수 있는 더 야심찬 가능성을 의미할 수 있습니다. 수학 문제 해결은 외삽 연구에 매우 적합한데, 숫자 범위나 연산, 재귀/구성적 깊이를 확장할 수 있기 때문입니다.
우리는 수치적 수준에 따라 다양한 테스트 세트로 문제 해결 성능을 평가하면서 이 현상을 연구했습니다. 모든 테스트 세트에서 약간의 매끄러운 거듭제곱법칙 더하기 상수 형태의 경향을 관찰했지만, 난이도 수준에 따라 지수와 오프셋이 다릅니다. 따라서 외삽 성능은 모델 크기가 커짐에 따라 향상됩니다.

그러나 그림 13에서 보듯이, 이 모델의 외삽 능력은 주로 훈련 분포에서의 성능에 달려 있습니다. 즉, 훈련 분포에서 동일한 손실을 달성하는 크기가 다른 모델들은 다양한 테스트 분포에서 대략 동등한 성능을 보입니다. 이런 의미에서 모델 크기를 늘리는 것만으로는 외삽 능력이 자동으로 향상되지 않고, 훈련 분포에서의 성능 향상을 통해서만 개선됩니다. [KMH+20]에서도 한 텍스트 분포에서 다른 분포로 외삽할 때 유사한 결과를 발견했습니다.
마지막으로, 수학 문제 해결의 정보 이론적 해석은 답안이 문제와 결정적으로 관련되어 있어 엔트로피가 실제로 0이 되어야 한다는 점에서 약간 다른 의미를 가집니다. 수학 성능과 이에 관한 훨씬 더 자세한 결과는 부록 B를 참고하시기 바랍니다.

 

 

 

 

 

6. An Incosistency in Compute and Datasize Scaling Laws

계산량 및 데이터 크기 스케일링 법칙의 불일치 실험은 저해상도 이미지 모델을 사용하여 연구하겠지만, 다룬 데이터 모두에서 질적으로 유사한 결과가 나타날 것으로 예상함.

그림 14 왼쪽을 보면, 다양한 모델 크기에 대한 학습 곡선과 완전히 학습된 초기 중지 L(D)의 트렌드를 볼 수 있습니다.
이는 학습 곡선이 모델 크기가 증가함에 따라 L(D) 트렌드에 점점 더 가까워지고 있음을 보여주는데, 이는 더 큰 모델이 더 빨리 학습한다는 것을 의미하며, 최적화가 모델 크기가 증가함에 따라 점점 더 효과적이 된다는 것을 시사합니다. 그러나 학습 곡선은 항상 샘플 효율성을 설정하는 L(D) 트렌드 위에 있습니다.

그림 15에서는 언어의 경우에 대한 유사한 현상을 볼 수 있습니다.
이제 두 가지 다른 트렌드의 투영을 비교해 보겠습니다. L(C) 계산량 트렌드는 그림 7에서 재현할 수 있습니다. L(D)를 계산량 축에 플롯하려면 N_opt(C) ≈ (2.8×10^8)C^0.74 의 거듭제곱법칙 트렌드를 사용해야 합니다(그림 16 참조).
이를 바탕으로 L(D) 대 C(D)를 그리면 그림 14 오른쪽과 같습니다. 여기서 문제는 모든 학습 곡선이 오른쪽 그림의 L(D) 트렌드 위에 있어야 하지만, L(C) 외삽은 궁극적으로 L(D)와 교차하고 그 아래로 내려간다는 점입니다. L(D), L(C) 또는 N_opt(C) 트렌드 중 하나는 이 교차점에서 또는 그 전에 무너져야 합니다.

이 불일치가 어떻게 해결되는지 확실하지 않습니다. 그러나 그림 14 왼쪽의 관찰과 앞서의 논의는 가능한 가설을 제시합니다. 모델과 데이터 크기를 늘릴수록 최적화 효율이 높아져 결국 학습 곡선이 L(D) 트렌드와 합쳐지게 됩니다. 교차점 근처에서는 계산량 프런티어가 구부러져 L(D)와 겹치게 될 것입니다. 이 관점에서 L(C)가 L(D(C))보다 더 가파른 것은 최적화의 결함 때문일 수 있습니다.
이 가설을 미래에 조사해 볼 만합니다. 만약 사실이라면, 최적 모델 및 데이터 크기의 상대적 스케일링이 궁극적으로 변경될 수 있으며, 과적합 등의 트렌드에 의해 결정될 수 있습니다.

마지막으로, 데이터 크기 트렌드에서 측정한 불가피한 손실은 16x16의 경우 2013 nats/이미지, 8x8의 경우 599 nats/이미지이고, 계산량 트렌드에서 추출한 값은 16x16에서 2023 nats/이미지, 8x8에서 602 nats/이미지로, 이 두 추정치가 꽤 유사하다는 점에서 우리의 결과가 일관성을 보인다고 할 수 있습니다.

 

 

 

 

 

 

 

 

7. Related Work

현대 신경망의 예측 가능한 스케일링 트렌드는 다양한 연구 그룹에 의해 연구되어 왔습니다. [HNA+ 17]으로 시작해서, 가장 최근에는 [RRBS19, LWS+ 20, RDG+ 20, Kom19, RFCS20]에서 다양한 모델 아키텍처와 데이터셋을 사용하여 스케일링 관계를 연구했습니다. 이 중 [KMH+ 20]의 언어 모델링 연구가 우리의 접근과 가장 유사합니다. 175B 파라미터 GPT-3 모델 연구 [BMR+ 20]도 이런 신경망 스케일링 법칙의 영향을 받았습니다.

우리와 다른 이들이 확인한 매우 정확한 스케일링 관계에 대한 이론적 설명은 많지 않습니다. [SK20]에서는 데이터 다양체 차원의 역수와 스케일링 지수를 연결하는 간단한 이론을 제안했습니다. [LXS+ 19, JGH18]의 모델 크기 확장, 특히 넓이에 대한 연구는 [LBD+ 20]에서 최적화된 하이퍼파라미터에 적용 가능하다면 우리의 스케일링 관계를 이해하는 데 유용한 틀을 제공할 수 있습니다.
우리가 사용한 모델과 데이터 양상은 과거에 널리 연구되어 왔습니다. 자기회귀적 이미지 모델은 PixelRNN [vdOKK16]부터 시작해서, 최근 [CRC+ 20]의 연구가 우리 모델과 학습 절차에 거의 동일합니다. 트랜스포머 기반 비디오 모델은 [WTU19]에서, 멀티모달 모델은 [TBL+ 19]에서 학습되었습니다. 원저자들은 수학 문제 데이터셋 [SGHK19]에 대해 트랜스포머를 포함하는 다양한 모델을 적용했고, [SSF+ 19]에서는 이를 더 특화된 아키텍처로 연구했습니다. 우리 모델은 대부분 이전에 논의된 것보다 간단한데, 디코더 전용 [LSP+ 18] 트랜스포머와 dense or sparse attention mechanism만 사용.

 

 

 

 

 

 

 

 

8. Discussion

우리는 단일 신경망 아키텍처인 트랜스포머를 이용해 이미지, 비디오, 멀티모달 데이터, 수학 문제 및 언어 [KMH+ 20, BMR+ 20] 생성 모델링을 수행할 수 있음을 보였습니다. 모든 데이터 양상에 대해 모델 크기와 계산 예산의 함수로 손실 달성 경향을 파악했습니다. 언어의 경우와 마찬가지로, 이 결과는 더 큰 모델이 더 많은 샘플 효율성을 가진다는 것을 의미합니다.
또한 일부 중요한 경우 파인튜닝된 하위 작업 성능도 유사한 스케일링 법칙을 따른다는 것을 확인했습니다. 이는 생성 모델링 손실의 경향이 실용적 기능에 이점으로 이어짐을 시사합니다.

더 놀라운 점은 데이터 분포와 거의 무관하게 최적 모델 크기는 training계산 budget의 함수라는 약 N_opt ∝ C^0.7의 보편적인 경향이었습니다.
이 경향은 최적화된 훈련 중 경과된 토큰 수의 C 또는 N에 대한 이중 경향을 의미하며, 따라서 더 큰 계산 예산은 훨씬 더 긴 훈련 시간보다는 더 큰 모델에 투자되어야 한다는 교훈을 줍니다. 이러한 언어 모델링 [KMH+ 20]의 교훈이 일반화되는 것입니다.

스케일링 법칙은 또한 신경망 아키텍처, 손실 함수, 훈련 알고리즘의 세부사항에서 벗어나 모델, 데이터, 계산 규모의 거대한 층위에 걸친 보편적 공통점을 향한 관점의 전환을 시사합니다. ML 연구는 현재 능력의 특정 결함을 파악하고 모델과 알고리즘을 변경하여 이를 개선하는 것을 수반합니다. 아마도 많은 기능은 단순히 규모 증가에 따라 연속적으로 해제될 수 있는 스펙트럼에 있을 수 있으며, GPT-3 모델의 메타학습 기능 [BMR+ 20]에서 암시되는 바와 같습니다.

우리는 또한 스케일링 법칙의 정보 이론적 함의를 논의했습니다.
가장 중요한 점은 (1.1)식의 두 항을 각각 진짜 데이터 분포의 엔트로피와 그 분포와 주어진 생성 모델 사이의 KL 발산으로 해석할 수 있다는 것이다. 엔트로피 식별은 정확한 경향의 외삽을 통해 가능했으며, 단일 모델의 결과로는 예측할 수 없다.

또한 멀티모달 모델에서 이미지와 캡션 간 경험적 상호 정보량의 흥미로운 스케일링 법칙을 관찰했습니다. 이는 상호 정보량이 캡션 엔트로피에 의해 제한되기 때문에 특히 흥미로운 것입니다.

 

 

 

 

 

 

 

 

Contributions

 

  • Tom Henighan은 이미지 및 비디오 모델링 실험과 분석을 수행했고, 실험과 데이터 분석을 가능하게 한 코드베이스를 관리했습니다.
  • Jared Kaplan은 수학 실험과 분석을 수행했고, 전반적인 데이터 분석을 주도했으며 논문을 작성했습니다.
  • Mor Katz는 멀티모달 실험과 데이터 분석을 수행했습니다.
  • Jacob Jackson, Chris Hesse, Heewoo Jun, John Schulman은 비디오 모델링 실험에 협력했습니다.
  • Jacob Jackson, Heewoo Jun, Prafulla Dhariwal, Alec Radford는 VQ-VAE 학습 전략과 코드베이스를 개발했습니다.
  • Sam McCandlish는 언어 모델의 질문-답변 기능 진보를 분석했습니다.
  • Aditya Ramesh와 Alec Radford는 멀티모달 모델링과 최적화에 대한 지도를 제공했습니다.
  • Chris Hallacy와 Alec Radford는 멀티모달 데이터셋을 큐레이션했습니다.
  • Heewoo Jun과 Aditya Ramesh는 이미지 데이터셋을 큐레이션했습니다.
  • Chris Hesse, Heewoo Jun, Alec Radford는 비디오 데이터셋을 큐레이션했습니다.
  • Mark Chen은 이미지 모델링과 파인튜닝에 대한 지도를 제공했습니다.
  • Tom Brown, Scott Gray, Benjamin Mann, Nick Ryder, Prafulla Dhariwal, Daniel Ziegler는 대규모 트랜스포머 모델 훈련을 위한 코드베이스를 구축, 최적화 및 유지했습니다.
  • Dario Amodei는 생성 모델링에 대한 전반적인 스케일링 법칙 연구를 옹호했습니다.
  • Sam McCandlish와 Jared Kaplan은 이 연구를 주도했습니다.

 

 

 

 

 

Appendix.

A. More Details on Image Modeling

그림 18과 19에서 우리는 다양한 이미지 해상도 및 인코딩에 대한 계산 규모 추세를 문서화하는 추가 정보를 제공합니다. 그림 20에서는 100k 파라미터 모델에서 400M 파라미터 모델로 전환될 때 손실이 가장 많이 개선되거나 개선되지 않은 이미지를 보여줍니다. 그림 17에서는 테스트 세트에서 무작위로 선택한 개별 이미지에 대한 추세도 보여줍니다.

그림 18은 다양한 이미지 해상도에 대한 픽셀 단위 계산 규모 추세와 식 (1.1)에 대한 거듭제곱 법칙 plus 상수 맞춤을 보여줍니다. 표 3에는 픽셀 단위 이미지 모델링에 대한 맞춤 결과가 나와 있습니다.

그림 19에서는 두 가지 다른 VQ 코드 해상도로 인코딩된 64x64 이미지에 대한 계산 규모 추세와 식 (1.1)에 대한 거듭제곱 법칙 plus 상수 맞춤을 보여줍니다. 일부 실행은 계산 한계를 넘어 발산되었고, 최악의 경우 그림 7의 모델 크기 추세에서 눈에 띄는 편차가 나타났습니다.

그림 20에서는 400M 파라미터 모델과 100k 파라미터 모델 간의 손실이 가장 많이 개선되거나 개선되지 않은 이미지를 보여줍니다. 이는 무작위로 선택한 1,000개 테스트 이미지 중 손실 비율 및 손실 차이로 측정했을 때 상위 또는 하위 10개 이미지였습니다. 사람이나 군중이 포함된 복잡하고 다채로운 장면의 이미지가 일반적으로 가장 많이 개선되었고, 흑백 이미지와 단순한 배경이 지배적인 이미지가 가장 적게 개선되었습니다.

그림 21에서는 이미지 완성 품질의 추세를 보여줍니다. 여기서 가장 왼쪽 열은 원본 이미지이고, 다른 열은 각각 상단에 표시된 비임베딩 파라미터 수를 가진 모델로 완성한 결과를 보여줍니다. 모델에는 이미지의 상단 절반이 조건으로 제공되며, 하단 절반은 온도 1.0으로 샘플링됩니다. 모델 크기가 증가함에 따라 사실감이 증가하는 명확한 추세가 있습니다.


B. Details of Math Experiments and Additional Results

B.1 절차적으로 생성된 교육 데이터
우리는 [SGHK19]에서 제공한 코드를 사용하여 모든 교육 데이터를 절차적으로 생성했습니다. 문제는 교육 분포에서 모듈을 무작위로 샘플링하여 생성되었으며, 'entropy' 설정은 정수 s ∈ [3, 10] 범위에서 균일하게 샘플링되었습니다. 엔트로피 s인 문제의 수는 약 10^s 정도이므로, 낮은 엔트로피의 쉬운 문제는 모델에 매우 많이 노출되지만, s=9인 일부 문제는 전혀 보이지 않을 수 있습니다. 따라서 교육 분포의 쉬운 구성 요소가 기억될 수 있습니다. 또한 우리의 절차적으로 생성된 데이터는 '보간' 테스트 분포 [SGHK19]에서 중복되지 않았지만, '외삽' 테스트 분포와는 완전히 분리되었습니다.

공식 외삽 분포는 하나의 난이도 수준만 제공하며 8가지 모듈 유형 모두를 포함하지 않습니다. 따라서 우리는 부드럽게 증가하는 난이도 수준(s=1, 2, ..., 19)의 문제 분포를 생성했습니다. 대부분의 모듈에 대해 보간 세팅을 사용했지만, 다른 매개변수가 필요한 경우 일반적으로 외삽 세팅을 사용했습니다. 중요한 것은 우리가 이러한 문제에서 항상 나쁘게 수행하고 빨리 과적합되는 것을 발견했기 때문에 probability__swr_p_level_set_more_samples 및 probability__swr_p_sequence_more_samples 생성기는 포함하지 않았다는 것입니다.

B.2 데이터셋 크기 조정
수학 데이터셋에 대해 N >> D이므로 성능이 과적합에 의해 제한되는 경우 데이터셋 크기 D에 따른 최적 성능을 연구했습니다. 각 데이터셋 크기와 문제 분포에 대해 L(D)를 훈련 중 최소 손실로 정의합니다(다양한 테스트 분포에 대한 손실이 여러 개인 경우 조기 종료와 약간 다름). 이 실험에서는 모든 데이터셋 크기에 대해 n_layer=64, d_model=512을 사용했습니다. L(D)에 대한 거듭제곱 법칙 맞춤을 얻었습니다(그림 22).

B.3 추가 수학 결과
여기에서는 문제 유형과 난이도 수준별 수학 성능에 대한 몇 가지 추가 관찰 결과를 제공합니다. 그림 23에서는 [SGHK19]에서 제공한 파일을 사용한 다양한 모듈의 성능을 보여주고, 그림 24에서는 다양한 모델 크기에 대한 난이도 수준별 성능을 보여줍니다. 공식 외삽 및 보간 테스트 세트에서 달성한 정확도는 그림 26과 27에 자세히 설명되어 있습니다.

전반적으로 이 부분에서는 수학 실험 및 추가 결과에 대한 자세한 내용을 제공하고 있습니다.


C. Additional Multimodal Results

이 섹션에서는 멀티모달 실험에 대한 추가 결과를 보여줍니다.

그림 29에서는 상호 정보의 학습 곡선을 보여줍니다. 여기에는 텍스트-이미지에 대한 공백 캡션 데이터의 95/5 혼합물로 처음부터 훈련하는 것과 50/50 혼합물로 10,000 단계 미세 조정하는 것이 포함됩니다. 이를 통해 우리는 상호 정보와 Infogain 추정치가 공백 캡션이나 이미지가 분포 밖인 문제로 혼란되지 않도록 합니다.

그림 28에서는 두 전략에 대한 최종 상호 정보와 Infogain을 비교합니다. 두 방법의 결과는 매우 유사합니다.

전반적으로 이 섹션에서는 멀티모달 실험에 대한 추가 결과, 특히 상호 정보 및 Infogain 측정에 대해 다루고 있습니다.


D. Additional Language Results

그림 30에서는 GPT-3 계열 모델의 산술 능력 진화를 보여줍니다. 작은 모델은 문제에 나오는 작은 숫자에 약간의 가중치를 두지만, 점점 더 큰 모델은 정답을 더 확신하게 선택하는 것을 볼 수 있습니다.

그림 31에서는 간단한 질문에 대한 답변 능력의 진화를 보여줍니다. 작은 모델은 질문을 이해하지 못하지만, 큰 모델은 질문의 두 가지 측면을 모두 이해하여 정답을 선택할 수 있게 됩니다.

전반적으로 이 섹션에서는 GPT-3 계열 모델의 산술 및 질문 답변 능력이 매개변수 수 증가에 따라 어떻게 발전하는지를 보여줍니다. 작은 모델은 질문을 이해하지 못하지만 큰 모델은 올바르게 답변할 수 있게 됩니다.


E. Mutual Information, Infogain, and Scaling

이 섹션에서는 경험적 상호 정보, Infogain 및 이들의 척도에 대해 설명합니다.

E.1 상호 정보 및 Infogain의 근사 유도 언어 모델의 경우 첫 T 토큰과 다음 T 토큰 간의 상호 정보를 연구할 수 있습니다. 모델 크기 N에 대해 토큰 위치 t에 따른 손실은 거듭제곱 법칙을 따른다는 것이 알려져 있습니다[KMH+20]. 우리는 이를 이용하여 상호 정보와 Infogain에 대한 근사 공식을 유도할 수 있습니다.

E.2 실제 세계 분포 간 KL 발산 추정 우리는 데이터 분포의 고유 엔트로피와 실제 분포 및 모델 분포 간의 KL 발산을 바탕으로 척도 추세를 해석했습니다. 이는 무한한 데이터, 모델 크기 및 계산 능력을 가지면 데이터 분포를 정확하게 모델링할 수 있다는 아이디어에 기반합니다. 새로운 데이터 분포에 대한 모델의 경험적 손실도 예측 가능한 척도 추세를 따르는 경우 이는 새 분포와 교육 분포 간의 근본적인 KL 발산을 추정할 수 있음을 의미합니다.

전반적으로 이 섹션에서는 상호 정보, Infogain 및 이들의 척도에 대한 수학적 분석과 해석을 제공하고 있습니다.


F. Hyperparameter Settings

이 섹션에서는 모델 학습에 사용된 하이퍼파라미터 설정에 대한 더 자세한 정보를 제공합니다.

모든 모델은 3,000단계의 선형 웜업 스케줄과 최대 학습률의 1/10까지의 선형 감쇄를 사용했습니다. 모델 하이퍼파라미터와 학습률은 표 4와 5에 나와 있습니다. 주의 개수는 항상 max(2, d_model/64)로 선택되었습니다. 대부분의 모델은 배치당 약 5 x 10^5 토큰으로 훈련되었지만, 일부 차이가 있습니다.

'Parameters'는 임베딩을 제외한 약칭으로, 편향은 포함되지 않습니다. 모든 모델은 최소 250,000 단계 이상 훈련되었지만, 많은 모델이 훨씬 더 오래 훈련되었습니다. 모델 크기에 따른 손실 추세는 테스트 손실을 최소화하는 단계에서 계산되었습니다. 동일한 크기의 모델에 대해 매우 유사한 학습률을 사용했으며, 이는 초기 그리드 검색을 통해 결정되었습니다.

 

 

 

+ Recent posts