docstr: recover_bucket: if node_hist is guest hist, can get the fid and bid of the split info
                  but for node_hist from host sites, histograms are shuffled, so can not get the fid and bid,
                  only hosts know them.
docstr_tok: ["recover_bucket",":","if","node_hist","is","guest","hist",",","can","get","the","fid","and","bid","of","the","split","info","but","for","node_hist","from","host","sites",",","histograms","are","shuffled",",","so","can","not","get","the","fid","and","bid",",","only","hosts","know","them","."]
code: def _find_best_splits(
      self,
      node_hist,
      sitename,
      cur_layer_nodes,
      reverse_node_map,
      recover_bucket=True,
      pack_info=None,
  ):
      """
      recover_bucket: if node_hist is guest hist, can get the fid and bid of the split info
                      but for node_hist from host sites, histograms are shuffled, so can not get the fid and bid,
                      only hosts know them.
      """
      l_g, l_h, l_cnt = self._extract_hist(node_hist, pack_info)
      g_sum, h_sum, cnt_sum = self._make_sum_tensor(cur_layer_nodes)
      rs = self._compute_gains(l_g, l_h, l_cnt, g_sum, h_sum, cnt_sum)
  
      # reduce
      best = rs.max(dim=-1)
      best_gain = best[0]
      best_idx = best[1]
      logger.debug("best_idx: {}".format(best_idx))
      logger.debug("best_gain: {}".format(best_gain))
  
      split_infos = []
      node_idx = 0
      for idx, gain in zip(best_idx, best_gain):
          idx_ = int(idx.detach().cpu().item())
          if (
              gain == float("-inf")
              or cnt_sum[node_idx] < self.min_sample_split
          ):
              split_infos.append(None)
              logger.info(
                  "Node {} can not be further split".format(
                      reverse_node_map[node_idx]
                  )
              )
          else:
              split_info = SplitInfo(
                  gain=float(gain),
                  sum_grad=float(l_g[node_idx][idx_]),
                  sum_hess=float(l_h[node_idx][idx_]),
                  sample_count=int(l_cnt[node_idx][idx_]),
                  sitename=sitename,
              )
              if recover_bucket:
                  fid, bid = self.get_bucket(idx_)
                  split_info.best_fid = fid
                  split_info.best_bid = bid
              else:
                  split_info.split_id = idx_
              split_infos.append(split_info)
          node_idx += 1
  
      return split_infos
  
imports: import torch
  import numpy
  import logging
  from fate.arch.dataframe import DataFrame
  from fate.arch import Context
  from fate.arch.histogram import DistributedHistogram
label_desc: Use image node_id 11 for calling the SBTSplitter obj's underlying member method code with example usage: obj._find_best_splits(node_hist, sitename, cur_layer_nodes, reverse_node_map, recover_bucket, pack_info) and returns: split_infos