Как отключить отдельные нейроны в полностью подключенной сети с одним скрытым слоем - PullRequest
0 голосов
/ 24 апреля 2018

У меня есть простая модель, обученная на 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.

Каков наилучший способ сделать это?

Есть ли у нас еще один узел из входных данных с весами ВНИЗ скрытого слоя -100000000, чтобы он подавлял все, что обычно происходит при активации (а остальное сделает relu). Это похоже на динамический взлом предвзятости.

Создаем ли мы еще один скрытый слой, где каждый из 600 узлов напрямую связан ровно с одним узлом из первого скрытого слоя (самого себя) с динамическим весом 0 (выкл) или 1 (продолжить как обычно), а затем полностью подключить этот новый скрытый слой к выходу?

Оба они кажутся немного хакерскими, они хотели знать, что думают другие.

1 Ответ

0 голосов
/ 24 апреля 2018

Я думаю, что лучший способ - нанести лямбда-слой с маской после этого плотного слоя.

Нет способа сделать это без небольшого взлома, но это довольно чистый взлом.

Создайте переменную для маски:

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

Добавьтелямбда-слой в модели:

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

Если вы хотите, чтобы это было более элегантно, вы можете использовать функциональную модель API, сделав mask один дополнительный вход с Input(tensor=mask).Я не знаю, есть ли какое-то преимущество в этом, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...