有一糖尿病数据集,在文件中,每个样本(sample)有8个维度的信息(feature),并以此进行二分类。
原模型改进
前篇中,单维度逻辑回归模型为
\[\widehat y^{(i)} = \sigma(x^{(i)} \omega+b)\]其中的 \(x^{(i)}\) 表示第i个样本的维度,对于多维度,输入要变为8个维度的输入因此,模型应当变为
\[\widehat y^{(i)} = \sigma(\sum _{n=1}^8 x^{(i)}_n \omega _n+b)\]其中的 \(x^{(i)}_n\) 表示第i个样本的第n个维度。由于在实际代码运算中是以矩阵进行计算的,因此其中
\[\sum _{n=1}^8 x^{(i)}_n \omega _n = \begin{bmatrix} {x_1^{(i)}}&{\cdots}&{x_8^{(i)}} \end{bmatrix} \begin{bmatrix} {w_1}\\ {\vdots}\\ {w_8} \end{bmatrix}\]则原式可以表示成
\[\widehat y^{(i)} = \sigma( \begin{bmatrix} {x_1^{(i)}}&{\cdots}&{x_8^{(i)}} \end{bmatrix} \begin{bmatrix} {w_1}\\ {\vdots}\\ {w_8} \end{bmatrix}+b)\\ =\sigma(z^{(i)})\]pytorch中的sigmoid函数,是一种按向量计算的函数。即
\[\begin{bmatrix} {\widehat y^{(1)}}\\ {\vdots}\\ {\widehat y^{(N)}} \end{bmatrix} = \begin{bmatrix} {\sigma(z^{(1)})}\\ {\vdots}\\ {\sigma(z^{(N)})} \end{bmatrix} =\sigma( \begin{bmatrix} {z^{(1)}}\\ {\vdots}\\ {z^{(N)}} \end{bmatrix})\]其中
\[z^{(i)} = \begin{bmatrix} {x_1^{(i)}}&{\cdots}&{x_8^{(i)}} \end{bmatrix} \begin{bmatrix} {w_1}\\ {\vdots}\\ {w_8} \end{bmatrix}+b\\\]则
\[\begin{bmatrix} {z^{(1)}}\\ {\vdots}\\ {z^{(N)}} \end{bmatrix} = \begin{bmatrix} {x_1^{(1)}} & {\cdots} & {x_8^{(1)}}\\ {\vdots} & {\vdots} & {\vdots}\\ {x_1^{(N)}} & {\cdots} & {x_8^{(N)}}\\ \end{bmatrix} \begin{bmatrix} {w_1}\\ {\vdots}\\ {w_8} \end{bmatrix} + \begin{bmatrix} {b}\\ {\vdots}\\ {b} \end{bmatrix}\]整体上将原先的标量运算,转换为矩阵运算,以方便进行并行计算,提高算法效率。
网络增加
矩阵实质上是一种空间变换的函数
按照原先的代码思路,只需要将Linear()中的参数改成下面代码,即可完成从8维输入到1位输出的过程。
self.linear = torch.nn.Linear(8,1)
同时,也可以将输出的部分转换为其他维度,来实现分布的维度下降,比如8维转6维,6维转4维,4维转1维,由此可以增加网络层数,增加网络复杂度。同理,对网络结构先增后减也是可以的。
理论上来说网络层数越多,网络越复杂,学习能力越强。但是太强会导致过拟合,需要找到一个泛化能力和拟合能力的平衡点。
所以,网络的层数和维度数需要超参数搜索。
代码部分
import torch
import numpy as np
#读取文件,一般GPU只支持32位浮点数
xy = np.loadtxt('diabetes.csv', delimiter=',', dtype = np.float32)
#-1行-1列不取
x_data = torch.from_numpy(xy[:-1, :-1])
#单取-1列作为矩阵
y_data = torch.from_numpy(xy[:-1, [-1]])
#取-1行的测试集部分
test_data = torch.from_numpy(xy[[-1], :-1])
pred_test = torch.from_numpy(xy[[-1],[-1]])
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
for epoch in range(1000):
#Forward 并非mini-batch的设计,只是mini-batch的风格
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print(epoch, loss.item())
#Backward
optimizer.zero_grad()
loss.backward()
#Update
optimizer.step()
print("test_pred = ", model(test_data).item())
print("infact_pred = ", pred_test.item())
本文参考自B站《PyTorch深度学习实践》P7