首页 > 解决方案 > 如何在完全连接的单隐藏层网络中“关闭”单个神经元

问题描述

我有一个在 MNIST 上训练的简单模型,在隐藏层中有 600 个节点。

一些前兆...

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, InputLayer, Activation
from keras.optimizers import RMSprop, Adam
import numpy as np
import h5py
import matplotlib.pyplot as plt
from keras import backend as K
import tensorflow as tf

MNIST 加载

batch_size = 128
num_classes = 10
epochs = 50

(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# One hot conversion
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

设计模型

model = Sequential() 
###Model###
model.add(Dense(600, input_dim=784))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('softmax'))
model.summary()

tfcall = keras.callbacks.TensorBoard(log_dir='./keras600logs', histogram_freq=1, batch_size=batch_size, write_graph=True)

model.compile(loss='categorical_crossentropy',optimizer=Adam(), metrics=['accuracy'])

history = model.fit(x_train, y_train,
    batch_size=batch_size,
    epochs=10, #EPOCHS
    verbose=1,
    validation_data=(x_test, y_test),
    callbacks=[tfcall])
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

现在是新的部分。我希望动态地(即每个新的输入图像)能够定义一个“掩码”,它将关闭隐藏层中的 600 个神经元中的一些,防止它们将激活传递到输出层。

mask_i = [0, 0, 1, 0, 1, .... 0, 1, 0, 0] (1x600)

这样对于输入图像 i,具有 1 的掩码索引对应于在处理图像 i 时关闭的节点。

这样做的最佳方法是什么?

我们是否有另一个来自输入的节点,其权重 TOWARDS 隐藏层为 -100000000,以便它会压倒通常存在的任何激活(其余的将由 relu 完成)。这有点像动态破解偏见。

我们是否创建另一个隐藏层,其中 600 个节点中的每一个都直接连接到第一个隐藏层(本身)的一个节点,动态权重为 0(关闭)或 1(正常进行),然后完全连接新的隐藏层输出?

这两个似乎都有点hackish,想知道其他人的想法。

标签: tensorflowkeras

解决方案


我认为最好的方法是在该密集层之后放置一个带有遮罩的 lambda 层。

没有一点黑客就没有办法做到这一点,但这是一个非常干净的黑客。

为掩码创建一个变量:

import keras.backend as K

#create a var with length 600 and 2D shape
mask = K.variable([[0,1,0,0,0,1,1,0,....,1]])
    #careful: 0 means off
    #(same number of dimensions of the output of the dense layer)
    #make sure the shape is either
        #(1,600) - same mask for all samples; or
        #(batch_size,600) - one mask per sample

#important: whenever you want to change the mask, you must use:
K.set_value(mask,newValue)
    #otherwise you will not be changing the variable connected to the model

在模型中添加 lambda 层:

....
model.add(Dense(600, input_dim=784))
model.add(Lambda(lambda x: x * mask))
model.add(Activation('relu'))
....

如果您希望这更优雅,您可以使用函数式 API 模型,mask使用Input(tensor=mask). 不过,我不知道这样做是否有任何优势。


推荐阅读