上一次,我们用最简短的篇幅讲述了用Pytorch实现线性回归的过程。整个程序仅仅用了约60多行就完成了一个线性回归机器学习程序的全部内容。这次的文章,我们来对上一次的内容做一下探索。
先用命令做一下程序备份,我们在备份的程序上做修改。
执行命令:
cp main.py m1.py
执行了这条拷贝命令后,就有了m1.py这样一个程序。以下的修改都是基于m1.py这个文件的。
为了让探索的内容看起来清晰一些,我特别把训练数据做了一下修改,只保留了两个样本:
从样本上看,这个我们希望得到的模型y=wx b应该是y=x 1,也就是w=1且b=1。
探索一、修改num_epoch
执行
python m1.py
一会发现一张画出来非常非常“歪”的直线,根本就没有穿过两个样本点。直观上看,误差非常大。
再试一试别的值,我们也会得到别的结果。
num_epochs=10
num_epochs=100
num_epochs=1000
应该说是拟合的效果越来越好。而从迭代中不断输出的MSELoss的值来看,我们就能看出误差的下降过程:
这是一个不断下降的过程,也就是梯度下降对于损失函数的收敛过程,次数越多,收敛点就越接近目标点,结果就越精确。
探索二、打印参数
加入这样一行,我们打印一下整个模型(因为太简单了,所以我还不打算称它为网络)的参数都是些什么值。
先做一下假设,根据给出的训练样本,模型里面应该是一个w=1,一个b=1。
而我们看到程序的运行结果
这里w和b两个值,w很接近1了;是1.0988,而b是0.6081,距离我们要求的理想值还差得很远。
不要紧,我们把num_epochs改成5000再试试:
我得到了这样的结果,两个值都离目标非常接近了,相信再把num_epochs改大一些,两个值都会更接近1。
结论:迭代次数是会影响模型训练结果的,直观感觉较多的次数会让训练结果更准确。
探索二、修改learning_rate
按照刚刚最后一步的操作,即修改num_epochs=10000,learning_rate=0.001
这时会得到这样的结果
这个情况应该说还算是比较好的,至少结果和我们期望的非常接近,那现在我们尝试着修改一下learning_rate的值来看看它对于训练的影响。Ps.为了让对比的过程比较清晰,num_epoch我们画个图做对比好了。
来做这样几个对应的修改
(1) 设置num_epochs=100
(2) 设置learning_rate=0.01
(3) 修改对应部分的程序
加入w和b两个numpy数组——你就理解它是普通的python数组也没问题,至少现在还没有用到它任何的高级属性。
在训练的迭代中,把每一次的w和b的值都加入这两个数组中去,让数组越变越长。
按照我们的程序设置,这个数组最后应该是有100个元素。
注释掉原来画样本拟合部分的程序段,加入一句话,就是63行这一句,画出w的变化趋势。
当你把learning_rate分别设置为0.001,0.01,0.1,1四种不同情况的时候,你会看到不同的结果图:
learning_rate=0.001
learning_rate=0.01
learning_rate=0.1
learning_rate=1
当learning_rate=0.001时曲线非常平缓,w的更新学习正在朝着正确的方向走下去。当你设置learning_rate更小的时候,这个曲线会边儿更为平缓,相当于步子减小了
当learning_reate=0.01时曲线开始变得有点奇怪,你会发现这像是一个一步迈过了,又往回走。是的,步长变大了,所以在碗底一脚迈过了过去,这时回头才发现,背后才是低点,就又往回走。这种情况其实就不大好了。
当learning_rate=0.1是情况相当糟糕,乍一看是w精神分裂一般地走出了两个值。仔细看你会发现他是每一脚都成功迈过了碗底,向着跨国碗底的对面更高点迈了过去,而且由于斜率增大的原因,步子越来越大。这种情况下模型已经不能正常收敛了。
而在最后一个learning_rate=1的情况下,只有二十几个有效值,剩下的值不是inf就是nan。所谓inf就是无穷,nan(not a number),这两类值都不再能进行有效的实数计算,或者笼统称为无效的数字。这时w和b已经早就远离碗底去了外太空。
这个小实验只是希望大家先有一个感性认识,让大家清楚learning_rate会影响模型收敛的速度,learning_rate大步长大,但是步长大不意味着收敛效率更为可靠有效。如果我们对模型训练中的learning_rate把握不好,可以参考别人在训练相同模型时的值设置,或者干脆先设置成为较小的值。
结论:learning_rate一般设置成为较小的值比较好。
探索三、查询或打印模型中的参数值
这种方法在刚刚的实验环节已经用过了,就是用这样的方法
model.state_dict()会返回一个列表。
我们重新把learning_rate调整成0.001,再加入下面的语句:
相当于遍历模型中的变量,并把变量的key和value都打印出来,也就是变量名和变量值。
打印的结果如下:
上面部分就是遍历中打印的linear.weight和它的值,以及linear.bias和它的值。
下面部分就是直接通过变量名下标访问到的字典中的变量值的打印内容。
结论:模型中的变量访问很简单,可以通过字典方式来访问。
探索四、模型文件
通过ll命令可以看到,这个模型文件只有447个字节大小,就是刚刚这个model.state_dict()里的内容。不过直接看是看不了的,它不是文本文件。至于怎么看,我们以后会提。
结论:模型文件的保存很简单,内容不是文本文件。