60行NumPy手搓GPT( 四 )


译者注:我们可以简单的认为 , 为了执行我们的自己的任务 , zero shot表示我们直接拿着大模型就能用于我们的任务了;one shot表示我们需要提供给大模型关于我们特定任务的一个列子;few shot表示我们需要提供给大模型关于我们特定任务的几个例子;
基于提示内容生成文本也被称之为条件生成 , 因为我们的模型是基于特定的输入(条件)进行生成的 。
当然 , GPT也不仅限于自然语言处理任务(NLP) 。你可以将模型用于任何你想要的条件下 。比如你可以将GPT变成一个聊天机器人(即:[32]) , 这里的条件就是你的对话历史 。你也可以进一步条件化你的聊天机器人 , 通过提示词进行某种描述 , 限定其表现为某种行为(比如你可以提示:“你是个聊天机器人 , 请礼貌一点 , 请讲完整的句子 , 不要说有害的东西 , 等等”) 。像这样条件化你的模型 , 你完全可以得到一个定制化私人助理机器人[33] 。但是这样的方式不一定很健壮 , 你仍然可以对你的模型进行越狱 , 然后让它表现失常[34] 。
译者注:原作者在这里主要讲了通过进行条件控制 , 其实还有很多其它的条件化机器人的方法 , 有兴趣我可以另开一篇来单独细说
说完了这些 , 现在终于要开始实际实现了 。
准备工作
首先将这个教程的仓库clone下来:

git clone https://github.com/jaymody/picoGPTcd picoGPT
然后安装依赖:
pip install -r requirements.txt
注意:目前代码在 3.9.10下测试通过 。
简单介绍一下每个文件:
在这里 , 我们将从0-1复现gpt2.py , 所以请先将这个文件删掉吧 , 我们重新建立一个新的gpt2.py文件 , 然后从头写起:
rm gpt2.pytouch gpt2.py
首先 , 将下面的代码粘贴到gpt2.py里:

import numpy as npdef gpt2(inputs, wte, wpe, blocks, ln_f, n_head):pass # TODO: implement thisdef generate(inputs, params, n_head, n_tokens_to_generate):from tqdm import tqdmfor _ in tqdm(range(n_tokens_to_generate), "generating"):# auto-regressive decode looplogits = gpt2(inputs, **params, n_head=n_head)# model forward passnext_id = np.argmax(logits[-1])# greedy samplinginputs.append(int(next_id))# append prediction to inputreturn inputs[len(inputs) - n_tokens_to_generate :]# only return generated idsdef main(prompt: str, n_tokens_to_generate: int = 40, model_size: str = "124M", models_dir: str = "models"):from utils import load_encoder_hparams_and_params# load encoder, hparams, and params from the released open-ai gpt-2 filesencoder, hparams, params = load_encoder_hparams_and_params(model_size, models_dir)# encode the input string using the BPE tokenizerinput_ids = encoder.encode(prompt)# make sure we are not surpassing the max sequence length of our modelassert len(input_ids) + n_tokens_to_generate < hparams["n_ctx"]# generate output idsoutput_ids = generate(input_ids, params, hparams["n_head"], n_tokens_to_generate)# decode the ids back into a stringoutput_text = encoder.decode(output_ids)return output_textif __name__ == "__main__":import firefire.Fire(main)
我们将分为四部分进行拆解:
gpt2函数是我们将要实现的实际GPT代码 。你会注意到函数签名中除了 , 还有其它的参数:
函数是我们之前看到的自回归解码算法 。为了简洁 , 我们使用贪心采样算法 。tqdm是一个进度条库 , 它可以帮助我们随着每次生成一个token , 可视化地观察解码过程 。