code: def _model_select(
      dataset_info: DatasetInfo,
      default_configs,
      user_config,
      use_reference_config: bool,
  ):
      """Performs model selection based on dataset or user specified model.
  
      Note: Current implementation returns tabnet by default for tabular datasets.
      """
      fields = dataset_info.fields
  
      base_config = copy.deepcopy(default_configs["base_config"])
      model_category = None
  
      input_features = default_configs["base_config"]["input_features"]
  
      # tabular dataset heuristics
      if len(fields) > 3 and all(
          f[TYPE] in TABULAR_TYPES for f in input_features
      ):
          model_category = TABULAR
          base_config = merge_dict(
              base_config,
              default_configs["combiner"][AUTOML_DEFAULT_TABULAR_MODEL],
          )
  
          # override combiner heuristic if explicitly provided by user
          if user_config is not None:
              if "combiner" in user_config.keys():
                  model_type = user_config["combiner"]["type"]
                  base_config = merge_dict(
                      base_config,
                      default_configs["combiner"][model_type],
                  )
      else:
          # text heuristics
          for i, input_feature in enumerate(input_features):
              base_config_input_feature = base_config["input_features"][
                  i
              ]
              # default text encoder is bert
              if input_feature[TYPE] == TEXT:
                  model_category = TEXT
                  if ENCODER in input_feature:
                      base_config_input_feature[ENCODER][
                          TYPE
                      ] = AUTOML_DEFAULT_TEXT_ENCODER
                  else:
                      base_config_input_feature[ENCODER] = {
                          TYPE: AUTOML_DEFAULT_TEXT_ENCODER
                      }
                  # TODO(shreya): Should this hyperopt config param be set here?
                  base_config[HYPEROPT]["executor"][
                      "num_samples"
                  ] = 5  # set for small hyperparameter search space
                  base_config = merge_dict(
                      base_config,
                      default_configs[TEXT][
                          AUTOML_DEFAULT_TEXT_ENCODER
                      ],
                  )
  
              # TODO (ASN): add image heuristics
              if input_feature[TYPE] == IMAGE:
                  model_category = IMAGE
                  if ENCODER in input_feature:
                      base_config_input_feature[ENCODER][
                          TYPE
                      ] = AUTOML_DEFAULT_IMAGE_ENCODER
                  else:
                      base_config_input_feature[ENCODER] = {
                          TYPE: AUTOML_DEFAULT_IMAGE_ENCODER
                      }
  
          # Merge combiner config
          base_config = merge_dict(
              base_config, default_configs["combiner"]["concat"]
          )
  
      # Adjust learning rate based on other config settings
      if base_config[TRAINER]["learning_rate"] == AUTO:
          # Add a fake output feature to ensure we can load the ModelConfig, as we expect there to be at least
          # one output feature in all cases
          # TODO(travis): less hacky way to do this, we should probably allow ModelConfig to be created without output
          # features
          load_config = copy.deepcopy(base_config)
          if not load_config.get(OUTPUT_FEATURES):
              load_config[OUTPUT_FEATURES] = [
                  {"name": "fake", "type": "binary"}
              ]
          base_config[TRAINER][
              "learning_rate"
          ] = get_auto_learning_rate(ModelConfig.from_dict(load_config))
  
      # override and constrain automl config based on user specified values
      if user_config is not None:
          base_config = merge_dict(base_config, user_config)
  
          # remove all parameters from hyperparameter search that user has
          # provided explicit values for
          hyperopt_params = copy.deepcopy(
              base_config["hyperopt"]["parameters"]
          )
          for hyperopt_params in hyperopt_params.keys():
              config_section, param = (
                  hyperopt_params.split(".")[0],
                  hyperopt_params.split(".")[1],
              )
              if config_section in user_config.keys():
                  if param in user_config[config_section]:
                      del base_config["hyperopt"]["parameters"][
                          hyperopt_params
                      ]
  
      # if single output feature, set relevant metric and goal if not already set
      base_config = set_output_feature_metric(base_config)
  
      # add as initial trial in the automl search the hyperparameter settings from
      # the best model for a similar dataset and matching model type, if any.
      if use_reference_config:
          ref_configs = get_reference_configs()
          base_config = _add_transfer_config(base_config, ref_configs)
  
      return base_config, model_category, dataset_info.row_count
  
imports: import argparse
  import copy
  import logging
  import os
  import warnings
  from typing import Any, Dict, List, Optional, Union
  import numpy
  import pandas
  import yaml
  from ludwig.api import LudwigModel
  from ludwig.api_annotations import PublicAPI
  from ludwig.automl.base_config import create_default_config, DatasetInfo, get_dataset_info, get_features_config, get_reference_configs
  from ludwig.backend import Backend, initialize_backend
  from ludwig.constants import AUTO, AUTOML_DEFAULT_IMAGE_ENCODER, AUTOML_DEFAULT_TABULAR_MODEL, AUTOML_DEFAULT_TEXT_ENCODER, BINARY, CATEGORY, ENCODER, HYPEROPT, IMAGE, INPUT_FEATURES, NAME, NUMBER, OUTPUT_FEATURES, TABULAR, TEXT, TRAINER, TYPE
  from ludwig.contrib import add_contrib_callback_args
  from ludwig.data.cache.types import CacheableDataset
  from ludwig.datasets import load_dataset_uris
  from ludwig.globals import LUDWIG_VERSION
  from ludwig.hyperopt.run import hyperopt
  from ludwig.schema.model_config import ModelConfig
  from ludwig.types import ModelConfigDict
  from ludwig.utils.automl.ray_utils import _ray_init
  from ludwig.utils.automl.utils import _add_transfer_config, get_model_type, set_output_feature_metric
  from ludwig.utils.data_utils import load_dataset, use_credentials
  from ludwig.utils.defaults import default_random_seed
  from ludwig.utils.fs_utils import open_file
  from ludwig.utils.heuristics import get_auto_learning_rate
  from ludwig.utils.misc_utils import merge_dict
  from ludwig.utils.print_utils import print_ludwig
label_desc: Use image node_id 6 for calling a global function with example usage: _model_select(dataset_info, default_configs, user_config, use_reference_config) and returns: base_config,  model_category,  dataset_info