创建图像的神经网络结构 [英] Create image of Neural Network structure
问题描述
许多论文使用了非常好的神经网络图像。我也想为我正在写的报告创建这样的图像。
示例:
SegNet:一种用于深度卷积的编解码器架构图片分割,来自V. Badrinarayanan等人,第4页
我的问题:可以使用哪个工具来创建此类图像?尤其是卷积矩形看起来非常好。
非常感谢
<我写了一个小班,可以画出这样的图像。
可以定义一些层(颜色/类型),绘制它们并在它们之间添加一些连接。输出是一个svg文件。
示例输出
代码(最后(如果是__name__ =='__main __',请参见)有生成上面图像的代码):
导入svgwrite
导入数学
def layer_def(type,height,id = None):
返回{
'type':type,
'height':height,
'id':id
}
class CNNDraw:
def __init __(self,dwg):
self .__ dwg = dwg
def draw_arrow(self,p_points,width = 2,color ='black'):
标记= self .__ dwg.marker(insert =(2.1,2),size =(2,4),orient ='auto')
marker.add(self .__ dwg.path(d ='M0,0 V4 L2, 2 Z',fill = color))
self .__ dwg.defs.add(marker)
line = self .__ dwg.add(svgwrite.shapes.Polyline(
p_p美分,stroke_width = width,
stroke ='black',fill ='none'))
line.set_markers((self .__ dwg.marker(),self .__ dwg.marker(),marker) )
def draw_3d_rectangle(self,p_start,width,height,Stretch,fg_color ='white',bg_color ='grey',border_color ='black'):
x_start,y_start = p_start
x_end,y_end = x_start +宽度,y_start +高度
多边形1 = [(x_start,y_start),(x_start +宽度,y_start),(x_start +宽度,y_start +高度), [x_start,y_start +高度)]
多边形2 = [[x_start,y_start),(x_start +拉伸,y_start-拉伸),(x_end +拉伸,y_start-拉伸),(x_end,y_start)]
多边形3 = [(x_end,y_start),(x_end +拉伸,y_start-拉伸),(x_end +拉伸,y_end-拉伸),(x_end,y_end)]
self .__ dwg.add( svgwrite.shapes.Polygon(polygon1,fill = fg_color,stroke = border_color))
self .__ dwg.add(svgwrite.shapes.Polygon(polygon2,fill = bg_color,stroke = border_color))
self .__ dwg.add(svgwrite.shapes.Polygon(polygon3,fill = bg_color,stroke = border_color))
def draw_multiple_layers(self,p_start,p_stretch = 0.4,layer_width = 10,space_width = 7,layers = [],return_hash = True):#个图层=(高度,颜色)
(如果len(layers)== 0:
返回
max_height = max (map(lambda l:l [1],filter(lambda l:isinstance(l,tuple),layers)))
x_offset = 0
side_width_before = 0
Drawn_polygons = []
对于xrange(len(layers))中的n:
layer =层[n]
如果不是isinstance(层,元组):
x_offset + =层
继续
id,高度,fg_color,bg_color =图层
side_width = math.floor(height * p_stretch)
total_width = side_width + layer_width
如果n > 0:如果total_width<
space_offset = space_width
side_width_before:
space_offset = math.floor((side_width_before-total_width)* 0.5)
space_offset = max(space_width,space_offset)
pass
x_offset + = space_offset
curr_p_start =(p_start [0] + x_offset,p_start [1] + math.floor((max_height-height)* 0.5))
self.draw_3d_rectangle(curr_p_start,layer_width,height,side_width,fg_color,bg_color )
Drawn_polygons.append((id,curr_p_start,layer_width,height,side_width))
side_width_before = side_width
x_offset + = layer_width
如果return_hash:
多边形= {}
用于过滤器中的多边形(lambda l:l [0]不为None,drawn_polygons):
多边形[polygon [0]] =多边形[1:]
Drawn_polygons =多边形
返回drawd_polygons
def draw_multiple_defined_layers(self, p_start,layer_definitions = {},layers = []):
plain_layers = []
用于层中的层:
如果不是isinstance(layer,dict):
plain_layers.append (图层)
其他:
layer_definition = layer_definitions [layer ['type']]
如果在layer_definition和layer_definition ['ignore']中忽略:
继续
plain_layer =(layer ['id'],layer ['height'],layer_definition ['fg_color'],layer_definition ['bg_color'])
如果layer_definition中的'add_space_before':
plain_layers.append (layer_definition ['add_space_before'])
plain_layers.append(plain_layer)
如果layer_definition中的'add_space_after':
plain_layers.append(layer_definition ['add_space_after'])
返回自身.draw_multiple_layers(p_start,layers = plain_layers)
def draw_arrow_be tween_points(自我,source_point,target_point,文本=无,y_delta = 10,bottom = False):
(如果不是bottom):
y = min(source_point [1],target_point [1])-y_delta
else:
y = max(source_point [1],target_point [1])+ y_delta
source_delta = source_point [1]-y
target_delta = target_point [1]-y
如果不是最低值:
mp0 =(source_point [0] + source_delta,source_point [1]-source_delta)
mp1 =(target_point [0]-target_delta,target_point [1]-target_delta)
其他:
mp0 =(source_point [0]-source_delta,source_point [1]-source_delta)
mp1 =(target_point [0] + target_delta,target_point [1]-target_delta)
点= [
source_point,
mp0,mp1,
target_point,
]
self.draw_arrow(points)
#如果需要:绘制文字
如果文字i s不是None:
text_lines = text.split('\n')
line_height = 15
mp_middle =(math.floor((mp0 [0] + mp1 [0])* 0.5),math.floor((mp0 [1] + mp1 [1])* 0.5))
如果不是底部:
y_offset = -10-line_height *(len(text_lines)-1)
else:
y_offset = 13
用于text_lines中的text_line:
mp_text =(mp_middle [0],mp_middle [1] + y_offset)
self .__ dwg.add( self .__ dwg.text(text_line,insert = mp_text,text_anchor = middle,style = font-family:Sans-Serif))
y_offset + = line_height
def draw_arrow_between_layers(自我,source_layer,target_layer,text = None,y_delta = 10):
source_point =(source_layer [0] [0] + source_layer [1] + source_layer [3],source_layer [0] [1]-source_layer [ 3])
target_point =(target_layer [0] [0] + target_layer [3],target_layer [0] [1]-target_layer [3])
self.draw_arrow_between_points(source_point,target_point,text,y_delta)
def draw_additive_arrow_between_layers(self,source_layers,target_layer,text = None,y_delta = 10,y_add = 0,bottom = True):
如果是底部:
target_point =(target_layer [0] [0],target_layer [0] [1] + target_layer [2])
#获取源点
sp0 = min(map(lambda l:(l [0] [0] + math.floor(l [1] * 0.5),l [0] [1] + l [2]),source_layers),key = lambda l: l [0])
sp1 = max(map(lambda l:(l [0] [0] + math.floor(l [1] * 0.5),l [0] [1] + l [2 ]),source_layers),key = lambda l:l [0])
sp_y = max(map(lambda l:l [0] [1] + l [2],source_layers))+ 5
sp0d =(sp0 [0],sp_y + y_add)
sp1d =(sp1 [0],sp_y + y_add)
else:
target_point =(target_layer [0] [0] + target_layer [3],target_layer [0] [1]-target_layer [3])
#获取源点
sp0 = min(map(lambda l:(l [0] [0] + l [3] + math.floor(l [1] * 0.5),l [0] [1]-l [3]),source_layers ),key = lambda l:l [0])
sp1 = max(map(lambda l:(l [0] [0] + l [3] + math.floor(l [1] * 0.5) ,l [0] [1]-l [3]),source_layers),key = lambda l:l [0])
sp_y = min(map(lambda l:l [0] [1]-l [3],source_layers))-5
sp0d =(sp0 [0],sp_y-y_add)
sp1d =(sp1 [0],sp_y-y_add)
self .__ dwg.add(svgwrite.shapes.Polyline([sp0,sp0d],stroke_width = 2,stroke ='black',fill ='none'))
self .__ dwg.add(svgwrite。 Shapes.Polyline([sp1,sp1d],stroke_width = 2,stroke ='black',fill ='none'))
如果底部:
mp0 =(sp0d [0] + y_delta,sp0d [1] + y_delta)
mp1 =(sp1d [0]-y_delta,sp1d [1] + y_delta)
else:
mp0 =(sp0d [0] + y_delta, sp0d [1]-y_delta)
mp1 =(sp1d [0]-y_delta,sp1d [1]-y_delta)
mp_middle =(math.fl oor((mp0 [0] + mp1 [0])* 0.5),math.floor((mp0 [1] + mp1 [1])* 0.5))
#绘制第一行
self .__ dwg.add(svgwrite.shapes.Polyline(
[sp0d,mp0,mp1,sp1d],stroke_width = 2,
stroke ='black',fill ='none'))
#现在这行本身
self.draw_arrow_between_points(mp_middle,target_point,text,y_delta,bottom = bottom)
如果__name__ =='__main__':
dwg = svgwrite.Drawing('test.svg')
cnn_draw = CNNDraw(dwg)
#绘制多层
layer_polygons = cnn_draw.draw_multiple_defined_layers((100 ,200),{#开始坐标
#定义几种图层类型
'dropout':{'fg_color':'#ffffcc','bg_color':'#ffff99','ignore ':True},
'conv':{'fg_color':'#e6faff','bg_color':'#99ebff'},
't_conv':{'fg_color':'#ffe6cc' ,'bg_color':'#ffcc99'},
'pool':{'fg_color':'#ccffcc','bg_color':'#99ff9 9','add_space_after':20},
'高档':{'fg_color':'#e6ccff','bg_color':'#cc99ff'}
},[
#要绘制的图层;可以看到一个图层可以有一个ID
layer_def('dropout',300),
layer_def('conv',300),
layer_def('conv',300),
layer_def('pool',300,id ='POOL1'),
layer_def('dropout',250),
layer_def('conv',250),
layer_def('conv',250),
layer_def('pool',250,id ='POOL2'),
layer_def('dropout',200),
layer_def('conv',200),
layer_def('conv',200),
layer_def('pool',200,id ='POOL3'),
layer_def('dropout',150),
layer_def('conv',150),
layer_def('conv',150),
layer_def('pool',150,id =' POOL4'),
layer_def('dropout',100),
layer_def('conv',100),
layer_def('conv',100),
layer_def('pool',100,id ='POOL5'),
layer_def('dropout',50),
layer_def('conv',50),
layer_def('conv',50),
layer_def('pool',50,id ='POOL6'),
layer_def('dropout',30),
layer_def('conv',30,id ='FINAL') ,
#素数只是空格
100,
layer_def('t_conv',50,id ='T_CONV1'),
60,
layer_def('t_conv',100,id ='T_CONV2'),
60,
layer_def('t_conv',150,id ='T_CONV3'),
60,
layer_def('t_conv',250,id ='T_CONV4'),
layer_def('conv',250),
layer_def('conv',250),
layer_def ('conv',250),
layer_def('dropout',250),
layer_def('conv',250),
layer_def('conv',250,id ='FINAL_CONV '),
50,
layer_def('upscale',300,id ='UPSCALED')
])
cnn_draw.draw_arrow_between_layers(layer_polygons ['FINAL'],layer_polygons ['T_CONV1'],text = transposed conv。)
cnn_draw.draw_additive_arrow_between_layers([layer_polygons ['P OOL5'],layer_polygons ['T_CONV1']],layer_polygons ['T_CONV2'],text = element-wise sum和\ntransposed conv。,y_add = 0)
cnn_draw.draw_additive_arrow_between_layers([layer_polygons [' POOL4'],layer_polygons ['T_CONV2']],layer_polygons ['T_CONV3'],text = element-wise sum和\ntransposed conv。,y_add = 0,bottom = False)
cnn_draw.draw_drawitive_arrow_between_layers( [layer_polygons ['POOL3'],layer_polygons ['T_CONV3']],layer_polygons ['T_CONV4'],text = element-wise sum和\ntransposed conv。,y_add = 0)
cnn_draw.draw_arrow_between_layers( layer_polygons ['FINAL_CONV'],layer_polygons ['UPSCALED'],text = upscale)
dwg.save()
Many papers use very nice images of neural networks. I also like to create such an image for a report which i'm writing.
An example: "SegNet: A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation" from V. Badrinarayanan et al., page 4
https://arxiv.org/pdf/1511.00561v3.pdf
My question: Which tool might be used to create such images? Especially the convvolution rectangles look very nice.
Thank you very much
I wrote a small class which helps to draw such images. Probably i will extend and clean it up soon.
It is possible to define some layers (colors / type), draw them and to add some connections between them. The output is a svg file.
Example output
Code (at the end (seeif __name__ == '__main__'
) there is the code to generate the image above):
import svgwrite
import math
def layer_def(type, height, id=None):
return {
'type': type,
'height': height,
'id': id
}
class CNNDraw:
def __init__(self, dwg):
self.__dwg = dwg
def draw_arrow(self, p_points, width=2, color='black'):
marker = self.__dwg.marker(insert=(2.1, 2), size=(2, 4), orient='auto')
marker.add(self.__dwg.path(d='M0,0 V4 L2,2 Z', fill=color))
self.__dwg.defs.add(marker)
line = self.__dwg.add(svgwrite.shapes.Polyline(
p_points, stroke_width=width,
stroke='black', fill='none'))
line.set_markers((self.__dwg.marker(), self.__dwg.marker(), marker))
def draw_3d_rectangle(self, p_start, width, height, stretch, fg_color='white', bg_color='grey', border_color='black'):
x_start, y_start = p_start
x_end, y_end = x_start + width, y_start + height
polygon1 = [(x_start, y_start), (x_start + width, y_start), (x_start + width, y_start + height), (x_start, y_start + height)]
polygon2 = [(x_start, y_start), (x_start + stretch, y_start - stretch), (x_end + stretch, y_start - stretch), (x_end, y_start)]
polygon3 = [(x_end, y_start), (x_end + stretch, y_start - stretch), (x_end + stretch, y_end - stretch), (x_end, y_end)]
self.__dwg.add(svgwrite.shapes.Polygon(polygon1, fill=fg_color, stroke=border_color))
self.__dwg.add(svgwrite.shapes.Polygon(polygon2, fill=bg_color, stroke=border_color))
self.__dwg.add(svgwrite.shapes.Polygon(polygon3, fill=bg_color, stroke=border_color))
def draw_multiple_layers(self, p_start, p_stretch=0.4, layer_width=10, space_width=7, layers=[], return_hash=True): # layers = (height, color)
if len(layers) == 0:
return
max_height = max(map(lambda l: l[1], filter(lambda l: isinstance(l, tuple), layers)))
x_offset = 0
side_width_before = 0
drawn_polygons = []
for n in xrange(len(layers)):
layer = layers[n]
if not isinstance(layer, tuple):
x_offset += layer
continue
id, height, fg_color, bg_color = layer
side_width = math.floor(height * p_stretch)
total_width = side_width + layer_width
if n > 0:
space_offset = space_width
if total_width < side_width_before:
space_offset = math.floor((side_width_before - total_width) * 0.5)
space_offset = max(space_width, space_offset)
pass
x_offset += space_offset
curr_p_start = (p_start[0] + x_offset, p_start[1] + math.floor((max_height - height) * 0.5))
self.draw_3d_rectangle(curr_p_start, layer_width, height, side_width, fg_color, bg_color)
drawn_polygons.append((id, curr_p_start, layer_width, height, side_width))
side_width_before = side_width
x_offset += layer_width
if return_hash:
polygons = {}
for polygon in filter(lambda l: l[0] is not None, drawn_polygons):
polygons[polygon[0]] = polygon[1:]
drawn_polygons = polygons
return drawn_polygons
def draw_multiple_defined_layers(self, p_start, layer_definitions={}, layers=[]):
plain_layers = []
for layer in layers:
if not isinstance(layer, dict):
plain_layers.append(layer)
else:
layer_definition = layer_definitions[layer['type']]
if 'ignore' in layer_definition and layer_definition['ignore']:
continue
plain_layer = (layer['id'], layer['height'], layer_definition['fg_color'], layer_definition['bg_color'])
if 'add_space_before' in layer_definition:
plain_layers.append(layer_definition['add_space_before'])
plain_layers.append(plain_layer)
if 'add_space_after' in layer_definition:
plain_layers.append(layer_definition['add_space_after'])
return self.draw_multiple_layers(p_start, layers=plain_layers)
def draw_arrow_between_points(self, source_point, target_point, text=None, y_delta=10, bottom=False):
if not bottom:
y = min(source_point[1], target_point[1]) - y_delta
else:
y = max(source_point[1], target_point[1]) + y_delta
source_delta = source_point[1] - y
target_delta = target_point[1] - y
if not bottom:
mp0 = (source_point[0] + source_delta, source_point[1] - source_delta)
mp1 = (target_point[0] - target_delta, target_point[1] - target_delta)
else:
mp0 = (source_point[0] - source_delta, source_point[1] - source_delta)
mp1 = (target_point[0] + target_delta, target_point[1] - target_delta)
points = [
source_point,
mp0, mp1,
target_point,
]
self.draw_arrow(points)
# If required: Draw the text
if text is not None:
text_lines = text.split('\n')
line_height = 15
mp_middle = (math.floor((mp0[0] + mp1[0]) * 0.5), math.floor((mp0[1] + mp1[1]) * 0.5))
if not bottom:
y_offset = -10 - line_height * (len(text_lines) - 1)
else:
y_offset = 13
for text_line in text_lines:
mp_text = (mp_middle[0], mp_middle[1] + y_offset)
self.__dwg.add(self.__dwg.text(text_line, insert=mp_text, text_anchor="middle", style="font-family:Sans-Serif"))
y_offset += line_height
def draw_arrow_between_layers(self, source_layer, target_layer, text=None, y_delta=10):
source_point = (source_layer[0][0] + source_layer[1] + source_layer[3], source_layer[0][1] - source_layer[3])
target_point = (target_layer[0][0] + target_layer[3], target_layer[0][1] - target_layer[3])
self.draw_arrow_between_points(source_point, target_point, text, y_delta)
def draw_additive_arrow_between_layers(self, source_layers, target_layer, text=None, y_delta=10, y_add=0, bottom=True):
if bottom:
target_point = (target_layer[0][0], target_layer[0][1] + target_layer[2])
# Get the source points
sp0 = min(map(lambda l: (l[0][0] + math.floor(l[1] * 0.5), l[0][1] + l[2]), source_layers), key=lambda l: l[0])
sp1 = max(map(lambda l: (l[0][0] + math.floor(l[1] * 0.5), l[0][1] + l[2]), source_layers), key=lambda l: l[0])
sp_y = max(map(lambda l: l[0][1] + l[2], source_layers)) + 5
sp0d = (sp0[0], sp_y + y_add)
sp1d = (sp1[0], sp_y + y_add)
else:
target_point = (target_layer[0][0] + target_layer[3], target_layer[0][1] - target_layer[3])
# Get the source points
sp0 = min(map(lambda l: (l[0][0] + l[3] + math.floor(l[1] * 0.5), l[0][1] - l[3]), source_layers), key=lambda l: l[0])
sp1 = max(map(lambda l: (l[0][0] + l[3] + math.floor(l[1] * 0.5), l[0][1] - l[3]), source_layers), key=lambda l: l[0])
sp_y = min(map(lambda l: l[0][1] - l[3], source_layers)) - 5
sp0d = (sp0[0], sp_y - y_add)
sp1d = (sp1[0], sp_y - y_add)
self.__dwg.add(svgwrite.shapes.Polyline([sp0, sp0d], stroke_width=2, stroke='black', fill='none'))
self.__dwg.add(svgwrite.shapes.Polyline([sp1, sp1d], stroke_width=2, stroke='black', fill='none'))
if bottom:
mp0 = (sp0d[0] + y_delta, sp0d[1] + y_delta)
mp1 = (sp1d[0] - y_delta, sp1d[1] + y_delta)
else:
mp0 = (sp0d[0] + y_delta, sp0d[1] - y_delta)
mp1 = (sp1d[0] - y_delta, sp1d[1] - y_delta)
mp_middle = (math.floor((mp0[0] + mp1[0]) * 0.5), math.floor((mp0[1] + mp1[1]) * 0.5))
# Draw the first line
self.__dwg.add(svgwrite.shapes.Polyline(
[sp0d, mp0, mp1, sp1d], stroke_width=2,
stroke='black', fill='none'))
# And now the line itself
self.draw_arrow_between_points(mp_middle, target_point, text, y_delta, bottom=bottom)
if __name__ == '__main__':
dwg = svgwrite.Drawing('test.svg')
cnn_draw = CNNDraw(dwg)
# Draw multiple layers
layer_polygons = cnn_draw.draw_multiple_defined_layers((100, 200), { # Start coordinate
# Define several layer types
'dropout': {'fg_color': '#ffffcc', 'bg_color': '#ffff99', 'ignore': True},
'conv': {'fg_color': '#e6faff', 'bg_color': '#99ebff'},
't_conv': {'fg_color': '#ffe6cc', 'bg_color': '#ffcc99'},
'pool': {'fg_color': '#ccffcc', 'bg_color': '#99ff99', 'add_space_after': 20},
'upscale': {'fg_color': '#e6ccff', 'bg_color': '#cc99ff'}
}, [
# The layers to draw; as can be seen a layer can have an id
layer_def('dropout', 300),
layer_def('conv', 300),
layer_def('conv', 300),
layer_def('pool', 300, id='POOL1'),
layer_def('dropout', 250),
layer_def('conv', 250),
layer_def('conv', 250),
layer_def('pool', 250, id='POOL2'),
layer_def('dropout', 200),
layer_def('conv', 200),
layer_def('conv', 200),
layer_def('pool', 200, id='POOL3'),
layer_def('dropout', 150),
layer_def('conv', 150),
layer_def('conv', 150),
layer_def('pool', 150, id='POOL4'),
layer_def('dropout', 100),
layer_def('conv', 100),
layer_def('conv', 100),
layer_def('pool', 100, id='POOL5'),
layer_def('dropout', 50),
layer_def('conv', 50),
layer_def('conv', 50),
layer_def('pool', 50, id='POOL6'),
layer_def('dropout', 30),
layer_def('conv', 30, id='FINAL'),
# Plain numbers are just space
100,
layer_def('t_conv', 50, id='T_CONV1'),
60,
layer_def('t_conv', 100, id='T_CONV2'),
60,
layer_def('t_conv', 150, id='T_CONV3'),
60,
layer_def('t_conv', 250, id='T_CONV4'),
layer_def('conv', 250),
layer_def('conv', 250),
layer_def('conv', 250),
layer_def('dropout', 250),
layer_def('conv', 250),
layer_def('conv', 250, id='FINAL_CONV'),
50,
layer_def('upscale', 300, id='UPSCALED')
])
cnn_draw.draw_arrow_between_layers(layer_polygons['FINAL'], layer_polygons['T_CONV1'], text="transposed conv.")
cnn_draw.draw_additive_arrow_between_layers([layer_polygons['POOL5'], layer_polygons['T_CONV1']], layer_polygons['T_CONV2'], text="element-wise sum and\ntransposed conv.", y_add=0)
cnn_draw.draw_additive_arrow_between_layers([layer_polygons['POOL4'], layer_polygons['T_CONV2']], layer_polygons['T_CONV3'], text="element-wise sum and\ntransposed conv.", y_add=0, bottom=False)
cnn_draw.draw_additive_arrow_between_layers([layer_polygons['POOL3'], layer_polygons['T_CONV3']], layer_polygons['T_CONV4'], text="element-wise sum and\ntransposed conv.", y_add=0)
cnn_draw.draw_arrow_between_layers(layer_polygons['FINAL_CONV'], layer_polygons['UPSCALED'], text="upscale")
dwg.save()
这篇关于创建图像的神经网络结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!