原文发表在 TensorBoard Projector 简易指南 - Alan Lee。

TensorBoard(TB)是一个非常棒的模型可视化工具,早期我也写过一篇文章来详细介绍各个面板。

不过士别三日,当刮目相待。现在的 TB 和那时相比变化太多了,增加了许多功能面板,绝大部分我都还没怎么用过。其中最吸引我的面板之一就是 Projector,虽然我现在工作中并不怎么用到。

现在终于抽出时间,来完整体验并写一篇 TensorBoard Projector(TBP)的简易教程。

本文将会从原始文本出发(中文),经过训练 embedding、生成所需文件等步骤,一步一步,最终使用 TBP 来可视化 embedding,并解决中文标签不能显示的问题。

我们先来看下最终效果:

虽然说现在 BERT 等预训练模型大行其道,但我还是想从更“复古”的词向量出发。当然如果你想使用 BERT 来生成 embedding,也是完全没有问题的,框架是相同的。

此外,这个过程和你所使用的库无关,无论你是 Numpy、Scipy 还是 TensorFlow、PyTorch,只要能够得到 embedding 向量,那就都没有问题。

使用 TBP 可视化 embedding 的基本逻辑是很简单的:

  1. 得到一些词及其 embedding。
  2. 将他们按照 TBP 认可的对应关系放到文件中。
  3. TBP 读取文件并可视化。

相应的我们需要下列文件:

  1. 原始文本和 embedding 模型:用以得到词及其 embedding。
  2. metadata.tsvtensor.tsvsprite.jpg:分别用于存放词、embedding 和词对应的图片(当然也可以是 PNG),最后一个用于解决中文标签不能显示的问题。
  3. projector_config.pbtxt:用于告诉 TBP 上述文件的位置以及其他配置。

下面我们就来一步一步看如何得到这些文件。

词及词向量

对原始文本使用 spacy 分句,共得到约 38 万句子。然后使用 jieba 和自定义词典进行分词,得到tokenized_sents.txt,该文件格式是一行一个分词后的句子,词之间空格分隔。词向量使用 gensim 的fasttext模型训练得到,维度 300。为减少词的数量,去掉停用词。

# Train embeddings
model = FastText(vector_size=300, window=5, min_count=10)
model.build_vocab(corpus_file='tokenized_sents.txt')
model.train(corpus_file='tokenized_sents.txt', total_examples=model.corpus_count, epochs=10, total_words=model.corpus_total_words)
model.save('fasttext.model')

metadata.tsv 和 tensor.tsv

metadata.tsv 的常见格式有两种:没有表头,只有一列;有表头,有两列。前者(格式 1)就是 NLP 中常见的 vocab.txt 的格式,一行一个词。后者(格式 2)的两列一般表示 index 和 label。label 就表示该样本所属的标签,一般多见于分类数据集。实际上格式 1 是格式 2 的特例,相当于默认认为其行号就是 index,行内容就是 label。

metadata.tsv 也可以有多列,多出来的列可以用来表示其他属性信息。

tensor.tsv 用于存储与 metadata.tsv 对应的 embeddings。顺序必须一致,即 metadata.tsv 中第 i 行的词,其 embedding 也必须是 tensor.tsv 中的第 i 行。embedding 中的数字用 \t 分隔。

接上,我们得到模型后,使用其得到的 vocab 及对应的 embedding 来生成这两个文件:

stopwords = Path("hit_stopwords.txt").read_text(encoding="utf8").splitlines()
model = FastText.load("fasttext.model")
words = [word for word in model.wv.key_to_index.keys() if word not in stopwords]  # 排除掉停用词
logdir = Path('projector/')  # 文件存储目录metadata_filename = 'metadata.tsv'
lines = ["index\tlable"]  # 此处我们存成两列,你也可以不要表头,只存词
for i, word in enumerate(words):lines.append(f"{i}\t{word}")
logdir.joinpath(metadata_filename).write_text("\n".join(lines), encoding="utf8")tensor_filename = 'tensor.tsv'
lines = ["\t".join(map(str, model.wv[word])) for word in words]
logdir.joinpath(tensor_filename).write_text("\n".join(lines), encoding="utf8")

sprite.jpg

正如开头给出的效果图一样,图中每个点都是有一个 label 的,这个 label 就是词。如果我们直接这样启动 tensorboard,会看到如下页面:

Projector 默认页面,不显示 3D 标签

但启用 3D 标签模式的话,我们将会看到下图所示的样子:

点击左上角的“A”开启 3D 标签模式后

我们可以看到所有的中文词都不见了,只剩下了数字字母等标签。

这是因为 tensorboard 目前还不支持所有 Unicode 字符标签,只支持 ascii 字符。

BUT!关闭 3D 标签模式后,如果你点击其中一个点,你会惊奇地发现又能显示中文标签了:
{% image https://s2.loli.net/2021/12/18/ft6WZmqrhuUdXTP.png “中文标签又回来了” %}

一个 workaround 是将汉字转成图片,用图片来作为 label,就像官方给出的 mnist 例子一样:

官方 Mnist 例子

但是由于每个词所含字的数量都不同,同时又需要尽量让词铺满整个图片,所以不同图片中字的 fontsize 都是不同的,需要视情况调整,这是一个迭代的过程。而转图片我们可以借助 PIL 来完成:

def text2image(text, imgfile):image = Image.new("RGB", (50, 50), color=(255, 255, 255))draw = ImageDraw.Draw(image)fontsize = 1  # starting font sizefontpath = "simhei.ttf"# portion of image width you want text width to beimg_fraction = 0.9font = ImageFont.truetype(fontpath, fontsize)while (font.getsize(text)[0] < img_fraction * image.size[0]) and (font.getsize(text)[1] < img_fraction * image.size[1]):# iterate until the text size is just larger than the criteriafontsize += 1font = ImageFont.truetype(fontpath, fontsize)# optionally de-increment to be sure it is less than criteriafontsize -= 1font = ImageFont.truetype(fontpath, fontsize)# print('final font size',fontsize)draw.text((0, 0), text, font=font, fill=(0, 0, 0))  # put the text on the imageimage.save(imgfile)  # save it

当我们把所有词都转成图片后,再将这些图片,按照一定规则拼接到一起,最终形成的这么一个大图,就是所谓的 sprite.jpg

Sprite Image


Mnist 例子中的 sprite image

那么按照什么规则来拼接呢?

sprite.jpg 必须是正方形,每个小图也最好是正方形,意味着行列上的小图数量必须是相等的,而且 tensorboard 读这个 sprite 的时候是按照行优先的顺序读的。所以假设你有 8 张小图,那么最终的摆放顺序就是下面这样:

8 张小图时的摆放顺序

最后那一格是空白的,也就是全白。

当然也有可能最后一行都是空白的,例如你有 5 张小图,那么要想每行每列上的小图数量是一样的,那么每行每列上就得有 3 张小图:

5 张小图时的摆放顺序

这样不仅第二行最后一格是空白的,就连第三行整行都是空白的。

所以总结来说,假设你有 nnn 张小图,那么每行每列上小图的数量就是 ⌈n⌉\lceil \sqrt n \rceiln

,即根号 nnn 然后上取整。

具体代码如下:

def text2image(text, imgfile):image = Image.new("RGB", (50, 50), color=(255, 255, 255))draw = ImageDraw.Draw(image)fontsize = 1  # starting font sizefontpath = "simhei.ttf"# portion of image width you want text width to beimg_fraction = 0.9font = ImageFont.truetype(fontpath, fontsize)while (font.getsize(text)[0] < img_fraction * image.size[0]) and (font.getsize(text)[1] < img_fraction * image.size[1]):  # 保证词在行列上均不超出图片范围# iterate until the text size is just larger than the criteriafontsize += 1font = ImageFont.truetype(fontpath, fontsize)# optionally de-increment to be sure it is less than criteriafontsize -= 1font = ImageFont.truetype(fontpath, fontsize)# print('final font size',fontsize)draw.text((0, 0), text, font=font, fill=(0, 0, 0))  # put the text on the imageimage.save(imgfile)  # save it

projector_config.pbtxt

在得到了 metadata.tsvtensor.tsvsprite.jpg 后,我们还需要告诉 tensorboard 这些文件的位置和每个小图的维度,所以我们需要一个 .pbtxt 文件来指定这些信息。

我们可以用以下程序来生成该文件:

from tensorboard.plugins import projectorconfig = projector.ProjectorConfig()
embedding = config.embeddings.add()
embedding.metadata_path = metadata_filename
embedding.tensor_path = tensor_filename
embedding.sprite.image_path = sprite_filename
embedding.sprite.single_image_dim.extend([unit_dim, unit_dim])  # unit_dim 就是小图维度
projector.visualize_embeddings(logdir, config)

然后就会得到一个名为 projector_config.pbtxt 的文件,文件内容如下:

embeddings {metadata_path: "metadata.tsv"sprite {image_path: "sprite.jpg"single_image_dim: 50single_image_dim: 50}tensor_path: "tensor.tsv"
}

当然你也可以按照这个格式直接手动创建这个文件。

启动

万事俱备,只欠东风。

现在我们终于可以启动 tensorboard 了:

$ tensorboard --logdir=projector/

projector/ 就是你上面指定的 logdir

然后根据提示在浏览器打开 http://localhost:6006/#projector 就可以看到页面了,你可以在这里尝试不同降维算法的效果,也可以点击或搜索图上的词来查看其相似词,大致评估下 embedding 的效果。

“捷克共和国”的近义词

扩展

Embedding Projector 中的点不仅仅可以是图像、词,理论上只要是可以 embedding 的东西,就可以显示。而且你懂的,万物皆可 embedding……

TensorBoard Projector 简易指南相关推荐

  1. git 简易指南+常用命令

    git 简易指南                      git 常用命令   ----------------------------------------------------------- ...

  2. 如何启动 WordPress 博客 – 简易指南 – 创建博客(2021)

    您想以正确的方式创建 WordPress 博客吗?我们知道,特别是当您不是技术极客时,创建博客可能是一个复杂的想法.在帮助许多用户创建博客后,我们决定创建最全面的指南,介绍如何在没有任何技术知识的情况 ...

  3. git - 简易指南

    http://www.bootcss.com/p/git-guide/ 转载于:https://www.cnblogs.com/passer1991/p/3279333.html

  4. 如何取消linux响铃_linux初学者入门:VIM编辑简易指南(常用操作)

    在linux低下最常用的文本编辑器为vim,如何进入编辑模式 i,I,a,A (i,在光标当前位置插入,a在当前位置追加),o,O在一个新的一行输入新字符,r,R为取代原来的字符以上输入都在一般模式当 ...

  5. 快速制作U盘WIN PE启动盘简易指南

    什么是WIN PE呢?WIN PE是一个精简过的WIN XP操作系统,具有图形界面的特点很适合做系统崩溃后的救急平台,是一个功能强大的维护工具,在没有光驱的情况下还可以用来硬盘安装WIN 98/WIN ...

  6. git reset --hard_Git紧急自救简易指南(二)——版本的游历

    这一篇重点说说 Git版本的游历,想要在不同版本之间操作,这个就要涉及到git一个非常重要的部分--日志管理 查看历史记录 git log 此命令用来查看版本的历史记录 比如说我这里添加了5条记录 由 ...

  7. php myflow,WordPress安装使用Flowplayer简易指南

    本文是简单易懂的现代魔法系列文章的第二弹~ 一.Flowplayer简介FlowPlayer 是一个用Flash开发的在Web上的视频播放器,可以很容易将它集成在任何的网页上.支持HTTP以及流媒体传 ...

  8. linux 更改ssh端口_如何在Linux中更改SSH端口-简易指南

    linux 更改ssh端口 The default port on SSH is 22. But for security reasons, it's a good idea to change SS ...

  9. 在虚拟机上安装Kali Linux的简易指南

    Let's learn to install Kali Linux on a Virtual machine today. If you want to venture into the field ...

  10. 从零开始山寨Caffe·伍:Protocol Buffer简易指南

    你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? --欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...

最新文章

  1. python输入input的用法
  2. Qt Creator浏览ISO 7000图标
  3. ①你真的学会Java了吗?来自《卷Ⅰ》的灵魂提问
  4. 路由 RIP 协议 和 滞空路由
  5. MyEclipse中流程定义文件保存时自动生成流程图
  6. Spring Cloud 之 Eureka.
  7. 日本词汇的认识与理解
  8. vue实现二维码扫码功能
  9. python excel处理重复行并统计个数_python统计一个文本中重复行数的方法
  10. 饥荒:mod教程索引
  11. c语言数据文件是,C语言数据文件操作.ppt
  12. FPGA_Verilog学习之旅(3)---VGA贪吃蛇游戏
  13. SF简易IDC系统V1.0免授权
  14. IDC具体是干什么的?
  15. 微信小程序和用网易新闻api实现自己的微信小程序
  16. [ZT]迅雷的工作原理
  17. 2021.10.12-13科研日志
  18. 十进制与二进制转换 python
  19. java毕业设计大学生规划平台Mybatis+系统+数据库+调试部署
  20. 视频直播类App SDK盘点

热门文章

  1. 解决多次点击出现蓝色背景
  2. 如何快速编写一个汇编软件
  3. oracle的视图和同义词
  4. 樊登读书会掌控读后感_《掌控谈话》读后感1500字
  5. Python学习笔记之小派读诗
  6. 电信物联网平台对接教程
  7. html里怎么旋转视频文件,拍摄的视频如何旋转 三种方法教你旋转视频
  8. 我查查 6.6 去校验分析
  9. ftp 报错 227 Entering Passive Mode (192,168,169,141,213,232)
  10. 【Matlab】前馈控制