prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  LWF "warmup_train" fun never used
  Hi @AntonioCarta, I've noticed this function in the `LearningWithoutForgetting` class is never used, do we need it?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `avalanche/training/strategies/lwf/lwf.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 
  4 ################################################################################
  5 # Copyright (c) 2020 ContinualAI Research                                      #
  6 # Copyrights licensed under the CC BY 4.0 License.                             #
  7 # See the accompanying LICENSE file for terms.                                 #
  8 #                                                                              #
  9 # Date: 1-05-2020                                                              #
  10 # Author(s): ContinualAI                                                       #
  11 # E-mail: contact@continualai.org                                              #
  12 # Website: clair.continualai.org                                               #
  13 ################################################################################
  14 
  15 """ Rehearsal Strategy Implementation """
  16 
  17 # Python 2-3 compatible
  18 from __future__ import print_function
  19 from __future__ import division
  20 from __future__ import absolute_import
  21 
  22 from training.strategies.strategy import Strategy
  23 from avalanche.evaluation.eval_protocol import EvalProtocol
  24 from avalanche.evaluation.metrics import ACC
  25 from avalanche.training.utils import pad_data, shuffle_in_unison
  26 import torch
  27 import torch.nn.functional as F
  28 import numpy as np
  29 import copy
  30 
  31 
  32 def distillation_loss(y_pred, y_teacher, temperature):
  33     """ Distillation loss. """
  34     scale = y_teacher.shape[-1]  # kl_div is normalized by element instead of observation
  35     log_p = F.log_softmax(y_pred / temperature, dim=1)
  36     q = F.softmax(y_teacher / temperature, dim=1)
  37     res = scale * F.kl_div(log_p, q, reduction='mean')
  38     return res
  39 
  40 
  41 class LearningWithoutForgetting(Strategy):
  42     def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=2, optimizer=None,
  43                  criterion=torch.nn.CrossEntropyLoss(), mb_size=256,
  44                  train_ep=2, device=None, preproc=None,
  45                  eval_protocol=EvalProtocol(metrics=[ACC()])):
  46         """
  47         Learning without Forgetting Strategy.
  48 
  49         paper: https://arxiv.org/abs/1606.09282
  50         original implementation (Matlab): https://github.com/lizhitwo/LearningWithoutForgetting
  51         reference implementation (pytorch): https://github.com/arunmallya/packnet/blob/master/src/lwf.py
  52 
  53         Args:
  54             classes_per_task:
  55             alpha: distillation loss coefficient. Can be an integer or a list of values (one for each task).
  56             distillation_loss_T: distillation loss temperature
  57             warmup_epochs: number of warmup epochs training only the new parameters.
  58         """
  59         super(LearningWithoutForgetting, self).__init__(
  60             model, optimizer, criterion, mb_size, train_ep, multi_head=False,
  61             device=device, preproc=preproc, eval_protocol=eval_protocol
  62         )
  63 
  64         # LwF parameters
  65         self.classes_per_task = classes_per_task
  66         self.prev_model = None
  67         self.distillation_loss_T = distillation_loss_T
  68         self.alpha = alpha
  69         self.warmup_epochs = warmup_epochs
  70 
  71     def warmup_train(self):
  72         """ Train only the new parameters for the first epochs. """
  73         # add only the last layer to the trainable parameters
  74         opt = torch.optim.SGD(lr=0.01, params=self.model.classifier.parameters())
  75 
  76         train_x, train_y, it_x_ep = self.preproc_batch_data(self.x, self.y, self.t)
  77         model = self.model.to(self.device)
  78 
  79         train_x = torch.tensor(train_x, dtype=torch.float)
  80         train_y = torch.tensor(train_y, dtype=torch.long)
  81         for ep in range(self.train_ep):
  82             for it in range(it_x_ep):
  83                 start = it * self.mb_size
  84                 end = (it + 1) * self.mb_size
  85 
  86                 self.optimizer.zero_grad()
  87                 x_mb = train_x[start:end].to(self.device)
  88                 y_mb = train_y[start:end].to(self.device)
  89                 logits = model(x_mb)
  90                 # loss computed only on the new classes
  91                 loss = self.criterion(logits[:, self.t*self.classes_per_task:(self.t+1)*self.classes_per_task],
  92                                       y_mb - self.t*self.classes_per_task)
  93                 loss.backward()
  94                 opt.step()
  95 
  96     def compute_loss(self, logits, y_mb):
  97         dist_loss = 0
  98         if self.prev_model is not None:
  99             y_prev = self.prev_model(self.x_mb).detach()
  100             loss = self.criterion(logits, y_mb)
  101             dist_loss += distillation_loss(logits, y_prev, self.distillation_loss_T)
  102 
  103             if isinstance(self.alpha, list):
  104                 loss = loss + self.alpha[self.t] * dist_loss
  105             else:
  106                 loss = loss + self.alpha * dist_loss
  107         else:
  108             loss = self.criterion(logits, y_mb)
  109         return loss
  110 
  111     def after_train(self):
  112         self.prev_model = copy.deepcopy(self.model)
  113 
  114
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/avalanche/training/strategies/lwf/lwf.py b/avalanche/training/strategies/lwf/lwf.py
  --- a/avalanche/training/strategies/lwf/lwf.py
  +++ b/avalanche/training/strategies/lwf/lwf.py
  @@ -39,7 +39,7 @@
   
   
   class LearningWithoutForgetting(Strategy):
  -    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=2, optimizer=None,
  +    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=0, optimizer=None,
                    criterion=torch.nn.CrossEntropyLoss(), mb_size=256,
                    train_ep=2, device=None, preproc=None,
                    eval_protocol=EvalProtocol(metrics=[ACC()])):
  @@ -78,7 +78,7 @@
   
           train_x = torch.tensor(train_x, dtype=torch.float)
           train_y = torch.tensor(train_y, dtype=torch.long)
  -        for ep in range(self.train_ep):
  +        for ep in range(self.warmup_epochs):
               for it in range(it_x_ep):
                   start = it * self.mb_size
                   end = (it + 1) * self.mb_size
  @@ -108,6 +108,9 @@
               loss = self.criterion(logits, y_mb)
           return loss
   
  +    def before_train(self):
  +        self.warmup_train()
  +
       def after_train(self):
           self.prev_model = copy.deepcopy(self.model)
  
verification_info: {"golden_diff": "diff --git a/avalanche/training/strategies/lwf/lwf.py b/avalanche/training/strategies/lwf/lwf.py\n--- a/avalanche/training/strategies/lwf/lwf.py\n+++ b/avalanche/training/strategies/lwf/lwf.py\n@@ -39,7 +39,7 @@\n \n \n class LearningWithoutForgetting(Strategy):\n-    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=2, optimizer=None,\n+    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=0, optimizer=None,\n                  criterion=torch.nn.CrossEntropyLoss(), mb_size=256,\n                  train_ep=2, device=None, preproc=None,\n                  eval_protocol=EvalProtocol(metrics=[ACC()])):\n@@ -78,7 +78,7 @@\n \n         train_x = torch.tensor(train_x, dtype=torch.float)\n         train_y = torch.tensor(train_y, dtype=torch.long)\n-        for ep in range(self.train_ep):\n+        for ep in range(self.warmup_epochs):\n             for it in range(it_x_ep):\n                 start = it * self.mb_size\n                 end = (it + 1) * self.mb_size\n@@ -108,6 +108,9 @@\n             loss = self.criterion(logits, y_mb)\n         return loss\n \n+    def before_train(self):\n+        self.warmup_train()\n+\n     def after_train(self):\n         self.prev_model = copy.deepcopy(self.model)\n", "issue": "LWF \"warmup_train\" fun never used\nHi @AntonioCarta, I've noticed this function in the `LearningWithoutForgetting` class is never used, do we need it?\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n################################################################################\n# Copyright (c) 2020 ContinualAI Research                                      #\n# Copyrights licensed under the CC BY 4.0 License.                             #\n# See the accompanying LICENSE file for terms.                                 #\n#                                                                              #\n# Date: 1-05-2020                                                              #\n# Author(s): ContinualAI                                                       #\n# E-mail: contact@continualai.org                                              #\n# Website: clair.continualai.org                                               #\n################################################################################\n\n\"\"\" Rehearsal Strategy Implementation \"\"\"\n\n# Python 2-3 compatible\nfrom __future__ import print_function\nfrom __future__ import division\nfrom __future__ import absolute_import\n\nfrom training.strategies.strategy import Strategy\nfrom avalanche.evaluation.eval_protocol import EvalProtocol\nfrom avalanche.evaluation.metrics import ACC\nfrom avalanche.training.utils import pad_data, shuffle_in_unison\nimport torch\nimport torch.nn.functional as F\nimport numpy as np\nimport copy\n\n\ndef distillation_loss(y_pred, y_teacher, temperature):\n    \"\"\" Distillation loss. \"\"\"\n    scale = y_teacher.shape[-1]  # kl_div is normalized by element instead of observation\n    log_p = F.log_softmax(y_pred / temperature, dim=1)\n    q = F.softmax(y_teacher / temperature, dim=1)\n    res = scale * F.kl_div(log_p, q, reduction='mean')\n    return res\n\n\nclass LearningWithoutForgetting(Strategy):\n    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=2, optimizer=None,\n                 criterion=torch.nn.CrossEntropyLoss(), mb_size=256,\n                 train_ep=2, device=None, preproc=None,\n                 eval_protocol=EvalProtocol(metrics=[ACC()])):\n        \"\"\"\n        Learning without Forgetting Strategy.\n\n        paper: https://arxiv.org/abs/1606.09282\n        original implementation (Matlab): https://github.com/lizhitwo/LearningWithoutForgetting\n        reference implementation (pytorch): https://github.com/arunmallya/packnet/blob/master/src/lwf.py\n\n        Args:\n            classes_per_task:\n            alpha: distillation loss coefficient. Can be an integer or a list of values (one for each task).\n            distillation_loss_T: distillation loss temperature\n            warmup_epochs: number of warmup epochs training only the new parameters.\n        \"\"\"\n        super(LearningWithoutForgetting, self).__init__(\n            model, optimizer, criterion, mb_size, train_ep, multi_head=False,\n            device=device, preproc=preproc, eval_protocol=eval_protocol\n        )\n\n        # LwF parameters\n        self.classes_per_task = classes_per_task\n        self.prev_model = None\n        self.distillation_loss_T = distillation_loss_T\n        self.alpha = alpha\n        self.warmup_epochs = warmup_epochs\n\n    def warmup_train(self):\n        \"\"\" Train only the new parameters for the first epochs. \"\"\"\n        # add only the last layer to the trainable parameters\n        opt = torch.optim.SGD(lr=0.01, params=self.model.classifier.parameters())\n\n        train_x, train_y, it_x_ep = self.preproc_batch_data(self.x, self.y, self.t)\n        model = self.model.to(self.device)\n\n        train_x = torch.tensor(train_x, dtype=torch.float)\n        train_y = torch.tensor(train_y, dtype=torch.long)\n        for ep in range(self.train_ep):\n            for it in range(it_x_ep):\n                start = it * self.mb_size\n                end = (it + 1) * self.mb_size\n\n                self.optimizer.zero_grad()\n                x_mb = train_x[start:end].to(self.device)\n                y_mb = train_y[start:end].to(self.device)\n                logits = model(x_mb)\n                # loss computed only on the new classes\n                loss = self.criterion(logits[:, self.t*self.classes_per_task:(self.t+1)*self.classes_per_task],\n                                      y_mb - self.t*self.classes_per_task)\n                loss.backward()\n                opt.step()\n\n    def compute_loss(self, logits, y_mb):\n        dist_loss = 0\n        if self.prev_model is not None:\n            y_prev = self.prev_model(self.x_mb).detach()\n            loss = self.criterion(logits, y_mb)\n            dist_loss += distillation_loss(logits, y_prev, self.distillation_loss_T)\n\n            if isinstance(self.alpha, list):\n                loss = loss + self.alpha[self.t] * dist_loss\n            else:\n                loss = loss + self.alpha * dist_loss\n        else:\n            loss = self.criterion(logits, y_mb)\n        return loss\n\n    def after_train(self):\n        self.prev_model = copy.deepcopy(self.model)\n\n", "path": "avalanche/training/strategies/lwf/lwf.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n################################################################################\n# Copyright (c) 2020 ContinualAI Research                                      #\n# Copyrights licensed under the CC BY 4.0 License.                             #\n# See the accompanying LICENSE file for terms.                                 #\n#                                                                              #\n# Date: 1-05-2020                                                              #\n# Author(s): ContinualAI                                                       #\n# E-mail: contact@continualai.org                                              #\n# Website: clair.continualai.org                                               #\n################################################################################\n\n\"\"\" Rehearsal Strategy Implementation \"\"\"\n\n# Python 2-3 compatible\nfrom __future__ import print_function\nfrom __future__ import division\nfrom __future__ import absolute_import\n\nfrom training.strategies.strategy import Strategy\nfrom avalanche.evaluation.eval_protocol import EvalProtocol\nfrom avalanche.evaluation.metrics import ACC\nfrom avalanche.training.utils import pad_data, shuffle_in_unison\nimport torch\nimport torch.nn.functional as F\nimport numpy as np\nimport copy\n\n\ndef distillation_loss(y_pred, y_teacher, temperature):\n    \"\"\" Distillation loss. \"\"\"\n    scale = y_teacher.shape[-1]  # kl_div is normalized by element instead of observation\n    log_p = F.log_softmax(y_pred / temperature, dim=1)\n    q = F.softmax(y_teacher / temperature, dim=1)\n    res = scale * F.kl_div(log_p, q, reduction='mean')\n    return res\n\n\nclass LearningWithoutForgetting(Strategy):\n    def __init__(self, model, classes_per_task, alpha=0.5, distillation_loss_T=2, warmup_epochs=0, optimizer=None,\n                 criterion=torch.nn.CrossEntropyLoss(), mb_size=256,\n                 train_ep=2, device=None, preproc=None,\n                 eval_protocol=EvalProtocol(metrics=[ACC()])):\n        \"\"\"\n        Learning without Forgetting Strategy.\n\n        paper: https://arxiv.org/abs/1606.09282\n        original implementation (Matlab): https://github.com/lizhitwo/LearningWithoutForgetting\n        reference implementation (pytorch): https://github.com/arunmallya/packnet/blob/master/src/lwf.py\n\n        Args:\n            classes_per_task:\n            alpha: distillation loss coefficient. Can be an integer or a list of values (one for each task).\n            distillation_loss_T: distillation loss temperature\n            warmup_epochs: number of warmup epochs training only the new parameters.\n        \"\"\"\n        super(LearningWithoutForgetting, self).__init__(\n            model, optimizer, criterion, mb_size, train_ep, multi_head=False,\n            device=device, preproc=preproc, eval_protocol=eval_protocol\n        )\n\n        # LwF parameters\n        self.classes_per_task = classes_per_task\n        self.prev_model = None\n        self.distillation_loss_T = distillation_loss_T\n        self.alpha = alpha\n        self.warmup_epochs = warmup_epochs\n\n    def warmup_train(self):\n        \"\"\" Train only the new parameters for the first epochs. \"\"\"\n        # add only the last layer to the trainable parameters\n        opt = torch.optim.SGD(lr=0.01, params=self.model.classifier.parameters())\n\n        train_x, train_y, it_x_ep = self.preproc_batch_data(self.x, self.y, self.t)\n        model = self.model.to(self.device)\n\n        train_x = torch.tensor(train_x, dtype=torch.float)\n        train_y = torch.tensor(train_y, dtype=torch.long)\n        for ep in range(self.warmup_epochs):\n            for it in range(it_x_ep):\n                start = it * self.mb_size\n                end = (it + 1) * self.mb_size\n\n                self.optimizer.zero_grad()\n                x_mb = train_x[start:end].to(self.device)\n                y_mb = train_y[start:end].to(self.device)\n                logits = model(x_mb)\n                # loss computed only on the new classes\n                loss = self.criterion(logits[:, self.t*self.classes_per_task:(self.t+1)*self.classes_per_task],\n                                      y_mb - self.t*self.classes_per_task)\n                loss.backward()\n                opt.step()\n\n    def compute_loss(self, logits, y_mb):\n        dist_loss = 0\n        if self.prev_model is not None:\n            y_prev = self.prev_model(self.x_mb).detach()\n            loss = self.criterion(logits, y_mb)\n            dist_loss += distillation_loss(logits, y_prev, self.distillation_loss_T)\n\n            if isinstance(self.alpha, list):\n                loss = loss + self.alpha[self.t] * dist_loss\n            else:\n                loss = loss + self.alpha * dist_loss\n        else:\n            loss = self.criterion(logits, y_mb)\n        return loss\n\n    def before_train(self):\n        self.warmup_train()\n\n    def after_train(self):\n        self.prev_model = copy.deepcopy(self.model)\n\n", "path": "avalanche/training/strategies/lwf/lwf.py"}]}