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

PyTorch 模型性能分析和优化 — 第 1 部分

一、说明

        这篇文章的重点将是GPU上的PyTorch培训。更具体地说,我们将专注于 PyTorch 的内置性能分析器 PyTorch Profiler,以及查看其结果的方法之一,即 PyTorch Profiler TensorBoard 插件

二、深度框架

        训练深度学习模型,尤其是大型模型,可能是一项昂贵的支出。我们可以使用的用于管理这些成本的主要方法之一是性能优化。性能优化是一个迭代过程,在这个过程中,我们不断寻找提高应用程序性能的机会,然后利用这些机会。在以前的帖子中(例如,这里我们强调了拥有进行这种分析的适当工具的重要性。选择的工具可能取决于许多因素,包括训练加速器的类型(例如,GPU、HPU 或其他)和训练框架。

性能优化流程(作者)

       

        这篇文章并不是要替代PyTorch Profiler上的官方PyTorch文档,也不是使用TensorBoard插件来分析分析器结果。我们的目的是展示如何在一个人的日常发展过程中使用这些工具。事实上,如果您还没有,我们建议您在阅读这篇文章之前先查看官方文档。

        一段时间以来,我一直对TensorBoard插件教程的一部分特别感兴趣。本教程介绍了一个分类模型(基于 Resnet 架构),该模型在流行的 Cifar10 数据集上进行训练。它继续演示如何使用PyTorch Profiler和TensorBoard插件来识别和修复数据加载器中的瓶颈。输入数据管道中的性能瓶颈并不少见,我们在之前的一些文章中(例如,在这里)已经详细讨论了它们。本教程令人惊讶的是(截至撰写本文时)呈现的最终(优化后)结果,我们将其粘贴到下面:

性能跟踪优化(来自 PyTorch 网站)

        如果仔细观察,您会发现优化后的 GPU 利用率为 40.46%。现在没有办法粉饰这一点:这些结果绝对是糟糕的,应该让你夜不能寐。正如我们过去所扩展的那样(例如,在这里),GPU 是我们训练机器中最昂贵的资源,我们的目标应该是最大限度地提高其利用率。40.46% 的利用率结果通常代表培训加速和成本节约的重要机会。当然,我们可以做得更好!在这篇博文中,我们将努力做得更好。我们将首先尝试重现官方教程中提供的结果,看看我们是否可以使用相同的工具来进一步提高训练性能。

三、玩具示例

下面的代码块包含由 TensorBoard 插件教程定义的训练循环,进行了两个小的修改:

  1. 我们使用与本教程中使用的CIFAR10数据集具有相同属性和行为的假数据集。这种变化的动机可以在这里找到。
  2. 我们初始化torch.profiler.schedule,预热标志设置为3重复标志设置为1。我们发现,预热步骤数量的略微增加提高了分析结果的稳定性。
import numpy as np
import torch
import torch.nn
import torch.optim
import torch.profiler
import torch.utils.data
import torchvision.datasets
import torchvision.models
import torchvision.transforms as T
from torchvision.datasets.vision import VisionDataset
from PIL import Imageclass FakeCIFAR(VisionDataset):def __init__(self, transform):super().__init__(root=None, transform=transform)self.data = np.random.randint(low=0,high=256,size=(10000,32,32,3),dtype=np.uint8)self.targets = np.random.randint(low=0,high=10,size=(10000),dtype=np.uint8).tolist()def __getitem__(self, index):img, target = self.data[index], self.targets[index]img = Image.fromarray(img)if self.transform is not None:img = self.transform(img)return img, targetdef __len__(self) -> int:return len(self.data)transform = T.Compose([T.Resize(224),T.ToTensor(),T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])train_set = FakeCIFAR(transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True)device = torch.device("cuda:0")
model = torchvision.models.resnet18(weights='IMAGENET1K_V1').cuda(device)
criterion = torch.nn.CrossEntropyLoss().cuda(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
model.train()# train step
def train(data):inputs, labels = data[0].to(device=device), data[1].to(device=device)outputs = model(inputs)loss = criterion(outputs, labels)optimizer.zero_grad()loss.backward()optimizer.step()# training loop wrapped with profiler object
with torch.profiler.profile(schedule=torch.profiler.schedule(wait=1, warmup=4, active=3, repeat=1),on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/resnet18'),record_shapes=True,profile_memory=True,with_stack=True
) as prof:for step, batch_data in enumerate(train_loader):if step >= (1 + 4 + 3) * 1:breaktrain(batch_data)prof.step()  # Need to call this at the end of each step

        本教程中使用的GPU是Tesla V100-DGXS-32GB。在这篇文章中,我们尝试使用包含Tesla V2-SXM3–2GB GPU的Amazon EC100 p2.16xlarge实例重现并改进本教程的性能结果。尽管它们共享相同的架构,但您可以在此处了解两个 GPU 之间存在一些差异。我们使用 AWS PyTorch 2.0 Docker 映像运行训练脚本。下图捕获了 TensorBoard 查看器概述页面中显示的训练脚本的性能结果:

TensorBoard Profiler 概述选项卡中显示的基线性能结果(由作者捕获)

        我们首先注意到,与本教程相反,我们实验中的概述页面(torch-tb-profiler 版本 0.4.1)将三个分析步骤合并为一个。因此,平均总步长时间为 80 毫秒,而不是报告的 240 毫秒。这可以在“跟踪”选项卡(根据我们的经验,几乎总是提供更准确的报告)中清楚地看到,其中每个步骤需要 ~80 毫秒。

TensorBoard Profiler 跟踪视图选项卡中显示的基线性能结果(由作者捕获)

        请注意,我们的起点 31.65% GPU 利用率和 80 毫秒的步进时间与教程中分别提供的 23.54% 和 132 毫秒的起点不同。这可能是训练环境差异的结果,包括 GPU 类型和 PyTorch 版本。我们还注意到,虽然教程基线结果清楚地将性能问题诊断为 DataLoader 中的瓶颈,但我们的结果却没有。我们经常发现,数据加载瓶颈会在“概述”选项卡中伪装成“CPU Exec”或“其他”的高比例。

3.1 优化#1:多进程数据加载

        让我们从应用多进程数据加载开始,如教程中所述。由于 Amazon EC2 p3.2xlarge 实例有 8 个 vCPU,因此我们将 DataLoader 辅助角色的数量设置为 8 个,以获得最佳性能:

train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True, num_workers=8)

        此优化的结果如下所示:

TensorBoard Profiler 概述选项卡中多进程数据加载的结果(由作者捕获)

        对单行代码的更改使 GPU 利用率提高了 200% 以上(从 31.65% 提高到 72.81%),并将我们的训练步骤时间减少了一半以上(从 80 毫秒减少到 37 毫秒)。

本教程中的优化过程到此结束。尽管我们的GPU利用率(72.81%)比教程中的结果(40.46%)高得多,但我毫不怀疑,像我们一样,您会发现这些结果仍然不令人满意。

您应该随意跳过的个人评论:想象一下,如果在 GPU 上训练时,如果 PyTorch 默认应用多进程数据加载,可以节省多少全球资金!诚然,使用多处理可能会有一些不必要的副作用。但是,必须运行某种形式的自动检测算法,以排除潜在问题场景的存在并相应地应用此优化。

3.2 优化#2:内存固定

        如果我们分析上一个实验的跟踪视图,我们可以看到大量时间(10 毫秒中的 37 毫秒)仍然花费在将训练数据加载到 GPU 上。

“跟踪视图”选项卡中多进程数据加载的结果(由作者捕获)

        为了解决这个问题,我们将应用另一个 PyTorch 推荐的优化来简化数据输入流,即内存固定。使用固定内存可以提高主机到 GPU 数据复制的速度,更重要的是,允许我们使它们异步。这意味着我们可以在 GPU 中准备下一个训练批次,同时在当前批次上运行训练步骤。请务必注意,尽管异步执行通常会提高性能,但它也会降低时间测量的准确性。出于我们的博客文章的目的,我们将继续使用 PyTorch Profiler 报告的测量值。有关如何获得精确测量的说明,请参阅此处。有关内存固定及其副作用的其他详细信息,请参阅 PyTorch 文档。

        此内存固定优化需要更改两行代码。首先,我们将 DataLoader 的 pin_memory 标志设置为 True。

train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True, num_workers=8, pin_memory=True)

        然后我们将主机到设备的内存传输(在训练函数中)修改为非阻塞:

inputs, labels = data[0].to(device=device, non_blocking=True), \data[1].to(device=device, non_blocking=True)

内存固定优化的结果如下所示:

TensorBoard 探查器概述选项卡中的内存固定结果(由作者捕获)

        我们的 GPU 利用率现在保持在可观的 92.37%,我们的步进时间进一步减少。但我们仍然可以做得更好。请注意,尽管进行了此优化,但性能报告继续表明我们花费了大量时间将数据复制到 GPU 中。我们将在下面的步骤 4 中回到这个问题。

3.3 优化#3:增加批量大小

        对于下一个优化,我们将注意力吸引到上一个实验的内存视图:

TensorBoard Profiler 中的内存视图(由作者捕获)

        图表显示,在 16 GB 的 GPU 内存中,我们的利用率峰值不到 1 GB。这是资源利用不足的一个极端示例,通常(尽管并非总是)表示有机会提高性能。控制内存利用率的一种方法是增加批大小。在下图中,我们显示了将批大小增加到 512(内存利用率增加到 11.3 GB)时的性能结果。

在 TensorBoard 分析器概述选项卡中增加批大小的结果(由作者捕获)

        尽管 GPU 利用率测量值变化不大,但我们的训练速度已大幅提高,从每秒 1200 个样本(批大小 46 为 32 毫秒)提高到每秒 1584 个样本(批大小 324 为 512 毫秒)。

        警告:与我们之前的优化相反,增加批大小可能会影响训练应用程序的行为。不同的模型对批量大小的变化表现出不同程度的敏感度。有些可能只需要对优化器设置进行一些调整。对于其他人来说,适应大批量可能更困难甚至不可能。请参阅上一篇文章,了解大批量培训所涉及的一些挑战。

3.4 优化#4:减少主机到设备的复制

        您可能注意到了我们之前结果中饼图中代表主机到设备数据副本的大红色眼球。尝试解决这种瓶颈的最直接方法是看看我们是否可以减少每批中的数据量。请注意,在我们的图像输入的情况下,我们将数据类型从 8 位无符号整数转换为 32 位浮点数,并在执行数据复制之前应用规范化。在下面的代码块中,我们提出了对输入数据流的更改,其中我们延迟数据类型转换和规范化,直到数据在 GPU 上:

# maintain the image input as an 8-bit uint8 tensor
transform = T.Compose([T.Resize(224),T.PILToTensor()])
train_set = FakeCIFAR(transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=1024, shuffle=True, num_workers=8, pin_memory=True)device = torch.device("cuda:0")
model = torch.compile(torchvision.models.resnet18(weights='IMAGENET1K_V1').cuda(device), fullgraph=True)
criterion = torch.nn.CrossEntropyLoss().cuda(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
model.train()# train step
def train(data):inputs, labels = data[0].to(device=device, non_blocking=True), \data[1].to(device=device, non_blocking=True)# convert to float32 and normalizeinputs = (inputs.to(torch.float32) / 255. - 0.5) / 0.5outputs = model(inputs)loss = criterion(outputs, labels)optimizer.zero_grad()loss.backward()optimizer.step()

由于这一变化,从 CPU 复制到 GPU 的数据量减少了 4 倍,红色的眼睛几乎消失了:

在 TensorBoard 探查器概述选项卡中将 CPU 复制到 GPU 的结果(由作者捕获)

        我们现在站在97.51%(!!)的新高GPU 利用率和每秒 1670 个样本的训练速度!让我们看看我们还能做什么。

3.5 优化#5:将梯度设置为无

        在这个阶段,我们似乎正在充分利用GPU,但这并不意味着我们不能更有效地利用它。据说可以减少 GPU 中内存操作的一种流行优化是在每个训练步骤中将模型参数梯度设置为 None 而不是。有关此优化的更多详细信息,请参阅 PyTorch 文档。实现此优化所需的只是将optimizer.zero_grad调用的set_to_none设置为 True

optimizer.zero_grad(set_to_none=True)

在我们的案例中,这种优化并没有以任何有意义的方式提高我们的性能。

3.6 优化#6:自动混合精度

        GPU 内核视图显示 GPU 内核处于活动状态的时间量,可以作为提高 GPU 利用率的有用资源:

TensorBoard Profiler 中的内核视图(由作者捕获)

        本报告中最明显的细节之一是缺乏使用 GPU 张量核心。张量核心可用于相对较新的 GPU 架构,是用于矩阵乘法的专用处理单元,可以显着提高 AI 应用程序的性能。它们的缺乏使用可能代表优化的重要机会。

        由于张量核是专门为混合精度计算而设计的,因此提高其利用率的一种直接方法是修改我们的模型以使用自动混合精度 (AMP)。在 AMP 模式下,模型的某些部分会自动转换为精度较低的 16 位浮点数,并在 GPU 张量核心上运行。

        重要的是,请注意,AMP 的完整实现可能需要梯度缩放,我们未包含在演示中。在调整之前,请务必查看有关混合精度训练的文档。

        下面的代码块演示了启用 AMP 所需的训练步骤的修改。

def train(data):inputs, labels = data[0].to(device=device, non_blocking=True), \data[1].to(device=device, non_blocking=True)inputs = (inputs.to(torch.float32) / 255. - 0.5) / 0.5with torch.autocast(device_type='cuda', dtype=torch.float16):outputs = model(inputs)loss = criterion(outputs, labels)# Note - torch.cuda.amp.GradScaler() may be required  optimizer.zero_grad(set_to_none=True)loss.backward()optimizer.step()

        下图显示了对张量核心利用率的影响。尽管它继续表明有进一步改进的机会,但仅使用一行代码,利用率就从 0% 跃升至 26.3%。

张量核心利用率与 AMP 优化从 TensorBoard 分析器中的内核视图(由作者捕获)

        除了增加张量核心利用率外,使用 AMP 还可以降低 GPU 内存利用率,从而释放更多空间来增加批量大小。下图捕获了 AMP 优化和批量大小设置为 1024 后的训练性能结果:

TensorBoard 分析器概述选项卡中的 AMP 优化结果(由作者捕获)

        尽管 GPU 利用率略有下降,但我们的主要吞吐量指标进一步增加了近 50%,从每秒 1670 个样本增加到 2477 个。我们正在滚动!

        警告: 降低模型各部分的精度可能会对其收敛产生有意义的影响。与增加批大小(见上文)的情况一样,使用混合精度的影响将因模型而异。在某些情况下,AMP 几乎不会费力地工作。其他时候,可能需要更加努力地调整自动缩放程序。还有一些时候,您可能需要显式设置模型不同部分的精度类型(即手动混合精度)。

有关使用混合精度作为内存优化方法的更多详细信息,请参阅我们之前关于该主题的博客文章。

3.7 优化#7:在图形模式下训练

        我们将应用的最终优化是模型编译。与默认的 PyTorch 渴望执行模式相反,在这种模式下,每个 PyTorch 操作都“急切”运行,编译 API 将您的模型转换为中间计算图,然后以最适合底层训练加速器的方式编译为低级计算内核。有关 PyTorch 2 中模型编译的更多信息,请查看我们之前关于该主题的文章。

以下代码块演示了应用模型编译所需的更改:

model = torchvision.models.resnet18(weights='IMAGENET1K_V1').cuda(device)
model = torch.compile(model)

模型编译优化的结果如下所示:

TensorBoard Profiler 概述选项卡中的图形编译结果(由作者捕获)

        与上一次实验中的 3268 个样本相比,模型编译进一步将我们的通量提高到每秒 2477 个样本,性能又提高了 32% (!!)。

        图编译改变训练步骤的方式在 TensorBoard 插件的不同视图中非常明显。例如,内核视图指示使用新的(融合的)GPU 内核,而跟踪视图(如下所示)显示的模式与我们之前看到的完全不同。

Results of Graph Compilation in the TensorBoard Profiler Trace View Tab (Captured by Author)

四、Interim Results

In the table below we summarize the results of the successive optimizations we have applied.

Performance Results Summary (By Author)

通过使用 PyTorch Profiler 和 TensorBoard 插件应用我们的迭代分析和优化方法,我们能够将性能提高 817%!!

        我们的工作完成了吗?绝对不行!我们实施的每项优化都会发现新的潜在性能改进机会。这些机会以释放资源的形式呈现(例如,转向混合精度使我们能够增加批量大小的方式)或新发现的性能瓶颈的形式(例如,我们的最终优化发现主机到设备数据传输中的瓶颈的方式)。此外,还有许多其他众所周知的优化形式,我们在这篇文章中没有尝试(例如,见这里和这里)。最后,新的库优化(例如,我们在步骤 7 中演示的模型编译功能)一直在发布,进一步实现了我们的性能改进目标。正如我们在简介中强调的那样,要充分利用这些机会,性能优化必须是开发工作流程中迭代且一致的部分。

五、总结

        在这篇文章中,我们展示了玩具分类模型性能优化的巨大潜力。尽管您可以使用其他性能分析器,每种分析器都有其优点和缺点,但我们选择了PyTorch Profiler和TensorBoard插件,因为它们易于集成。

        我们应该强调的是,成功优化的路径会因训练项目的细节而有很大差异,包括模型架构和训练环境。在实践中,实现目标可能比我们在此处介绍的示例更困难。我们描述的一些技术可能对您的表现几乎没有影响,甚至可能使情况变得更糟。我们还注意到,我们选择的精确优化以及我们选择应用它们的顺序有些武断。我们强烈建议您开发自己的工具和技术,以根据项目的具体细节实现优化目标。

        机器学习工作负载的性能优化有时被视为次要的、非关键的和可恶的。我希望我们已经成功地说服您,节省开发时间和成本的潜力值得在性能分析和优化方面进行有意义的投资。而且,嘿,你甚至可能会发现它很有趣:)。

接下来呢?

这只是冰山一角。性能优化的内容比我们在这里介绍的要多得多。在这篇文章的续集中,我们将深入探讨一个在 PyTorch 模型中很常见的性能问题,其中部分计算在 CPU 而不是 GPU 上运行,通常是以开发人员不知道的方式运行的。我们还鼓励您查看我们在 medium 上的其他帖子,其中许多文章涵盖了机器学习工作负载性能优化的不同元素。

相关文章:

PyTorch 模型性能分析和优化 — 第 1 部分

一、说明 这篇文章的重点将是GPU上的PyTorch培训。更具体地说,我们将专注于 PyTorch 的内置性能分析器 PyTorch Profiler,以及查看其结果的方法之一,即 PyTorch Profiler TensorBoard 插件。 二、深度框架 训练深度学习模型,尤其是…...

Unity3D 简易音频管理器

依赖于Addressable 依赖于单例模板&#xff1a;传送门 using System.Collections.Generic; using System.Security.Cryptography; using System; using UnityEngine; using UnityEngine.AddressableAssets;namespace EasyAVG {public class AudioManager : MonoSingleton<…...

【李沐深度学习笔记】线性回归

课程地址和说明 线性回归p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性回归 如何在美国买房&#xff08;经典买房预测问题&#xff09; 一个简化的模型 线性模型 其中&#xff0c; x → [ x 1 , x 2 ,…...

微信收款码费率0.38太坑了

作为一个有多年运营经验的商家&#xff0c;我本人在申请收款功能时曾经走过了不少弯路。我找遍了市面上的知名的支付公司&#xff0c;但了解到的收款手续费率通常都在0.6左右&#xff0c;最低也只能降到0.38。这个过程吃过不少苦头。毕竟&#xff0c;收款功能是我们商家的命脉&…...

【学习笔记】CF1103D Professional layer

首先分析不出啥性质&#xff0c;所以肯定是暴力优化&#x1f605; 常见的暴力优化手段有均摊&#xff0c;剪枝&#xff0c;数据范围分治&#xff08;points&#xff09;&#xff0c;答案值域分析之类的。 比较经典的题目是 CF1870E Another MEX Problem&#xff0c;可以用剪枝…...

vue之Pinia

定义 Store | Pinia 开发文档 1.什么是Pinaia Pinia 是 Vue 的专属状态管理库&#xff0c;它允许你跨组件或页面共享状态。 2.理解Pinaia核心概念 定义Store 在深入研究核心概念之前&#xff0c;我们得知道 Store 是用 defineStore() 定义的&#xff0c;它的第一个参数要求是一…...

antd-vue 级联选择器默认值不生效解决方案

一、业务场景&#xff1a; 最近在使用Vue框架和antd-vue组件库的时候&#xff0c;发现在做编辑回显时** 级联选择器** 组件的默认值不生效。为了大家后面遇到和我一样的问题&#xff0c;给大家分享一下 二、bug信息&#xff1a; 三、问题原因&#xff1a; 确定不了唯一的值&a…...

分享53个Python源码源代码总有一个是你想要的

分享53个Python源码源代码总有一个是你想要的 链接&#xff1a;https://pan.baidu.com/s/1ew3w2_DXlSBrK7Mybx3Ttg?pwd8888 提取码&#xff1a;8888 项目名称 100-Python ControlXiaomiDevices DRF-ADMIN 后台管理系统 FishC-Python3小甲鱼 Flask框架的api项目脚手架 …...

【每日一题】658. 找到 K 个最接近的元素

658. 找到 K 个最接近的元素 - 力扣&#xff08;LeetCode&#xff09; 给定一个 排序好 的数组 arr &#xff0c;两个整数 k 和 x &#xff0c;从数组中找到最靠近 x&#xff08;两数之差最小&#xff09;的 k 个数。返回的结果必须要是按升序排好的。 整数 a 比整数 b 更接近 …...

并发任务队列(字节青训测试题)

需求描述 封装一个并发任务队列类&#xff0c;用于对一些异步任务按指定的并发数量进行并发执行。 /*** 延迟函数* param {number} time - 延迟时间* return {Promise} delayFn - 延迟函数(异步封装)*/ function timeout(time) {return new Promise((resolve) > {setTimeo…...

Ubuntu 安装Nacos

1、官网下载最新版nacos https://github.com/alibaba/nacos/releases 本人环境JDK8&#xff0c;Maven3.6.3&#xff0c;启动Nacos2.2.1启动失败&#xff0c;故切换到2.1.0启动成功 2、放到服务器目录下&#xff0c;我的在/home/xxx/apps下 3、解压 $ tar -zxvf nacos-serve…...

CSS 小球随着椭圆移动

html代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><…...

【李沐深度学习笔记】线性代数

课程地址和说明 线性代数p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性代数 标量 标量&#xff08;scalar&#xff09;&#xff0c;亦称“无向量”。有些物理量&#xff0c;只具有数值大小&#xff0c…...

vuejs - - - - - 递归组件的实现

递归组件的实现 1. 需求描述&#xff1a;2. 效果图&#xff1a;3. 代码3.1 封装组件代码3.2 父组件使用 1. 需求描述&#xff1a; 点击添加行&#xff0c;增加一级目录结构当类型为object or array时&#xff0c;点击右侧➕&#xff0c;增加子集点击右侧&#x1f6ae;&#x…...

精准对接促合作:飞讯受邀参加市工信局举办的企业供需对接会

2023年9月21日&#xff0c;由惠州市工业和信息化局主办的惠州市工业软件企业与制造业企业供需对接会成功举办&#xff0c;对接会旨在促进本地工业软件企业与制造业企业的紧密合作&#xff0c;推动数字化转型的深入发展。此次会议在市工业和信息化局16楼会议室举行&#xff0c;会…...

数学建模之遗传算法

文章目录 前言遗传算法算法思想生物的表示初始种群的生成下一代种群的产生适应度函数轮盘赌交配变异混合产生新种群 停止迭代的条件遗传算法在01背包中的应用01背包问题介绍01背包的其它解法01背包的遗传算法解法生物的表示初始种群的生成下一代种群的产生适应度函数轮盘赌交配…...

ISO9001认证常见的不符合项

今天&#xff0c;整理了一些关于ISO9001质量管理体系审核最常见的不合格项&#xff0c;以供大家参考。 一、质量管理体系 1、质量手册&#xff08;标准条款4.2.2&#xff09; &#xff08;1&#xff09;各部门执行的文件与手册的规定不一致。 &#xff08;2&#xff09;质量…...

crypto:看我回旋踢

题目 下载压缩包后解压可得到提示文本 经过观察&#xff0c;synt{}这个提示与flag{}形式很像 由题目名中的回旋可以推测为凯撒密码&#xff0c;由凯撒密码的定义可知&#xff0c;需要先推出移位数&#xff0c;s->f数13次&#xff0c;因此移位数为13&#xff0c;解码可得...

Springcloud实战之自研分布式id生成器

一&#xff0c;背景 日常开发中&#xff0c;我们需要对系统中的各种数据使用 ID 唯一表示&#xff0c;比如用户 ID 对应且仅对应一个人&#xff0c;商品 ID 对应且仅对应一件商品&#xff0c;订单 ID 对应且仅对应 一个订单。我们现实生活中也有各种 ID &#xff0c;比如身…...

java 企业工程管理系统软件源码 自主研发 工程行业适用

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...

Spring Cloud Alibaba Nacos 2.2.3 (4) - 本地源码编译 调试

下载nacos nacos在GitHub上有下载地址&#xff1a;https://github.com/alibaba/nacos/releases&#xff0c;可以选择任意版本下载。 我下载的是2.2.3 版本 导入idea mvn 安装包 1&#xff0c;切换到Terminal ,并且使用command prompt模式 2&#xff0c;执行 mvn -Prelease…...

WKB近似

WKB方法用于研究一种特定类型的微分方程的全局性质 很有用这种特定的微分方程形如&#xff1a; 经过一些不是特别复杂的推导&#xff0c;我们可以得到他的WKB近似解。 该近似解的选择取决于函数和参数的性质同时&#xff0c;我们默认函数的定义域为当恒大于零,时&#xff1a; 当…...

LeetCode算法二叉树—108. 将有序数组转换为二叉搜索树

目录 108. 将有序数组转换为二叉搜索树 代码&#xff1a; 运行结果&#xff1a; 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不…...

如何设置 Git 短命令

设置 Git 短命令 对喜欢敲命令而不用图形化工具的爱好者来说&#xff0c;设置短命令可以很好的提高效率。下面介绍两种设置短命令的方式。 方式一 git config --global alias.ps push方式二 打开全局配置文件 vim ~/.gitconfig写入内容 [alias] co checkoutps pushpl p…...

virtualbox无界面打开linux虚拟机的bat脚本,以及idea(代替Xshell)连接linux虚拟机的方法

virtualbox无界面打开linux虚拟机的bat脚本&#xff0c;以及idea连接linux虚拟机的方法 命令行运行代码成功运行的效果图 idea连接linux虚拟机的方法【重要】查看虚拟机的IP地址idea中选择菜单&#xff08;该功能可代替Xshell软件&#xff09;配置设置连接成功进入idea中的命令…...

mockito 的 InjectMocks 和 Mock 有什么区别?

InjectMocks 和 Mock 是 Mockito 框架中用于测试的注解&#xff0c;用于创建和管理模拟对象&#xff08;mocks&#xff09;的不同方式。它们有以下区别&#xff1a; InjectMocks&#xff1a; InjectMocks 用于注入模拟对象&#xff08;mocks&#xff09;到被测试对象&#xf…...

网络工程师的爬虫技术之路:跨界电商与游戏领域的探索

随着数字化时代的到来&#xff0c;跨界电商和游戏行业成为了网络工程师们充满机遇的领域。这两个领域都依赖于高度复杂的技术来实现商业目标和提供卓越的用户体验。本文将深入探讨网络工程师在跨界电商和游戏领域的技术挑战以及应对这些挑战的方法。 突破技术障碍的爬虫应用 …...

【TCP】确认应答 与 超时重传

确认应答 与 超时重传 一. 确认应答机制二. 超时重传机制 一. 确认应答机制 确认应答: 保障可靠传输的核心机制。 可靠传输: 不是指传输过去的数据不出错, 也不是指数据一定能传输过去&#xff0c;而是指发送方能够知道接收方是否接收到了数据。确认应答的关键就是接收方收到数…...

Kubernetes中Pod的扩缩容介绍

Kubernetes中Pod的扩缩容介绍 在实际生产系统中&#xff0c;我们经常会遇到某个服务需要扩容的场景&#xff0c;也可能会遇到由于资源紧张或者工作负载降低而需 要减少服务实例数量的场景。此时可以利用 Deployment/RC 的 Scale 机制来完成这些工作。 Kubernetes 对 Pod 的扩…...

vue点击pdf文件直接在浏览器中预览文件

好久没有更新文章了&#xff0c;说说为什么会有这篇文章呢&#xff0c;其实是应某个热线评论的要求出的&#xff0c;不过由于最近很长一段时间没打开csdn现在才看到&#xff0c;所以才会导致到现在才出。 先来看看封装完这个预览方法的使用&#xff0c;主打一个方便使用&#x…...