1.输入特征与输出特征几个代表有几个神经元
2.输入层没有内部参数(第0层)。内部参数:权重w,偏置b。外部参数:网络层数,每个隐藏层的节点数,每个激活函数的类型,学习率(超参数)
3.batch——size(一般设置为2的幂次)
批量梯度下降(BGD):把所有样本一次性输入网络
随机梯度下降(SGD):每次只把一个样本输入网络,每计算一个样本就更新参数(敛散性差,可能在最优点附近震荡)
小批量梯度下降(MBGD):中和上述两种
独热编码:独热编码(One-Hot)最简洁理解-CSDN博客
DNN的实现
#jupyter notebook
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
%matplotlib inline
# 展示高清图
from matplotlib_inline import backend_inline
backend_inline.set_matplotlib_formats('svg')
'''在训练之前,要准备好训练集的样本。
这里生成 10000 个样本,设定 3 个输入特征与 3 个输出特征,其中
⚫ 每个输入特征相互独立,均服从均匀分布;
⚫ 当(X1+X2+X3)< 1 时,Y1 为 1,否则 Y1 为 0;
⚫ 当 1<(X1+X2+X3)<2 时,Y2 为 1,否则 Y2 为 0;
⚫ 当(X1+X2+X3)>2 时,Y3 为 1,否则 Y3 为 0;
⚫ .float()将布尔型张量转化为浮点型张量。'''
# 生成数据集
X1 = torch.rand(10000,1) # 输入特征 1
X2 = torch.rand(10000,1) # 输入特征 2
X3 = torch.rand(10000,1) # 输入特征 3
Y1 = ( (X1+X2+X3)<1 ).float() # 输出特征 1
Y2 = ( (1<(X1+X2+X3)) & ((X1+X2+X3)<2) ).float() # 输出特征 2
Y3 = ( (X1+X2+X3)>2 ).float() # 输出特征 3
Data = torch.cat([X1,X2,X3,Y1,Y2,Y3],axis=1) # 整合数据集
Data = Data.to('cuda:0') # 把数据集搬到 GPU 上
Data.shape
# 划分训练集与测试集
train_size = int(len(Data) * 0.7) # 训练集的样本数量
test_size = len(Data) - train_size # 测试集的样本数量
Data = Data[torch.randperm( Data.size(0)) , : ] # 打乱样本的顺序
train_Data = Data[ : train_size , : ] # 训练集样本
test_Data = Data[ train_size : , : ] # 测试集样本
train_Data.shape, test_Data.shape
class DNN(nn.Module):
def __init__(self):
''' 搭建神经网络各层 '''
super(DNN,self).__init__()
self.net = nn.Sequential( # 按顺序搭建各层
nn.Linear(3, 5), nn.ReLU(), # 第 1 层:全连接层
nn.Linear(5, 5), nn.ReLU(), # 第 2 层:全连接层
nn.Linear(5, 5), nn.ReLU(), # 第 3 层:全连接层
nn.Linear(5, 3) # 第 4 层:全连接层
)
def forward(self, x):
''' 前向传播 '''
y = self.net(x) # x 即输入数据
return y # y 即输出数据
model = DNN().to('cuda:0') # 创建子类的实例,并搬到 GPU 上
model # 查看该实例的各层
网络的外部参数
外部参数即超参数,这是调参师们关注的重点。搭建网络时的超参数有:网
络的层数、各隐藏层节点数、各节点激活函数、内部参数的初始值等。训练网络
的超参数有:如损失函数、学习率、优化算法、batch_size、epochs 等。
(1)激活函数
PyTorch 1.12.0 版本进入 https://pytorch.org/docs/1.12/nn.html 搜索 Non-linear
Activations,即可查看 torch 内置的所有非线性激活函数(以及各种类型的层)。
(2)损失函数
进入 https://pytorch.org/docs/1.12/nn.html 搜索 Loss Functions,即可查看 torch
内置的所有损失函数。
(3)学习率与优化算法
进入 https://pytorch.org/docs/1.12/optim.html,可查看 torch 的所有优化算法。
learning_rate = 0.01 # 设置学习率
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
注:PyTorch 实现时只支持 BGD 或 MBGD,不支持单个样本的输入方式。
这里的 torch.optim.SGD 只表示梯度下降,具体的批量与小批量见第四、五章。
训练网络
# 训练网络
epochs = 1000
losses = [] # 记录损失函数变化的列表
# 给训练集划分输入与输出
X = train_Data[ : , :3 ] # 前 3 列为输入特征
Y = train_Data[ : , -3: ] # 后 3 列为输出特征
for epoch in range(epochs):
Pred = model(X) # 一次前向传播(批量)
loss = loss_fn(Pred, Y) # 计算损失函数
losses.append(loss.item()) # 记录损失函数的变化,loss.item将张量退化为普通元素
optimizer.zero_grad() # 清理上一轮滞留的梯度
loss.backward() # 一次反向传播
optimizer.step() # 优化内部参数
Fig = plt.figure()
plt.plot(range(epochs), losses)
plt.ylabel('loss'), plt.xlabel('epoch')
plt.show()
测试网络
测试时,只需让测试集进行 1 次前向传播即可,这个过程不需要计算梯度,
因此可以在该局部关闭梯度,该操作使用 with torch.no_grad():命令。
考虑到输出特征是独热编码,而预测的数据一般都是接近 0 或 1 的小数,为
了能让预测数据与真实数据之间进行比较,因此要对预测数据进行规整。例如,
使用 Pred[:,torch.argmax(Pred, axis=1)] = 1 命令将每行最大的数置 1,接着再使用
Pred[Pred!=1] = 0 将不是 1 的数字置 0,这就使预测数据与真实数据的格式相同。
# 测试网络
# 给测试集划分输入与输出
X = test_Data[:, :3] # 前 3 列为输入特征
Y = test_Data[:, -3:] # 后 3 列为输出特征
with torch.no_grad(): # 该局部关闭梯度计算功能
Pred = model(X) # 一次前向传播(批量)
Pred[:,torch.argmax(Pred, axis=1)] = 1
Pred[Pred!=1] = 0
correct = torch.sum( (Pred == Y).all(1) ) # 预测正确的样本
total = Y.size(0) # 全部的样本数量
print(f'测试集精准度: {100*correct/total} %')
在计算 correct 时需要动点脑筋。
首先,(Pred == Y)计算预测的输出与真实的输出的各个元素是否相等,返回
一个 3000 行、3 列的布尔型张量。
其次,(Pred == Y).all(1)检验该布尔型张量每一行的 3 个数据是否都是 True,
对于全是 True 的样本行,结果就是 True,否则是 False。all(1)中的 1 表示按“行”
扫描,最终返回一个形状为 3000 的一阶张量。
最后,torch.sum( (Pred == Y).all(1) )的意思就是看这 3000 个向量相加,True
会被当作 1,False 会被当作 0,这样相加刚好就是预测正确的样本数。
保存网络:torch.save(model, 'model.pth')
导入网络:# 把模型赋给新网络
new_model = torch.load('model.pth')