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

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理

首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的初始化参数:root为数据存储的路径,如果数据已经下载,会直接从这个路径加载数据。train如果为True,表示加载训练集,train如果为False,加载测试集。download如果设置为True,表示如果本地不存在数据集,会自动从互联网上下载。transform指定一个转换函数,对数据进行预处理和数据增强等操作。所以下载训练集train_full时,train赋值为True,下载测试集时,train赋值为False。之后对下载的训练集train_full进行划分,先规定指定的大小,然后利用random_split进行划分,最后就是创建Dataloader,batch_size设为64,得到train_loader,val_loader,test_loader。

代码:

# 检查是否有可用的 GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")# 数据预处理和增强
transform = transforms.Compose([transforms.ToTensor(),  # 将图像转换为Tensortransforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 图像标准化
])# 下载 CIFAR-10 数据集
train_full = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
test = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)# 划分训练集(40,000)和验证集(10,000)
train_size = int(0.8 * len(train_full))  # 80% 用于训练
val_size = len(train_full) - train_size  # 剩余 20% 用于验证
train_data, val_data = random_split(train_full, [train_size, val_size])# 创建 DataLoader
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)
val_loader = DataLoader(val_data, batch_size=64, shuffle=False)
test_loader = DataLoader(test, batch_size=64, shuffle=False)

2.模型构建

模型构建就比较简单,直接使用使用pytorch定义的库函数,只有一行代码:

model = models.resnet18(pretrained=False),pretrained=False表示不使用在Imagenet上预训练的权重,pretrained=True表示使用在Imagenet上预训练的权重。因为这个模型是训练Imagenet构建的模型,要想让这个模型适应新任务,需要获取最后一层的输入特征数,然后利用一个全连接层将输出改为10。

代码:

# 初始化 ResNet-18 模型
model = models.resnet18(pretrained=True)
# 修改最后一层(全连接层),适应新的任务
num_ftrs = model.fc.in_features  # 获取最后一层的输入特征数
model.fc = torch.nn.Linear(num_ftrs, 10)  # 将输出改为 10 个类别(例如 CIFAR-10)

3.模型训练

创建Runner类,管理训练、评估、测试和预测过程。还是之前的一套东西,首先是一个init函数,用于初始化数据集、损失函数、优化器等。train函数用于计算在训练集上的loss,并反向传播更新参数。evaluate函数用于计算在验证集上的损失,不用反向传播更新模型的参数,同时根据evaluate函数得到的损失判断是否保存最优模型,利用state_dict函数保存最优模型。test函数首先加载最优模型,然后在测试集计算最优模型的准确率。predict函数预测某个图像属于某个类别的概率,虽然resnet最后一层没有softmax,但是也可以根据最后一层得到的10个logits(未经过归一化的原始输出)取最大来判断图像属于某一类(因为这10个值也是有大小关系的,softmax函数不会修改这10个值的大小关系)。

定义学习率=0.01、批次大小=30、损失函数为交叉熵损失nn.CrossEntropyLoss()、优化器为Adam。

实例化Runner,调用train函数,开始训练。

代码:

class Runner:def __init__(self, model, train_loader, val_loader, test_loader, criterion, optimizer, device):self.model = model.to(device)  # 将模型移到GPUself.train_loader = train_loaderself.val_loader = val_loaderself.test_loader = test_loaderself.criterion = criterionself.optimizer = optimizerself.device = deviceself.best_model = Noneself.best_val_loss = float('inf')self.train_losses = []  # 存储训练损失self.val_losses = []  # 存储验证损失def train(self, epochs=10):for epoch in range(epochs):self.model.train()running_loss = 0.0for inputs, labels in self.train_loader:# 将数据移到GPUinputs, labels = inputs.to(self.device), labels.to(self.device)self.optimizer.zero_grad()outputs = self.model(inputs)loss = self.criterion(outputs, labels)loss.backward()self.optimizer.step()running_loss += loss.item()# 计算平均训练损失train_loss = running_loss / len(self.train_loader)self.train_losses.append(train_loss)# 计算验证集上的损失val_loss = self.evaluate()self.val_losses.append(val_loss)print(f'Epoch [{epoch + 1}/{epochs}], Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}')# 如果验证集上的损失最小,保存模型if val_loss < self.best_val_loss:self.best_val_loss = val_lossself.best_model = self.model.state_dict()def evaluate(self):self.model.eval()val_loss = 0.0with torch.no_grad():for inputs, labels in self.val_loader:# 将数据移到GPUinputs, labels = inputs.to(self.device), labels.to(self.device)outputs = self.model(inputs)loss = self.criterion(outputs, labels)val_loss += loss.item()return val_loss / len(self.val_loader)def test(self):self.model.load_state_dict(self.best_model)self.model.eval()correct = 0total = 0with torch.no_grad():for inputs, labels in self.test_loader:# 将数据移到GPUinputs, labels = inputs.to(self.device), labels.to(self.device)outputs = self.model(inputs)_, predicted = torch.max(outputs, 1)total += labels.size(0)correct += (predicted == labels).sum().item()test_accuracy = correct / totalprint(f'Test Accuracy: {test_accuracy:.4f}')def predict(self, image):self.model.eval()image = image.to(self.device)  # 将图像移到GPUwith torch.no_grad():output = self.model(image)_, predicted = torch.max(output, 1)return predicted.item()def visualize_and_predict(self, index):"""针对训练集中的某一张图片进行预测,并可视化图片。:param index: 训练集中的图片索引"""# 获取训练集中的第 index 张图片image, label = self.train_loader.dataset[index]# 将图像移到GPU(如果需要)image = image.unsqueeze(0).to(self.device)  # 增加一个维度作为batch size# 可视化图像plt.imshow(image.cpu().squeeze().numpy(), cmap='gray')  # 假设是灰度图,若是彩色图像要调整plt.title(f"True Label: {label}")plt.show()# 预测该图片的类别predicted_label = self.predict(image)print(f"Predicted Label: {predicted_label}")
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)# 实例化Runner类
runner = Runner(model, train_loader, val_loader, test_loader, criterion, optimizer, device)# 训练模型
runner.train(epochs=30)
# 绘制损失曲线
plt.figure(figsize=(10, 6))
plt.plot(runner.train_losses, label='Train Loss')
plt.plot(runner.val_losses, label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.legend()
plt.grid()
plt.show()

4.模型评价

调用test函数,计算在测试集上的准确率。

代码:

# 在最优模型上评估测试集准确率
runner.test()

5.模型预测

在训练集任意选取一个图像,获取图像的image和标签label,因为图像已经经过了transform的变换,所以这个图像不需要transform,只需要添加一个维度1作为batch_size,可视化图像和真实标签,然后调用predict函数进行预测,输出真实类别。

代码:

# CIFAR-10 是 RGB 图像,确保正确显示
# 将 Tensor 转换为 numpy 数组并调整维度顺序为 HWC (Height, Width, Channels)
image_np = image.numpy().transpose((1, 2, 0))  # 从 CHW 转为 HWC# 可视化图像
plt.imshow(image_np)
plt.title(f"True Label: {label}")
plt.show()# 直接将图像传递给预测函数,不再需要 transform
# 但是要确保图像传入时是正确的 batch size 形状,即增加一个 batch 维度
image_transformed = image.unsqueeze(0).to(device)  # 增加一个维度作为 batch size# 预测该图片的类别
predicted_label = runner.predict(image_transformed)
print(f"Predicted Label: {predicted_label}")

6.实验结果与分析

不使用预训练权重的损失变化、准确率和预测结果

使用预训练权重的损失变化、准确率和预测结果

通过观察损失变化,我们发现两个模型在训练集上的loss一直在减小,说明模型的参数一直在更新。但是在验证集上的损失一开始是下降的,但是后来不断增大,我觉得是因为模型过拟合了。但是可以发现在没有预训练权重上的最优验证损失是比有预训练权重的模型上的最优验证损失大的。通过保存最优模型,在最优模型上计算准确率,发现在没有预训练权重的模型得到的准确率是0.7332,在使用预训练权重的模型得到的准确率是0.7431。

结论:通过对比在验证集上的最优验证损失和在测试集上的准确率,得到结论使用了预训练的模型效果要更好。

7.总结与心得体会

总结:

1.预训练模型:

预训练模型是指在一个大规模数据集上(如 ImageNet、COCO 等)经过训练的模型。这个模型已经学习到了一些通用的特征,比如图像中的边缘、纹理、颜色、形状等,或者文本中的语法、词汇关系等。这些特征是从数据中自动学习的,并且在很多不同的任务中都有用。

例子:

在图像分类任务中,ResNet、VGG、Inception 等深度神经网络在 ImageNet 上经过训练后,它们可以识别成千上万种不同的物体。由于这些物体特征具有广泛的普适性,我们可以将这些模型用于其他图像分类任务(例如 Cifar-10、Cifar-100),而无需从头开始训练。

在自然语言处理(NLP)中,像 BERT、GPT 等预训练语言模型已经在大量的文本数据上训练过,学习了丰富的语言知识。因此,我们可以将这些模型应用于文本分类、情感分析、问答等任务。

预训练模型的优势:

节省计算资源:训练深度神经网络需要大量的计算资源和时间,尤其是在大规模数据集上。通过使用预训练模型,用户可以避免从零开始训练,直接利用现成的知识。

提高效果:预训练模型已经学习到了一些通用的特征,可以加速学习过程,并且通常能够取得比从头开始训练更好的效果。
2. 迁移学习(Transfer Learning)

迁移学习是一种利用在一个任务上学到的知识,来帮助在另一个相关任务上进行学习的技术。换句话说,它将一个任务中的学习成果迁移到另一个任务中,特别是在目标任务的数据较少时。

迁移学习的核心思想是:如果一个模型在某个任务上已经学到了一些有用的特征,那么这些特征可以迁移到另一个任务上,帮助模型更好地学习。

迁移学习的典型流程:

模型加载:加载一个在大数据集上预训练的模型(如 ResNet、VGG、BERT 等)。

模型微调:对模型的部分层进行微调,或者只训练新添加的层(如分类层)。

应用于新任务:将经过微调的模型应用于新的、可能较小的数据集。

迁移学习的类型

迁移学习有多种不同的方式,常见的有以下几种:

微调(Fine-Tuning):使用预训练模型的权重,并对某些层或整个模型进行微调,以适应新的任务和数据。

通常会冻结前几层(因为它们学习的是通用特征),只训练后几层(专门针对当前任务)。

特征提取(Feature Extraction):使用预训练模型的特征提取能力,将前几层的权重固定,不更新,仅训练新加的全连接层或输出层。

零-shot 学习:在一些任务中,预训练模型被直接应用到目标任务,而不进行微调,特别是当目标任务的标注数据非常少时。

迁移学习的应用:

计算机视觉:在一个大规模的数据集(如 ImageNet)上训练的模型可以用于许多不同的图像分类任务,例如识别猫、狗、车、飞机等物体,或者在医疗影像、无人驾驶等领域中应用。

自然语言处理(NLP):例如,BERT 和 GPT 等模型可以在情感分析、命名实体识别、机器翻译等任务上进行迁移学习。

3. 预训练模型和迁移学习的关系

预训练模型和迁移学习是紧密相关的。迁移学习通常依赖于预训练模型,使用在一个任务中学到的知识来帮助另一个任务。在迁移学习中,预训练模型提供了一个良好的起点,减少了从头开始训练的难度和所需的数据量。

预训练模型与迁移学习的关系:

预训练模型是迁移学习的基础,因为迁移学习的一个关键步骤是使用已经在其他任务上训练好的模型。

迁移学习则是使用这些预训练模型的技术,它通过微调或特征提取等方式,将预训练模型的知识应用到新任务中。

使用torchvision.datasets的常见参数:

root:数据存储的路径。如果数据已经下载,它会直接从该路径加载数据。

train:如果设置为 True,加载训练集;如果设置为 False,加载测试集。

download:如果设置为 True,如果本地不存在数据集,它会自动从互联网上下载。

transform:指定一个转换函数,对数据进行预处理和数据增强等操作。

transforms.Compose 是 torchvision.transforms 模块中的一个函数,用于将多个图像预处理操作组合成一个复合操作。在神经网络训练中,常常需要对输入图像进行多种预处理,例如将图像转换为张量(Tensor)、标准化、数据增强等。transforms.Compose 允许你将这些操作按顺序组合在一起,并一次性应用于输入图像。

心得体会:

这个实验直接调用预训练的resnet18进行CIFAR-10数据集的分类,因为这个模型是在Imagenet数据集上训练得到的,所以适用于新的任务需要微调模型。通过对比没有预训练权重的模型和有预训练权重的模型的训练效果,发现还是有预训练权重得到的结果比较好,因为预训练模型已经学习到了一些通用的特征,可以加速学习过程,通常能够取得比从头开始训练更好的效果。在实际应用中在理解模型内部实现的基础上,直接调用高层API是一个不错的选择,可以减少代码量。

相关文章:

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform&#xff0c;里面定义了两种操作&#xff0c;一个是将图像转换为Tensor&#xff0c;一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集&#xff0c;这个函数有四个常见的…...

【开发文档】资源汇总,持续更新中......

文章目录 AI大模型数据集PytorchPythonUltralyticsOpenCVNetronSklearnCMakeListsNVIDIADocker刷题网站持续更新&#xff0c;欢迎补充 本文汇总了一些常用的开发文档资源&#xff0c;涵盖了常用AI大模型、刷题网站、Python、Pytorch、OpenCV、TensorRT、Docker 等技术栈。通过这…...

【k8s实践】 创建第一个Pod(Nginx)

环境 Rocky Linux9.4 x86_64 VM安装了Microk8s (参考:Microk8s安装方法) 说明: 其他k8s(例如: k3s, kubernetes)创建Pod的方法和Microk8s没啥区别&#xff0c;可以参考本文 目标 创建一个Nginx的Pod&#xff0c;映射宿主机30000端口到Pod容器的80端口&#xff1b;客户端能通…...

盘古大模型实战

0 前言 前一段时间&#xff0c;在学习人工智能的同时&#xff0c;也去了解了一下几乎是作为人工智能在气象上应用的一大里程碑式的研究成果-华为盘古气象大模型。正是盘古大模型的出现&#xff0c;促使天气预报的未来发展方向多了个除天气学方法、统计学方法、数值预报方法之外…...

Python subprocess.run 使用注意事项,避免出现list index out of range

在执行iOS UI 自动化专项测试的时候&#xff0c;在运行第一遍的时候遇到了这样的错误&#xff1a; 2024-12-04 20:22:27 ERROR conftest pytest_runtest_makereport 106 Test test_open_stream.py::TestOpenStream::test_xxx_open_stream[iPhoneX-xxx-1-250] failed with err…...

包管理器npm,cnpm,yarn和pnpm

npm (Node Package Manager) 核心技术与工作原理 依赖解析&#xff1a; 广度优先搜索&#xff08;BFS&#xff09;&#xff1a;npm 使用 BFS 算法来解析依赖树&#xff0c;尽量扁平化 node_modules 目录以减少重复的依赖项。冲突处理&#xff1a;如果两个包需要同一个依赖的不…...

树莓派4B使用opencv读取摄像头配置指南

本文自己记录&#xff0c;给我们lab自己使用&#xff0c;其他朋友们不一定完全适配&#xff0c;请酌情参考。 一. 安装opecnv 我们的树莓派4B默认是armv7l架构&#xff0c;安装的miniconda最新的版本 Miniconda3-latest-Linux-armv7l.sh 仍然是python3.4几乎无法使用&#xff…...

Spring Boot 进阶话题:部署

部署是将应用程序从开发环境移动到可以供用户访问的生产环境的过程。Spring Boot提供了多种部署选项&#xff0c;包括打包为可执行jar文件&#xff0c;使用Docker容器化&#xff0c;以及部署到云平台。 打包Spring Boot应用 Spring Boot应用可以打包为包含所有依赖、类和资源…...

Python 3 和 MongoDB 的集成使用

Python 3 和 MongoDB 的集成使用 MongoDB 是一个流行的 NoSQL 数据库&#xff0c;以其灵活的数据模型和强大的查询功能而闻名。Python 3 作为一种广泛使用的编程语言&#xff0c;与 MongoDB 的集成变得日益重要。本文将介绍如何在 Python 3 环境中集成和使用 MongoDB&#xff…...

perl语言中模式匹配的左右关系

这里简单记录一下&#xff0c;在perl语言中&#xff0c;关于模式匹配的一个细节&#xff1a; 在进行模式匹配的时候&#xff0c;左边写需要查找的字符串&#xff0c;右侧写匹配的关键字&#xff0e; 两边的顺序不一样就会导致匹配结果不一样&#xff0e; 测试代码&#xff1a;…...

【漏洞复现】网动统一通信平台(ActiveUC)接口iactiveEnterMeeting存在信息泄露漏洞

🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦 @TOC 一、漏洞概述 1.1漏洞简介 漏洞名称:网动统一通信平台(ActiveUC)接口iactiveEnterMeeting存在信息泄露漏洞漏洞编号:无漏洞类型:信息泄露漏洞威胁等级:高危影…...

C++ STL 容器系列(三)list —— 编程世界的万能胶,数据结构中的百变精灵

STL系列学习参考&#xff1a; C STL系列__zwy的博客-CSDN博客https://blog.csdn.net/bite_zwy/category_12838593.html 学习C STL的三个境界&#xff0c;会用&#xff0c;明理&#xff0c;能扩展&#xff0c;STL中的所有容器都遵循这个规律&#xff0c;下面我们就按照这三个境…...

Java经典面试题总结(附答案)2025

点击获取PDF版 10、如何将字符串反转&#xff1f; 添加到StringBuilder中&#xff0c;然后调用reverse()。 11、String 类的常用方法都有那些&#xff1f; equals、length、contains、replace、split、hashcode、indexof、substring、trim、toUpperCase、toLowerCase、isEmpt…...

Stylus 浏览器扩展开发-Cursor AI辅助

项目起源 作为一个经常需要长时间盯着屏幕的开发者&#xff0c;我一直在寻找一个简单的方法来保护眼睛。最初的想法很简单&#xff1a;将网页背景色替换成护眼的豆沙绿。虽然市面上已经有类似的扩展&#xff0c;但我想要一个更加轻量且可定制的解决方案。 这个简单的需求逐渐…...

DAY35|动态规划Part03|LeetCode:01背包问题 二维、01背包问题 一维、416. 分割等和子集

目录 01背包理论基础&#xff08;一&#xff09; 基本思路 C代码 01背包理论基础&#xff08;二&#xff09; 基本思路 C代码 LeetCode:416. 分割等和子集 基本思路 C代码 01背包理论基础&#xff08;一&#xff09; 题目链接&#xff1a;卡码网46. 携带研究材料 文字…...

创建空向量:std::vector<int> v,刚创建时大小为0

创建一个空的std::vector<int> v会在刚创建时具有大小&#xff08;size&#xff09;为0的特点。这意味着此时向量中没有任何元素&#xff0c;而且其容量&#xff08;capacity&#xff09;也返回0&#xff0c;表明还没有为这个向量分配任何内存空间3。换句话说&#xff0c…...

VBA基础2

VBA基础2 sub过程语法对单元格进行赋值操作连续赋值不连续赋值 cells &#xff08;行&#xff0c;列&#xff09;行引用rows列引用 &#xff08;columns&#xff09;offset位移属性End属性&#xff08;指定返回&#xff09; 使用VBA编辑器需要用AltF11打开 或者VB编辑器打开 可…...

计算机网络-GRE基础实验二

前面我们学习了GRE隧道的建立以及通过静态路由指向的方式使得双方能够网络互联&#xff0c;但是通过静态路由可能比较麻烦&#xff0c;GRE支持组播、单播、广播因此可以在GRE隧道中运行动态路由协议使得网络配置更加灵活。 通过前面的动态路由协议的学习我们知道动态路由协议都…...

JSON 使用

JSON 使用 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript编程语言的一个子集,但因其文本格式清晰简洁,被广泛用于数据交换和存储。本文将详细介绍JSON的使用方法,包括其语法、数据类型、如…...

Leetcode—1539. 第 k 个缺失的正整数【简单】

2024每日刷题&#xff08;206&#xff09; Leetcode—1539. 第 k 个缺失的正整数 C实现代码 class Solution { public:int findKthPositive(vector<int>& arr, int k) {int missing 1;int cur 1;int n arr.size();int missingCnt 0;int ptr 0;for(; missingCn…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...