来自 B 站刘二大人的《PyTorch深度学习实践》P7 的学习笔记
回顾
上一篇逻辑斯蒂回归中,分类的最终结果是输出概率对应的分类,是离散的集合,虽然神经网络预测的概率的分布拟合的是 Sigmoid,但这些概率是用于决策分类的,类别是离散的集合;
而线性回归的输出结果是实数集,它们拟合目标函数。
数据表示
对于关系型数据表,在 PyTorch 中读取时是以下面的方式表示的:
- 一行是一个 Sample(样本):
- 一列是一个 Feature(特征):
多维数据
需要转换成矩阵运算
-
Mini-Batch(N Samples) 得益于 PyTorch Tensor 的矩阵广播能力,我们可以很轻松地构建矩阵输入进行 Mini-Batch 运算: 由于输入的矩阵特征维度(列数)增加了,从上一章的
N
×
1
N \times 1
N×1 变成了
N
×
8
N \times 8
N×8 ,我们在模型 Linear 层中也需要更改相应参数: -
Linear Layer torch.nn.Linear(in_features, out_features) : 对输入数据应用线性变换:
y
=
x
?
A
T
+
b
y = x \cdot A^T+b
y=x?AT+b
- 输入维度:
(
N
,
?
,
H
i
n
)
(N, *, H_{in})
(N,?,Hin?)。
* 表示 sample 数(行数),
H
i
n
=
H_{in} =
Hin?= in_features - 输出维度:
(
N
,
?
,
H
o
u
t
)
(N, *, H_{out})
(N,?,Hout?)。除了最后一个维度外,其他所有维度都与输入的形状相同,
H
o
u
t
=
H_{out} =
Hout?= out_features
Examples: >>> m = nn.Linear(20,30)
>>> input = torch.randn(128,20)
>>> output = m(input)
>>> print(output.size())
torch.size([128,30])
对于以下矩阵,每一行是一个 sample,size of each sample 表示一行的大小,也即列数(Feature): 所以说神经网络可以做空间变换,
σ
(
?
)
\sigma(\cdot)
σ(?) 提供了非线性变换:
神经网络构造
多个非线性变换的链接可以拟合更复杂的函数,网络层的输出可降维也可升维,是升是降,这是超参数的哲学。 这里老师即兴穿插读书的哲学 🐶 : 三层 Linear Layer 构建的神经网络: 代码与计算图一一对应,一目了然
不同的激活函数的输出区间不同,由于我们最后要计算 log(x) ,x 不能为 0(ReLU 把小于 0 的都取为 0),所以要注意最后输出的仍然要经过 sigmoid() : 经过测试的完整代码如下:
import copy
import numpy as np
import torch
from torch import nn, optim
from torch.nn import functional as F
xy = np.loadtxt("../datasets/diabetes/diabetes.csv.gz", delimiter=",", dtype=np.float32)
x_data = torch.from_numpy(xy[:, :-1])
y_data = torch.from_numpy(xy[:, [-1]])
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = nn.Linear(8, 6)
self.linear2 = nn.Linear(6, 4)
self.linear3 = nn.Linear(4, 1)
self.activate = nn.Sigmoid()
def forward(self, x):
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = F.sigmoid((self.linear3(x)))
return x
model = Model()
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.03)
npz_dict = {"loss": [], "acc": []}
for epoch in range(1000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
y_pred_hat = copy.copy(y_pred.data.numpy())
y_pred_hat[y_pred_hat >= 0.5] = 1.0
y_pred_hat[y_pred_hat < 0.5] = 0.0
acc = np.sum(y_pred_hat.flatten() == y_data.data.numpy().flatten()) / len(y_data)
print("epoch:", epoch, "loss:", loss.item(), "acc:", acc)
npz_dict["loss"].append(loss.item())
npz_dict["acc"].append(acc)
optimizer.zero_grad()
loss.backward()
optimizer.step()
np.savez("./npz_file/sigmoid.npz", loss = npz_dict["loss"], acc = npz_dict["acc"])
注意我们虽然输入训练的是多维特征的数据,但是我们实际上还没有用 Mini-Batch 来训练,这部分详细内容在下一篇:PyTorch 加载数据集(Dataset、DataLoader)
读取 npz 文件得到数值后绘图结果如下: 读取文件的绘图函数如下:
import numpy as np
import matplotlib.pyplot as plt
def draw(name, title="acc"):
loss_acc = np.load(f"./npz_file/{name}.npz")
y = loss_acc[f"{title}"]
x = np.arange(len(y))
plt.plot(x, y, label=f"best:{max(y)}" if title == "acc" else None)
plt.title(title)
plt.xlabel("x")
plt.ylabel(name)
plt.legend()
plt.grid()
plt.show()
filename = ["sigmoid", "relu", "leakyrelu", "tanh", "softplus"]
draw(filename[0], title="acc")
|