训练的过程中内存一直增加的问题(内存泄漏)、如何检查是否内存泄漏

更新于:2024年5月27日09:47:01

经过了漫长的排查,使用tracemalloc也并不能找到哪里内存泄漏,最后只能通过给出的错误去反思,然后再凭感觉去猜测错误所在位置:

所报的错误是:

Too many open files, Cannot allocate memory (12)

所以就猜测应该是打开的文件太多导致的,可是为什么会导致打开的文件太多呢?唯一与打开文件相关的代码在datasets中的init函数中的3D数据读取中,于是去看到底是哪里的问题:

我是首先使用csv存储大量的已经读取好的tensor,然后将它们在init中读取为一个list, 每一行为一个512维度的tensor。问题就出在了:

threeD_data_list = get_dataset(threeD_data_path)

解决: 

将上述代码改为下面的方式,也就是说使用numpy.array将list转为array 

self.threeD_graph_data = np.array(torch.stack(threeD_data_list))

我主要是参考了https://zhuanlan.zhihu.com/p/401073320的评论所说的

为什么会内存泄漏?

这个问题出在了init中存储的是一个list, 然后我们在getitem中取出这个list中的元素,最后在collate函数中将这一个批次的所有数据(这个批次的数据会存储为list)转为tensor。问题就出在了list与tensor的转换过程中,这个过程会有内存泄漏。

所以应该在init中将list转为array,从而避免内存泄漏

默认的collate函数:

# step3 collate_fn 转tensor
# site-packages/torch/utils/data/_utils/collate.py:
def default_collate(batch):elem = batch[0]elem_type = type(elem)elif elem_type.__module__ == 'numpy':elif elem.shape == ():  # scalarsreturn torch.as_tensor(batch)elif isinstance(elem, float):return torch.tensor(batch, dtype=torch.float64)elif isinstance(elem, int_classes):return torch.tensor(batch)elif isinstance(elem, container_abcs.Sequence):transposed = zip(*batch)return [default_collate(samples) for samples in transposed]


 

如何排查哪段代码存在内存泄漏?

使用内存检查工具tracemalloc模块,具体用法看:https://zhuanlan.zhihu.com/p/80689571#%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0

一般是使用下面这段代码,看看是否出现激增情况:

内存泄漏:

import numpy as np
import tracemalloc
tracemalloc.start()n = 10
l = []for i in range(n):snapshot1 = tracemalloc.take_snapshot()array_large = np.random.choice(1000, size=(700, 700))array_small = array_large[:5, :5]l.append(array_small)snapshot2 = tracemalloc.take_snapshot()top_stats = snapshot2.compare_to(snapshot1, 'lineno')stat = top_stats[0]print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))for line in stat.traceback.format():print(line)

输出:发现逐渐增长,那么是错误的。

3 memory blocks: 1914.2 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))
5 memory blocks: 3828.4 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))
7 memory blocks: 5742.5 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))
9 memory blocks: 7656.6 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))
11 memory blocks: 9570.8 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))
14 memory blocks: 11484.9 KiB
  File "<ipython-input-10-4097e1dc518b>", line 11
    array_large = np.random.choice(1000, size=(700, 700))

内存未泄漏: 

import numpy as np
import tracemalloc
tracemalloc.start()n = 10
l = []for i in range(n):snapshot1 = tracemalloc.take_snapshot()array_large = np.random.choice(1000, size=(700, 700))array_small = array_large[:5, :5].copy()l.append(array_small)snapshot2 = tracemalloc.take_snapshot()top_stats = snapshot2.compare_to(snapshot1, 'lineno')stat = top_stats[0]print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))for line in stat.traceback.format():print(line)

输出:较为平稳,那么是没有内存泄漏的 

8 memory blocks: 3829.4 KiB
  File "/mnt/d/Pycharm_workspace/test/MDT/66.py", line 11
    array_large = np.random.choice(1000, size=(700, 700))
5 memory blocks: 0.6 KiB
  File "/mnt/d/Pycharm_workspace/test/MDT/66.py", line 12
    array_small = array_large[:5, :5].copy()
41 memory blocks: 1.9 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
40 memory blocks: 1.9 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
43 memory blocks: 2.0 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
87 memory blocks: 4.1 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
83 memory blocks: 3.9 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
54 memory blocks: 2.5 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
52 memory blocks: 2.4 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))
82 memory blocks: 3.8 KiB
  File "/home/mapengsen/anaconda3/envs/MDT/lib/python3.8/tracemalloc.py", line 185
    self._frames = tuple(reversed(frames))

可能的原因一(loss.item()):

解决pytorch训练的过程中内存一直增加的问题_pytorch训练过程中,内存一直增长-CSDN博客

可能的原因二(numpy切片相关):

看numpy下内存泄露的例子https://zhuanlan.zhihu.com/p/338232671

可能的原因三(dataloader相关):

又重新整了一下内存泄漏的问题,看到dataloader内存泄漏主要是来源于getitem()中,这里返回了array类型的数据,从而导致collect函数形成了list of np scalars,从而导致内存泄漏,参考于:

https://zhuanlan.zhihu.com/p/338232671

解决:

那么问题的解决就不应该是像下面说的转为什么array类型啥的,应该是修改最后getitem()返回的数据类型:

这主要是因为__getitem__返回的是一个numpy类型的值,在dataloader中会组成一个list of np scalars,并调用torch.tensor,从而引起内存泄露。要解决这个问题,只需要让__getitem__返回一个python内置的数据类型,例如在最后返回XX.tolist()....(实测了一下,在最后返回的array中,让它转为tensor类型也是可以的:torch.tensor(xxx))

注意:一般将array转list时,最好用tolist()彻底转换过来,如果只是用list(array)依然不能存,因为里面每个元素还是numpy中定义的类型。

注意:如果你看到内存刚开始会增加,先不要着急,看看最后是否趋于平稳,如果趋于平稳,那么就没问题

更新于2024年5月26日08:27:08:

以下内容可能是错误的:

DataLoader num_workers > 0 causes CPU memory from parent process to be replicated in all worker processes · Issue #13246 · pytorch/pytorch · GitHub

【Pytorch排坑记】:1.内存泄漏 | TianHongZXY

 例子:

from torch.utils.data import Dataset, DataLoader
import numpy as np
import torchclass DataIter(Dataset):def __init__(self):# 不会导致内存一直增加# self.data_np = np.array([x for x in range(24000000)])# 会导致内存一直增加self.data = [x for x in range(24000000)]def __len__(self):return len(self.data)def __getitem__(self, idx):data = self.data[idx]data = np.array([data], dtype=np.int64)return torch.tensor(data)train_data = DataIter()
train_loader = DataLoader(train_data, batch_size=300,shuffle=True,drop_last=True,pin_memory=False,num_workers=6)for i, item in enumerate(train_loader):if i % 1000 == 0:print(i)

解决办法1:

在dataset中,将init中的数据类型换成下面的形式:

dict --> pandas 

lists --> numpy arrays

也就是说,如果你的init函数中使用了列表,那么你需要将这个list转为np.array形式(同时指定dtype类型),

1)list包含的不是tensor类型:

可以直接np.array():

numpy_array = np.array(your_list, dtype=np.XXX)

2)list包含的是tensor类型:

例如你的list包含了N个tensor,那么你应该将list中的每个tensor转为numpy形式,然后再np.array():

numpy_list = [tensor.numpy() for tensor in your_tensor_list]numpy_array = np.array(numpy_list, dtype=np.float32)

你也可以先使用torch.stack(),然后再 np.array():

stacked_tensor = torch.stack(your_tensor_list)numpy_array = np.array(stacked_tensor, dtype=np.float32)

不可以直接:

numpy_array = np.array(your_tensor_list, dtype=np.float32)

解决办法2(推荐):

可以在getitem中设置深拷贝,然后init中此时就无需设置np.array这种复杂操作

class DataIter(Dataset):def __init__(self):# 不会导致内存一直增加# self.data = np.array([x for x in range(24000000)],dtype=np.str_)# self.data = np.array([x for x in range(24000000)],dtype=np.int64)# 会导致内存一直增加self.data = [x for x in range(24000000)]def __len__(self):return len(self.data)def __getitem__(self, idx):data = copy.deepcopy(self.data[idx])# data = np.array([data], dtype=np.int64)return torch.tensor(data)

PyTorch训练模型,内存泄露问题解决_python程序内存泄露改num workers-CSDN博客

备注:np.array()的dtype类型都有什么?

注意:不要使用np.object类型,否则内存会一直增加,没有用处

详细看:https://gist.github.com/mprostock/2850f3cd465155689052f0fa3a177a50

  1. 整数类型

    • np.int8: 8-bit 整数
    • np.int16: 16-bit 整数
    • np.int32: 32-bit 整数
    • np.int64: 64-bit 整数
  2. 无符号整数类型

    • np.uint8: 8-bit 无符号整数
    • np.uint16: 16-bit 无符号整数
    • np.uint32: 32-bit 无符号整数
    • np.uint64: 64-bit 无符号整数
  3. 浮点数类型

    • np.float16: 16-bit 半精度浮点数
    • np.float32: 32-bit 单精度浮点数
    • np.float64: 64-bit 双精度浮点数
  4. 复数类型

    • np.complex64: 32-bit 实部和虚部的复数
    • np.complex128: 64-bit 实部和虚部的复数
  5. 布尔类型

    • np.bool_: 布尔类型
  6. 对象类型

    • np.object_: 通用对象类型
  7. 字符串类型

    • np.str_: 固定长度的字符串类型
    • np.unicode_: 固定长度的 Unicode 类型

不将list设置为np.array的可能后果

错误一:

[06:55:34.417285] RuntimeError: unable to mmap 2048 bytes from file </torch_106078_2225082816_70220>: Cannot allocate memory (12)

错误二:

OSError: [Errno 24] Too many open files

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

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

相关文章

mysql中InnoDB的表空间--独立表空间

大家好&#xff0c;上篇文章我们在讲mysql数据目录的时候提到了表空间这个名词&#xff0c;它是一个抽象的概念&#xff0c;对于系统表空间来说&#xff0c;对应着文件系统中一个或多个实际文件&#xff1b;对于每个独立表空间来说&#xff0c;对应着文件系统中一个名为表名.ib…

DQL( 数据查询语言)

1. 基本查询 select * from 表名; select 字段,字段2,… from 表名; select * from 表名 where 筛选条件; select 字段,字段2,… from 表名 where 筛选条件; 2. 范围查询 select * from emp where sal 3000; select * from emp where sal ! 3000; select * from emp where s…

node.js学习P3-P10

P3 npm package.json&#xff08;package解读npm工具换镜像源&#xff09; 一个package.json文件可以的作用 作为一个描述文件&#xff0c;描述了你的项目依赖哪些包 &#xff0c;用来干什么的允许我们使用“语义版本规则”&#xff0c;指明你项目依赖的版本让你的构建更好的…

Java绩效考核系统源码 springboot员工绩效考核系统源码

Java绩效考核系统源码 springboot员工绩效考核系统源码-009 源码下载地址&#xff1a;https://download.csdn.net/download/xiaohua1992/89352195 项目介绍 本系统的功能分为管理员和员工两个角色 管理员的功能有&#xff1a; &#xff08;1&#xff09;个人中心管理功能&a…

代码随想录训练营Day49、50、52:Leetcode123、188、309、714、300、674、718

Leetcode123&#xff1a; 问题描述&#xff1a; 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔交易&#xff08;你必须在再次购买前…

一文搞定cuda版本、显卡驱动及多CUDA版本管理

安装cuda是每个AI从业人员必经之路。网上关于cuda、显卡驱动已经相关命令很多都解释不清楚&#xff0c;于是本文梳理一下&#xff0c;既方便自己记忆&#xff0c;也方便小白学习。 CUDA 首先&#xff0c;CUDA版本&#xff0c;一般指cuda-toolkit&#xff0c;即cuda开发工具包…

XShell免费版的安装配置

官网下载 https://www.xshell.com/zh/free-for-home-school/ 下载地址 通过邮箱验证 新建会话 通过ssh登录树莓派 填写主机IP 点击用户身份验证 成功连接

hadoop基础之MapReduce的学习

hadoop基础之MapReduce的学习 MapReduce的执行步骤&#xff1a; 1.Map package com.shujia.mr.worcount;import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapp…

24校招总结

个人背景 本科&#xff1a;三本通信专业 硕士&#xff1a;B区双非计算机硕 今年2月签了东南沿海二线城市某公司C游戏服务端开发 我同学大部分都是去电网&#xff0c;大专老师&#xff0c;气象局事业编……就我这个是纯牛马了。 离收到Offer3个月了&#xff0c;前段时间参加…

高项案例分析知识点总结

文章目录 纠错题计算题进度估算成本管理立项管理版本管理组合管理知识产权信息技术计算题运筹学 纠错题 人&#xff1a;人员经验、能力、数量、缺少培训&#xff1b;自己一个人完成需求和计划不正确流程&#xff1a;先做什么&#xff0c;后做什么&#xff0c;流程是否正确。是…

前端基础入门三大核心之JS篇:掌握数字魔法 ——「累加器与累乘器」的奥秘籍【含样例代码】

前端基础入门三大核心之JS篇&#xff1a;掌握数字魔法 ——「累加器与累乘器」的奥秘籍 &#x1f9d9;‍♂️ 基础概念&#xff1a;数字的魔杖与炼金术累加器&#xff08;Accumulator&#xff09;累乘器&#xff08;Multiplier&#xff09; &#x1f4da; 实战演练&#xff1a;…

c++ (命名空间 字符串)

思维导图&#xff1a; 定义自己得命名空间myspace,在myspace中定义string类型变量s1,再定义一个函数完成字符串逆置 #include <iostream> #include <cstring> //定义自己得命名空间myspace,在myspace中定义string类型变量s1,再定义一个函数完成字符串逆置 using n…

抽屉网关停,Digg类网站退出互联网舞台

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 别人我不清楚&#xff0c;至少在松松我心中&#xff1a;抽屉网是世界著名的网站&#xff0c;而近期抽屉新热榜突然宣布关站了&#xff0c;我内心充满遗憾。因为抽屉网站收集的内容&#xff0c;让我看到了更大的世界…

【算法】合并k个已排序的链表

✨题目链接&#xff1a; NC51 合并k个已排序的链表 ✨题目描述 合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。 数据范围&#xff1a;节点总数 0≤&#x1d45b;≤50000≤n≤5000&#xff0c;每个节点的val满足 ∣&#x1d463;&#x1d44e;&#x1d459;∣&…

【学习记录】服务器转发使用tensorboard

场景 代码在服务器上运行&#xff0c;想使用tensorboard查看训练的过程。 但是服务器上不能直接访问地址&#xff0c;所以要转发端口到本地&#xff0c;从而在本地网页中能够打开tensorboard。 参考&#xff1a;https://zhuanlan.zhihu.com/p/680596384 这时我们需要建立本地…

C++ 函数模板与模板函数

一 代码重用技术 函数 类与对象 继承与派生 多态&#xff08;函数重载、运算符重载、虚函数、纯虚函数与抽象类&#xff09; 泛型程序设计 通用的代码需要补受数据类型的影响&#xff0c;并且可以自动适应数据类型的变化&#xff0c;这种程序设计类型称为泛型程序设计。 二 模…

Logstash笔记

目录​​​​​​​ 一、简介 二、单个输入和输出插件 三、多个输入和输出插件 四、pipeline结构 五、队列和数据弹性 六、内存队列 七、持久化队列 八、死信队列 (DLQ) 九、输入插件 1)、beats 2)、dead_letter_queue 3)、elasticsearch 4)、file 5)、redis 十、…

字符串和字符串函数(1)

前言&#xff1a; 字符串在C语言中比较特别&#xff0c;没有单另的字符串类型&#xff0c;想要初始化字符串必须用字符变量的数组初始化&#xff0c;但是在C语言标准库函数中提供了大量能对字符串进行修改的函数&#xff0c;比如说可以实现字符串的的拷贝&#xff0c;字符串的追…

经常碰到的20个等待事件

经常碰到的20个等待事件 oracle等待事件简介 DBA团队维护的部分应用运行在oracle数据库平台&#xff0c;为及时了解数据库的运行情况&#xff0c;需要建立涵盖各个维度的监控体系&#xff0c;包括实例状态、空间使用率、ORA错误等数十项监控指标。这其中有一个有效判断数据库…

PY32F002A单片机 us 延时,非常惊讶

先说结论&#xff0c;这个型号&#xff0c;运算速度 慢&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 测试1 volatile uint32_t delay 1000;/* 初始化所有外设&#xff0c;Flash接口&#xff0c;SysTick *…