【昇腾】从单机单卡到单机多卡训练

昇腾:单机单卡训练->单机多卡训练

分布式训练

(1)单机单卡的训练流程在这里插入图片描述

  • 硬盘读取数据
  • CPU处理数据,将数据组成一个batch
  • 传入GPU
  • 网络前向传播计算loss
  • 网络反向传播计算梯度

(2)PyTorch中最早的数据并行框架:Data Parallel (DP)——单进程、多线程

  • 从硬盘读取数据,通过一个CPU进程将数据分成多份
  • 给每个GPU一份
  • 每个GPU独立进行网络的前向传播、后向传播,计算出各自的梯度
  • 所有其他的GPU都将自己计算出的梯度传递到GPU0上进行平均
  • GPU0通过全局平均的梯度更新自己的网络参数
  • GPU0将更新后的参数广播到其他GPU上
    在这里插入图片描述
    在这里插入图片描述

分布式训练中最关键的问题是如何减少多卡之间的通信量,以提高训练效率。

  • 下面分析一下DP这种模式的通信量:
    假设参数量为 ψ \psi ψ,节点数为 N N N
    对于GPU0,传入梯度为 ( N − 1 ) ψ (N-1)\psi (N1)ψ;传出参数为 ( N − 1 ) ψ (N-1)\psi (N1)ψ
    对于其他GPU,传入梯度为 ψ \psi ψ;传出参数为 ψ \psi ψ
  • DP这种模式存在的问题:
    单进程,多线程,Python GIL只能利用一个CPU核;
    GPU0负责收集梯度,更新参数,广播参数。通信计算压力大。

(3)PyTorch中替代DP的分布式训练框架:Distributed Data Parallel (DDP)——多进程,分布式数据并行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在环形连接的Ring-AllReduce里,每个GPU的负载都是一样的。每个GPU同时发送和接收,可以最大限度利用每个显卡的上下行带宽。

在这里插入图片描述

  • DDP模式是多进程的,每个进程为自己的GPU准备数据并和其他GPU通信,每个进程用各自的数据进行神经网络的前向和反向传播计算自己的梯度。
  • 由于每个进程的数据不同,所以每个batch数据计算出来的梯度也不同,这个时候就需要用Ring-AllReduce的方式同步每个GPU上的梯度,同步后各个GPU上的梯度都相同。
  • 他们用各自的优化器来更新各自的神经网络,网络状态和优化器状态始终保持同步。优化器一样,梯度也一样,保证了优化结果的一致性。

下面分析一下DDP这种模式的通信量:
假设参数量为 ψ \psi ψ,进程数为 N N N
对于每一个GPU进程,
Scatter-Reduce阶段传入/传出: ( N − 1 ) ψ N (N-1) \frac{\psi}{N} (N1)Nψ
AllGather阶段传入/传出: ( N − 1 ) ψ N (N-1) \frac{\psi}{N} (N1)Nψ
总传入传出: 2 ψ 2\psi 2ψ,与集群大小无关

昇腾DDP参考代码——shell版本

(1)华为官方单机多卡训练脚本demo:ddp_test_shell.py

# 导入依赖和库 
import torch 
from torch import nn 
import torch_npu 
import torch.distributed as dist 
from torch.utils.data import DataLoader 
from torchvision import datasets 
from torchvision.transforms import ToTensor 
import time 
import torch.multiprocessing as mp 
import os torch.manual_seed(0) 
# 下载训练数据 
training_data = datasets.FashionMNIST( root="./data", train=True, download=True, transform=ToTensor(), 
) # 下载测试数据 
test_data = datasets.FashionMNIST( root="./data", train=False, download=True, transform=ToTensor(), 
) # 构建模型 
class NeuralNetwork(nn.Module): def __init__(self): super().__init__() self.flatten = nn.Flatten() self.linear_relu_stack = nn.Sequential( nn.Linear(28*28, 512), nn.ReLU(), nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 10) ) def forward(self, x): x = self.flatten(x) logits = self.linear_relu_stack(x) return logits def test(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) model.eval() test_loss, correct = 0, 0 with torch.no_grad(): for X, y in dataloader: X, y = X.to(device), y.to(device) pred = model(X) test_loss += loss_fn(pred, y).item() correct += (pred.argmax(1) == y).type(torch.float).sum().item() test_loss /= num_batches correct /= size print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")def main(world_size: int,  batch_size = 64, total_epochs = 5,):    # 用户可自行设置ngpus_per_node = world_sizemain_worker(args.gpu, ngpus_per_node, args)def ddp_setup(rank, world_size):"""Args:rank: Unique identifier of each processworld_size: Total number of processes"""os.environ["MASTER_ADDR"] = "localhost"    # 用户需根据自己实际情况设置os.environ["MASTER_PORT"] = "29500"    # 用户需根据自己实际情况设置dist.init_process_group(backend="hccl", rank=rank, world_size=world_size)def main_worker(gpu, ngpus_per_node, args):start_epoch = 0end_epoch = 5args.gpu = int(os.environ['LOCAL_RANK'])    # 在shell脚本中循环传入local_rank变量作为指定的deviceddp_setup(args.gpu, args.world_size)torch_npu.npu.set_device(args.gpu)total_batch_size = args.batch_sizetotal_workers = ngpus_per_nodebatch_size = int(total_batch_size / ngpus_per_node)    workers = int((total_workers + ngpus_per_node - 1) / ngpus_per_node)model = NeuralNetwork()device = torch.device("npu")train_sampler = torch.utils.data.distributed.DistributedSampler(training_data)test_sampler = torch.utils.data.distributed.DistributedSampler(test_data)train_loader = torch.utils.data.DataLoader(training_data, batch_size=batch_size, shuffle=(train_sampler is None),num_workers=workers, pin_memory=False, sampler=train_sampler, drop_last=True)val_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=(test_sampler is None),num_workers=workers, pin_memory=False, sampler=test_sampler, drop_last=True)loc = 'npu:{}'.format(args.gpu)model = model.to(loc)criterion = nn.CrossEntropyLoss().to(loc)optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])for epoch in range(start_epoch, end_epoch):train_sampler.set_epoch(epoch)train(train_loader, model, criterion, optimizer, epoch, args.gpu)def train(train_loader, model, criterion, optimizer, epoch, gpu):size = len(train_loader.dataset)model.train()end = time.time()for i, (images, target) in enumerate(train_loader):# measure data loading timeloc = 'npu:{}'.format(gpu)target = target.to(torch.int32)        images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False)# compute outputoutput = model(images)loss = criterion(output, target)# compute gradient and do SGD stepoptimizer.zero_grad()loss.backward()optimizer.step()end = time.time()if i % 100 == 0:loss, current = loss.item(), i * len(target)print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")if __name__ == "__main__":import argparseparser = argparse.ArgumentParser(description='simple distributed training job')parser.add_argument('--batch_size', default=512, type=int, help='Input batch size on each device (default: 32)')parser.add_argument('--gpu', default=None, type=int,help='GPU id to use.')args = parser.parse_args()world_size = torch.npu.device_count()args.world_size = world_sizengpus_per_node = world_sizestart_epoch = 0end_epoch = 5args.gpu = int(os.environ['LOCAL_RANK'])    # 在shell脚本中循环传入local_rank变量作为指定的deviceprint('args.gpu:',args.gpu)ddp_setup(args.gpu, args.world_size)torch_npu.npu.set_device(args.gpu)total_batch_size = args.batch_sizetotal_workers = ngpus_per_nodebatch_size = int(total_batch_size / ngpus_per_node)    workers = int((total_workers + ngpus_per_node - 1) / ngpus_per_node)model = NeuralNetwork()device = torch.device("npu")train_sampler = torch.utils.data.distributed.DistributedSampler(training_data)test_sampler = torch.utils.data.distributed.DistributedSampler(test_data)train_loader = torch.utils.data.DataLoader(training_data, batch_size=batch_size, shuffle=(train_sampler is None),num_workers=workers, pin_memory=False, sampler=train_sampler, drop_last=True)val_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=(test_sampler is None),num_workers=workers, pin_memory=False, sampler=test_sampler, drop_last=True)loc = 'npu:{}'.format(args.gpu)model = model.to(loc)criterion = nn.CrossEntropyLoss().to(loc)optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])for epoch in range(start_epoch, end_epoch):train_sampler.set_epoch(epoch)train(train_loader, model, criterion, optimizer, epoch, args.gpu)

(2)华为官方单机多卡启动脚本demo:run.sh
这里是单机双卡示例:

#!/bin/bash
export HCCL_WHITELIST_DISABLE=1
RANK_ID_START=0
WORLD_SIZE=2
for((RANK_ID=$RANK_ID_START;RANK_ID<$((WORLD_SIZE+RANK_ID_START));RANK_ID++));
doecho "Device ID: $RANK_ID"export LOCAL_RANK=$RANK_IDpython3 /home/work/user-job-dir/app/notebook/RTDosePrediction-main/RTDosePrediction/Src/DCNN/train-2p.py &
done
wait

详细解释

参考代码:https://github.com/pytorch/examples/blob/main/distributed/ddp-tutorial-series/multigpu.py
参考视频:https://www.youtube.com/watch?v=-LAtx9Q6DA8&list=PL_lsbAsL_o2CSuhUhJIiW0IkdT5C2wGWj&index=3

01 导入一些分布式相关的包

(1)torch.multiprocessing
对 Python 标准库 multiprocessing 的扩展,用于在多个进程之间共享和传输 PyTorch 对象,尤其是张量(Tensors)和模型(Models)。在多进程环境中,数据共享是一个挑战。torch.multiprocessing 允许在进程之间共享 PyTorch 张量,这些张量存储在共享内存中,而不是在进程之间复制数据。
(2)import torch.distributed as dist
train_sampler = torch.utils.data.distributed.DistributedSampler(training_data)
在分布式训练环境中对数据集进行采样。这个采样器的设计目的是确保在分布式训练过程中,每个进程只处理数据集的一个子集,这样可以有效地利用多个进程和GPU来加速训练。

(3)torch.nn.parallel
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])
DDP通过在每个进程中创建模型的一个副本,并在每个副本上独立地进行前向和反向传播,从而实现并行计算。在每个训练步骤后,DDP自动同步各个进程计算出的梯度,确保所有进程的模型参数保持一致。DDP使用高效的通信后端(如NCCL)来在进程间同步梯度,这对于GPU之间的通信尤其重要。
(4)torch.distributed
dist.init_process_group(backend="hccl", rank=rank, world_size=world_size)
用于初始化分布式训练的环境。这个函数会设置一个进程组,该进程组是一组进程,它们可以相互通信以进行分布式训练。

02 初始化分布式训练进程组(intitialize the distributed process group)

def ddp_setup(rank, world_size):"""Args:rank: Unique identifier of each processworld_size: Total number of processes"""os.environ["MASTER_ADDR"] = "localhost"    # 用户需根据自己实际情况设置os.environ["MASTER_PORT"] = "29500"    # 用户需根据自己实际情况设置dist.init_process_group(backend="hccl", rank=rank, world_size=world_size)

MASTER_ADDR:the machine that running the rank 0 process
MASTER_PORT:any free port on this machine
(master: the machine coordinates the communication across all of our processes)

dist.init_process_group(backend="hccl", rank=rank, world_size=world_size)中,

  • backend指定了用于进程间通信的后端。华为Ascend NPU通信后端:hccl,用于在NPU上实现高效的分布式通信;NVIDIA通信后端:nccl(nvidia collective communications library)
  • rank参数是当前进程的唯一标识符,通常是一个从0开始的整数。用于确定每个进程应该使用的GPU设备,以及在进行集合通信时如何定位其他进程。
  • world_size指定了进程组中的进程总数,即参与分布式训练的进程数量。如果你有4个NPU,并且你想要在所有4个NPU上进行分布式训练,那么 world_size 应该设置为4。

03 在进行模型训练之前对模型用DDP进行wrap

model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])

04 在模型保存时要记得unwrap

因为我们在上面将模型包装成了一个DDP Object,所以在模型保存时不能直接ckp = model.state_dict()
而要:ckp = model.module.state_dict()
示例代码:

    def _save_checkpoint(self, epoch):ckp = self.model.module.state_dict()PATH = "checkpoint.pt"torch.save(ckp, PATH)print(f"Epoch {epoch} | Training checkpoint saved at {PATH}")

05 确保在分布式训练过程中,每个进程只处理数据集的一个子集:DistributedSampler

train_sampler = torch.utils.data.distributed.DistributedSampler(training_data)
test_sampler = torch.utils.data.distributed.DistributedSampler(test_data)train_loader = torch.utils.data.DataLoader(training_data, batch_size=batch_size, shuffle=(train_sampler is None),num_workers=workers, pin_memory=False, sampler=train_sampler, drop_last=True)val_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=(test_sampler is None),num_workers=workers, pin_memory=False, sampler=test_sampler, drop_last=True)

在Dataloader函数中传入采样器sampler,注意分布式训练时,传入sampler参数后,shuffle需要设为false

06 主函数修改

示例代码:多传入两个参数:rank,world_size

def main(rank: int, world_size: int, save_every: int, total_epochs: int, batch_size: int):ddp_setup(rank, world_size)dataset, model, optimizer = load_train_objs()train_data = prepare_dataloader(dataset, batch_size)trainer = Trainer(model, train_data, optimizer, rank, save_every)trainer.train(total_epochs)destroy_process_group()

注意事项

(1)shell脚本中的python脚本要使用绝对路径,否则会报错:No such file or directory
注:获取绝对路径的方法:直接copy path的不全

import os
# 获取当前文件的绝对路径
current_path = os.path.abspath(__file__)
print(current_path)

(2)在modelmate平台上提交训练任务、启动训练时,可能会报错:Bus error


notebook/RTDosePrediction-main/RTDosePrediction/Src/DCNN/run_8p.sh: line 11:   738 Bus error               (core dumped) python3 /home/work/user-job-dir/app/notebook/RTDosePrediction-main/RTDosePrediction/Src/DCNN/train-8p.py

这个原因未知,多试几次可能又行了。

附件:yotube视频中的代码

import torch
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from datautils import MyTrainDatasetimport torch.multiprocessing as mp
from torch.utils.data.distributed import DistributedSampler
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.distributed import init_process_group, destroy_process_group
import osdef ddp_setup(rank, world_size):"""Args:rank: Unique identifier of each processworld_size: Total number of processes"""os.environ["MASTER_ADDR"] = "localhost"os.environ["MASTER_PORT"] = "12355"torch.cuda.set_device(rank)init_process_group(backend="nccl", rank=rank, world_size=world_size)class Trainer:def __init__(self,model: torch.nn.Module,train_data: DataLoader,optimizer: torch.optim.Optimizer,gpu_id: int,save_every: int,) -> None:self.gpu_id = gpu_idself.model = model.to(gpu_id)self.train_data = train_dataself.optimizer = optimizerself.save_every = save_everyself.model = DDP(model, device_ids=[gpu_id])def _run_batch(self, source, targets):self.optimizer.zero_grad()output = self.model(source)loss = F.cross_entropy(output, targets)loss.backward()self.optimizer.step()def _run_epoch(self, epoch):b_sz = len(next(iter(self.train_data))[0])print(f"[GPU{self.gpu_id}] Epoch {epoch} | Batchsize: {b_sz} | Steps: {len(self.train_data)}")self.train_data.sampler.set_epoch(epoch)for source, targets in self.train_data:source = source.to(self.gpu_id)targets = targets.to(self.gpu_id)self._run_batch(source, targets)def _save_checkpoint(self, epoch):ckp = self.model.module.state_dict()PATH = "checkpoint.pt"torch.save(ckp, PATH)print(f"Epoch {epoch} | Training checkpoint saved at {PATH}")def train(self, max_epochs: int):for epoch in range(max_epochs):self._run_epoch(epoch)if self.gpu_id == 0 and epoch % self.save_every == 0:self._save_checkpoint(epoch)def load_train_objs():train_set = MyTrainDataset(2048)  # load your datasetmodel = torch.nn.Linear(20, 1)  # load your modeloptimizer = torch.optim.SGD(model.parameters(), lr=1e-3)return train_set, model, optimizerdef prepare_dataloader(dataset: Dataset, batch_size: int):return DataLoader(dataset,batch_size=batch_size,pin_memory=True,shuffle=False,sampler=DistributedSampler(dataset))def main(rank: int, world_size: int, save_every: int, total_epochs: int, batch_size: int):ddp_setup(rank, world_size)dataset, model, optimizer = load_train_objs()train_data = prepare_dataloader(dataset, batch_size)trainer = Trainer(model, train_data, optimizer, rank, save_every)trainer.train(total_epochs)destroy_process_group()if __name__ == "__main__":import argparseparser = argparse.ArgumentParser(description='simple distributed training job')parser.add_argument('total_epochs', type=int, help='Total epochs to train the model')parser.add_argument('save_every', type=int, help='How often to save a snapshot')parser.add_argument('--batch_size', default=32, type=int, help='Input batch size on each device (default: 32)')args = parser.parse_args()world_size = torch.cuda.device_count()mp.spawn(main, args=(world_size, args.save_every, args.total_epochs, args.batch_size), nprocs=world_size)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【动手学电机驱动】STM32-FOC(3)STM32 三路互补 PWM 输出

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 三路互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…

docker+nacos

安装数据库 以docker安装为例&#xff08;实际建议实体&#xff09; 初始化数据库 /******************************************/ /* 数据库全名 nacos_config */ /* 表名称 config_info */ /******************************************/ CREATE TABLE config_i…

边缘计算网关如何打造智慧变电站

随着工业化发展&#xff0c;电网规模持续扩大&#xff0c;电力终端设备的数量呈几何级数增长&#xff0c;由此产生了海量的数据传输和处理需求&#xff0c;不仅给服务器主站造成了巨大压力&#xff0c;并且过程中的高时延、高误差也无法满足智能化、自动化等新业务形态的要求。…

Uniapp安装Pinia并持久化(Vue3)

安装pinia 在uni-app的Vue3版本中&#xff0c;Pinia已被内置&#xff0c;无需额外安装即可直接使用&#xff08;Vue2版本则内置了Vuex&#xff09;。 HBuilder X项目&#xff1a;直接使用&#xff0c;无需安装。CLI项目&#xff1a;需手动安装&#xff0c;执行yarn add pinia…

(没有跳过联网激活)导致使用微软账号激活电脑---修改为本地账户和英文名字

修改为本地账户和英文名字 前言微软账号&#xff0c;本地账号与用户名基本知识账户管理方式一方式2 查看账户的sid并且修改文件夹名字和系统变量修改注册表和建立软件路径超链接注意事项总结 前言 当没有联网激活新买的电脑时候&#xff0c;这个就不用看了 当你是联网激活的时…

18、论文阅读:AOD-Net:一体化除雾网络

AOD-Net: All-in-One Dehazing Network 前言介绍相关工作物理模型传统方法深度学习方法 建模与扩展变换后的公式网络设计与高级特征任务相结合 除雾评价数据集和实现 前言 该论文提出了一种基于卷积神经网络&#xff08;CNN&#xff09;的图像去雾模型&#xff0c;称为 All-in…

[ DOS 命令基础 2 ] DOS 命令详解-网络相关命令

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

【docker】6. 镜像仓库/镜像概念

Docker Registry&#xff08;镜像仓库&#xff09; 什么是 Docker Registry 镜像仓库 (Docker Registry) 负责存储、管理和分发镜像&#xff0c;并且提供了登录认证能力&#xff0c;建立了仓库的索引。 镜像仓库管理多个 Repository&#xff0c; Repository 通过命名来区分。…

安装和运行开发微信小程序

下载HBuilder uniapp官网 uni-app官网 微信开发者工具 安装 微信小程序 微信小程序 官网 微信小程序 配置 运行 注意&#xff1a;运行前需要开启服务端口 如果运行看不到效果&#xff0c;设置下基础库选别的版本 配置

[mysql]mysql的DML数据操作语言增删改,以及新特性计算列,阿里巴巴开发手册mysql相关

1DML数据操作语言,增加删除改数据 插入数据INSERT 插入添加数据,两种方法 方式1:VALUES添加数据 #准备工作 USE atguigudb; CREATE TABLE IF NOT EXISTS emp1( id INT, name VARCHAR(15), hire_data DATE, salary DOUBLE(10,2)); SELECT * FROM emp1 INSERT INTO em…

【华为云-云驻共创】UCS跨云多活容灾:让业务高可用不再是难题

【摘要】云原生应用深入到企业各个业务场景&#xff0c;云原生正在走向分布式化&#xff0c;跨云跨域统一协同治理&#xff0c;保证一致应用体验&#xff0c;这些新的需求日益凸显。而容灾是确保服务高可用的保障&#xff0c;但即使应用部署在云上&#xff0c;也无法避免市政方…

R语言生物群落(生态)数据统计分析与绘图丨tidyverse数据清洗、多元统计分析、随机森林、回归及混合效应模型、结构方程模型等

R 语言的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂&#xff0c;涉及众多统计分析方法。内容以生物群落数据分析中的最常用的统计方法回归和混合效应模型、多元统计分析技术及结构方程等数量分析方法为主线&#xff0c;通过多个来自经…

极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果

目录 前言 1.弹性放大按钮效果 2.旋转和缩放组合动画 3.颜色渐变背景动画 4.缩放进出效果 前言 在上一篇文章中&#xff0c;我们介绍了Flutter中的隐式动画的一些相关知识&#xff0c;在这篇文章中,我们可以结合多个隐式动画 Widget 在 Flutter 中创建一些酷炫的视觉效果&…

数字马力二面面试总结

24.03.07数字马力二面面试总结 前段时间找工作,做的一些面试笔记总结 大家有面试录音或者记录的也可以发给我,我来整理答案呀 数字马力二面面试总结 24.03.07数字马力二面面试总结你可以挑一个你的最有挑战性的,有难度的,最具有复杂性的项目,可以简单说一下。有没有和算…

C语言例题练手(1)

前几篇博客的内容已经涉及了C语言的部分语法知识&#xff0c;我们可以尝试做一些编程题&#xff0c;或者换一种说法就是可以写出什么样的程序以此来解决一些问题。 题目来自牛客网https://www.nowcoder.com和C语言菜鸟教程C 语言教程 | 菜鸟教程 数值计算 【例1】带余除法计…

大模型LLama3!!!Ollama下载、部署和应用(保姆级详细教程)

首先呢&#xff0c;大家在网站先下载ollama软件 这就和anaconda和python是一样的 废话不多说 直接上链接&#xff1a;Download Ollama on Windows 三个系统都支持 注意&#xff1a; 这里的Models&#xff0c;就是在上面&#xff0c;大家点开之后&#xff0c;里面有很多模型…

【359】基于springboot的智慧草莓基地管理系统

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本智慧草莓基地管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…

MongoDB笔记03-MongoDB索引

文章目录 一、前言1.1 概述1.2 MongoDB索引使用B-Tree还是BTree&#xff1f;1.3 B 树和 B 树的对比1.4 总结 二、索引的类型2.1 单字段索引2.2 复合索引2.3 其他索引 三、索引的管理操作3.1 索引的查看3.2 索引的创建3.2.1 单字段索引3.2.2 复合索引 3.3 索引的移除3.3.1 指定索…

string模拟实现流插入(输出)+流提取(输入)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 string模拟实现clear 模拟实现clear的目的是在流提取的时候我们清空之前的数据&#x…

C++入门基础知识134—【关于C 库函数 - gmtime()】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 库函数 - gmtime()的相关内容&#xf…