文章目录

  • 卷积层的数据shape和普通层的数据shape差别:
  • 卷积层实现
  • 实现池化层
  • 实现 CNN 中的特殊层结构
  • 实现 LayerFactory
  • 网络结构

卷积层的数据shape和普通层的数据shape差别:

针对一般图像数据shape: Npq,图像就是二维浮点数据,N为数据个数,p,q为图像的维度。
卷积层的中间层数据shape: Npq*r,r为channels。
数据的shape必须非常清楚,因为假如自己处理卷积层就需要用到shape

卷积层实现

1、卷积层自身多了 Kernel 这个属性并因此带来了诸如 Stride、Padding 等属性,不过与此同时、卷积层之间没有权值矩阵,
2、卷积层和普通层的shape属性记录的东西不同,具体而言:
普通层的shape记录着上个 Layer 和该 Layer 所含神经元的个数
卷积层的shape记录着上个卷积层的输出和该卷积层的 Kernel 的信息(注意卷积层的上一层必定还是卷积层)
3、卷积填充有2种方式,tesorflow支持两种方式:一是不填充VALID,二是全部填充SAME,没有部分填充的方式,假如需要实现部分填充,就需要在数据预处理填充0,然后使用VALID方式卷积。

padding 可以为VALID,可以为SAME,也可以为int整型数,为int整型数时就是自填充数据。

class ConvLayer(Layer):"""初始化结构self.shape:记录着上个卷积层的输出和该Layer的Kernel的信息,具体而言:self.shape[0] = 上个卷积层的输出的形状(频道数×高×宽)常简记为self.shape[0] =(c,h_old,w_old)self.shape[1] = 该卷积层Kernel的信息(Kernel数×高×宽)常简记为self.shape[1] =(f,h_new,w_new)self.stride、self.padding:记录Stride、Padding的属性self.parent:记录父层的属性"""def __init__(self, shape, stride=1, padding="SAME", parent=None):if parent is not None:_parent = parent.root if parent.is_sub_layer else parentshape = _parent.shapeLayer.__init__(self, shape)self.stride = stride# 利用Tensorflow里面对Padding功能的封装、定义self.padding属性if isinstance(padding, str):# "VALID"意味着输出的高、宽会受Kernel的高、宽影响,具体公式后面会说if padding.upper() == "VALID":self.padding = 0self.pad_flag = "VALID"# "SAME"意味着输出的高、宽与Kernel的高、宽无关、只受Stride的影响else:self.padding = self.pad_flag = "SAME"# 如果输入了一个整数、那么就按照VALID情形设置Padding相关的属性else:self.padding = int(padding)self.pad_flag = "VALID"self.parent = parentif len(shape) == 1:self.n_channels = self.n_filters = self.out_h = self.out_w = Noneelse:self.feed_shape(shape)# 定义一个处理shape属性的方法def feed_shape(self, shape):self.shape = shapeself.n_channels, height, width = shape[0]self.n_filters, filter_height, filter_width = shape[1]# 根据Padding的相关信息、计算输出的高、宽if self.pad_flag == "VALID":self.out_h = ceil((height - filter_height + 1) / self.stride)self.out_w = ceil((width - filter_width + 1) / self.stride)else:self.out_h = ceil(height / self.stride)self.out_w = ceil(width / self.stride)class ConvLayerMeta(type):def __new__(mcs, *args, **kwargs):name, bases, attr = args[:3]# 规定继承的顺序为ConvLayer→Layerconv_layer, layer = basesdef __init__(self, shape, stride=1, padding="SAME"):conv_layer.__init__(self, shape, stride, padding)# 利用Tensorflow的相应函数定义计算卷积的方法def _conv(self, x, w):return tf.nn.conv2d(x, w, strides=[self.stride] * 4, padding=self.pad_flag)# 依次进行卷积、激活的步骤def _activate(self, x, w, bias, predict):res = self._conv(x, w) + biasreturn layer._activate(self, res, predict)# 在正式进行前向传导算法之前、先要利用Tensorflow相应函数进行Paddingdef activate(self, x, w, bias=None, predict=False):if self.pad_flag == "VALID" and self.padding > 0:_pad = [self.padding] * 2x = tf.pad(x, [[0, 0], _pad, _pad, [0, 0]], "CONSTANT")return _activate(self, x, w, bias, predict)# 将打包好的类返回for key, value in locals().items():if str(value).find("function") >= 0:attr[key] = valuereturn type(name, bases, attr)class ConvReLU(ConvLayer, ReLU, metaclass=ConvLayerMeta):pass

实现池化层

对于最常见的两种池化——极大池化和平均池化,Kernel 个数从数值上来说与输出频道个数一致,所以对于池化层的实现而言、我们应该直接用输入频道数来赋值 Kernel 数,因为池化不会改变数据的频道数。

class ConvPoolLayer(ConvLayer):def feed_shape(self, shape):shape = (shape[0], (shape[0][0], *shape[1]))ConvLayer.feed_shape(self, shape)def activate(self, x, w, bias=None, predict=False):pool_height, pool_width = self.shape[1][1:]# 处理Paddingif self.pad_flag == "VALID" and self.padding > 0:_pad = [self.padding] * 2x = tf.pad(x, [[0, 0], _pad, _pad, [0, 0]], "CONSTANT")# 利用self._activate方法进行池化return self._activate(None)(x, ksize=[1, pool_height, pool_width, 1],strides=[1, self.stride, self.stride, 1], padding=self.pad_flag)def _activate(self, x, *args):pass# 实现极大池化
class MaxPool(ConvPoolLayer):def _activate(self, x, *args):return tf.nn.max_pool# 实现平均池化
class AvgPool(ConvPoolLayer):def _activate(self, x, *args):return tf.nn.avg_pool

实现 CNN 中的特殊层结构

在 CNN 中同样有着 Dropout 和 Normalize 这两种特殊层结构,CNN 则通常是N×p×q×r的、其中r是当前数据的频道数。将 CNN 中r个频道的数据放在一起并视为 NN 中的一个神经元,这样做的话就能通过简易的封装来直接利用上我们对 NN 定义的特殊层结构。

# 定义作为封装的元类
class ConvSubLayerMeta(type):def __new__(mcs, *args, **kwargs):name, bases, attr = args[:3]conv_layer, sub_layer = basesdef __init__(self, parent, shape, *_args, **_kwargs):conv_layer.__init__(self, None, parent=parent)# 与池化层类似、特殊层输出数据的形状应保持与输入数据的形状一致self.out_h, self.out_w = parent.out_h, parent.out_wsub_layer.__init__(self, parent, shape, *_args, **_kwargs)self.shape = ((shape[0][0], self.out_h, self.out_w), shape[0])# 如果是CNN中的Normalize、则要提前初始化好γ、βif name == "ConvNorm":self.tf_gamma = tf.Variable(tf.ones(self.n_filters), name="norm_scale")self.tf_beta = tf.Variable(tf.zeros(self.n_filters), name="norm_beta")# 利用NN中的特殊层结构的相应方法获得结果def _activate(self, x, predict):return sub_layer._activate(self, x, predict)def activate(self, x, w, bias=None, predict=False):return _activate(self, x, predict)# 将打包好的类返回for key, value in locals().items():if str(value).find("function") >= 0 or str(value).find("property"):attr[key] = valuereturn type(name, bases, attr)# 定义CNN中的Dropout,注意继承顺序
class ConvDrop(ConvLayer, Dropout, metaclass=ConvSubLayerMeta):pass# 定义CNN中的Normalize,注意继承顺序
class ConvNorm(ConvLayer, Normalize, metaclass=ConvSubLayerMeta):pass

实现 LayerFactory

集合所有的layer,这样就可以通过字符串索引到对应的layer

class LayerFactory:# 使用一个字典记录下所有的Root Layeravailable_root_layers = {"Tanh": Tanh, "Sigmoid": Sigmoid,"ELU": ELU, "ReLU": ReLU, "Softplus": Softplus,"Identical": Identical,"CrossEntropy": CrossEntropy, "MSE": MSE,"ConvTanh": ConvTanh, "ConvSigmoid": ConvSigmoid,"ConvELU": ConvELU, "ConvReLU": ConvReLU, "ConvSoftplus": ConvSoftplus,"ConvIdentical": ConvIdentical,"MaxPool": MaxPool, "AvgPool": AvgPool}# 使用一个字典记录下所有特殊层available_special_layers = {"Dropout": Dropout,"Normalize": Normalize,"ConvDrop": ConvDrop,"ConvNorm": ConvNorm}# 使用一个字典记录下所有特殊层的默认参数special_layer_default_params = {"Dropout": (0.5,),"Normalize": ("Identical", 1e-8, 0.9),"ConvDrop": (0.5,),"ConvNorm": ("Identical", 1e-8, 0.9)}# 定义根据“名字”获取(Root)Layer的方法def get_root_layer_by_name(self, name, *args, **kwargs):# 根据字典判断输入的名字是否是Root Layer的名字if name in self.available_root_layers:# 若是、则返回相应的Root Layerlayer = self.available_root_layers[name]return layer(*args, **kwargs)# 否则返回Nonereturn None# 定义根据“名字”获取(任何)Layer的方法def get_layer_by_name(self, name, parent, current_dimension, *args, **kwargs):# 先看输入的是否是Root Layer_layer = self.get_root_layer_by_name(name, *args, **kwargs)# 若是、直接返回相应的Root Layerif _layer:return _layer, None# 否则就根据父层和相应字典进行初始化后、返回相应的特殊层_current, _next = parent.shape[1], current_dimensionlayer_param = self.special_layer_default_params[name]_layer = self.available_special_layers[name]if args or kwargs:_layer = _layer(parent, (_current, _next), *args, **kwargs)else:_layer = _layer(parent, (_current, _next), *layer_param)return _layer, (_current, _next)  

网络结构

class NN(ClassifierBase):def __init__(self):super(NN, self).__init__()self._layers = []self._optimizer = Noneself._current_dimension = 0self._available_metrics = {key: value for key, value in zip(["acc", "f1-score"], [NN.acc, NN.f1_score])}self.verbose = 0self._metrics, self._metric_names, self._logs = [], [], {}self._layer_factory = LayerFactory()# 定义Tensorflow中的相应变量self._tfx = self._tfy = None  # 记录每个Batch的样本、标签的属性self._tf_weights, self._tf_bias = [], []  # 记录w、b的属性self._cost = self._y_pred = None  # 记录损失值、输出值的属性self._train_step = None  # 记录“参数更新步骤”的属性self._sess = tf.Session()  # 记录Tensorflow Session的属性# 利用Tensorflow相应函数初始化参数@staticmethoddef _get_w(shape):initial = tf.truncated_normal(shape, stddev=0.1)return tf.Variable(initial, name="w")@staticmethoddef _get_b(shape):return tf.Variable(np.zeros(shape, dtype=np.float32) + 0.1, name="b")# 做一个初始化参数的封装,要注意兼容CNNdef _add_params(self, shape, conv_channel=None, fc_shape=None, apply_bias=True):# 如果是FC的话、就要根据铺平后数据的形状来初始化数据if fc_shape is not None:w_shape = (fc_shape, shape[1])b_shape = shape[1],# 如果是卷积层的话、就要定义Kernel而非权值矩阵elif conv_channel is not None:if len(shape[1]) <= 2:w_shape = shape[1][0], shape[1][1], conv_channel, conv_channelelse:w_shape = (shape[1][1], shape[1][2], conv_channel, shape[1][0])b_shape = shape[1][0],# 其余情况和普通NN无异else:w_shape = shapeb_shape = shape[1],self._tf_weights.append(self._get_w(w_shape))if apply_bias:self._tf_bias.append(self._get_b(b_shape))else:self._tf_bias.append(None)# 由于特殊层不会用到w和b、所以要定义一个生成占位符的方法def _add_param_placeholder(self):self._tf_weights.append(tf.constant([.0]))self._tf_bias.append(tf.constant([.0]))

深度学习:卷积层的实现相关推荐

  1. 深度学习——卷积层+填充和步幅(笔记)

    一 卷积层 1.了解二维交叉相关:具体做法是 对应数字 相乘后相加 Output具体的运算过程: 2.二维卷积层 * ①输入X:    (输入高为h,宽为w的矩阵)  如3*3 ②卷积核W:   ③偏 ...

  2. 动手学深度学习——卷积层里的填充和步幅

    1.填充 填充( padding )是指在输⼊⾼和宽的两侧填充元素(通常是 0 元素). 给定(32x32)输入图像: 应用5x5大小的卷积核,第一层得到输出大小28x28,第七层得到输出大小4x4: ...

  3. 动手学深度学习——卷积层

    从全连接到卷积 1.简单例子:分类猫和狗的图片 使用一个还不错的相机采集图片(12M像素) RGB图片有36M元素 使用100大小的单隐藏层MLP,模型有3.6B元素,远多于世界上所有猫和狗总数(90 ...

  4. 深度学习 卷积层与全连接层权重参数个数的计算

    1.卷积网络实例分析 构建卷积网络如下: from tensorflow.python.keras import datasets, models, layers class CNN(object): ...

  5. 想知道深度学习卷积在GPU上如何优化吗?“大神”赵开勇带你深入浅出

    想知道深度学习卷积在GPU上如何优化吗?"大神"赵开勇带你深入浅出 2016-08-19 11:54 转载 陈杨英杰 0条评论 雷锋网(搜索"雷锋网"公众号关注 ...

  6. 深度学习 | BN层原理浅谈

    深度学习 | BN层原理浅谈 文章目录 深度学习 | BN层原理浅谈 一. 背景 二. BN层作用 三. 计算原理 四. 注意事项 为什么BN层一般用在线性层和卷积层的后面,而不是放在激活函数后 为什 ...

  7. 毕设 深度学习卷积神经网络的花卉识别

    文章目录 0 前言 1 项目背景 2 花卉识别的基本原理 3 算法实现 3.1 预处理 3.2 特征提取和选择 3.3 分类器设计和决策 3.4 卷积神经网络基本原理 4 算法实现 4.1 花卉图像数 ...

  8. 深度学习 卷积神经网络原理

    深度学习 卷积神经网络原理 一.前言 二.全连接层的局限性 三.卷积层 3.1 如何进行卷积运算? 3.2 偏置 3.3 填充 3.4 步长 3.5 卷积运算是如何保留图片特征的? 3.6 三维卷积 ...

  9. 毕业设计 - 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉

    文章目录 0 前言 1 项目背景 2 花卉识别的基本原理 3 算法实现 3.1 预处理 3.2 特征提取和选择 3.3 分类器设计和决策 3.4 卷积神经网络基本原理 4 算法实现 4.1 花卉图像数 ...

  10. 深度学习--卷积神经网络CNN

    主要内容 1. 神经网络 1.1 感知器 1.2 Sigmoid神经元 1.3 神经网络 2. 卷积神经网络CNN 2.1 卷积神经网络结构 2.2 数据输入层 2.3 卷积层 2.3.1 局部感知( ...

最新文章

  1. js——全选框 checkbox
  2. linux怎么增加cpu负载,Linux下的CPU平均负载
  3. EXPLAIN字段详解
  4. Spark on YARN的部署
  5. 防止xss(脚本攻击)的方法之过滤器
  6. Intel IPP密码库 IPPCP 2018 开发笔记与总结(全)
  7. 服务器网卡多路径配置文件,IPSAN(五)IPSAN多路径设置(客户端)
  8. linux下好看的中文字体,推荐一款 Linux 上比较漂亮的字体(转)
  9. 使用WIFIPR跑握手包,破解wifi密码
  10. 高性能服务器架构拓扑图,topology: 开源、易扩展、方便集成的在线绘图(微服务架构图、网络拓扑图、流程图等)工具...
  11. 如何使用分布式管理工具:Git
  12. 父亲母亲-山里老房子
  13. 40岁销售被裁员后抑郁了,学Python是他最后的希望
  14. MATLAB线形规划函数linprog、intlinprog与二次规划函数quadprog
  15. 基于MATLAB的远程声控小车的系统设计与仿真
  16. Retrofit @Multipart@PartMap@Part组合的一种用法
  17. 【转】设置右键显示/隐藏系统文件
  18. gt2怎么与微信连接不上服务器,华为WATCH GT2收不到通知消息怎么办?收不到短信微信消息的解决方...
  19. DAT的算法原理及实现
  20. 【unity shader】高级光照 --- 薄膜干涉

热门文章

  1. 小程序支付 PHP
  2. html 按下和松开事件,利用JQuery实现一个键盘按下与松开触发事件
  3. c语言中freopen函数,fopen和freopen_C中freopen和fopen的区别(用法+详解+区别)
  4. windows下mysql(解压版)安装教程
  5. php监控系统,php 系统监控 | 学步园
  6. springboot starter工作原理_springboot基础知识集结,你get到了吗
  7. 错误:未在本地计算机上注册“Microsoft.Ace.OleDb.12.0”提供程序
  8. Spring Cloud Data Flow手动安装
  9. Linux 下修改hosts文件
  10. c语言中热河输入空格,承德市2020年(春秋版)小学英语六年级上册期中考试模拟试卷(1)C卷...