야놀자 모델의 확장에서 추가된 한국어 토큰에 대해서는 얼려두었다라는 논의 글을 보고 약간 조사를 해봤는데, 레이어단위와 별도로 토큰 단위로도 얼리는게 가능하구나라는 것을 알 수 있는 정보를 찾아서 링크합니다.


[수정: 토큰단위로 학습률 조절은 안됩니다. 또한 그냥 개념만 대충 설명하는 코드이니 실제 실행은 안될겁니다. chatgpt 가 만들어준 코드라고 하네요 ;;]



import torch
import transformers

model = transformers.RobertaModel.from_pretrained('roberta-base')
embedding_layer = model.embeddings

weight = embedding_layer.weight

vocab_size = weight.size(0)

new_token_indices = [vocab_size - num_added_toks + i for i in range(num_added_toks)]

# Set a high learning rate for the new tokens' embeddings
high_lr = 1e-3
for index in new_token_indices:
    weight[index].requires_grad = True
    weight[index].lr = high_lr

# Set a low learning rate for the existing tokens' embeddings
low_lr = 1e-5
for index in range(vocab_size - num_added_toks):
    weight[index].requires_grad = True
    weight[index].lr = low_lr

#ALTERNATIVELY, you can freeze the existing token embeddings with:
# Freeze the embeddings of the existing tokens
for index in range(vocab_size - num_added_toks):
    weight[index].requires_grad = False




https://github.com/huggingface/tokenizers/issues/1160


다만, 저 위의 코드는 chatgpt 가 만든 코드라서 lr이 각 웨이트마다 있는 것처럼 착각해서 만들어짐. lr은 글로벌 파라메터이므로 모듈 내에서는 개별적으로 조절이 불가. 그냥 requires_grad조절 만 가능함



transformers의 llama model소스를 살펴보고 내용 보충합니다.

https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py


 llama causal 모델은 크게 3개의 덩어리로 나눠져 있습니다


1. token (input_ids 로 입력받는 부분) 을 embed로 변환하는 레이어 - self.embed_tokens 레이어

2. embed를 GPT의 디코더 구조에 따라 해석하는 부분 (self.layers 배열에 정의된 레이어들

3. 최종적인 hidden_state로부터 다음 토큰을 예측하는 부분 (self.lm_head 레이어)


여기서 토큰 확장에 따라 직접 영향받는 레이어는 embed_tokens 와 lm_head 두개의 레이어입니다


토큰 갯수(vocab_size)가 30000 개이고, 각 엠베딩의 벡터의 성분 갯수 (hidden_size)가 4096 (llama 의 config.json에 정의) 이라고 할때

embed_tokens 와 lm_head 는 둘다 [30000, 4096] 텐서가 됩니다. (embed_tokens 에는  padding에 대한 것도 있지만 여기선 중요한게 아니므로 생략)


텐서가 담고 있는 각각 weight 들은 역전파를 돌릴지 말지에 대한 정보 (requires_grad)를 갖고 있습니다. [3,3] 짜리 LinearLayer 같은 텐서 1 개에는, requires_grad 가 1개 있는게 아니라 각각의 MLP마다 requires_grad가 있어서 총 9개의 requires_grad가 있는 것입니다.


lm_head는 맨 뒤쪽에 있는 레이어고 embed_tokens 는 맨 앞에있는 레이어이기 때문에 둘 다 영어쪽의 토큰에 해당하는 웨이트들의 학습을 얼리면 한국어 학습에 영어가 지장을 받지 않는다.. 가 핵심이 되겠네요. 

레이어끼리는 중간층에서 서로 얽혀있기 때문에 맨 뒤에 있는 영어토큰을 얼려도 중간에 타고 들어와서 앞쪽 레이어의 영어 토큰이 영향을 받을 수가 있으니 둘 다 얼리는게 맞을거 같습니다.