python链式调用顺序_[Python]深度学习网络的链式调用语法

问题导出:

比如CTPN的网络结构在 lib/networks/VGGnet_train.py下:

(self.feed('data')

.conv(3, 3, 64, 1, 1, name='conv1_1')

.conv(3, 3, 64, 1, 1, name='conv1_2')

.max_pool(2, 2, 2, 2, padding='VALID', name='pool1')

.conv(3, 3, 128, 1, 1, name='conv2_1')

.conv(3, 3, 128, 1, 1, name='conv2_2')

.max_pool(2, 2, 2, 2, padding='VALID', name='pool2')

.conv(3, 3, 256, 1, 1, name='conv3_1')

.conv(3, 3, 256, 1, 1, name='conv3_2')

.conv(3, 3, 256, 1, 1, name='conv3_3')

.max_pool(2, 2, 2, 2, padding='VALID', name='pool3')

.conv(3, 3, 512, 1, 1, name='conv4_1')

.conv(3, 3, 512, 1, 1, name='conv4_2')

.conv(3, 3, 512, 1, 1, name='conv4_3')

.max_pool(2, 2, 2, 2, padding='VALID', name='pool4')

.conv(3, 3, 512, 1, 1, name='conv5_1')

.conv(3, 3, 512, 1, 1, name='conv5_2')

.conv(3, 3, 512, 1, 1, name='conv5_3'))

#========= RPN ============

(self.feed('conv5_3')

.conv(3,3,512,1,1,name='rpn_conv/3x3'))

(self.feed('rpn_conv/3x3').Bilstm(512,128,512,name='lstm_o'))

(self.feed('lstm_o').lstm_fc(512,len(anchor_scales) * 10 * 4, name='rpn_bbox_pred'))

(self.feed('lstm_o').lstm_fc(512,len(anchor_scales) * 10 * 2, name='rpn_cls_score'))

# generating training labels on the fly

# output: rpn_labels(HxWxA, 2) rpn_bbox_targets(HxWxA, 4) rpn_bbox_inside_weights rpn_bbox_outside_weights

# 给每个anchor上标签,并计算真值(也是delta的形式),以及内部权重和外部权重

(self.feed('rpn_cls_score', 'gt_boxes', 'gt_ishard', 'dontcare_areas', 'im_info')

.anchor_target_layer(_feat_stride, anchor_scales, name = 'rpn-data' ))

# shape is (1, H, W, Ax2) -> (1, H, WxA, 2)

# 给之前得到的score进行softmax,得到0-1之间的得分

(self.feed('rpn_cls_score')

.spatial_reshape_layer(2, name = 'rpn_cls_score_reshape')

.spatial_softmax(name='rpn_cls_prob'))

整体的网络结构是Conv+RPN+Bi-LSTM+fc,但本文探究的就不是这些了,只是好奇为什么这么多网络结构能链式连接在一起,所以恰当来说,本文类型属于Python语法之类了。

-----------------------------------------------------------------------纯语法,非喜勿进---------------------------------------------------------------------

首先需要这个Class是如何调用的。

lib/networks/VGGnet_train.py:

class VGGnet_train(Network):

lib/networks/network.py:

class Network(object):

在实例化class VGGnet_train的时候,继承了class Network,所以class VGGnet_train继承了class Network所有的类函数。

实例化的过程会调用__init__()函数,可以看到最后一行:

self.setup()

所以说网络结构在一开始实例化的时候就加载进内存了,只不过一般都会初始化为一个值(比如Conv中的weights一般初始化为mean为0、std为0.1的值)。

分析setup()函数,从self.feed('data')开始,就一直链式调用将所有网格加载进来了。

首先来说,self代表的是类的实例化,而非类,可以参考Python面向对象。

类的实例化表明其可以通过点号来访问类的属性。

先下个结论,链式调用的原理是type(self) = type(self.feed('data')) = type(self.conv(3, 3, 64, 1, 1, name='conv1_1')),即类的实例化访问类属性后返回值依然是类的实例化,从而可以继续访问返回值的类属性,实现链式调用。

那么关键是,怎么实现:类的实例化访问类属性后返回值依然是类的实例化,答案就是network.py里面的装饰器函数layer()【注:feed()函数除外,其本身就返回了一个类的实例化self】,在一个函数上方添加代码@layer就是其表示形式。

装饰器的作用就是将被修饰的函数作为参数,并返回修饰后的同名函数或其它可调用的东西。

在这份代码里,意思就是在执行属性conv(3, 3, 64, 1, 1, name='conv1_1')及max_pool(2, 2, 2, 2, padding='VALID', name='pool1')之前,会先调用layer函数。

分析conv()等函数发现,其与一般的卷积函数并无不同,也是调用TensorFlow里面的函数,将输入经过函数操作后得到输出值。

再回顾下装饰器的作用,操作被修饰的函数后,装饰器再执行操作返回类的实例化self即可。

观察源码发现确实是这样的,在layer()函数中:

# Perform the operation and get the output.

layer_output = op(self, layer_input, *args, **kwargs)

# Add to layer LUT.

self.layers[name] = layer_output

# This output is now the input for the next layer.

self.feed(layer_output)

# Return self for chained calls.

return self

执行op(self, layer_input, *args, **kwargs)操作会将输入处理后得到输出,最后还是需要return self的。

至于self.feed(layer_output)的作用,是将列表清空,将输出放入进去替换输入,这样下一次调用的输入就是这次的输出了,达到链式调用的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值