class_docstr: Training pipeline for a multi-stage hybrid recommendation model.
  
  ``HybridModel`` models contain dense layers that process item and/or user metadata, concatenate
  this embedding with user and item embeddings, sending this concatenated embedding through more
  dense layers to output a single float ranking / rating. We add both user and item biases to
  this score before returning. This is the same architecture as the ``HybridPretrainedModel``,
  but we are training the embeddings ourselves rather than relying on pulling this from a
  pre-trained model.
  
  The stages in a ``HybridModel`` depend on whether both item and user metadata is used.
  For the full model, they are, in order:
  
  1. ``matrix_factorization``
      Matrix factorization exactly as we do in ``MatrixFactorizationModel``. In this stage,
      metadata is NOT incorporated into the model.
  2. ``metadata_only``
      User and item embeddings terms are frozen, and the MLP layers for the metadata (if
      specified) and combined embedding-metadata data are optimized.
  3. ``all``
      Embedding and MLP layers are all optimized together, including those for metadata.
  
  All ``HybridModel`` instances are subclasses of the ``LightningModule`` class provided by
  PyTorch Lightning. This means to train a model, you will need a
  ``collie.model.CollieTrainer`` object, but the model can be saved and loaded without this
  ``Trainer`` instance. Example usage may look like:
  
  .. code-block:: python
  
      from collie.model import CollieTrainer, HybridModel
  
  
      # instantiate and fit a ``HybridModel`` as expected
      model = HybridModel(train=train,
                          item_metadata=item_metadata,
                          user_metadata=user_metadata)
      trainer = CollieTrainer(model)
      trainer.fit(model)
  
      # train for X more epochs on the next stage, ``metadata_only``
      trainer.max_epochs += X
      model.advance_stage()
      trainer.fit(model)
  
      # train for Y more epochs on the next stage, ``all``
      trainer.max_epochs += Y
      model.advance_stage()
      trainer.fit(model)
  
      model.eval()
  
      # do evaluation as normal with ``model``
  
      model.save_model(path='model')
      new_model = HybridModel(load_model_path='model')
  
      # do evaluation as normal with ``new_model``
  
  Note
  ----
  The ``forward`` calculation will be different depending on the stage that is set. Note this
  when evaluating / saving and loading models in.
  
  Parameters
  ----------
  item_metadata: torch.tensor, pd.DataFrame, or np.array, 2-dimensional
      The shape of the item metadata should be (num_items x metadata_features), and each item's
      metadata should be available when indexing a row by an item ID
  user_metadata: torch.tensor, pd.DataFrame, or np.array, 2-dimensional
      The shape of the user metadata should be (num_users x metadata_features), and each user's
      metadata should be available when indexing a row by a user ID
  embedding_dim: int
      Number of latent factors to use for user and item embeddings
  item_metadata_layers_dims: list
      List of linear layer dimensions to apply to the item metadata only, starting with
      the dimension directly following ``item_metadata_features`` and ending with the
      dimension to concatenate with the item embeddings
  user_metadata_layers_dims: list
      List of linear layer dimensions to apply to the user metadata only, starting with
      the dimension directly following ``user_metadata_features`` and ending with the
      dimension to concatenate with the user embeddings
  combined_layers_dims: list
      List of linear layer dimensions to apply to the concatenated item embeddings and item
      metadata, starting with the dimension directly following the shape of
      ``item_embeddings + metadata_features`` and ending with the dimension before the final
      linear layer to dimension 1
  dropout_p: float
      Probability of dropout
  metadata_only_stage_lr: float
      Learning rate for metadata and combined layers optimized during the ``metadata_only`` stage
  all_stage_lr: float
      Learning rate for all model parameters optimized during the ``all`` stage
  optimizer: torch.optim or str
      Optimizer used for embeddings and bias terms (if ``bias_optimizer`` is ``None``) during the
      ``matrix_factorization`` stage. If a string, one of the following supported optimizers:
  
      * ``'sgd'`` (for ``torch.optim.SGD``)
  
      * ``'adam'`` (for ``torch.optim.Adam``)
  
  metadata_only_stage_optimizer: torch.optim or str
      Optimizer used for metadata and combined layers during the ``metadata_only`` stage. If a
      string, one of the following supported optimizers:
  
      * ``'sgd'`` (for ``torch.optim.SGD``)
  
      * ``'adam'`` (for ``torch.optim.Adam``)
  
  all_stage_optimizer: torch.optim or str
      Optimizer used for all model parameters during the ``all`` stage. If a string, one of the
      following supported optimizers:
  
      * ``'sgd'`` (for ``torch.optim.SGD``)
  
      * ``'adam'`` (for ``torch.optim.Adam``)
docstr: Get user embeddings on device.
docstr_tok: ["Get","user","embeddings","on","device","."]
code: def _get_user_embeddings(self) -> torch.tensor:
      """Get user embeddings on device."""
      # TODO: update this to get the embeddings post-MLP
      return self.user_embeddings.weight.data
  
imports: from functools import partial
  import os
  from pathlib import Path
  from typing import Callable, Dict, Iterable, List, Optional, Union
  import warnings
  import joblib
  import numpy
  import pandas
  import torch
  from torch import nn
  import torch.nn.functional
  from torch.optim.lr_scheduler import ReduceLROnPlateau
  from collie.config import DATA_PATH
  from collie.interactions import ApproximateNegativeSamplingInteractionsDataLoader, Interactions, InteractionsDataLoader
  from collie.model.base import MultiStagePipeline, ScaledEmbedding, ZeroEmbedding
  from collie.utils import get_init_arguments, merge_docstrings
label_desc: Use image node_id 10 for calling the HybridModel obj's underlying member method code with example usage: obj._get_user_embeddings() and returns: self