说明
- v3 主要更换了sky-pile 数据集
- v3 使用了转义词表技术,使得8000 多的em size 能够表达 2000 多w 的词表
- v3 由于词表是使用jieaba 分词 ,自然在相同token_id 数量的情况下信息量更多(更多的字符)
- v3 解码速度保持不变,同样训练消耗算力不变
- v3 幻觉不变
- v3 解码消耗显存不变
- v3 上下文长度不变
- v3 同样算力输出信息量更多(转义大词表的功劳)
- v3 目前只是给词表扩为了2000 多倍,理论上该em size 能将词表 放大到该em size 的平方倍数
- v3 目前没想到更好的能获得更大词表的方案,转义词表能力太强也有烦恼,感叹啊
- v3 提供了转义词表技术的全流程用法,可以将其使用在其他模型上,要是太模型用上后估计 voc-size 就剩1024 大小了
推理代码展示
import torch
import pandas as pd
import polars as pl
import numpy as np
from jieba import lcut
from tqdm import tqdm
from infer_model import SamOut
def load_model_and_voc(device="cpu"):
voc = pd.read_pickle("total_voc_new.pkl")["voc"]
voc = ["<|sos|>", "<|user|>", "<|agent|>", "<|pad|>", "<|history|>", "<|unk|>", "<|end|>", "<|next|>"] + sorted(
set(voc))
voc_size = len(voc) - 8
voc1 = pd.read_pickle("total_voc_new.pkl")["voc1"]
voc1 = pd.DataFrame({"voc": voc1.keys(), "count": voc1.values()})
voc1 = voc1[~voc1["voc"].isin(voc)]
voc1 = voc1.sort_values("count", ascending=False)
voc1["voc_id"] = np.array(list(range(len(voc1)))) % voc_size + 8
voc1["voc_num"] = np.array(list(range(len(voc1)))) // voc_size + 9
dl = pl.DataFrame(
{"voc": voc + voc1["voc"].values.tolist(), "voc_id": list(range(len(voc))) + voc1["voc_id"].values.tolist(),
"voc_num": [8] * len(voc) + voc1["voc_num"].values.tolist()})
net = SamOut(len(voc), 1024 + 512, 64, 16)
# net = SamOut(len(voc["voc"]), 512, 32, 8)
print(sum([i.shape[0] * i.shape[1] for i in net.parameters() if len(i.shape) > 1]) + sum(
[i.shape[0] for i in net.parameters() if len(i.shape) == 1]))
# net.load_state_dict(torch.load("pretrain_768.pth", map_location=device))
# net.load_state_dict(torch.load("pretrain_sft_single.pth", map_location=device))
net.load_state_dict(torch.load("pretrain_sft_single_1024.pth", map_location=device))
# net.load_state_dict(torch.load("pretrain.pth", map_location=device))
net.to(device)
net.eval()
return net, dl
def gen_token(voc, voc_dict, model, prompt, max_len, rp=1.2, temp=0.13, top_k=16, device="cuda"):
voc_list = pl.DataFrame({"voc": prompt}).join(voc, on="voc", how="left").to_numpy()
prompt_list = voc_list[:, 1].tolist()
print("agent:", end="", flush=True)
model.to(device)
current_voc = 8
state = None
for _ in tqdm(range(max_len)):
# for _ in range(max_len):
if state is None:
out, state = model(torch.Tensor([prompt_list]).to(device).long())
else:
out, state = model(torch.Tensor([prompt_list[-1:]]).to(device).long(), state)
out = out[:, -1:]
# 重复抑制
for token_id in enumerate(prompt_list):
out[:, :, token_id] /= rp
score = torch.softmax(out, -1)[0, 0]
score, score_index = torch.sort(score, descending=True)
if device == "cpu":
score = score.detach().numpy()
score_index = score_index.detach().numpy()
else:
score = score.cpu().detach().numpy()
score_index = score_index.cpu().detach().numpy()
score_sum = np.cumsum(score)
score1 = score[score_sum < 0.9]
if score1.size == 0:
score = score[:1]
else:
score = score1
score_index = score_index[:min(top_k, score.size)]
out = score / temp
v = out[:min(top_k, score.size)]
# top 中限制词表大小方可 ok
idx_next = torch.multinomial(torch.Tensor(v), num_samples=1, generator=None)
idx_next = score_index[idx_next.item()]
if prompt_list[-1] == 7:
current_voc = idx_next
if idx_next != 7:
if idx_next == 6:
break
# out_item = voc["voc"].filter(
# voc["voc_id"].is_in([idx_next]) & voc["voc_num"].is_in([current_voc])).to_numpy().tolist()
out_item = voc_dict.get("{}_{}".format(idx_next, current_voc))
if len(out_item):
prompt += [out_item[0]]
prompt_list.append(idx_next)
else:
prompt += ["<|next|>"]
prompt_list.append(7)
continue
if prompt_list[-1] == 7 or prompt_list[-2] == 7:
continue
print(prompt[-1], end="", flush=True)
def t_infre():
model, voc = load_model_and_voc()
voc_dict = {"{}_{}".format(k, v): i for i, k, v in voc.to_numpy().tolist()}
while True:
text = input("user:")
gen_token(voc, voc_dict, model,
["<|next|>"] + ["\x00"] + ["<|user|>"] + lcut("{}".format(text)) + ["<|agent|>"], 256)
print()
if __name__ == '__main__':
t_infre()
AI 代码解释
这段代码定义了一个基于PyTorch的文本生成模型,它使用了Pandas、Polars、NumPy、jieba和tqdm库来处理数据、分词以及展示进度条。下面我将逐步解析代码的功能,并解释各个部分的作用。
加载模型和词汇表
首先,load_model_and_voc
函数负责加载预训练好的神经网络模型(SamOut
)和词汇表。这里用到了Pandas读取并处理存储在文件中的词汇表,同时利用Polars创建一个新的DataFrame dl
来保存扩展后的词汇信息。此外,该函数还会实例化一个SamOut
模型,并尝试加载预训练权重到这个模型中。最后,将模型设置为评估模式,并返回模型和词汇表的数据结构。
def load_model_and_voc(device="cpu"):
# Load vocabulary from pickle file using pandas
voc = pd.read_pickle("total_voc_new.pkl")["voc"]
voc = ["<|sos|>", "<|user|>", "<|agent|>", "<|pad|>", "<|history|>", "<|unk|>", "<|end|>", "<|next|>"] + sorted(set(voc))
voc_size = len(voc) - 8
# Process additional vocabulary items with pandas
voc1 = pd.read_pickle("total_voc_new.pkl")["voc1"]
voc1 = pd.DataFrame({"voc": voc1.keys(), "count": voc1.values()})
voc1 = voc1[~voc1["voc"].isin(voc)]
voc1 = voc1.sort_values("count", ascending=False)
voc1["voc_id"] = np.array(list(range(len(voc1)))) % voc_size + 8
voc1["voc_num"] = np.array(list(range(len(voc1)))) // voc_size + 9
# Create a Polars DataFrame for the final vocabulary
dl = pl.DataFrame(
{"voc": voc + voc1["voc"].values.tolist(),
"voc_id": list(range(len(voc))) + voc1["voc_id"].values.tolist(),
"voc_num": [8] * len(voc) + voc1["voc_num"].values.tolist()}
)
# Initialize the neural network model SamOut and load pre-trained weights
net = SamOut(len(voc), 1024 + 512, 64, 16)
print(sum([i.shape[0] * i.shape[1] for i in net.parameters() if len(i.shape) > 1]) + sum([i.shape[0] for i in net.parameters() if len(i.shape) == 1]))
net.load_state_dict(torch.load("pretrain_sft_single_1024.pth", map_location=device))
net.to(device)
net.eval()
return net, dl
生成token序列
接下来是gen_token
函数,它的目的是根据给定的提示生成新的token序列。此过程中会用到之前加载的模型以及词汇表。每当需要生成下一个token时,就会调用模型预测最有可能出现的下一个字符或单词,并通过一些策略(如温度采样、top-k采样等)选择最终输出的token。为了显示进度,这里引入了tqdm
库来构建一个进度条。
def gen_token(voc, voc_dict, model, prompt, max_len, rp=1.2, temp=0.13, top_k=16, device="cuda"):
# Convert prompt into token IDs using Polars join operation
voc_list = pl.DataFrame({"voc": prompt}).join(voc, on="voc", how="left").to_numpy()
prompt_list = voc_list[:, 1].tolist()
print("agent:", end="", flush=True)
state = None
for _ in tqdm(range(max_len)):
...
交互式推理
最后是t_infre
函数,它提供了一个简单的命令行界面让用户输入文本,然后调用gen_token
函数来生成回复。循环将持续直到用户终止程序。
def t_infre():
model, voc = load_model_and_voc()
voc_dict = {"{}_{}".format(k, v): i for i, k, v in voc.to_numpy().tolist()}
while True:
text = input("user:")
gen_token(voc, voc_dict, model,
["<|next|>"] + ["\x00"] + ["<|user|>"] + lcut("{}".format(text)) + ["<|agent|>"], 256)
print()
综上所述,这段代码实现了一个可以与用户对话的系统,能够接收用户的输入并根据上下文生成相应的回应。它结合了深度学习模型与多种Python库,以确保高效的数据处理和良好的用户体验。特别是通过使用Polars代替传统的Pandas进行更高效的内存管理和更快的数据操作,以及利用tqdm库为长时间运行的任务添加了直观的进度反馈机制。
标签:词汇,表达,voc,list,词表,len,score,voc1,net From: https://blog.csdn.net/weixin_32759777/article/details/145094018