「深度学习一遍过」必修2:解读简化版模型代码
Posted 荣仔!最靓的仔!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「深度学习一遍过」必修2:解读简化版模型代码相关的知识,希望对你有一定的参考价值。
本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。
专栏地址:「深度学习一遍过」必修篇
目 录
1 总观整体代码
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda, Compose
# 加载数据集
training_data = datasets.FashionMNIST(
root='data',
train=True,
download=True,
transform=ToTensor(),
)
test_data = datasets.FashionMNIST(
root='data',
train=False,
download=True,
transform=ToTensor(),
)
# 定义数据加载器
batch_size = 64
training_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
for X, y in test_dataloader:
print("shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
device = "cuda" if torch.cuda.is_available() else 'cpu'
print("Using {} device".format(device))
# 创建模型
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28 * 28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.ReLU()
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)
print(model)
# 选择优化函数
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
pred = model(X)
loss = loss_fn(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss:{loss:>7f} [{current:>5d}/{size:>5d}]")
# 定义测试函数
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, corrent = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
corrent += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
corrent /= size
print(f"Test Error: \\n Accuracy: {(100 * corrent):>0.1f}%, Avg loss:{test_loss:>8f}\\n")
# 开始训练
epoch = 50
for t in range(epoch):
print(f"Epoch {t + 1}\\n----------------------")
train(training_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")
# 保存模型参数
torch.save(model.state_dict(), "model.pth")
print("Save PyTorch Model State to model.pth")
# 加载模型
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))
# 获取预测结果
classes = [
"T-shirt/top",
"Trouser",
"Pollover",
"Dress",
"coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]
model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "actual"')
2 代码细致解读
2.1 训练
2.1.1 导入库
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda, Compose
① from torch import nn : 神经网络模块相关包 。
② from torch.utils.data import DataLoader : 实现一个数据加载器 。
2.1.2 加载数据集
training_data = datasets.FashionMNIST(
root='data',
train=True,
download=True,
transform=ToTensor(),
)
test_data = datasets.FashionMNIST(
root='data',
train=False,
download=True,
transform=ToTensor(),
)
① 加载 datasets 中的 FashionMNIST 数据集。
② root = 'data' :保存到 data 文件夹中;
③ train = True :设定为训练集 ;
train = False :设定为测试集 ;
④ download = True :为 True 时若本地没有该数据集就从官网进行下载(源码中指定了官方下载路径,见下图)
⑤ transform = ToTensor() :此代码作用是对数据进行转换,直接把数据变为输入,相当于是进行了数据预处理;其他数据预处理常用的还有:resize()、尺度变换、随即翻转等。
2.1.3 定义数据加载器
batch_size = 64
training_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
for X, y in test_dataloader:
print("shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
① batch_size = 64:用于设置一次传入的数据数量;
② training_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
用于给训练集、测试集分别创建一个数据集加载器;
③ for X, y in test_dataloader:
print("shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
用于查看 dataloader 读取情况;
X.shape 表示多个维度的图片,其中 N:代表传入64张图片
C:代表通道数(灰度图通道数为1)
H:图片的长
W:图片的宽
y 是指标签。
2.1.4 创建模型
device = "cuda" if torch.cuda.is_available() else 'cpu'
print("Using {} device".format(device))
上面这段代码表示:如果显卡可用,则用显卡进行训练。
# 创建模型
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28 * 28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.ReLU()
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)
print(model)
① self.flatten = nn.Flatten() :作用是碾平,将数据碾平为一维。
② self.linear_relu_stack = nn.Sequential(
nn.Linear(28 * 28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.ReLU()
)
用于定义 linear_relu_stack,由多层神经网络构成;
Sequential 意为其下定义的多层操作一个接一个按顺序进行,把它们前后全部拼接在一起。
③ nn.Linear 是全连接层
28 * 28 :表示输入维度数量
512 :表示目前维度数/下一层输出数量
③ nn.ReLU() :表示 ReLU 非线性激活函数
④ def forward(self, x) :其中 x 为输入数据,forward 定义前向传播函数。
⑤ model = NeuralNetwork().to(device) :调用刚定义的模型,如果 cuda 可用将模型转到 GPU。
2.1.5 选择优化函数
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
① loss_fn = nn.CrossEntropyLoss():用于定义损失函数,计算实际输出和真实相差多少。本句代码具体用到的是交叉熵损失函数,事实上,它就是做图片分类任务时常用的损失函数。
② optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) :作用是定义优化器,用来训练时候优化模型参数;其中,SGD表示随机梯度下降,用于控制实际输出y与真实y之间的相差有多大
③ lr=1e-3 :代表初始学习率。
2.1.6 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
pred = model(X)
loss = loss_fn(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss:{loss:>7f} [{current:>5d}/{size:>5d}]")
① 此处定义训练函数,把数据加载器、模型、损失,优化器等传到网络中去;
② size = len(dataloader.dataset) :用于查看 dataloader 有多少张图片;
③ for batch, (X, y) in enumerate(dataloader) :用于从数据加载器中读取 banch(一次读取多少张,即批次数),X(图片数据),y(图片真实标签);
④ X, y = X.to(device), y.to(device) :用于将数据存到显卡;
⑤ pred = model(X) :用于得到预测的结果 pred;
⑥ loss = loss_fn(pred, y) :用于计算预测的误差;
⑦ optimizer.zero_grad() :优化器工作之前先将梯度置0,进行归零操作;
⑧ loss.backward() :用相差多少这样一个损失值来对模型进行参数更新(反向传播,更新模型参数);
⑨ optimizer.step() :更新优化其中的参数;
⑩ if batch % 100 == 0 :每训练100次,输出一次当前信息
注:loss 值越低越好,预测值与真实值越来越靠近,这说明模型设计成功!
2.1.7 定义测试函数
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, corrent = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
corrent += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
corrent /= size
print(f"Test Error: \\n Accuracy: {(100 * corrent):>0.1f}%, Avg loss:{test_loss:>8f}\\n")
① model.eval() :将模型转换为验证模式;
② test_loss, corrent = 0, 0 :初始化 test_loss、corrent 用来统计每次的误差;
③ with torch.no_grad() :测试时模型参数不用更新,所以 no_grad,整个模型参数正向推就ok,不反向更新参数;
④ for X, y in dataloader :加载数据加载器,得到里面的 X(图片数据)和 y(真实标签);
④ X, y = X.to(device), y.to(device) :将数据转换为 GPU;
⑤ pred = model(X) :将图片传图到模型中就得到预测的 pred;
⑥ test_loss += loss_fn(pred, y).item() :计算预测值pred和真实值y的差距;
⑦ corrent += (pred.argmax(1) == y).type(torch.float).sum().item() :统计预测正确的个数。
2.1.8 开始训练
epoch = 50
for t in range(epoch):
print(f"Epoch {t + 1}\\n----------------------")
train(training_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")
2.2 保存
2.2.1 保存模型参数
torch.save(model.state_dict(), "model.pth")
print("Save PyTorch Model State to model.pth")
2.3 测试
2.3.1 加载模型
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))
① model = NeuralNetwork() :得到前面定义的模型框架
② model.load_state_dict(torch.load("model.pth")) :框架本身加载模型里的参数
注:此处要做到前后呼应,即先 torch.load 读取模型 pth,
再用 load_state_dict 读取到里面所有参数
2.3.2 获取预测结果
classes = [
"T-shirt/top",
"Trouser",
"Pollover",
"Dress",
"coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]
classes 用于定义整个标签类。
本身标签中有什么,模型并不知道,只是简化标签为 0、1、2、. . . ,之后再将 0、1、2、. . . 对应标签的名字。
model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "actual"')
① model.eval() :进入验证阶段,不会梯度更新,只会向前推;
② predicted, actual = classes[pred[0].argmax(0)], classes[y] :得到预测类别中最高的那一类,再把最高的这一类对应 classes 中的哪一个标签。
③ print(f'Predicted: "{predicted}", Actual: "actual"') :最终输出预测值与真实值。
3 结果运行展示
3.1 模型结构
3.2 训练轮次、Loss与Accuracy情况
3.3 预测结果
欢迎大家交流评论,一起学习
希望本文能帮助您解决您在这方面遇到的问题
感谢阅读
END
版权声明:本文为CSDN博主「荣仔!最靓的仔!」的原创文章,遵循 CC 4.0 BY-SA 版权协议。
转载请在醒目位置附上原文出处链接及本声明。
以上是关于「深度学习一遍过」必修2:解读简化版模型代码的主要内容,如果未能解决你的问题,请参考以下文章
「深度学习一遍过」必修18:基于pytorch的语义分割模型实现