当使用Tensorboard进行神经网络训练的可视化时,训练完后可能有许多记录文件夹,在shell里使用命令查看各个训练结果十分不便(需要指定具体的文件夹),因此有了在文件浏览器中添加右键菜单,快速打开Tensorboard查看记录的想法。
由于自己使用的是Ubuntu自带的Gnome桌面,而Nautilus又原生提供自定义脚本的功能,因此参考[1]即可实现脚本的添加,需要注意的是~/. local /share/nautilus/scripts
中的脚本需要设置为可执行
才能被添加到右键菜单中。
这是是我遇到的坑最多的地方,现在功能实现后再回过头反思,觉得问题主要出在一开始需求定义的时候把简单的需求复杂化了。
其实一开始只是觉得在shell里输入tensorboard的启动命令太麻烦了(需要指定具体的文件夹),所以想在右键菜单里加一个命令,可以直接在shell中启动tensorboard
命令,并指定logdir
为当前选择的文件夹。实现该功能最简单的方法就是使用shell脚本。
但是一开始我的想法是不显示shell界面,而是用python脚本在后台执行tensorboard
命令,并且实时获取tensorboard
命令的输出,当得到tensorboard输出的url时,利用PyGObject
模块显示一个对话窗口,点击该对话窗口中的按键即可打开浏览器查看可视化结果。但是在这其中遇到了许多坑,最终也没有实现,这里把遇到的坑做一个记录。
shell的解释器:
#!/bin/bash
python的解释器:
#!/usr/bin/env python
ERROR: Could not build wheels for PyGObject which use PEP 517 and cannot be installed directly
以及undefined symbol: cairo_svg_surface_set_document_unit
。pip3 install pycairo==1.11.1
;python -m pip install --no-use-pep517 PyGObject
进行安装。http://localhost:6006/
的url,在这里遇到的一个坑是tensorboard的输出是以stderr
的方法打印的,而不是通常的stdout
,这一点可以参考代码注释。#!/usr/bin/env python
import os
from subprocess import Popen, PIPE
import re
def Find(string):
# findall() has been used
# with valid conditions for urls in string
regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))"
url = re.findall(regex,string)
return [x[0] for x in url]
def run(command):
# 这里一定要注意是stderr,否则无法获取到tensorboard的打印输出
sub=Popen(command, stderr=PIPE, shell=True)
while True:
line = sub.stderr.readline().rstrip().decode('utf8')
if not line:
break
yield line
if __name__ == "__main__":
selected = os.environ.get('NAUTILUS_SCRIPT_SELECTED_FILE_PATHS', '')
command = "tensorboard "+"--logdir "+selected
for path in run(command):
url=Find(path)
if url:
break
方案二就是改用shell脚本,而非python脚本,这种方案虽然视觉效果可能没有方案一好,但是却是最直接,最快速的实现,最终脚本如下:
#!/bin/bash
for url in $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS
do
cmd="source /home/wangpeng/anaconda3/bin/activate; conda activate base; tensorboard --logdir $url ; bash"
gnome-terminal -- bash -c "$cmd ;read"
done
在实现的过程中,同样遇到了一些坑,记录一下:
=
之间不能有空格,另外[2]比较详细地介绍了shelll中字符串的声明方法及需要注意的项。下面这样可以正确赋值:
cmd="abc"
但是这样就无法正确赋值:
cmd = "abc"
NAUTILUS_SCRIPT_SELECTED_FILE_PATHS
就是我们需要的环境变量,本来以为该变量是以数组形式存储的,所以想通过${NAUTILUS_SCRIPT_SELECTED_FILE_PATHS[0]}
来获取每个值[4],然而实际上并不能通过这种方式来枚举,这里如果如果有大佬知道解决方案,还请留言赐教。for xx in xx
的方式来获取各个值。NAUTILUS_SCRIPT_SELECTED_FILE_PATHS:用新行分开的所选文件的路径(除非是本地文件) # 是当前选择的文件(夹)的路径
NAUTILUS_SCRIPT_SELECTED_URIS:用新行分开的所选文件的 URI # 是当前选择的文件(夹)的URI(即带有file:\\前缀)
NAUTILUS_SCRIPT_CURRENT_URI:当前位置的 URI # 是当前选择的文件(夹)的URI(即带有file:\\前缀)
NAUTILUS_SCRIPT_WINDOW_GEOMETRY:当前窗口的位置和大小
解决方案不止一种,时间紧张的情况下,优先考虑最快速的方案,不要太纠结于形式。
[1]ubuntu14.04右键菜单添加sublime打开选项
[2]shell脚本系列:shell脚本中的字符串
[3]Linux nautilus 右键菜单脚本
[4]linux的shell数组变量,给环境变量赋多个值