본문 바로가기
Computer/LLM

nanoGPT, prepare.py

by hexists 2023. 3. 16.

오늘은 quick start에 있는 prepare.py 코드를 읽어봅니다.

코드는 아래 경로에 있습니다.

data/shakespeare_char/prepare.py

* 아래에서 정리된 모든 코드는 위 경로에 있는 코드입니다. 이해를 위해 옮겨 적었습니다.

 

경로에서도 알 수 있듯이 token 단위로 charater를 사용합니다.

 

전체 flow입니다. 코드에 있는 주석대로 정리하겠습니다.

 

1) download the tiny shakespeare dataset

requests.get()를 이용해서 input.txt를 다운로드합니다.

이전에 karpathy가 char-rnn에 사용했던 tinyshakespeare 파일을 사용합니다.

 

input_file_path = os.path.join(os.path.dirname(__file__), 'input.txt')
if not os.path.exists(input_file_path):
    data_url = 'https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt'
    with open(input_file_path, 'w') as f:
        f.write(requests.get(data_url).text)

 

2) get all the unique characters that occur in this text

1에서 저장한 데이터를 읽어와서 vocab을 만듭니다.

 

chars = sorted(list(set(data)))
vocab_size = len(chars)
print("all the unique characters:", ''.join(chars))
print(f"vocab size: {vocab_size:,}")

 

3) create a mapping from characters to integers

vocab과 index를 변환할 수 있도록 dict를 만듭니다. stoi, itos

그리고, encode, decode 함수를 정의합니다.

encode 함수는 string to integers으로 변환하고, decode 함수는 integers to string으로 변환합니다.

 

stoi = { ch:i for i,ch in enumerate(chars) }
itos = { i:ch for i,ch in enumerate(chars) }
def encode(s):
    return [stoi[c] for c in s] # encoder: take a string, output a list of integers
def decode(l):
    ''.join([itos[i] for i in l]) # decoder: take a list of integers, output a string

 

4) create the train and test splits

train, validation 데이터를 9:1 비율로 분리합니다. shuffle을 하지 않네요.

n = len(data)
train_data = data[:int(n*0.9)]
val_data = data[int(n*0.9):]

 

5) encode both to integers

train, validation 데이터를 encoding 합니다.

train_ids = encode(train_data)
val_ids = encode(val_data)
print(f"train has {len(train_ids):,} tokens")
print(f"val has {len(val_ids):,} tokens")

 

6) export to bin files

train_ids, val_ids를 numpy array로 변환합니다. uint16 type을 지정해서 변환하네요.

변환된 np.array를 train.bin, val.bin 파일로 저장합니다.

train_ids = np.array(train_ids, dtype=np.uint16)
val_ids = np.array(val_ids, dtype=np.uint16)
train_ids.tofile(os.path.join(os.path.dirname(__file__), 'train.bin'))
val_ids.tofile(os.path.join(os.path.dirname(__file__), 'val.bin'))

 

7) save the meta information as well, to help us encode/decode later

meta 정보(vocab size, dict)를 pickle 파일로 저장합니다.

meta = {
    'vocab_size': vocab_size,
    'itos': itos,
    'stoi': stoi,
}
with open(os.path.join(os.path.dirname(__file__), 'meta.pkl'), 'wb') as f:
    pickle.dump(meta, f)

너무 단순한 코드라서 몇 번 코드를 읽어본 사람이라면 설명이 필요 없을 수 있지만, 기록하면서 정리할 때 머릿속에 잘 저장되는 것 같아 정리해 봅니다.


추가로, BPE(Byte Pair Encoding) 단위를 사용하는 prepare.py도 정리합니다.

https://github.com/karpathy/nanoGPT/blob/master/data/shakespeare/prepare.py

 

데이터 다운로드 부분은 건너뛰고, encode 부분부터 봅니다.

 

1) download the tiny shakespeare dataset

위 내용을 참고해 주세요.

 

2) encode with tiktoken gpt2 bpe

char 단위와 다르게 tiktoken이라는 라이브러리를 사용합니다.

tiktoken은 huggingface tokenizer 대시 3-6배 빠르다고 합니다. link

tiktoken.get_encoding()으로 gpt2 encoder를 지정하고, enc.encode_ordinary()로 encoding 합니다.

 

get_encoding()에 지정 가능한 인코더는 cl100k_base, p50k_base, r50k_base (or gpt2)이 있습니다.

 

모델에 맞는 encoder는 "tiktoken.encoding_for_model('gpt-3.5-turbo')" 이렇게 찾아볼 수 있습니다.

https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

 

참고로 encode_ordinary()는 special tokens을 무시하는 함수입니다.

(encode() 함수는 special token을 artificial token으로 변환합니다.)

자세한 설명은 아래 링크에 있습니다.

https://github.com/openai/tiktoken/blob/main/tiktoken/core.py

 

import tiktoken  # prepare.py 맨 위에 있습니다.

enc = tiktoken.get_encoding("gpt2")
train_ids = enc.encode_ordinary(train_data)
val_ids = enc.encode_ordinary(val_data)
print(f"train has {len(train_ids):,} tokens")
print(f"val has {len(val_ids):,} tokens")

 

3) export to bin files

encoding 된 파일을 bin 파일로 저장합니다. 이 부분도 위 char 단위와 같습니다.
차이점은 meta 정보를 별도로 저장할 필요가 없습니다. tiktoken의 gpt2를 사용하기 때문입니다.

 

train_ids = np.array(train_ids, dtype=np.uint16)
val_ids = np.array(val_ids, dtype=np.uint16)
train_ids.tofile(os.path.join(os.path.dirname(__file__), 'train.bin'))
val_ids.tofile(os.path.join(os.path.dirname(__file__), 'val.bin'))

'Computer > LLM' 카테고리의 다른 글

MLM vs CLM  (0) 2023.04.20
InstructGPT Evaluation  (2) 2023.04.17
In-context Learning  (0) 2023.04.13
nanoGPT, readme  (0) 2023.03.08
ChatGPT  (0) 2023.03.07