Keras結合Keras後端搭建個性化神經網絡模型(不用原生Tensorflow)

2021-01-11 紙鶴視界

Keras是基於Tensorflow等底層張量處理庫的高級API庫。它幫我們實現了一系列經典的神經網絡層(全連接層、卷積層、循環層等),以及簡潔的迭代模型的接口,讓我們能在模型層面寫代碼,從而不用仔細考慮模型各層張量之間的數據流動。

但是,當我們有了全新的想法,想要個性化模型層的實現,Keras的高級API是不能滿足這一要求的,而換成Tensorflow又要重新寫很多輪子,這時,Keras的後端就派上用場了。Keras將底層張量庫的函數功能統一封裝在「backend」中,用戶可以用統一的函數接口調用不同的後端實現的相同功能。所以,如果不追求速度的話,可以僅使用Keras實現你的任何獨特想法,從而避免使用原生Tensorflow寫重複的輪子。

我們定義並訓練一個神經網絡模型需要考慮的要素有三個:層、損失函數、優化器。而我們創新主要在於前兩個,因此下面介紹如何結合Keras高級API與後端,自定義特殊神經網絡層以及損失函數。

自定義網絡層

自定義層可以通過兩種方式實現:使用Lambda層和繼承Layer類。

lambda層

Lambda層僅能對輸入做固定的變換,並不能定義可以通過反向傳播訓練的參數(通過Keras的fit訓練),因此能實現的東西較少。以下代碼實現了Dropout的功能:

from keras import backend as Kfrom keras import layersdef my_layer(x): mask = K.random_binomial(K.shape(x),0.5) return x*mask*2x = layers.Lambda(my_layer)(x)

其中my_layer函數是自定義層要實現的操作,傳遞參數只能是Lambda層的輸入。定義好函數後,直接在layers.Lambda中傳入函數對象即可。實際上,這些變換不整合在lambda層中而直接寫在外面也是可以的:

from keras import backend as Kfrom keras import layersx = layers.Dense(500,activation='relu')(x) mask = K.random_binomial(K.shape(x),0.5)x = x*mask*2

數據先經過一個全連接層,然後再被0.5概率Dropout。以上實現Dropout只是作舉例,你可以以同樣的方式實現其它的功能。

繼承layer類

如果你想自定義可以訓練參數的層,就需要繼承實現Keras的抽象類Layer。主要實現以下三個方法:

1、__init__(self, *args, **kwargs):構造函數,在實例化層時調用。此時還沒有添加輸入,也就是說此時輸入規模未知,但可以定義輸出規模等與輸入無關的變量。類比於Dense層裡的units、activations參數。

2、build(self, input_shape):在添加輸入時調用(__init__之後),且參數只能傳入輸入規模input_shape。此時輸入規模與輸出規模都已知,可以定義訓練參數,比如全連接層的權重w和偏執b。

3、call(self, *args, **kwargs):編寫層的功能邏輯。

單一輸入

當輸入張量只有一個時,下面是實現全連接層的例子:

import numpy as npfrom keras import layers,Model,Input,utilsfrom keras import backend as Kimport tensorflow as tfclass MyDense(layers.Layer): def__init__(self, units=32): #初始化 super(MyDense, self).__init__()#初始化父類 self.units = units #定義輸出規模def build(self, input_shape): #定義訓練參數 self.w = K.variable(K.random_normal(shape=[input_shape[-1],self.units])) #訓練參數 self.b = tf.Variable(K.random_normal(shape=[self.units]),trainable=True) #訓練參數 self.a = tf.Variable(K.random_normal(shape=[self.units]),trainable=False) #非訓練參數def call(self, inputs): #功能實現return K.dot(inputs, self.w) + self.b #定義模型input_feature = Input([None,28,28]) x = layers.Reshape(target_shape=[28*28])(input_feature)x = layers.Dense(500,activation='relu')(x) x = MyDense(100)(x)x = layers.Dense(10,activation='softmax')(x) model = Model(input_feature,x) model.summary() utils.plot_model(model)

模型結構如下:

在build()中,訓練參數可以用K.variable或tf.Variable定義。並且,只要是用這兩個函數定義並存入self中,就會被keras認定為訓練參數,不管是在build還是__init__或是其它函數中定義。但是K.variable沒有trainable參數,不能設置為Non-trainable params,所以還是用tf.Variable更好更靈活些。

多源輸入

如果輸入包括多個張量,需要傳入張量列表。實現代碼如下:

import numpy as npfrom keras import layers,Model,Input,utilsfrom keras import backend as Kimport tensorflow as tfclass MyLayer(layers.Layer): def__init__(self, output_dims): super(MyLayer, self).__init__() self.output_dims = output_dims def build(self, input_shape): [dim1,dim2] = self.output_dims self.w1 = tf.Variable(K.random_uniform(shape=[input_shape[0][-1],dim1])) self.b1 = tf.Variable(K.random_uniform(shape=[dim1])) self.w2 = tf.Variable(K.random_uniform(shape=[input_shape[1][-1],dim2])) self.b2 = tf.Variable(K.random_uniform(shape=[dim2])) def call(self, x): [x1, x2] = x y1 = K.dot(x1, self.w1)+self.b1 y2 = K.dot(x2, self.w2)+self.b2 return K.concatenate([y1,y2],axis = -1) #定義模型input_feature = Input([None,28,28])#輸入x = layers.Reshape(target_shape=[28*28])(input_feature) x1 = layers.Dense(500,activation='relu')(x) x2 = layers.Dense(500,activation='relu')(x) x = MyLayer([100,80])([x1,x2]) x = layers.Dense(10,activation='softmax')(x) model = Model(input_feature,x) model.summary() utils.plot_model(model,show_layer_names=False,show_shapes=True)

模型結構如下:

總之,傳入張量列表,build傳入的input_shape就是各個張量形狀的列表。其它都與單一輸入類似。

自定義損失函數

根據Keras能添加自定義損失的特性,這裡將添加損失的方法分為兩類:

1、損失需要根據模型輸出與真實標籤來計算,也就是只有模型的輸出與外部真實標籤作為計算損失的參數。

2、損失無需使用外部真實標籤,也就是只用模型內部各層的輸出作為計算損失的參數。

這兩類損失添加的方式並不一樣,希望以後Keras能把API再改善一下,這種冗餘有時讓人摸不著頭腦。

第一類損失

這類損失可以通過自定義函數的形式來實現。函數的參數必須是兩個:真實標籤與模型輸出,不能多也不能少,並且順序不能變。然後你可以在這個函數中定義你想要的關於輸出與真實標籤之間的損失。然後在model.compile()中將這個函數對象傳給loss參數。代碼示例如下(參考連結):

def customed_loss(true_label,predict_label): loss = keras.losses.categorical_crossentropy(true_label,predict_label) loss += K.max(predict_label) return loss model.compile(optimizer='rmsprop', loss=customed_loss)

如果硬是想用這種方法把模型隱層的輸出拿來算損失的話,也不是不可以。只要把相應隱層的輸出添加到模型的輸出列表中,自定義損失函數就可以從模型輸出列表中取出隱層輸出來用了。即:

model = Model(input,[model_output, hidden_layer_output])

當然,這樣就把模型結構改了,如果不想改模型的結構而添加「正則化」損失,可以使用下面的方法。

第二類損失

這類損失可以用Model.add_loss(loss)方法實現,loss可以使用Keras後端定義計算圖來實現。但是顯然,計算圖並不能把未來訓練用的真實標籤傳入,所以,add_loss方法只能計算模型內部的「正則化」損失。

add_loss方法可以使用多次,損失就是多次添加的loss之和。使用了add_loss方法後,compile中就可以不用給loss賦值,不給loss賦值的話使用fit()時就不能傳入數據的標籤,也就是y_train。如果給compile的loss賦值,最終的目標損失就是多次add_loss添加的loss和compile中loss之和。另外,如果要給各項損失加權重的話,直接在定義loss的時候加上即可。代碼示例如下:

loss = 100000*K.mean(K.square(somelayer_output))#somelayer_output是定義model時獲得的某層輸出model.add_loss(loss)model.compile(optimizer='rmsprop')

以上講的都是關於層輸出的損失,層權重的正則化損失並不這樣添加,自定義正則項可以看下面。

keras中添加正則化_Bebr的博客-CSDN博客_keras 正則化

裡面介紹了已實現層的自定義正則化,但沒有介紹自定義層的自定義正則化,這裡先挖個坑,以後要用再研究。

相關焦點

  • Keras和TensorFlow究竟哪個會更好?
    在 TensorFlow 中結合 Keras 使用,會有雙贏效果: 你可以使用 Keras 提供的簡單、原生 API 來創建自己的模型。 Keras 的 API 類似於 scikit-learn 的,都可稱為機器學習的優質 API。 Keras 的 API 是模塊化的、基於 Python ,並且極其易於使用。
  • 初學AI神經網絡應該選擇Keras或是Pytorch框架?
    keras是神經網絡的一個模型計算框架,嚴格來說不是神經網絡框架。本身沒有重量級計算,它使用其他AI框架作為計算後臺,傻瓜式的使用。它的計算後臺還支持 Theano、CNTK(微軟的一個AI計算後臺)等,也就是說keras是多個計算後臺的門面。官方設計哲學為Simple. Flexible.
  • Keras入門系列教程:兩分鐘構建你的第一個神經網絡模型
    要開始使用tf.keras, 請將其作為TensorFlow程序的一部分導入:import tensorflow as tffrom tensorflow import kerastf.keras 可以運行任何與Keras兼容的代碼
  • TensorFlow(Keras)中的正則化技術及其實現(附代碼)
    了解用於緩解深度神經網絡內過度擬合問題的常規技術。正則化深度神經網絡(DNN)在體系結構內部具有大量的權重參數,可以學習一系列值。這些值的範圍是使神經網絡能夠解決龐大的複雜功能的關鍵。l2懲罰權重的平方和(權重)如果您要結合使用L1和L2正則化技術的效果,那麼您將獲得「彈性網正則化 」正則化技術對訓練過程中的神經網絡產生影響,而不是推論。
  • 用TensorFlow和Keras構建卷積神經網絡
    筆者已經編寫了一個如何使用TensorFlow的KerasAPI來訓練神經網絡的教程,著重介紹了自動編碼器:http://www.datastuff.tech/machine-learning/autoencoder-deep-learning-tensorflow-eager-api-keras/本文將嘗試三種不同的體系結構
  • 通過Keras 構建基於 LSTM 模型的故事生成器
    LSTM 網絡工作示意圖什麼是 LSTM 網絡?LSTM (Long Short Term Memory, 長短期神經網絡)是一種特殊的循環神經網絡(RNN, Recurrent neural networks)。
  • Keras R語言接口正式發布,同時公開20個完整示例
    關於keras的介紹Keras是一個高層神經網絡API,為支持快速實驗而生,目前主要功能如下:支持相同的代碼無縫跑在CPU或GPU上對用戶友好,易於快速prototype深度學習模型支持計算機視覺中的卷積網絡、序列處理中的循環網絡,也支持兩種網絡的任意組合支持任意網絡架構:多段輸入或多段輸出模型、層共享、模型共享等。
  • 深度解讀TensorFlow,了解它的最新發展!
    TensorFlow.js 可以為開發者提供高性能的、易於使用的機器學習構建模塊,允許研發人員在瀏覽器上訓練模型,或以推斷模式運行預訓練的模型。TensorFlow.js 不僅可以提供低級的機器學習構建模塊,還可以提供高級的類似 Keras 的 API 來構建神經網絡。
  • TensorFlow 2.1指南:keras模式、渴望模式和圖形模式(附代碼)
    經過一些實驗後,我發現在TensorFlow 2.1中,有3種構建模型的方法:Keras模式(tf.keras):基於圖形定義,並在以後運行圖形。渴望模式:基於定義執行的所有迭代定義圖的操作。圖形模式(tf.function):之前兩種方法的混合。讓我們來看看代碼。
  • TensorFlow 1.9.0-rc0 升級 tf.keras 至 Keras 2.1.6 API
    該版本帶來了不少改進和新特性:Update tf.keras to the Keras 2.1.6 API.tfe.Network is deprecated. Please inherit from tf.keras.Model.
  • 基於RTX2060構建TensorFlow-gpu(keras)學習平臺
    開始菜單運行anaconda navigator檢查是否安裝了notebook(默認有安裝)三、安裝tensorflow/keras在激活的環境中安裝:1. 如果機器上有gpu,則安裝gpu版本,沒有GPU就安裝cpu版。
  • 評測| CNTK在Keras上表現如何?能實現比TensorFlow更好的深度學習嗎?
    我選取了強調不同神經網絡架構的幾個例子(https://github.com/minimaxir/keras-cntk-benchmark/tree/master/test_files),並添加了一個自定義 logger,它能夠輸出含有模型性能和訓練時間進程的 CSV 文件。如前所述,只需要設置一個 flag 就能方便地切換後端引擎。
  • 小白學CNN以及Keras的速成
    sherlock使用的是Google的開源框架Tensorflow,因為Google開源了tensorflow之後其社區非常活躍,而且版本更新也非常穩定,所以我就選擇了這個框架。對於框架之爭,在知乎上已經有很多人在撕逼了,這個就好比哪種程式語言好這個問題一樣。
  • 使用Keras將音樂分類為不同類型
    我們將使用Keras,採用tensorflow作為後端。  重要的提示:  檢查tensorflow的版本應該大於1.1否則各種keras功能將失敗。  Pip可能無法獲得最新的tensorflow版本,因此請使用以下命令安裝tensorflow:  pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.6.0-py3-none-any.whl
  • 這裡有一份TensorFlow2.0中文教程
    簡單的圖像分類任務探一探此文章中,機器之心為大家推薦一個持續更新的中文教程,方便大家更系統的學習、使用 TensorFlow 2.0 : 知乎專欄地址:https://zhuanlan.zhihu.com/c_1091021863043624960 Github 項目地址:https://github.com/czy36mengfei/tensorflow2_tutorials_chinese
  • TensorFlow官方力推、GitHub爆款項目:用Attention模型自動生成...
    tf.keras: https://www.tensorflow.org/guide/keras eager execution: https://www.tensorflow.org/guide/eager 這款筆記是一種
  • Keras官方出調參工具了,然而Francois說先別急著用
    據介紹,Keras Tuner 是專為 AI 從業者、hypertuner 算法創建者和模型設計人員開發的一款簡單高效調參框架。它提供乾淨簡單的 API,用戶只需改變幾行代碼即可完成模型調參工作。除了簡單直觀的 API 之外,Keras Tuner 還提供 SOTA hypertuner 算法、可調整的架構,以及無縫實驗記錄功能。
  • Keras 2發布:實現與TensorFlow的直接整合
    Keras 2 有很多新變化,下面是簡明概覽:與 TensorFlow 整合儘管 Keras 自 2015 年 12 月已經作為運行時間後端(runtime backend)開始支持 TensorFlow,Keras API 卻一直與 TensorFlow 代碼庫相分離,這種情況正在改變:從 TensorFlow 1.2 版本開始,Keras API 可作為
  • 使用TF2與Keras實現經典GNN的開源庫——Spektral
    該項目的主要目的是提供一個簡單但又不失靈活性的圖神經網絡(graph neural networks,GNNs) 框架。我們可以使用 Spektral 來進行網絡節點分類、預測分子特性、使用 GAN 生成新的拓撲圖、節點聚類、預測連結以及其他任意數據是使用拓撲圖來描述的任務。
  • TensorFlow 2入門指南,初學者必備!
    Tensorflow v1難以使用和理解,因為它的Pythonic較少,但是隨著Keras發行的v2現在與Tensorflow.keras完全同步,它易於使用,易學且易於理解。現在,我們必須導入其他重要的庫,這將有助於我們創建神經網絡。