class_docstr: Grover Finetune model.
  
  For a graph level prediction task, the GroverFinetune model uses node/edge embeddings
  output by the GroverEmbeddong layer and applies a readout function on it to get
  graph embeddings and use additional MLP layers to predict the property of the molecular graph.
  
  Parameters
  ----------
  embedding: nn.Module
      An embedding layer to generate embedding from input molecular graph
  readout: nn.Module
      A readout layer to perform readout atom and bond hidden states
  mol_atom_from_atom_ffn: nn.Module
      A feed forward network which learns representation from atom messages generated via atom hidden states of a molecular graph
  mol_atom_from_bond_ffn: nn.Module
      A feed forward network which learns representation from atom messages generated via bond hidden states of a molecular graph
  mode: str
      classification or regression
  
  Returns
  -------
  prediction_logits: torch.Tensor
      prediction logits
  
  Example
  -------
  >>> import deepchem as dc
  >>> from deepchem.utils.grover import BatchGroverGraph
  >>> from deepchem.models.torch_models.grover_layers import GroverEmbedding
  >>> from deepchem.models.torch_models.readout import GroverReadout
  >>> from deepchem.models.torch_models.grover import GroverFinetune
  >>> smiles = ['CC', 'CCC', 'CC(=O)C']
  >>> fg = dc.feat.CircularFingerprint()
  >>> featurizer = dc.feat.GroverFeaturizer(features_generator=fg)
  >>> graphs = featurizer.featurize(smiles)
  >>> batched_graph = BatchGroverGraph(graphs)
  >>> attributes = batched_graph.get_components()
  >>> components = {}
  >>> additional_features = batched_graph.additional_features
  >>> f_atoms, f_bonds, a2b, b2a, b2revb, a2a, a_scope, b_scope, fg_labels = attributes
  >>> inputs = f_atoms, f_bonds, a2b, b2a, b2revb, a_scope, b_scope, a2a
  >>> components = {}
  >>> components['embedding'] = GroverEmbedding(node_fdim=f_atoms.shape[1], edge_fdim=f_bonds.shape[1])
  >>> components['readout'] = GroverReadout(rtype="mean", in_features=128)
  >>> components['mol_atom_from_atom_ffn'] = nn.Linear(in_features=additional_features.shape[1]+ 128, out_features=128)
  >>> components['mol_atom_from_bond_ffn'] = nn.Linear(in_features=additional_features.shape[1] + 128, out_features=128)
  >>> model = GroverFinetune(**components, mode='regression', hidden_size=128)
  >>> model.training = False
  >>> output = model((inputs, additional_features))
  
  Reference
  ---------
  .. Rong, Yu, et al. "Self-supervised graph transformer on large-scale molecular data." Advances in Neural Information Processing Systems 33 (2020): 12559-12571.
code: def __init__(
      self,
      embedding: nn.Module,
      readout: nn.Module,
      mol_atom_from_atom_ffn: nn.Module,
      mol_atom_from_bond_ffn: nn.Module,
      hidden_size: int = 128,
      mode: str = "regression",
      n_tasks: int = 1,
      n_classes: Optional[int] = None,
  ):
      super().__init__()
      self.embedding = embedding
      self.readout = readout
      self.mol_atom_from_atom_ffn = mol_atom_from_atom_ffn
      self.mol_atom_from_bond_ffn = mol_atom_from_bond_ffn
      self.n_tasks = n_tasks
      self.n_classes = n_classes
      self.mode = mode
      # the hidden size here is the output size of last layer in mol_atom_from_atom_ffn and mol_atom_from_bond_ffn components.
      # it is necessary that aforementioned components produces output tensor of same size.
      if self.mode == "classification":
          assert n_classes is not None
          self.linear = nn.Linear(
              hidden_size, out_features=n_tasks * n_classes
          )
      elif self.mode == "regression":
          self.linear = nn.Linear(hidden_size, out_features=n_tasks)
  
imports: import math
  import torch
  import torch.nn
  import torch.nn.functional
  import numpy
  from typing import List, Sequence, Optional, Any, Tuple
  from rdkit import Chem
  from deepchem.models.torch_models.modular import ModularTorchModel
  from deepchem.models.torch_models.grover_layers import GroverEmbedding, GroverBondVocabPredictor, GroverAtomVocabPredictor, GroverFunctionalGroupPredictor
  from deepchem.models.torch_models.readout import GroverReadout
  from deepchem.feat.vocabulary_builders import GroverAtomVocabularyBuilder, GroverBondVocabularyBuilder
  from deepchem.utils.grover import BatchGroverGraph
  import logging
label_desc: Use image node_id 1 to create a new GroverFinetune object from inherited base classes: nn with example: obj = GroverFinetune(embedding, readout, mol_atom_from_atom_ffn, mol_atom_from_bond_ffn, hidden_size, mode, n_tasks, n_classes)