python卷积神经网络图像,神经网络python库
关键词:机器学习/神经网络/稀疏性
摘要:
自发明以来,全连接神经网络随处可见。可用于实现分类或回归任务,有效扩展机器的决策能力。但是全连通参数的总数非常大,既需要硬盘空间来保存模型,又需要大量内存来实现运行时的计算。因此,稀疏网络的概念应运而生!去掉一些环节实现网络的轻量化是它的重要贡献!
引言神经网络是指一种结构化的分层网络结构。虽然也是由节点和边组成的,但是每个节点都不能和与自己同层的其他节点相连,所以网络结构示意图往往是这样画的:
实际上,在计算机中实现这种结构的过程是通过矩阵计算:
节点的数量由矩阵的长度和宽度决定,而边的权重由另一个充满颜色的矩阵管理。原理图中的“空”框,乍一看可能令人费解。这是因为在实践中,多比率数据可以一次性输入神经网络。沿着彩色的示意图方向看,我们很容易看到,这里一次性放了4倍的数据!但是你能放几笔呢?这取决于计算机缓存的大小。理论上,如果缓存足够大,可以将所有数据放入网络进行分析。
然而,随着神经网络的结构变得越来越复杂,参数也呈指数增长。除了直接抛弃神经网络不使用之外,剪枝成为了另一个很好的解决方法。既然所有的连接都占了很大空间,那就减去一些不用的吧!数学表达式就是让权重矩阵中的一些值变成0。既然理论上可行,就有实现这个理论的基础!
本算法讲解和练习将使用以下模块:
导入数学导入torch导入torch.nn作为nn模块不是Python内置的,需要单独安装。
让我们放上一个示意图,让读者更好地理解切断连接后的神经网络:
如上所述,断开连接的方法是将权重矩阵中的值重置为零。为了更方便地控制连接,并确保这些断开的连接可以恢复,我们不会直接重置矩阵中的值,而是使用另一个相同大小的掩码来控制连接是否断开:
[与辍学的区别]
有经验的读者可能会疑惑,这种操作和常用的退学法具体有什么区别?不都是为了打破一个连接,简化神经网络吗?实际上,剪枝实现的断开是完全断开,也就是说,即使是梯度的反馈过程也不能直接更新断开的参数,这是与训练过程完全分离的操作。反之,只有在正向传播时,漏点才断开,训练过程仍会通过反馈梯度更新断开的连接参数。
稀疏神经网络的实现已经走过了边肖的全网地毯式搜索。直到2019年底,Pytorch、Tensorflow等流行框架才开始提供相应的剪枝功能供我们直接调用。虽然有一些改进,但是功能还是有一定的局限性。为了能够一边修剪一边享受GPU加速的效果,接下来,让我们更改Pytorch的源代码,创建一个我们自定义的函数!
P.S .如果你想阅读官方文档,你可以点击这里进入网站。
由于控制一个网络节点是否断开的方法是通过0和1来操作,所以我们需要一个可以用来自动生成满足我们预期大小的掩码的函数。下面是一个随机生成函数的演示,其他生成方法也可以自己定义!
def gen_mask(row,col,percent=0.5,num_zeros=None):如果num_zeros为None: #默认情况下,被屏蔽的总数为0.5。num_zeros=int((行*列)*百分比)Mask=NP。hstack ([NP。零(num _ zeroes),NP。one(row * col-num _ zeros)])NP。随机的。shuffle (mask)返回掩码。reshape (row,col)遮挡权重的数量可以根据具体的num _ zeroes数来确定,或者根据
框架的全联接函数此函数将会继承自动反向传播的类,我们的目标就是在前向和反向传播的过程都让遮罩参与其中,因此改造函数的时候需要新增加一个参数面具传入:
类线性函数(火炬。亲笔签名。函数):“”通过“面具”屏蔽其权重的自动签名功能。 #注意向前和向后的都是@静态方法@静态方法# bias,mask是可选参数def forward(ctx,input,weight,bias=None,mask=None):如果面具不是无:#将重量改为0其中掩码==0权重=权重*掩码输出=输入。mm(体重。t())如果偏见不是无:输出=偏置。取消排队(0).expand _ as(输出)CTX。save _ for _ backward(输入、权重、偏差、掩码)返回输出#这个函数只有一个输出,所以它只得到一个gradient @ static method def backward(CTX,grad_output):输入,权重,偏差,掩码=CTX。saved _ tensors grad _ input=grad _ weight=grad _ bias=grad _ mask=None #这些需求_投入_毕业检查是可选的,只是为了#提高效率。如果你想让你的代码更简单,你可以#跳过它们。为不需要渐变的输入返回渐变不是错误如果CTX。需求输入梯度[0]:梯度输入=梯度输出。mm(重量)如果CTX。需要_输入_梯度[1]:梯度_重量=梯度_输出。t().毫米(输入)如果面具不为无:#将梯度重量改为0其中掩码==0梯度权重=梯度权重*掩码#如果偏见不为没有人且ctx.needs_input_grad[2]:如果CTX。需求_输入_梯度[2]:梯度_偏差=梯度_输出。总和(0).挤压(0)返回梯度输入、梯度权重、梯度偏差、梯度掩码不过这还只是自创框架函数的第一步,接下来才是本文代码部分的重头戏,自定义的一个类也需要继承nn .模块,这么一来类才有向前等一系列的框架基本操作。努力了这么久,该是为自己的方法取个帅名的好时候了!
类别定制行.Module): def __init__(self,input_features,output_features,bias=True,mask=None): Argumens-mask[numpy。数组]:形状为(输入特征,输出特征).元素为0或1,表示未连接或连接bias [bool]:偏置的标志. super(定制线路,自助)._ _ init _ _()self。输入特征=输入特征本身。输出特征=输出特征# nn .参数是一种特殊的张量,一旦它被#赋值为属性,它将#自动注册为模块的参数。自重=nn .参数(火炬。张量(self.output_features,self。input _ features))如果偏向:自我。偏差=nn .参数(火炬张量(自我。output _ features))否则:#你应该总是注册所有可能的参数,但是#如果你愿意,可选参数可以是没有.self.register_parameter(bias ,None) #初始化上述参数(权重偏差)。self.init_params()如果面具不为None: mask=torch.tensor(mask,dtype=torch.float).t() self.mask=nn .Parameter(mask,requires _ grad=False)# print( \ n[!]customized line:\ n ,self。体重。数据。t())else:self。register _ parameter( mask ,None)def init _ params(self):stdv=1 ./数学。sqrt(self。体重。大小(1))自我。体重。数据。统一_(-stdv,stdv)如果自我偏见不为无:自我。偏见。数据。统一_(-stdv,stdv)定义转发(自身,输入):#有关此处发生的情况的解释,请参见自动签名部分返回线性函数。应用(输入、自身权重、自身偏差、自身。mask)def extra _ repr(self):#(可选)设置关于此模块的额外信息。您可以通过打印这个类的对象来测试# it .返回输入要素={},输出要素={},偏差={},掩码={} .格式(自我.输入_特征,自我.输出_特征,自我.偏差不是无,自我屏蔽不是无)在定制线类的__init__函数里要特别注意参数注册成参数的顺序,小编的经验可以告诉你,如果面具参数早于重量或偏见注册的话,那就是品尝病菌滋味的时候了。参数定义清楚并注册之后,记得要通过一些分布来初始化里面的数值。经过这么一大通修改后,我们就能得到一个可以输入遮罩面具的自定义层,并且在向后的的时候避免更新那些被断开的权重。
实际模型的应用算法实操中使用自定义遮罩稀疏神经网络的方法也非常直观,只要参数的顺序,初始化的过程,还有反向传播的机制设定没有问题,就能够用定制线完全取代nn .线性的的功能,不多废话先上代码!
班级网(nn。Module): def __init__(self,in_size,out_size,ratio=[0,0.5,0]): super(Network,self)。__init__() # self.fc1=nn。Linear(in_size,32)self . fc1=customized linear(in _ size,32,mask=gen_mask( in_size,32,ratio[0])) self.bn1=nn。BatchNorm1d(32) # self.fc2=nn。Linear(32,16)self . fc2=customized linear(32,16,mask=gen_mask(32,16,ratio[1])) self.bn2=nn。BatchNorm1d(16) # self.fc3=nn。Linear(16,out_size)self . fc3=customized linear(16,out_size,mask=gen_mask( 16,out _ size,ratio[2])) self.bn3=nn。batch norm 1d(out _ size)self . relu=nn。self.modules()中m的ReLU():if is instance(m,nn。linear):nn . init . uniform _(m . weight,a=0,b=1) elif isinstance(m,(nn .nn的BatchNorm1d。group norm)):nn . init . constant _(m . weight,1) nn.init.constant_(m.bias,0) def forward(self,X):X=self . fc1(X)X=self . relu(X)X=self . fc2(X)X=self . bn2(X)X=self . relu(X)X=self . fc3(X)X=self . bn3(X)X=self . relu(X)return X类似地,的参数输入借助gen_mask函数生成随机掩码,可以自由控制各层网络断开和连接的权重,实现网络稀疏的效果。
剪枝策略对于一个全连接的神经网络,剪枝方法可以分为两类:
边剪枝——随机或按阈值节点剪枝——减去整列权矩阵这两种方法是目前全连接神经网络中仅有的剪枝策略。上面演示的修剪算法是针对边缘修剪的。如果你也对第二个策略感兴趣,不妨根据这个自定义函数自己搭建一个!
【E N D】-【END】-【END】
AI算法字典——你想知道的所有算法都在这里!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。