PyTorch入门------训练图像分类器
前言
1. 操作步骤
2. 数据集
一、公共部分
1.加载并归一化 CIFAR10
2.定义卷积神经网络
二、训练、保存模型参数部分 train_and_save.py
3.定义损失函数和优化器
4.训练网络(使用 CPU 或者 GPU)
5.保存训练好的模型参数
三、加载模型参数、模型推理部分 load_and_infer.py
6.加载模型参数
7.在测试数据集上使用加载的模型进行推理
四、代码及运行结果
1.train_and_save.py
1.1 代码
1.2运行结果
CPU
GPU
2.load_and_infer.py
2.1 代码
2.2 运行结果
前言
参考:训练分类器 — PyTorch 教程 2.7.0+cu126 文档 - PyTorch 深度学习库
1. 操作步骤
我们将按顺序执行以下步骤训练图像分类器
-
使用
torchvision
加载并归一化 CIFAR10 训练和测试数据集 -
定义卷积神经网络
-
定义损失函数
-
在训练数据上训练网络
-
保持训练好的模型参数
-
加载模型参数
-
在测试数据上测试网络
2. 数据集
使用 CIFAR10 数据集。它具有以下类别:“airplane”、“automobile”、“bird”、“cat”、“deer”、“dog”、“frog”、“horse”、“ship”、“truck”。CIFAR-10 中的图像大小为 3x32x32,即 3 通道彩色图像,大小为 32x32 像素。
一、公共部分
1.加载并归一化 CIFAR10
#----- 1.加载并归一化 CIFAR10 -----#
import torch
import torchvision
import torchvision.transforms as transforms# transforms.Compose(): 组合变换操作的容器, 允许将多个图像转换操作按顺序执行
transform = transforms.Compose(# 将范围在 [0, 255] 的 PIL Image 或 numpy.ndarray (H x W x C) 转换为形状为 (C x H x W)、范围在 [0.0, 1.0] 的 torch.FloatTensor[transforms.ToTensor(), # 使用均值和标准差归一化张量图像,将每个通道的值标准化为 [-1, 1] 区间。 output[channel] = (input[channel] - mean[channel]) / std[channel] = 2x - 1transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)# 设置批量大小
batch_size = 4# 加载CIFAR-10训练数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
# 创建训练数据的DataLoader,按批次加载数据并进行随机打乱
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,shuffle=True, num_workers=2)# 加载CIFAR-10测试数据集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
# 创建测试数据的DataLoader,按批次加载数据但不打乱
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,shuffle=False, num_workers=2)# CIFAR-10数据集的分类标签,包含10类
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')# 输出训练集和测试集的大小
train_size = len(trainset)
test_size = len(testset)
print(f'Training set size: {train_size}') # 50000
print(f'Test set size: {test_size}') # 10000# 展示训练集图像
import matplotlib.pyplot as plt
import numpy as npdef imshow(img, title=None):"""显示图像,并且可以选择性地显示标题。参数:img (Tensor): 要显示的图像。通常是经过预处理后的Tensor图像, 形状为 (C, H, W)。title (str, optional): 要显示的标题。如果提供了标题,则在图像上方显示它。"""img = img / 2 + 0.5 # unnormalize,反标准化,将图像的像素值从[-1, 1]映射回[0, 1]npimg = img.numpy() # 将PyTorch tensor转换为NumPy数组plt.imshow(np.transpose(npimg, (1, 2, 0))) # 将tensor的维度从 (C, H, W) 转换为 (H, W, C) 以便绘制# 如果提供了标题,就显示标题if title:plt.title(title)plt.show()# 从训练数据加载器中获取一个批次的数据 (随机的)
print("----------随机展示训练集图像----------")
dataiter = iter(trainloader) # 创建数据加载器的迭代器
images, labels = next(dataiter) # 获取一批数据,其中images是图像数据,labels是对应的标签# 创建标题,显示标签名称。5s 表示字符串的宽度为 5,不足的部分会使用空格填充
title = ' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)) # join() 方法将生成的类别名称列表(每个类别名称都经过格式化)用空格连接成一个单一的字符串。# 显示图像并且显示标题
imshow(torchvision.utils.make_grid(images), title=title) # 使用make_grid将图像组合成一个网格并显示
2.定义卷积神经网络
#----- 2.定义卷积神经网络 -----#
import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = torch.flatten(x, 1) # torch.flatten(input, start_dim=0, end_dim=-1) :将输入张量从 start_dim 到 end_dim 维度展平为一个维度。x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xnet = Net()
print("----------模型结构----------")
print(net)
二、训练、保存模型参数部分 train_and_save.py
3.定义损失函数和优化器
#----- 3.定义损失函数和优化器 -----#
import torch.optim as optim'''CrossEntropyLoss 通常用于分类问题,计算目标类别与模型预测类别之间的误差。交叉熵(Cross-Entropy)本质上是两个概率分布之间的差异度量,常用于比较:一个真实分布P(通常是 one-hot 编码)一个预测分布Q(通常是 softmax 输出)它的数学定义如下:CCrossEntropy(P,Q)=- ∑ [ Pi*log(Qi) ]i=1其中:C 是类别总数Pi是真实标签中第 i 类的概率(一般为 1 或 0)Qi是模型预测中第 i 类的概率(softmax 输出)交叉熵损失只对正确类别的预测概率进行惩罚,其它类别不参与损失。'''
# 定义损失函数(这里使用的是分类交叉熵损失函数(CrossEntropyLoss))
criterion = nn.CrossEntropyLoss()'''optim.SGD 是 PyTorch 提供的随机梯度下降(SGD)优化器。参数解释:net.parameters():模型参数,即网络中的所有可训练参数。lr=0.001: 学习率,控制每次参数更新的步长。较小的学习率有助于防止过拟合,但可能导致训练变慢。momentum=0.9: 动量项,用来加速收敛,并帮助跳出局部最小值。动量类似于物理中的惯性,它使用上一次的梯度来调整当前的梯度。
'''
# 定义优化器(这里使用的是带动量的随机梯度下降(SGD with momentum))
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
4.训练网络(使用 CPU 或者 GPU)
#----- 4.训练网络(使用 CPU 或者 GPU) -----#
import time
use_gpu = False # 改成 False 就强制使用 CPUif not use_gpu:start_time = time.time() # 记录开始时间print("----------模型训练: CPU----------")for epoch in range(2): # 遍历整个数据集多次(训练2个 epoch)running_loss = 0.0 # 初始化每2000个小批次(即处理8000张图片)的累计损失for i, data in enumerate(trainloader, 0): # 遍历训练数据集,每次获取一个小批次(mini-batch)# 获取输入数据;data 是一个包含 [inputs, labels] 的列表inputs, labels = data# 将优化器的梯度清零,避免累积梯度optimizer.zero_grad()# 前向传播 + 反向传播 + 更新优化器outputs = net(inputs) # 通过网络进行前向传播,得到预测结果loss = criterion(outputs, labels) # 计算损失函数的值loss.backward() # 计算梯度(反向传播)optimizer.step() # 使用优化器更新模型的参数# 打印统计信息running_loss += loss.item() # 将当前损失加到累计损失中if i % 2000 == 1999: # 每2000个小批次(即处理8000张图片)打印一次信息print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')running_loss = 0.0 # 重置累计损失print('CPU Finished Training') # 打印训练结束的提示end_time = time.time() # 记录结束时间elapsed_time = end_time - start_time # 计算消耗的时间print(f"CPU time: {elapsed_time:.6f} 秒")else:start_time = time.time() # 记录开始时间print("----------模型训练: GPU----------")# 确保在 GPU 上训练,如果有 CUDA 可用device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')print("device", device)# ①将神经网络 net 的所有参数和缓冲区(buffers)转移到 device 上net.to(device)for epoch in range(2): # 遍历整个数据集多次(训练2个 epoch)running_loss = 0.0 # 初始化每2000个小批次(即处理8000张图片)的累计损失for i, data in enumerate(trainloader, 0): # 遍历训练数据集,每次获取一个小批次(mini-batch)# 获取输入数据;data 是一个包含 [inputs, labels] 的列表inputs, labels = data# ②将输入数据(即图像)和标签(即真实标签)转移到 device 上inputs, labels = inputs.to(device), labels.to(device)# 将优化器的梯度清零,避免累积梯度optimizer.zero_grad()# 前向传播 + 反向传播 + 更新优化器outputs = net(inputs) # 通过网络进行前向传播,得到预测结果loss = criterion(outputs, labels) # 计算损失函数的值loss.backward() # 计算梯度(反向传播)optimizer.step() # 使用优化器更新模型的参数# 打印统计信息running_loss += loss.item() # 将当前损失加到累计损失中if i % 2000 == 1999: # 每2000个小批次(即处理8000张图片)打印一次信息print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')running_loss = 0.0 # 重置累计损失print('GPU Finished Training') # 打印训练结束的提示end_time = time.time() # 记录结束时间elapsed_time = end_time - start_time # 计算消耗的时间print(f"GPU time: {elapsed_time:.6f} 秒")"""
模型训练: multi GPU
数据并行教程: https://pytorch.ac.cn/tutorials/beginner/blitz/data_parallel_tutorial.html
"""
5.保存训练好的模型参数
#----- 5.保存训练好的模型参数 -----#
import osprint("----------保存模型参数----------")
PATH = './model/cifar_net.pth'
os.makedirs('model', exist_ok=True) # 创建一个名为 'model' 的文件夹,如果文件夹已存在则不会报错。
torch.save(net.state_dict(), PATH)
三、加载模型参数、模型推理部分 load_and_infer.py
6.加载模型参数
#----- 6.加载模型参数 -----#
print("----------加载模型参数----------")
PATH = './model/cifar_net.pth'
net = Net()
net.load_state_dict(torch.load(PATH, weights_only=True))
7.在测试数据集上使用加载的模型进行推理
#----- 7.在测试数据集上使用加载的模型进行推理 -----#
print("----------加载4张测试集图像----------")
# 展示测试集图像
dataiter = iter(testloader)
images, labels = next(dataiter)# 使用训练好的模型进行推理
print("----------模型推理----------")
outputs = net(images)
_, predicted = torch.max(outputs, 1) # 1 是指按行(类别维度)选取最大值。函数返回每一行的最大值,及其对应的索引(类别)print('Predicted: ', ' '.join(f'{classes[predicted[j]]:5s}'for j in range(4)))# show images
title = ' '.join(f'{classes[labels[j]]:5s}' for j in range(4))
imshow(torchvision.utils.make_grid(images), title=title)print("----------网络在整个测试集上的准确率----------")
correct = 0 # 用于记录预测正确的图像数量
total = 0 # 用于记录测试集中图像的总数with torch.no_grad(): # 禁用梯度计算,减少内存消耗并加速推理过程for data in testloader: # 遍历测试数据集images, labels = data # 获取当前小批次的图像和标签# # test# print("标签(labels)为:", labels) # 示例:tensor([6, 0, 5, 7])# print("labels shape: ", labels.shape) # labels shape: torch.Size([4])# 使用网络进行推理,计算输出outputs = net(images)# 选择输出中最大值的类别作为预测结果_, predicted = torch.max(outputs, 1) # 1 是指按行(类别维度)选取最大值。函数返回每一行的最大值,及其对应的索引(类别)total += labels.size(0) # 累加测试集中的样本数量correct += (predicted == labels).sum().item() # 统计预测正确的样本数量# 打印测试集上模型的准确率
print(f'Accuracy of the network on the 10000 test images: {100 * correct // total} %')print("----------网络在每个类别上的准确率----------")
# 初始化字典
correct_pred = {classname: 0 for classname in classes} # 初始化每个类别的正确预测数
total_pred = {classname: 0 for classname in classes} # 初始化每个类别的总预测数# 由于不需要计算梯度,使用 no_grad 来加速推理过程
with torch.no_grad(): for data in testloader: # 遍历测试数据集images, labels = data # 获取当前批次的图像和标签outputs = net(images) # 使用网络进行前向传播,得到预测输出_, predictions = torch.max(outputs, 1) # 得到每个图像的预测类别(索引)# 收集每个类别的正确预测数量for label, prediction in zip(labels, predictions): # 同时遍历标签和预测值total_pred[classes[label]] += 1 # 增加对应类别的总预测数if label == prediction: # 如果标签与预测相同,表示预测正确correct_pred[classes[label]] += 1 # 增加对应类别的正确预测# 打印每个类别的准确率
for classname, correct_count in correct_pred.items(): # 遍历每个类别的正确预测数accuracy = 100 * float(correct_count) / total_pred[classname] # 计算准确率print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %') # 打印每个类别的准确率
四、代码及运行结果
1.train_and_save.py
1.1 代码
#----- 1.加载并归一化 CIFAR10 -----#
import torch
import torchvision
import torchvision.transforms as transforms# transforms.Compose(): 组合变换操作的容器, 允许将多个图像转换操作按顺序执行
transform = transforms.Compose(# 将范围在 [0, 255] 的 PIL Image 或 numpy.ndarray (H x W x C) 转换为形状为 (C x H x W)、范围在 [0.0, 1.0] 的 torch.FloatTensor[transforms.ToTensor(), # 使用均值和标准差归一化张量图像,将每个通道的值标准化为 [-1, 1] 区间。 output[channel] = (input[channel] - mean[channel]) / std[channel] = 2x - 1transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)# 设置批量大小
batch_size = 4# 加载CIFAR-10训练数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
# 创建训练数据的DataLoader,按批次加载数据并进行随机打乱
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,shuffle=True, num_workers=2)# 加载CIFAR-10测试数据集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
# 创建测试数据的DataLoader,按批次加载数据但不打乱
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,shuffle=False, num_workers=2)# CIFAR-10数据集的分类标签,包含10类
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')# 输出训练集和测试集的大小
train_size = len(trainset)
test_size = len(testset)
print(f'Training set size: {train_size}') # 50000
print(f'Test set size: {test_size}') # 10000# 展示训练集图像
import matplotlib.pyplot as plt
import numpy as npdef imshow(img, title=None):"""显示图像,并且可以选择性地显示标题。参数:img (Tensor): 要显示的图像。通常是经过预处理后的Tensor图像, 形状为 (C, H, W)。title (str, optional): 要显示的标题。如果提供了标题,则在图像上方显示它。"""img = img / 2 + 0.5 # unnormalize,反标准化,将图像的像素值从[-1, 1]映射回[0, 1]npimg = img.numpy() # 将PyTorch tensor转换为NumPy数组plt.imshow(np.transpose(npimg, (1, 2, 0))) # 将tensor的维度从 (C, H, W) 转换为 (H, W, C) 以便绘制# 如果提供了标题,就显示标题if title:plt.title(title)plt.show()# 从训练数据加载器中获取一个批次的数据 (随机的)
print("----------随机展示训练集图像----------")
dataiter = iter(trainloader) # 创建数据加载器的迭代器
images, labels = next(dataiter) # 获取一批数据,其中images是图像数据,labels是对应的标签# 创建标题,显示标签名称。5s 表示字符串的宽度为 5,不足的部分会使用空格填充
title = ' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)) # join() 方法将生成的类别名称列表(每个类别名称都经过格式化)用空格连接成一个单一的字符串。# 显示图像并且显示标题
imshow(torchvision.utils.make_grid(images), title=title) # 使用make_grid将图像组合成一个网格并显示#----- 2.定义卷积神经网络 -----#
import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = torch.flatten(x, 1) # torch.flatten(input, start_dim=0, end_dim=-1) :将输入张量从 start_dim 到 end_dim 维度展平为一个维度。x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xnet = Net()
print("----------模型结构----------")
print(net)'''
以上为公共部分
'''#----- 3.定义损失函数和优化器 -----#
import torch.optim as optim'''CrossEntropyLoss 通常用于分类问题,计算目标类别与模型预测类别之间的误差。交叉熵(Cross-Entropy)本质上是两个概率分布之间的差异度量,常用于比较:一个真实分布P(通常是 one-hot 编码)一个预测分布Q(通常是 softmax 输出)它的数学定义如下:CCrossEntropy(P,Q)=- ∑ [ Pi*log(Qi) ]i=1其中:C 是类别总数Pi是真实标签中第 i 类的概率(一般为 1 或 0)Qi是模型预测中第 i 类的概率(softmax 输出)交叉熵损失只对正确类别的预测概率进行惩罚,其它类别不参与损失。'''
# 定义损失函数(这里使用的是分类交叉熵损失函数(CrossEntropyLoss))
criterion = nn.CrossEntropyLoss()'''optim.SGD 是 PyTorch 提供的随机梯度下降(SGD)优化器。参数解释:net.parameters():模型参数,即网络中的所有可训练参数。lr=0.001: 学习率,控制每次参数更新的步长。较小的学习率有助于防止过拟合,但可能导致训练变慢。momentum=0.9: 动量项,用来加速收敛,并帮助跳出局部最小值。动量类似于物理中的惯性,它使用上一次的梯度来调整当前的梯度。
'''
# 定义优化器(这里使用的是带动量的随机梯度下降(SGD with momentum))
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)#----- 4.训练网络(使用 CPU 或者 GPU) -----#
import time
use_gpu = False # 改成 False 就强制使用 CPUif not use_gpu:start_time = time.time() # 记录开始时间print("----------模型训练: CPU----------")for epoch in range(2): # 遍历整个数据集多次(训练2个 epoch)running_loss = 0.0 # 初始化每2000个小批次(即处理8000张图片)的累计损失for i, data in enumerate(trainloader, 0): # 遍历训练数据集,每次获取一个小批次(mini-batch)# 获取输入数据;data 是一个包含 [inputs, labels] 的列表inputs, labels = data# 将优化器的梯度清零,避免累积梯度optimizer.zero_grad()# 前向传播 + 反向传播 + 更新优化器outputs = net(inputs) # 通过网络进行前向传播,得到预测结果loss = criterion(outputs, labels) # 计算损失函数的值loss.backward() # 计算梯度(反向传播)optimizer.step() # 使用优化器更新模型的参数# 打印统计信息running_loss += loss.item() # 将当前损失加到累计损失中if i % 2000 == 1999: # 每2000个小批次(即处理8000张图片)打印一次信息print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')running_loss = 0.0 # 重置累计损失print('CPU Finished Training') # 打印训练结束的提示end_time = time.time() # 记录结束时间elapsed_time = end_time - start_time # 计算消耗的时间print(f"CPU time: {elapsed_time:.6f} 秒")else:start_time = time.time() # 记录开始时间print("----------模型训练: GPU----------")# 确保在 GPU 上训练,如果有 CUDA 可用device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')print("device", device)# ①将神经网络 net 的所有参数和缓冲区(buffers)转移到 device 上net.to(device)for epoch in range(2): # 遍历整个数据集多次(训练2个 epoch)running_loss = 0.0 # 初始化每2000个小批次(即处理8000张图片)的累计损失for i, data in enumerate(trainloader, 0): # 遍历训练数据集,每次获取一个小批次(mini-batch)# 获取输入数据;data 是一个包含 [inputs, labels] 的列表inputs, labels = data# ②将输入数据(即图像)和标签(即真实标签)转移到 device 上inputs, labels = inputs.to(device), labels.to(device)# 将优化器的梯度清零,避免累积梯度optimizer.zero_grad()# 前向传播 + 反向传播 + 更新优化器outputs = net(inputs) # 通过网络进行前向传播,得到预测结果loss = criterion(outputs, labels) # 计算损失函数的值loss.backward() # 计算梯度(反向传播)optimizer.step() # 使用优化器更新模型的参数# 打印统计信息running_loss += loss.item() # 将当前损失加到累计损失中if i % 2000 == 1999: # 每2000个小批次(即处理8000张图片)打印一次信息print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')running_loss = 0.0 # 重置累计损失print('GPU Finished Training') # 打印训练结束的提示end_time = time.time() # 记录结束时间elapsed_time = end_time - start_time # 计算消耗的时间print(f"GPU time: {elapsed_time:.6f} 秒")"""
模型训练: multi GPU
数据并行教程: https://pytorch.ac.cn/tutorials/beginner/blitz/data_parallel_tutorial.html
"""#----- 5.保存训练好的模型参数 -----#
import osprint("----------保存模型参数----------")
PATH = './model/cifar_net.pth'
os.makedirs('model', exist_ok=True) # 创建一个名为 'model' 的文件夹,如果文件夹已存在则不会报错。
torch.save(net.state_dict(), PATH)
1.2运行结果
-
CPU
(yolov5_env) wu@WP:~/yolo/pytorch_practice$ python train_and_save.py
Files already downloaded and verified
Files already downloaded and verified
Training set size: 50000
Test set size: 10000
----------随机展示训练集图像----------
----------模型结构----------
Net((conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))(fc1): Linear(in_features=400, out_features=120, bias=True)(fc2): Linear(in_features=120, out_features=84, bias=True)(fc3): Linear(in_features=84, out_features=10, bias=True)
)
----------模型训练: CPU----------
[1, 2000] loss: 2.237
[1, 4000] loss: 1.895
[1, 6000] loss: 1.648
[1, 8000] loss: 1.555
[1, 10000] loss: 1.495
[1, 12000] loss: 1.454
[2, 2000] loss: 1.394
[2, 4000] loss: 1.343
[2, 6000] loss: 1.349
[2, 8000] loss: 1.292
[2, 10000] loss: 1.289
[2, 12000] loss: 1.273
CPU Finished Training
CPU time: 45.390200 秒
----------保存模型参数----------
-
GPU
(yolov5_env) wu@WP:~/yolo/pytorch_practice$ python train_and_save.py
Files already downloaded and verified
Files already downloaded and verified
Training set size: 50000
Test set size: 10000
----------随机展示训练集图像----------
----------模型结构----------
Net((conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))(fc1): Linear(in_features=400, out_features=120, bias=True)(fc2): Linear(in_features=120, out_features=84, bias=True)(fc3): Linear(in_features=84, out_features=10, bias=True)
)
----------模型训练: GPU----------
device cuda:0
[1, 2000] loss: 2.236
[1, 4000] loss: 1.876
[1, 6000] loss: 1.694
[1, 8000] loss: 1.633
[1, 10000] loss: 1.556
[1, 12000] loss: 1.492
[2, 2000] loss: 1.420
[2, 4000] loss: 1.386
[2, 6000] loss: 1.381
[2, 8000] loss: 1.343
[2, 10000] loss: 1.307
[2, 12000] loss: 1.283
GPU Finished Training
GPU time: 25.720243 秒
----------保存模型参数----------
2.load_and_infer.py
2.1 代码
#----- 1.加载并归一化 CIFAR10 -----#
import torch
import torchvision
import torchvision.transforms as transforms# transforms.Compose(): 组合变换操作的容器, 允许将多个图像转换操作按顺序执行
transform = transforms.Compose(# 将范围在 [0, 255] 的 PIL Image 或 numpy.ndarray (H x W x C) 转换为形状为 (C x H x W)、范围在 [0.0, 1.0] 的 torch.FloatTensor[transforms.ToTensor(), # 使用均值和标准差归一化张量图像,将每个通道的值标准化为 [-1, 1] 区间。 output[channel] = (input[channel] - mean[channel]) / std[channel] = 2x - 1transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)# 设置批量大小
batch_size = 4# 加载CIFAR-10训练数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
# 创建训练数据的DataLoader,按批次加载数据并进行随机打乱
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,shuffle=True, num_workers=2)# 加载CIFAR-10测试数据集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
# 创建测试数据的DataLoader,按批次加载数据但不打乱
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,shuffle=False, num_workers=2)# CIFAR-10数据集的分类标签,包含10类
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')# # 输出训练集和测试集的大小
# train_size = len(trainset)
# test_size = len(testset)
# print(f'Training set size: {train_size}') # 50000
# print(f'Test set size: {test_size}') # 10000# 展示训练集图像
import matplotlib.pyplot as plt
import numpy as npdef imshow(img, title=None):"""显示图像,并且可以选择性地显示标题。参数:img (Tensor): 要显示的图像。通常是经过预处理后的Tensor图像, 形状为 (C, H, W)。title (str, optional): 要显示的标题。如果提供了标题,则在图像上方显示它。"""img = img / 2 + 0.5 # unnormalize,反标准化,将图像的像素值从[-1, 1]映射回[0, 1]npimg = img.numpy() # 将PyTorch tensor转换为NumPy数组plt.imshow(np.transpose(npimg, (1, 2, 0))) # 将tensor的维度从 (C, H, W) 转换为 (H, W, C) 以便绘制# 如果提供了标题,就显示标题if title:plt.title(title)plt.show()# # 从训练数据加载器中获取一个批次的数据 (随机的)
# print("----------随机展示训练集图像----------")
# dataiter = iter(trainloader) # 创建数据加载器的迭代器
# images, labels = next(dataiter) # 获取一批数据,其中images是图像数据,labels是对应的标签# # 创建标题,显示标签名称。5s 表示字符串的宽度为 5,不足的部分会使用空格填充
# title = ' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)) # join() 方法将生成的类别名称列表(每个类别名称都经过格式化)用空格连接成一个单一的字符串。# # 显示图像并且显示标题
# imshow(torchvision.utils.make_grid(images), title=title) # 使用make_grid将图像组合成一个网格并显示#----- 2.定义卷积神经网络 -----#
import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = torch.flatten(x, 1) # torch.flatten(input, start_dim=0, end_dim=-1) :将输入张量从 start_dim 到 end_dim 维度展平为一个维度。x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x# net = Net()
# print("----------模型结构----------")
# print(net)'''
以上为公共部分
'''#----- 6.加载模型参数 -----#
print("----------加载模型参数----------")
PATH = './model/cifar_net.pth'
net = Net()
net.load_state_dict(torch.load(PATH, weights_only=True))#----- 7.在测试数据集上使用加载的模型进行推理 -----#
print("----------加载4张测试集图像----------")
# 展示测试集图像
dataiter = iter(testloader)
images, labels = next(dataiter)# 使用训练好的模型进行推理
print("----------模型推理----------")
outputs = net(images)
_, predicted = torch.max(outputs, 1) # 1 是指按行(类别维度)选取最大值。函数返回每一行的最大值,及其对应的索引(类别)print('Predicted: ', ' '.join(f'{classes[predicted[j]]:5s}'for j in range(4)))# show images
title = ' '.join(f'{classes[labels[j]]:5s}' for j in range(4))
imshow(torchvision.utils.make_grid(images), title=title)print("----------网络在整个测试集上的准确率----------")
correct = 0 # 用于记录预测正确的图像数量
total = 0 # 用于记录测试集中图像的总数with torch.no_grad(): # 禁用梯度计算,减少内存消耗并加速推理过程for data in testloader: # 遍历测试数据集images, labels = data # 获取当前小批次的图像和标签# # test# print("标签(labels)为:", labels) # 示例:tensor([6, 0, 5, 7])# print("labels shape: ", labels.shape) # labels shape: torch.Size([4])# 使用网络进行推理,计算输出outputs = net(images)# 选择输出中最大值的类别作为预测结果_, predicted = torch.max(outputs, 1) # 1 是指按行(类别维度)选取最大值。函数返回每一行的最大值,及其对应的索引(类别)total += labels.size(0) # 累加测试集中的样本数量correct += (predicted == labels).sum().item() # 统计预测正确的样本数量# 打印测试集上模型的准确率
print(f'Accuracy of the network on the 10000 test images: {100 * correct // total} %')print("----------网络在每个类别上的准确率----------")
# 初始化字典
correct_pred = {classname: 0 for classname in classes} # 初始化每个类别的正确预测数
total_pred = {classname: 0 for classname in classes} # 初始化每个类别的总预测数# 由于不需要计算梯度,使用 no_grad 来加速推理过程
with torch.no_grad(): for data in testloader: # 遍历测试数据集images, labels = data # 获取当前批次的图像和标签outputs = net(images) # 使用网络进行前向传播,得到预测输出_, predictions = torch.max(outputs, 1) # 得到每个图像的预测类别(索引)# 收集每个类别的正确预测数量for label, prediction in zip(labels, predictions): # 同时遍历标签和预测值total_pred[classes[label]] += 1 # 增加对应类别的总预测数if label == prediction: # 如果标签与预测相同,表示预测正确correct_pred[classes[label]] += 1 # 增加对应类别的正确预测# 打印每个类别的准确率
for classname, correct_count in correct_pred.items(): # 遍历每个类别的正确预测数accuracy = 100 * float(correct_count) / total_pred[classname] # 计算准确率print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %') # 打印每个类别的准确率
2.2 运行结果
(yolov5_env) wu@WP:~/yolo/pytorch_practice$ python load_and_infer.py
Files already downloaded and verified
Files already downloaded and verified
----------加载模型参数----------
----------加载4张测试集图像----------
----------模型推理----------
Predicted: bird car car ship
----------网络在整个测试集上的准确率----------
Accuracy of the network on the 10000 test images: 55 %
----------网络在每个类别上的准确率----------
Accuracy for class: plane is 67.1 %
Accuracy for class: car is 77.8 %
Accuracy for class: bird is 37.8 %
Accuracy for class: cat is 46.6 %
Accuracy for class: deer is 52.9 %
Accuracy for class: dog is 36.4 %
Accuracy for class: frog is 51.7 %
Accuracy for class: horse is 57.0 %
Accuracy for class: ship is 58.2 %
Accuracy for class: truck is 69.3 %
相关文章:
PyTorch入门------训练图像分类器
前言 1. 操作步骤 2. 数据集 一、公共部分 1.加载并归一化 CIFAR10 2.定义卷积神经网络 二、训练、保存模型参数部分 train_and_save.py 3.定义损失函数和优化器 4.训练网络(使用 CPU 或者 GPU) 5.保存训练好的模型参数 三、加载模型参数、模型推理部分 load_and_infer.py 6…...
DeepSeek V3 架构创新:大规模MoE与辅助损失移除
DeepSeek 团队推出的全新 DeepSeek V3 模型版本,相比之前的 V2 版本,V3 的参数量从两千多亿一跃攀升到 6710 亿,近乎实现了参数规模的三倍增长。如此宏大的模型规模并不只是简单地堆砌参数,而是建立在稀疏混合专家(Mixture-of-Experts,MoE)结构之上。得益于 MoE 的稀疏激…...
MCP 多工具协作链路设计:打造真正的智能工作流
目录 [TOC] 🚀 MCP 多工具协作链路设计:打造真正的智能工作流 🌟 多工具协作链核心思想 🛠️ 设计示例:智能文档分析系统 📑 1. MCP Server 定义多工具 list_txt_files.py read_file_content.py su…...
某修改版软件,已突破限制!
聊一聊 现在很多输入法都带有广告。 用着用着,不是提示升级就是弹出资讯。 特别是忙的时候,很影响心情。 今天给大家分享一款干净的输入法软件。 希望能你喜欢。 软件介绍 Q拼音输入法 工具我们下载后,进行安装。 双击打开,…...
透视Linux内核:深度剖析Socket机制的本质
在Linux操作系统构建的网络世界里,Socket 宛如纵横交错的交通枢纽,承担着不同应用程序间数据往来的重任。无论是日常浏览网页时,浏览器与 Web 服务器间信息的快速交互;还是畅玩网络游戏过程中,玩家操作指令与游戏服务器…...
PostgreSQL数据表操作SQL
数据表操作 创建表 CREATE TABLE t_test(id SERIAL PRIMARY KEY,name varchar(30),birthday date);修改表名 ALTER TABLE t_test RENAME TO t_test1;添加列 ALTER TABLE t_test1 ADD COLUMN score numeric(5,2);删除列 ALTER TABLE t_test1 DROP COLUMN score;修改数据类型 AL…...
OpenAI最新发布的GPT-4.1系列模型,性能体验如何?
简单来说,这次GPT-4.1的核心思路就是:更实用、更懂开发者、更便宜!OpenAI这次没搞太多花里胡哨的概念,而是实实在在地提升了大家最关心的几个点:写代码、听指令、处理超长文本,而且知识库也更新到了2024年6月。 写代码。要说这次GPT-4.1最亮眼的地方,可能就是写代码这块…...
2025五一数学建模C题完整分析论文(共36页)(含模型、可运行代码、数据)
2025年五一数学建模C题完整分析论文 摘要 一、问题分析 二、问题重述 三、模型假设 四、符号定义 五、 模型建立与求解 5.1问题1 5.1.1问题1思路分析 5.1.2问题1模型建立 5.1.3问题1代码 5.1.4问题1求解结果 5.2问题2 5.2.1问题2思路分析 5.2.2问题…...
Vue2基础速成
一、准备工作 首先下载vue2的JavaScript库,并且命名为vue.min.js 下载链接:https://cdn.jsdelivr.net/npm/vue2(若链接失效可去vue官网寻找) CTRLS即可下载保存 文件目录结构 二、使用操作原生DOM与使用VUE操作DOM的便捷性比较…...
Java大厂硬核面试:Flink流处理容错、Pomelo JVM调优、MyBatis二级缓存穿透防护与Kubernetes服务网格实战解析
第二幕:系统架构设计 面试官:设计一个处理10万QPS的秒杀系统需要的技术方案和技术选型 xbhog:采用基础架构: 存储层:Redis限流分布式锁服务层:Sentinel流量控制消息层:RocketMQ事务消息保证最…...
Python实现简易博客系统
下面我将介绍如何使用Python实现一个简易的博客系统,包含前后端完整功能。这个系统将使用Flask作为Web框架,SQLite作为数据库,并包含用户认证、文章发布、评论等基本功能。 1. 系统架构设计 技术栈选择 后端:Flask (Python Web框架)数据库:SQLite (轻量…...
【T型三电平仿真】SPWM调制
自然采样法和规则采样法的特点和计算 https://blog.csdn.net/u010632165/article/details/110889621 单极性和双极性的单双体现在什么地方 单极性和双极性的单双是指载波三角波的极性 为什么simulink进行电路仿真时,都需要放置一个powergui模块 任何使用SimPow…...
Astral Ascent 星界战士(星座上升) [DLC 解锁] [Steam] [Windows SteamOS macOS]
Astral Ascent 星界战士(星座上升) [DLC 解锁] [Steam] [Windows & SteamOS & macOS] 需要有游戏正版基础本体,安装路径不能带有中文,或其它非常规拉丁字符; DLC 版本 至最新全部 DLC 后续可能无法及时更新文章…...
Ubuntu20.04如何优雅的安装ROS 1(胎教级教程)
1、USTC的源: sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ lsb_release -cs main" > /etc/apt/sources.list.d/ros-latest.list2、设置的ROS源添加密钥: sudo apt-key adv --keyserver …...
terraform生成随机密码
在 Terraform 中生成安全随机密码可以通过 random_password 资源实现,以下是完整实现方案及安全实践: 基础实现 (生成随机密码) terraform {required_providers {random {source "hashicorp/random"version "~> 3.5.1" # 使…...
一个linux系统电脑,一个windows电脑,怎么实现某一个文件夹共享
下载Samba linux主机名字不能超过15个字符 sudo dnf install samba samba-client -y 创建共享文件夹 sudo mkdir /shared 配置文件 vim /etc/samba/smb.conf [shared] path /shared available yes valid users linux电脑用户 read only no browsable yes p…...
等保系列(一):网络安全等级保护介绍
一、基本概念 网络安全等级保护(以下简称:等保)是根据《中华人民共和国网络安全法》及配套规定(如《信息安全技术 网络安全等级保护基本要求》等)建立的系统性安全防护机制,要求网络运营者根据信息系统的重…...
【专题五】位运算(2)
📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码;ÿ…...
【2025五一数学建模竞赛A题】 支路车流量推测问题|建模过程+完整代码论文全解全析
你是否在寻找数学建模比赛的突破点?数学建模进阶思路! 作为经验丰富的美赛O奖、国赛国一的数学建模团队,我们将为你带来本次数学建模竞赛的全面解析。这个解决方案包不仅包括完整的代码实现,还有详尽的建模过程和解析,…...
案例:自动化获取Web页面小说(没钱修什么仙)——selenium
目录 前言一、目标即结果1. 目标:2. 提前了解网页信息3. 结果 二、逐步分析1 . selenium启动2. 获取所有章节3.打开对应章节链接,获取小说文本4. 内容写入本地文件 三、完整代码四、声名 前言 提示:通过案例掌握selenium语法 涉及技术&#…...
硬件工程师面试常见问题(11)
第五十一问:器件手册的翻译题目 要学英语啊,孩子。 第五十二问:二极管三极管常识题 1.二极管的导通电压一般是 0.7V 2.MOS管根据掺杂类型可以分为 NMOS和PMOS 3.晶体三极管在工作时,发射结和集电结均处于正向偏置,该晶体管工作在一饱和态。…...
TTL、LRU、LFU英文全称及释义
以下是 TTL、LRU 和 LFU 的英文全称及其简要解释: 1. TTL 全称:Time To Live(存活时间)含义: 表示数据在缓存或存储中的有效存活时间,过期后自动删除。 Redis 示例:SET key value EX 60&#x…...
本地部署 n8n 中文版
本地部署 n8n 中文版 0. n8n的核心价值1. 本地部署 n8n 中文版2. 访问 n8n 在技术团队寻求高效自动化解决方案的今天,n8n 作为一款安全的工作流自动化平台脱颖而出!它将代码的灵活性与低代码的便捷性深度融合,为开发者提供了独特的工具选择。…...
蓝桥杯比赛
蓝桥杯全国软件和信息技术专业人才大赛是由工业和信息化部人才交流中心主办,国信蓝桥教育科技(北京)股份有限公司承办的计算机类学科竞赛。以下是其相关信息: 参赛对象 具有正式全日制学籍且符合相关科目报名要求的研究生、本科生…...
【Linux】Makefile
Makefile常用用法介绍。 部分图片和经验来源于网络,还有正点原子的Linux驱动开发教程,若有侵权麻烦联系我删除,主要是做笔记的时候忘记写来源了,做完笔记很久才写博客。 专栏目录:记录自己的嵌入式学习之路-CSDN博客 1…...
【工具】Windows批量文件复制教程:用BAT脚本自动化文件管理
一、引言 在日常开发与部署过程中,文件的自动化复制是一个非常常见的需求。无论是在构建过程、自动部署,还是备份任务中,开发者经常需要将某个目录中的 DLL、配置文件、资源文件批量复制到目标位置。相比使用图形界面的复制粘贴操作…...
字节一面:后端开发
前言 这是我字节一面的回忆录,可能有些不全。 由于博主是Java面试Go岗,操作系统和计网问的还是比较多。 个人感觉字节很喜欢追问,博主被追问拷打的找不到北了,总结还是学的太浅了。 面试官给我的建议:再更深挖一些…...
西式烹饪实训室建设路径
在餐饮行业持续变革与教育信息化快速发展的当下,西式烹饪实训室的智能化建设成为提升教学质量、培养适应新时代需求烹饪人才的关键举措。通过引入先进技术,创新教学与管理模式,为学生打造更高效、更具沉浸感的学习环境。凯禾瑞华——实训室建…...
[更新完毕]2025五一杯A题五一杯数学建模思路代码文章教学:支路车流量推测问题
完整内容请看文章最下面的推广群 支路车流量推测问题 摘要 本文针对支路车流量推测问题展开研究,通过建立数学模型解决不同场景下的车流量分析需求。 针对问题一(Y型道路场景),研究两支路汇入主路的车流量推测。通过建立线性增长…...
2025年五一杯C题详细思路分析
C题 社交媒体平台用户分析问题 问题背景 近年来,社交媒体平台打造了多元化的线上交流空间和文化圈,深刻影响着人们社交互动与信息获取。博主基于专业知识或兴趣爱好等创作出高质量内容,吸引并获得用户的关注。用户可以随时通过观看、点赞、…...
攻防世界 dice_game
dice_game dice_game (1) motalymotaly-VMware-Virtual-Platform:~/桌面$ file game game: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]254…...
如何进行 JVM 性能调优?
进行 JVM 性能调优是一个系统性的过程,旨在提高 Java 应用程序的响应速度、吞吐量、降低资源消耗(如 CPU 和内存)以及提高稳定性。 以下是一个通用的 JVM 性能调优步骤和常用方法: 第一步:明确目标与建立基线 (Defin…...
艺华直播 5.0 |专注于提供港澳台及央视频道的电视直播应用,加载快,播放流畅
艺华直播是一款专注于提供港澳台及央视频道的电视直播应用。它以加载速度快、播放流畅不卡顿著称,是目前少数能够稳定观看港澳台频道的应用之一。此次分享的版本为测试版,支持4K秒播,带来极致的观看体验。尽管该应用已开始收费,但…...
【软件设计师:复习】上午题核心知识点总结(三)
一、编译原理(基础题) 1.编译过程概述(必考) 编译过程分为六个阶段,各阶段核心任务与典型输出如下: 阶段核心任务输入输出关键方法/工具词法分析将字符流转换为标记(Token)流源代码字符串Token序列(如<ID, "x">)正则表达式、有限自动机(DFA/NFA)…...
SAE极速部署弹性微服务商城——实验记录
SAE极速部署弹性微服务商城 本实验带您体验在SAE上快速部署一个弹性的在线商城微服务应用,使得终端用户可以通过公网访问该商城,并进行压力测试以验证其性能与稳定性。 文章目录 SAE极速部署弹性微服务商城使用SAE部署应用有哪些优势? 对商城…...
内存 “舞台” 上,进程如何 “翩翩起舞”?(转)
在数字世界里,计算机的每一次高效运转都离不开内存与进程的默契配合。内存,恰似一座宏大且有序的舞台,为进程提供了施展拳脚的空间。而进程,则如同舞台上的舞者,它们在内存的舞台上,遵循着一套复杂而精妙的…...
产品手册小程序开发制作方案
公司产品手册小程序系统主要是为了解决传统纸质或PDF格式手册更新成本高、周期长,难以及时反映最新产品信息。线下分发效率低,线上分享体验差,不利于品牌推广。传统手册单向传递信息,无法与用户进行互动,企业难以了解用…...
【dify—8】Agent实战——占星师
目录 一、创建Agent应用 二、创建提示词 三、创建变量 四、添加工具 五、发布更新 六、运行 第一部分 安装difydocker教程:【difydocker安装教程】-CSDN博客 第二部分 dock重装教程:【dify—2】docker重装-CSDN博客 第三部分 dify拉取镜像ÿ…...
Redis的键过期删除策略与内存淘汰机制详解
Redis 的键过期删除策略与内存淘汰机制详解 一、键过期删除策略 Redis 通过 定期删除(Active Expire) 和 惰性删除(Lazy Expire) 两种方式结合,管理键的过期清理。 1. 惰性删除(Lazy Expire) …...
数据结构——树(中篇)
今日名言: 人生碌碌,竞短论长,却不道枯荣有数,得失难量 上次我们讲了树的相关知识,接下来就进一步了解二叉树吧。本文为个人学习笔记,如有侵权,请 联系删除,如有错误,欢…...
实验三 软件黑盒测试
实验三 软件黑盒测试使用测试界的一个古老例子---三角形问题来进行等价类划分。输入三个整数a、b和c分别作为三角形的三条边,通过程序判断由这三条边构成的三角形类型是等边三角形、等腰三角形、一般三角形或非三角形(不能构成一个三角形)。其中要求输入变量&#x…...
PHP-Cookie
Cookie 是什么? cookie 常用于识别用户。cookie 是一种服务器留在用户计算机上的小文件。每当同一台计算机通过浏览器请求页面时,这台计算机将会发送 cookie。通过 PHP,您能够创建并取回 cookie 的值。 设置Cookie 在PHP中,你可…...
提升采购管理,打造核心竞争力七步战略采购法详解P94(94页PPT)(文末有下载方式)
资料解读:《提升采购管理,打造核心竞争力 —— 七步战略采购法详解》 详细资料请看本解读文章的最后内容。 在当今竞争激烈的商业环境中,采购管理已成为企业打造核心竞争力的关键环节。这份文件围绕七步战略采购法展开,深入剖析了…...
单片机-89C51部分:13、看门狗
飞书文档https://x509p6c8to.feishu.cn/wiki/LefkwDPU7iUUWBkfKE9cGLvonSh 一、作用 程序发生死循环的时候(跑飞),能够自动复位。 启动看门狗计数器->计数器计数->指定时间内不对计数器赋值(主程序跑飞,无法喂…...
基于MyBatis的银行转账系统开发实战:从环境搭建到动态代理实现
目标: 掌握mybatis在web应用中怎么用 mybatis三大对象的作用域和生命周期 ThreadLocal原理及使用 巩固MVC架构模式 为学习MyBatis的接口代理机制做准备 实现功能: 银行账户转账 使用技术: HTML Servlet MyBatis WEB应用的名称&am…...
纹理采样+光照纹理采样
普通纹理显示 导入纹理 1.将纹理拷贝到项目中 2.配置纹理 纹理显示原理 原始纹理(边长是),如果原始图的边长不是,游戏引擎在运行时,会自动将 纹理的边长补偿为,所以补偿是有损耗的(纹理不一定是…...
408真题笔记
2024 年全国硕士研究生招生考试 计算机科学与技术学科联考 计算机学科专业基础综合 (科目代码:408) 一、单项选择题 第 01~40 小题,每小题 2 分,共 80 分。下列每小题给出的四个选项中,只有一个…...
【Shell 脚本编程】详细指南:第一章 - 基础入门与最佳实践
Shell 脚本编程完全指南:第一章 - 基础入门与最佳实践 引言:Shell 脚本在现代开发中的重要性 Shell 脚本作为 Linux/Unix 系统的核心自动化工具,在 DevOps、系统管理、数据处理等领域扮演着关键角色。本章将系统性地介绍 Shell 脚本的基础知…...
PostgreSQL数据库操作SQL
数据库操作SQL 创建 创建数据库 create database db_test;创建并指定相关参数 with owner : 所有者encoding : 编码connection limit :连接限制 create database db_test1 with owner postgresencoding utf-8connection limit 100;修改 修改数据库名称 renam…...
RAG工程-基于LangChain 实现 Advanced RAG(预检索-查询优化)(下)
Multi-Query 多路召回 多路召回流程图 多路召回策略利用大语言模型(LLM)对原始查询进行拓展,生成多个与原始查询相关的问题,再将原始查询和生成的所有相关问题一同发送给检索系统进行检索。它适用于用户查询比较宽泛、模糊或者需要…...