簡體   English   中英

如何刪除模型 Tensorflow Keras 中的特定神經元

[英]How to remove a specific neuron inside Model Tensorflow Keras

有沒有辦法去除模型中的特定神經元?

例如,我有一個帶有 512 個神經元的 Dense 層的模型。 有沒有辦法刪除所有在list_indeces中有索引的神經元? 當然,移除一個神經元會影響下一層甚至前一層。

例子:

我在多篇論文中都有這個通用模型:

data_format = 'channels_last'
    input_shape = [28, 28, 1]
    max_pool = functools.partial(
        tf.keras.layers.MaxPooling2D,
        pool_size=(2, 2),
        padding='same',
        data_format=data_format)
    conv2d = functools.partial(
        tf.keras.layers.Conv2D,
        kernel_size=5,
        padding='same',
        data_format=data_format,
        activation=tf.nn.relu)
    model = tf.keras.models.Sequential([
        conv2d(filters=32, input_shape=input_shape),
        max_pool(),
        conv2d(filters=64),
        max_pool(),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(512, activation=tf.nn.relu),
        tf.keras.layers.Dense(10 if only_digits else 62),
    ])
    return model

假設從層tf.keras.layers.Dense(512, activation=tf.nn.relu)我想移除 100 個神經元,基本上將它們關閉。

當然,我將有一個新模型,層為tf.keras.layers.Dense(412, activation=tf.nn.relu)而不是tf.keras.layers.Dense(512, activation=tf.nn.relu)但是這個修改也應該傳播到下一層的權重,因為從密集層的神經元到下一層的連接也被刪除了。

關於如何這樣做的任何意見? 我可以通過執行以下操作來手動執行此操作:

如果我正確理解,模型形狀就是這個: [5, 5, 1, 32], [32], [5, 5, 32, 64], [64], [3136, 512], [512], [512, 62], [62]

所以我可以做這樣的事情:

  1. 生成我需要的所有索引並在list_indices它們相同
  2. 訪問層tf.keras.layers.Dense(512, activation=tf.nn.relu)的權重,並使用list_indices內的list_indices重創建張量
  3. 將新的權重張量分配給子模型的層tf.keras.layers.Dense(412, activation=tf.nn.relu)

問題是我不知道如何獲得下一層權重的正確權重,這些權重對應於我剛剛創建的權重索引以及我應該分配給子模型下一層的權重。 我希望我已經清楚地解釋了自己。

謝謝,萊拉。

您的操作在文獻中被稱為selective dropout ,實際上不需要每次都創建不同的模型,您只需要將所選神經元的輸出乘以 0,這樣下一層的輸入就不會采用那些帳戶中的激活。

請注意,如果您“關閉” Ln層中的一個神經元,它不會完全“關閉” Ln+1層中的任何神經元,假設兩者都是完全連接的層(密集): Ln+1中的每個神經元層連接到前一層中的所有神經元。 換句話說,移除全連接(密集)層中的神經元不會影響下一層的維度。

您可以使用Multiply Layer (Keras)簡單地實現此操作。 缺點是您需要學習如何使用Keras 函數式 API 還有其他方法但比這更復雜(例如自定義層),而且函數式 API 在許多方面都非常有用和強大,非常建議閱讀!

你的模型會變成這樣:

data_format = 'channels_last'
input_shape = [28, 28, 1]
max_pool = ...
conv2d = ...

# convert a list of indexes to a weight tensor
def make_index_weights(indexes):
    # converting indexes to a list of weights
    indexes = [ float(i not in indexes) for i in range(units) ]
    # converting indexes from list/numpy to tensor
    indexes = tf.convert_to_tensor(indexes)
    # reshaping to the correct format
    indexes = tf.reshape(indexes, (1, units))
    # ensuring it is a float tensor
    indexes = tf.cast(indexes, 'float32')
    return indexes

# layer builder utility
def selective_dropout(units, indexes, **kwargs):
    indexes = make_index_weights(indexes)
    dense = tf.keras.layers.Dense(units, **kwargs)
    mul = tf.keras.layers.Multiply()
    # return the tensor builder
    return lambda inputs: mul([ dense(inputs), indexes ])

input_layer = tf.keras.layers.Input(input_shape)
conv_1  = conv2d(filters=32, input_shape=input_shape)(input_layer)
maxp_1  = max_pool()(conv_1)
conv_2  = conv2d(filters=64)(maxp_1)
maxp_2  = max_pool()(conv_2)
flat    = tf.keras.layers.Flatten()(maxp_2)
sel_drop_1 = selective_dropout(512, INDEXES, activation=tf.nn.relu)(flat)
dense_2 = tf.keras.layers.Dense(10 if only_digits else 62)(sel_drop_1)
output_layer = dense2
model = tf.keras.models.Model([ input_layer ], [ output_layer ])
return model

現在你只需要根據你需要刪除的那些神經元的索引來建立你的INDEXES列表。

在您的情況下,張量的形狀為1x512因為密集層中有 512 個權重(單位/神經元),因此您需要為索引提供盡可能多的權重。 selective_dropout函數允許傳遞要丟棄的索引列表,並自動建立所需的張量。

例如,如果您想移除神經元 1, 10, 12,您只需將列表[1, 10, 12]傳遞給函數,它將生成一個1x512張量,這些位置為0.0 ,所有其他位置為1.0

編輯:

正如您所提到的,您嚴格需要減少模型中參數的大小。

每個密集層由關系y = Wx + B ,其中W是內核(或權重矩陣), B是偏置向量。 WINPUTxOUTPUT維度的矩陣,其中INPUT是最后一層輸出形狀, OUTPUT是層中神經元/單元/權重的數量; B只是一個維度為1xOUTPUT的向量(但我們對此不感興趣)。

現在的問題是您在Ln層中丟棄了N神經元,這會導致Ln+1層中的NxOUTPUT權重下降。 讓我們用一些數字來實事求是。 在你的情況下(假設only_digits為真)你開始:

Nx512 -> 512x10 (5120 weights)

並且在丟掉 100 個神經元之后(這意味着減少了 100*10=1000 個權重)

Nx412 -> 412x10 (4120 weights)

現在W矩陣的每一列都描述了一個神經元(作為一個維度等於前一層輸出維度的權重向量,在我們的例子中是 512 或 412)。 矩陣的行代表前一層中的單個神經元。

W[0,0]表示第n層的第一個神經元和第n+1層的第一個神經元之間的關系。

  • W[0,0] -> 1st n, 1st n+1
  • W[0,1] -> 2nd n, 1st n+1
  • W[1,0] -> 1st n, 2nd n+1

等等。 因此,您可以從此矩陣中刪除與您刪除的神經元索引相關的所有行: index 0 -> row 0

您可以使用dense.kernel從密集層訪問W矩陣作為張量

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM