pytorch多GPU训练教程

在这里插入图片描述

pytorch多GPU训练教程

文章目录

  • pytorch多GPU训练教程
    • 1. Torch 的两种并行化模型封装
      • 1.1 DataParallel
      • 1.2 DistributedDataParallel
    • 2. 多GPU训练的三种架构组织方式
      • 2.2 数据不拆分,模型拆分(Model Parallelism)
      • 2.3 数据拆分,模型拆分(Pipeline Parallelism)
    • 3. NCCL以及DistributedSampler
      • 3.1 NCCL
      • 3.2 常见参数
      • 3.3 DistributedSampler
      • 4.2 多卡训练多进程调试办法(Pycharm为例)
    • 附:参考链接

1. Torch 的两种并行化模型封装

1.1 DataParallel

DataParallel 是 PyTorch 提供的一种数据并行方法,用于在单台机器上的多个 GPU 上进行模型训练。它通过将输入数据划分成多个子部分(mini-batches),并将这些子部分分配给不同的 GPU,以实现并行计算。
在前向传播过程中,输入数据会被划分成多个副本并发送到不同的设备(device)上进行计算。模型(module)会被复制到每个设备上,这意味着输入的批次(batch)会被平均分配到每个设备,但模型会在每个设备上有一个副本。每个模型副本只需要处理对应的子部分。需要注意的是,批次大小应大于GPU数量。在反向传播过程中,每个副本的梯度会被累加到原始模型中。总结来说,DataParallel会自动将数据切分并加载到相应的GPU上,将模型复制到每个GPU上,进行正向传播以计算梯度并汇总。
注意:DataParallel是单进程多线程的,仅仅能工作在单机中。
封装示例:

import torch
import torch.nn as nn
import torch.optim as optim

# 定义模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)

# 初始化模型
model = SimpleModel()

# 使用 DataParallel 将模型分布到多个 GPU 上
model = nn.DataParallel(model)

1.2 DistributedDataParallel

DistributedDataParallel (DDP) 是 PyTorch 提供的一个用于分布式数据并行训练的模块,适用于单机多卡和多机多卡的场景。相比于 DataParallel,DDP 更加高效和灵活,能够在多个 GPU 和多个节点上进行并行训练。
DistributedDataParallel是多进程的,可以工作在单机或多机器中。DataParallel通常会慢于DistributedDataParallel。所以目前主流的方法是DistributedDataParallel。
封装示例:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

def main(rank, world_size):
    # 初始化进程组
    dist.init_process_group("nccl", rank=rank, world_size=world_size)
    
    # 创建模型并移动到GPU
    model = SimpleModel().to(rank)
    
    # 包装模型为DDP模型
    ddp_model = DDP(model, device_ids=[rank])
    

if __name__ == "__main__":
    import os
    import torch.multiprocessing as mp

    # 世界大小:总共的进程数
    world_size = 4
    
    # 使用mp.spawn启动多个进程
    mp.spawn(main, args=(world_size,), nprocs=world_size, join=True)

2. 多GPU训练的三种架构组织方式


由于上一节的讨论,本节所有源码均由DDP封装实现。
###2.1 数据拆分,模型不拆分(Data Parallelism)
数据并行(Data Parallelism)将输入数据拆分成多个子部分(mini-batches),并分配给不同的 GPU 进行计算。每个 GPU 上都有一份完整的模型副本。这种方式适用于模型相对较小,但需要处理大量数据的场景。
由于下面的代码涉及了rank、world_size等概念,这里先做一下简要普及。
** Rank**
rank 是一个整数,用于标识当前进程在整个分布式训练中的身份。每个进程都有一个唯一的 rank。rank 的范围是 0 到 world_size - 1。

  • 用于区分不同的进程。
  • 可以根据 rank 来分配不同的数据和模型部分。

World Size
world_size 是一个整数,表示参与分布式训练的所有进程的总数。

  • 确定分布式训练中所有进程的数量。
  • 用于初始化通信组,确保所有进程能够正确地进行通信和同步。

Backend
backend 指定了用于进程间通信的后端库。常用的后端有 nccl(适用于 GPU)、gloo(适用于 CPU 和 GPU)和 mpi(适用于多种设备)。

  • 决定了进程间通信的具体实现方式。
  • 影响训练的效率和性能。

Init Method
init_method 指定了初始化分布式环境的方法。常用的初始化方法有 TCP、共享文件系统和环境变量。

  • 用于设置进程间通信的初始化方式,确保所有进程能够正确加入到分布式训练中。

Local Rank
local_rank 是每个进程在其所在节点(机器)上的本地标识。不同节点上的进程可能会有相同的 local_rank。

  • 用于将每个进程绑定到特定的 GPU 或 CPU。
import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mp

class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)

def train(rank, world_size):
    dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)
    
    model = SimpleModel().to(rank)
    ddp_model = DDP(model, device_ids=[rank])
    
    criterion = nn.MSELoss().to(rank)
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)
    
    inputs = torch.randn(64, 10).to(rank)
    targets = torch.randn(64, 1).to(rank)
    
    outputs = ddp_model(inputs)
    loss = criterion(outputs, targets)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    dist.destroy_process_group()

if __name__ == "__main__":
    world_size = 4
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

2.2 数据不拆分,模型拆分(Model Parallelism)

模型并行(Model Parallelism)将模型拆分成多个部分,并分配给不同的 GPU。输入数据不拆分,但需要通过不同的 GPU 处理模型的不同部分。这种方式适用于模型非常大,单个 GPU 无法容纳完整模型的场景。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mp

class ModelParallelModel(nn.Module):
    def __init__(self):
        super(ModelParallelModel, self).__init__()
        self.fc1 = nn.Linear(10, 10).to('cuda:0')
        self.fc2 = nn.Linear(10, 1).to('cuda:1')

    def forward(self, x):
        x = x.to('cuda:0')
        x = self.fc1(x)
        x = x.to('cuda:1')
        x = self.fc2(x)
        return x

def train(rank, world_size):
    dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)
    
    model = ModelParallelModel()
    ddp_model = DDP(model, device_ids=[rank])
    
    criterion = nn.MSELoss().to('cuda:1')
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)
    
    inputs = torch.randn(64, 10).to('cuda:0')
    targets = torch.randn(64, 1).to('cuda:1')
    
    outputs = ddp_model(inputs)
    loss = criterion(outputs, targets)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    dist.destroy_process_group()

if __name__ == "__main__":
    world_size = 2
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

2.3 数据拆分,模型拆分(Pipeline Parallelism)

流水线并行(Pipeline Parallelism)结合了数据并行和模型并行。输入数据和模型都被拆分成多个部分,每个 GPU 处理部分数据和部分模型。这种方式适用于需要平衡计算和内存需求的大规模深度学习任务。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mp

class PipelineParallelModel(nn.Module):
    def __init__(self):
        super(PipelineParallelModel, self).__init__()
        self.fc1 = nn.Linear(10, 10)
        self.fc2 = nn.Linear(10, 1)

    def forward(self, x):
        if self.fc1.weight.device != x.device:
            x = x.to(self.fc1.weight.device)
        x = self.fc1(x)
        if self.fc2.weight.device != x.device:
            x = x.to(self.fc2.weight.device)
        x = self.fc2(x)
        return x

def train(rank, world_size):
    dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)
    
    model = PipelineParallelModel()
    model.fc1.to('cuda:0')
    model.fc2.to('cuda:1')
    
    ddp_model = DDP(model)
    
    criterion = nn.MSELoss().to('cuda:1')
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)
    
    inputs = torch.randn(64, 10).to('cuda:0')
    targets = torch.randn(64, 1).to('cuda:1')
    
    outputs = ddp_model(inputs)
    loss = criterion(outputs, targets)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    dist.destroy_process_group()

if __name__ == "__main__":
    world_size = 2
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

3. NCCL以及DistributedSampler

3.1 NCCL

NCCL是一个Nvidia专门为多GPU之间提供集合通讯的通讯库,或者说是一个多GPU卡通讯的框架 ,它具有一定程度拓扑感知的能力,提供了包括AllReduce、Broadcast、Reduce、AllGather、ReduceScatter等集合通讯API,也支持用户去使用ncclSend()、ncclRecv()来实现各种复杂的点对点通讯,如One-to-all、All-to-one、All-to-all等,在绝大多数情况下都可以通过服务器内的PCIe、NVLink、NVSwitch等和服务器间的RoCEv2、IB、TCP网络实现高带宽和低延迟。它解决了前文提到的GPU间拓补识别、GPU间集合通信优化的问题。NCCL屏蔽了底层复杂的细节,向上提供API供训练框架调用,向下连接机内机间的GPU以完成模型参数的高效传输。

3.2 常见参数

修改环境变量或在nccl.conf中修改相关参数选项。可以改变通信特点,进而起到影响通行性能的作用。
NCCL_P2P_DISABLE 默认是开启P2P通信的,这样一般会更高效,用到点对点通信延迟会有所改善,带宽也是。
NCCL_P2P_LEVEL 开启P2P后可以设置P2P的级别,比如在那些特定条件下可以开启点对点通信,具体的可以参看文档(0-5)
NCCL_SOCKET_NTHREADS 增加它的数量可以提高socker传输的效率,但是会增加CPU的负担
NCCL_BUFFLE_SIZE 缓存数据量,缓存越大一次ring传输的数据就越大自然对带宽的压力最大,但是相应的总延迟次数会少。缺省值是4M(4194304),注意设置的时候使用bytes(字节大小)
NCCL_MAX/MIN_NCHANNELS 最小和最大的rings,rings越多对GPU的显存、带宽的压力都越大,也会影响计算性能
NCCL_CHECKS_DISABLE 在每次集合通信进行前对参数检验校对,这会增加延迟时间,在生产环境中可以设为1.缺省是0
NCCL_CHECK_POINTERS 在每次集合通信进行前对CUDA内存 指针进行校验,这会增加延迟时间,在生产环境中可以设为1.缺省是0
NCCL_NET_GDR_LEVEL GDR触发的条件,默认是当GPU和NIC挂载一个swith上面时使用GDR
NCCL_IGNORE_CPU_AFFINITY 忽略CPU与应用的亲和性使用GPU与nic的亲和性为主
NCCL_ALGO 通信使用的算法,ring Tree Collnet
NCCL_IB_HCA 代表IB使用的设备:Mellanox mlx5系列的HCA设备
A40(GPU3-A40:596:596 [2] NCCL INFO NET/IB : Using [0]mlx5_0:1/IB ; OOB ib0:66.66.66.211<0>),
V100(gpu196-v100:786:786 [5] NCCL INFO NET/IB : Using [0]mlx5_0:1/IB [1]mlx5_1:1/IB ; OOB ib0:66.66.66.110<0>),
A100(GPU6-A100:686:686 [1] NCCL INFO NET/IB : Using [0]mlx5_0:1/RoCE [1]mlx5_2:1/IB [2]mlx5_3:1/IB ; OOB ib0:66.66.66.128<0>),
NCCL_IB_HCA=mlx5 会默认轮询所有的设备。
NCCL_IB_HCA=mlx5_0:1 指定其中一台设备。
a100有两个口,如果都开的话,会出现训练的浮动;如果指定只使用一个口,训练速度会下降。

3.3 DistributedSampler

DistributedSampler原理如图所示:假设当前数据集有0~10共11个样本,使用2块GPU计算。首先打乱数据顺序,然后用 11/2 =6(向上取整),然后6乘以GPU个数2 = 12,因为只有11个数据,所以再把第一个数据(索引为6的数据)补到末尾,现在就有12个数据可以均匀分到每块GPU。然后分配数据:间隔将数据分配到不同的GPU中。

BatchSampler原理: DistributedSmpler将数据分配到两个GPU上,以第一个GPU为例,分到的数据是6,9,10,1,8,7,假设batch_size=2,就按顺序把数据两两一组,在训练时,每次获取一个batch的数据,就从组织好的一个个batch中取到。注意:只对训练集处理,验证集不使用BatchSampler。

train_dset = NBADataset(
    obs_len=self.cfg.past_frames,
    pred_len=self.cfg.future_frames,
    training=True)

self.train_sampler = torch.utils.data.distributed.DistributedSampler(train_dset)
self.train_loader = DataLoader(train_dset, batch_size=self.cfg.train_batch_size, sampler=self.train_sampler,
                               num_workers=4, collate_fn=seq_collate)

##4. 多进程启动综合测试
###4.1 多卡训练多进程启动的两种方式
多卡训练启动有两种方式,其一是pytorch自带的torchrun,其二是自行设计多进程程序。

以下为torch,distributed.launch的简单demo:
运行方式为

# 直接运行
torchrun --nproc_per_node=4 test.py
# 等价方式
python -m torch.distributed.launch --nproc_per_node=4 test.py

torchrun实际上运行的是/usr/local/mambaforge/envs/led/lib/python3.7/site-packages/torch/distributed/launch.py(根据读者的环境变化)
python -m torch.distributed.launch也会找到这个程序的python文件执行,这个命令会帮助设置一些环境变量启动backend,否则需要自行设置环境变量。

import torch
import torch.distributed as dist
import torch.multiprocessing as mp
import torch.nn as nn
import torch.optim as optim
from torch.nn.parallel import DistributedDataParallel as DDP
import os


def example(rank, world_size):
    # create default process group
    dist.init_process_group("nccl", rank=rank, world_size=world_size)
    # create local model
    model = nn.Linear(10, 10).to(rank)
    # construct DDP model
    ddp_model = DDP(model, device_ids=[rank])
    # define loss function and optimizer
    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)

    # forward pass
    outputs = ddp_model(torch.randn(20, 10).to(rank))
    labels = torch.randn(20, 10).to(rank)
    # backward pass
    loss_fn(outputs, labels).backward()
    # update parameters
    optimizer.step()

def main():
    world_size = 2
    mp.spawn(example,
        args=(world_size,),
        nprocs=world_size,
        join=True)

if __name__=="__main__":
    # Environment variables which need to be
    # set when using c10d's default "env"
    # initialization mode.
    os.environ["MASTER_ADDR"] = "localhost"
    os.environ["MASTER_PORT"] = "10086"
    main()
以下为multiprocessing的设计demo
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP

def setup(rank, world_size):
    dist.init_process_group(
        backend='nccl',
        init_method='tcp://localhost:12355',
        rank=rank,
        world_size=world_size
    )
    torch.cuda.set_device(rank)
    dist.barrier()

def cleanup():
    dist.destroy_process_group()

def demo_basic(rank, world_size):
    setup(rank, world_size)

    model = torch.nn.Linear(10, 10).to(rank)
    ddp_model = DDP(model, device_ids=[rank])

    inputs = torch.randn(20, 10).to(rank)
    outputs = ddp_model(inputs)
    print(f"Rank {rank} outputs: {outputs}")

    cleanup()

def main():
    world_size = torch.cuda.device_count()
    mp.spawn(demo_basic, args=(world_size,), nprocs=world_size, join=True)

if __name__ == "__main__":
    main()

4.2 多卡训练多进程调试办法(Pycharm为例)

首先如果读者使用的是multiprocessing的方式,那么直接使用本地工具运行和调试即可,如果使用torchrun的方式,那么我们需要手动配置Run/Debug Configurations,根据4.1,我们要找到原型文件launch.py,以笔者的环境为例,我的launch文件在/usr/local/mambaforge/envs/led/lib/python3.7/site-packages/torch/distributed/launch.py,添加一个配置,笔者命名为torchrun,在Script path一列选择launch.py,参数

在torchrun等方式下,我们可以看到其实有多个进程或线程启动,而默认的调试窗口只能提供主进程的代码流程断点,此时需要看启动进程的pid

根据pid绑定到对应的进程上


可以看到断点可以断住第二块卡的程序了

测试代码,启动方式torchrun

import time

import torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optim

from torch.nn.parallel import DistributedDataParallel as DDP

class ToyModel(nn.Module):
    def __init__(self):
        super(ToyModel, self).__init__()
        self.net1 = nn.Linear(10, 10)
        self.relu = nn.ReLU()
        self.net2 = nn.Linear(10, 5)

    def forward(self, x):
        return self.net2(self.relu(self.net1(x)))


def demo_basic():
    dist.init_process_group("nccl")
    rank = dist.get_rank()
    print(f"Start running basic DDP example on rank {rank}.")

    # create model and move it to GPU with id rank
    device_id = rank % torch.cuda.device_count()
    model = ToyModel().to(device_id)
    time.sleep(10)
    print("DDP model init start...")
    ddp_model = DDP(model, device_ids=[device_id])
    print("DDP model init end...")

    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)

    optimizer.zero_grad()
    outputs = ddp_model(torch.randn(20, 10))
    labels = torch.randn(20, 5).to(device_id)
    loss_fn(outputs, labels).backward()
    optimizer.step()

if __name__ == "__main__":
    demo_basic()

注意:强制终止DDP的程序可能会使得显存占用未释放,此时需要找出nccl监听的端口,例如笔者是29500

附:参考链接

DP与DDP的区别:https://zhuanlan.zhihu.com/p/343951042?utm_id=0
DDP初始化:https://www.cnblogs.com/rossiXYZ/p/15584032.html
常见卡死问题:https://blog.csdn.net/weixin_42001089/article/details/122733667
https://www.cnblogs.com/azureology/p/16632988.html
https://github.com/IDEA-CCNL/Fengshenbang-LM/issues/123
NCCL:https://zhuanlan.zhihu.com/p/667221519
NCCL参数:https://zhuanlan.zhihu.com/p/661597951
init_process_group:https://blog.csdn.net/m0_37400316/article/details/107225030
参数检测:https://blog.csdn.net/weixin_46552088/article/details/138687997
分布式训练架构:https://zhuanlan.zhihu.com/p/689464092
https://zhuanlan.zhihu.com/p/706298084

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/930409.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用el-row和el-col混合table设计栅格化,实现表头自适应宽度,表格高度占位

演示效果&#xff1a; 如上图,由于地址信息很长,需要占多个格子,所以需要错开,若想实现这种混合效果,可以这样搭建: 页面效果&#xff1a; 代码分析: 上面使用el-row和el-col搭建表单显示 第一排三个8,第二排8和16 下面混合table实现&#xff0c;并使用border来自适应宽度…

WPS解决Word文件引入excel对象文件无法打开提示“不能启动此对象...”的问题

一、问题现象 接收到了一份 Word文件&#xff0c;里面引入了一个Excel对象文件&#xff0c;双击时候&#xff0c;wps出现卡顿&#xff0c;过一会之后弹出错误提示&#xff1a;不能启动此对象... 二、解决方法 1.点击WPS左上角图标&#xff0c;并打开右上角设置&#xff0c;萱蕚…

JAVA (Springboot) i18n国际化语言配置

JAVA i18n国际化语言配置 一、简介二、功能三、Java配置国际化步骤四、Java国际化配置工具类五、Spring Boot配置六、测试 一、简介 在Java中&#xff0c;国际化&#xff08;Internationalization&#xff0c;通常简称为i18n&#xff09;是一个过程&#xff0c;它允许应用程…

Jenkins 中自定义Build History中显示构建信息

有时候会遇到一个代码仓库下面会有多个不同的分支&#xff0c;而这写分支表示着不同的开发者在开发新的需求&#xff0c;但是这样就会出现一个问题&#xff0c;在Jenkins上进行多分支构建的时候&#xff0c;很难找到哪一个是属于自己分支构建的&#xff0c;这样的问题大家应该都…

springboot安康旅游网站的设计与实现(代码+数据库+LW)

目 录 目 录 摘 要 Abstract 第一章 绪论 1.1 研究现状 1.2 设计原则 1.3 研究内容 第二章 相关技术简介 2.1 JSP技术 2.2 Java技术 2.3 MYSQL数据库 2.4 B/S结构 2.5 Spring Boot框架 第三章 系统分析 3.1可行性分析 3.1.1技术可行性 …

asp.net core过滤器应用

筛选器类型 授权筛选器 授权过滤器是过滤器管道的第一个被执行的过滤器&#xff0c;用于系统授权。一般不会编写自定义的授权过滤器&#xff0c;而是配置授权策略或编写自定义授权策略。简单举个例子。 using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCo…

深入体验c语言中const的多种多样的用法

const是一个C语言&#xff08;ANSI C&#xff09;的关键字&#xff0c;它限定一个变量不允许被改变&#xff0c;一定程序上提高程序的安全性和可靠性。虽然这个关键字看起来简单&#xff0c;但是实际上随着它限定位置不一样&#xff0c;产生的效果也各异。 一、const作用 cons…

齐护机器人ModbusRTU RS485转TTL通信模块与ESP32 Arduino通信可Mixly的图形化编程Scratch图形化编程

齐护机器人ModbusRTU RS485-TTL通信模块 一、概念理解 Modbus协议是一种由Modicon公司&#xff08;现为施耐德电气Schneider Electric&#xff09;于1979年发表的网络通信协议&#xff0c;旨在实现可编辑逻辑控制器&#xff08;PLC&#xff09;之间的通信。 1.1 什么是Mod…

【动手学运动规划】 4.5 A*算法

我宁愿永远做我自己&#xff0c;也不愿成为别人&#xff0c;即使那个人比你更快乐。 —《成为简奥斯汀》 &#x1f3f0;代码及环境配置&#xff1a;请参考 环境配置和代码运行! 4.5.1 概述 Dijkstra算法是基于广度优先搜索策略来遍历空间内的所有节点&#xff0c;最终计算出…

一些引入依赖,提示引入方式报错的问题

背景 当我们使用gulp自动化处理文件的时候&#xff0c;难免会遇到需要按照一定条件过滤的需求&#xff0c;这里博主所遇到问题是&#xff0c;通过文件内容中是否包含 某一串字符串 决定过滤当前的文件 比如&#xff1a; 碰到文件中包含注释 * replace-note 此文件未被引用 ,那…

十二月第二周

作业题&#xff1a; 嵌套循环穷举&#xff0c;先看一道题也是今天作业题&#xff1a; 重点掌握题&#xff1a; 接下来&#xff0c;我们看一下未来要学习的内容&#xff1a;数组 数组基本用法如下&#xff1a; 扩展题&#xff1a;

PyTorch环境迁移指南

在进行深度学习研究和开发时,我们经常需要在不同计算机之间迁移PyTorch环境。无论是更换新设备还是在多台机器间协同工作,都需要确保环境配置的一致性。本文将详细介绍PyTorch环境迁移的完整流程和注意事项。 环境迁移看似简单,实则暗藏玄机。直接复制文件可能会遇到系统差异带…

QGroundControl之4-QGCCorePlugin.cc

介绍 核心控件接口 Core Plugin Interface for QGroundControl 。主要看settingsPages、analyzePages、instrumentPages 等&#xff0c;这里明显看出配置了不同类型toolbar按钮对应的页面 1.MainRootWindow.qml MainRootWindow.qml页面中使用 AppSettings.qml 2.AppSettings.…

tomcat 运行加载机制解析

tomcat 运行加载机制 从tomcat jar包的加载顺序&#xff1a; tomcat的具体运行加载 可以从 start、setclasspath、catalina文件中看出来&#xff1a; start.bat执行 去找bin目录下的catalina.bat,catalina 或去找 bin\setenv.bat以获取标准环境变量&#xff0c;然后去找bin\…

【机器学习 | 基于Lasso回归和随机森林的上海链家二手房房价预测】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 去除重复数据2.4 去除缺失数据2.5 面积、价格、单价、楼层、建筑时间数据提取2.6 朝向数据处理 &#x1f3f3;️‍&#x1f308; 3. 特…

npm, yarn, pnpm之间的区别

前言 在现代化的开发中&#xff0c;一个人可能同时开发多个项目&#xff0c;安装的项目越来越多&#xff0c;所随之安装的依赖包也越来越臃肿&#xff0c;而且有时候所安装的速度也很慢&#xff0c;甚至会安装失败。 因此我们就需要去了解一下&#xff0c;我们的包管理器&#…

使用Java将PDF文件解析成Excel文件

安装pom依赖 <!-- 解析pdf--><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.27</version> <!-- 请检查并使用最新版本 --></dependency>测试读取pdf文件…

Celery使用小结

介绍 Celery 是异步任务调度工具就&#xff0c;或分布式任务队列&#xff08;Distributed Task Queue&#xff09;&#xff0c;有多个worker。 Broker&#xff1a;中间人&#xff0c;所有任务放在broker中&#xff0c;worker到broker中提取任务执行。 这样系统为开环系统&am…

java注解(二):注解的解析以及应用场景、用注解和反射模拟junit框架代码演示

目录 1、什么是注解的解析&#xff1f; 2、解析注解的案例 1、自定义一个注解 2、在类和方法上使用自己定义的注解 3、解析注解 3、模拟Junit框架案例 1、自定义一个MyTest注解 2、定义一个测试类&#xff0c;使用自定义的注解 3、写一个启动类 本文章主要讲解什么是注…

VUE脚手架练习

脚手架安装的问题&#xff1a; 1.安装node.js,配置环境变量,cmd输入node -v和npm -v可以看到版本号&#xff08;如果显示不是命令&#xff0c;确认环境变量是否配置成功&#xff0c;记得配置环境变量之后重新打开cmd&#xff0c;再去验证&#xff09; 2.在安装cnmp时&#xf…