【Pytorch】物理cpu、逻辑cpu、cpu核数、pytorch线程数设置

本文详细介绍了PyTorch中CPU线程配置的方法及注意事项,包括如何设置torch.set_num_threads,以及如何处理DistributedDataParallel(DDP)和DataLoader的线程数配置问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上周末写ddp,常常遇到中途退出的问题,解决中途遇到了很多CPU线程数和核心数的问题,记录如下

1. 物理cpu、逻辑cpu、cpu核数、超线程

这一部分主要来自什么是物理cpu,什么是逻辑cpu,什么cpu核数,什么是超线程?

a. 物理CPU

就是实实在在插在主机上看得见摸得着那块CPU硬件,可通过如下命令来查看物理CPU个数:

cat /proc/cpuinfo | grep 'physical id' | sort | uniq | wc -l

下图代表服务器有两块cpu

b.cpu核数

一块物理CPU上能处理数据的芯片组数量。也就是说一个物理CPU上可能会有多个核心,日常中说的双核,四核就是指的CPU核心。可通过如下命令来查看CPU核心数:

cat /proc/cpuinfo | grep 'core id' | sort | uniq | wc -l

下图代表一块cpu有10个核心

c.超线程

一个CPU核就是一个物理线程,由英特尔开发超线程技术可以把一个物理线程模拟出两个线程来使用,使得单个核心用起来像两个核一样,以充分发挥CPU的性能。

d.逻辑cpu

逻辑CPU的概念比较抽象,可简单理解为一个处理单元,通常来说,总的逻辑CPU数对应总的CPU核数,但借助超线程技术,一个核用起来像两个核,这时逻辑CPU数就是核心数的两倍了。可通过如下命令来查看逻辑CPU数:

cat /proc/cpuinfo | grep 'processor' | sort | uniq | wc -l

下图代表服务器逻辑cpu数为40,显然开启了超线程

总核数 = 物理CPU个数 X 每颗物理CPU的核数
总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

top指令中的%cpu就是占用的逻辑cpu数,如下图为占用一个逻辑cpu

2. Pytorch设置线程数

a. torch.set_num_threads

这一部分来自Set the Number of Threads to Use in PyTorch

Pytorch使用CPU计算op时默认使用OpenMP进行并行计算,一般默认使用全部CPU线程(即逻辑cpu数)的一半

set_num_threads()用于设置CPU上用于内部操作(intra operations)的线程数。 根据这里的讨论,内部操作大致是指在一个操作中执行的操作,例如矩阵乘法。 默认情况下,pytorch将使用计算机上所有可用的内核(比如我这里是2*10=20),为了验证这一点,我们可以使用torch.get_num_threads()获取默认线程数。

import time
 
import torch
import numpy as np
import os
#torch.set_num_threads(8) 这里有注释!
while True:
    arr= np.zeros((100,3, 300, 300), dtype=np.float32)
    start=time.time()
    aaa=torch.from_numpy(arr)
    start = time.time()
    aaa.add_(-0.406)
    print('time2',time.time() - start)
    print("hello")
    print("num_threads: %d" % torch.get_num_threads())

输出如下,可以看到用了一半的逻辑cpu数

取消上面对torch.set_num_threads(8)的注释

下图可以看到占用了约8个线程

对于支持并行性的操作,增加线程的数量通常会使CPU上的执行速度更快。 除了通过pytorch设置线程数,还可以设置环境变量OMP_NUM_THREADSMKL_NUM_THREADS来设置线程数。

b. torch.set_num_threads 和’MKL_NUM_THREADS’ 'OMP_NUM_THREADS’三个的区别是什么?

先贴pytorch官方解释两图

以下部分参考pytorch模型在multiprocessing下前馈速度明显降低的原因是什么?

Pytorch使用CPU计算op时默认使用OpenMP进行并行计算。每次模型进行inference的时候,pytorch的核心会fork出多个线程进行Inter-op的并行计算,在每个op计算的内部(Intra-op)又会使用ATen,MKL,MKL-DNN等矩阵加速库进行加速,并使用OpenMP(默认)或TBB进行多线程计算。

标题提到的torch.set_num_threads 和’MKL_NUM_THREADS’ 'OMP_NUM_THREADS’,其实我也分不太清楚。记住有优先级并且’MKL_NUM_THREADS’ 'OMP_NUM_THREADS’一起设置为torch.set_num_threads的数目好了即三个设置成一样的,怕出错就按如下顺序设置。

    torch.set_num_threads(1)
    os.environ["OMP_NUM_THREADS"] = "1"  # 设置OpenMP计算库的线程数
    os.environ["MKL_NUM_THREADS"] = "1"  # 设置MKL-DNN CPU加速库的线程数。

c.ddp下的线程设置

pytorch下的DistributedDataParallel(即ddp),推荐每个进程的OMP_NUM_THREADS设置为1,防止系统过载。(但这样挺低效的,根据自己的子进程数来看叭)

Setting OMP_NUM_THREADS environment variable for each process to be 1 in default, to avoid your system being overloaded, please further tune the variabl
e for optimal performance in your application as needed.

它推荐的设置法(亲测环境变量加在这里比代码中有效)

OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 python -m torch.distributed.launch --nproc_per_node=2 test.py

d.num_workers下的线程数

关于DataLoader num_workerstorch.set_num_threads

The num_workers for the DataLoader specifies how many parallel workers to use to load the data and run all the transformations. If you are loading large images or have expensive transformations then you can be in situation where GPU is fast to process your data and your DataLoader is too slow to continuously feed the GPU. In that case setting higher number of workers helps. I typically increase this number until my epoch step is fast enough. Also, a side tip: if you are using docker, usually you want to set shm to 1X to 2X number of workers in GB for large dataset like ImageNet.

The torch.set_num_threads specifies how many threads to use for parallelizing CPU-bound tensor operations. If you are using GPU for most of your tensor operations then this setting doesn’t matter too much. However, if you have tensors that you keep on cpu and you are doing lot of operations on them then you might benefit from setting this. Pytorch docs, unfortunately, don’t specify which operations will benefit from this so see your CPU utilization and adjust this number until you can max it out.

总结就是这两没有关系,num_workers是独立于程序单独开出来的torch.set_num_threads是pytorch给cpu做并行的。

如果我使用

OMP_NUM_THREADS=10 MKL_NUM_THREADS=10 python -m torch.distributed.launch --nproc_per_node=2 test.py

会得到下面的结果,十个线程。两个是ddp给的进程(前两个),后面八个是4*2即两个进程分别的num_workers用于读取数据。

3. torch.set_num_threads没用?

个人觉得三个原因(可能)

A. 刚刚的图片展示了,其实我每个进程都是torch.set_num_threads(10),但是cpu的进程7010和7006才分别用了不到200%。很大可能是cpu上进行的数据操作不多,时间很短也用不不着这么多线程就结束了,这个是最有可能的

B. 要把num_workers 也设置不为零
来自https://github.com/pytorch/pytorch/issues/19213

This only happens when num_workers is set for the dataloader. If num_workers is not set, torch.set_num_threads works correctly. I’d say it’s like set_num_threads is not inherited by the dataloader workers, which fall back to the default.

C. opencv中也用了openmp做加速,有时出现死锁。可以设置

cv2.setNumThreads(0)
cv2.ocl.setUseOpenCL(False)

个人不推荐使用


参考链接

1.什么是物理cpu,什么是逻辑cpu,什么cpu核数,什么是超线程?

2. Linux下确认CPU是否开启超线程

3. Linux OS下,你真的读懂了cat /proc/cpuinfo 吗?

4. torch.set_num_threads

5. Set the Number of Threads to Use in PyTorch

6. DataLoader num_workers vs torch.set_num_threads

7.pytorch锁死在dataloader(训练时卡死)

好的!以下是关于如何离线部署 DeepSeek 模型及知识库的详细教程,并优化性能以充分利用您的硬件资源。 --- ### **一、准备工作** 由于整个安装过程不能联网,您需要事先准备好所有所需的文件和依赖项: #### **1. 下载DeepSeek模型及相关工具** - 访问[DeepSeek官网](https://www.deepseek.ai/)或其他可信来源获取预训练模型权重。 - 确保下载对应版本的 `transformers` 库以及相关的支持包(如 `sentence-transformers` 和其他必要的 Python 包)。 - 使用网络连接良好的机器完成以下操作: - 安装最新的 `transformers` 版本并导出其依赖列表: ```bash pip freeze > requirements.txt ``` - 将 `requirements.txt` 文件保存下来,用于后续离线环境中安装依赖。 #### **2. 准备Python环境** - 下载适用于 Windows 的 [Anaconda 或 Miniconda](https://docs.conda.io/en/latest/miniconda.html) 安装包。 - 创建一个包含必要软件包的 `.zip` 压缩包: - 所有从 PyPI 导出的 whl 文件。 - CUDA 驱动程序(针对 NVIDIA RTX A2000 显卡)。 - cuDNN 对应版本。 #### **3. 其他必备组件** - NVIDIA GPU 驱动:确保下载兼容 RTX A2000 的驱动程序(建议使用最新稳定版)。 - Microsoft Visual C++ Redistributable 最新版本。 - Git for Windows (如果计划通过脚本管理项目结构) 将以上内容拷贝到 U盘或硬盘中,准备传输至目标主机。 --- ### **二、在目标主机上设置离线环境** #### **1. 安装CUDA和cuDNN** - 插入U盘并将预先下载的NVIDIA驱动程序安装到系统中。 - 根据您的显卡型号选择适合的CUDA版本 (推荐使用 CUDA 11.x),并手动解压 cuDNN 至相应路径下: - 解压缩后复制 bin/include/lib 目录下的文件覆盖至 `%CUDA_HOME%`. #### **2. 设置Conda虚拟环境** - 运行Miniconda安装包,在离线模式下初始化环境。 - 使用命令创建一个新的 Conda 虚拟环境: ```bash conda create -n deepseek_env python=3.9 conda activate deepseek_env ``` #### **3. 安装PyTorch及其他依赖** - 切换至存储whl文件目录,逐一加载所需模块: ```bash pip install transformers torch torchvision torchaudio --find-links ./offline-packages/ ``` #### **4. 加载DeepSeek模型** - 将之前下载的 DeepSeek 权重放入指定位置,并编写加载代码示例: ```python from transformers import AutoTokenizer, AutoModelForCausalLM # 初始化分词器与模型实例 tokenizer = AutoTokenizer.from_pretrained("path/to/deepseek-model") model = AutoModelForCausalLM.from_pretrained("path/to/deepseek-model") def generate_text(prompt): inputs = tokenizer.encode(prompt, return_tensors="pt").cuda() outputs = model.generate(inputs) result = tokenizer.decode(outputs[0], skip_special_tokens=True) print(result) if __name__ == "__main__": prompt = "请告诉我今天天气怎么样?" generate_text(prompt) ``` --- ### **三、调整硬件性能配置** #### **1. CPU超线程利用** Intel Xeon W-4210 支持多核心处理能力,请启用最大可用CPU目: ```python import torch.multiprocessing as mp mp.set_start_method('spawn') torch.set_num_threads(20) # 设定并发线程数接近总 ``` #### **2. GPU加速优化** 为了最大化RTX A2000显存利用率,可以尝试以下几个技巧: - 分批输入据集,避免单次请求占用过多资源; - 修改批次大小(batch size)参直至达到合理平衡点而不会触发OOM错误; - 启用混合精度计算减少内存消耗同时提升速度: ```python scaler = torch.cuda.amp.GradScaler() with torch.autocast(device_type='cuda', dtype=torch.float16): output = model(input_ids=input_tensor.to(torch.int).cuda()) ``` #### **3. 性能监控与调试** 借助[NVSMI](https://developer.nvidia.com/nvidia-system-management-interface)实时查看GPU工作状态;也可采用类似[TensorBoard](https://www.tensorflow.org/tensorboard/get_started)可视化平台记录各项指标变化趋势图谱以便分析改进方向。 --- **四、测试与验证结果** 完成上述步骤之后就可以正式开始实验了。记得每次运行前检查当前设备分配情况是否正常运作无误!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值