tensorflow打印模型图_从Tensorflow模型文件中解析并显示网络结构图(pb模型篇)...

最近看到一个巨牛的人工智能教程,分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。平时碎片时间可以当小说看,【点这里可以去膜拜一下大神的“小说”】。

Tensorflow官方提供的Tensorboard可以可视化神经网络结构图,但是说实话,我几乎从来不用。主要是因为Tensorboard中查看到的图结构太混乱了,包含了网络中所有的计算节点(读取数据节点、网络节点、loss计算节点等等)。更可怕的是,如果一个计算节点是由多个基础计算(如加减乘除等)构成,那么在Tensorboard中会将基础计算节点显示而不是作为一个整体显示(典型的如Squeeze计算节点)。最近为了排查网络结构BUG花费一周时间,因此,狠下心来决定自己写一个工具,将Tensorflow中的图以最简单的方式显示最关键的网络结构。

1 Tensor对象与Operation对象

Tensorflow中,Tensor对象主要用于存储数据如常量和变量(训练参数),Operation对象是计算节点,如卷积计算、反卷积计算、ReLU等等。每一个Operation对象均有输入和输出Tensor,同理,每个Tensor对象均有对应生成该Tensor的Operation对象和使用该Tensor对象作为输入的Operation对象。Tensor和Operation对象内均有相关属性和函数来获取其关联的Operation和Tensor对象,相关属性如下所示。

Tensor对象的op属性指向生成该Tensor的Operation对象。

Tensor对象的consumers()函数获取使用该Tensor对象作为输入的Operation对象。

Operation对象的inputs属性指向该计算节点的输入Tensor对象。

Operation对象的outputs属性执行该计算节点的输出Tensor对象。

如下图所示的网络结构中,调用Tensor_2对象的consumers()函数,返回的是[op_1,op_2]。Tensor_3的op属性指向的是op_1。op_1的inputs属性指向的是[Tensor_1,Tensor_2],op_1的output属性指向的是[Tensor_3]。

Tensor与Operation

有了Tensor与Operation对应在图中的关联关系,就可以将网络结构给画出来。

2 提取pb文件中的网络结构图

pb文件是将模型参数固化到图文件中,并合并了一些基础计算和删除了反向传播相关计算得到的protobuf协议文件。如果读者还不懂如何将CKPT模型文件转pb文件,请参考我另一篇文章《 Tensorflow MobileNet移植到Android》的第1节部分。有了pb模型文件后,接下来是加载模型,加载pb模型示例代码如下所示。

def read_graph_from_pb(tf_model_path ,input_names,output_name):

with open(tf_model_path, 'rb') as f:

serialized = f.read()

tf.reset_default_graph()

gdef = tf.GraphDef()

gdef.ParseFromString(serialized)

with tf.Graph().as_default() as g:

tf.import_graph_def(gdef, name='')

with tf.Session(graph=g) as sess:

OPS=get_ops_from_pb(g,input_names,output_name)

return OPS

其中,倒数第2行调用到的函数get_ops_from_pb()用于获取网络结构图中指定输入节点和指定输出节点之间的计算节点。之所以要指定输入和输出,是为了将输入之前的计算节点(如加载数据队列等相关计算节点)和输出之后的计算节点(如计算loss等相关计算节点)去除,免得碍眼。函数get_ops_from_pb()实现代码如下。

def get_ops_from_pb(graph,input_names,output_name,save_ori_network=True):

if save_ori_network:

with open('ori_network.txt','w+') as w:

OPS=graph.get_operations()

for op in OPS:

txt = str([v.name for v in op.inputs])+'---->'+op.type+'--->'+str([v.name for v in op.outputs])

w.write(txt+'\n')

inputs_tf = [graph.get_tensor_by_name(input_name) for input_name in input_names]

output_tf =graph.get_tensor_by_name(output_name)

OPS =get_ops_from_inputs_outputs(graph, inputs_tf,[output_tf] )

with open('network.txt','w+') as w:

for op in OPS:

txt = str([v.name for v in op.inputs])+'---->'+op.type+'--->'+str([v.name for v in op.outputs])

w.write(txt+'\n')

OPS = sort_ops(OPS)

OPS = merge_layers(OPS)

return OPS

在裁剪网络结构(即只保留input_names和output_name之间节点)之前,先将原始的网络结构写入到ori_network.txt中,文件中,每一行写入:输入Tensor---->op---->输出Tensor。接下来调用函数get_ops_from_inputs_outputs获取指定节点之间的节点。并调用sort_ops函数对所有的节点排序,以保证被依赖的节点总是出现在相关节点之前。最后调用merge_layers函数,将一些可以合并的计算合并成一个独立的节点,例如,Squeeze计算相关节点合并成一个单独的Squeeze节点,又如const-->identity两个计算节点可以直接忽略(即删除)。

注意:篇幅有限,这里不再将函数get_ops_from_inputs_outputs、sort_ops、merge_layers贴出,相关代码请前往文尾提供的源码地址中阅读。

3 绘制网络结构

考虑到SVG绘制图形的简单易用优点,将排好序的网络计算节点和相关Tensor对象数据以Javascript字符串的形式写入到HTML中,使用标签绘制箭头,使用标签绘制矩形,使用标签绘制椭圆,使用标签显示文字。绘制类似于如下所示图像

绘制网络结构示例

注意:篇幅有限,这里不再介绍Javascript代码解析模型结构和SVG显示相关的原理,相关代码请前往文尾提供的源码地址中阅读。

4 测试模型显示

以《MobileNet V1官方预训练模型的使用》文中介绍的MobileNet V1网络结构为例,下载MobileNet_v1_1.0_192文件并压缩后,得到mobilenet_v1_1.0_192_frozen.pb文件。我们还需要知道mobilenet_v1_1.0_192_frozen.pb模型对应的输入和输出Tensor对象的名称,好在MobileNet_v1_1.0_192压缩包中包含文件mobilenet_v1_1.0_192_info.txt。通过该文件可知,输入Tensor的名称为:input:0,输出Tensor名称为:MobilenetV1/Predictions/Reshape_1:0。有了这些信息后,调用函数read_graph_from_pb得到静态图的节点列表对象ops,调用函数gen_graph(ops,"save/path/graph.html")后,在目录save/path中得到graph.html文件,打开graph.html后,显示结果如下。

显示网络结构分两种模式:合并模式和展开模式,分别如下图所示。

合并模式网络结构

截取的展开模式网络结构

5 源码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法题目——省份数量(dfs,bfs)

题目链接:leetcode.547省份数量 dfs: 深度优先遍历:递归 思路:读入数据完成后 重点:建立一个数组记录该省份是否访问,新建一个元素记录省份圈的个数 1.对所有省份循环一次,如果该省份未被访问,则进入dfs 2.dfs中,对所有省份循环一遍,如果未被访问且省份index可以到达…

两台思科交换机vlan划分_Cisco交换机Vlan划分及ACL配置详细步骤 | 吴文辉博客

一、开机1、如是新设备,开机需跳过系统默认配置模式,进入手动配置模式。2、进入用户模式,系统提示符为 >,此模式只能查看统计信息,无配置功能。3、用户模式下,输入 enable ,进入特权模式&…

用重构指导Clean Code(二):依恋情结和switch语句

书接上回,我们继续聊如何用重构指导Clean Code。在Clean Code的3.4节中有这样一段代码(代码清单3-4)。(第3章主要讲的是函数,而3.4节讨论的是switch语句。)public Money calculatePay(Employee e) throws I…

算法题目——杨辉三角问题

思路: #include<iostream> #include<cstdio> #include<cstring> #

cascade down_Cascaded CNN 方法寻找人脸关键点

Cascaded CNN 方法寻找人脸关键点论文笔记阅读论文第一阶段阅读论文&#xff0c;大约两天大体阅读完论文 Deep Convolutional Network Cascade for Facial Point Detection。感觉还是比较缺乏论文阅读经验&#xff0c;但是比以前快了很多。主要阅读论文 intro、method 和 model…

了解一下HTTP1.1 Pipelining技术

为什么谈HTTP1.1 Pipelining呢&#xff1f;主要问题根源还是来源于Beetlex参加了techempower的测试。先看一下以下两项测试的结果&#xff1a;以上分别是.net平台的Json和Plaintext的测试结果&#xff0c;其实Plaintext最高能跑700多万RPS已经完全超了对网络IO读写损耗的认知&a…

springboot2 多线程写入数据_解决SpringBoot项目使用多线程处理任务时无法通过@Autowired注入bean问题...

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":7,"count":7}]},"card":[{"des":"EDAS 是一个应用托管和微服务管理的PaaS平台…

算法题目——子序列和问题(poj-3061)(尺取法)

题目链接:POJ-3061 题意:给定一个序列,使得其和大于或等于S,求最短的子序列长度。 问题分析: 1.首先序列都是正整数,当子序列和大于等于S时,已经没有必要再将右端点继续向右移动。因为再向右移动,序列的长度一定会大于此时的长度 2.所以,当子序列和小于S时,右端点向…

读书 | 数字化转型的道与术(下)

【数字化转型】| 作者 / Edison Zhou这是EdisonTalk的第313篇学习总结 最近在阅读钟华老师的新作《数字化转型的道与术》&#xff0c;记录和总结了一些学习笔记和感想&#xff0c;整理成文分享与你&#xff0c;本文为下半部分&#xff0c;希望能对也在参与数字化转型的各位童鞋…

算法题目——读书知识点统计问题(POJ-3320)(尺取法)

题目链接:poj-3320 问题:杰西卡是一个非常可爱的女孩,受到许多男孩的追捧。最近她有个问题。期末考试快到了,但她几乎没花什么时间。如果她想通过考试,她必须掌握一本厚厚的教科书中包含的所有思想。那本教科书的作者和其他作者一样,对这些观点极为挑剔,因此有些观点被…

aop springboot 传入参数_Springboot添加AOP打印请求参数

1. 引入依赖org.springframework.bootspring-boot-starter-aop2. 写切面切面类需要加Aspect和Component注解package com.test.demo.aspect;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.Pro…

GraphQL:面对复杂类型

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述&#xff0c;使得客户端能够准确地获得它需要的数据&#xff0c;而且没有任何冗余&#xff0c;也让 API 更容易地随着时间推移而演进&#xff0c…

算法与数据结构——并查集

文章推荐:【算法与数据结构】—— 并查集 例子: 数据结构——最小生成树之克鲁斯卡尔算法(Kruskal) 1.2 并查集思想(重点) 我们可以把每个连通分量看成一个集合,该集合包含了连通分量的所有点。而具体的连通方式无关紧要,好比集合中的元素没有先后顺序之分,只有“属于”…

eclipse 输入卡顿_7个小技巧,解决eclipse卡顿问题

eclipse作为开发工具&#xff0c;每天都要使用&#xff0c;你肯定遇到过eclipse卡到想哭的时刻&#xff0c;严重影响开发效率啊&#xff01;如果内存条不要钱&#xff0c;那就加内存吧&#xff01;一个不够加两个&#xff01;当然这都是玩笑话&#xff0c;如果不花钱也能解决问…

为什么建议学生积极参与开源项目?

喜欢就关注我们吧&#xff01;“ 你参与过开源项目吗&#xff1f;” 随着开源技术对信息产业的积极影响进一步扩大&#xff0c;越来越多的面试官将是否参与开源项目作为考核开发者能力的一项基本指标。对于求职者来说&#xff0c;参与开源能为简历增色不少 &#xff0c;增加赢得…

mysql 左连接 怎么走索引_数据库索引、左连接、右连接、等值连接

在MySQL中&#xff0c;主要有四种类型的索引&#xff0c;分别为&#xff1a;B-Tree索引&#xff0c;Hash索引&#xff0c;Fulltext索引(MyISAM 表)和R-Tree索引&#xff0c;本文讲的是B-Tree索引。一、Mysql索引主要有两种结构&#xff1a;BTree索引和Hash索引(a) Innodb存储引…

微服务技术栈及分享计划

前言上一篇对微服的演变、优缺点进行了概述&#xff0c;对于业务复杂项目&#xff0c;微服务算是比较合适的解决方案&#xff1b;对于咱们开发者来说&#xff0c;有好的解决方案肯定要跟进学习&#xff0c;但不能盲目追崇流行技术&#xff0c;目的还是为了解决问题。这里就把As…

PAT乙级题目——1002写出这个数

问题分析&#xff1a;1.数据比较大&#xff0c;并且输入数据时没有停顿&#xff0c;所有使用字符串来存储数据 string str""; cin>>str;2.使用字符串数组来存储每个数字的拼音 string S[10]{"ling","yi","er","san"…

northstar机器人编程_《机器人构建实战》——导读

前言机器人构建实战机器人是21世纪发展最为迅速、应用前景最为广阔的科学技术领域之一。机器人技术综合运用了基础科学和应用工程技术的最新成果&#xff0c;是一个国家科技发展水平和国民经济现代化、信息化的重要标志&#xff0c;是世界强国重点发展的高技术之一。近年来&…

Linux性能挖潜的隐藏招数:内核CPU亲和性参数调整

作者&#xff1a;李彬&#xff0c;赵雪枫&#xff0c;金融科技工程师&#xff0c;架构师社区特邀作者&#xff01;应用服务性能调优&#xff0c;是每个系统投产前都需要关注的问题&#xff0c;系统及软件层面的调优方法均有大量文章介绍&#xff0c;但在所有招数使出后&#xf…