文章目录
神经网络(理论)
深度学习模型 = 复杂的神经网络模型
- CNN 卷积神经网络
卷积神经网络*(Convolutional Neural Networks)是深度学习中非常常见的算法(模型),其在图像处理中应用广泛*,基于CNN的专利申请近些年也增长迅速。
- GNN 图神经网络
图(graph)是一种数据结构,常⻅的图结构包含节点(node)和边(edge),GNN是深度学习在图结构上的一个分支。
- RNN 循环神经网络
循环神经网络*(Recurrent Neural Network)是一类具有短期记忆能力的神经网络,因而常用于文本数据处理*。
- GAN 生成对抗网络
GAN属于人工智能领域:通过对某一事物大量数据的学习,来学习总结出其在数学层面上的分布规律,构建出合理的映射函数,从而解决现实问题,主要用于图片生成。
- Auto-Encoder 自编码器
Auto-Encoder,中文称作自编码器,是一种无监督式学习模型,它基于反向传播算法与最优化方法(如梯度下降法)。
- Transformer 变形金刚模型
Transformer是一个利用注意力机制来提高模型训练速度的模型。
神经网络的层级结构
神经网络*(Neural Network)是一种模仿生物神经系统的计算模型,用于解决分类、回归、生成等机器学习问题。神经网络的层级结构通常包括输入层、隐藏层和输出层,每一层都由若干个神经元(或称为节点)组成,其中每个节点又被成为感知机模型*。
- 输入层:为接收数据的网络第一层。
- 输出层:为输出数据的网络的最后一层。
- 隐藏层:每一个层数、节点都是一个超参数,可以任意手动调节。
神经网络对数据的特征提取
xi为输入数据,wi为权重,b为偏置,黄色节点进行处理,y为结果。
y
=
(
∑
i
=
1
n
x
i
×
w
i
)
+
b
y = (\sum_{i=1}^{n} x_{i}\times w_{i})+ b
y=(i=1∑nxi×wi)+b
神经网络的pytorch API
神经网络在pytorch中被封装为一个类torch.nn.Linear
,其中:
- in_features为输入数据数量
- out_features为输出数据数量
- bias为偏置,默认为随机初始数
- device为指定当前神经网络计算时环境
- dtype为指定计算所用的数据类型,推荐使用浮点型
神经网络的有监督训练
减小预测值Predication和真值之间的Distance
损失函数loss fuction,例如:
l
o
s
s
=
1
2
(
y
−
y
^
)
2
loss = \frac{1}{2} (y-\hat{y})^{2}
loss=21(y−y^)2
神经网络的梯度下降
梯度下降*(Gradient Descent GD)简单来说就是一种寻找目标函数最小化*的方法,它利用梯度信息,通过不断迭代调整参数来寻找合适的目标值。
θ
=
θ
′
−
l
r
⋅
g
\theta =\theta ^{'} - lr·g
θ=θ′−lr⋅g
其中 lr 为学习速率, g 为梯度*(即求导)*。
pytorch在深度学习中的作用
- 第一步Train Data :pytorch负责数据集的加载——
DataLoader
(自定义数据加载)。 - 第二步Model :使用pytorch中的
nn.model
类搭建神经网络模型。 - 第三步Prediction :比较预测结果和数据真值的距离。
- 第四步loss fuction :pytorch自带损失函数,例如
loss = nn.CrossEntropyLoss()
交叉熵损失。 - 第五步求导损失函数 :
loss.backward()
自动求导。 - 第六步梯度下降 :
optimizer.step()
自动下降。
神经网络(实践)
解决方案
-
自定义数据集加载,并将其划分为训练集和测试集。
-
nn.Module
构造神经网络模型,对于这个问题,可以使用一个简单的多层感知器*(MLP)*模型。在输出层,可以使用Softmax
激活函数将输出转换为概率分布。 -
模型训练
- 选择一个适当的损失函数,例如交叉嫡损失*(Cross-Entropy Loss)*,用于衡量模型预测与实际标签之间的差异。
- 选择一个优化算法,例如随机梯度下降_(SGD)_或**Adam **等,用于更新神经网络的权重以最小化损失函数。
- 设置训练参数.如批量大小*(Batch Size)、学习率(Learning Rate)和训练轮数(Epochs)*等。
- 使用训练集数据进行训练,不断更新神经网络权重以最小化损失。
-
模型评估
- 使用测试集数据对训练好的神经网络模型进行评估,计算分类准确率等指标。
- 如果性能不佳,可以尝试调整神经网络结构*(如增加隐藏层节点数)、优化算法(如调整学习率)或训练参数(如增加训练轮数)*等,以提高模型性能。
-
使用训练好的神经网络模型对新的鸢尾花数据进行分类预测。
数据集的加载
data_loader.py
from torch.utils.data import Dataset
import os
import pandas as pd
import numpy as np
import torch
class iris_dataloader(Dataset):
# 读取数据,要求一定要复现三个方法
def __init__(self, data_path):
# data_path为数据文件的路径
self.data_path = data_path
# 判断数据文件是否存在,不存在时报错
assert os.path.exists(self.data_path), 'dataset does not exits'
# 规定读取数据的0~4列,即全部列
df = pd.read_csv(self.data_path, name=[0, 1, 2, 3, 4])
# 替换花朵类型规则
d = {'Iris-Setosa': 0, 'Iris-Versicolor': 1, 'Iris-Virginical': 2}
df[4] = df[4].map(d)
# 读取数据与数据标签
data = df.iloc[:, :4]
label = df.iloc[:, 4:]
# 数据归一化,将数据映射至N~(0,1)的正态分布
data = (data - np.mean(data) / np.std(data))
# 将数据转化为numpy类型,再转为tensor类型
self.data = torch.from_numpy(np.array(data, dtype='float32'))
self.label = torch.from_numpy(np.array(label, dtype='int64'))
# 统计数据数量
self.data_num = len(label)
print('当前数据集的大小', self.data_num)
# 读取数据集的大小
def __len__(self):
return self.data_num
# 获取数据集中的单个样本
def __getitem__(self, index):
# 用列表(可迭代对象)封装数据
self.data = list(self.data)
self.label = list(self.label)
return self.data[index], self.label[index]
训练、验证和测试函数
iris.py
import os
import sys
# 导入批量数据封装
from torch.utils.data import DataLoader
# 终端进度条
from tqdm import tqdm
# 导入Torch类
import torch
# 导入神经网络功能类
import torch.nn as nn
# 导入神经网络优化器
import torch.optim as op
# 导入数据加载类
from data_loader import iris_dataloader
os.environ['CUDA_LAUNCH_BLOCKING'] = '1'
# 初始化神经网络模型
class NN(nn.Module):
def __init__(self, in_dim, hidden_dim1, hidden_dim2, out_dim):
super().__init__()
# 定义网络层级结构
self.layer1 = nn.Linear(in_dim, hidden_dim1)
self.layer2 = nn.Linear(hidden_dim1, hidden_dim2)
self.layer3 = nn.Linear(hidden_dim2, out_dim)
# 数据处理
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
# 返回结构
return x
# 定义网络计算环境
# device 如果有GPU则torch.cuda.is_available()返回cuda:0,否则返回cpu
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 训练集,验证集和测试集的划分
custom_dataset = iris_dataloader('./iris_training.csv')
# 划分各集的长度
# 训练集
train_size = int(len(custom_dataset) * 0.7)
# 验证集
val_size = int(len(custom_dataset) * 0.2)
# 测试集
test_size = int(len(custom_dataset) - train_size - val_size)
# 随机数据集切分
train_dataset, val_dataset, test_dataset = torch.utils.data.random_split(
custom_dataset, [train_size, val_size, test_size])
# 按批量封装加载数据,batch_size表示一次运算取出数据量,shuffle表示是否打散数据
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=1, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=1, shuffle=False)
print('训练集的大小', len(train_loader) * 16, '验证集的大小', len(val_loader), '测试集的大小', len(test_loader))
# 定义推理函数,返回准确率
def infer(model, dataset, device):
model.eval()
acc_num = 0
# 约束函数,不改变模型参数
with torch.no_grad():
for data in dataset:
datas, label = data
outputs = model(datas.to(device))
predict_y = torch.max(outputs, dim=1)[1]
# torch.max的返回值是一个元组,第一个值是max的值,第二个值是所对应的值的索引,所以只需要取第二个索引
acc_num += torch.eq(predict_y, label.to(device)).sum().item()
acc = acc_num / len(dataset)
return acc
# 定义训练,验证,测试的过程
def main(lr=0.005, epochs=20):
model = NN(4, 12, 6, 3).to(device)
# 定义损失函数
loss_f = nn.CrossEntropyLoss()
# 定义模型参数
pg = [p for p in model.parameters() if p.requires_grad]
# 定义优化器
optimizer = op.Adam(pg, lr=lr)
# 权重文件存储路径
save_path = os.path.join(os.getcwd(), 'pytorchProject/weights')
# 判断路径是否正确,若不存在,重新创建路径
if os.path.exists(save_path) is False:
os.makedirs(save_path)
# 开始训练
for epoch in range(epochs):
model.train()
# 预测正确的样本数量
acc_num = torch.zeros(1).to(device)
sample_num = 0
# 取得数据集, 使用tqdm封装, 并循环训练
train_bar = tqdm(train_loader, file=sys.stdout, ncols=100)
for datas in train_bar:
data, label = datas
label = label.squeeze(-1)
# 样本数累加
sample_num += data.shape[0]
# 优化器梯度清零
optimizer.zero_grad()
outputs = model(data.to(device))
pred_class = torch.max(outputs, dim=1)[1]
acc_num = torch.eq(pred_class, label.to(device)).sum()
# 计算损失
loss = loss_f(outputs, label.to(device))
print(loss)
# 损失求导
loss.backward()
print(loss)
# 优化器更新
optimizer.step()
# 打印训练指标到进度条
train_acc = acc_num / sample_num
train_bar.desc = 'train epoch[{}/{}] loss:{:.3f} train_acc{:.3f}'.format(epoch + 1, epochs, loss, train_acc)
# 验证
val_acc = infer(model, val_loader, device)
print('train epoch[{}/{}] loss:{:.3f} val_acc{:.3f}'.format(epoch + 1, epochs, loss, val_acc))
# 保存模型
torch.save(model.state_dict(), os.path.join(save_path, 'NN.pth'))
# 初始化指标清零
train_acc = 0.
val_acc = 0.
print('Fished Traning')
# 测试
test_acc = infer(model, test_loader, device)
print('test_acc:', test_acc)
if __name__ == '__main__':
main()
错误调试与记录
1、输出台输出的中文显示为乱码
-
问题描述:VS Code编译python语言出现中文乱码,而运行其他编程语言,例如C语言、JAVA语言等,则不会出现类似的问题。
-
问题解决:在电脑的环境变量中,添加一条环境变量,环境变量名为 PYTHONIOENCODING ,变量值为 UTF-8 。
2、RuntimeError: CUDA error: device-side assert triggered
- 问题描述:
iris.py
在运行时会偶尔出现device-side assert triggered的错误,并且即使成功运行时,最后所得到的测试准确率test_acc
依然较低。
- 问题解决:每次都在同样的地方出错的程序,问题不一定出在程序上。检查数据集
iris_training.csv
,数据集第一行包含数据名,影响了数据加载,非数字数据使得在计算指标的时候给进去的数据超出了边界。
- 删去此行即可。
3、报错显示的位置不准确
-
问题描述:GPU会给出报错,但是有时报错的位置不准确,特别是运行时错误。
-
问题解决:在
import os
下添加os.environ['CUDA_LAUNCH_BLOCKING'] = '1'
。
鸢尾花的数据集,我的文件名称为iris_training.csv
,如果需要数据文件,我把它贴在文章后面,请勿用作商用,不想抄要源文件的可以私聊我,让我看看谁是小懒鬼
Sepal Length | Sepal Width | Petal Length | Petal Width | Flower species |
---|---|---|---|---|
6.4 | 2.8 | 5.6 | 2.2 | Iris-Virginical |
5.0 | 2.3 | 3.3 | 1.0 | Iris-Versicolor |
4.9 | 2.5 | 4.5 | 1.7 | Iris-Virginical |
4.9 | 3.1 | 1.5 | 0.1 | Iris-Setosa |
5.7 | 3.8 | 1.7 | 0.3 | Iris-Setosa |
4.4 | 3.2 | 1.3 | 0.2 | Iris-Setosa |
5.4 | 3.4 | 1.5 | 0.4 | Iris-Setosa |
6.9 | 3.1 | 5.1 | 2.3 | Iris-Virginical |
6.7 | 3.1 | 4.4 | 1.4 | Iris-Versicolor |
5.1 | 3.7 | 1.5 | 0.4 | Iris-Setosa |
5.2 | 2.7 | 3.9 | 1.4 | Iris-Versicolor |
6.9 | 3.1 | 4.9 | 1.5 | Iris-Versicolor |
5.8 | 4.0 | 1.2 | 0.2 | Iris-Setosa |
5.4 | 3.9 | 1.7 | 0.4 | Iris-Setosa |
7.7 | 3.8 | 6.7 | 2.2 | Iris-Virginical |
6.3 | 3.3 | 4.7 | 1.6 | Iris-Versicolor |
6.8 | 3.2 | 5.9 | 2.3 | Iris-Virginical |
7.6 | 3.0 | 6.6 | 2.1 | Iris-Virginical |
6.4 | 3.2 | 5.3 | 2.3 | Iris-Virginical |
5.7 | 4.4 | 1.5 | 0.4 | Iris-Setosa |
6.7 | 3.3 | 5.7 | 2.1 | Iris-Virginical |
6.4 | 2.8 | 5.6 | 2.1 | Iris-Virginical |
5.4 | 3.9 | 1.3 | 0.4 | Iris-Setosa |
6.1 | 2.6 | 5.6 | 1.4 | Iris-Virginical |
7.2 | 3.0 | 5.8 | 1.6 | Iris-Virginical |
5.2 | 3.5 | 1.5 | 0.2 | Iris-Setosa |
5.8 | 2.6 | 4.0 | 1.2 | Iris-Versicolor |
5.9 | 3.0 | 5.1 | 1.8 | Iris-Virginical |
5.4 | 3.0 | 4.5 | 1.5 | Iris-Versicolor |
6.7 | 3.0 | 5.0 | 1.7 | Iris-Versicolor |
6.3 | 2.3 | 4.4 | 1.3 | Iris-Versicolor |
5.1 | 2.5 | 3.0 | 1.1 | Iris-Versicolor |
6.4 | 3.2 | 4.5 | 1.5 | Iris-Versicolor |
6.8 | 3.0 | 5.5 | 2.1 | Iris-Virginical |
6.2 | 2.8 | 4.8 | 1.8 | Iris-Virginical |
6.9 | 3.2 | 5.7 | 2.3 | Iris-Virginical |
6.5 | 3.2 | 5.1 | 2.0 | Iris-Virginical |
5.8 | 2.8 | 5.1 | 2.4 | Iris-Virginical |
5.1 | 3.8 | 1.5 | 0.3 | Iris-Setosa |
4.8 | 3.0 | 1.4 | 0.3 | Iris-Setosa |
7.9 | 3.8 | 6.4 | 2.0 | Iris-Virginical |
5.8 | 2.7 | 5.1 | 1.9 | Iris-Virginical |
6.7 | 3.0 | 5.2 | 2.3 | Iris-Virginical |
5.1 | 3.8 | 1.9 | 0.4 | Iris-Setosa |
4.7 | 3.2 | 1.6 | 0.2 | Iris-Setosa |
6.0 | 2.2 | 5.0 | 1.5 | Iris-Virginical |
4.8 | 3.4 | 1.6 | 0.2 | Iris-Setosa |
7.7 | 2.6 | 6.9 | 2.3 | Iris-Virginical |
4.6 | 3.6 | 1.0 | 0.2 | Iris-Setosa |
7.2 | 3.2 | 6.0 | 1.8 | Iris-Virginical |
5.0 | 3.3 | 1.4 | 0.2 | Iris-Setosa |
6.6 | 3.0 | 4.4 | 1.4 | Iris-Versicolor |
6.1 | 2.8 | 4.0 | 1.3 | Iris-Versicolor |
5.0 | 3.2 | 1.2 | 0.2 | Iris-Setosa |
7.0 | 3.2 | 4.7 | 1.4 | Iris-Versicolor |
6.0 | 3.0 | 4.8 | 1.8 | Iris-Virginical |
7.4 | 2.8 | 6.1 | 1.9 | Iris-Virginical |
5.8 | 2.7 | 5.1 | 1.9 | Iris-Virginical |
6.2 | 3.4 | 5.4 | 2.3 | Iris-Virginical |
5.0 | 2.0 | 3.5 | 1.0 | Iris-Versicolor |
5.6 | 2.5 | 3.9 | 1.1 | Iris-Versicolor |
6.7 | 3.1 | 5.6 | 2.4 | Iris-Virginical |
6.3 | 2.5 | 5.0 | 1.9 | Iris-Virginical |
6.4 | 3.1 | 5.5 | 1.8 | Iris-Virginical |
6.2 | 2.2 | 4.5 | 1.5 | Iris-Versicolor |
7.3 | 2.9 | 6.3 | 1.8 | Iris-Virginical |
4.4 | 3.0 | 1.3 | 0.2 | Iris-Setosa |
7.2 | 3.6 | 6.1 | 2.5 | Iris-Virginical |
6.5 | 3.0 | 5.5 | 1.8 | Iris-Virginical |
5.0 | 3.4 | 1.5 | 0.2 | Iris-Setosa |
4.7 | 3.2 | 1.3 | 0.2 | Iris-Setosa |
6.6 | 2.9 | 4.6 | 1.3 | Iris-Versicolor |
5.5 | 3.5 | 1.3 | 0.2 | Iris-Setosa |
7.7 | 3.0 | 6.1 | 2.3 | Iris-Virginical |
6.1 | 3.0 | 4.9 | 1.8 | Iris-Virginical |
4.9 | 3.1 | 1.5 | 0.1 | Iris-Setosa |
5.5 | 2.4 | 3.8 | 1.1 | Iris-Versicolor |
5.7 | 2.9 | 4.2 | 1.3 | Iris-Versicolor |
6.0 | 2.9 | 4.5 | 1.5 | Iris-Versicolor |
6.4 | 2.7 | 5.3 | 1.9 | Iris-Virginical |
5.4 | 3.7 | 1.5 | 0.2 | Iris-Setosa |
6.1 | 2.9 | 4.7 | 1.4 | Iris-Versicolor |
6.5 | 2.8 | 4.6 | 1.5 | Iris-Versicolor |
5.6 | 2.7 | 4.2 | 1.3 | Iris-Versicolor |
6.3 | 3.4 | 5.6 | 2.4 | Iris-Virginical |
4.9 | 3.1 | 1.5 | 0.1 | Iris-Setosa |
6.8 | 2.8 | 4.8 | 1.4 | Iris-Versicolor |
5.7 | 2.8 | 4.5 | 1.3 | Iris-Versicolor |
6.0 | 2.7 | 5.1 | 1.6 | Iris-Versicolor |
5.0 | 3.5 | 1.3 | 0.3 | Iris-Setosa |
6.5 | 3.0 | 5.2 | 2.0 | Iris-Virginical |
6.1 | 2.8 | 4.7 | 1.2 | Iris-Versicolor |
5.1 | 3.5 | 1.4 | 0.3 | Iris-Setosa |
4.6 | 3.1 | 1.5 | 0.2 | Iris-Setosa |
6.5 | 3.0 | 5.8 | 2.2 | Iris-Virginical |
4.6 | 3.4 | 1.4 | 0.3 | Iris-Setosa |
4.6 | 3.2 | 1.4 | 0.2 | Iris-Setosa |
7.7 | 2.8 | 6.7 | 2.0 | Iris-Virginical |
5.9 | 3.2 | 4.8 | 1.8 | Iris-Versicolor |
5.1 | 3.8 | 1.6 | 0.2 | Iris-Setosa |
4.9 | 3.0 | 1.4 | 0.2 | Iris-Setosa |
4.9 | 2.4 | 3.3 | 1.0 | Iris-Versicolor |
4.5 | 2.3 | 1.3 | 0.3 | Iris-Setosa |
5.8 | 2.7 | 4.1 | 1.0 | Iris-Versicolor |
5.0 | 3.4 | 1.6 | 0.4 | Iris-Setosa |
5.2 | 3.4 | 1.4 | 0.2 | Iris-Setosa |
5.3 | 3.7 | 1.5 | 0.2 | Iris-Setosa |
5.0 | 3.6 | 1.4 | 0.2 | Iris-Setosa |
5.6 | 2.9 | 3.6 | 1.3 | Iris-Versicolor |
4.8 | 3.1 | 1.6 | 0.2 | Iris-Setosa |
6.3 | 2.7 | 4.9 | 1.8 | Iris-Virginical |
5.7 | 2.8 | 4.1 | 1.3 | Iris-Versicolor |
5.0 | 3.0 | 1.6 | 0.2 | Iris-Setosa |
6.3 | 3.3 | 6.0 | 2.5 | Iris-Virginical |
5.0 | 3.5 | 1.6 | 0.6 | Iris-Setosa |
5.5 | 2.6 | 4.4 | 1.2 | Iris-Versicolor |
5.7 | 3.0 | 4.2 | 1.2 | Iris-Versicolor |
4.4 | 2.9 | 1.4 | 0.2 | Iris-Setosa |
4.8 | 3.0 | 1.4 | 0.1 | Iris-Setosa |
5.5 | 2.4 | 3.7 | 1.0 | Iris-Versicolor |