Keras: Visualizing weights and convolutions

Created on 23 Jul 2015  Â·  53Comments  Â·  Source: keras-team/keras

Hi,
Looking at this Torch tutorial:
http://code.madbits.com/wiki/doku.php?id=tutorial_basics

A Spatial Convolution layer is generated, and its weights are visualized,
then Lena's image is forwarded through the layer and the resulting images are visualized.

It would be nice if Keras would support the visualization of both things (aka include the visualization in its tutorials).

Most helpful comment

I have a notebook based on keras' CNN example on MNIST that has example code to show the convolution and weights :
https://github.com/julienr/ipynb_playground/blob/master/keras/convmnist/keras_cnn_mnist.ipynb

You cannot call l.activation directly, you have to first have Theano compile the expression. For example :

model = Sequential()

model.add(Convolution2D(32, 1, 3, 3, border_mode='full')) 
convout1 = Activation('relu')
model.add(convout1)

convout1_f = theano.function([model.get_input(train=False)], convout1.get_output(train=False))

And then you can call convout1_f on an image and get your result.

All 53 comments

In particular, I'd expect to see the different versions of the picture after each of the convolutions have been applied. The following code, when executed in IPython Notebook, will display an image but not the convolutions over it.

from keras.datasets import mnist
from matplotlib.pyplot import imshow

(X_train, y_train), (X_test, y_test) = mnist.load_data()
inpic = X_train[0][0]

%matplotlib inline
imshow(X_train[0][0]) #shows the first image in the mnist dataset.

from keras.layers.convolutional import Convolution2D
l = Convolution2D(32, 1, 3, 3, border_mode='full')
imshow(l.activation(inpic)) #l.activation returns inpic unchanged, so the image is showed again.

I have a notebook based on keras' CNN example on MNIST that has example code to show the convolution and weights :
https://github.com/julienr/ipynb_playground/blob/master/keras/convmnist/keras_cnn_mnist.ipynb

You cannot call l.activation directly, you have to first have Theano compile the expression. For example :

model = Sequential()

model.add(Convolution2D(32, 1, 3, 3, border_mode='full')) 
convout1 = Activation('relu')
model.add(convout1)

convout1_f = theano.function([model.get_input(train=False)], convout1.get_output(train=False))

And then you can call convout1_f on an image and get your result.

@julienr cool stuff!

Here's a fully working example based on @julienr 's comment - running this in IPython Notebook yields neat results:

# Imports
import matplotlib.pyplot as plt

import theano

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers.convolutional import Convolution2D
from keras.layers.core import Activation


# Model 
model = Sequential()

model.add(Convolution2D(28, 1, 3, 3, border_mode='full')) 
convout1 = Activation('relu')
model.add(convout1)


# Data loading + reshape to 4D
(X_train, y_train), (X_test, y_test) = mnist_dataset = mnist.load_data()
reshaped = X_train.reshape(X_train.shape[0], 1, X_train.shape[1], X_train.shape[2])


from random import randint
img_to_visualize = randint(0, len(X_train) - 1)


# Generate function to visualize first layer
convout1_f = theano.function([model.get_input(train=False)], convout1.get_output(train=False))
convolutions = convout1_f(reshaped[img_to_visualize: img_to_visualize+1])


%matplotlib inline
#The non-magical version of the previous line is this:
#get_ipython().magic(u'matplotlib inline')
imshow = plt.imshow #alias
plt.title("Image used: #%d (digit=%d)" % (img_to_visualize, y_train[img_to_visualize]))
imshow(X_train[img_to_visualize])


plt.title("First convolution:")
imshow(convolutions[0][0])


print "The second dimension tells us how many convolutions do we have: %s (%d convolutions)" % (
    str(convolutions.shape),
    convolutions.shape[1])


for i, convolution in enumerate(convolutions[0]):
    plt.figure()
    plt.title("Convolution %d" % (i))
    plt.imshow(convolution)

@guy4261 when runing the code i am getting this error " Exception: Layer is not connected and is not an input layer." can you please help ...

1

@erfannoury I'll have a look. I have keras 0.1.3 on my machine and I see that the latest version is 0.3.0. Can you please run the following cell to tell me your version?

! pip list | grep -i keras

@guy4261 I think I shouldn't have been mentioned. Anyway, I'm using the latest version of Keras (0.3.0).

This is possible with graphs as well, but graph.get_input() does not give a value suitable for theano.function. Instead you need to grab each input's get_input() result and use that instead. E.g.

    midout_fn = theano.function([graph.inputs['input1'].get_input(train=False),
                                 graph.inputs['input2'].get_input(train=False)],
                                midout.get_output(train=False))

where midout is equivalent of convout1 above.

Is there an easy way to do this with the tensorflow backend? or is making a new network with a different outputs

@kmader I think you should be able to replace theano.function with K.function (where K is the backend imported with from keras import backend as K). Haven't tested it though.

@julienr thanks, that is what I ended up doing and it works fine

@kallewoof @julienr @guy4261 ... I am getting following error for Sequential model.
Using keras 1.0.

convout1_f = theano.function([model.get_input()], convout1.get_output(train=False))

Error :
AttributeError: 'Sequential' object has no attribute 'get_input'

Same issue as saj1919. As soon as I upgraded to Keras 1.0 I started getting the error

AttributeError: 'Sequential' object has no attribute 'get_input'

I think you should use model.inputs instead of model.get_input() :

convout1_f = K.function(model.inputs, [convout1.output])

And later you have to call it with a list of inputs :

C1 = convout1_f([X])

Full working example with keras 1.0.1 :
https://github.com/julienr/ipynb_playground/blob/master/keras/convmnist/keras_cnn_mnist_v1.ipynb

Ok, now I'm getting a new error:

MissingInputError: ("An input of the graph, used to compute DimShuffle{x,x,x,x}(keras_learning_phase), was not provided and not given a value.Use the Theano flag exception_verbosity='high',for more information on this error.", keras_learning_phase)

The problem seems to be dropout. Dropout needs to know the learning phase because it has different behavior for train time vs test time. When I get rid of dropout in my model it works and when I add dropout to your (julienr) model before the layer we want output from I start getting the same error. How do we tell the backend function the learning phase?

Here, btw is how I modified julienr's model to get the error:

model = Sequential()

model.add(Convolution2D(32, 3, 3, border_mode='valid', input_shape=X_train.shape[1:]))
model.add(Dropout(0.01)) # This breaks it
convout1 = Activation('relu')
model.add(convout1)
model.add(Convolution2D(32, 3, 3))

@datamath28 You need to add K.learning_phase to the list of inputs and specify a value (0 to disable) for it. This is a boolean variable that's used by Dropout (and other train-only layers) to determine if they should have an effect.

I've pushed the fix to my notebook. You need to modify how you create the convout1_f function as follow:

# K.learning_phase() is a flag that indicates if the network is in training or
# predict phase. It allow layer (e.g. Dropout) to only be applied during training
inputs = [K.learning_phase()] + model.inputs

_convout1_f = K.function(inputs, [convout1.output])
def convout1_f(X):
    # The [0] is to disable the training phase flag
    return _convout1_f([0] + [X])

For reference, this is similar to what's done in engine/training.py. See here for how the dropout layers uses K.in_train_phase.

Hello,guys!
Now I wanna get the FC layer's feature datas and use it in SVM to be classified for 2 classes.Here is my main code:

  • from future import print_function
    import cPickle
    import theano
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.svm import SVC
    from sklearn.preprocessing import MinMaxScaler
    from luobindata8_18 import load_data
    import random

def svc(traindata,trainlabel,testdata,testlabel):
print("Start training SVM...")
svcClf = SVC(C=1.0,kernel="rbf",cache_size=900)
svcClf.fit(traindata,trainlabel)

pred_testlabel = svcClf.predict(testdata)
num = len(pred_testlabel)
accuracy = len([1 for i in range(num) if testlabel[i]==pred_testlabel[i]])/float(num)
print("cnn-svm Accuracy:",accuracy)

def rf(traindata,trainlabel,testdata,testlabel):
print("Start training Random Forest...")
rfClf = RandomForestClassifier(n_estimators=2,criterion='gini')
rfClf.fit(traindata,trainlabel)

pred_testlabel = rfClf.predict(testdata)
num = len(pred_testlabel)
accuracy = len([1 for i in range(num) if testlabel[i]==pred_testlabel[i]])/float(num)
print("cnn-rf Accuracy:",accuracy)

if name == "main":
#load data
data, label = load_data()
#shuffle the data
index = [i for i in range(len(data))]
random.shuffle(index)
data = data[index]
label = label[index]

(traindata,testdata) = (data[0:900],data[900:])
(trainlabel,testlabel) = (label[0:900],label[900:])
#use origin_model to predict testdata
origin_model = cPickle.load(open("model8.18.pkl","rb"))
#print(origin_model.layers)

pred_testlabel = origin_model.predict_classes(testdata)
#print(pred_testlabel)
num = len(testlabel)
accuracy = len([1 for i in range(num) if testlabel[i]==pred_testlabel[i]])/float(num)
print(" Origin_model Accuracy:",accuracy)
#define theano funtion to get output of FC layer
get_feature=    theano.function([origin_model.layers[0].input],origin_model.layers[13].output,allow_input_downcast=False)
feature = get_feature(data)
#train svm using FC-layer feature
scaler = MinMaxScaler()
feature = scaler.fit_transform(feature)
svc(feature[0:900],label[0:900],feature[900:],label[900:])
rf(feature[0:900],label[0:900],feature[900:],label[900:])
#

However,here is luobindata8_18 which used for load data from my pictures:

  • import os
    from PIL import Image
    import numpy as np
    def load_data():
    data = np.empty((1040,1,60,60),dtype="float32")
    label = np.empty((1040,),dtype="int")
    imgs = os.listdir("./sampleyingguang8.18")
    num = len(imgs)
    for i in range(num):
    img = Image.open("./sampleyingguang8.18/"+imgs[i])
    arr = np.asarray(img,dtype="float32")
    data[i,:,:,:] = arr
    if i<623:
    label[i] = int(0)
    else:
    label[i] = int(1)
    data /= np.max(data)
    data -= np.mean(data)
    return data,label
    ########################################
    That's all codes.Please neglect the 1040 sample number even though I really know it is too few for CNN but it is not the key making the error.When I run these codes,the error below happened:
  • MissingInputError: ("An input of the graph, used to compute DimShuffle{x,x,x,x}(keras_learning_phase), was not provided and not given a value.Use the Theano flag exception_verbosity='high',for more information on this error.", keras_learning_phase)
  • This error happened in :get_feature = theano.function([origin_model.layers[0].input],origin_model.layers[13].output,allow_input_downcast=False)
    #############################################
    I really don't know the reason as a Keras fish!

I also have tryed a solution below but it doesn't work:
from keras import backend as K

and then replace get_feature = theano.function([origin_model.layers[0].input],origin_model.layers[13].output,allow_input_downcast=False) with get_feature = K.function([origin_model.layers[0].input],origin_model.layers[13].output)

Sorry for my poor english and the wrong format of codes when uploading. @julienr @erfannoury @guy4261 @fchollet @ArkAlista

I haven't reminded the file of "model8.18.pkl".Actually it came from codes below:

from future import absolute_import
from future import print_function
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD,Adadelta
import keras.regularizers
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.preprocessing import MinMaxScaler
import theano

from keras.utils import np_utils, generic_utils

from six.moves import range
from luobindata8_18 import load_data
import random,cPickle
from keras.callbacks import EarlyStopping
import numpy as np

np.random.seed(1024)
data, label = load_data()

def create_model():
model = Sequential()
model.add(Convolution2D(32, 5, 5, border_mode='valid',input_shape=(1,60,60)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Convolution2D(32,3, 3, border_mode='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Convolution2D(64,3, 3, border_mode='valid')) 
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.3))
model.add(Dense(1))
model.add(Activation('sigmoid'))
return model
#

开始训练模型

#

model = create_model()

sgd = SGD(lr=0.001, decay=1e-8, momentum=0.9, nesterov=True)

model.compile(loss='binary_crossentropy', optimizer=sgd,metrics=["accuracy"])

sgd = SGD(lr=0.005, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd,metrics=["accuracy"])

adadelta=Adadelta(lr=1.0, rho=0.95, epsilon=1e-09)

model.compile(loss='mse', optimizer=adadelta,metrics=["accuracy"])

model.compile(loss="binary_crossentropy", optimizer=adadelta,metrics=["accuracy"])

index = [i for i in range(len(data))]
random.shuffle(index)
data = data[index]
label = labelindex = (data[0:900],data[900:])
(Y_train,Y_val) = (label[0:900],label[900:])

使用early stopping返回最佳epoch对应的model

early_stopping = EarlyStopping(monitor='val_loss', patience=1)

model.fit(X_train, Y_train,callbacks=[early_stopping])

model.fit(X_train, Y_train, batch_size=30,validation_data=(X_val, Y_val),nb_epoch=15,callbacks=[early_stopping])
pred_testlabel=model.predict_classes(X_val)

print('true test label:')

print(Y_val)

print('cnn test label:')

print(pre_label)

print('calculate stone and kuang accuracy:')
num=len(Y_val)
stonenum=0
for i in Y_val:
if i==0:
stonenum=stonenum+1
kuangnum=num-stonenum
cnnstone=0
for i in range(num):
if Y_val[i]==pred_testlabel[i] and Y_val[i]==0:
cnnstone=cnnstone+1
stoneaccuracy=float(cnnstone)/float(stonenum)
print(stoneaccuracy)

cnnkuang=0
for i in range(num):
if Y_val[i]==pred_testlabel[i] and Y_val[i]==1:
cnnkuang=cnnkuang+1
kuangaccuracy=float(cnnkuang)/float(kuangnum)
print(kuangaccuracy)

cPickle.dump(model,open("./model8.18.pkl","wb"))

@tangjie77wd You need to add K.learning_phase() to the list of inputs when creating your K.function as explained in my comment.

So something like

K.function([K.learning_phase(), origin_model.layers[0].input],origin_model.layers[13].output)

Also, you should put your code into ``` blocks to have nice formatting.

@julienr Thanks for your comment.I have run it again after changed like this:get_feature = K.function([K.learning_phase(), origin_model.layers[0].input],origin_model.layers[13].output),but I got the same error.
`
File "E:/Keras_Code/luobin_cnn-svm8.18.py", line 59, in
get_feature = K.function([K.learning_phase(), origin_model.layers[0].input],origin_model.layers[13].output)

File "C:\Anaconda2\lib\site-packages\keras\backend\theano_backend.py", line 572, in function
return Function(inputs, outputs, updates=updates, **kwargs)

File "C:\Anaconda2\lib\site-packages\keras\backend\theano_backend.py", line 558, in init
**kwargs)

File "C:\Anaconda2\lib\site-packages\theano\compile\function.py", line 320, in function
output_keys=output_keys)

File "C:\Anaconda2\lib\site-packages\theano\compile\pfunc.py", line 479, in pfunc
output_keys=output_keys)

File "C:\Anaconda2\lib\site-packages\theano\compile\function_module.py", line 1776, in orig_function
output_keys=output_keys).create(

File "C:\Anaconda2\lib\site-packages\theano\compile\function_module.py", line 1428, in init
accept_inplace)

File "C:\Anaconda2\lib\site-packages\theano\compile\function_module.py", line 177, in std_fgraph
update_mapping=update_mapping)

File "C:\Anaconda2\lib\site-packages\theano\gof\fg.py", line 171, in init
self.import_r(output, reason="init")

File "C:\Anaconda2\lib\site-packages\theano\gof\fg.py", line 360, in import_r
self.import(variable.owner, reason=reason)

File "C:\Anaconda2\lib\site-packages\theano\gof\fg.py", line 474, in import
r)

MissingInputError: ("An input of the graph, used to compute DimShuffle{x,x,x,x}(keras_learning_phase), was not provided and not given a value.Use the Theano flag exception_verbosity='high',for more information on this error.", keras_learning_phase)`

@tangjie77wd It might have something to do with the use of cPickle. Maybe try running compile on your model after you have loaded it. Or try with model.save or model.to_json.

The following works for me (keras master) - this is a minimal example based on your code

import os
os.environ['KERAS_BACKEND'] = 'theano'

from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD

model = Sequential()
model.add(Convolution2D(32, 5, 5, border_mode='valid', input_shape=(1,60,60))) 
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.3))
model.add(Dense(1))
model.add(Activation('sigmoid'))

sgd = SGD(lr=0.005, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=["accuracy"])

import keras.backend as K
f = K.function([K.learning_phase(), model.layers[0].input], [model.layers[4].output])

Maybe you want to try AETROS which visualises weights and convolutional layer out of the box using a simple callback/hook. https://youtu.be/_HsuYywGmXA?t=127,

@julienr @marcj Thank you! Well,I think i have known the reason which caused the error below in theano.function() or K.function().
MissingInputError: ("An input of the graph, used to compute DimShuffle{x,x,x,x}(keras_learning_phase), was not provided and not given a value.Use the Theano flag exception_verbosity='high',for more information on this error.", keras_learning_phase)
I think the key cause error is this sentence:origin_model = cPickle.load(open("model8.18.pkl","rb")).Maybe we shouldn't load a model by 'rb' but '.json'' if we wanna get the FC layer's feature.However,I run the codes to create model again and then save it as '.json'' like the following:
json_string = model.to_json()
open('savemodel8.20.json','w').write(json_string)
model.save_weights('savemodel_weights8.20.h5')
After that,i create another '.py' to load it as the following shows:
if name == "main":
data, label = load_data()
index = [i for i in range(len(data))]
random.shuffle(index)
data = data[index]
label = labelindex = (data[0:900],data[900:])
(trainlabel,testlabel) = (label[0:900],label[900:])
origin_model = model_from_json(open('savemodel8.20.json').read())
origin_model.load_weights('savemodel_weights8.20.h5')
pred_testlabel = origin_model.predict_classes(testdata,batch_size=1, verbose=1)
num = len(testlabel)
accuracy = len([1 for i in range(num) if testlabel[i]==pred_testlabel[i]])/float(num)
print(" Origin_model Accuracy:",accuracy)
import keras.backend as K
f = K.function([K.learning_phase(), origin_model.layers[0].input], [origin_model.layers[13].output])
Guess what?It does work now!It doesn't show any error in K.function() now!

However,as you know,i wanna get the feature of data after Flatten layer finally,so when i run like below:
f = K.function([K.learning_phase(), origin_model.layers[0].input], [origin_model.layers[13].output])
feature=f(data)
It shows error as the following shows:

File "E:/Keras_Code/luobin_cnn-svm8.18.py", line 79, in
feature=f(data)

File "C:\Anaconda2\lib\site-packages\keras\backend\theano_backend.py", line 561, in call
assert type(inputs) in {list, tuple}
Aha,'feature=f(data)' causes the error again!I am wandering if the shape of data is conflict with the origin_model.layer[0].input.

Oh,I changed 'feature=f(data)' into 'feature=f([data])'.Now the error is:
TypeError: ('Bad input argument to theano function with name "C:\Anaconda2\lib\site-packages\keras\backend\theano_backend.py:558" at index 0(0-based)', 'Wrong number of dimensions: expected 0, got 4 with shape (1040L, 1L, 60L, 60L).')
Do you remember my model:
def create_model():
model = Sequential()
model.add(Convolution2D(32, 5, 5, border_mode='valid',input_shape=(1,60,60)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Convolution2D(32,3, 3, border_mode='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Convolution2D(64,3, 3, border_mode='valid')) 
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.3))
model.add(Dense(1))
model.add(Activation('sigmoid'))
return model
#

The model need the input shape is (1,60,60),isn't it?And now,in this sentence: feature=f([data]),the data shape is (1040L, 1L, 60L, 60L),so i think it isn't conflict!Anyway,the error says:TypeError: ('Bad input argument to theano function with name "C:\Anaconda2\lib\site-packages\keras\backend\theano_backend.py:558" at index 0(0-based)', 'Wrong number of dimensions: expected 0??????What does it mean that it expects 0?Why not expect (1L, 60L, 60L)?

hi @kallewoof ,I use the graph model.
like this,

model = graph()
model.add_input(name='input0',input_shape=())
model.add_node(Convolution2D(),name='c1',input='input0')
.......

And i want to see the output of the c1,Then

getFeatureMap = theano.function(model.inputs['input0'].input,model.nodes['c1'].get_output(train=False),
allow_input_downcast=True)

But it show me that
TypeError: list indices must be integers, not str

Do you give me some advices? Thanks.

Unfortunately I haven't used Keras for some time, but hopefully someone else can help out!

hi @julienr ,i use the graph model ,refer to #41
like this,

model = graph()
model.add_input(name='input0',input_shape=())
model.add_node(Convolution2D(),name='c1',input='input0')
.......

And i want to see the output of the c1,Then

getFeatureMap = theano.function(model.inputs['input0'].input,model.nodes['c1'].get_output(train=False),
allow_input_downcast=True)

But it show me that
TypeError: list indices must be integers, not str

Do you give me some advices? Thanks.

hi @saj1919 ,i use the graph model ,refer to #41
like this,

model = graph()
model.add_input(name='input0',input_shape=())
model.add_node(Convolution2D(),name='c1',input='input0')
.......

And i want to see the output of the c1,Then

getFeatureMap = theano.function(model.inputs['input0'].input,model.nodes['c1'].get_output(train=False),
allow_input_downcast=True)

But it show me that
TypeError: list indices must be integers, not str

Do you give me some advices? Thanks.

hi @guy4261 ,i use the graph model ,refer to #41 and my keras is 1.0.3
like this,

model = graph()
model.add_input(name='input0',input_shape=())
model.add_node(Convolution2D(),name='c1',input='input0')
.......

And i want to see the output of the c1,Then

getFeatureMap = theano.function(model.inputs['input0'].input,model.nodes['c1'].get_output(train=False),
allow_input_downcast=True)

But it show me that
TypeError: list indices must be integers, not str

Do you give me some advices? Thanks.

@julienr
I tried your code:

inputs = [theano.learning_phase()] + model.inputs
convout1_f = theano.function(inputs, convout1.get_output(train=False))

but I got the error:

AttributeError: 'module' object has no attribute 'learning_phase'

Do you perhaps know why I got this error? Thank you.

@matchifang This is because learning_phase is in keras.backend, not in theano.

import keras.backend as K
inputs = [K.learning_phase()] + model.inputs
convout1_f = K.function(inputs, convout1.get_output(train=False))

Hi @julienr , I'm trying to implement your code (https://github.com/julienr/ipynb_playground/blob/master/keras/convmnist/keras_cnn_mnist_v1.ipynb) and apply it to obtain the featrures maps of a CNN. I'm loading a model I've previously trained. I get the following error with this code:

import os
os.environ['THEANO_FLAGS']='mode=FAST_RUN,device=gpu,floatX=float32'
# This gives a 'perform' error in compile
#os.environ['THEANO_FLAGS']='mode=FAST_COMPILE,device=gpu1,floatX=float32'
#os.environ['THEANO_FLAGS']='device=gpu0'
import pylab as pl
import matplotlib.cm as cm
import numpy as np
from keras.layers import Activation
from keras.models import load_model
from keras import backend as K

model = load_model('model.149-0.18.hdf5')
X_test = np.load('test_X_1inP.npy')
convout1 = Activation('relu')
inputs = [K.learning_phase()] + model.inputs

_convout1_f = K.function(inputs, [convout1.output])
def convout1_f(X):
    # The [0] is to disable the training phase flag
    return _convout1_f([0] + [X])

Traceback (most recent call last):

  File "<ipython-input-25-8723074daa75>", line 3, in <module>
    _convout1_f = K.function(inputs, [convout1.output])

  File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 776, in output
    'hence the notion of "layer output" '

Exception: Layer activation_2 has multiple inbound nodes, hence the notion of "layer output" is ill-defined. Use `get_output_at(node_index)` instead.

Is your code working for any loaded model?
Thank you very much.

@Mako18 I'm note sure what's the problem. Can you try using convout1.get_output_at(0) instead of convout1.output as the error message suggets ?

Hi, @julienr I have tried also that, but it gives me another error:

Traceback (most recent call last):

  File "<ipython-input-33-4c9014fadc67>", line 1, in <module>
    _convout1_f = K.function(inputs, [convout1.get_output_at(0)])

  File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 674, in get_output_at
    'output')

  File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 636, in _get_node_attribute_at_index
    'and thus has no defined ' + attr_name + '.')

Exception: The layer has never been called and thus has no defined output.

Then I tried to apply the code to a model I trained in that moment and the error was other. The issue is that I am interested in apply it to a loaded model, previously trained. I guess I am missing something, sorry if it is too dumb, but I am relatively new to Keras and Python. Thanks.

@Mako18 I'm not sure where this error comes from. Does calling model.compile solve the problem ?

@julienr It doesn't, I tried compiling the model before the line _convout1_f = K.function(inputs, [convout1.get_output_at(0)]) and I'm not sure about how can I fix it.

How to plot convolution 1d weights with 64 filters

@Mako18 you are not using the Activation layer from your loaded model but creating a new one with convout1 = Activation('relu').

Instead try this code:

model = load_model('model.149-0.18.hdf5')
layer_idx = [idx for idx, layer in enumerate(model.layers) if layer.name == 'convolution2d_1'][0]
convout1 = model.layers[layer_idx]

You may have to replace convolution2d_1 with the name of your first conv layer.

Hi @xge, in that case I get another error, although it make sense your code. My inputs are three separated images, each one with 2 channels, so the input of my network is [XL, XR, XF], where each structure has dimensions (2100, 2, 10, 8). The error I get in this case is:

Traceback (most recent call last):

  File "<ipython-input-43-9b29e8db04b3>", line 1, in <module>
    W = model.layers[0].W.get_value(borrow=True)

AttributeError: 'Merge' object has no attribute 'W'

After the code

# Visualize weights
W = model.layers[0].W.get_value(borrow=True)
W = np.squeeze(W)
print("W shape : ", W.shape)

pl.figure(figsize=(15, 15))
pl.title('conv1 weights')
nice_imshow(pl.gca(), make_mosaic(W, 6, 6), cmap=cm.binary)

Also in order to get the code working I had to set X=X_test[i:i+1, 1, :, :] when trying to visualize the first layer of convolutions on an input image, but couldn't introduce the two channels of my input.

@tangjie77wd @julienr did you solve your error problem. i am using same model with keras and got same error during feature extraction.
can you tell how can solve this problem

@tangjie77wd you can try this
def get_activations(model, layer, X):
get_activations = K.function([model.layers[0].input, K.learning_phase()], [model.layers[9].output,])
activations = get_activations([X,0])
return activations

@myk1603 great, thanks!

Visualizing the average activation values of the input features and Saliency map for a chosen sample

my network is given below

  1. define the network

model = Sequential()
model.add(LSTM(4,input_dim=42)) # try using a GRU instead, for fun
model.add(Dropout(0.1))
model.add(Dense(5))
model.add(Activation('softmax'))

Taylor expansion and compute first partial derivative of the classification results

from keras import backend as K
import theano
def compile_saliency_function(model):
"""
Compiles a function to compute the saliency maps and predicted classes
for a given minibatch of input images.
"""
inp = model.layers[0].input
print("-----------------------input-----------------------------")
print(inp)
outp = model.layers[-1].output
print("-----------------------output----------------------------")
print(outp)
max_outp = K.T.max(outp, axis=1)
print(max_outp)
saliency = K.gradients(K.sum(max_outp), inp)
print(saliency)
max_class = K.T.argmax(outp, axis=1)
print(max_class)
v1 = K.function([inp, K.learning_phase()], [saliency, max_class])
return v1

print(([X_train[:20], 0])[0])
v = compile_saliency_function(model)([X_train[:5], 0])[0]
print(v)

Sailnce map gives
[[[ -8.015e-29 6.428e-28 -1.365e-29 3.198e-30 -1.229e-29 -2.009e-30
-1.273e-30 -2.512e-29 -6.153e-28 3.688e-29 2.205e-28 4.094e-28
5.667e-28 -1.401e-27 1.892e-28 5.810e-30 1.736e-29 7.379e-29
-2.122e-28 8.063e-29 3.660e-31 1.458e-31 9.196e-28 -1.335e-30
1.608e-30 -8.264e-29 -1.094e-28 1.099e-29 6.411e-30 1.134e-28
3.281e-29 3.869e-29 -1.276e-30 -9.509e-31 8.313e-29 4.073e-29
-8.345e-30 3.455e-29 -1.100e-28 -8.354e-29 -5.175e-29 1.583e-29]]

[[ -8.015e-29 6.428e-28 -1.365e-29 3.198e-30 -1.229e-29 -2.009e-30
-1.273e-30 -2.512e-29 -6.153e-28 3.688e-29 2.205e-28 4.094e-28
5.667e-28 -1.401e-27 1.892e-28 5.810e-30 1.736e-29 7.379e-29
-2.122e-28 8.063e-29 3.660e-31 1.458e-31 9.196e-28 -1.335e-30
1.608e-30 -8.264e-29 -1.094e-28 1.099e-29 6.411e-30 1.134e-28
3.281e-29 3.869e-29 -1.276e-30 -9.509e-31 8.313e-29 4.073e-29
-8.345e-30 3.455e-29 -1.100e-28 -8.354e-29 -5.175e-29 1.583e-29]]

[[ -8.015e-29 6.428e-28 -1.365e-29 3.198e-30 -1.229e-29 -2.009e-30
-1.273e-30 -2.512e-29 -6.153e-28 3.688e-29 2.205e-28 4.094e-28
5.667e-28 -1.401e-27 1.892e-28 5.810e-30 1.736e-29 7.379e-29
-2.122e-28 8.063e-29 3.660e-31 1.458e-31 9.196e-28 -1.335e-30
1.608e-30 -8.264e-29 -1.094e-28 1.099e-29 6.411e-30 1.134e-28
3.281e-29 3.869e-29 -1.276e-30 -9.509e-31 8.313e-29 4.073e-29
-8.345e-30 3.455e-29 -1.100e-28 -8.354e-29 -5.175e-29 1.583e-29]]

[[ -1.190e-28 7.039e-28 -3.475e-30 3.815e-30 -1.410e-29 -2.210e-30
-1.390e-30 -3.224e-29 -7.007e-28 3.122e-29 2.429e-28 4.564e-28
6.228e-28 -1.537e-27 1.703e-28 1.865e-29 1.983e-29 7.343e-29
-2.412e-28 7.795e-29 3.947e-31 1.972e-31 9.979e-28 -1.683e-30
1.429e-30 -1.043e-28 -1.336e-28 1.509e-29 6.298e-30 1.371e-28
4.295e-29 7.593e-29 -1.360e-30 -5.704e-31 9.312e-29 8.257e-29
-3.896e-30 4.088e-29 -1.375e-28 -1.039e-28 -6.191e-29 1.965e-29]]

[[ -1.188e-28 7.032e-28 -3.503e-30 3.810e-30 -1.408e-29 -2.208e-30
-1.388e-30 -3.220e-29 -6.999e-28 3.121e-29 2.427e-28 4.559e-28
6.221e-28 -1.535e-27 1.702e-28 1.860e-29 1.980e-29 7.337e-29
-2.409e-28 7.790e-29 3.943e-31 1.969e-31 9.969e-28 -1.681e-30
1.429e-30 -1.042e-28 -1.334e-28 1.507e-29 6.294e-30 1.369e-28
4.289e-29 7.576e-29 -1.359e-30 -5.711e-31 9.302e-29 8.237e-29
-3.906e-30 4.083e-29 -1.373e-28 -1.038e-28 -6.183e-29 1.962e-29]]]

Visualizing the average activation values of the input features for 5 samples of class 0

def get_activations(model, layer, X_batch):
get_activations = K.function([model.layers[0].input, K.learning_phase()], model.layers[layer].output)
activations = get_activations([X_batch,0])
return activations
my_featuremaps = get_activations(model, 0, ([X_train[:5], 0])[0])
print(my_featuremaps)
np.savetxt('featuremap', my_featuremaps)

activation values
[[ 0.762 -0.122 0.044 -0.758]
[ 0.762 -0.122 0.044 -0.758]
[ 0.762 -0.122 0.044 -0.758]
[ 0.762 -0.038 0.043 -0.752]
[ 0.762 -0.038 0.043 -0.752]
[ 0.762 -0.038 0.043 -0.752]
[ 0.125 -0. 0.038 -0.083]
[ 0.762 -0.121 0.044 -0.758]
[ 0.762 -0.038 0.043 -0.752]
[ 0.762 -0.433 0.091 -0.755]]

Could you please tell that the followed methid is correct if So could you please tell how to generate the plots fig 3 fig 6 of the paper titled "Empowering Convolutional Networks for Malware
Classification and Analysis"

Hello @julienr @johnny5550822 @tangjie77wd
data input for CNN
X_train = (2012L, 3L, 200L, 200L)
Y_train = (2012L, 2L) #label after encoding for CNN

Store features after CNN training

get_activations = K.function([model.layers[0].input, K.learning_phase()], [model.layers[9].output,])
feature = get_activations([X_train,0])

Now I have feature vector

features = float (2012L, 128L)

y_train = (2012L,)

I want to use this feature vector with SVM anyone can help me?

currently, I am trying this code

svcClf = SVC(C=1.0,kernel="rbf",cache_size=975)
scaler = MinMaxScaler() #transform features by scaling each features to a given range
feature = scaler.fit_transform(feature)
svcClf.fit(feature, y_train)

But I got error

with scaler
ValueError: Found array with dim 3. MinMaxScaler expected <= 2.
Without scaler
ValueError: Found array with dim 3. Estimator expected <= 2

Hi, @julienr I have solved the errors I had, so now I am able to visualize the weights of my last convolutional layer, but not the convolutions. It gives me this error:

  File "C:\Users\Macarena\Anaconda2\lib\site-packages\theano\compile\function_module.py", line 845, in __call__
    self.inv_finder[c]))

TypeError: Missing required input: convolution2d_input_20

My model start with three different networks each one with a convolutional layer (starting with convolution2d_21). After that convolution I apply a Merge layer and after that a convolutional layer (the last one, convolution2d_24). One of my problems is that I am not able to set the first convolutional layer (of one of the three starting branches) as convout1, I would like to solve that. Also, my model takes as inputs three different images of two channels with 10x8 dimension, so the input structure is (nb_samples, 3L, 2L, 10L, 8L), how can I modify the convout1_f definition to work with this case?

@Mako18 It's hard to tell without code to test. I think convout1_f should be a function taking 3 inputs (which are the 3 inputs to your top-level networks).

Can you provide a minimal example of the network construction and visualization that reproduces the problem ?

More generally you can visualise the output/activations of every layer of your model. I wrote an example with MNIST to show how here:

https://github.com/philipperemy/keras-visualize-activations

So far it's the least painful I've seen.

@philipperemy Thank you for the awesome get_activations function. I would like to post it here for people who just want a copy paste implementation. It would be great to have this as a functionality in Keras ! If someone from the Keras is willing to review, I am ready to work on this, write the necessary documentation, tests etc to add this.

def get_activations(model, model_inputs, print_shape_only=True, layer_name=None):
    import keras.backend as K
    print('----- activations -----')
    activations = []
    inp = model.input

    model_multi_inputs_cond = True
    if not isinstance(inp, list):
        # only one input! let's wrap it in a list.
        inp = [inp]
        model_multi_inputs_cond = False

    outputs = [layer.output for layer in model.layers if
               layer.name == layer_name or layer_name is None]  # all layer outputs

    funcs = [K.function(inp + [K.learning_phase()], [out]) for out in outputs]  # evaluation functions

    if model_multi_inputs_cond:
        list_inputs = []
        list_inputs.extend(model_inputs)
        list_inputs.append(1.)
    else:
        list_inputs = [model_inputs, 1.]

    # Learning phase. 1 = Test mode (no dropout or batch normalization)
    # layer_outputs = [func([model_inputs, 1.])[0] for func in funcs]
    layer_outputs = [func(list_inputs)[0] for func in funcs]
    for layer_activations in layer_outputs:
        activations.append(layer_activations)
        if print_shape_only:
            print(layer_activations.shape)
        else:
            print(layer_activations)
    return activations

# activations = get_activations(model, X_test)
# print(activations[0])

@sahmed95 @philipperemy
Thanks a lot for sharing!
One simple issue,
# Learning phase. 1 = Test mode (no dropout or batch normalization)
However, I found in Keras (2.0.2)
` The learning phase flag is a bool tensor (0 = test, 1 = train)

`
And in practice I set the flag to 0 will get same output for same samples.

@zhhongzhi good catch! Maybe I did a mistake there.

I didn't test it for dropout or batch normalization so the result was always the same.

Please open a PR at:

https://github.com/philipperemy/keras-visualize-activations

Thanks a lot!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

somewacko picture somewacko  Â·  3Comments

kylemcdonald picture kylemcdonald  Â·  3Comments

vinayakumarr picture vinayakumarr  Â·  3Comments

amityaffliction picture amityaffliction  Â·  3Comments

nryant picture nryant  Â·  3Comments