pyplot.plot使用遇到:UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail

2023-05-16

问题出现的背景:之前的工作:tensorflow利用for循环进行训练遇到的内存爆炸问题(OOM)

文章目录

      • 问题介绍
      • 解决方法:
        • 方法一:
        • 方法二:
        • 方法三:
          • 注意:
      • 参考

问题介绍

在threading.Thread创建的线程中使用了matplotlib.pyplot来做图,但出现:
UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail

之后查找Matplotlib官方文档,有这样的描述:

Working with threads:
Matplotlib is not thread-safe: in fact, there are known race conditions that affect certain artists. Hence, if you work with threads, it is your responsibility to set up the proper locks to serialize access to Matplotlib artists.
Note that (for the case where you are working with an interactive backend) most GUI backends require being run from the main thread as well.

并不是说无法在子线程中用plt绘图,只是会提示不安全。
经过实践,还是可以在Thread创建的子线程中使用plt来绘图的。(既然这样提示,也有可能出现失败的情况,只是自己没遇到)

如果不想有此Warning的提示,解决如下。

解决方法:

方法一:

将plt需要的变量设置为全局变量,这样等Thread创建的子线程结束之后,在主线程中再进行作图

本代码是要将模型训练得到的结果进行绘图
部分相关代码如下:

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import threading
import time

# distill_history是我们绘图需要用到的变量,所以需要先在模块层面(全局层面)声明此变量。即:类似于C,在所有的import之后声明变量即可
# 如果没有在全局层面声明global变量的话,会报错
distill_history = []
...
# main_loop()相关部分:
 def main_loop(alpha, T):
 	...
 	global distill_history
    # distill teacher to student
    distill_history = distiller.fit(train_images, train_labels, epochs=20, validation_data=(test_images, test_labels))   
    ...

# draw_distill()相关部分:
def draw_distill():
	# 评估distilled student模型
    plt.figure(figsize=(16, 8))
    # the accuracy plot
    plt.subplot(1, 2, 1)
    plt.plot(distill_history.history['accuracy'], label='accuracy')
    plt.plot(distill_history.history['val_accuracy'], label='val_accuracy')
	...                   
	                                                     
if __name__ == '__main__':
	...
	# 利用循环调参,观察不同超参数对应的蒸馏效果
	for alpha in (0.1, 0.2, 0.3):
	        for T in range(5, 21, 5):
	            print(time.strftime("%Hh-%Mm-%Ss: "))
	            t = threading.Thread(target=main_loop, args=(alpha, T))
	            t.start()
	            # join() : 阻塞当前线程,告诉主线程,当线程t执行完之后才能向后继续执行
	            t.join()
	            # 再使用draw_distill()函数来绘图
	            draw_distill()
				...	            
                       

方法二:

使用multiprocessing.Process类,即改用创建子进程的方式来处理(不过因为Process创建的是单独的进程,与主进程相互独立,无法直接使用主进程中的变量,必须将需要的变量作为参数传入args)

multiprocessing.Process与threading.Thread的区别及使用见:另一篇文章:python multiprocessing.Process与threading.Thread的区别以及多进程,多线程的一些使用方法

# 使用Process类的相关代码如下:
if __name__ == '__main__':
    # 加载数据集
    (train_images, train_labels), (test_images, test_labels) = keras.datasets.cifar10.load_data()
    # Normalize pixel values
    train_images, test_images = train_images / 255.0, test_images / 255.0

    teacher = build_model('teacher', 32, 64, 64, 64)
    # load teacher model from SavedModel
    teacher = keras.models.load_model('teacher_model')

    for alpha in (0.1, 0.2, 0.3):
        for T in range(5, 21, 5):
            print(time.strftime('%H-%M-%S: '))
            """
            使用Process就要把需要的参数都传入args中,传参比较麻烦
            main_loop的中训练用到了teacher, train_image, train_labels等很多变量,都需要传入,不然会报错:xxx is not defined
            """
            p = Process(target=main_loop, args=(alpha, T, teacher, train_images, train_labels, test_images, test_labels))
            """
            相应的,main_loop函数的形参列表也要修改
            可以将plt绘图部分直接放到main_loop里面,因为使用Process不会出现标题所述的warning
            """
            p.start()
            # join() : 阻塞当前进程,告诉主进程,当进程p执行完之后才能向后继续执行进程
            p.join()

方法三:

继承Thread类,重写run()函数,以及添加get_result()函数

根据threading的官方文档,run()函数是有关线程活动的方法,我们可以在子类中重写这个方法

首先参考Thread的源代码:

class Thread:
    ...
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, *, daemon=None):
     	...
        if kwargs is None:
            kwargs = {}
        self._target = target
        self._args = args
        self._kwargs = kwargs
        ...
	    def run(self):
        """Method representing the thread's activity.

        You may override this method in a subclass. The standard run() method
        invokes the callable object passed to the object's constructor as the
        target argument, if any, with sequential and keyword arguments taken
        from the args and kwargs arguments, respectively.
        """
        try:
            if self._target:
                self._target(*self._args, **self._kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args, self._kwargs
   		...

我们进行修改,添加self._result成员变量来记录传入的target函数的返回值,并将获取返回值的操作封装进get_result()函数中

修改后代码如下:

from threading import Thread
import traceback

class MyThread(Thread):
    def __init__(self, target=None, args=()):
        super(MyThread, self).__init__()
        self._target = target
        self._args = args
        # 先在__init__中声明 _result 变量
        self._result = None

    def run(self):
        try:
            if self._target:
            	# 此处做修改
                self._result = self._target(*self._args)
            else:
                print('target is None')
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args
	
	# 添加get_result()成员函数
    def get_result(self):
        try:
            if self._result:
                return self._result
        except Exception as e:
            traceback.print_exc()
            return None

进行测试:

def func_a(x, y):
    print('ok')
    return x * y

def func_b(num):
    print(f'num is : {num}')

if __name__ == '__main__':
    for i in range(5):
        t = MyThread(target=func_a, args=(i, i + 1))
        t.start()
        t.join()
        result = t.get_result()
        func_b(result)
注意:

使用方法三时,要记得修改我们传入的target函数,需要在target函数中把我们需要的变量return出来

参考

Matplotlib官方文档
threading的官方文档

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pyplot.plot使用遇到:UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail 的相关文章

  • matplotlib:在次要标签下绘制主要刻度标签

    这看起来应该很容易 但我不知道该怎么做 我有一个 X 轴上有时间的图 我想设置两组刻度 小刻度显示一天中的小时 大刻度显示日 月 所以我这样做 set date ticks to something sensible xax ax get
  • matplotlib 绘制什么都不显示

    我正在使用 python 的 matplotlib 使用轮廓和轮廓函数来绘制一些轮廓 使用 show 时它们都工作正常 但是当我尝试在方法内使用 draw 时 我得到了 matplotlib 窗口 但没有得到图形 show 调用将在代码中以
  • 如何在 R 中绘制预测的子集?

    我有一个简单的 R 脚本来根据文件创建预测 自 2014 年以来就有数据记录 但我在尝试实现以下两个目标时遇到了困难 仅绘制预测信息的子集 从 11 2017 开始 以特定格式包含月份和年份 即 6 月 17 日 这是链接到dataset
  • 使用 matplotlib 为水平条形图创建替代 y 轴标签

    这是我刚刚提出的问题的 更清晰的 转发 我的去身份化让人们感到困惑 你好 我是使用 matplotlib pyplot 在 python 中绘图的新手 并花了很多时间在这个网站和其他网站上搜索 并试图弄清楚这一点 但我还没有成功完成我想做的
  • 将数据提示堆栈放在轴标签顶部,并在轴位置发生更改后更新轴标签

    此问题仅适用于 unix matlab Windows 用户将无法重现该问题 我在尝试创建位于 y 轴标签顶部的数据提示时遇到问题 下图很能说明问题 正如您所看到的 在 ylabel 附近创建的数据提示将到达 ylabel 文本的底部 而期
  • 绘制具有数据子集的图层时,因子水平的顺序会发生变化

    我试图控制图例中项目的顺序ggplot2我查找了其他一些类似的问题 并发现了如何更改我正在绘制的因子变量的水平顺序 我正在绘制 12 月 1 月 7 月和 6 月 4 个月的数据 如果我只对所有月份执行一个绘图命令 它会按预期工作 图例中排
  • 在 R 中使用 spplot 将多个绘图放在一个页面上?

    我知道如何在使用简单函数图时绘制两个图 old par lt par mfrow c 1 2 plot faithful main Faithful eruptions plot large islands main Islands yla
  • 在单个显示器中绘制多个 jpeg 图像

    我需要在单个组合显示器 或画布 中绘制和显示多个 jpeg 图像 例如 假设我有图像 a b c d jpg 每个图像的大小不同 我想将它们绘制在 2x2 网格的一页上 能够为每个子图设置标题也很好 我一直在彻底寻找解决方案 但不知道如何去
  • 如何在 Python 中根据日期列绘制分类变量

    我有这样的数据 Date Fruit 2017 01 01 Orange 2017 01 01 Apple 2017 01 08 Orange 2017 01 09 Orange 2017 01 09 Apple 我想在一个图中按日期绘制橙
  • 无法将matplotlib安装到pycharm

    我最近开始使用Python速成课程学习Python编程 我陷入困境 因为我无法让 matplotlib 在 pycharm 中工作 我已经安装了pip 我已经通过命令提示符使用 pip 安装了 matplotlib 现在 当我打开 pych
  • 如何在向量中的所有点之间绘制线?

    我有一个包含二维空间中一些点的向量 我希望 MATLAB 用从每个点到每个其他点绘制的线来绘制这些点 基本上 我想要一个所有顶点都连接的图 你能用情节来做到这一点吗 如果可以 怎么做 一种解决方案是使用该函数为每个点组合创建一组索引MESH
  • 在 pandas 条形图中设置 xticks

    我在下面的第三个示例图中遇到了这种不同的行为 为什么我能够正确编辑 x 轴的刻度pandas line and area 情节 但不与bar 修复 一般 第三个示例的最佳方法是什么 import numpy as np import pan
  • matplotlib 中的 R 风格数据轴缓冲区

    R 绘图自动设置 x 和 y 限制 以在数据和轴之间留出一些空间 我想知道 matplotlib 是否有办法自动执行相同的操作 如果没有 是否有一个好的公式或 经验法则 来说明 R 如何设置其轴限制 在 matplotlib 中 您可以通过
  • 在 iPython/pandas 中绘制多条线会生成多个图

    我试图了解 matplotlib 的状态机模型 但在尝试在单个图上绘制多条线时遇到错误 据我了解 以下代码应该生成包含两行的单个图 import pandas as pd import pandas io data as web aapl
  • Matlab 图像数据的 hist 函数

    我是 Matlab 新手 我想制作自己的函数 与 imhist 显示图像数据的直方图 完成相同的工作 但我对此完全是新手 我不知道如何做开发这样的功能 我开始做一些东西 但它非常不完整 function output args myhist
  • 如何在 Seaborn 中的热图轴上表达类

    我使用 Seaborn 创建了一个非常简单的热图 显示相似性方阵 这是我使用的一行代码 sns heatmap sim mat linewidths 0 square True robust True sns plt show 这是我得到的
  • Jupyter Notebook:带有小部件的交互式绘图

    我正在尝试生成一个依赖于小部件的交互式绘图 我遇到的问题是 当我使用滑块更改参数时 会在前一个绘图之后完成一个新绘图 而我预计只有一个绘图会根据参数发生变化 Example from ipywidgets import interact i
  • 将自定义误差线添加到 seaborn regplot 和 residplot

    有没有一种方法可以将自定义错误栏添加到seaborn regplot和residplot中 就像使用yerr对matplotlib错误栏所做的那样 例子在这里 如果我只是添加 yrr 参数就会发生错误 import seaborn as s
  • 更改 x 轴比例

    我使用 Matlab 创建了这个图 使用 matplotlib x 轴绘制大数字 例如 100000 200000 300000 我想要 1 2 3 和 10 5 之类的值来指示它实际上是 100000 200000 300000 有没有一
  • 如何绘制堆积比例图?

    我有一个数据框 x lt data frame id letters 1 3 val0 1 3 val1 4 6 val2 7 9 id val0 val1 val2 1 a 1 4 7 2 b 2 5 8 3 c 3 6 9 我想绘制一个

随机推荐

  • 网页限制F12,接触教程

    开启右键菜单 document oncontextmenu 61 function return true 开启文字选择 document onselectstart 61 function return true 开启复制 documen
  • 区间覆盖问题-贪心求解

    题目 https vjudge net problem OpenJ Bailian 2376 题目大意 本题给定两个整数n和t xff0c n表示接下来会输入n段区间 xff0c t表示需要覆盖的区间为 1 t 题目要求利用输入的n段区间来
  • DDL问题-贪心算法

    题目 题目大意 本题给出了若干个任务的DDL和对应的分值 xff0c 要求得出最少扣分值 xff0c 也就是求出最大得分 在DDL前完成任务可以得分 xff0c 否则就不能 解题思路 本题与区间覆盖问题有一些相似之处 xff0c 因此在贪心
  • TT 的神秘礼物-二分答案

    题目 题目大意 题目给出了一个长度为N的数组cat xff0c 要求产生新数组ans xff0c 其中ans由所有abs cat i cat j 组成 xff0c 其中i j且1 i xff1c j N 要求求出ans排序后的中位数 xff
  • 【区间选点 II】差分约束

    题目 题意 给定一个数轴上的 n 个区间 xff0c 要求在数轴上选取最少的点使得第 i 个区间 ai bi 里至少有 ci 个点 使用差分约束系统的解法解决这道题 Input 输入第一行一个整数 n 表示区间的个数 xff0c 接下来的
  • 【东东学打牌】复杂模拟

    题目 题意 最近 xff0c 东东沉迷于打牌 所以他找到 HRZ ZJM 等人和他一起打牌 由于人数众多 xff0c 东东稍微修改了亿下游戏规则 xff1a 所有扑克牌只按数字来算大小 xff0c 忽略花色 每张扑克牌的大小由一个值表示 A
  • 【Max Sum Plus Plus】区间dp

    题目 HDU 1024 传送门 题意 东东每个学期都会去寝室接受扫楼的任务 xff0c 并清点每个寝室的人数 每个寝室里面有ai个人 1 lt 61 i lt 61 n 从第i到第j个宿舍一共有sum i j 61 a i 43 43 a
  • 【TT的奖励】动态规划

    题目 题意 在大家不辞辛劳的帮助下 xff0c TT 顺利地完成了所有的神秘任务 神秘人很高兴 xff0c 决定给 TT 一个奖励 xff0c 即白日做梦之捡猫咪游戏 捡猫咪游戏是这样的 xff0c 猫咪从天上往下掉 xff0c 且只会掉在
  • 【ZJM要抵御宇宙射线】CSP模测T2

    题目 题目大意 本题给出平面二维坐标上的若干个点 xff0c 要求选取一个点做圆心 xff0c 此时可以以最短半径包含所有点 xff0c 求出圆心坐标和最短半径平方 xff0c 结果保留两位小数 解题思路 本题乍看只下可能觉得会很复杂 xf
  • 【宇宙狗的危机】CSP模测T4

    题目 题目描述 在瑞神大战宇宙射线中我们了解到了宇宙狗的厉害之处 xff0c 虽然宇宙狗凶神恶煞 xff0c 但是宇宙狗有一 个很可爱的女朋友 最近 xff0c 他的女朋友得到了一些数 xff0c 同时 xff0c 她还很喜欢树 xff0c
  • 【猫睡觉问题】较复杂模拟

    题目 HDU 3700 Cat 题目大意 题目给出一只猫每天若干个时间段有任务 xff0c 没有任务时猫可以睡觉 题目还给出两个数A和B xff0c 表示猫每次睡觉时间不能少于A小时且每次醒着的时间不能多于B小时 题目要求输出一天猫可能睡觉
  • linux 部署django时报错django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.3 or newer is required

    1 在项目中 init py中这个报错原因 xff0c python 3 5以上版本不支持这种方式 from pymysql import install as MySQLdb install as MySQLdb 解决 xff1a imp
  • 栈求解最大矩形

    题目描述 给一个直方图 xff0c 求直方图中的最大矩形的面积 例如 xff0c 下面这个图片中直方图的高度从左到右分别是2 1 4 5 1 3 3 他们的宽都是1 xff0c 其中最大的矩形是阴影部分 Input 输入包含多组数据 每组数
  • 负权环路问题-SPFA算法的应用

    题目描述 这一晚 xff0c TT 做了个美梦 xff01 在梦中 xff0c TT 的愿望成真了 xff0c 他成为了喵星的统领 xff01 喵星上有 N 个商业城市 xff0c 编号 1 xff5e N xff0c 其中 1 号城市是
  • Ubuntu Linux 安装部署 code-server 在线代码编写环境(含卸载教程)

    Ubuntu Linux 安装部署 code server 在线代码编写环境 xff08 含卸载教程 xff09 安装 code server开启服务及密码修改设置code server开机自启动卸载 code server 安装 code
  • 09 sprintf、printf函数的源码

    实现printf以及Sprintf源码 printf函数的全称为格式化输出函数 之所以叫做格式化出 xff0c 是因为这个函数提供有多种格式化输出方式 xff0c 可以向标准输出中输出某种格式的内容 本文目标是详细的讲述printf函数的用
  • C++后端开发(2.2.3)——POSIX网络API解析

    C 43 43 后端开发 xff08 2 2 3 xff09 POSIXAPI解析 0 前言网络中进程之间如何通信 xff1f POSIX介绍 1 POSIX网络API2 函数与内部过程分析2 1 Socket2 2 bind2 3 lis
  • 用pip查看要安装的python包的所有版本

    我使用的是ubuntu20 04 xff0c windows下操作相同 文章目录 正文附第一点第二点 xff1a 可能出现的bug 正文 首先 xff0c 我的pip版本如下 xff1a 然后 xff0c 就可以通过 xff1a span
  • python import 搜索包路径的机制,以及添加自定义python包的方法

    系统 xff1a win10 xff08 linux系统也是类似的方法 xff09 python xff1a 3 8 3 正文 python import 的搜索方法 在python中 xff0c 有模块 xff08 module xff0
  • pyplot.plot使用遇到:UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail

    问题出现的背景 xff1a 之前的工作 xff1a tensorflow利用for循环进行训练遇到的内存爆炸问题 OOM 文章目录 问题介绍解决方法 xff1a 方法一 xff1a 方法二 xff1a 方法三 xff1a 注意 xff1a