基于Redis训练模型时Loss值等实时动态远程监测

前言

当我在跑一个深度学习或者神经网络模型等训练时,我们常常需要跑很多个epoch,而我们在训练中最关心的当然是模型的准确率等参数,但是在这之前,需要经过一个调参数的过程。而调参的过程往往是根据loss 值在什么时候的大小去决定的。因此当我们跑代码的时候直观地实时地观测loss值的变化,那么一定可以更高效地调整参数。
为了让训练的程序稳定跑起来,在远程,随时随地观察loss值的变化,本文引入了Redis 来存储当前的loss值,Redis 相对其他数据库更轻便,读取速度更快(当然在这并不体现出来),可扩展性好
不懂Redis 的可以看看这个以前写的 Redis简说与Python 操作Redis实例介绍

本文将介绍在pycharm、Jupyter Notebook 两个开发环境下介绍实时显示方法。


一、Redis 如何设计?

无需设计,只需要安装好,打开服务端即可。在Linux 中可以直接输入命令直接打开连接上Redis 服务端,由于这里只是简单介绍就不设计用户密码等设计了。

./redis-server
redis-cli

你可能会想,在python中如何建立redis的连接呢 ?很简单的 Redis简说与Python 操作Redis实例介绍

这里用最常用的 List 结构存储Loss值,需要注意的是Redis 的Lists 是LIFO机制。这也是后面的代码注释里说明的为什么要反转一下的原因。如何在训练中保存loss值在Redis里面呢?
这里不详细在某个训练代码中展示,看懂以下代码稍微改一下保存的loss值再哪即可,过程很简单,就一句代码。

r1.lpush(redis_range_name, loss_val)
# encoding:utf8
# 免密码的redis,实时显示loss值的趋势
import redis
ip = '127.0.0.1'
redis_range_name = 'loss_val'  # 要和redis 存储的 key 保持一致,也就是我这个list 叫什么名字不要搞错了

r1 = redis.Redis(host=ip, port=6379, db=0, decode_responses=True)  # 建立连接
for i in range(10):
    r1.lpush(redis_range_name, i)  # 保存数据到redis 

二、读取redis 中的数据与展示

1.读取Redis List的Loss值函数

详细说明请看注释

# 定义函数获取当前redis 的loss 值的状况。
# redis_range_name,表示当前在redis 中list 存储着的 loss值的 key,可以自定义修改,两边对应起来就可以。
def now_loss(redis_range_name='loss_val'):
    ip = '127.0.0.1'  # 远程主机 或本地ip
    r1 = redis.Redis(host=ip, port=6379, db=0, decode_responses=True)  # redis 与主机远程连接,这里是无密码版,密码版需要更新redis.conf 配置
    now_loss_list = r1.lrange(redis_range_name, 0, -1)[::-1]  # [::-1]用于反转,这里说了redis 的List是 LIFO机制
    now_loss_list = [eval(i) for i in now_loss_list]  # 存储的是字符形式需要eval 改变下 ,比直接用int float double 好
    return now_loss_list

2. Pycharm环境下动态显示Loss值

  1. 不用远程服务器的pycharm可以关闭Setting 中的Tools – Python Scientific – Show plots in tool window 。这个可以像社区版的pycharm 用Matplotlib 画图的时候出现一个弹窗 ,动态刷新的图片更加稳定。
    在这里插入图片描述
    2.如果你正在调用Linux服务器,若关闭上面的Show plots in tool window 可能会报错,也没事我们可以在 pycharm的 SciView中观察。部分内容在代码注释里面
# encoding:utf8
# 免密码的redis,实时显示loss值的趋势
# author : 半斤地瓜烧
import time
import redis
import matplotlib.pyplot as plt
import random


# 返回当前的redis函数值
# 即 ltrim key start end 中的start要比end大即可,数值且都为正数 ,清空当前的list,修建语句这里用于清空
def update(update_content: list):
    ax = []
    ay = []
    plt.ion()  # 开启一个画图的窗口
    for v, i in enumerate(update_content):  # 遍历0-99的值
        ax.append(v)  # 添加 i 到 x 轴的数据中
        ay.append(i)  # 添加 i 的平方到 y 轴的数据中
        plt.clf()  # 清除之前画的图
        plt.plot(ax, ay)  # 画出当前 ax 列表和 ay 列表中的值的图形
        plt.pause(0.01)  # 暂停一秒
        plt.ioff()  # 关闭画图的窗口


# 定义函数获取当前redis 的loss 值的状况。
# redis_range_name,表示当前在redis 中list 存储着的 loss值的 key,可以自定义修改,两边对应起来就可以。
def now_loss(redis_range_name='loss_val'):
    ip = '127.0.0.1'  # 远程主机 或本地ip
    r1 = redis.Redis(host=ip, port=6379, db=0, decode_responses=True)  # redis 与主机远程连接,这里是无密码版,密码版需要更新redis.conf 配置
    now_loss_list = r1.lrange(redis_range_name, 0, -1)[::-1]  # [::-1]用于反转,这里说了redis 的List是 LIFO机制
    now_loss_list = [eval(i) for i in now_loss_list]  # 存储的是字符形式需要eval 改变下 ,比直接用int float double 好
    return now_loss_list


if __name__ == '__main__':
    # update(now_loss())
    last_len = 0
    interrupt_time = 5  # 检测更新的时间间隔,根据服务器的运行状况和代码跑的状况灵活自行调节
    while True:  # 一直死循环检测redis 是否更新数值

        loss_list = now_loss()
        now_len = len(loss_list)
        update_len = now_len - last_len  # 比较长度来说明是否有更新数据了
        if update_len > 0:  # 是否需要更新
            print("已有更新的loss值")
            print(loss_list)
            update(loss_list)
            last_len = now_len
            time.sleep(interrupt_time)  # 休眠时长
        else:
            time.sleep(interrupt_time)

看看是不是你想要的效果?

127.0.0.1:6379> lpush loss_val 37
(integer) 27
127.0.0.1:6379>

是你要找的效果吗

3. Jupyter Notebook环境下动态显示Loss值

原理是一样的,就是Jupyter Notebook环境 效果有点不一样,只要开好远程连接,即可随时随地在任何可以上网的设备上看看你的代码跑得怎么样了,感觉还是蛮实用的。

  1. 在PC上

在这里插入图片描述

  1. 在平板、手机上也可以:

在这里插入图片描述
Jupyter版代码有点不一样,我觉得在Jupyter Notebook 上的效果更好。

# 免密码的redis,实时显示loss值的趋势
# author : 半斤地瓜烧
import time
import redis
import matplotlib.pyplot as plt
%matplotlib inline
from IPython import display


# 返回当前的redis函数值
# 即 ltrim key start end 中的start要比end大即可,数值且都为正数 ,清空当前的list,修建语句这里用于清空
def update(update_content: list):
    ax = []
    ay = []
    plt.ion()  # 开启一个画图的窗口
    for v, i in enumerate(update_content):  # 遍历0-99的值
        ax.append(v)  # 添加 i 到 x 轴的数据中
        ay.append(i)  # 添加 i 的平方到 y 轴的数据中
        display.clear_output(wait=True)  # 这样就可以只显示一个窗口的动态图
        plt.plot(ax, ay)  # 画出当前 ax 列表和 ay 列表中的值的图形
        plt.pause(0.01)  # 暂停一秒
        plt.ioff()  # 关闭画图的窗口


# 定义函数获取当前redis 的loss 值的状况。
# redis_range_name,表示当前在redis 中list 存储着的 loss值的 key,可以自定义修改,两边对应起来就可以。
def now_loss(redis_range_name='loss_val'):
    ip = '127.0.0.1'  # 远程主机 或本地ip
    r1 = redis.Redis(host=ip, port=6379, db=0, decode_responses=True)  # redis 与主机远程连接,这里是无密码版,密码版需要更新redis.conf 配置
    now_loss_list = r1.lrange(redis_range_name, 0, -1)[::-1]  # [::-1]用于反转,这里说了redis 的List是 LIFO机制
    now_loss_list = [eval(i) for i in now_loss_list]  # 存储的是字符形式需要eval 改变下 ,比直接用int float double 好
    return now_loss_list


if __name__ == '__main__':
    # update(now_loss())
    last_len = 0
    interrupt_time = 5  # 检测更新的时间间隔,根据服务器的运行状况和代码跑的状况灵活自行调节
    while True:  # 一直死循环检测redis 是否更新

        loss_list = now_loss()
        now_len = len(loss_list)
        update_len = now_len - last_len  # 比较长度来说明是否有更新数据了
        if update_len > 0:  # 是否需要更新
            print("已有更新的loss值")
            print(loss_list)
            update(loss_list)
            last_len = now_len
            time.sleep(interrupt_time)  # 休眠时长
        else:
            time.sleep(interrupt_time)

总结

1. 跑模型的代码尽管跑,时不时提交一下Loss值到Redis就可以。将可视化的代码和跑模型的代码分割开,对代码管理也有帮助。
2. 保存在redis 更加轻便,对接多个设备,不同环境效果非常不错。
3. 本文例子中的可视化仅供参考,比较简洁,包括标题,epoch 说明 ,XY 轴刻度设计合理等界面问题还有待开发,欢迎开发者分享下可视化美感设计。

如果对你有帮助,欢迎打赏

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值