欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

keras 實(shí)現(xiàn)輕量級網(wǎng)絡(luò)ShuffleNet教程

 更新時間:2020年06月19日 10:06:51   作者:zjn.ai  
這篇文章主要介紹了keras 實(shí)現(xiàn)輕量級網(wǎng)絡(luò)ShuffleNet教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

ShuffleNet是由曠世發(fā)表的一個計算效率極高的CNN架構(gòu),它是專門為計算能力非常有限的移動設(shè)備(例如,10-150 MFLOPs)而設(shè)計的。該結(jié)構(gòu)利用組卷積和信道混洗兩種新的運(yùn)算方法,在保證計算精度的同時,大大降低了計算成本。ImageNet分類和MS COCO對象檢測實(shí)驗(yàn)表明,在40 MFLOPs的計算預(yù)算下,ShuffleNet的性能優(yōu)于其他結(jié)構(gòu),例如,在ImageNet分類任務(wù)上,ShuffleNet的top-1 error 7.8%比最近的MobileNet低。在基于arm的移動設(shè)備上,ShuffleNet比AlexNet實(shí)際加速了13倍,同時保持了相當(dāng)?shù)臏?zhǔn)確性。

Paper:ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile

Github:https://github.com/zjn-ai/ShuffleNet-keras

網(wǎng)絡(luò)架構(gòu)

組卷積

組卷積其實(shí)早在AlexNet中就用過了,當(dāng)時因?yàn)镚PU的顯存不足因而利用組卷積分配到兩個GPU上訓(xùn)練。簡單來講,組卷積就是將輸入特征圖按照通道方向均分成多個大小一致的特征圖,如下圖所示左面是輸入特征圖右面是均分后的特征圖,然后對得到的每一個特征圖進(jìn)行正常的卷積操作,最后將輸出特征圖按照通道方向拼接起來就可以了。

目前很多框架都支持組卷積,但是tensorflow真的不知道在想什么,到現(xiàn)在還是不支持組卷積,只能自己寫,因此效率肯定不及其他框架原生支持的方法。組卷積層的代碼編寫思路就與上面所說的原理完全一致,代碼如下。

def _group_conv(x, filters, kernel, stride, groups):
 """
 Group convolution
 # Arguments
  x: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  filters: Integer, number of output channels
  kernel: An integer or tuple/list of 2 integers, specifying the
   width and height of the 2D convolution window.
  strides: An integer or tuple/list of 2 integers,
   specifying the strides of the convolution along the width and height.
   Can be a single integer to specify the same value for
   all spatial dimensions.
  groups: Integer, number of groups per channel
  
 # Returns
  Output tensor
 """
 channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
 in_channels = K.int_shape(x)[channel_axis]
 
 # number of input channels per group
 nb_ig = in_channels // groups
 # number of output channels per group
 nb_og = filters // groups
 
 gc_list = []
 # Determine whether the number of filters is divisible by the number of groups
 assert filters % groups == 0
 
 for i in range(groups):
  if channel_axis == -1:
   x_group = Lambda(lambda z: z[:, :, :, i * nb_ig: (i + 1) * nb_ig])(x)
  else:
   x_group = Lambda(lambda z: z[:, i * nb_ig: (i + 1) * nb_ig, :, :])(x)
  gc_list.append(Conv2D(filters=nb_og, kernel_size=kernel, strides=stride, 
        padding='same', use_bias=False)(x_group))
  
 return Concatenate(axis=channel_axis)(gc_list)

通道混洗

通道混洗是這篇paper的重點(diǎn),盡管組卷積大量減少了計算量和參數(shù),但是通道之間的信息交流也受到了限制因而模型精度肯定會受到影響,因此作者提出通道混洗,在不增加參數(shù)量和計算量的基礎(chǔ)上加強(qiáng)通道之間的信息交流,如下圖所示。

通道混洗層的代碼實(shí)現(xiàn)很巧妙參考了別人的實(shí)現(xiàn)方法。通過下面的代碼說明,d代表特征圖的通道序號,x是經(jīng)過通道混洗后的通道順序。

>>> d = np.array([0,1,2,3,4,5,6,7,8]) 
>>> x = np.reshape(d, (3,3)) 
>>> x = np.transpose(x, [1,0]) # 轉(zhuǎn)置
>>> x = np.reshape(x, (9,)) # 平鋪
'[0 1 2 3 4 5 6 7 8] --> [0 3 6 1 4 7 2 5 8]' 

利用keras后端實(shí)現(xiàn)代碼:

def _channel_shuffle(x, groups):
 """
 Channel shuffle layer
 
 # Arguments
  x: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  groups: Integer, number of groups per channel
  
 # Returns
  Shuffled tensor
 """
 
 if K.image_data_format() == 'channels_last':
  height, width, in_channels = K.int_shape(x)[1:]
  channels_per_group = in_channels // groups
  pre_shape = [-1, height, width, groups, channels_per_group]
  dim = (0, 1, 2, 4, 3)
  later_shape = [-1, height, width, in_channels]
 else:
  in_channels, height, width = K.int_shape(x)[1:]
  channels_per_group = in_channels // groups
  pre_shape = [-1, groups, channels_per_group, height, width]
  dim = (0, 2, 1, 3, 4)
  later_shape = [-1, in_channels, height, width]
 
 x = Lambda(lambda z: K.reshape(z, pre_shape))(x)
 x = Lambda(lambda z: K.permute_dimensions(z, dim))(x) 
 x = Lambda(lambda z: K.reshape(z, later_shape))(x)
 
 return x

ShuffleNet Unit

ShuffleNet的主要構(gòu)成單元。下圖中,a圖為深度可分離卷積的基本架構(gòu),b圖為1步長時用的單元,c圖為2步長時用的單元。

ShuffleNet架構(gòu)

注意,對于第二階段(Stage2),作者沒有在第一個1×1卷積上應(yīng)用組卷積,因?yàn)檩斎胪ǖ赖臄?shù)量相對較少。

環(huán)境

Python 3.6

Tensorlow 1.13.1

Keras 2.2.4

實(shí)現(xiàn)

支持channel first或channel last

# -*- coding: utf-8 -*-
"""
Created on Thu Apr 25 18:26:41 2019
@author: zjn
"""
import numpy as np
from keras.callbacks import LearningRateScheduler
from keras.models import Model
from keras.layers import Input, Conv2D, Dropout, Dense, GlobalAveragePooling2D, Concatenate, AveragePooling2D
from keras.layers import Activation, BatchNormalization, add, Reshape, ReLU, DepthwiseConv2D, MaxPooling2D, Lambda
from keras.utils.vis_utils import plot_model
from keras import backend as K
from keras.optimizers import SGD
 
def _group_conv(x, filters, kernel, stride, groups):
 """
 Group convolution
 
 # Arguments
  x: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  filters: Integer, number of output channels
  kernel: An integer or tuple/list of 2 integers, specifying the
   width and height of the 2D convolution window.
  strides: An integer or tuple/list of 2 integers,
   specifying the strides of the convolution along the width and height.
   Can be a single integer to specify the same value for
   all spatial dimensions.
  groups: Integer, number of groups per channel
  
 # Returns
  Output tensor
 """
 
 channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
 in_channels = K.int_shape(x)[channel_axis]
 
 # number of input channels per group
 nb_ig = in_channels // groups
 # number of output channels per group
 nb_og = filters // groups
 
 gc_list = []
 # Determine whether the number of filters is divisible by the number of groups
 assert filters % groups == 0
 
 for i in range(groups):
  if channel_axis == -1:
   x_group = Lambda(lambda z: z[:, :, :, i * nb_ig: (i + 1) * nb_ig])(x)
  else:
   x_group = Lambda(lambda z: z[:, i * nb_ig: (i + 1) * nb_ig, :, :])(x)
  gc_list.append(Conv2D(filters=nb_og, kernel_size=kernel, strides=stride, 
        padding='same', use_bias=False)(x_group))
  
 return Concatenate(axis=channel_axis)(gc_list)
def _channel_shuffle(x, groups):
 """
 Channel shuffle layer
 
 # Arguments
  x: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  groups: Integer, number of groups per channel
  
 # Returns
  Shuffled tensor
 """
 if K.image_data_format() == 'channels_last':
  height, width, in_channels = K.int_shape(x)[1:]
  channels_per_group = in_channels // groups
  pre_shape = [-1, height, width, groups, channels_per_group]
  dim = (0, 1, 2, 4, 3)
  later_shape = [-1, height, width, in_channels]
 else:
  in_channels, height, width = K.int_shape(x)[1:]
  channels_per_group = in_channels // groups
  pre_shape = [-1, groups, channels_per_group, height, width]
  dim = (0, 2, 1, 3, 4)
  later_shape = [-1, in_channels, height, width]
 
 x = Lambda(lambda z: K.reshape(z, pre_shape))(x)
 x = Lambda(lambda z: K.permute_dimensions(z, dim))(x) 
 x = Lambda(lambda z: K.reshape(z, later_shape))(x)
 
 return x
 
def _shufflenet_unit(inputs, filters, kernel, stride, groups, stage, bottleneck_ratio=0.25):
 """
 ShuffleNet unit
 
 # Arguments
  inputs: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  filters: Integer, number of output channels
  kernel: An integer or tuple/list of 2 integers, specifying the
   width and height of the 2D convolution window.
  strides: An integer or tuple/list of 2 integers,
   specifying the strides of the convolution along the width and height.
   Can be a single integer to specify the same value for
   all spatial dimensions.
  groups: Integer, number of groups per channel
  stage: Integer, stage number of ShuffleNet
  bottleneck_channels: Float, bottleneck ratio implies the ratio of bottleneck channels to output channels
   
 # Returns
  Output tensor
  
 # Note
  For Stage 2, we(authors of shufflenet) do not apply group convolution on the first pointwise layer 
  because the number of input channels is relatively small.
 """
 channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
 in_channels = K.int_shape(inputs)[channel_axis]
 bottleneck_channels = int(filters * bottleneck_ratio)
 
 if stage == 2:
  x = Conv2D(filters=bottleneck_channels, kernel_size=kernel, strides=1,
     padding='same', use_bias=False)(inputs)
 else:
  x = _group_conv(inputs, bottleneck_channels, (1, 1), 1, groups)
 x = BatchNormalization(axis=channel_axis)(x)
 x = ReLU()(x)
 
 x = _channel_shuffle(x, groups)
 x = DepthwiseConv2D(kernel_size=kernel, strides=stride, depth_multiplier=1, 
      padding='same', use_bias=False)(x)
 x = BatchNormalization(axis=channel_axis)(x)
  
 if stride == 2:
  x = _group_conv(x, filters - in_channels, (1, 1), 1, groups)
  x = BatchNormalization(axis=channel_axis)(x)
  avg = AveragePooling2D(pool_size=(3, 3), strides=2, padding='same')(inputs)
  x = Concatenate(axis=channel_axis)([x, avg])
 else:
  x = _group_conv(x, filters, (1, 1), 1, groups)
  x = BatchNormalization(axis=channel_axis)(x)
  x = add([x, inputs])
 return x
 
def _stage(x, filters, kernel, groups, repeat, stage):
 """
 Stage of ShuffleNet
 
 # Arguments
  x: Tensor, input tensor of with `channels_last` or 'channels_first' data format
  filters: Integer, number of output channels
  kernel: An integer or tuple/list of 2 integers, specifying the
   width and height of the 2D convolution window.
  strides: An integer or tuple/list of 2 integers,
   specifying the strides of the convolution along the width and height.
   Can be a single integer to specify the same value for
   all spatial dimensions.
  groups: Integer, number of groups per channel
  repeat: Integer, total number of repetitions for a shuffle unit in every stage
  stage: Integer, stage number of ShuffleNet
  
 # Returns
  Output tensor
 """
 x = _shufflenet_unit(x, filters, kernel, 2, groups, stage)
 
 for i in range(1, repeat):
  x = _shufflenet_unit(x, filters, kernel, 1, groups, stage)
 return x
 
def ShuffleNet(input_shape, classes):
 """
 ShuffleNet architectures
 
 # Arguments
  input_shape: An integer or tuple/list of 3 integers, shape
   of input tensor
  k: Integer, number of classes to predict
  
 # Returns
  A keras model
 """
 inputs = Input(shape=input_shape)
 
 x = Conv2D(24, (3, 3), strides=2, padding='same', use_bias=True, activation='relu')(inputs)
 x = MaxPooling2D(pool_size=(3, 3), strides=2, padding='same')(x)
 
 x = _stage(x, filters=384, kernel=(3, 3), groups=8, repeat=4, stage=2)
 x = _stage(x, filters=768, kernel=(3, 3), groups=8, repeat=8, stage=3)
 x = _stage(x, filters=1536, kernel=(3, 3), groups=8, repeat=4, stage=4)
 
 x = GlobalAveragePooling2D()(x)
 
 x = Dense(classes)(x)
 predicts = Activation('softmax')(x)
 model = Model(inputs, predicts)
 return model
 
if __name__ == '__main__':
 model = ShuffleNet((224, 224, 3), 1000)
 #plot_model(model, to_file='ShuffleNet.png', show_shapes=True)

以上這篇keras 實(shí)現(xiàn)輕量級網(wǎng)絡(luò)ShuffleNet教程就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python爬蟲谷歌Chrome F12抓包過程原理解析

    Python爬蟲谷歌Chrome F12抓包過程原理解析

    這篇文章主要介紹了Python爬蟲谷歌Chrome F12抓包過程原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Python2中的raw_input() 與 input()

    Python2中的raw_input() 與 input()

    這篇文章主要介紹了Python2中的raw_input() 與 input(),本文分析了它們的內(nèi)部實(shí)現(xiàn)和不同之處,并總結(jié)了什么情況下使用哪個函數(shù),需要的朋友可以參考下
    2015-06-06
  • Python中函數(shù)的返回值示例淺析

    Python中函數(shù)的返回值示例淺析

    這篇文章主要給大家介紹了關(guān)于Python中函數(shù)返回值的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • python條件語句和while循環(huán)語句

    python條件語句和while循環(huán)語句

    這篇文章主要介紹了python條件語句和while循環(huán)語句,文章基于python的相關(guān)資料展開對其條件語句及while循環(huán)語句的詳細(xì)內(nèi)容介紹,需要的小伙伴可以參考一下
    2022-04-04
  • OpenCV仿射變換的示例代碼

    OpenCV仿射變換的示例代碼

    本文主要介紹了OpenCV仿射變換的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 基于Python實(shí)現(xiàn)人臉識別相似度對比功能

    基于Python實(shí)現(xiàn)人臉識別相似度對比功能

    人臉識別技術(shù)是一種通過計算機(jī)對人臉圖像進(jìn)行分析和處理,從而實(shí)現(xiàn)自動識別和辨認(rèn)人臉的技術(shù),隨著計算機(jī)視覺和模式識別領(lǐng)域的快速發(fā)展,人臉識別技術(shù)取得了長足的進(jìn)步,本文給大家介紹了基于Python實(shí)現(xiàn)人臉識別相似度對比功能,感興趣的朋友可以參考下
    2024-01-01
  • Pycharm自帶Git實(shí)現(xiàn)版本管理的方法步驟

    Pycharm自帶Git實(shí)現(xiàn)版本管理的方法步驟

    這篇文章主要介紹了Pycharm自帶Git實(shí)現(xiàn)版本管理的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 使用Pytorch實(shí)現(xiàn)Swish激活函數(shù)的示例詳解

    使用Pytorch實(shí)現(xiàn)Swish激活函數(shù)的示例詳解

    激活函數(shù)是人工神經(jīng)網(wǎng)絡(luò)的基本組成部分,他們將非線性引入模型,使其能夠?qū)W習(xí)數(shù)據(jù)中的復(fù)雜關(guān)系,Swish 激活函數(shù)就是此類激活函數(shù)之一,在本文中,我們將深入研究 Swish 激活函數(shù),提供數(shù)學(xué)公式,探索其相對于 ReLU 的優(yōu)勢,并使用 PyTorch 演示其實(shí)現(xiàn)
    2023-11-11
  • Django查詢優(yōu)化及ajax編碼格式原理解析

    Django查詢優(yōu)化及ajax編碼格式原理解析

    這篇文章主要介紹了Django查詢優(yōu)化及ajax編碼格式原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 一文搞懂python 中的迭代器和生成器

    一文搞懂python 中的迭代器和生成器

    這篇文章主要介紹了python 中的迭代器和生成器簡單介紹,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03

最新評論