code: def cross_validation(
      ctx: Context,
      role: Role,
      cv_data: cpn.dataframe_input(roles=[GUEST, HOST]),
      epochs: cpn.parameter(
          type=params.conint(gt=0), default=20, desc="max iteration num"
      ),
      batch_size: cpn.parameter(
          type=params.conint(ge=10),
          default=None,
          desc="batch size, None means full batch, otherwise should be no less than 10, default None",
      ),
      tol: cpn.parameter(type=params.confloat(ge=0), default=1e-4),
      early_stop: cpn.parameter(
          type=params.string_choice(["weight_diff", "diff", "abs"]),
          default="diff",
          desc="early stopping criterion, choose from {weight_diff, diff, abs}, if use weight_diff,"
          "weight will be revealed every epoch",
      ),
      learning_rate: cpn.parameter(
          type=params.confloat(ge=0), default=0.05, desc="learning rate"
      ),
      init_param: cpn.parameter(
          type=params.init_param(),
          default=params.InitParam(
              method="random_uniform",
              fit_intercept=True,
              random_state=None,
          ),
          desc="Model param init setting.",
      ),
      threshold: cpn.parameter(
          type=params.confloat(ge=0.0, le=1.0),
          default=0.5,
          desc="predict threshold for binary data",
      ),
      reveal_every_epoch: cpn.parameter(
          type=bool,
          default=False,
          desc="whether reveal encrypted result every epoch, "
          "only accept False for now",
      ),
      reveal_loss_freq: cpn.parameter(
          type=params.conint(ge=1),
          default=1,
          desc="rounds to reveal training loss, "
          "only effective if `early_stop` is 'loss'",
      ),
      cv_param: cpn.parameter(
          type=params.cv_param(),
          default=params.CVParam(
              n_splits=5, shuffle=False, random_state=None
          ),
          desc="cross validation param",
      ),
      metrics: cpn.parameter(
          type=params.metrics_param(), default=["auc"]
      ),
      output_cv_data: cpn.parameter(
          type=bool,
          default=True,
          desc="whether output prediction result per cv fold",
      ),
      cv_output_datas: cpn.dataframe_outputs(
          roles=[GUEST, HOST], optional=True
      ),
  ):
      init_param = init_param.dict()
      ctx.mpc.init()
  
      from fate.arch.dataframe import KFold
  
      kf = KFold(
          ctx,
          role=role,
          n_splits=cv_param.n_splits,
          shuffle=cv_param.shuffle,
          random_state=cv_param.random_state,
      )
      i = 0
      for fold_ctx, (
          train_data,
          validate_data,
      ) in ctx.on_cross_validations.ctxs_zip(kf.split(cv_data.read())):
          logger.info(f"enter fold {i}")
          module = SSHELinearRegression(
              epochs=epochs,
              batch_size=batch_size,
              learning_rate=learning_rate,
              tol=tol,
              early_stop=early_stop,
              init_param=init_param,
              threshold=threshold,
              reveal_every_epoch=reveal_every_epoch,
              reveal_loss_freq=reveal_loss_freq,
          )
          module.fit(fold_ctx, train_data, validate_data)
          if output_cv_data:
              if role.is_guest:
                  sub_ctx = fold_ctx.sub_ctx("predict_train")
                  predict_df = module.predict(sub_ctx, train_data)
                  train_predict_result = tools.add_dataset_type(
                      predict_df, consts.TRAIN_SET
                  )
                  sub_ctx = fold_ctx.sub_ctx("predict_validate")
                  predict_df = module.predict(sub_ctx, validate_data)
                  validate_predict_result = tools.add_dataset_type(
                      predict_df, consts.VALIDATE_SET
                  )
                  predict_result = DataFrame.vstack(
                      [train_predict_result, validate_predict_result]
                  )
                  next(cv_output_datas).write(df=predict_result)
              elif role.is_host:
                  sub_ctx = fold_ctx.sub_ctx("predict_train")
                  module.predict(sub_ctx, train_data)
                  sub_ctx = fold_ctx.sub_ctx("predict_validate")
                  module.predict(sub_ctx, validate_data)
          i += 1
  
file_path: FATE/python/fate/components/components/sshe_linr.py
imports: import logging
  from fate.arch import Context
  from fate.arch.dataframe import DataFrame
  from fate.components.components.utils import consts, tools
  from fate.components.core import GUEST, HOST, Role, cpn, params
  from fate.ml.glm.hetero.sshe import SSHELinearRegression
label_desc: Use image node_id 4 for calling a global function with example usage: cross_validation(ctx, role, cv_data, epochs, batch_size, tol, early_stop, learning_rate, init_param, threshold, reveal_every_epoch, reveal_loss_freq, cv_param, metrics, output_cv_data, cv_output_datas) without return types