99.1.人工智能——卷积神经网络的基础算子:卷积算子

人工智能
后台-插件-广告管理-内容页头部广告(手机)

卷积神经网络是目前计算机视觉中使用最普遍的模型结构,如下图所示,由M个卷积层和b个汇聚层组合作用在输入图片上,在网络的最后通常会加入K个全连接层。

卷积神经网络经典结构

从上图可以看出,卷积网络是由多个基础的算子组合而成。下面我们先实现卷积网络的两个基础算子:卷积层算子和汇聚层算子。

卷积算子

卷积层是指用卷积操作来实现神经网络中一层。为了提取不同种类的特征,通常会使用多个卷积核一起进行特征提取。

多通道卷积

在前面介绍的二维卷积运算中,卷积的输入数据是二维矩阵。但实际应用中,一幅大小为M×N的图片中的每个像素的特征表示不仅仅只有灰度值的标量,通常有多个特征,可以表示为D维的向量,比如RGB三个通道的特征向量。因此,图像上的卷积操作的输入数据通常是一个三维张量,分别对应了图片的高度M、宽度N和深度D,其中深度D通常也被称为输入通道数D。如果输入如果是灰度图像,则输入通道数为1;如果输入是彩色图像,分别有R、G、B三个通道,则输入通道数为3。

此外,由于具有单个核的卷积每次只能提取一种类型的特征,即输出一张大小为U×V特征图(Feature Map)。而在实际应用中,我们也希望每一个卷积层能够提取多种不同类型的特征,所以一个卷积层通常会组合多个不同的卷积核来提取特征,经过卷积运算后会输出多张特征图,不同的特征图对应不同类型的特征。输出特征图的个数通常将其称为输出通道数P。


多输入通道的卷积运算

多通道卷积层算子实现的代码

import paddleimport paddle.nn as nn#多通道卷积层算子class Conv2D(nn.Layer):    def __init__(self,in_channels,out_channels,kernel_size,stride=1,padding=0,                weight_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=1.0)),                bias_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=0.0))):        super(Conv2D,self).__init__()        #创建卷积核        self.weight=paddle.create_parameter(shape=[out_channels,in_channels,kernel_size,kernel_size],                                            dtype="float32",                                            attr=weight_attr)        #创建偏置        self.bias=paddle.create_parameter(shape=[out_channels,1],                                          dtype="float32",                                          attr=bias_attr)        self.stride=stride        self.padding=padding        #输入通道数        self.in_channels=in_channels        #输出通道数        self.out_channels=out_channels            #基础卷积运算    def single_forward(self,x,weight):        new_x=paddle.zeros([x.shape[0],x.shape[1]+2*self.padding,x.shape[2]+2*self.padding])        new_x[:,self.padding:x.shape[1]+self.padding,self.padding:x.shape[2]+self.padding]=x        u,v=weight.shape        output_w=(new_x.shape[1]-u)//self.stride+1        output_h=(new_x.shape[2]-v)//self.stride+1        output=paddle.zeros([x.shape[0],output_w,output_h])        for i in range(output.shape[1]):            for j in range(output.shape[2]):                output[:,i,j]=paddle.sum(                    new_x[:,self.stride*i:self.stride*i+u,self.stride*j:self.stride*j+v]*weight,                    axis=[1,2]                )        return output        def forward(self,inputs):        '''        输入:        inputs:输入矩阵,shape=[B,D,M,N]        weights:P组二维卷积核,shape=[p,D,U,V]        bias:p个偏置,shape=[p,1]        '''        feature_maps=[]        #进行多次多输入通道卷积运算        p=0        for w,b in zip(self.weight,self.bias):#p个(w,b)每次计算一个特征图Zp            multi_outs=[]            #循环计算每个输入特征图对应的卷积结果            for i in range(self.in_channels):                single=self.single_forward(inputs[:,i,:,:],w[i])                multi_outs.append(single)                #print("Conv2D in_channels:",self.in_channels,"i:",i,"single:",single.shape)            feature_map=paddle.sum(paddle.stack(multi_outs),axis=0)+b #Zp                                feature_maps.append(feature_map)            #print("Conv2D out_channels:",self.out_channels, "p:",p,"feature_map:",feature_map.shape)            p=p+1        #将所有Zp进行堆叠              out=paddle.stack(feature_maps,1)        return out         
inputs=paddle.to_tensor([[[[0.0,1.0,2.0],[3.0,4.0,5.0],[6.0,7.0,8.0]],                          [[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0]]]])print("inputs shape",inputs.shape)conv2d=Conv2D(in_channels=2,out_channels=5,kernel_size=3)outputs=conv2d(inputs)print("Conv2D outputs shape",outputs.shape,outputs)
#输出结果:inputs shape [1, 2, 3, 3]Conv2D outputs shape [1, 5, 1, 1] Tensor(shape=[1, 5, 1, 1], dtype=float32, place=CPUPlace, stop_gradient=False,       [[[[81.]],         [[81.]],         [[81.]],         [[81.]],         [[81.]]]])
后台-插件-广告管理-内容页尾部广告(手机)
标签:

评论留言

我要留言

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。