請快點粘貼複製,這是一份好用的TensorFlow代碼集

TensorFlow 雖然是目前最爲流行的神經網絡框架,卻以「難於上手」著稱(Jeff Dean:怪我咯)。有些時候,咱們須要簡明扼要的代碼來指點迷津。最近,來自 NCsoft AI 研究部門的 Junho Kim 就放出了一份這樣的 TensorFlow 代碼集。它相似於一個迷你版的 Keras,只不過由於其簡單性,源碼要好讀得多。

項目連接:https://github.com/taki0112/Tensorflow-Cookbookgit

在這個項目中,做者重點突出這是一份易於使用的 TensorFlow 代碼集,它包括常見的正則化、卷積運算和架構模塊等代碼。實際上,在咱們搭建本身的模型或系統時,複製並粘貼這些代碼就好了。它們以規範的形式定義不一樣的功能模塊,所以只要修改少許參數與代碼,它們就能完美地融入到咱們項目中。github

目前該項目包含通常深度學習架構所須要的代碼,例如初始化和正則化、各類卷積運算、基本網絡架構與模塊、損失函數和其它數據預處理過程。此外,做者還特別增長了對 GAN 的支持,這主要體如今損失函數上,其中生成器損失和判別器損失可使用推土機距離、最小二乘距離和 KL 散度等。bash

使用方法markdown

使用方法其實有兩種,首先咱們能夠複製粘貼代碼,這樣對於模塊的定製化很是有利。其次咱們能夠直接像使用 API 那樣調用操做與模塊,這種方法會使模型顯得很是簡潔,並且導入的源碼也通俗易懂。首先對於第二種直接導入的方法,咱們能夠從 ops.py 和 utils.py 文件分別導入模型運算部分與圖像預處理過程。網絡

  • from ops import *架構

  • from utils import *框架

from ops import convx = conv(x, channels=64, kernel=3, stride=2, pad=1, pad_type='reflect', use_bias=True, sn=True, scope='conv')複製代碼

而對於第一種複製粘貼,咱們可能會根據實際修改一些參數與結構,但這要比從頭寫簡單多了。以下所示,對於通常的神經網絡,它會採用以下結構模板:ide

def network(x, is_training=True, reuse=False, scope="network"):    with tf.variable_scope(scope, reuse=reuse):        x = conv(...)        ...return logit複製代碼

其實深度神經網絡就像一塊塊積木,咱們按照上面的模板把 ops.py 中不一樣的模塊堆疊起來,最終就能獲得完整的前向傳播過程。函數

代碼集目錄oop

項目頁面:www.notion.so/Simple-Tens…

目前整個項目包含 20 種代碼塊,它們可用於快速搭建深度學習模型:

代碼示例

以下主要介紹幾段代碼示例,包括最多見的卷積操做和殘差模塊等。每一項代碼示例都能採用 API 式的調用或複製粘貼,因此它們不僅能快速使用,學習各類操做的實現方法也是很好的資源。

卷積

卷積的原理相信你們都很熟悉,那就直接看調用代碼吧:

x = conv(x, channels=64, kernel=3, stride=2, pad=1, pad_type='reflect', use_bias=True, sn=True, scope='conv')複製代碼

以下所示爲實現以上 API 的代碼,相比於直接使用 padding='SAME',瞭解如何手給圖像 padding 零也是很好的。此外,這一段代碼嵌入了譜歸一化(spectral_normalization/sn),甚至咱們能夠截取這一小部分嵌入到本身的代碼中。

# padding='SAME' ======> pad = ceil[ (kernel - stride) / 2 ]def conv(x, channels, kernel=4, stride=2, pad=0, pad_type='zero', use_bias=True, sn=False, scope='conv_0'): with tf.variable_scope(scope): if pad > 0: h = x.get_shape().as_list()[1] if h % stride == 0: pad = pad * 2 else: pad = max(kernel - (h % stride), 0) pad_top = pad // 2 pad_bottom = pad - pad_top pad_left = pad // 2 pad_right = pad - pad_left if pad_type == 'zero': x = tf.pad(x, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]]) if pad_type == 'reflect': x = tf.pad(x, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], mode='REFLECT') if sn: w = tf.get_variable("kernel", shape=[kernel, kernel, x.get_shape()[-1], channels], initializer=weight_init, regularizer=weight_regularizer) x = tf.nn.conv2d(input=x, filter=spectral_norm(w), strides=[1, stride, stride, 1], padding='VALID') if use_bias: bias = tf.get_variable("bias", [channels], initializer=tf.constant_initializer(0.0)) x = tf.nn.bias_add(x, bias) else: x = tf.layers.conv2d(inputs=x, filters=channels, kernel_size=kernel, kernel_initializer=weight_init, kernel_regularizer=weight_regularizer, strides=stride, use_bias=use_bias) return x複製代碼

部分卷積(Partial Convolution)

部分卷積是英偉達爲圖像修復引入的卷積運算,它使模型可以修復任意非中心、不規則的區域。在論文 Image Inpainting for Irregular Holes Using Partial Convolutions 中,實現部分卷積是很是關鍵的,以下展現了簡單的調用過程:

x = partial_conv(x, channels=64, kernel=3, stride=2, use_bias=True, padding='SAME', sn=True, scope='partial_conv')        複製代碼

讀者可根據如下定義 PConv 的代碼瞭解具體實現信息:

def partial_conv(x, channels, kernel=3, stride=2, use_bias=True, padding='SAME', sn=False, scope='conv_0'):    with tf.variable_scope(scope):        if padding.lower() == 'SAME'.lower():            with tf.variable_scope('mask'):                _, h, w, _ = x.get_shape().as_list()                slide_window = kernel * kernel                mask = tf.ones(shape=[1, h, w, 1])                update_mask = tf.layers.conv2d(mask, filters=1,                                               kernel_size=kernel, kernel_initializer=tf.constant_initializer(1.0),                                               strides=stride, padding=padding, use_bias=False, trainable=False)                mask_ratio = slide_window / (update_mask + 1e-8)                update_mask = tf.clip_by_value(update_mask, 0.0, 1.0)                mask_ratio = mask_ratio * update_mask            with tf.variable_scope('x'):                if sn:                    w = tf.get_variable("kernel", shape=[kernel, kernel, x.get_shape()[-1], channels],                                        initializer=weight_init, regularizer=weight_regularizer)                    x = tf.nn.conv2d(input=x, filter=spectral_norm(w), strides=[1, stride, stride, 1], padding=padding)                else:                    x = tf.layers.conv2d(x, filters=channels,                                         kernel_size=kernel, kernel_initializer=weight_init,                                         kernel_regularizer=weight_regularizer,                                         strides=stride, padding=padding, use_bias=False)                x = x * mask_ratio                if use_bias:                    bias = tf.get_variable("bias", [channels], initializer=tf.constant_initializer(0.0))                    x = tf.nn.bias_add(x, bias)                    x = x * update_maskelse:            if sn:                w = tf.get_variable("kernel", shape=[kernel, kernel, x.get_shape()[-1], channels],                                    initializer=weight_init, regularizer=weight_regularizer)                x = tf.nn.conv2d(input=x, filter=spectral_norm(w), strides=[1, stride, stride, 1], padding=padding)                if use_bias:                    bias = tf.get_variable("bias", [channels], initializer=tf.constant_initializer(0.0))                    x = tf.nn.bias_add(x, bias)            else:                x = tf.layers.conv2d(x, filters=channels,                                     kernel_size=kernel, kernel_initializer=weight_init,                                     kernel_regularizer=weight_regularizer,                                     strides=stride, padding=padding, use_bias=use_bias)        return x   複製代碼

殘差模塊

ResNet 最大的特色即解決了反向傳播過程當中的梯度消失問題,所以它能夠訓練很是深的網絡而不用像 GoogLeNet 那樣在中間添加分類網絡以提供額外的梯度。而 ResNet 是由殘差模塊堆疊起來的,通常根據須要能夠定義幾種不一樣的殘差模塊:

x = resblock(x, channels=64, is_training=is_training, use_bias=True, sn=True, scope='residual_block')x = resblock_down(x, channels=64, is_training=is_training, use_bias=True, sn=True, scope='residual_block_down')x = resblock_up(x, channels=64, is_training=is_training, use_bias=True, sn=True, scope='residual_block_up')複製代碼

如上展現了三種殘差模塊,其中 down 表示降採樣,輸入特徵圖的長寬都會減半;而 up 表示升採樣,輸入特徵圖的長寬都會加倍。在每個殘差模塊上,殘差鏈接會將該模塊的輸入與輸出直接相加。所以在反向傳播中,根據殘差鏈接傳遞的梯度就能夠不通過殘差模塊內部的多個卷積層,於是能爲前一層保留足夠的梯度信息。

以下簡單定義了通常的 resblock 和採用升採樣的 resblock_up,由於它們調用的 conv()、deconv() 和 batch_norm() 等函數都是前面定義的不一樣計算模塊,所以總體上代碼看起來很是簡潔。

def resblock(x_init, channels, use_bias=True, is_training=True, sn=False, scope='resblock'):    with tf.variable_scope(scope):        with tf.variable_scope('res1'):            x = conv(x_init, channels, kernel=3, stride=1, pad=1, use_bias=use_bias, sn=sn)            x = batch_norm(x, is_training)            x = relu(x)        with tf.variable_scope('res2'):            x = conv(x, channels, kernel=3, stride=1, pad=1, use_bias=use_bias, sn=sn)            x = batch_norm(x, is_training)        return x + x_initdef resblock_up(x_init, channels, use_bias=True, is_training=True, sn=False, scope='resblock_up'):    with tf.variable_scope(scope):        with tf.variable_scope('res1'):            x = deconv(x_init, channels, kernel=3, stride=2, use_bias=use_bias, sn=sn)            x = batch_norm(x, is_training)            x = relu(x)        with tf.variable_scope('res2') :            x = deconv(x, channels, kernel=3, stride=1, use_bias=use_bias, sn=sn)            x = batch_norm(x, is_training)        with tf.variable_scope('skip') :            x_init = deconv(x_init, channels, kernel=3, stride=2, use_bias=use_bias, sn=sn)複製代碼

這裏只展現了三種功能塊的代碼實現,可能咱們會感受該項目相似於一個迷你的 Keras。但由於這個項目實現的操做都比較簡單常見,所以源碼讀起來會比 Keras 之類的大型庫簡單地多,這對於嵌入使用仍是學習都更有優點。

相關文章
相關標籤/搜索