基于tensorflow __init__、build 和call的使用小结


Posted in Python onFebruary 26, 2021

1.介绍

在使用tf构建网络框架的时候,经常会遇到__init__、build 和call这三个互相搭配着使用,那么它们的区别主要在哪里呢?

1)__init__主要用来做参数初始化用,比如我们要初始化卷积的一些参数,就可以放到这里面

2)call可以把类型的对象当做函数来使用,这个对象可以是在__init__里面也可以是在build里面

3)build一般是和call搭配使用,这个时候,它的功能和__init__很相似,当build中存放本层需要初始化的变量,当call被第一次调用的时候,会先执行build()方法初始化变量,但后面再调用到call的时候,是不会再去执行build()方法初始化变量

2.代码

class RB(tf.keras.layers.Layer): 
 def __init__(self, num_filters, *args, **kwargs):
 self.num_filters = num_filters
 super(RB, self).__init__(*args, **kwargs)
 #按需求添加卷积
 def build(self, input_shape):
 #按需求添加卷积
 self._layers = [
 ]
 super(RB, self).build(input_shape)
 
 def call(self, tensor):
 for layer in self._layers:
  tensor = layer(tensor) 
class DecodeNet(tf.keras.layers.Layer):
 
 def __init__(self, num_filters, *args, **kwargs):
 self.num_filters = num_filters
 super(DecodeNet, self).__init__(*args, **kwargs)
 self.rb_block0 = RB(self.num_filters)
 self.rb_block1 = RB(self.num_filters)
 self.rb_block2 = RB(self.num_filters)
 
 def build(self, input_shape):
 self._layers = [
  RB(self.num_filters),
  RB(self.num_filters),
  RB(self.num_filters),
 ]
 super(DecodeNet, self).build(input_shape)
 
 def call(self, tensor):
 tensor = self.rb_block0(tensor)
 tensor = self.rb_block1(tensor)
 for layer in self._layers:
  tensor = layer(tensor)
 tensor = self.rb_block2(tensor)
 return tensor

补充:Python类中的__init__() 和 self 的解析

1、Python中self的含义

self,英文单词意思很明显,表示自己,本身。

此处有几种潜在含义:

1.这里的自己,指的是,实例Instance本身。

2.同时, 由于说到“自己”这个词,都是和相对而言的“其他”而说的;而此处的其他,指的是,类Class,和其他变量,比如局部变量,全局变量等。

此处的self,是个对象(Object),是当前类的实例。

因此,对应的self.valueName 和 self.function()中的valueName:表示self对象,即实例的变量。与其他的,Class的变量,全局的变量,局部的变量,是相对应的。

function:表示是调用的是self对象,即实例的函数。与其他的全局的函数,是相对应的。

2、Python中为何要有self

那就是:

在类的代码(函数)中,需要访问当前的实例中的变量和函数的,即,访问Instance中的:

对应的变量(属性,property):Instance.ProperyNam,去读取之前的值和写入新的值

调用对应函数(function):Instance.function(),即执行对应的动作

-> 而需要访问实例的变量和调用实例的函数,当然需要对应的实例Instance对象本身

-> 而Python中就规定好了,函数的第一个参数,就必须是实例对象本身,并且建议,约定俗成,把其名字写为self

-> 所以,我们需要self(需要用到self)

而如果没有用到self,即代码中,去掉self后,那种写法所使用到的变量,实际上不是你所希望的,不是真正的实例中的变量和函数,而是的访问到了其他部分的变量和函数了。甚至会由于没有合适的初始化实例变量,而导致后续无法访问的错误。

下面,就通过代码,来演示,如果去掉self,或者没有合理的使用self,会出现哪些错误。

3、首先来看一下__init__()和self对象

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies 
class Person(object):
 def __init__(self, name, lang, website):
  self.name = name
  self.lang = lang
  self.website = website
 
  print('self: ', self)
  print('type of self: ', type(self))
'''
未实例化时,运行程序,构造方法没有运行
''' 
p = Person('Tim', 'English', 'www.universal.com') 
'''实例化后运行的结果
self: <__main__.Person object at 0x00000000021EAF98>
type of self: <class '__main__.Person'>
'''

可以看出self为实例变量p,是一个Person类型的对象。

class Dog(object):  
 def __init__(self,name,dog_type):
  self.name = name
  self.type = dog_type 
 def sayhi(self):
  print("hello,I am a dog, my name is ",self.name) 
 
d = Dog('LiChuang',"京巴")   # 实例化
d.sayhi()

以下是d = Dog('LiChuang',"京巴")实例化的示意图:

基于tensorflow __init__、build 和call的使用小结

4、如果没有在__init__中初始化对应的实例变量的话,导致后续引用实例变量会出错

如下代码,完整的演示了,如果没有在类Class的最初的__init__函数中,正确的初始化实例变量,则会导致后续没有变量可用,因而出现AttributeError的错误:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies 
name = 'whole global name'
'''
注:此处全局的变量名,写成name,只是为了演示而用
实际上,好的编程风格,应该写成gName之类的名字,
以表示该变量是Global的变量
''' 
class Person(object):
 def __init__(self, newPersonName):
  # self.name = newPersonName
  '''
  如果此处不写成self.name
  那么此处的name,只是__init__函数中的局部临时变量name而已
  和全局中的name,没有半毛钱关系
  '''
  name = newPersonName
  '''
  此处只是为了代码演示,而使用了局部变量name,
  不过需要注意的是,此处很明显,由于接下来的代码也没有利用到此处的局部变量name
  则就导致了,此处的name变量,实际上被浪费了,根本没有利用到
  '''
 def sayYourName(self):
  '''
  此处由于找不到实例中的name变量,所以会报错:
  AttributeError: Person instance has no attribute 'name'
  '''
  print('My name is %s' %self.name)
 
def selfAndInitDemo():
 personInstance = Person('Tim')
 personInstance.sayYourName() 
if __name__ == '__main__':
 selfAndInitDemo()
 
''' 未使用self.name时抛异常
Traceback (most recent call last):
 File "E:/python14_workspace/s14/day06/test_1.py", line 18, in <module>
 selfAndInitDemo()
 File "E:/python14_workspace/s14/day06/test_1.py", line 15, in selfAndInitDemo
 personInstance.sayYourName()
 File "E:/python14_workspace/s14/day06/test_1.py", line 11, in sayYourName
 print('My name is %s' %self.name)
AttributeError: 'Person' object has no attribute 'name'
'''

从上述代码可见,由于在类的初始化(实例化)的__init__函数中,没有给self.name设置值,使得实例中,根本没有name这个变量,导致后续再去访问self.name,就会出现AttributeError的错误了。

对应的,如果写成self.name,则意思就正确了,就是初始化的时候,给实例中新增加,并且正常设置了正确的值newPersionName了,所以后续再去通过self.name,就可以访问到,当前实例中正确的变量name了。

相应的正确写法的代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies 
name = 'whole global name'
'''
注:此处全局的变量名,写成name,只是为了演示而用
实际上,好的编程风格,应该写成gName之类的名字,
以表示该变量是Global的变量
''' 
class Person(object):
 def __init__(self, newPersonName):
  self.name = newPersonName
  '''
  此处正确的,通过访问self.name的形式,实现了:
   1.给实例中,增加了name变量
   2.并且给name赋了初值,为newPersionName
  '''
 def sayYourName(self):
  '''
  此处由于开始正确的初始化了self对象,使得其中有了name变量,
  所以此处可以正确访问了name值了
  '''
  print('My name is %s' %self.name)
 
def selfAndInitDemo():
 personInstance = Person('Tim')
 personInstance.sayYourName()
 
if __name__ == '__main__':
 selfAndInitDemo() 
'''My name is Tim'''

5、在函数中,使用对应的变量

虽然代码是可以运行的,但是实际上却是使用的,不是实例中的变量

有时候,虽然你写的代码,可以运行,但是使用到的变量,由于没有加self,实际上是用到的不是实例的变量,而是其他的变量。

此类问题,主要和Python中的变量的作用域有关,但是此处例子中,也和是否使用self有关:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies 
name = 'whole global name'
'''
注:此处全局的变量名,写成name,只是为了演示而用
实际上,好的编程风格,应该写成gName之类的名字,
以表示该变量是Global的变量
'''
class Person(object):
 name = 'class global name' 
 def __init__(self, newPersonName):
  # self.name = newPersonName
  '''
  此处,没有使用self.name
  而使得此处的name,实际上仍是局部变量name
  虽然此处赋值了,但是后面没有被利用到,属于被浪费了的局部变量name
  '''
  name = newPersonName
 def sayYourName(self):
  '''
  此处,之所以没有像之前一样出现:
  AttributeError: Person instance has no attribute 'name'
  那是因为,虽然当前的实例self中,没有在__init__中初始化对应的name变量,实例self中没有对应的name变量
  但是由于实例所对应的类Person,有对应的name变量,所以也是可以正常执行代码的
  对应的,此处的self.name,实际上是Person.name
  '''
  print('My name is %s' %self.name)
  print('Name within class Person is actually the global name: %s' %name)
  print("Only access Person's name via Person.name = %s" %(Person.name))
 
def selfAndInitDemo():
 personInstance = Person('Tim')
 personInstance.sayYourName()
 print('whole global name is %s' %name)
 
if __name__ == '__main__':
 selfAndInitDemo()
'''
My name is class global name
Name within class Person is actually the global name: whole global name
Only access Person's name via Person.name = class global name
whole global name is whole global name
'''

其中,可见,此处开始__init__中,没有给self实例初始化对应的name,

而后面的函数sayYourName中,虽然可以调用到self.name而没有出现AttributeError错误,

但是实际上此处的值,不是所期望的,传入的name,即"Tim",而是类中的name的值,即"class global name"。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Python 相关文章推荐
Python爬虫:通过关键字爬取百度图片
Feb 17 Python
Python实现模拟分割大文件及多线程处理的方法
Oct 10 Python
基于循环神经网络(RNN)的古诗生成器
Mar 26 Python
Python 实现在文件中的每一行添加一个逗号
Apr 29 Python
对pandas读取中文unicode的csv和添加行标题的方法详解
Dec 12 Python
对python的unittest架构公共参数token提取方法详解
Dec 17 Python
使用Python实现企业微信的自动打卡功能
Apr 30 Python
在Python中使用turtle绘制多个同心圆示例
Nov 23 Python
Python3列表List入门知识附实例
Feb 09 Python
python shapely.geometry.polygon任意两个四边形的IOU计算实例
Apr 12 Python
浅谈pandas dataframe对除数是零的处理
Jul 20 Python
python绘制汉诺塔
Mar 01 Python
python实现MySQL指定表增量同步数据到clickhouse的脚本
Feb 26 #Python
详解python的xlwings库读写excel操作总结
Feb 26 #Python
pytorch 中forward 的用法与解释说明
Feb 26 #Python
浅谈Python xlwings 读取Excel文件的正确姿势
Feb 26 #Python
pycharm Tab键设置成4个空格的操作
Feb 26 #Python
解决pycharm 格式报错tabs和space不一致问题
Feb 26 #Python
pycharm 使用tab跳出正在编辑的括号(){}{}等问题
Feb 26 #Python
You might like
phpwind中的数据库操作类
2007/01/02 PHP
php常用字符串比较函数实例汇总
2014/11/24 PHP
PHP+jquery实时显示网站在线人数的方法
2015/01/04 PHP
理解JavaScript中的事件
2006/09/23 Javascript
jquery.lazyload  实现图片延迟加载jquery插件
2010/02/06 Javascript
javascript学习笔记(九)javascript中的原型(prototype)及原型链的继承方式
2011/04/12 Javascript
扩展JavaScript功能的正确方法(译文)
2012/04/12 Javascript
js操作textarea 常用方法总结
2012/12/03 Javascript
js去除重复字符串两种实现方法
2013/01/09 Javascript
解析js中获得父窗口链接getParent方法以及各种打开窗口的方法
2013/06/19 Javascript
jquery select多选框的左右移动 具体实现代码
2013/07/03 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
Flow之一个新的Javascript静态类型检查器
2015/12/21 Javascript
Vue.js实现输入框绑定的实例代码
2017/08/24 Javascript
原生JS实现$.param() 函数的方法
2018/08/10 Javascript
使用Vue-scroller页面input框不能触发滑动的问题及解决方法
2020/08/08 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
Vue项目利用axios请求接口下载excel
2020/11/17 Vue.js
浅析vue中的nextTick
2020/12/28 Vue.js
python复制文件的方法实例详解
2015/05/22 Python
六个窍门助你提高Python运行效率
2015/06/09 Python
python开发之字符串string操作方法实例详解
2015/11/12 Python
Python实现通过继承覆盖方法示例
2018/07/02 Python
对python字典元素的添加与修改方法详解
2018/07/06 Python
Flask-WTF表单的使用方法
2019/07/12 Python
Django 实现admin后台显示图片缩略图的例子
2019/07/28 Python
解决IDEA 的 plugins 搜不到任何的插件问题
2020/05/04 Python
HTML5 canvas基本绘图之文字渲染
2016/06/27 HTML / CSS
大学生实习期自我评价范文
2013/10/03 职场文书
后勤园长自我鉴定
2013/10/17 职场文书
《孔子游春》教学反思
2014/02/25 职场文书
生产现场禁烟通知
2015/04/23 职场文书
公务员爱岗敬业心得体会
2016/01/25 职场文书
学生检讨书范文
2019/06/24 职场文书
六年级作文之预言作文
2019/10/25 职场文书
JavaScript流程控制(循环)
2021/12/06 Javascript