写此文的目的:警醒我自己。。。因为一个plt.clf()的问题卡壳了一整天
问题描述:用python写了一个for循环把序列数据批量转换成图片,然后在for循环里写了如下几句
def get_image(scaled_data,start,number):#scaled_data:传入的数组 start:起始下标 len:待处理的数据量
column = scaled_data.shape[1] # 传入数组的列数=格拉姆角场大小
counter=start
for i in scaled_data[start:start+number]:#遍历待处理部分 生成格拉姆角场并保存图片
arccos_X = np.arccos(i) # 求反余弦
field = [a+b for a in arccos_X for b in arccos_X]
gram = np.cos(field).reshape(-1,column)#格拉姆角场
plt.axis('off') # 关闭坐标
plt.imshow(gram)
plt.savefig('GAF_Image/train_in_'+str(counter)+'.png',bbox_inches='tight',pad_inches = 0)#保存图片
print("\r",end="")
print("generating No."+str(counter+1)+"/"+str(start+number),end="")
counter += 1 # 图片序号+1
print("generated all pictures successfully!")
乍一看好像没什么问题,跑起来也没报错,但是有个问题就是,随着时间推移,图片的生成速度会越来越慢,开始一秒三张,一分钟过后变成了一秒一张,5分钟过后就变成10秒一张了。。。
检查了一个晚上,排查结果如下:
循环调用print语句会延长代码的运行时间
python的for循环效率太低,得想办法加速
针对以上问题,开展了各种挽救措施,然鹅卵用没有,因为这些问题根本就不是关键!
关键就是题目里的plt.clf(),官方的解释如下:
嗯,很简短,还是说说我的个人理解吧,figure就是图形,clear the current figure就是清除当前的图形,此外还会保留当前的窗口以便下次绘图,具体解释可以参考【matplotlib】 之 清理、清除 axes 和 figure (plt.cla、plt.clf、plt.close)_tz_zs的博客-CSDN博客
如果在循环绘图过程中不使用plt.clf()就会造成内存泄漏(应该是这个意思),之前用于绘图的内存无法被释放掉,导致后面的图形堆叠在前面的图形上,如果打开生成的图片,可能会看到一堆重叠的线条之类的,可惜因为特殊原因,我把重叠的图当成正常的图了。。。
在运行时间上的体现就是,循环会越跑越慢,越跑越慢,知道屏幕前的你没有耐心,直至崩溃
所以,及时释放内存真的很重要,之前生成图片忽略了这一点,吃了大亏,下面放上修改后的代码,出图速度很稳定,基本可以一秒出好几张
def get_image(scaled_data,start,number):#scaled_data:传入的数组 start:起始下标 len:待处理的数据量
column = scaled_data.shape[1] # 传入数组的列数=格拉姆角场大小
counter=start
for i in scaled_data[start:start+number]:#遍历待处理部分 生成格拉姆角场并保存图片
arccos_X = np.arccos(i) # 求反余弦
field = [a+b for a in arccos_X for b in arccos_X]
gram = np.cos(field).reshape(-1,column)#格拉姆角场
plt.axis('off') # 关闭坐标
plt.imshow(gram)
plt.savefig('GAF_Image/train_in_'+str(counter)+'.png',bbox_inches='tight',pad_inches = 0)#保存图片
print("\r",end="")
print("generating No."+str(counter+1)+"/"+str(start+number),end="")
plt.clf()#手动清理 防止内存泄漏
counter += 1 # 图片序号+1
print("generated all pictures successfully!")
总结:用plt画完图或者保存完图片后立刻打上plt.clf()等清除语句,防止内存泄漏,节省debug时间