class_docstr: Description
  -----------
  Boost GNN predictor for semi-supervised node classification or regression problems.
  Publication: https://arxiv.org/abs/2101.08543
  
  Parameters
  ----------
  gnn_model : nn.Module
      DGL implementation of GNN model.
  task: str, optional
      Regression or classification task.
  loss_fn : callable, optional
      Function that takes torch tensors, pred and true, and returns a scalar.
  trees_per_epoch : int, optional
      Number of GBDT trees to build each epoch.
  backprop_per_epoch : int, optional
      Number of backpropagation steps to make each epoch.
  lr : float, optional
      Learning rate of gradient descent optimizer.
  append_gbdt_pred : bool, optional
      Append GBDT predictions or replace original input node features.
  train_input_features : bool, optional
      Train original input node features.
  gbdt_depth : int, optional
      Depth of each tree in GBDT model.
  gbdt_lr : float, optional
      Learning rate of GBDT model.
  gbdt_alpha : int, optional
      Weight to combine previous and new GBDT trees.
  random_seed : int, optional
      random seed for GNN and GBDT models.
  
  Examples
  ----------
  gnn_model = GAT(10, 20, num_heads=5),
  bgnn = BGNNPredictor(gnn_model)
  metrics = bgnn.fit(graph, X, y, train_mask, val_mask, test_mask, cat_features)
code: def plot_interactive(
      self,
      metrics,
      legend,
      title,
      logx=False,
      logy=False,
      metric_name="loss",
      start_from=0,
  ):
      import plotly.graph_objects as go
  
      metric_results = metrics[metric_name]
      xs = [list(range(len(metric_results)))] * len(metric_results[0])
      ys = list(zip(*metric_results))
  
      fig = go.Figure()
      for i in range(len(ys)):
          fig.add_trace(
              go.Scatter(
                  x=xs[i][start_from:],
                  y=ys[i][start_from:],
                  mode="lines+markers",
                  name=legend[i],
              )
          )
  
      fig.update_layout(
          title=title,
          title_x=0.5,
          xaxis_title="Epoch",
          yaxis_title=metric_name,
          font=dict(
              size=40,
          ),
          height=600,
      )
  
      if logx:
          fig.update_layout(xaxis_type="log")
      if logy:
          fig.update_layout(yaxis_type="log")
  
      fig.show()
  
imports: import itertools
  import time
  from collections import defaultdict
  import numpy
  import pandas
  import torch
  import torch.nn.functional
  from catboost import CatBoostClassifier, CatBoostRegressor, Pool, sum_models
  from sklearn import preprocessing
  from sklearn.metrics import r2_score
  from tqdm import tqdm
label_desc: Use image node_id 17 for calling the BGNNPredictor obj's underlying member method code with example usage: obj.plot_interactive(metrics, legend, title, logx, logy, metric_name, start_from) without return types