class_docstr: The ExpertGate algorithm is a dynamic architecture algorithm.
  For every new task, it trains an autoencoder to reconstruct input data
  and then trains an AlexNet classifier. Prior to AlexNet training,
  the algorithm searches through existing autoencoders, if there are any,
  to find the most related autoencoder and select the expert associated
  to that autoencoder. The new expert is then fine-tuned or trained using
  Learning without Forgetting (LwF) based on the most related previous expert.
class_docstr_tok: ["The","ExpertGate","algorithm","is","a","dynamic","architecture","algorithm",".","For","every","new","task",",","it","trains","an","autoencoder","to","reconstruct","input","data","and","then","trains","an","AlexNet","classifier",".","Prior","to","AlexNet","training",",","the","algorithm","searches","through","existing","autoencoders",",","if","there","are","any",",","to","find","the","most","related","autoencoder","and","select","the","expert","associated","to","that","autoencoder",".","The","new","expert","is","then","fine-tuned","or","trained","using","Learning","without","Forgetting","(","LwF",")","based","on","the","most","related","previous","expert","."]
code: def before_training_exp(
      self, strategy: "SupervisedTemplate", *args, **kwargs
  ):
      super().before_training_exp(strategy, *args, **kwargs)
  
      # Store task label for easy access
      task_label = strategy.experience.task_label
  
      # Build an autoencoder for this experience and
      # store it in a dictionary
      autoencoder = self._add_autoencoder(strategy, task_label)
  
      # Train the autoencoder on current experience
      self._train_autoencoder(strategy, autoencoder)
  
      # If experts exist, build new expert with feature extraction
      # from the most related existing expert
      new_expert, relatedness = self._select_expert(
          strategy, task_label
      )
  
      # Store the new expert in dictionary
      self._add_expert(strategy, task_label, new_expert)
  
      # Set the correct expert to be trained
      strategy.model.expert = new_expert
  
      # Reset the optimizer for the new expert model
      # reset_optimizer(strategy.optimizer, strategy.model.expert)
      # make_optimizer should be called instead of reset_optimizer
      # It puts all parameters from strategy.model in the optimizer
      # To freeze parameters use param.requires_grad = False
      # and param.grad = None
      strategy.make_optimizer(**kwargs)
  
      # Remove LwF plugin in case it is not needed
      if self.lwf_plugin in strategy.plugins:
          strategy.plugins.remove(self.lwf_plugin)
  
      print("\nTRAINING EXPERT")
      # If needed, add a new instance of LwF plugin back
      if relatedness > strategy.rel_thresh:
          print("WITH LWF")
          self.lwf_plugin = LwFPlugin(self.alpha, self.temp)
          strategy.plugins.append(self.lwf_plugin)
  
imports: from collections import OrderedDict
  import warnings
  import torch
  from torch.nn import Module, CrossEntropyLoss
  from torch.optim import Optimizer, SGD, Adam
  from torch.nn.functional import log_softmax
  from typing import Optional, List
  from avalanche.models.expert_gate import ExpertAutoencoder, ExpertModel, ExpertGate
  from avalanche.models.dynamic_optimizers import reset_optimizer
  from avalanche.training.supervised import AETraining
  from avalanche.training.templates import SupervisedTemplate
  from avalanche.training.plugins import SupervisedPlugin, EvaluationPlugin, LwFPlugin
  from avalanche.training.plugins.evaluation import default_evaluator
label_desc: Use image node_id 2 for calling the _ExpertGatePlugin obj's underlying member method code with example usage: obj.before_training_exp(strategy) without return types