+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2020-04(13)

2020-05(32)

2020-06(40)

2020-07(41)

2020-08(42)

节约内存的方法

发布于2021-04-03 20:13     阅读(2484)     评论(0)     点赞(23)     收藏(4)


0

1

2

3

4

5

6

节约内存的方法

在python中,经常会有大量数据的计算,一般都通过多维数组来存储,或者一些库称之为张量。在读取大量数据的时候,有可能会遇到内存不足的情况,今天了解了一下对多维数组是如何分配内存的,又该如何节约内存。

主要通过测试python listnumpypytorch,对比这几个之间是否有区别。在做之前,自己的判断是没有区别的,先猜测在验证。

  1. python list
a = [[i for i in range(0, 4)] for j in range(3)]
b = [[i for i in range(4, 8)] for j in range(3)]
print(id(a))
print(id(b))
a = a + b
print(id(a))
a += b
print(id(a))
a[:] = a + b
print(id(a))
140434968054720
140434968053376
140434968099968
140434968099968
140434968099968

从上面的输出结果可以看到,刚开始赋值的时候aid为4720,bid为3376;
然后开始对a和b做加法操作,再赋值给a,结果a的id变成了9968,说明a = a + b,是将a + b的结果保存在新的内存中,再使a指向这个新内存地址;
接着计算a += b,a的id是9968,与计算之前的id相同,我们通常都说a += b等价于a = a + b,但是实际上只是结果等价,a += b可没有将a指向新的内存;
最后是使用切片的方式,id与计算之前相同。

  1. numpy
import numpy as np
# 在notebook中注意restart kernel
a = np.arange(12).reshape(3, -1)
b = np.arange(12).reshape(3, -1)
print(id(a))
print(id(b))
a = a + b
print(id(a))
a += b
print(id(a))
a[:] = a + b
print(id(a))
139670777306928
139670777331920
139670777332000
139670777332000
139670777332000
  1. pytorch
import torch
a = torch.arange(12).reshape(3, -1)
b = torch.arange(12).reshape(3, -1)
print(id(a))
print(id(b))
a = a + b
print(id(a))
a += b
print(id(a))
a[:] = a + b
print(id(a))
139881180034624
139881313662592
139881313683840
139881313683840
139881313683840

可见numpy和pytorch与python list的内存分配时一直的。

注意:
在python list中,对两个list做+运算,其实时对两个list进行拼接,并且- * /等操作是不能list对list操作的;
numpy和pytorch是按元素(elementwise)进行操作的,当两个多维数据的shape不相等时会调用广播机制(broadcasting mechanism)来执行按元素操作。

a = [[i for i in range(0, 4)] for j in range(3)]
b = [[i for i in range(4, 8)] for j in range(3)]
c = a
print(id(a), id(c))
print(a), print(c)
a += b
print(id(a), id(c))
print(a), print(c)
139909205242624 139909205242624
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
139909205242624 139909205242624
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [4, 5, 6, 7], [4, 5, 6, 7], [4, 5, 6, 7]]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [4, 5, 6, 7], [4, 5, 6, 7], [4, 5, 6, 7]]

原地操作

import numpy as np

a = np.arange(12).reshape(3, -1)
b = np.arange(12).reshape(3, -1)
c = a
print('id a:', id(a), 'id c:', id(c))
print('a: \n', a), print('c: \n', c)
a = a + b
print('id a:', id(a), 'id c:', id(c))
print('a: \n', a), print('c: \n', c)
id a: 139909204801616 id c: 139909204801616
a: 
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
c: 
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
id a: 139912994696288 id c: 139909204801616
a: 
 [[ 0  2  4  6]
 [ 8 10 12 14]
 [16 18 20 22]]
c: 
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

我们使用c = a其实就是将c指向id(a),当我们计算a = a + b时,由于a指向了新的内存地址,a的值更新了,但这并不会影响c的值。如果需要c的值跟着a变化,则可以使用原地操作:

import numpy as np

a = np.arange(12).reshape(3, -1)
b = np.arange(12).reshape(3, -1)
c = a
print('id a:', id(a), 'id c:', id(c))
print('a: \n', a), print('c: \n', c)
a[:] = a + b
print('id a:', id(a), 'id c:', id(c))
print('a: \n', a), print('c: \n', c)
a += b
print('id a:', id(a), 'id c:', id(c))
print('a: \n', a), print('c: \n', c)
id a: 139909204802336 id c: 139909204802336
a: 
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
c: 
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
id a: 139909204802336 id c: 139909204802336
a: 
 [[ 0  2  4  6]
 [ 8 10 12 14]
 [16 18 20 22]]
c: 
 [[ 0  2  4  6]
 [ 8 10 12 14]
 [16 18 20 22]]
id a: 139909204802336 id c: 139909204802336
a: 
 [[ 0  3  6  9]
 [12 15 18 21]
 [24 27 30 33]]
c: 
 [[ 0  3  6  9]
 [12 15 18 21]
 [24 27 30 33]]

0

1

2

3

4

5



所属网站分类: 技术文章 > 博客

作者:dfh8374

链接: https://www.pythonheidong.com/blog/article/915692/3ec31a5f5d6d0f937e2f/

来源: python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

23 0
收藏该文
已收藏

评论内容:(最多支持255个字符)