pytorch学习7-处理多维特征的输入


有一糖尿病数据集,在文件中,每个样本(sample)有8个维度的信息(feature),并以此进行二分类。

image-20210302173422666

原模型改进

前篇中,单维度逻辑回归模型为

\[\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())

微信截图_20220926103003

本文参考自B站《PyTorch深度学习实践》P7