LightNovelModel-Alpha / pretrain.py
hugfaceguy0001's picture
upload model and train/infer codes
e10f35b verified
Raw
History Blame Contribute Delete
5.53 kB
from model import TransformerConfig, TransformerLanguageModel
from tokenizer import load_tokenizer
import torch
from torch.utils.data import DataLoader
from dataset_loader import MultiSourceDatasetV2
import random
from tqdm import tqdm
# 模型参数
config = TransformerConfig(
50304, # vocab_size
1024, # block_size
768, # n_embed
12, # n_heads
12, # n_layers
0.0, # dropout
True # bias
)
# 训练参数
batch_size = 8
max_iters = 150000
gradient_accumulation_steps = 5
eval_interval = 100
save_interval = 500
learning_rate = 1e-4
device = 'cuda:0' # if torch.cuda.is_available() else 'cpu'
# 建立模型
model = TransformerLanguageModel(config)
model = model.to(device)
ckpt_id = 43000
checkpoint = f"checkpoints/new/{ckpt_id}.pt"
model.load_state_dict(torch.load(checkpoint))
# 加载分词器
tokenizer = load_tokenizer("tokenizer.model")
# 数据加载
recipe_files = [
[f"data/enwiki/enwiki-{page}.jsonl" for page in range(6400)],
[f"data/fineweb/fineweb-{page}.jsonl" for page in range(14850)],
[f"data/zhwiki/zhwiki-{page}.jsonl" for page in range(1350)],
[f"data/zhihu/zhihu-{page}.jsonl" for page in range(975)],
[f"data/allnovels-split/ans-{page}.jsonl" for page in range(1330)]
]
probs = [
0.2,
0.3,
0.2,
0.1,
0.2
]
# 建立数据加载器
ds = MultiSourceDatasetV2(recipe_files, probs)
loader = DataLoader(ds, batch_size)
# 建立数据处理函数
# 1. 使用tokenizer转化为整数id
# 2. 添加eos token
# 3. 对超出长度限制+1的数据进行随机截取
# 4. 计算最大长度
# 4. 对不足最大长度的数据用pad token(此处等于eos token)补足
# 5. 合成一个int64格式的tensor ids, 形状为(B,T+1), 使用ids[:,:-1]和ids[:,1:]作为x,y
def get_input_ids(text_batch, eos_token_id=50303, block_size=config.block_size):
texts = text_batch["text"]
ids = [tokenizer.encode(text) + [eos_token_id] for text in texts]
for i in range(len(ids)):
if len(ids[i]) > block_size+1:
start = random.randint(0,len(ids[i])-100)
ids[i] = ids[i][start:start+block_size+1]
max_len = max([len(item) for item in ids])
ids = [item + [eos_token_id] * (max_len - len(item)) for item in ids]
ids = torch.tensor(ids, dtype=torch.int64)
return ids[:,:-1],ids[:,1:]
# 建立优化器
optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate)
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, 1000, 2, 5e-7)
# 文本生成测试函数
@torch.no_grad()
def gen_text(text):
model.eval()
ids = torch.tensor(tokenizer.encode(text)).to(device).view(1,-1)
output_ids = model.generate(ids)[0,:]
model.train()
return tokenizer.decode(output_ids.tolist())[0]
# # 进行训练
# # 初始化进度条
# pbar = tqdm(total=max_iters+1)
# # 初始化每步的loss
# all_loss = 0.0
# # 初始化梯度累加
# grad_steps = 0
# # 使用数据加载器获取一个新的数据batch
# for iter_num, (x,y) in enumerate(loader):
# # x,y = get_input_ids(batch)
# # 每隔eval_interval轮检查模型生成效果,每隔save_interval保存一次
# steps = iter_num // gradient_accumulation_steps
# if iter_num % gradient_accumulation_steps == 0 and (steps % save_interval == 0 or steps == max_iters):
# print(gen_text("I love you, "))
# torch.save(model.state_dict(),f'checkpoints/mixed/mixed-{steps}.pt')
# print(f"Step {steps} saved.")
# # 调用模型计算logits和loss
# _, loss = model(x.to(device), targets = y.to(device), device=device)
# loss = loss / gradient_accumulation_steps
# # 反向传播计算梯度
# loss.backward()
# grad_steps += 1
# all_loss += loss.item()
# # 到达梯度累加步数以后更新参数
# if grad_steps >= gradient_accumulation_steps:
# # 更新参数
# optimizer.step()
# # 梯度归零
# optimizer.zero_grad(set_to_none=True)
# # 重置梯度累加步数
# grad_steps = 0
# # 更新进度条
# pbar.update()
# # 每轮输出一次loss
# print(f"\nLoss: {all_loss}")
# # 重置loss
# all_loss = 0.0
# # 达到步数以后结束训练
# if iter_num == max_iters * gradient_accumulation_steps:
# break
# 进行训练
ds_iter = iter(loader)
for iter in tqdm(range(max_iters+1)):
if iter < ckpt_id:
continue
all_loss = 0.0
# 梯度归零
optimizer.zero_grad(set_to_none=True)
for _ in range(gradient_accumulation_steps):
# 使用数据加载器获取一个新的数据batch
x, y = next(ds_iter)
# 调用模型计算logits和loss
logits,loss = model(x.to(device), y.to(device), device=device)
loss = loss / gradient_accumulation_steps
all_loss += loss.item()
# 反向传播计算梯度
loss.backward()
# 更新参数
optimizer.step()
scheduler.step()
# 每隔save_interval保存一次
if iter % save_interval == 0 or iter == max_iters:
torch.save(model.state_dict(),f'checkpoints/new/{iter}.pt')
print(f"Step {iter} saved.")
# 每隔eval_iter步评估一次
if iter % eval_interval == 0 or iter == max_iters:
print(f"Step: {iter}, Loss: {all_loss}")
print(gen_text("我喜欢你,"))