当前位置: 首页 > 科技观察

用60行代码构建GPT!网友:比之前的教程更清楚了

时间:2023-03-20 10:24:52 科技观察

本文经AI新媒体量子位(公众号ID:QbitAI)授权转载,转载请联系出处。现在只需60行代码,您就可以从0构建GPT!当年特斯拉前AI总监的minGPT和nanoGPT也需要300行代码。这个60行的GPT也是有名字的,博主给它取名为PicoGPT。不过与之前的minGPT和nanoGPT教程不同,今天要说的博主教程更侧重于代码实现部分,模型的权重已经训练好了。对此,博主解释说,本教程的重点是提供简单易懂的完整技术介绍。这对于不了解GPT背后概念的朋友来说非常友好。有网友称赞这个博客的介绍很清楚,尤其是第一部分。这篇介绍GPT模型的文章真好,比我之前看到的介绍还清楚,至少第一部分讨论了文本生成和采样。目前这个项目在GitHub上的star已经超过100,在HackerNews上的点击量也即将突破1000。让我们从什么是GPT开始。在介绍之前,我们还是需要说明一下,本教程并不是完全零门槛的。需要读者提前熟悉Python、NumPy和一些基本的训练神经网络。教程的重点是技术介绍,一共六个部分:什么是GPT?按照惯例,在正式搭建GPT之前,有必要对它做一些基本的介绍。教程从三个部分解释了GPT的工作原理:输入/输出、文本生成和训练。在这里,博主附上代码,甚至用了一些比喻,让读者更好的理解GPT。比如在输入部分,作者把句子比作一根绳子,tokenizer会把它分成小块(词),称为token。再比如,在生成文本的部分引入自动回归时,博主直接贴出代码:defgenerate(inputs,n_tokens_to_generate):for_inrange(n_tokens_to_generate):#auto-regressivedecodeloopoutput=gpt(inputs)#模型前向传递next_id=np.argmax(output[-1])#贪婪采样inputs=np.append(out,[next_id])#将预测附加到输入returnlist(inputs[len(inputs)-n_tokens_to_generate:])#只返回生成的IDsinput_ids=[1,0]#"not""all"output_ids=generate(input_ids,3)#output_ids=[2,4,6]output_tokens=[vocab[i]foriinoutput_ids]#“heroes”“wear”“capes”在每次迭代时,它都会将预测的token追加回输入,这个预测未来值并将它们追加回输入的过程就是GPT被描述为自动回归的原因。60行代码如何工作?了解了GPT的基本概念后,我直接快进到如何在电脑上运行这个PicoGPT。博主先扔了他那只有60行的代码:importnumpyasnpdefgpt2(inputs,wte,wpe,blocks,ln_f,n_head):pass#TODO:implementthisdefgenerate(inputs,params,n_head,n_tokens_to_generate):fromtqdmimporttqdmfor_intqdm(range(n_tokens_to_generate),"generating"):#自动回归解码循环logits=gpt2(inputs,**params,n_head=n_head)#模型正向传递next_id=np.argmax(logits[-1])#greedysamplinginputs=np.append(inputs,[next_id])#将预测附加到输入returnlist(inputs[len(inputs)-n_tokens_to_generate:])#只返回生成的idsdefmain(prompt:str,n_tokens_to_generate:int=40,model_size:str="124M",models_dir:str="models"):fromutilsimportload_encoder_hparams_and_params#从已发布的open-aigpt-2文件中加载编码器、hparams和paramsencoder、hparams、params=load_encoder_hparams_and_params(model_size,models_dir)#使用BPEt对输入字符串进行编码okenizerinput_ids=encoder.encode(prompt)#确保我们没有超过模型的最大序列长度assertlen(input_ids)+n_tokens_to_generate[n_seq,n_vocab]#token+位置嵌入x=wte[inputs]+wpe[range(len(inputs))]#[n_seq]->[n_seq,n_embd]#forwardpassthroughn_layertransformerblocksforblockinblocks:x=transformer_block(x,block,n_head=n_head)#[n_seq,n_embd]->[n_seq,n_embd]#投影到词汇表x=layer_norm(x,ln_f)#[n_seq,n_embd]->[n_seq,n_embd]returnx@wte.T#[n_seq,n_embd]->[n_seq,n_vocab]之后,关于这三个部分的更多细节.......testbuild的GPT部分结合所有代码得到gpt2.py,共120行代码。如果删除注释和空格,则为60行。然后测试一下!pythongpt2.py\"AlanTuring认为计算机有一天会变成"\--n_tokens_to_generate8结果是:地球上最强大的机器。成功!上一部分的一些后续补充,博主也总结了这短短60行代码的缺点:非常低效!不过,他还是给出了两种让GPT更高效的方法:同时进行注意力计算,而不是顺序进行。实现KV缓存。此外,博主还推荐了一些训练模型、评估模型、改进架构的方法和教程。有兴趣的可以点文末链接哦~作者介绍了JayMody,目前在加拿大NLP初创公司Cohere从事机器学习方面的工作。在此之前,他还曾在特斯拉和亚马逊实习过一段时间,担任软件工程师。除了这篇教程,我的博客站点还有更新的其他文章,都附上了代码~代码传送门:https://github.com/jaymody/picoGPT/blob/29e78cc52b58ed2c1c483ffea2eb46ff6bdec785/gpt2_pico.py#L3-L58教程链接:https://jaykmody.com/blog/gpt-from-scratch/#putting-it-all-together