相关说明
这篇文章的大部分内容参考自我的新书《解构大语言模型:从线性回归到通用人工智能》,欢迎有兴趣的读者多多支持。
本文涉及到的代码链接如下:regression2chatgpt/ch10_rnn/char_mlp.ipynb、regression2chatgpt/ch10_rnn/embedding_example.ipynb
本文将介绍如何利用多层感知器(MLP)来自动生成Python代码(Python代码本身也是一种语言),为后续讨论循环神经网络(RNN)做好准备。如果读者对语言数字化、迁移学习、自回归学习等概念不太了解,可以先参考自然语言处理的基本要素。
在本文的基础上,系列的后续文章将着重探讨如何利用循环神经网络(RNN)来改进学习效果:
一、基础准备
自然语言处理的基本要素这篇文章讨论了在迁移学习中,预训练(Pre-training)的三种模式:序列到序列模式、自编码模式和自回归模式。在自回归模式下,我们的目标是根据文本背景来预测下一个词元。在这个过程中,模型需要应对以下两个关键问题。
- 变长输入:随着文本的深入,文本背景的长度逐渐增加,因此模型需要处理不定长的输入数据。
- 文字间的关联:模型必须捕捉文字之间的相互关系,以便得到更准确的预测结果。
然而,作为普通神经网络的代表,传统的多层感知器模型未能满足这两个要求。首先,多层感知器的输入形状是固定的;其次,它的模型结构无法直接捕捉文字间的依赖关系。不过,我们可以通过调整模型输入的方法来巧妙地解决(部分解决)这两个问题,从而成功地将多层感知器用于语言学习。
具体来说,设置一个固定的窗口长度,比如n,然后将模型的输入限制为n个连续的词元。这种方法虽然与自回归模式的要求稍有不同,但仍然能够根据部分文本背景来预测下一个词元。下面将深入讨论这一方法的细节。
二、数据准备
在学习自然语言处理时,首要步骤是获取充足的语言数据,通常称为语料库。本节将使用开源的Python代码作为语料库1,也就是说,尝试使用神经网络来学习如何自动生成Python代码。如图1所示,使用datasets可以方便地获取已经整理好的开源代码。
在处理获取到的Python代码时,需要完成两个关键任务:首先,将文本数字化;其次,根据自回归模式创建训练数据。
- 使用字母分词器实现文本数字化,这意味着训练数据中出现的字符将组成分词器的字典,如程序清单1的第5行所示(完整代码2)。此外,为了标识文本的开头和结尾,引入两个特殊字符“<|b|>”和“<|e|>”分别表示开头和结尾,如第7—9行所示。需要注意的是,这两个特殊字符的具体形式只是为了便于理解,它们并不匹配任何实际的字符。
1 | class char_tokenizer:
2 |
3 | def __init__(self, data, begin_ind=0, end_ind=1):
4 | # 数据中出现的所有字符构成字典
5 | chars = sorted(list(set(''.join(data))))
6 | # 预留两个位置给开头和结尾的特殊字符
7 | self.char2ind = {
s : i + 2 for i, s in enumerate(chars)}
8 | self.char2ind['<|b|>'] = begin_ind
9 | self.char2ind['<|e|>'] = end_ind
10 | self.begin_ind = begin_ind
11 | self.end_ind = end_ind
12 | self.ind2char = {
i : s for s, i in self.char2ind.items()}
13 | ......
14 |
15 | def autoregressive_trans(text, tokenizer, context_length=10)