docstr: Train the model on the given dataset. If given a validation
  dataset, returns a list of loss scores at each epoch.
  
  :param dataset: A Dataset or DataLoader containing the dataset
      to train on. If given a Dataset, this method automatically
      wraps it in a DataLoader with `shuffle` set to `True`.
  :type dataset: detecto.core.Dataset or detecto.core.DataLoader
  :param val_dataset: (Optional) A Dataset or DataLoader containing
      the dataset to validate on. Defaults to None, in which case no
      validation occurs.
  :type val_dataset: detecto.core.Dataset or detecto.core.DataLoader
  :param epochs: (Optional) The number of runs over the data in
      ``dataset`` to train for. Defaults to 10.
  :type epochs: int
  :param learning_rate: (Optional) How fast to update the model
      weights at each step of training. Defaults to 0.005.
  :type learning_rate: float
  :param momentum: (Optional) The momentum used to reduce the
      fluctuations of gradients at each step. Defaults to 0.9.
  :type momentum: float
  :param weight_decay: (Optional) The amount of L2 regularization
      to apply on model parameters. Defaults to 0.0005.
  :type weight_decay: float
  :param gamma: (Optional) The decay factor that ``learning_rate``
      is multiplied by every ``lr_step_size`` epochs. Defaults to 0.1.
  :type gamma: float
  :param lr_step_size: (Optional) The number of epochs between each
      decay of ``learning_rate`` by ``gamma``. Defaults to 3.
  :type lr_step_size: int
  :param verbose: (Optional) Whether to print the current epoch, progress,
      and loss (if given a validation dataset) at each step, along with
      some additional warnings if using a CPU. Defaults to True.
  :type verbose: bool
  :return: If ``val_dataset`` is not None and epochs is greater than 0,
      returns a list of the validation losses at each epoch. Otherwise,
      returns nothing.
  :rtype: list or None
  
  **Example**::
  
      >>> from detecto.core import Model, Dataset, DataLoader
  
      >>> dataset = Dataset('training_data/')
      >>> val_dataset = Dataset('validation_data/')
      >>> model = Model(['rose', 'tulip'])
  
      >>> losses = model.fit(dataset, val_dataset, epochs=5)
  
      >>> # Alternatively, provide a custom DataLoader over your dataset
      >>> loader = DataLoader(dataset, batch_size=2, shuffle=True)
      >>> losses = model.fit(loader, val_dataset, epochs=5)
  
      >>> losses
      [0.11191498369799327, 0.09899920264606253, 0.08454859235434461,
          0.06825731012780788, 0.06236840748117637]
docstr_tok: ["Train","the","model","on","the","given","dataset",".","If","given","a","validation","dataset",",","returns","a","list","of","loss","scores","at","each","epoch",".",":","param","dataset",":","A","Dataset","or","DataLoader","containing","the","dataset","to","train","on",".","If","given","a","Dataset",",","this","method","automatically","wraps","it","in","a","DataLoader","with","`","shuffle","`","set","to","`","True","`",".",":","type","dataset",":","detecto.core.Dataset","or","detecto.core.DataLoader",":","param","val_dataset",":","(","Optional",")","A","Dataset","or","DataLoader","containing","the","dataset","to","validate","on",".","Defaults","to","None",",","in","which","case","no","validation","occurs",".",":","type","val_dataset",":","detecto.core.Dataset","or","detecto.core.DataLoader",":","param","epochs",":","(","Optional",")","The","number","of","runs","over","the","data","in","``","dataset","``","to","train","for",".","Defaults","to","10.",":","type","epochs",":","int",":","param","learning_rate",":","(","Optional",")","How","fast","to","update","the","model","weights","at","each","step","of","training",".","Defaults","to","0.005.",":","type","learning_rate",":","float",":","param","momentum",":","(","Optional",")","The","momentum","used","to","reduce","the","fluctuations","of","gradients","at","each","step",".","Defaults","to","0.9.",":","type","momentum",":","float",":","param","weight_decay",":","(","Optional",")","The","amount","of","L2","regularization","to","apply","on","model","parameters",".","Defaults","to","0.0005.",":","type","weight_decay",":","float",":","param","gamma",":","(","Optional",")","The","decay","factor","that","``","learning_rate","``","is","multiplied","by","every","``","lr_step_size","``","epochs",".","Defaults","to","0.1.",":","type","gamma",":","float",":","param","lr_step_size",":","(","Optional",")","The","number","of","epochs","between","each","decay","of","``","learning_rate","``","by","``","gamma","``",".","Defaults","to","3.",":","type","lr_step_size",":","int",":","param","verbose",":","(","Optional",")","Whether","to","print","the","current","epoch",",","progress",",","and","loss","(","if","given","a","validation","dataset",")","at","each","step",",","along","with","some","additional","warnings","if","using","a","CPU",".","Defaults","to","True",".",":","type","verbose",":","bool",":","return",":","If","``","val_dataset","``","is","not","None","and","epochs","is","greater","than","0",",","returns","a","list","of","the","validation","losses","at","each","epoch",".","Otherwise",",","returns","nothing",".",":","rtype",":","list","or","None","*","*","Example","*","*",":",":",">",">",">","from","detecto.core","import","Model",",","Dataset",",","DataLoader",">",">",">","dataset","=","Dataset","(","'training_data\/","'",")",">",">",">","val_dataset","=","Dataset","(","'validation_data\/","'",")",">",">",">","model","=","Model","(","[","'rose","'",",","'tulip","'","]",")",">",">",">","losses","=","model.fit","(","dataset",",","val_dataset",",","epochs=5",")",">",">",">","#","Alternatively",",","provide","a","custom","DataLoader","over","your","dataset",">",">",">","loader","=","DataLoader","(","dataset",",","batch_size=2",",","shuffle=True",")",">",">",">","losses","=","model.fit","(","loader",",","val_dataset",",","epochs=5",")",">",">",">","losses","[","0.11191498369799327",",","0.09899920264606253",",","0.08454859235434461",",","0.06825731012780788",",","0.06236840748117637","]"]
code: def fit(
      self,
      dataset,
      val_dataset=None,
      epochs=10,
      learning_rate=0.005,
      momentum=0.9,
      weight_decay=0.0005,
      gamma=0.1,
      lr_step_size=3,
      verbose=True,
  ):
      """Train the model on the given dataset. If given a validation
      dataset, returns a list of loss scores at each epoch.
  
      :param dataset: A Dataset or DataLoader containing the dataset
          to train on. If given a Dataset, this method automatically
          wraps it in a DataLoader with `shuffle` set to `True`.
      :type dataset: detecto.core.Dataset or detecto.core.DataLoader
      :param val_dataset: (Optional) A Dataset or DataLoader containing
          the dataset to validate on. Defaults to None, in which case no
          validation occurs.
      :type val_dataset: detecto.core.Dataset or detecto.core.DataLoader
      :param epochs: (Optional) The number of runs over the data in
          ``dataset`` to train for. Defaults to 10.
      :type epochs: int
      :param learning_rate: (Optional) How fast to update the model
          weights at each step of training. Defaults to 0.005.
      :type learning_rate: float
      :param momentum: (Optional) The momentum used to reduce the
          fluctuations of gradients at each step. Defaults to 0.9.
      :type momentum: float
      :param weight_decay: (Optional) The amount of L2 regularization
          to apply on model parameters. Defaults to 0.0005.
      :type weight_decay: float
      :param gamma: (Optional) The decay factor that ``learning_rate``
          is multiplied by every ``lr_step_size`` epochs. Defaults to 0.1.
      :type gamma: float
      :param lr_step_size: (Optional) The number of epochs between each
          decay of ``learning_rate`` by ``gamma``. Defaults to 3.
      :type lr_step_size: int
      :param verbose: (Optional) Whether to print the current epoch, progress,
          and loss (if given a validation dataset) at each step, along with
          some additional warnings if using a CPU. Defaults to True.
      :type verbose: bool
      :return: If ``val_dataset`` is not None and epochs is greater than 0,
          returns a list of the validation losses at each epoch. Otherwise,
          returns nothing.
      :rtype: list or None
  
      **Example**::
  
          >>> from detecto.core import Model, Dataset, DataLoader
  
          >>> dataset = Dataset('training_data/')
          >>> val_dataset = Dataset('validation_data/')
          >>> model = Model(['rose', 'tulip'])
  
          >>> losses = model.fit(dataset, val_dataset, epochs=5)
  
          >>> # Alternatively, provide a custom DataLoader over your dataset
          >>> loader = DataLoader(dataset, batch_size=2, shuffle=True)
          >>> losses = model.fit(loader, val_dataset, epochs=5)
  
          >>> losses
          [0.11191498369799327, 0.09899920264606253, 0.08454859235434461,
              0.06825731012780788, 0.06236840748117637]
      """
  
      if verbose and self._device == torch.device("cpu"):
          print(
              "It looks like you're training your model on a CPU. "
              "Consider switching to a GPU; otherwise, this method "
              "can take hours upon hours or even days to finish. "
              "For more information, see https://detecto.readthedocs.io/"
              "en/latest/usage/quickstart.html#technical-requirements"
          )
  
      # If doing custom training, the given images will most likely be
      # normalized. This should fix the issue of poor performance on
      # default classes when normalizing, so resume normalizing. TODO
      if epochs > 0:
          self._disable_normalize = False
  
      # Convert dataset to data loader if not already
      if not isinstance(dataset, DataLoader):
          dataset = DataLoader(dataset, shuffle=True)
  
      if val_dataset is not None and not isinstance(
          val_dataset, DataLoader
      ):
          val_dataset = DataLoader(val_dataset)
  
      losses = []
      # Get parameters that have grad turned on (i.e. parameters that should be trained)
      parameters = [
          p for p in self._model.parameters() if p.requires_grad
      ]
      # Create an optimizer that uses SGD (stochastic gradient descent) to train the parameters
      optimizer = torch.optim.SGD(
          parameters,
          lr=learning_rate,
          momentum=momentum,
          weight_decay=weight_decay,
      )
      # Create a learning rate scheduler that decreases learning rate by gamma every lr_step_size epochs
      lr_scheduler = torch.optim.lr_scheduler.StepLR(
          optimizer, step_size=lr_step_size, gamma=gamma
      )
  
      # Train on the entire dataset for the specified number of times (epochs)
      for epoch in range(epochs):
          if verbose:
              print("Epoch {} of {}".format(epoch + 1, epochs))
  
          # Training step
          self._model.train()
  
          if verbose:
              print("Begin iterating over training dataset")
  
          iterable = (
              tqdm(dataset, position=0, leave=True)
              if verbose
              else dataset
          )
          for images, targets in iterable:
              self._convert_to_int_labels(targets)
              images, targets = self._to_device(images, targets)
  
              # Calculate the model's loss (i.e. how well it does on the current
              # image and target, with a lower loss being better)
              loss_dict = self._model(images, targets)
              total_loss = sum(loss for loss in loss_dict.values())
  
              # Zero any old/existing gradients on the model's parameters
              optimizer.zero_grad()
              # Compute gradients for each parameter based on the current loss calculation
              total_loss.backward()
              # Update model parameters from gradients: param -= learning_rate * param.grad
              optimizer.step()
  
          # Validation step
          if val_dataset is not None:
              avg_loss = 0
              with torch.no_grad():
                  if verbose:
                      print("Begin iterating over validation dataset")
  
                  iterable = (
                      tqdm(val_dataset, position=0, leave=True)
                      if verbose
                      else val_dataset
                  )
                  for images, targets in iterable:
                      self._convert_to_int_labels(targets)
                      images, targets = self._to_device(images, targets)
                      loss_dict = self._model(images, targets)
                      total_loss = sum(
                          loss for loss in loss_dict.values()
                      )
                      avg_loss += total_loss.item()
  
              avg_loss /= len(val_dataset.dataset)
              losses.append(avg_loss)
  
              if verbose:
                  print("Loss: {}".format(avg_loss))
  
          # Update the learning rate every few epochs
          lr_scheduler.step()
  
      if len(losses) > 0:
          return losses
  
imports: import os
  import pandas
  import random
  import torch
  import torchvision
  from detecto.config import config
  from detecto.utils import default_transforms, filter_top_predictions, xml_to_csv, _is_iterable, read_image
  from torchvision import transforms
  from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
  from tqdm import tqdm
label_desc: Use image node_id 5 for calling the Model obj's underlying member method code with example usage: obj.fit(dataset, val_dataset, epochs, learning_rate, momentum, weight_decay, gamma, lr_step_size, verbose) and returns: losses