python列表中的内存泄漏问题
Posted
技术标签:
【中文标题】python列表中的内存泄漏问题【英文标题】:Memory leakage issue in python list 【发布时间】:2021-01-23 04:40:01 【问题描述】:身份列表包含大约 57000 张图像的大数组。现在,我在itertools.product()
的帮助下创建了一个负面清单。这会将整个列表存储在内存中,这非常昂贵,并且我的系统在 4 分钟后挂起。
如何优化以下代码并避免节省内存?`
for i in range(0, len(idendities) - 1):
for j in range(i + 1, len(idendities)):
cross_product = itertools.product(samples_list[i], samples_list[j])
cross_product = list(cross_product)
for cross_sample in cross_product:
negative = []
negative.append(cross_sample[0])
negative.append(cross_sample[1])
negatives.append(negative)
print(len(negatives))
negatives = pd.DataFrame(negatives, columns=["file_x", "file_y"])
negatives["decision"] = "No"
negatives = negatives.sample(positives.shape[0])
内存9.30会越来越高,有一点系统已经完全挂掉了。
我也实现了下面的答案,并根据他的答案修改了代码。
for i in range(0, len(idendities) - 1):
for j in range(i + 1, len(idendities)):
for cross_sample in itertools.product(samples_list[i], samples_list[j]):
negative = [cross_sample[0], cross_sample[1]]
negatives.append(negative)
print(len(negatives))
negatives = pd.DataFrame(negatives, columns=["file_x", "file_y"])
negatives["decision"] = "No"
第三版代码
即使您打开一个文件,这个 CSV 文件也太大,然后它会提示您的程序无法加载所有文件。关于这个过程,十分钟,然后系统将完全挂起。
for i in range(0, len(idendities) - 1):
for j in range(i + 1, len(idendities)):
for cross_sample in itertools.product(samples_list[i], samples_list[j]):
with open('/home/khawar/deepface/tests/results.csv', 'a+') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([cross_sample[0], cross_sample[1]])
negative = [cross_sample[0], cross_sample[1]]
negatives.append(negative)
negatives = pd.DataFrame(negatives, columns=["file_x", "file_y"])
negatives["decision"] = "No"
negatives = negatives.sample(positives.shape[0])
内存截图。
【问题讨论】:
是的;您不需要一次完整的样品清单吗?你需要 ?正如我告诉你的那样,即使你想在上面做一些机器学习方法,你也可以逐行阅读,你不应该一次性加载整个训练数据;您需要对数据进行切片 所以我想现在与这些行无关;也许它与您代码的其他部分有关 但我正在考虑一件可能的事情 python 有抓取收集 somtimes 它并没有清除他完成的任务,变量和......你需要手动清理这些东西检查这个问题并通知我:***.com/questions/1316767/… 其实,为了衡量算法的性能,我需要比较所有的负对和正对。 【参考方案1】:itertools 中的 product 是 generator,因此它自然不会将整个列表存储在内存中,而是在下一行 cross_product = list(cross_product)
中转换它列出将整个数据存储在内存中的对象。
生成器的想法是您不会像调用list(itertools.product(samples_list[i], samples_list[j]))
那样同时进行所有计算。所以你要做的就是一一生成结果:
试试这样的:
for i in range(len(idendities) - 1):
for j in range(i + 1, len(idendities)):
for cross_sample in itertools.product(samples_list[i], samples_list[j]):
# do something ...
所以我想我发现了你的问题;您首先将所有样本附加到否定列表,因为您的内存会越来越高,您需要实时写入每一行,一次一行;
您的数据是 csv 对吗?所以你可以这样做:
import csv
for i in range(0, len(idendities) - 1):
for j in range(i + 1, len(idendities)):
for cross_sample in itertools.product(samples_list[i], samples_list[j]):
with open('results.csv', 'a+') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([cross_sample[0], cross_sample[1]])
这个想法是实时写你的行
也请查看此链接how to write the real time data into csv file in python
感谢@9mat、@cybot 以及这些问题How to get Cartesian product in Python using a generator?、how to write the real time data into csv file in python
【讨论】:
有人告诉了这个但从来没有给我一个完整的答案“原因是这种方式一次只有一个来自 cross_product 迭代器的 cross_sample 在内存中实例化。在 RAM 上大量节省”【参考方案2】:您可以创建一个类来表示多个列表的乘积,其行为类似于列表,但不存储任何组合。这只会按需“组合”项目。
class ProductList:
def __init__(self,*data):
self.data = data
self.size = 1
for d in self.data: self.size *= len(d)
def __len__(self): return self.size
def __getitem__(self,index):
if isinstance(index,slice):
return [*map(self.__getitem__,range(len(self))[index])]
result = tuple()
for d in reversed(self.data):
index,i = divmod(index,len(d))
result = (d[i],) + result
return result
def __iter__(self):
for i in range(len(self)): yield self[i]
def __contains__(self,value):
return len(value) == len(self.data) \
and all(v in d for v,d in zip(value,self.data))
def index(self,value):
index = 0
for v,d in zip(value,self.data):
index = index*len(d)+d.index(v)
return index
用法:
p = ProductList(range(1234),range(1234,5678),range(5678,9101))
print(*p[:10],sep="\n")
(0, 1234, 5678)
(0, 1234, 5679)
(0, 1234, 5680)
(0, 1234, 5681)
(0, 1234, 5682)
(0, 1234, 5683)
(0, 1234, 5684)
(0, 1234, 5685)
(0, 1234, 5686)
(0, 1234, 5687)
len(p) # 18771376008
p[27] # (2, 6, 12)
for c in p[103350956:103350960]: print(c)
(6, 4763, 5995)
(6, 4763, 5996)
(6, 4763, 5997)
(6, 4763, 5998)
p.index((6, 4763, 5995)) # 103350956
p[103350956] # (6, 4763, 5995)
(6, 4763, 5995) in p # True
(5995, 4763, 6) in p # False
【讨论】:
【参考方案3】:实际上,生成的对保存在你的记忆中,这就是为什么你的记忆会越来越高。
您必须更改生成对的代码并立即从内存中释放它们。
以前的代码:
for i in range(0, len(idendities) - 1):
for j in range(i + 1, len(idendities)):
cross_product = itertools.product(samples_list[i], samples_list[j])
cross_product = list(cross_product)
for cross_sample in cross_product:
negative = []
negative.append(cross_sample[0])
negative.append(cross_sample[1])
negatives.append(negative)
print(len(negatives))
negatives = pd.DataFrame(negatives, columns=["file_x", "file_y"])
negatives["decision"] = "No"
内存高效代码将配对保存在列表中,然后第二次无需再次生成。
samples_list = list(identities.values())
negatives = pd.DataFrame()
if Path("positives_negatives.csv").exists():
df = pd.read_csv("positives_negatives.csv")
else:
for combo in tqdm(itertools.combinations(identities.values(), 2), desc="Negatives"):
for cross_sample in itertools.product(combo[0], combo[1]):
negatives = negatives.append(pd.Series("file_x": cross_sample[0], "file_y": cross_sample[1]).T,
ignore_index=True)
negatives["decision"] = "No"
negatives = negatives.sample(positives.shape[0])
df = pd.concat([positives, negatives]).reset_index(drop=True)
df.to_csv("positives_negatives.csv", index=False)
【讨论】:
以上是关于python列表中的内存泄漏问题的主要内容,如果未能解决你的问题,请参考以下文章