6.2 使用特征归一化进行性能优化
接下来我们将进行数据正则化,数据正则化需要写一个正则化的方法。在6.1节我们已经讲解了正则化的背景、意义及工作的过程,这里将只有0、1的数据变成–4~4的数据。正则化有一个幅度的问题,数据的最小值是–4,最大值是4,尽可能平衡地将数据分布在–4~4的区间,这是基本思路。
在service目录中创建一个FeatureNormalization.py文件。先创建一个类FeatureNormalization,在类FeatureNormalization中定义一个方法normalize,使用normalize方法对输入的实例集进行正则化。
chapter6_Create_AI_Framework版本的FeatureNormalization.py的源代码如下:
第6行代码:获取实例集第一条记录的长度。Neuron_Network_Entry.py中输入数据源:[0,0,0]、[0,1,1]、[1,0,1]、[1,1,0],如果对输入的数据特征(第1列数据,第2列数据)进行正则化,需正则化至[–4,4]。正则化时第3列数据也需要进行正则化,第1列、第2列的输入特征变成了[–4,4]的数据,如果第3列数据不相应进行正则化,那么计算的数据和原来的结果就不符合,因此,len(instances[0])不用再减去1,将所有的输入数据的第1列、第2列、第3列数据都进行正则化。
第8行代码:max_items记录实例集中每一列的最大值。
第9行代码:min_items记录实例集中每一列的最小值。
第12~28行代码:循环遍历计算每一列特征的最大值和最小值。
第12行代码:循环遍历num_of_elements。
第14~15行代码:temp_max、temp_min为临时的最大值、最小值,初始化为实例集第0个输入实例中第j列的值。
第18~25行代码:循环遍历每个实例,计算每一列数据中的最大值、最小值。如果当前值大于临时设置的最大值,将当前值赋值给临时的最大值,这里指不是整个区间的最大值,整个区间的值在–4~4。如果当前值小于临时设置的最小值,将当前值赋值给临时的最小值。循环后找到这一列的最大值、最小值,这里实例集的最小值是0,最大值是1。实际的数据可能有几百个特征,数据的多样化就会极大地提升。
第27~28行代码:计算出每一列数据的最大值、最小值以后,将最大值、最小值追加到max_items、min_items数组中,获取每一列的最大值、最小值。
第31~50行代码:实现正则化的逻辑。正则化要循环所有的实例,循环所有的特征,正则化和前面的操作是不一样的,前面的操作是针对一列一列的数据,这里的操作是针对一行一行的数据,操作每一行具体的值,对每一行的内容进行修改。
第33行代码:提取出当前输入行对应列的元素本身,例如实例集第1行第1列的元素是0,第1行第2列的元素是0,第1行第3列的元素是0。
第36~37行代码:获取当前行的元素所在列的最大值(maxItem)和最小值(minItem),max_items、min_items计算的是每一列的最大值和最小值,根据列的索引进行提取,max_items[j]取j列的最大值,min_items[j]取j列的最小值。
第40~46行代码:获取新的最大值(newMax)、最小值(newMin)。如果j等于最后一个元素,最后一个元素是真实的值,则记录一下结果,newMax是1,newMin是0;否则,newMax是4,newMin是–4。如果是最后一列,最后一列是实际值在0~1,而Sigmoid激活函数计算的值也是0~1,因此,最小值是0,最大值是1;但如果是特征,特征是x的值,例如神经网络输入层节点的x1、x2,x值在–4~4,特征进行正则化的时候,为了最大限度地发挥Sigmoid函数的功能,把最大值newMax设置为4,最小值newMin设置为–4。
第48行代码:对数据进行正则化处理,使其符合Sigmoid函数的定义域[–4,–4]和值域[0,1]。定义域和值域分别是x和y的区间,x的有效区间是[–4,4],y的有效区间是[0,1]。
第50行代码:将实现的正则化数据赋值给instances[i][j]。
第52行代码:返回正则化处理以后的实例集。
图6-8中,x1是一个神经元的数据,是一个特征,x2是另外一个特征,x1和x2里面的数据是输入实例不同列的数据,正则化需对输入的每一列数据进行相应的正则化。不可能对每一行的数据进行正则化,在进行某种算法计算的时候,对第一行第一个元素进行了一种算法操作,对第二行第一个元素也要进行同种类型的算法操作,这才是所谓的正则化。
图6-8 正则化处理
然后在入口程序Neuron_Network_Entry.py中运用FeatureNormalization.normalize方法,在chapter5_Create_AI_Framework版本的Neuron_Network_Entry.py代码的基础上新增正则化的代码,并打印正则化以后的数据内容:
Neuron_Network_Entry.py程序中原来的输入数据为:
运行Neuron_Network_Entry.py程序,正则化运行结果如下:
原来的实例集的数据为[0,0,0],经过正则化处理,转换成了[–4.0,–4.0,0.0];[0,1,1]经过正则化处理,转换成了[–4.0,4.0,1.0];[1,0,1]经过正则化处理,转换成了[4.0,–4.0,1.0];[1,1,0]经过正则化处理,转换成了[4.0,4.0,0.0]。正则化以后完成了异或操作的计算,第一个元素和第二个元素不同的时候,结果是1.0;第一个元素和第二个元素相同的时候,结果是0.0,值域是[0.0,1.0],定义域是[–4.0,4.0]。当原来的x的值是0的时候正则化变成–4.0,当原来的x的值是1的时候正则化变成4.0,原来的y值是0的时候变成0.0,原来的y值是1的时候变成1.0,我们成功完成了数据的正则化。正则化是以后实现机器学习、人工智能一个很重要的步骤,在实际的商业生产案例中,几乎一定要进行正则化处理,因为现实的数据与数学公式要求的数据形态往往是有区别的。
数据正则化以后,运行Neuron_Network_Entry.py程序得到的结果如图6-9所示。
图6-9 正则化处理结果
数据正则化对结果产生了影响,第一行的实际值是0,预测值是0.026712792773893174,这是目前为止最接近实际值的数值;但其他的数据还是有些问题,后面的数据误差变大了,不过正则化处理是有效的。我们从问题出发,基于Sigmoid激活函数的图形,编写代码实现了盘古人工智能框架的正则化。Python生态系统中的一些库,或者人工智能框架肯定也实现了正则化方法,使用这些方法时我们只需调用相应的API接口。