处理多维特征的输入
具有多维特征的数据集
前面我们处理特征维数一直是一维特征,在本节中,我们将处理具有多维特征的数据集,并且对其进行预测分类
对于具有多维输入的数据集,每一行叫做一个样本Sample
,每一列叫做特征feature
当特征是多维(如上图是8维)时,逻辑回归模型的函数如下:
y^(i)=σ(∑n=18xn(i)ωn+b)
\hat y^{(i)} = \sigma(\sum_{n=1}^{8}x_n^{(i)}\omega _n + b)
y^(i)=σ(n=1∑8xn(i)ωn+b)
即:
y^(i)=σ([xi(i) … x8(i)][ω1⋮ω8]+b)=σ(z(i))
\hat y^{(i)} = \sigma(\begin{bmatrix} x_i^{(i)} \ \dots \ x_8^{(i)} \end{bmatrix}\begin{bmatrix}\omega _1 \\ \vdots \\ \omega _8 \end{bmatrix} + b) = \sigma (z^{(i)})
y^(i)=σ([xi(i) … x8(i)]ω1⋮ω8+b)=σ(z(i))
只需要在源代码中改变一下线性模型的定义即可
self.linear = torch.nn.Linear(8, 1)
使用多层神经网络进行分类任务
多层神经网络主要是利用了矩阵相乘,实现不断地降维或者升维,不断增加模型的复杂性,但必须要保证输入和输出的维度与数据集一致
矩阵 →\to→ 空间变换的函数
在多层神经网络里,每一层通过对线性模型增加非线性因子,即激活函数,实现非线性的变换
但同时,还不能过多的增加层数,因为层数越多,学习能力越强,可能会更多地学习到数据中的噪声,使模型不具有较强的泛化能力
对于每层的输出,一般是要进行超参数搜索,寻找最优的组合
在此次代码实践中,采用如下组合:
- 第一层实现8维向6维的非线性转换
- 第二层实现6维向4维的非线性转换
- 第三层实现4为向1维的非线性转换
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
使用多层神经网络对糖尿病数据集进行分类
三层神经网络全部采用Sigmoid
import torch
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
######### 数据集的准备 ##########
xy = np.array(pd.read_csv("./dataset/diabetes.csv"))
x_data = torch.Tensor(xy[:, :-1]) # 最后一列不要
y_data = torch.Tensor(xy[:, [-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() # 将sigmoid单独作为一层
# 因此要实例化
def forward(self, x):
## 注意书写习惯 要始终用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.01)
########## 模型训练 ###########
loss_history = []
epoch_history = []
for epoch in range(10000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
print(epoch, loss.item())
epoch_history.append(epoch)
loss_history.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
plt.plot(epoch_history, loss_history)
plt.xlabel('epoch')
plt.ylabel("loss")
plt.grid()
plt.show()
注意:
- 这里把
Sigmoid
单独作为了神经网络的一层,而不是简单的函数的使用 - 损失函数使用样本
BCE
损失的平均值,即criterion = torch.nn.BCELoss(reduction='mean')
最终每一步的损失如下所示:
前两层神经网络使用Relu
,最后一层使用Sigmoid
考虑到最后的平均损失为0.64+,不是特别理想,因此改变模型,增加模型的非线性程度
将前两层神经网络使用Relu
作为激活函数,最后一层使用Sigmoid
模型改变如下:
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() # 将sigmoid单独作为一层
# 因此要实例化
self.activate = torch.nn.ReLU() # 增加Relu激活函数
def forward(self, x):
## 注意书写习惯 要始终用x
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
整体代码:
import torch
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
######### 数据集的准备 ##########
xy = np.array(pd.read_csv("./dataset/diabetes.csv"))
x_data = torch.Tensor(xy[:, :-1]) # 最后一列不要
y_data = torch.Tensor(xy[:, [-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() # 将sigmoid单独作为一层
# 因此要实例化
self.activate = torch.nn.ReLU()
def forward(self, x):
## 注意书写习惯 要始终用x
x = self.activate(self.linear1(x))
x = self.activate(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.01)
########## 模型训练 ###########
loss_history = []
epoch_history = []
for epoch in range(10000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
print(epoch, loss.item())
epoch_history.append(epoch)
loss_history.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
plt.plot(epoch_history, loss_history)
plt.xlabel('epoch')
plt.ylabel("loss")
plt.grid()
plt.show()
最终损失收敛到0.475左右