code: def check_types(
      config: ModelConfigDict,
      input_features: List[FeatureConfigDict],
      output_features: List[FeatureConfigDict],
  ):
      actual_features = config.get(INPUT_FEATURES, []) + config.get(
          OUTPUT_FEATURES, []
      )
      expected_features = {
          f[NAME]: f for f in input_features + output_features
      }
      assert len(actual_features) == len(expected_features)
      for actual_feature in actual_features:
          expected_feature = expected_features[actual_feature[NAME]]
          assert (
              actual_feature[TYPE] == expected_feature[TYPE]
          ), f"{actual_feature[NAME]}: actual type {actual_feature[TYPE]} != {expected_feature[TYPE]}"
  
imports: import os
  import tempfile
  from typing import List, Set
  from unittest import mock
  import numpy
  import pandas
  import pytest
  from ludwig.api import LudwigModel
  from ludwig.constants import COLUMN, ENCODER, INPUT_FEATURES, NAME, OUTPUT_FEATURES, PREPROCESSING, SPLIT, TYPE
  from ludwig.schema.model_types.base import ModelConfig
  from ludwig.types import FeatureConfigDict, ModelConfigDict
  from ludwig.utils.misc_utils import merge_dict
  from tests.integration_tests.utils import binary_feature, category_feature, generate_data, image_feature, minio_test_creds, number_feature, private_param, remote_tmpdir, text_feature
  import dask.dataframe
  from ray.tune.experiment.trial import Trial
  from ludwig.automl import auto_train, create_auto_config, train_with_config
  from ludwig.automl.automl import OUTPUT_DIR
  from ludwig.hyperopt.execution import RayTuneExecutor
label_desc: Use image node_id 4 for calling a global function with example usage: check_types(config, input_features, output_features) without return types