当前位置: 首页 > news >正文

基于ResNet-18的简单分类(新手,而且网络效果不咋滴,就是学个流程)

引言

先看问题:

我手边有一数据集,然后我想分分类!~~·

咳咳,最近刚做了一个:训练集有1143张,分为5类,里面图片是打乱的。测试集有248张,想把它分分类看看咋样。

再看一下效果: 

这是经过100轮训练后准确率。(准确率最高也就72%左右,要想再升高就要改变数据集或者改网络了)

同时我们也将训练后的结果保存到了文件夹里。

经过网络训练后,最后的显示图:

预测第一张图属于第二类,它的确也确实属于第二类;但第二张图预测它是第二类,但是它事实上属于第四类。


操作

一、明确知道代码结构流程

① Prepare dataset   构建数据集

② Design model using Class   设计模型 

③ Construct loss and optimizer  构造损失函数和优化器

④ Training   训练

⑤ Prediction  预测结果(第五步可适当补充想生成的图像)

二、写代码

1.构建数据集

在写代码的时候,如果数据集都构建不好,后续都不用进行了。

接下来,我们简单说一下两种数据集构建代码。

(1) torchvision内置的数据集

这种就是最为简单的一种,可以直接调用的。如 MNIST、Fashion-MNIST、EMNIST、COCO、LSUN、ImageFolder、DatasetFolder、Imageenet-12、CIFAR、STL10 等。

下面简单以 CIFAR-10 为例:

a. 下载

CIFAR-10 and CIFAR-100 datasets (toronto.edu)

(下载解压后如下,并将文件夹放入一个新的文件夹 CIFAR 里,并将该文件夹放入另一个文件夹SH1中。)

大致构建如下:

b. 简单介绍 CIFAR-10 

The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, with 6000 images per class. There are 50000 training images and 10000 test images.The dataset is divided into five training batches and one test batch, each with 10000 images. The test batch contains exactly 1000 randomly-selected images from each class. The training batches contain the remaining images in random order, but some training batches may contain more images from one class than another. Between them, the training batches contain exactly 5000 images from each class.
(该数据集包含10个类别的60000张32x32彩色图像,每类有6000张图像。其中,有50000张用于训练,10000张用于测试。数据集被分为五个训练批次和一个测试批次,每批包含10000张图像。测试批次包含每个类别中随机选取的1000张图像。训练批次按照随机顺序包含剩余的图像,但有些训练批次可能包含某一类图像的数量多于另一类。在它们之间,训练批次包含每类5000张图像.)

c. 下载并配置数据集及加载器
# 下载并配置数据集
trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()])  
train_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=True, transform=trans)
test_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=False, transform=trans)# 配置数据加载器
batch_size = 64
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size, shuffle=True)

1. trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()]): 这行代码创建了一个数据转换操作的组合 trans,其中包括将图像大小调整为 (96, 96) 并将其转换为张量的操作。

2. train_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=True, transform=trans): 这行代码创建了一个 CIFAR-10 数据集的训练集 train_dataset,指定了数据集的根目录和使用的数据转换操作。

3. test_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=False, transform=trans): 这行代码创建了一个 CIFAR-10 数据集的测试集 test_dataset,同样指定了数据集的根目录和使用的数据转换操作。

4. batch_size = 64: 这行代码定义了批量大小为 64。

5. train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True): 这行代码创建了一个训练数据加载器 train_loader,用于加载训练数据集,指定了数据集、批量大小和是否打乱数据顺序。

6. test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True): 这行代码创建了一个测试数据加载器 test_loader,用于加载测试数据集,同样指定了数据集、批量大小和是否打乱数据顺序。

(2)我们自己手里的数据集

a. 整理标签

以上上周我们老师给我的数据集为例。老师给我的数据集里面包含训练集和测试集以及相应的标签。

但是标签里面的信息太多了,我只需要它的名称以及类别。

以Training_Labels为例,我只需要第一列 image 和 第二列 myopic_maculopathy_grade。

import pandas as pd
# 读取原始标签文件
df_train = pd.read_csv('Training_labels.csv')
df_test = pd.read_csv('Testing_labels.csv')# 提取所需字段
new_df_train = df_train[['image', 'myopic_maculopathy_grade']]
new_df_test = df_test[['image', 'myopic_maculopathy_grade']]# 重命名列
new_df_train.columns = ['filename', 'label']
new_df_test.columns = ['filename', 'label']
# 保存新的标签文件
new_df_train.to_csv('train_labels.csv', index=False)
new_df_test.to_csv('test_labels.csv', index=False)

所以我通过上面的代码将第一列和第二列进行了提取,并且改成了:filename', 'label',生成了另外的标签。

同样以train_Labels为例:

b. 定义一个自定义数据集类 

我们要定义一个自定义数据集类 CustomDataset , 用于加载图像数据集并返回及其对应的标签。

class CustomDataset(Dataset):def __init__(self, csv_file, root_dir, transform=None):self.labels_df = pd.read_csv(csv_file)self.root_dir = root_dirself.transform = transformdef __len__(self):return len(self.labels_df)def __getitem__(self, idx):img_name = os.path.join(self.root_dir, self.labels_df.iloc[idx, 0])try:image = Image.open(img_name)except FileNotFoundError:print(f"File not found: {img_name}")raiselabel = int(self.labels_df.iloc[idx, 1])  # 使用标签列if self.transform:image = self.transform(image)return image, label

1. class CustomDataset(Dataset)::定义了一个名为 CustomDataset 的类,该类继承自 Dataset 类,用于创建自定义数据集。

2. def __init__(self, csv_file, root_dir, transform=None)::定义了类的初始化方法,接受三个参数:csv_file 表示包含标签信息的 CSV 文件路径,root_dir 表示图像文件所在的根目录,transform 表示数据转换操作,默认为 None。

3. self.labels_df = pd.read_csv(csv_file): 从给定的 CSV 文件中读取标签信息并存储在 labels_df 中。

4. self.root_dir = root_dir:将图像文件的根目录路径存储在 root_dir 中。

5. self.transform = transform:存储数据转换操作,例如将图像转换为张量等。

6. def __len__(self)::定义了 __len__ 方法,返回数据集的长度,即标签信息的数量。

7. def __getitem__(self, idx)::定义了 __getitem__ 方法,用于获取数据集中特定索引 idx 处的图像及其标签。

8. img_name = os.path.join(self.root_dir, self.labels_df.iloc[idx, 0]):构建图像文件的完整路径。

9. try...except...:尝试打开图像文件,如果文件不存在则捕获 FileNotFoundError 异常并打印错误信息。

10. label = int(self.labels_df.iloc[idx, 1]):从标签数据中提取标签信息,转换为整数类型。

11. if self.transform::检查是否存在数据转换操作。

12. image = self.transform(image):如果存在数据转换操作,则对图像进行相应的转换。

13. return image, label:返回处理后的图像及其对应的标签。

c. 配置数据集及加载器
# 定义数据转换
trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()])# 创建自定义数据集
train_dataset = CustomDataset(csv_file='train_labels.csv', root_dir='training', transform=trans)
test_dataset = CustomDataset(csv_file='test_labels.csv', root_dir='testing', transform=trans)# 配置数据加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=0)  # 设置 num_workers=0 以避免多线程问题
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=True, num_workers=0)

( 由于这个代码和下载并配置CIFAR-10数据集及加载器的代码差不多,刚才仔细讲过了,所以这里就不再讲一遍了)

2. 设计模型

我们用的是ResNet-18网络,要想更好的理解这个网络,我们需要了解一个知识点----残差块。

在 ResNet-18 中,残差块起着关键的作用,通过引入跳跃连接(skip connection)来缓解深层神经网络中的梯度消失问题,从而使得训练更深层的网络成为可能。具体来说:

1. 跳跃连接:在每个残差块中,通过将输入直接与输出相加(即跳跃连接),实现了从底层到顶层的直接信息传递。这种跳跃连接有助于梯度的流动,避免了梯度在深层网络中逐渐消失的问题。

2. 缓解梯度消失:由于跳跃连接的存在,即使在深层网络中,梯度可以通过跳跃连接直接传播到较浅层,从而减轻了梯度消失问题,使得网络更容易训练。

3. 增强网络性能:残差块的设计使得网络更加深层时仍能保持较好的性能,因为网络可以更好地学习残差(即残差块的输出与输入之间的差异),而不是直接学习原始特征。

了解后,我们要了解一下网络的结构图:

经典CNN网络:Resnet18网络结构输入和输出[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com)

(网上有很多资料,我随便找了一个,应该还是比较容易的)

接下来,我们讲下代码:

(1) 残差块

class Residual(nn.Module):# 残差块def __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels,kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels,kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):# self.bn1(...):对卷积层的输出应用第一个批量归一化层,F.relu(...): 对归一化后的输出应用ReLU激活函数,Y: 存储激活后的输出Y = F.relu(self.bn1(self.conv1(X)))# Y: 更新Y为第二个卷积层和归一化后的输出Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += X  # Y += X: 将输入X(或经过1x1卷积层的X)加到Y上,实现残差连接。return F.relu(Y)

1. class Residual(nn.Module)::定义了一个名为 Residual 的类,继承自 nn.Module 类,表示这是一个 PyTorch 模型。

2. def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1)::定义了类的初始化方法,接受输入通道数 input_channels、输出通道数 num_channels、是否使用 1x1 卷积 use_1x1conv 和步幅 strides 作为参数。

3. super().__init__():调用父类的初始化方法。

4. self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1, stride=strides): 创建第一个卷积层,使用 3x3 的卷积核,填充为 1,步幅为 strides。

5. self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1): 创建第二个卷积层,输入通道数为 num_channels,输出通道数为 num_channels,使用 3x3 的卷积核,填充为 1。

6. if use_1x1conv::检查是否使用 1x1 卷积。

7. self.conv3 = nn.Conv2d(input_channels, num_channels, kernel_size=1, stride=strides): 如果使用 1x1 卷积,创建一个 1x1 的卷积层。

8. self.bn1 = nn.BatchNorm2d(num_channels): 创建第一个批量归一化层。

9. self.bn2 = nn.BatchNorm2d(num_channels): 创建第二个批量归一化层。

10. def forward(self, X)::定义了前向传播方法,接受输入 X。

11. Y = F.relu(self.bn1(self.conv1(X))): 应用第一个卷积层、批量归一化和 ReLU 激活函数。

12. Y = self.bn2(self.conv2(Y)): 应用第二个卷积层和批量归一化。

13. if self.conv3::检查是否存在第三个卷积层。

14. X = self.conv3(X): 如果存在第三个卷积层,应用该卷积层。

15. Y += X: 将输入 X(或经过 1x1 卷积层的 X)加到 Y 上,实现残差连接。

16. return F.relu(Y): 返回经过激活函数处理后的输出 Y。

(2) ResNet-18 网络


# ResNet-18
b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),  # 批量归一化层,通道数为64, ReLU激活函数nn.MaxPool2d(kernel_size=3, stride=2, padding=1))  # 最大池化层,核大小为3x3,步幅为2,填充为1def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []  # blk = []: 初始化一个空列表 blk,用于存储残差块。for i in range(num_residuals):if i == 0 and not first_block:# blk.append: 将一个新的残差块添加到 blk 列表中。blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))  # 不使用1x1卷积层,步幅为默认值1。return blk# *: 解包操作符,将 resnet_block 返回的列表解包为单个参数传递给 nn.Sequential。
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))# nn.AdaptiveAvgPool2d((1, 1)):自适应平均池化层,将每个特征图的空间维度(高度和宽度)缩小到1x1。
# 作用是将不同大小的特征图统一到相同的输出尺寸。
# nn.Flatten():将多维特征图展平成一维向量
# 作用是将特征图转换为全连接层可以处理的输入格式
# nn.Linear(512, 5)):全连接层,输入维度为512,输出维度为5。
# 作用是将展平后的特征向量映射到 5个类别 .(例如,CIFAR-10数据集有10个类别)。# 定义完整的ResNet模型
net = nn.Sequential(b1, b2, b3, b4, b5, nn.AdaptiveAvgPool2d((1, 1)),nn.Flatten(), nn.Linear(512, 5))
# nn.AdaptiveAvgPool2d((1, 1)),  # 自适应平均
# nn.Flatten(),  # 将特征图展平为一维向量
# nn.Linear(512, 5)  # 全连接层,将特征向量映射到 5个类别

(这段的讲解放在了代码里面)

3. 构造损失函数和优化器

lr = 0.001
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()

1. lr = 0.001: 定义了学习率为 0.001,即优化器在更新模型参数时的步长大小。

2. optimizer = torch.optim.Adam(net.parameters(), lr=lr): 创建了一个 Adam 优化器,用于更新模型 net 中的参数。Adam 是一种常用的优化算法,通过调整学习率来最小化损失函数。

3. loss = nn.CrossEntropyLoss(): 创建了一个交叉熵损失函数,用于计算模型输出与真实标签之间的损失。交叉熵损失通常用于多分类问题,特别是在输出层使用 softmax 激活函数时。

4.训练

# 定义训练模型
epochs = 100
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def train(net, train_iter, test_iter, epochs, device):# 初始化模型参数的权重def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)# 对模型应用初始化权重函数net.apply(init_weights)# 打印当前训练使用的设备print(f'Training on: [{device}]')# 将模型移动到指定的设备上进行训练net.to(device)# 创建计时器和获取训练数据迭代器的长度timer, num_batches = d2l.Timer(), len(train_iter)# 检查训练数据迭代器是否为空if num_batches == 0:print("No batches found in the training data.")return# 循环遍历每个训练轮数for epoch in range(epochs):# 训练损失之和,训练准确率之和,样本数metric = d2l.Accumulator(3)# 将模型设置为训练模式net.train()# 遍历训练数据迭代器for i, (X, y) in enumerate(train_iter):timer.start()optimizer.zero_grad()  # 清空优化器的梯度X, y = X.to(device), y.to(device)  # 将输入数据和标签移动到指定的设备上y_hat = net(X)  # 前向传播,获取模型的预测输出l = loss(y_hat, y)  # 计算模型输出与真实标签之间的损失l.backward()  # 反向传播,计算梯度optimizer.step()  # 更新模型参数with torch.no_grad():metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])  # 累积训练损失、准确率和样本数timer.stop()train_l = metric[0] / metric[2]  # 计算平均训练损失train_acc = metric[1] / metric[2]  # 计算平均训练准确率if (i + 1) % max(1, (num_batches // 30)) == 0 or i == num_batches - 1:print(f'Epoch: {epoch + 1}, Step: {i + 1}, Loss: {train_l:.4f}')  # 打印每个训练步骤的损失test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)  # 在测试集上评估模型的准确率print(f'Epoch {epoch + 1}: Train Accuracy: {train_acc * 100:.2f}%, Test Accuracy: {test_acc * 100:.2f}%')  # 打印每个训练轮数的训练准确率和测试准确率# 确保保存目录存在print(f'{metric[2] * epochs / timer.sum():.1f} examples/sec on: [{str(device)}]')# 确保保存目录存在save_dir = 'D:\\SH2\\result'  # 这里我在SH2文件夹里新建了一个文件夹result,用于存放最后结果os.makedirs(save_dir, exist_ok=True)# 保存模型torch.save(net.state_dict(), os.path.join(save_dir, f"ResNet-18_SHIYAN_Epoch{epochs}_Accuracy{test_acc * 100:.2f}%.pth"))train(net, train_loader, test_loader, epochs, device)

5. 预测结果

def show_predict():# 预测结果图像可视化net.to(device)  # 将模型移动到指定设备loader = DataLoader(dataset=test_dataset, batch_size=1, shuffle=True)  # 创建数据加载器plt.figure(figsize=(12, 8))  # 创建图像窗口name = ('first', 'second', 'third', 'fourth', 'fifth')  # 类别名称for i in range(9):(images, labels) = next(iter(loader))  # 获取图像和标签images = images.to(device)  # 将图像移动到指定设备labels = labels.to(device)  # 将标签移动到指定设备outputs = net(images)  # 获取模型输出_, predicted = torch.max(outputs.data, 1)  # 获取预测结果title = f"Predicted: {name[int(predicted[0])]}, True: {name[int(labels[0])]}"  # 设置标题plt.subplot(3, 3, i + 1)  # 创建子图plt.imshow(images.cpu()[0].permute(1, 2, 0))  # 显示图像plt.title(title, fontsize=10)  # 设置标题plt.xticks([])  # 隐藏x轴刻度plt.yticks([])  # 隐藏y轴刻度plt.show()  # 显示图像show_predict()

三、总代码

import os
import pandas as pd
from PIL import Image
from torch.utils.data import Dataset
from torchvision import transforms
import torch
from d2l.torch import d2l
from torch import nn
from torch.utils.data import DataLoader
from torchvision import transforms
from torch.nn import functional as F
import matplotlib.pyplot as plt
# import pandas as pd
# # 读取原始标签文件
# df_train = pd.read_csv('Training_labels.csv')
# df_test = pd.read_csv('Testing_labels.csv')# # 提取所需字段
# new_df_train = df_train[['image', 'myopic_maculopathy_grade']]
# new_df_test = df_test[['image', 'myopic_maculopathy_grade']]# # 重命名列
# new_df_train.columns = ['filename', 'label']
# new_df_test.columns = ['filename', 'label']
# # 保存新的标签文件
# new_df_train.to_csv('train_labels.csv', index=False)
# new_df_test.to_csv('test_labels.csv', index=False)class CustomDataset(Dataset):def __init__(self, csv_file, root_dir, transform=None):self.labels_df = pd.read_csv(csv_file)self.root_dir = root_dirself.transform = transformdef __len__(self):return len(self.labels_df)def __getitem__(self, idx):img_name = os.path.join(self.root_dir, self.labels_df.iloc[idx, 0])try:image = Image.open(img_name)except FileNotFoundError:print(f"File not found: {img_name}")raiselabel = int(self.labels_df.iloc[idx, 1])  # 使用标签列if self.transform:image = self.transform(image)return image, label# 定义数据转换
trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()])# 创建自定义数据集
train_dataset = CustomDataset(csv_file='train_labels.csv', root_dir='training', transform=trans)
test_dataset = CustomDataset(csv_file='test_labels.csv', root_dir='testing', transform=trans)# 配置数据加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=0)  # 设置 num_workers=0 以避免多线程问题
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=True, num_workers=0)# 这些代码定义了一个残差块(Residual Block),这是ResNet(残差网络)中的基本构建单元。
# 残差块的主要作用是通过引入跳跃连接(skip connection)来缓解深层神经网络中的梯度消失问题,从而使得训练更深层的网络成为可能。
class Residual(nn.Module):# 残差块def __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels,kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels,kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):# self.bn1(...):对卷积层的输出应用第一个批量归一化层,F.relu(...): 对归一化后的输出应用ReLU激活函数,Y: 存储激活后的输出Y = F.relu(self.bn1(self.conv1(X)))# Y: 更新Y为第二个卷积层和归一化后的输出Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += X  # Y += X: 将输入X(或经过1x1卷积层的X)加到Y上,实现残差连接。return F.relu(Y)# ResNet-18
b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),  # 批量归一化层,通道数为64, ReLU激活函数nn.MaxPool2d(kernel_size=3, stride=2, padding=1))  # 最大池化层,核大小为3x3,步幅为2,填充为1def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []  # blk = []: 初始化一个空列表 blk,用于存储残差块。for i in range(num_residuals):if i == 0 and not first_block:# blk.append: 将一个新的残差块添加到 blk 列表中。blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))  # 不使用1x1卷积层,步幅为默认值1。return blk# *: 解包操作符,将 resnet_block 返回的列表解包为单个参数传递给 nn.Sequential。
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))# nn.AdaptiveAvgPool2d((1, 1)):自适应平均池化层,将每个特征图的空间维度(高度和宽度)缩小到1x1。
# 作用是将不同大小的特征图统一到相同的输出尺寸。
# nn.Flatten():将多维特征图展平成一维向量
# 作用是将特征图转换为全连接层可以处理的输入格式
# nn.Linear(512, 5)):全连接层,输入维度为512,输出维度为5。
# 作用是将展平后的特征向量映射到 5个类别 .(例如,CIFAR-10数据集有10个类别)。# 定义完整的ResNet模型
net = nn.Sequential(b1, b2, b3, b4, b5, nn.AdaptiveAvgPool2d((1, 1)),nn.Flatten(), nn.Linear(512, 5))
# nn.AdaptiveAvgPool2d((1, 1)),  # 自适应平均
# nn.Flatten(),  # 将特征图展平为一维向量
# nn.Linear(512, 5)  # 全连接层,将特征向量映射到 5个类别  lr = 0.001
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()# 定义训练模型
epochs = 100
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def train(net, train_iter, test_iter, epochs, device):# 初始化模型参数的权重def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)# 对模型应用初始化权重函数net.apply(init_weights)# 打印当前训练使用的设备print(f'Training on: [{device}]')# 将模型移动到指定的设备上进行训练net.to(device)# 创建计时器和获取训练数据迭代器的长度timer, num_batches = d2l.Timer(), len(train_iter)# 检查训练数据迭代器是否为空if num_batches == 0:print("No batches found in the training data.")return# 循环遍历每个训练轮数for epoch in range(epochs):# 训练损失之和,训练准确率之和,样本数metric = d2l.Accumulator(3)# 将模型设置为训练模式net.train()# 遍历训练数据迭代器for i, (X, y) in enumerate(train_iter):timer.start()optimizer.zero_grad()  # 清空优化器的梯度X, y = X.to(device), y.to(device)  # 将输入数据和标签移动到指定的设备上y_hat = net(X)  # 前向传播,获取模型的预测输出l = loss(y_hat, y)  # 计算模型输出与真实标签之间的损失l.backward()  # 反向传播,计算梯度optimizer.step()  # 更新模型参数with torch.no_grad():metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])  # 累积训练损失、准确率和样本数timer.stop()train_l = metric[0] / metric[2]  # 计算平均训练损失train_acc = metric[1] / metric[2]  # 计算平均训练准确率if (i + 1) % max(1, (num_batches // 30)) == 0 or i == num_batches - 1:print(f'Epoch: {epoch + 1}, Step: {i + 1}, Loss: {train_l:.4f}')  # 打印每个训练步骤的损失test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)  # 在测试集上评估模型的准确率print(f'Epoch {epoch + 1}: Train Accuracy: {train_acc * 100:.2f}%, Test Accuracy: {test_acc * 100:.2f}%')  # 打印每个训练轮数的训练准确率和测试准确率# 确保保存目录存在print(f'{metric[2] * epochs / timer.sum():.1f} examples/sec on: [{str(device)}]')# 确保保存目录存在save_dir = 'D:\\SH2\\result'os.makedirs(save_dir, exist_ok=True)# 保存模型torch.save(net.state_dict(), os.path.join(save_dir, f"ResNet-18_CIFAR-10_Epoch{epochs}_Accuracy{test_acc * 100:.2f}%.pth"))train(net, train_loader, test_loader, epochs, device)def show_predict():# 预测结果图像可视化net.to(device)  # 将模型移动到指定设备loader = DataLoader(dataset=test_dataset, batch_size=1, shuffle=True)  # 创建数据加载器plt.figure(figsize=(12, 8))  # 创建图像窗口name = ('first', 'second', 'third', 'fourth', 'fifth')  # 类别名称for i in range(9):(images, labels) = next(iter(loader))  # 获取图像和标签images = images.to(device)  # 将图像移动到指定设备labels = labels.to(device)  # 将标签移动到指定设备outputs = net(images)  # 获取模型输出_, predicted = torch.max(outputs.data, 1)  # 获取预测结果title = f"Predicted: {name[int(predicted[0])]}, True: {name[int(labels[0])]}"  # 设置标题plt.subplot(3, 3, i + 1)  # 创建子图plt.imshow(images.cpu()[0].permute(1, 2, 0))  # 显示图像plt.title(title, fontsize=10)  # 设置标题plt.xticks([])  # 隐藏x轴刻度plt.yticks([])  # 隐藏y轴刻度plt.show()  # 显示图像show_predict()

附赠:用CIFAR-10数据集操作的代码(20轮,准确率大概在80%左右)

代码1和代码2都差不多,代码1和今天讲的差不多就改了一下数据集,代码2删减了一部分更改了一些,更为简单一点

代码1:

import os
import torch
from torch import nn
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
from d2l import torch as d2l# 下载并配置数据集
trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()])
train_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=True, transform=trans)
test_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=False, transform=trans)# 配置数据加载器
batch_size = 64
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size, shuffle=True)# 这些代码定义了一个残差块(Residual Block),这是ResNet(残差网络)中的基本构建单元。
# 残差块的主要作用是通过引入跳跃连接(skip connection)来缓解深层神经网络中的梯度消失问题,从而使得训练更深层的网络成为可能。
class Residual(nn.Module):# 残差块def __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels,kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels,kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):# self.bn1(...):对卷积层的输出应用第一个批量归一化层,F.relu(...): 对归一化后的输出应用ReLU激活函数,Y: 存储激活后的输出Y = F.relu(self.bn1(self.conv1(X)))# Y: 更新Y为第二个卷积层和归一化后的输出Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += X  # Y += X: 将输入X(或经过1x1卷积层的X)加到Y上,实现残差连接。return F.relu(Y)# ResNet-18
b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),  # 批量归一化层,通道数为64, ReLU激活函数nn.MaxPool2d(kernel_size=3, stride=2, padding=1))  # 最大池化层,核大小为3x3,步幅为2,填充为1def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []  # blk = []: 初始化一个空列表 blk,用于存储残差块。for i in range(num_residuals):if i == 0 and not first_block:# blk.append: 将一个新的残差块添加到 blk 列表中。blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))  # 不使用1x1卷积层,步幅为默认值1。return blk# *: 解包操作符,将 resnet_block 返回的列表解包为单个参数传递给 nn.Sequential。
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))# nn.AdaptiveAvgPool2d((1, 1)):自适应平均池化层,将每个特征图的空间维度(高度和宽度)缩小到1x1。
# 作用是将不同大小的特征图统一到相同的输出尺寸。
# nn.Flatten():将多维特征图展平成一维向量
# 作用是将特征图转换为全连接层可以处理的输入格式
# nn.Linear(512, 5)):全连接层,输入维度为512,输出维度为5。
# 作用是将展平后的特征向量映射到 5个类别 .(例如,CIFAR-10数据集有10个类别)。# 定义完整的ResNet模型
net = nn.Sequential(b1, b2, b3, b4, b5, nn.AdaptiveAvgPool2d((1, 1)),nn.Flatten(), nn.Linear(512, 10))
# nn.AdaptiveAvgPool2d((1, 1)),  # 自适应平均
# nn.Flatten(),  # 将特征图展平为一维向量
# nn.Linear(512, 5)  # 全连接层,将特征向量映射到 5个类别  lr = 0.001
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()# 定义训练模型
epochs = 20
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def train(net, train_iter, test_iter, epochs, device):# 初始化模型参数的权重def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)# 对模型应用初始化权重函数net.apply(init_weights)# 打印当前训练使用的设备print(f'Training on: [{device}]')# 将模型移动到指定的设备上进行训练net.to(device)# 创建计时器和获取训练数据迭代器的长度timer, num_batches = d2l.Timer(), len(train_iter)# 检查训练数据迭代器是否为空if num_batches == 0:print("No batches found in the training data.")return# 循环遍历每个训练轮数for epoch in range(epochs):# 训练损失之和,训练准确率之和,样本数metric = d2l.Accumulator(3)# 将模型设置为训练模式net.train()# 遍历训练数据迭代器for i, (X, y) in enumerate(train_iter):timer.start()optimizer.zero_grad()  # 清空优化器的梯度X, y = X.to(device), y.to(device)  # 将输入数据和标签移动到指定的设备上y_hat = net(X)  # 前向传播,获取模型的预测输出l = loss(y_hat, y)  # 计算模型输出与真实标签之间的损失l.backward()  # 反向传播,计算梯度optimizer.step()  # 更新模型参数with torch.no_grad():metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])  # 累积训练损失、准确率和样本数timer.stop()train_l = metric[0] / metric[2]  # 计算平均训练损失train_acc = metric[1] / metric[2]  # 计算平均训练准确率if (i + 1) % max(1, (num_batches // 30)) == 0 or i == num_batches - 1:print(f'Epoch: {epoch + 1}, Step: {i + 1}, Loss: {train_l:.4f}')  # 打印每个训练步骤的损失test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)  # 在测试集上评估模型的准确率print(f'Epoch {epoch + 1}: Train Accuracy: {train_acc * 100:.2f}%, Test Accuracy: {test_acc * 100:.2f}%')  # 打印每个训练轮数的训练准确率和测试准确率# 确保保存目录存在print(f'{metric[2] * epochs / timer.sum():.1f} examples/sec on: [{str(device)}]')# 确保保存目录存在save_dir = 'D:\\SH1\\result-1'os.makedirs(save_dir, exist_ok=True)# 保存模型torch.save(net.state_dict(), os.path.join(save_dir, f"ResNet-18_SHIYAN_Epoch{epochs}_Accuracy{test_acc * 100:.2f}%.pth"))train(net, train_loader, test_loader, epochs, device)def show_predict():# 预测结果图像可视化net.to(device)  # 将模型移动到指定设备loader = DataLoader(dataset=test_dataset, batch_size=1, shuffle=True)  # 创建数据加载器plt.figure(figsize=(12, 8))  # 创建图像窗口name = ('airplane', 'automobile', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')for i in range(9):(images, labels) = next(iter(loader))  # 获取图像和标签images = images.to(device)  # 将图像移动到指定设备labels = labels.to(device)  # 将标签移动到指定设备outputs = net(images)  # 获取模型输出_, predicted = torch.max(outputs.data, 1)  # 获取预测结果title = f"Predicted: {name[int(predicted[0])]}, True: {name[int(labels[0])]}"  # 设置标题plt.subplot(3, 3, i + 1)  # 创建子图plt.imshow(images.cpu()[0].permute(1, 2, 0))  # 显示图像plt.title(title, fontsize=10)  # 设置标题plt.xticks([])  # 隐藏x轴刻度plt.yticks([])  # 隐藏y轴刻度plt.show()  # 显示图像show_predict()

代码2:

import torch
from torch import nn
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
from d2l import torch as d2l# 下载并配置数据集
trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()])
train_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=True, transform=trans)
test_dataset = datasets.CIFAR10(root=r'D:\SH1\CIFAR', train=False, transform=trans)# 配置数据加载器
batch_size = 64
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size, shuffle=True)class Residual(nn.Module):# 残差块def __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels,kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels,kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):Y = F.relu(self.bn1(self.conv1(X)))Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += Xreturn F.relu(Y)# ResNet-18
b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []for i in range(num_residuals):if i == 0 and not first_block:blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))return blkb2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))net = nn.Sequential(b1, b2, b3, b4, b5,nn.AdaptiveAvgPool2d((1, 1)),nn.Flatten(), nn.Linear(512, 10))def train(net, train_iter, test_iter, epochs, lr, device):def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)net.apply(init_weights)print(f'Training on:[{device}]')net.to(device)optimizer = torch.optim.Adam(net.parameters(), lr=lr)loss = nn.CrossEntropyLoss()timer, num_batches = d2l.Timer(), len(train_iter)for epoch in range(epochs):# 训练损失之和,训练准确率之和,样本数metric = d2l.Accumulator(3)net.train()for i, (X, y) in enumerate(train_iter):timer.start()optimizer.zero_grad()X, y = X.to(device), y.to(device)y_hat = net(X)l = loss(y_hat, y)l.backward()optimizer.step()with torch.no_grad():metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])timer.stop()train_l = metric[0] / metric[2]train_acc = metric[1] / metric[2]if (i + 1) % (num_batches // 30) == 0 or i == num_batches - 1:print(f'Epoch: {epoch+1}, Step: {i+1}, Loss: {train_l:.4f}')test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)print(f'Epoch {epoch + 1}: Train Accuracy: {train_acc*100:.2f}%, Test Accuracy: {test_acc*100:.2f}%')print(f'{metric[2] * epochs / timer.sum():.1f} examples/sec 'f'on: [{str(device)}]')torch.save(net.state_dict(),f"D:\\SH1\\result-2\\ResNet-18_CIFAR-10_Epoch{epochs}_Accuracy{test_acc*100:.2f}%.pth")epochs, lr = 20, 0.001
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
train(net, train_loader, test_loader, epochs, lr, device)
# 加载保存的模型def show_predict():# 预测结果图像可视化net.to(device)loader = DataLoader(dataset=test_dataset, batch_size=1, shuffle=True)plt.figure(figsize=(12, 8))name = ('airplane', 'automobile', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')for i in range(9):(images, labels) = next(iter(loader))images = images.to(device)labels = labels.to(device)outputs = net(images)_, predicted = torch.max(outputs.data, 1)title = f"Predicted: {name[int(predicted[0])]}, True: {name[int(labels[0])]}"plt.subplot(3, 3, i + 1)plt.imshow(images.cpu()[0].permute(1, 2, 0))plt.title(title, fontsize=10)plt.xticks([])plt.yticks([])plt.show()show_predict()

相关文章:

基于ResNet-18的简单分类(新手,而且网络效果不咋滴,就是学个流程)

引言 先看问题: 我手边有一数据集,然后我想分分类!~~ 咳咳,最近刚做了一个:训练集有1143张,分为5类,里面图片是打乱的。测试集有248张,想把它分分类看看咋样。 再看一下效果: …...

自动化测试:Autorunner的使用

自动化测试:Autorunner的使用 一、实验目的 1、掌握自动化测试脚本的概念。 2、初步掌握Autorunner的使用 二、Autorunner的简单使用 autoRunner使用方法 新建项目 a) 在项目管理器空白区域,右键鼠标,选择新建项目 b) 输入项目名后,点击[确定]. 在初次打开aut…...

时序预测 | Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测; 2.多变量时间序列数据集(负荷数据集),采用前96个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&…...

软考 系统架构设计师系列知识点之杂项集萃(42)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(41) 第67题 Windows操作系统在图形界面处理方面采用的核心架构风格是( )风格。Java语言宣传的“一次编写,到处运行”的特性,从架构风格…...

FastBoot刷机获取root权限(Magisk)

1.首先要下载ADB、Fastboot等工具。 1.ADB、Fastboot工具 https://developer.android.com/studio/releases/platform-tools 2.安装FastBoot的USB驱动 https://developer.android.com/studio/run/oem-usb 2.下载对应的镜像 https://developers.google.com/android/images?…...

信息检索(43):SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking

SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking 摘要1 引言2 相关工作3 方法3.1 SparTerm3.2 SPLADE:稀疏词汇和扩展模型 4 实验5 结论 发布时间(2021) 标题:稀疏词汇 扩展模型 摘要 稀疏的优点&#xf…...

DockerHub 镜像加速

Docker Hub 作为目前全球最大的容器镜像仓库,为开发者提供了丰富的资源。Docker Hub 是目前最大的容器镜像社区,DokcerHub的不能使用,导致在docker下pull镜像无法下载,安装kubernetes镜像也受到影响,下面请看解决方式。 1.加速原理 Docker下载加速的原理…...

Oracle 迁移 Mysql

-- Oracle->MySQL -- 使用时改一下where条件的owner和table_name -- 字段数据类型映射时会将Oracle中的浮点NUMBER转换为decimal(65,8)定点数 -- 可以识别主键约束、非空约束,但无法识别外键约束、唯一约束、自定义check -- 对于Oracle字符串长度为4000的&#x…...

vue3父子组件通信

一&#xff0c;父传子——defineProps 方法&#xff1a; 在父组件的模板中使用子组件标签&#xff0c;并且给标签自定义属性和属性名&#xff0c;即通过v-bind绑定数值&#xff0c;而后传给子组件&#xff1b;子组件则通过defineProps接收使用。 父组件&#xff1a; <tem…...

CSS中使用应用在伪元素中的计数器属性counter-increment

在CSS中&#xff0c;counter-increment 是一个用于递增计数器值的属性。它通常与 counter-reset 和 content 属性一起使用&#xff0c;以在文档中的特定位置&#xff08;如列表项、标题等&#xff09;插入自动生成的数字或符号。 counter-increment 基本用法&#xff1a; 使…...

【SkiaSharp绘图08】SKPaint方法:自动换行、是否乱码、字符偏移、边界、截距、文本轮廓、测量文本

文章目录 SKPaint方法BreakText 计算指定宽度内可绘制的字符个数ContainsGlyphs字体是否包含文本字符(是否会乱码)GetGlyphOffsets 字符偏移量GetGlyphPositions 偏移坐标GetGlyphWidths 每个字符的宽度与边界GetHorizontalTextIntercepts 轮廓截距GetPositionedTextIntercepts…...

深入理解Servlet Filter及其限流实践

引言 在Java Servlet技术中&#xff0c;Filter是一个拦截器&#xff0c;它允许开发者在请求到达目标资源之前或响应发送给客户端之后&#xff0c;对请求或响应进行拦截和处理。这种机制为实现诸如身份验证、日志记录、请求修改等功能提供了极大的灵活性。 Filter基础 Filter…...

使用cv2对视频指定区域进行去噪

视频去噪其实和图象一样&#xff0c;只是需要现将视频截成图片&#xff0c;在对图片进行去噪&#xff0c;将去噪的图片在合成视频就行。可以利用cv2.imread()、imwrite()等轻松实现。 去噪步骤 1、视频逐帧读成图片 2、图片指定区域批量去噪 2、去噪后的图片写入视频 1、视频逐…...

AI在创造还是毁掉音乐?

AI对音乐产业的影响是复杂而多维的&#xff0c;既有创造性的贡献也存在潜在的挑战。我们可以从以下几个角度来分析这个问题&#xff1a; ### 创造性贡献 1. **音乐创作**&#xff1a;AI可以帮助音乐家创作新的旋律和和声&#xff0c;甚至生成完整的音乐作品。例如&#xff0c…...

【2023年全国青少年信息素养大赛智能算法挑战赛复赛真题卷】

目录 2023全国青少年信息素养大赛智能算法挑战赛初中组复赛真题 2023全国⻘少年信息素养⼤赛智能算法挑战复赛⼩学组真题 2023全国青少年信息素养大赛智能算法挑战赛初中组复赛真题 1. 修复机器人的对话词库错误 【题目描述】 基于人工智能技术的智能陪伴机器人的语言词库被…...

Android系统揭秘(一)-Activity启动流程(上)

public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread (IApplicationThread) contextThread; … try { … int result …...

使用Java实现哈夫曼编码

前言 哈夫曼编码是一种经典的无损数据压缩算法&#xff0c;它通过赋予出现频率较高的字符较短的编码&#xff0c;出现频率较低的字符较长的编码&#xff0c;从而实现压缩效果。这篇博客将详细讲解如何使用Java实现哈夫曼编码&#xff0c;包括哈夫曼编码的原理、具体实现步骤以…...

IDEA、PyCharm等基于IntelliJ平台的IDE汉化方式

PyCharm 或者 IDEA 等编辑器是比较常用的&#xff0c;默认是英文界面&#xff0c;有些同学用着不方便&#xff0c;想要汉化版本的&#xff0c;但官方没有这个设置项&#xff0c;不过可以通过插件的方式进行设置。 方式1&#xff1a;插件安装 1、打开设置 File->Settings&a…...

visual studio 创建c++项目

目录 环境准备&#xff1a;安装 visual studiovisual studio 创建c项目Tips&#xff1a;新建cpp文件注释与取消注释代码 其他初学者使用Visual Studio开发C和C时常遇到的3个坑 环境准备&#xff1a;安装 visual studio 官网&#xff1a;https://visualstudio.microsoft.com/zh…...

MGV电源维修KUKA机器人电源模块PH2003-4840

MGV电源维修 库卡电源模块维修 机器人电源模块维修 库卡控制器维修 KUKA电源维修 库卡机器人KUKA主机维修 KUKA驱动器模块维修 机械行业维修&#xff1a;西门子系统、法那克系统、沙迪克、FIDIA、天田、阿玛达、友嘉、大宇系统&#xff1b;数控冲床、剪板机、折弯机等品牌数控…...

设置浏览器互不干扰

目录 一、查看浏览器文件路径 二、 其他盘新建文件夹Cache 三、以管理员运行CMD 四、执行命令 一、查看浏览器文件路径 chrome://version/ 二、 其他盘新建文件夹Cache D:\chrome\Cache 三、以管理员运行CMD 四、执行命令 Mklink /d "C:\Users\Lenovo\AppData\Loca…...

kafka操作命令详解

目录 1、集群运维命令 1.1、集群启停命令 1.3、集群迁移命令 1.4、权限管理命令 1.4.1、权限参数介绍 1.4.2、增加权限命令 1.4.3、移出权限命令 1.4.4、查看所有topic权限命令 1.4.5、查看某个topic权限命令 2、生产者命令 2.1、创建topic命令 2.2、删除topic命令 …...

graalvm jdk和openjdk

下载地址:https://github.com/graalvm/graalvm-ce-builds/releases 官网: https://www.graalvm.org...

docker基础使用教程

1.准备工作 例子&#xff1a;工程在docker_test 生成requirements.txt文件命令&#xff1a;&#xff08;使用参考链接2&#xff09; pip list --formatfreeze > requirements.txt 参考链接1&#xff1a; 安装pipreqs可能比较困难 python 项目自动生成环境配置文件require…...

计算机网络 交换机的安全配置

一、理论知识 1.交换机端口安全功能介绍 交换机端口安全功能是针对交换机端口进行安全属性的配置&#xff0c;以控制用户的安全接入。主要包括以下两种配置项&#xff1a; ①限制交换机端口的最大连接数&#xff1a;控制交换机端口连接的主机数量&#xff1b;防止用户进行恶…...

深入解析大语言模型系列:Transformer架构的原理与应用

引言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;近几年取得了突破性的进展&#xff0c;而 Transformer 作为这些模型的核心架构&#xff0c;功不可没。本文将详细介绍 Transformer 的原理、结…...

uni-app地图组件控制

uni.createMapContext(mapId,this) 创建并返回 map 上下文 mapContext 对象。在自定义组件下&#xff0c;第二个参数传入组件实例this&#xff0c;以操作组件内 <map> 组件。 注意&#xff1a;uni.createMapContext(mapId, this) app-nvue 平台 2.2.5 支持 uni.create…...

前端调用api发请求常用的请求头content- type的类型和常用场景

Content-Type 是一个非常重要的HTTP头&#xff0c;它定义了发送给服务器或客户端的数据的MIME类型。这对于服务器和客户端正确解析和处理数据至关重要。下面是一些常见的 Content-Type 值及其用途和区别。 常见的 Content-Type 值 text/plain • 用途: 纯文本&#xff0c;无格…...

数据仓库之SparkSQL

Apache Spark SQL是Spark中的一个组件&#xff0c;专门用于结构化数据处理。它提供了通过SQL和DataFrame API来执行结构化数据查询的功能。以下是对Spark SQL的详细介绍&#xff1a; 核心概念 DataFrame: 定义: DataFrame是一个分布式数据集合&#xff0c;类似于关系型数据库中…...

如何在 MySQL 中导入和导出数据库以及重置 root 密码

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 如何导入和导出数据库 导出 要导出数据库&#xff0c;打开终端&#xff0c;确保你没有登录到 MySQL 中&#xff0c;然后输入以下命令&…...

基于uni-app和图鸟UI的云课堂小程序开发实践

摘要&#xff1a; 随着移动互联网的快速发展&#xff0c;移动学习已成为教育领域的重要趋势。本文介绍了基于uni-app和图鸟UI框架开发的云课堂小程序&#xff0c;该小程序实现了移动教学、移动学习、移动阅读和移动社交的完美结合&#xff0c;为用户提供了一个便捷、高效的学习…...

解决python从TD数据库取50w以上大量数据慢的问题

1.问题背景描述 python项目中的时序数据都存放在TD数据库中&#xff0c;数据是秒级存入的&#xff0c;当查询一周数据时将超过50w数据量&#xff0c;这是一次性获取全量数据到python程序很慢&#xff0c;全流程10秒以上&#xff0c;希望进行优化加速 2.排查 首先&#xff0c…...

游戏心理学Day21

玩家情绪与暴力攻击 情绪 情绪的分类 情绪是一种经常波动的东西&#xff0c;我们既体验过骄傲激动和开心&#xff0c;也体验过羞怯内疚和沮丧。我们的感受高度依赖于情境。研究者区分出至少三种途径来考察作为一种相对固定的人格特征的情绪&#xff0c;即为情感性&#xff0…...

接口测试基础 --- 什么是接口测试及其测试流程?

接口测试是软件测试中的一个重要部分&#xff0c;它主要用于验证和评估不同软件组件之间的通信和交互。接口测试的目标是确保不同的系统、模块或组件能够相互连接并正常工作。 接口测试流程可以分为以下几个步骤&#xff1a; 1.需求分析&#xff1a;首先&#xff0c;需要仔细…...

贪心+动归1

​​​​​​​​​​​​​​跳跃游戏 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0…...

三星S20以上手机中的动态相片及其分解

三星S20以后的相机&#xff0c;相机拍出来的图片&#xff0c;用三星手机自带的“相册”打开之后&#xff0c;还会有“查看动态照片”的选项&#xff0c;点击之后就能查看拍照片时前后2秒左右的视频&#xff01; 不知道这个功能是不是三星独有的。 这样得到的图片非常大。因为…...

一文了解HarmonyOSNEXT发布重点内容

华为在2024年6月21日的开发者大会上正式发布了HarmonyOS NEXT版&#xff0c;这是华为在操作系统领域的一次重大飞跃&#xff0c;标志着华为在构建全场景智能生态方面的卓越成就。HarmonyOS NEXT版不仅带来了全新的系统架构和性能提升&#xff0c;还首次将AI能力融入系统&#x…...

矩阵中严格递增的单元格数

题目链接&#xff1a;leetcode:矩阵中严格递增的单元格数 描述 给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat&#xff0c;你可以选择任一单元格作为 起始单元格 。 从起始单元格出发&#xff0c;你可以移动到 同一行或同一列 中的任何其他单元格&#xff0c;但前提是目…...

超参数调优-通用深度学习篇(上)

文章目录 深度学习超参数调优网格搜索示例一&#xff1a;网格搜索回归模型超参数示例二&#xff1a;Keras网格搜索 随机搜索贝叶斯搜索 超参数调优框架Optuna深度学习超参数优化框架nvidia nemo大模型超参数优化框架 参数调整理论&#xff1a; 黑盒优化&#xff1a;超参数优化…...

小程序中data-xx是用方式

data-sts"3" 是微信小程序中的一种数据绑定语法&#xff0c;用于在 WXML&#xff08;小程序模板&#xff09;中将自定义的数据绑定到页面元素上。让我详细解释一下&#xff1a; data-xx 的作用&#xff1a; data-xx 允许你在页面元素上自定义属性&#xff0c;以便在事…...

【2024德国工作】外国人在德国找工作是什么体验?

挺难的&#xff0c;德语应该是所有中国人的难点。大部分中国人进德国公司要么是做中国业务相关&#xff0c;要么是做技术领域的工程师。先讲讲人在中国怎么找德国的工作&#xff0c;顺便延申下&#xff0c;德国工作的真实体验&#xff0c;最后聊聊在今年的德国工作签证申请条件…...

Unity中获取数据的方法

Input和GetComponent 一、Input 1、Input类&#xff1a; 用于处理用户输入&#xff08;如键盘、鼠标、触摸等&#xff09;的静态类 2、作用&#xff1a; 允许你检查用户的输入状态。如某个键是否被按下&#xff0c;鼠标的位置&#xff0c;触摸的坐标等 3、实例 (1) 键盘…...

Java的死锁问题

Java中的死锁问题是指两个或多个线程互相持有对方所需的资源&#xff0c;导致它们在等待对方释放资源时永久地阻塞的情况。 死锁产生条件 死锁发生通常需要满足以下四个必要条件&#xff1a; 互斥条件&#xff1a;至少有一个资源是只能被一个线程持有的&#xff0c;如果其他…...

Unity 公用函数整理【二】

1、在规定时间时间内将一个值变化到另一个值&#xff0c;使用Mathf.Lerp实现 private float timer;[Tooltip("当前温度")]private float curTemp;[Tooltip("开始温度")]private float startTemp 20;private float maxTemp 100;/// <summary>/// 升…...

千年古城的味蕾传奇-平凉锅盔

在甘肃平凉这片古老而神秘的土地上&#xff0c;有一种美食历经岁月的洗礼&#xff0c;依然散发着独特的魅力&#xff0c;那便是平凉锅盔。平凉锅盔&#xff0c;那可是甘肃平凉的一张美食名片。它外表金黄&#xff0c;厚实饱满&#xff0c;就像一轮散发着诱人香气的金黄月亮。甘…...

微信小程序视频如何下载

一、工具准备 1、抓包工具Fiddler Download Fiddler Web Debugging Tool for Free by Telerik 2、VLC media player Download official VLC media player for Windows - VideoLAN 3、微信PC端 微信 Windows 版 二、开始抓包 1、打开Fiddler工具&#xff0c;设置修改如下…...

SVN 安装教程

SVN 安装教程 SVN&#xff08;Subversion&#xff09;是一个开源的版本控制系统&#xff0c;广泛用于软件开发和文档管理。本文将详细介绍如何在不同的操作系统上安装SVN&#xff0c;包括Windows、macOS和Linux。 Windows系统上的SVN安装 1. 下载SVN 访问SVN官方网站或Visu…...

HTML静态网页成品作业(HTML+CSS)—— 家乡山西介绍网页(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代…...

【抽代复习笔记】20-群(十四):定理6的补充证明及三道循环置换例题

例1&#xff1a;找出S3中所有不能和(123)交换的元。 解&#xff1a;因为 (123)(1) (1)(123) (123)&#xff0c;(123)(132) (132)(123) (1)&#xff0c;所以(1)、(132)和(123)均可以交换&#xff1b; 而(12)(123) (23)&#xff0c;(123)(12) (13)&#xff0c;故 (12)(12…...

【单片机毕业设计选题24018】-基于STM32和阿里云的农业大棚系统

系统功能: 系统分为手动和自动模式&#xff0c;上电默认为自动模式&#xff0c;自动模式下系统根据采集到的传感器值 自动控制&#xff0c;温度过低后自动开启加热&#xff0c;湿度过高后自动开启通风&#xff0c;光照过低后自动开启补 光&#xff0c;水位过低后自动开启水泵…...