文章目录
前言
当我在跑一个深度学习或者神经网络模型等训练时,我们常常需要跑很多个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值
- 不用远程服务器的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环境 效果有点不一样,只要开好远程连接,即可随时随地在任何可以上网的设备上看看你的代码跑得怎么样了,感觉还是蛮实用的。
- 在PC上
- 在平板、手机上也可以:
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 轴刻度设计合理等界面问题还有待开发,欢迎开发者分享下可视化美感设计。
如果对你有帮助,欢迎打赏