mirror of
https://github.com/datawhalechina/llms-from-scratch-cn.git
synced 2026-09-07 12:09:55 +00:00
45 KiB
45 KiB
In [1]:
from importlib.metadata import version
import tiktoken
import torch
print("torch version:", version("torch"))
print("tiktoken version:", version("tiktoken"))torch version: 2.2.1 tiktoken version: 0.6.0
In [2]:
with open("the-verdict.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
print("Total number of character:", len(raw_text))
print(raw_text[:99])Total number of character: 20479 I HAD always thought Jack Gisburn rather a cheap genius--though a good fellow enough--so it was no
In [3]:
import re
text = "Hello, world. This, is a test."
result = re.split(r'(\s)', text)
print(result)['Hello,', ' ', 'world.', ' ', 'This,', ' ', 'is', ' ', 'a', ' ', 'test.']
In [4]:
result = re.split(r'([,.]|\s)', text)
print(result)['Hello', ',', '', ' ', 'world', '.', '', ' ', 'This', ',', '', ' ', 'is', ' ', 'a', ' ', 'test', '.', '']
In [5]:
# 从每个元素中删除空白,然后过滤掉所有空字符串。
result = [item.strip() for item in result if item.strip()]
print(result)['Hello', ',', 'world', '.', 'This', ',', 'is', 'a', 'test', '.']
In [6]:
text = "Hello, world. Is this-- a test?"
result = re.split(r'([,.?_!"()\']|--|\s)', text)
result = [item.strip() for item in result if item.strip()]
print(result)['Hello', ',', 'world', '.', 'Is', 'this', '--', 'a', 'test', '?']
In [7]:
preprocessed = re.split(r'([,.?_!"()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
print(preprocessed[:30])['I', 'HAD', 'always', 'thought', 'Jack', 'Gisburn', 'rather', 'a', 'cheap', 'genius', '--', 'though', 'a', 'good', 'fellow', 'enough', '--', 'so', 'it', 'was', 'no', 'great', 'surprise', 'to', 'me', 'to', 'hear', 'that', ',', 'in']
In [8]:
print(len(preprocessed))4649
In [9]:
all_words = sorted(list(set(preprocessed)))
vocab_size = len(all_words)
print(vocab_size)1159
In [10]:
vocab = {token:integer for integer,token in enumerate(all_words)}In [11]:
for i, item in enumerate(vocab.items()):
print(item)
if i >= 50:
break('!', 0)
('"', 1)
("'", 2)
('(', 3)
(')', 4)
(',', 5)
('--', 6)
('.', 7)
(':', 8)
(';', 9)
('?', 10)
('A', 11)
('Ah', 12)
('Among', 13)
('And', 14)
('Are', 15)
('Arrt', 16)
('As', 17)
('At', 18)
('Be', 19)
('Begin', 20)
('Burlington', 21)
('But', 22)
('By', 23)
('Carlo', 24)
('Carlo;', 25)
('Chicago', 26)
('Claude', 27)
('Come', 28)
('Croft', 29)
('Destroyed', 30)
('Devonshire', 31)
('Don', 32)
('Dubarry', 33)
('Emperors', 34)
('Florence', 35)
('For', 36)
('Gallery', 37)
('Gideon', 38)
('Gisburn', 39)
('Gisburns', 40)
('Grafton', 41)
('Greek', 42)
('Grindle', 43)
('Grindle:', 44)
('Grindles', 45)
('HAD', 46)
('Had', 47)
('Hang', 48)
('Has', 49)
('He', 50)
In [12]:
class SimpleTokenizerV1:
def __init__(self, vocab):
self.str_to_int = vocab
self.int_to_str = {i:s for s,i in vocab.items()}
def encode(self, text):
preprocessed = re.split(r'([,.?_!"()\']|--|\s)', text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
ids = [self.str_to_int[s] for s in preprocessed]
return ids
def decode(self, ids):
text = " ".join([self.int_to_str[i] for i in ids])
# Replace spaces before the specified punctuations
text = re.sub(r'\s+([,.?!"()\'])', r'\1', text)
return textIn [13]:
tokenizer = SimpleTokenizerV1(vocab)
text = """"It's the last he painted, you know," Mrs. Gisburn said with pardonable pride."""
ids = tokenizer.encode(text)
print(ids)[1, 58, 2, 872, 1013, 615, 541, 763, 5, 1155, 608, 5, 1, 69, 7, 39, 873, 1136, 773, 812, 7]
In [14]:
tokenizer.decode(ids)Out [14]:
'" It\' s the last he painted, you know," Mrs. Gisburn said with pardonable pride.'
In [15]:
tokenizer.decode(tokenizer.encode(text))Out [15]:
'" It\' s the last he painted, you know," Mrs. Gisburn said with pardonable pride.'
In [17]:
tokenizer = SimpleTokenizerV1(vocab)
text = "Hello, do you like tea. Is this-- a test?"
tokenizer.encode(text)[0;31m---------------------------------------------------------------------------[0m [0;31mKeyError[0m Traceback (most recent call last) Cell [0;32mIn[17], line 5[0m [1;32m 1[0m tokenizer [38;5;241m=[39m SimpleTokenizerV1(vocab) [1;32m 3[0m text [38;5;241m=[39m [38;5;124m"[39m[38;5;124mHello, do you like tea. Is this-- a test?[39m[38;5;124m"[39m [0;32m----> 5[0m [43mtokenizer[49m[38;5;241;43m.[39;49m[43mencode[49m[43m([49m[43mtext[49m[43m)[49m Cell [0;32mIn[12], line 9[0m, in [0;36mSimpleTokenizerV1.encode[0;34m(self, text)[0m [1;32m 7[0m preprocessed [38;5;241m=[39m re[38;5;241m.[39msplit([38;5;124mr[39m[38;5;124m'[39m[38;5;124m([,.?_![39m[38;5;124m"[39m[38;5;124m()[39m[38;5;130;01m\'[39;00m[38;5;124m]|--|[39m[38;5;124m\[39m[38;5;124ms)[39m[38;5;124m'[39m, text) [1;32m 8[0m preprocessed [38;5;241m=[39m [item[38;5;241m.[39mstrip() [38;5;28;01mfor[39;00m item [38;5;129;01min[39;00m preprocessed [38;5;28;01mif[39;00m item[38;5;241m.[39mstrip()] [0;32m----> 9[0m ids [38;5;241m=[39m [[38;5;28mself[39m[38;5;241m.[39mstr_to_int[s] [38;5;28;01mfor[39;00m s [38;5;129;01min[39;00m preprocessed] [1;32m 10[0m [38;5;28;01mreturn[39;00m ids Cell [0;32mIn[12], line 9[0m, in [0;36m<listcomp>[0;34m(.0)[0m [1;32m 7[0m preprocessed [38;5;241m=[39m re[38;5;241m.[39msplit([38;5;124mr[39m[38;5;124m'[39m[38;5;124m([,.?_![39m[38;5;124m"[39m[38;5;124m()[39m[38;5;130;01m\'[39;00m[38;5;124m]|--|[39m[38;5;124m\[39m[38;5;124ms)[39m[38;5;124m'[39m, text) [1;32m 8[0m preprocessed [38;5;241m=[39m [item[38;5;241m.[39mstrip() [38;5;28;01mfor[39;00m item [38;5;129;01min[39;00m preprocessed [38;5;28;01mif[39;00m item[38;5;241m.[39mstrip()] [0;32m----> 9[0m ids [38;5;241m=[39m [[38;5;28;43mself[39;49m[38;5;241;43m.[39;49m[43mstr_to_int[49m[43m[[49m[43ms[49m[43m][49m [38;5;28;01mfor[39;00m s [38;5;129;01min[39;00m preprocessed] [1;32m 10[0m [38;5;28;01mreturn[39;00m ids [0;31mKeyError[0m: 'Hello'
In [18]:
preprocessed = re.split(r'([,.?_!"()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
all_tokens = sorted(list(set(preprocessed)))
all_tokens.extend(["<|endoftext|>", "<|unk|>"])
vocab = {token:integer for integer,token in enumerate(all_tokens)}In [19]:
len(vocab.items())Out [19]:
1161
In [20]:
for i, item in enumerate(list(vocab.items())[-5:]):
print(item)('younger', 1156)
('your', 1157)
('yourself', 1158)
('<|endoftext|>', 1159)
('<|unk|>', 1160)
In [21]:
class SimpleTokenizerV2:
def __init__(self, vocab):
self.str_to_int = vocab
self.int_to_str = { i:s for s,i in vocab.items()}
def encode(self, text):
preprocessed = re.split(r'([,.?_!"()\']|--|\s)', text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
preprocessed = [item if item in self.str_to_int
else "<|unk|>" for item in preprocessed]
ids = [self.str_to_int[s] for s in preprocessed]
return ids
def decode(self, ids):
text = " ".join([self.int_to_str[i] for i in ids])
# 替换指定标点符号前的空格
text = re.sub(r'\s+([,.?!"()\'])', r'\1', text)
return textIn [22]:
tokenizer = SimpleTokenizerV2(vocab)
text1 = "Hello, do you like tea?"
text2 = "In the sunlit terraces of the palace."
text = " <|endoftext|> ".join((text1, text2))
print(text)Hello, do you like tea? <|endoftext|> In the sunlit terraces of the palace.
In [23]:
tokenizer.encode(text)Out [23]:
[1160, 5, 362, 1155, 642, 1000, 10, 1159, 57, 1013, 981, 1009, 738, 1013, 1160, 7]
In [24]:
tokenizer.decode(tokenizer.encode(text))Out [24]:
'<|unk|>, do you like tea? <|endoftext|> In the sunlit terraces of the <|unk|>.'
In [25]:
# pip install tiktokenIn [26]:
import importlib
import tiktoken
print("tiktoken version:", importlib.metadata.version("tiktoken"))tiktoken version: 0.6.0
In [27]:
tokenizer = tiktoken.get_encoding("gpt2")In [31]:
text = "Hello, do you like tea? <|endoftext|> In the sunlit terraces of someunknownPlace."
integers = tokenizer.encode(text, allowed_special={"<|endoftext|>"})
print(integers)[15496, 11, 466, 345, 588, 8887, 30, 220, 50256, 554, 262, 4252, 18250, 8812, 2114, 286, 617, 34680, 27271, 13]
In [32]:
strings = tokenizer.decode(integers)
print(strings)Hello, do you like tea? <|endoftext|> In the sunlit terraces of someunknownPlace.
In [34]:
integers = tokenizer.encode("Akwirw ier")
print(integers)[33901, 86, 343, 86, 220, 959]
In [35]:
for i in integers:
print(f"{i} -> {tokenizer.decode([i])}")33901 -> Ak 86 -> w 343 -> ir 86 -> w 220 -> 959 -> ier
In [36]:
strings = tokenizer.decode(integers)
print(strings)Akwirw ier
In [37]:
with open("the-verdict.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
enc_text = tokenizer.encode(raw_text)
print(len(enc_text))5145
In [38]:
enc_sample = enc_text[50:]In [39]:
context_size = 4
x = enc_sample[:context_size]
y = enc_sample[1:context_size+1]
print(f"x: {x}")
print(f"y: {y}")x: [290, 4920, 2241, 287] y: [4920, 2241, 287, 257]
In [40]:
for i in range(1, context_size+1):
context = enc_sample[:i]
desired = enc_sample[i]
print(context, "---->", desired)[290] ----> 4920 [290, 4920] ----> 2241 [290, 4920, 2241] ----> 287 [290, 4920, 2241, 287] ----> 257
In [41]:
for i in range(1, context_size+1):
context = enc_sample[:i]
desired = enc_sample[i]
print(tokenizer.decode(context), "---->", tokenizer.decode([desired]))and ----> established and established ----> himself and established himself ----> in and established himself in ----> a
In [42]:
import torch
print("PyTorch version:", torch.__version__)PyTorch version: 2.2.1+cu121
In [43]:
from torch.utils.data import Dataset, DataLoader
class GPTDatasetV1(Dataset):
def __init__(self, txt, tokenizer, max_length, stride):
self.tokenizer = tokenizer
self.input_ids = []
self.target_ids = []
# 对全部文本进行分词
token_ids = tokenizer.encode(txt, allowed_special={'<|endoftext|>'})
# 使用滑动窗口将图书分块为最大长度的重叠序列
for i in range(0, len(token_ids) - max_length, stride):
input_chunk = token_ids[i:i + max_length]
target_chunk = token_ids[i + 1: i + max_length + 1]
self.input_ids.append(torch.tensor(input_chunk))
self.target_ids.append(torch.tensor(target_chunk))
def __len__(self):
return len(self.input_ids)
def __getitem__(self, idx):
return self.input_ids[idx], self.target_ids[idx]In [44]:
def create_dataloader_v1(txt, batch_size=4, max_length=256, stride=128, shuffle=True, drop_last=True):
# 分词器初始化
tokenizer = tiktoken.get_encoding("gpt2")
# 创建数据集
dataset = GPTDatasetV1(txt, tokenizer, max_length, stride)
# 创建加载器
dataloader = DataLoader(
dataset, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last)
return dataloaderIn [45]:
with open("the-verdict.txt", "r", encoding="utf-8") as f:
raw_text = f.read()In [47]:
dataloader = create_dataloader_v1(raw_text, batch_size=1, max_length=4, stride=1, shuffle=False)
data_iter = iter(dataloader)
first_batch = next(data_iter)
print(first_batch)[tensor([[ 40, 367, 2885, 1464]]), tensor([[ 367, 2885, 1464, 1807]])]
In [48]:
second_batch = next(data_iter)
print(second_batch)[tensor([[ 367, 2885, 1464, 1807]]), tensor([[2885, 1464, 1807, 3619]])]
In [49]:
dataloader = create_dataloader_v1(raw_text, batch_size=8, max_length=4, stride=4, shuffle=False)
data_iter = iter(dataloader)
inputs, targets = next(data_iter)
print("Inputs:\n", inputs)
print("\nTargets:\n", targets)Inputs:
tensor([[ 40, 367, 2885, 1464],
[ 1807, 3619, 402, 271],
[10899, 2138, 257, 7026],
[15632, 438, 2016, 257],
[ 922, 5891, 1576, 438],
[ 568, 340, 373, 645],
[ 1049, 5975, 284, 502],
[ 284, 3285, 326, 11]])
Targets:
tensor([[ 367, 2885, 1464, 1807],
[ 3619, 402, 271, 10899],
[ 2138, 257, 7026, 15632],
[ 438, 2016, 257, 922],
[ 5891, 1576, 438, 568],
[ 340, 373, 645, 1049],
[ 5975, 284, 502, 284],
[ 3285, 326, 11, 287]])
In [50]:
input_ids = torch.tensor([5, 1, 3, 2])In [51]:
vocab_size = 6
output_dim = 3
torch.manual_seed(123)
embedding_layer = torch.nn.Embedding(vocab_size, output_dim)In [52]:
print(embedding_layer.weight)Parameter containing:
tensor([[ 0.3374, -0.1778, -0.1690],
[ 0.9178, 1.5810, 1.3010],
[ 1.2753, -0.2010, -0.1606],
[-0.4015, 0.9666, -1.1481],
[-1.1589, 0.3255, -0.6315],
[-2.8400, -0.7849, -1.4096]], requires_grad=True)
In [53]:
print(embedding_layer(torch.tensor([3])))tensor([[-0.4015, 0.9666, -1.1481]], grad_fn=<EmbeddingBackward0>)
In [54]:
print(embedding_layer(input_ids))tensor([[-2.8400, -0.7849, -1.4096],
[ 0.9178, 1.5810, 1.3010],
[-0.4015, 0.9666, -1.1481],
[ 1.2753, -0.2010, -0.1606]], grad_fn=<EmbeddingBackward0>)
In [55]:
vocab_size = 50257
output_dim = 256
token_embedding_layer = torch.nn.Embedding(vocab_size, output_dim)In [56]:
max_length = 4
dataloader = create_dataloader_v1(raw_text, batch_size=8, max_length=max_length, stride=5, shuffle=False)
data_iter = iter(dataloader)
inputs, targets = next(data_iter)In [57]:
print("Token IDs:\n", inputs)
print("\nInputs shape:\n", inputs.shape)Token IDs:
tensor([[ 40, 367, 2885, 1464],
[ 3619, 402, 271, 10899],
[ 257, 7026, 15632, 438],
[ 257, 922, 5891, 1576],
[ 568, 340, 373, 645],
[ 5975, 284, 502, 284],
[ 326, 11, 287, 262],
[ 286, 465, 13476, 11]])
Inputs shape:
torch.Size([8, 4])
In [58]:
token_embeddings = token_embedding_layer(inputs)
print(token_embeddings.shape)torch.Size([8, 4, 256])
In [61]:
block_size = max_length
pos_embedding_layer = torch.nn.Embedding(block_size, output_dim)Warning:
Output truncated. This notebook contains too many cells to display efficiently.