Keras使用進階(Ⅰ)

2021-03-02 機器學習算法工程師
作者&編輯:李中梁前言

在一年多前筆者寫過一篇keras使用入門指南:超快速!10分鐘入門Keras指南。憶往事悠悠,某日打開自己博客發現文章閱讀量快3W了。恰好這大半年的research也用到了keras高級點的特性,尋思著是時候寫一篇keras使用進階的文章來記錄下自己「摸魚」的日子.

用keras訓練多標籤數據

通常用keras做分類任務,一張圖像往往只對應著一種類別,但是在實際的問題中,可能你需要預測出一張圖像的多種屬性。例如在pyimagesearch的《multi-label-classification-with-keras》這篇文章中提出了一個衣服數據集,整個數據集有兩種屬性,一種是顏色(blue, red, black),另一種是衣服的類型(dress, jeans, shirt) 。如假設one-hot-vector編碼順序是(blue, red, black, dress, jeans, shirt)則black jeans的 label就是[0,0,1,0,1,0]。

那麼面對這樣的多標籤任務如何使用keras進行CNN模型的搭建與訓練呢?

首先我們搭建一個單輸入(一張圖像)多輸出(圖像的多個屬性,比如衣服的顏色,類型)的CNN。

def GenModel(img_width = 512, img_height = 512 , model_name = 'AlexNet'):        image_input_shape = (img_width, img_height, 3)        if model_name == 'AlexNet':        print('\n---Start build model ', model_name, '---\n')                        image_input = Input(shape=image_input_shape, name='image_input')
conv_image = Conv2D(96, (11, 11), strides = (4, 4), padding = 'valid', activation = 'relu')(image_input) conv_image = MaxPooling2D(pool_size = (3, 3), strides = (2, 2))(conv_image)
conv_image = Conv2D(256, (5, 5), strides = (1, 1), padding = 'same', activation = 'relu')(conv_image) conv_image = MaxPooling2D(pool_size = (3, 3), strides = (2, 2))(conv_image)
conv_image = Conv2D(384, (3,3), strides = (1, 1), padding = 'same', activation = 'relu')(conv_image) conv_image = Conv2D(384, (3,3), strides = (1, 1), padding = 'same', activation = 'relu')(conv_image)
conv_image = Conv2D(384, (3,3), strides = (1, 1), padding = 'same', activation = 'relu')(conv_image) conv_image = MaxPooling2D(pool_size = (3, 3), strides = (2, 2))(conv_image)
conv_image = Flatten()(conv_image)
out_color = Dense(4096, activation='relu',)(conv_image) out_color = Dense(512, activation='relu',)(out_color) out_color = Dense(3, activation='sigmoid', name='out_age')(out_color) out_type = Dense(4096, activation='relu',)(conv_image) out_type = Dense(512, activation='relu',)(out_sex) out_type = Dense(3, activation='sigmoid', name='out_sex')(out_sex)
model=Model(inputs = image_input, outputs = [out_color, out_type]) return model


然後對模型進行編譯

    opt=Adadelta()    print('\n--- optimizer: %s ---\n'%(opt.__class__.__name__) )    model.compile(  optimizer = opt,                     loss = {'out_color': 'categorical_crossentropy', 'out_type': 'categorical_crossentropy'},                     loss_weights = {'out_color': out_color_weight, 'out_type': out_type_weight, metrics = ['accuracy']) 

最後將數據集載入模型進行訓練和預測

print("[INFO] loading images...")imagePaths = sorted(list(paths.list_images(args["dataset"])))random.seed(42)random.shuffle(imagePaths)
data = []labels = []
for imagePath in imagePaths: image = cv2.imread(imagePath) image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0])) image = img_to_array(image) data.append(image)
l = label = imagePath.split(os.path.sep)[-2].split("_") labels.append(l)
data = np.array(data, dtype="float") / 255.0labels = np.array(labels)print("[INFO] data matrix: {} images ({:.2f}MB)".format( len(imagePaths), data.nbytes / (1024 * 1000.0)))print(labels)print("[INFO] class labels:")mlb = MultiLabelBinarizer()labels = mlb.fit_transform(labels)print(labels)for (i, label) in enumerate(mlb.classes_): print("{}. {}".format(i + 1, label))
(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.2, random_state=42)
aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1, height_shift_range=0.1, shear_range=0.2, zoom_range=0.2, horizontal_flip=True, fill_mode="nearest")
print("[INFO] training network...")H = model.fit_generator( aug.flow(trainX, trainY, batch_size=BS), validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS, epochs=EPOCHS, verbose=1)


使用Lambda層讓你的keras網絡更加靈活

 keras的lambda層可以算是自定義keras的神器,一起來看下。

keras的Lambda層的導入方法和函數原型:

from keras.layers.core import Lambdakeras.layers.core.Lambda(function, output_shape=None, mask=None, arguments=None)

參數的含義:

function: 要實現的函數,該函數僅接受一個變量,即上一層的輸出output_shape: 函數應該返回值的shape,可以是一個tuple,也可以是一個根據輸入shape`mask: 掩膜arguments: 可選參數,字典,用來記錄向函數中傳遞的其他關鍵字參數

例子:

model.add(Lambda(lambda x: x ** 2))

def antirectifier(x): x -= K.mean(x, axis=1, keepdims=True) x = K.l2_normalize(x, axis=1) pos = K.relu(x) neg = K.relu(-x) return K.concatenate([pos, neg], axis=1)
def antirectifier_output_shape(input_shape): shape = list(input_shape) assert len(shape) == 2 shape[-1] *= 2 return tuple(shape)
model.add(Lambda(antirectifier, output_shape=antirectifier_output_shape))


import numpy as np from keras.models import Sequential from keras.layers import Dense, Activation,Reshape from keras.layers import merge from keras.utils import plot_modelfrom keras.layers import *from keras.models import Model
def get_slice(x, index): return x[:, index]
keep_num = 3 field_lens = 90input_field = Input(shape=(keep_num, field_lens))avg_pools = []for n in range(keep_num): block = Lambda(get_slice,output_shape=(1,field_lens),arguments={'index':n})(input_field) x_emb = Embedding(input_dim=100, output_dim=200, input_length=field_lens)(block) x_avg = GlobalAveragePooling1D()(x_emb) avg_pools.append(x_avg) output = concatenate([p for p in avg_pools])model = Model(input_field, output) plot_model(model, to_file='model/lambda.png',show_shapes=True)
plt.figure(figsize=(21, 12))im = plt.imread('model/lambda.png')plt.imshow(im)



from keras import backend as Kfrom keras.engine.topology import Layerimport numpy as np
class MyLayer(Layer):
def __init__(self, output_dim, **kwargs): self.output_dim = output_dim super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape): self.kernel = self.add_weight(name='kernel', shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True) super(MyLayer, self).build(input_shape)
def call(self, x): return K.dot(x, self.kernel)
def compute_output_shape(self, input_shape): return (input_shape[0], self.output_dim)

總結一下,keras的Lambda層就是一個層,允許用戶自定義對上層輸入數據的操作,自定義操作通過keras.layers.core.Lambda的function進行。

使用回調函數

model的fit()方法有一個參數是callbacks,這個參數可以傳入一些其他待執行的函數,在訓練過程中,每一個epoch會調用一次列表中的callbacks,這樣我們就可以實現很多騷操作在訓練過程中了。

在下面這個例子中設置monitor=』val_acc』來保存訓練過程中驗證集準確率最高的模型

checkpoint = ModelCheckpoint(filepath='./best_model.weights',                             monitor='val_acc',                             verbose=1,                             save_best_only=True)
model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test), callbacks=[checkpoint])


深度學習模型有時需要訓練很長時間,如果中斷了就要親命了。

那麼如何在訓練途中保存想要的模型呢?

ArgName=',epo='+str(epoch)+',bsize='+str(batch_size)+',lr='+str(LearningRate)+',DropRate='+str(DropoutRate)FileNamePy=os.path.basename(__file__).split('.')[-2]checkpoint_filepath = FileNamePy+ArgName
checkpointer_val_best = ModelCheckpoint(filepath=checkpoint_filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max', save_weights_only=True)
callbacks_list = [checkpointer_val_best]
hist=model.fit_generator( train_generator, steps_per_epoch=nb_train_samples, epochs=epoch, validation_data=validation_generator, validation_steps=nb_validation_samples, callbacks = callbacks_list)

這種方法雖然簡單,但是有一個明顯的缺點,就是裡邊的指標是由compile的metrics來確定的,而Keres中自定義一個metric,需要寫成張量運算才行,也就是說如果你期望的指標並不能寫成張量運算(比如bleu等指標),那麼就沒法寫成一個metric函數了,也就不能用這個方案了。
by:蘇劍林

蘇劍林大神提供了一個方案:自己寫回調器

from keras.callbacks import Callback
def evaluate(): pred = model.predict(x_test) return np.mean(pred.argmax(axis=1) == y_test) class Evaluate(Callback):
def __init__(self): self.accs = [] self.highest = 0.
def on_epoch_end(self, epoch, logs=None): acc = evaluate() self.accs.append(acc) if acc >= self.highest: self.highest = acc model.save_weights('best_model.weights')
print 'acc: %s, highest: %s' % (acc, self.highest)
evaluator = Evaluate()model.fit(x_train, y_train, epochs=10, callbacks=[evaluator])


訓練過程中還有可能對超參數進行微調,比如最常見的一個需求是根據epoch來調整學習率,這可以簡單地通過LearningRateScheduler來實現,它也屬於回調器之一。這個方案也是蘇神的~

from keras.callbacks import LearningRateScheduler
def lr_schedule(epoch): if epoch < 50: lr = 1e-2 elif epoch < 80: lr = 1e-3 else: lr = 1e-4 return lr
lr_scheduler = LearningRateScheduler(lr_schedule)
model.fit(x_train, y_train, epochs=10, callbacks=[evaluator, lr_scheduler])

更多例子可以看蘇神博客:https://www.spaces.ac.cn/

輸出優化器的名字

下面簡單介紹一個小技巧,可能一些初學者還沒有用過。通常我們import了一個優化器但是需要以字符串的形式知道這個優化器的名字進行一些記錄類的操作,那麼怎麼實現呢?

from keras.optimizers import Adam
opt=Adam()opt_name=opt.__class__.__name__print(opt_name)

寫在最後

keras可以說是深度學習最容易上手的深度學習框架了。雖然一些不了解它的人會「詬病」它的不靈活性。但其實它是非常靈活的,用蘇神的話來說就是:tf能實現的,keras也可以~

這篇文章叫《Keras使用進階(Ⅰ)》,講道理應該有《Keras使用進階(Ⅱ)》,只是下一篇更新時間的話.嘻嘻~

參考資料&延伸閱讀

[keras作者fchollet的學習資源推薦]

(https://github.com/fchollet/keras-resources)

[Multi_Label_Classification_Keras](https://github.com/ItchyHiker/Multi_Label_Classification_Keras)

[keras官方使用自定義層文檔]

(https://keras.io/layers/writing-your-own-keras-layers/)

[讓Keras更酷一些!Keras模型雜談 - 科學空間|Scientific Spaces](https://www.spaces.ac.cn/archives/5765)

[UCF課程:高級計算機視覺(Keras) by Mubarak Shah](https://www.bilibili.com/video/av24577241)

[某位博主寫的Lambda層例子]

(https://www.cnblogs.com/jins-note/p/9734771.html)

[keras官方callbacks文檔]

(https://keras.io/zh/callbacks/)

與我交流

github: https://github.com/keloli

blog:    https://www.jianshu.com/u/d055ee434e59

機器學習算法工程師

                            一個用心的公眾號

長按,識別,加關注

進群,學習,得幫助

你的關注,我們的熱度,

我們一定給你學習最大的幫助

相關焦點

  • 使用Keras進行遷移學習
    因此,使用預先訓練的網絡權值作為初始化或固定的特徵提取器有助於解決現有的大多數問題。非常深的網絡訓練是昂貴的。最複雜的模型需要使用數百臺配備了昂貴gpu的機器,數周的時間來進行訓練。因為深度學習確定結構/調整/訓練方法/超參數是一門沒有太多理論指導的黑盒子。
  • 使用 Keras Tuner 調節超參數
    下方示例中,我們構建了一個簡單的可調參模型,並使用 CIFAR-10 進行訓練:import tensorflow as tfdef build_model(hp): inputs = tf.keras.Input(shape=(32, 32, 3)) x = inputs for i in range(hp.Int('conv_blocks
  • 初學者怎樣使用Keras進行遷移學習
    首先,載入相關包 import pandas as pdimport numpy as npimport osimport kerasimport matplotlib.pyplot as pltfrom keras.layers import Dense,GlobalAveragePooling2Dfrom keras.applications
  • 技術分享|深度學習之Keras簡介與使用
    compile(optimizer, loss=None, metrics=None, loss_weights=None, sample_weight_mode=None, weighted_metrics=None, target_tensors=None)2.1 optimizeroptimizer 是指此模型使用的優化器
  • 初學AI神經網絡應該選擇Keras或是Pytorch框架?
    keras是神經網絡的一個模型計算框架,嚴格來說不是神經網絡框架。本身沒有重量級計算,它使用其他AI框架作為計算後臺,傻瓜式的使用。它的計算後臺還支持 Theano、CNTK(微軟的一個AI計算後臺)等,也就是說keras是多個計算後臺的門面。官方設計哲學為Simple. Flexible.
  • 易用的新深度學習框架Keras簡介及使用
    Theano,前面五篇Deeplearning相關的文章也是學習Theano的一些筆記,當時已經覺得Theano用起來略顯麻煩,有時想實現一個新的結構,就要花很多時間去編程,所以想過將代碼模塊化,方便重複使用,但因為實在太忙沒有時間去做。
  • 使用tensorflow和Keras的初級教程
    損失函數在處理回歸問題時,我們不需要為輸出層使用任何激活函數。在訓練回歸問題時使用的損失函數是均方誤差。然而,訓練集中的異常值可以用平均絕對誤差來處理。Huber損失也是基於回歸的任務中廣泛使用的誤差函數。當誤差小於閾值t(大多為1)時,Huber損失是二次的,但當誤差大於t時,Huber損失是線性的。
  • keras 教程
    除此之外還有在gpu下使用的版本,在keras中的名字就是CuDNN。如果為False,gamma不使用。># 相當於 subtracted = keras.layers.subtract([x1, x2])# 使用x1張量減去x2,最終得到一個尺寸與兩者相同的張量subtracted = keras.layers.Subtract()([x1, x2])
  • Keras 2.3.0 發布,後續將被 tf.keras 取代
    此版本 API 與 TensorFlow 2.0 中的 tf.keras API 同步。但需要注意的是,它不支持大多數 TensorFlow 2.0 功能,包括 Eager Execution。如果需要使用這些功能,可以使用 tf.keras。
  • python在Keras中使用LSTM解決序列問題
    首先,我們將了解如何使用單個特徵解決一對一的序列問題,然後我們將了解如何使用多個特徵解決一對一的序列問題。單一特徵的一對一序列問題在本節中,我們將看到如何解決每個時間步都有一個特徵的一對一序列問題。首先,我們導入將在本文中使用的必需庫:from numpy import arrayfrom keras.preprocessing.text import one_hotfrom keras.preprocessing.sequence import pad_sequencesfrom keras.models import
  • 使用 keras-bert 實現文本多分類任務
    本文將會介紹如何使用kera
  • TensorFlow 1.9 新增 tf.keras 官方入門教程(Keras與TF的深度集成)
    TensorFlow雖然功能強大,但是對於工程師來說,它的使用卻十分的繁瑣。好消息是Keras的許多核心功能已經融入了原生的TensorFlow(tf.keras),TensorFlow 1.9新增tf.keras官方入門文檔,介紹了tf.keras的使用。
  • 深度學習Keras中的Embedding層的理解與使用
    這個數據準備步驟可以使用Keras提供的Tokenizer API來執行。嵌入層用隨機權重進行初始化,並將學習訓練數據集中所有單詞的嵌入。它是一個靈活的圖層,可以以多種方式使用,例如:它可以單獨使用來學習一個單詞嵌入,以後可以保存並在另一個模型中使用。
  • 深度學習 | Keras 簡介
    當然,業界也有很多優秀的框架比如Pytorch,不過筆者更傾向於前者,前者的開發主要由Google支持,而且Keras API打包為tf.keras封裝在TensorFlow中。此外,Microsoft維護CNTK Keras後端。Amazon AWS正在使用MXNet支持維護Keras分支。其他貢獻公司包括NVIDIA,Uber和Apple。
  • Keras系列(一):介紹
    下面有請鐵柱介紹Keras:Keras是什麼Keras是深度學習建模的一個上層建築,其後端可以靈活使用CNTK、TensorFlow或者Theano。這樣就可以避免不同深度學習框架的差異而集中於建模過程。
  • 用Keras復現DCN算法
    可是DCN算法並沒有keras的實現代碼,而我之前也沒有用過keras,導致用keras復現DCN算法耗費了我一周多的時間,不過經過了一周的折騰,也算基本熟悉了keras的使用。keras由於過於的強調易用性,以及受制於tensorflow等底層框架的機制影像導致開發簡單應用很容易但是如果做復現最新論文算法的定製開發就會比較困難,而pytorch就比較好的平衡了易用性以及拓展性,用pytorch來實現上述功能則比較簡單,這也是pytorch應用越來越受歡迎的原因吧。不過由於實驗室之前的代碼都是用keras寫的,這裡的DCN算法也要用keras來實現。
  • Keras結合Keras後端搭建個性化神經網絡模型(不用原生Tensorflow)
    所以,如果不追求速度的話,可以僅使用Keras實現你的任何獨特想法,從而避免使用原生Tensorflow寫重複的輪子。我們定義並訓練一個神經網絡模型需要考慮的要素有三個:層、損失函數、優化器。而我們創新主要在於前兩個,因此下面介紹如何結合Keras高級API與後端,自定義特殊神經網絡層以及損失函數。
  • 手把手教你在小數據集下使用Keras進行圖像分類
    現在我們翻譯了 Rising Odegua 這篇基於 keras 進行圖像分類的文章。在本文,作者介紹了如何在數據集較小的情況下,如何使用 keras 進行圖像分類。更多乾貨內容請關注微信公眾號「AI 前線」(ID:ai-front) 上個周末,我經歷了一場思想狂潮。
  • 教程 | 一招教你使用 tf.keras 和 eager execution 解決複雜問題
    (圖片標註)在暑期實習期間,我使用 TensorFlow 的兩個最新 API(tf.keras 和 eager execution)開發了這些示例,以下是分享內容。希望你們能覺得它們有用,有趣! Eager execution 是一個由運行定義的命令式接口,一旦從 Python 調用,其操作將被立即執行。這使得入門 TensorFlow 變得更簡單,也使研發更直觀。
  • 心法利器[3] | tf.keras自學筆記
    build中可以進一步對參數進行定義,在第一次使用該層的時候調用該部分代碼,在這裡創建變量可以使得變量的形狀自適應輸入的形狀,並且給裡面的參數進行初始化,可以看到裡面有個initializercall,在函數式下,執行這一層的時候會調用這個函數進行前向計算。像上面的例子就是做了一個線性變換。如果是需要支持序列化,則需要用get_config或者是from_config的方式把必要的超參返回出來。