日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

深度学习:卷积层的实现

發布時間:2024/9/15 pytorch 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度学习:卷积层的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 卷積層的數據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]))

總結

以上是生活随笔為你收集整理的深度学习:卷积层的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。