(一)数据集的认识
对于回归任务,我们输出的结果是一个实数集,而对于分类任务来说,我们输出的结果是属于一个离散的集合,接下来我们观察一个关于糖尿病的数据集,我们把这样的一个表,数据库中叫做关系图,每一行是一个样本,在数据库里叫做记录,每一列是一个特征,在数据库中叫字段,其中输入为X,输出为Y。
这样的数据我们在sk-learn中也可以找到类似的数据,如果安装了Anaconda,我们可以在lib下的site-packages中找到相关的数据集,里面用的文件扩展名为gz,用解压缩文件即可打开,是一个csv文件,里面的文件名为x与y,表示了输入与输出。csv文件面对的数据是用逗号来做分隔符,而excel文件面对的数据是用空格或者table做分隔符,所以不同的文件用excel打开不一定都是对齐的。在我们本次用到的数据中,输入的维度是八维,而输出的维度是一维的。
(二)模型的计算
对于n维的数据,我们要计算他的y_hat,那么他每个维度都有一个权重,每个权重与相应的特征值相乘进行加和得到响应的计算值,再将该计算值带入logistic函数中计算
对于Mini-Batch的样本,由于pytorch提供的函数是向量函数,计算这些输入的话,我们可以将其装变为矩阵之间的计算,利用GPU的并行性计算的能力得到输出,因为如果我们用for循环来写里面的计算,会相当麻烦。对应的,我们在实际代码中,Linear类需要修改下参数,输入为8维,输出1维
由于矩阵乘法其实是一个空间转换,M x N矩阵可以看成是一个m维的向量映射到n维空间的变换函数,在我们要做的线性变换中有可能不是线性的,我们可能要通过多次的变换来实现非线性,所以我们可以用多个logistic函数的线性变换层首尾相连,中间每一层记得加上一个激活函数,这样可以让每一次的空间压缩都引入一个非线性,这样我们就可以通过调整线性变换,来去拟合真正想要的空间变换。
因为我们想要找的是一个8维空间到1维空间的非线性的空间变换,我们可以将8维先变为6维,再把6维降为1维,也可以先把8维往高维度变化例如24维,再往低维度变化,变化的层数和维度决定了网络的复杂程度,但具体这些值(维度,层数等)取什么好,这就是一个超参数的搜索问题,一般来说里面的层数越多,中间的神经元越多,那我们可以对非线性变换的学习能力就越强。但学习能力越强也不一定是件好事,因为它可能会把输入样本的噪音也学习进去,但不同的数据他们的噪声是可能不相同的。我们需要的是学习数据本身的能力,从而保证他的泛化能力最好。这一般要通过超参数搜索的方式来尝试谁实现的比较好。
(三)pytorch代码解析
1. loadtxt函数中delimiter是分隔符参数,这里由于为csv文件所以用 “ , ” 作为分隔符,用numpy读取的时候要指定数据类型,用float32的原因是神经网络中经常用32位,因为一般GPU如2080或者1080他们只支持32位的浮点数运算,只有在比较贵的显卡如英伟达特斯拉系列显卡他支持64位,但对于神经网络来说,32位的浮点数足够用了。
2. 对于x_data和y_data,由于输入和输出特征是放在一起的,所以读取的时候,x_data取前八列,y_data取最后一列,由于我们要输出的数据是一个向量形式,所以要加 "[ ]"
补充:关于列表和数组的关系
列表:是python中的一种数据结构,列表中每个元素的大小可以不同,因而不支持一次性读取一列这样的操作,但可以支持索引操作
数组:在python中并不存在这样的数据结构,但是可以通过numpy中的函数numpy.array() 把列表转为数组,这样就可以将原来的列表表示为一个矩阵,也可以使用分片操作了。样例代码中
3. 注意torch.nn.Sigmoid()是一个模块,继承自Module,而且这个模块没有什么参数,所以我们只要一个实例化self.sigmoid就可以了,而torch.nn.Function.sigmoid()是一个函数。在使用的时候我们应该把torch.nn.Sigmoid看做是一层来调用。
4. 在定义forward函数的时候,由于我们每层的输出都是下一层的输入,如果我们把每一层的输出定义成多个变量,那么可能我们后续再写代码的时候出现问题很难发现具体是哪一层出了错,很不方便,所以我们不如把所有的变量都设为一个x,这样在命名上就不用有所考虑。
5. 虽然我们前面讲了Mini-Batch风格,但我们这个例子中并没有利用Mni-Batch来实现而是把所有的数据都扔进去了。
6. 激活函数有的连续有的不连续,比如ReLU这个就不连续,softplus长得很像ReLU, 但它的激活函数是连续的。还要注意的一点是,ReLU这个函数的输出是[0,1],后续的损失函数计算会涉及到求ln 0,所以我们在算最后的y_hat的时候,forward中的最后一个激活函数应该改为sigmoid,这样算出的就是[0,1]之间,比较光滑的。