albermax / innvestigate

A toolbox to iNNvestigate neural networks' predictions!
Other
1.25k stars 233 forks source link

Saving and loading trained PatternNet Analyzer for multiple reuse #188

Closed elboyran closed 4 years ago

elboyran commented 4 years ago

This issue is similar to #155 , but the comments there did not help, therefore I open a new issue.

I am very glad that this toolbox exists! Currently trying to perform some simple experiments using it.

I'm especially interested in attribution methods, such as PatternNet etc. Training the PatterNet analyzer, every time, however, is time wasting and does not make much sense. Therefore I used the save_npz and load_npz functionality provided (on many analyzers). However, only very few analyzers are working again after loading and unfortunately the PatternNet does not work.

An example notebook which works just fine with training (the first time) the analyzer can be found here.

If I want, however, to run the notebook again by loading the trained analyzer, it does not work. Below are the errors I'm getting while running the last cell of the Notebook above (on Ubuntu 18.04 VM):

Analyzer exists. Loading...


TypeError Traceback (most recent call last)

in 28 analysis = PatternNet_analyzer.analyze(image, neuron_index) 29 """ ---> 30 analysis = PatternNet_analyzer.analyze(image) 31 # Displaying the gradient 32 plt.imshow(analysis.squeeze(), cmap='seismic', interpolation='nearest') ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/base.py in analyze(self, X, neuron_selection) 473 """ 474 if not hasattr(self, "_analyzer_model"): --> 475 self.create_analyzer_model() 476 477 X = iutils.to_list(X) ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/base.py in create_analyzer_model(self) 411 412 tmp = self._create_analysis( --> 413 model, stop_analysis_at_tensors=stop_analysis_at_tensors) 414 if isinstance(tmp, tuple): 415 if len(tmp) == 3: ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/pattern_based.py in _create_analysis(self, *args, **kwargs) 201 ) 202 --> 203 return super(PatternNet, self)._create_analysis(*args, **kwargs) 204 205 def _fit_generator(self, ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/base.py in _create_analysis(self, model, stop_analysis_at_tensors) 711 model, 712 stop_analysis_at_tensors=stop_analysis_at_tensors, --> 713 return_all_reversed_tensors=return_all_reversed_tensors) 714 715 if return_all_reversed_tensors: ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/base.py in _reverse_model(self, model, stop_analysis_at_tensors, return_all_reversed_tensors) 700 clip_all_reversed_tensors=self._reverse_clip_values, 701 project_bottleneck_tensors=self._reverse_project_bottleneck_layers, --> 702 return_all_reversed_tensors=return_all_reversed_tensors) 703 704 def _create_analysis(self, model, stop_analysis_at_tensors=[]): ~/anaconda3/lib/python3.6/site-packages/innvestigate/utils/keras/graph.py in reverse_model(model, reverse_mappings, default_reverse_mapping, head_mapping, stop_mapping_at_tensors, verbose, return_all_reversed_tensors, clip_all_reversed_tensors, project_bottleneck_tensors, execution_trace, reapply_on_copied_layers) 972 { 973 "model": model, --> 974 "layer": layer, 975 } 976 ) ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/pattern_based.py in create_kernel_layer_mapping(layer, state) 191 # Apply the pattern mapping on all layers that contain a kernel. 192 def create_kernel_layer_mapping(layer, state): --> 193 pattern = self._get_pattern_for_layer(layer, state) 194 pattern = self._prepare_pattern(layer, state, pattern) 195 mapping_obj = PatternNetReverseKernelLayer(layer, state, pattern) ~/anaconda3/lib/python3.6/site-packages/innvestigate/analyzer/pattern_based.py in _get_pattern_for_layer(self, layer, state) 181 if kchecks.contains_kernel(l)] 182 --> 183 return self._patterns[layers.index(layer)] 184 185 def _prepare_pattern(self, layer, state, pattern): TypeError: 'NoneType' object is not subscriptable

It seems like the PaterNet analyzer is not constructed properly after loading, but I find hard to debug. It seems the state and name are loaded properly after load_npz, but later something gets messed up maybe by creating a new analyzer to be filled with the pre-trained weights.

Is this code then the correct use of your toolbox for reusing a per-trained analyzer?

PatternNet_analyzer = innvestigate.create_analyzer("pattern.net", model_wo_sm, pattern_type = "relu")

if os.path.isfile(fname):
    print("Analyzer exists. Loading...")
    PatternNet_analyzer.load_npz(fname)
else:
    print("Analyzer doesn't exist. Training and [Saving]...")
    # Some analyzers require training.
    PatternNet_analyzer.fit(images_train, batch_size=200, verbose=1)
    PatternNet_analyzer.save_npz(fname)

analysis = PatternNet_analyzer.analyze(image)
plt.imshow(analysis.squeeze(), cmap='seismic', interpolation='nearest')
plt.show()

The problem is even bigger- only for very few of all supported methods it is possible to save the analyzer and reuse it later again. Cell 8 of this notebook lists in the comments some of the problems I've encountered with saving and loading.

@albermax , @sebastian-lapuschkin , I would appreciate a lot if you can help me with the issue!

elboyran commented 4 years ago

Finally I have figured it out- I have been using the loading from file method wrongly! The correct way is: PatternNet_analyzer = PatternNet_analyzer.load_npz(fname)

Would have been nice and very useful for the practical usage to have such example in the notebooks!