text: import itertools
  import logging
  
  from det3d.utils.config_tool import get_downsample_factor
  
  tasks = [
      dict(num_class=1, class_names=["curb"]),
  ]
  
  class_names = list(itertools.chain(*[t["class_names"] for t in tasks]))
  
  # training and testing settings
  target_assigner = dict(
      tasks=tasks,
  )
  
  # dataset settings
  dataset_type = "CurbsDataset"
  num_features = 3
  nsweeps = 10
  data_root = "/mnt/g/PointCloud DataSets/curbs/"
  
  voxel_size = [0.2, 0.2, 10]
  # voxel_size = [0.1, 0.1, 8]
  # pointcloud_range=[-51.2, -51.2, -5.0, 51.2, 51.2, 3.0]
  # pointcloud_range=[-2.0, -2.0, -2.0, 2.0, 2.0, 2.0]
  # pointcloud_range=[-8.0, -8.0, -voxel_size[2]/2, 8.0, 8.0, voxel_size[2]/2]
  pointcloud_range=[-4.0, -4.0, 0, 4.0, 4.0, voxel_size[2]]
  # pointcloud_range=[-0.5, -0.5, -voxel_size[2]/2, 0.5, 0.5, voxel_size[2]/2]
  line_max_gap = 0.001
  point_loss_weight = 1
  add_voxel_z_min = False
  
  # model settings
  model_type = "PointPillars"
  model = dict(
      type=model_type,
      pretrained=None,
      reader=dict(
          type="PillarFeatureNet",
          num_filters=[64, 64],
          num_input_features=num_features,
          with_distance = False,
          with_dist_to_min_Z = False,
          voxel_size=tuple(voxel_size),
          pc_range=tuple(pointcloud_range),
          point_encoder = "PFNLayer",
      ),
      backbone=dict(type="PointPillarsScatter", num_input_features = 64, ds_factor=1, add_voxel_z_min = add_voxel_z_min),
      neck=dict(
          type="RPN",
          layer_nums=[3, 5, 5],
          ds_layer_strides=[2, 2, 2],
          ds_num_filters=[64, 128, 256],
          us_layer_strides=[2, 4, 8],
          us_num_filters=[128, 128, 128],
          num_input_features=64,
          logger=logging.getLogger("RPN"),
      ),
      bbox_head=dict(
          # type='RPNHead',
          type="CenterHead",
          in_channels=sum([128, 128, 128])+int(add_voxel_z_min),
          share_conv_channel = 64,
          # share_conv_channel = None,
          tasks=tasks,
          weight=point_loss_weight, # heatmap loss = 1 + points xyz loss * 0.25
          code_weights = [], #[1.0, 1.0, 1.0], # x, y and z have same importance
          dataset=dataset_type,
          crit_reg = "RegLoss", # l1 loss
          # crit_reg = "EuclideanLoss",
          # crit_reg = "SmoothL1Loss",
          # crit_reg = "HuberLoss",
          # z_reg = "RegLoss",
          dcn_head = True,
          # common_heads={'reg': (2, 2), 'height': (1, 2), 'dim':(3, 2), 'rot':(2, 2), 'vel': (2, 2)}, # (output_channel, num_conv)
          common_heads={'reg':(2, 2), 'height': (1, 2)}, # (output_channel, num_conv)
          # common_heads={}, # output only heatmap
          # point shift from voxel center  == reg == xy
          # height == z
      ),
  )
  
  out_size_factor = get_downsample_factor(model)
  
  assigner = dict(
      target_assigner=target_assigner,
      out_size_factor= out_size_factor,
      gaussian_overlap=0.1,
      max_line_points=700,
      line_point_radius = 1,
      take_voxel_line_point = "middle",
      # take_voxel_line_point = "most_center",
  )
  
  train_cfg = dict(assigner=assigner)
  
  score_threshold = 0.3
  test_cfg = dict(
      post_center_limit_range=[-10, -10, -10.0, 10, 10, 10.0],
      max_per_img=500,
      nms=dict(
          nms_pre_max_size=1000,
          nms_post_max_size=83,
          nms_iou_threshold=0.2,
      ),
      score_threshold=score_threshold,
      pc_range=pointcloud_range[:2],
      out_size_factor= out_size_factor,
      voxel_size=voxel_size[:2]
  )
  
  train_preprocessor = dict(
      mode="train",
      shuffle_points=True,
      pointcloud_range = pointcloud_range,
      augmentation = True,
      Z_augmentation = False,
      offset = True,
      global_rotation_noise = [-1, 1],
      sample_random_center = False,
      class_names=class_names,
  )
  
  val_preprocessor = dict(
      mode="val",
      shuffle_points = True,
      pointcloud_range = pointcloud_range,
      augmentation = True,
      Z_augmentation = False,
      offset = False,
      sample_random_center = False,
      class_names=class_names,
  )
  
  voxel_generator = dict(
      range=pointcloud_range,
      voxel_size=voxel_size,
      max_points_in_voxel=20,
      max_voxel_num=[30000, 60000],
  )
  
  # point cloud density and point cloud cut range result in larget sample
  # if samples are to large, multi-threaded data loader craches
  pointcloud_downsampling = 0.04
  pointcloud_display_downsampling = 0.06
  cache_in_RAM = True
  max_sample_points = 200000
  min_sample_points = 1000
  
  train_pipeline = [
      # dict(type="LoadCurbPointCloudFromFile", dataset=dataset_type, downsample = pointcloud_downsampling, cache_in_RAM = cache_in_RAM),
      # dict(type="LoadCADLines", line_max_gap = line_max_gap, cache_in_RAM = cache_in_RAM),
      dict(type="PreprocessCurbs", cfg=train_preprocessor, max_sample_points = max_sample_points, min_sample_points = min_sample_points),
      dict(type="Voxelization", cfg=voxel_generator),
      dict(type="AssignVoxelCenterCurbLabel", cfg=train_cfg["assigner"]),
      dict(type="Reformat"),
  ]
  val_pipeline = [
      # dict(type="LoadCurbPointCloudFromFile", dataset=dataset_type, downsample = pointcloud_downsampling, cache_in_RAM = cache_in_RAM),
      # dict(type="LoadCADLines", line_max_gap = line_max_gap, cache_in_RAM = cache_in_RAM),
      dict(type="PreprocessCurbs", cfg=val_preprocessor, max_sample_points = max_sample_points, min_sample_points = min_sample_points),
      dict(type="Voxelization", cfg=voxel_generator),
      dict(type="AssignVoxelCenterCurbLabel", cfg=train_cfg["assigner"]),
      dict(type="Reformat"),
  ]
  
  train_anno = data_root+"/lines/"
  val_anno = data_root+"/lines/"
  test_anno = None
  
  train_samples_count = 2000
  val_samples_count = 300
  wand_upload_samples = 4
  
  samples_per_gpu = 10
  workers_per_gpu = 2
  
  data = dict(
      samples_per_gpu=samples_per_gpu,
      workers_per_gpu=workers_per_gpu,
      train=dict(
          type=dataset_type,
          num_features = num_features,
          root_path=data_root,
          info_path=train_anno,
          ann_file=train_anno,
          nsweeps=nsweeps,
          class_names=class_names,
          pipeline=train_pipeline,
          samples_count=train_samples_count,
          downsample = pointcloud_downsampling,
          sample_by_line_point_count = False,
          line_max_gap = line_max_gap,
          trim_point_cloud = not train_preprocessor['sample_random_center'],
          pc_range = pointcloud_range,
          cached_data = False
      ),
      val=dict(
          type=dataset_type,
          num_features = num_features,
          root_path=data_root,
          info_path=val_anno,
          test_mode=True,
          ann_file=val_anno,
          nsweeps=nsweeps,
          class_names=class_names,
          pipeline=val_pipeline,
          samples_count=val_samples_count,
          downsample = pointcloud_downsampling,
          line_max_gap = line_max_gap,
          sample_by_line_point_count = True,
          trim_point_cloud = not val_preprocessor['sample_random_center'],
          log_downsample = pointcloud_display_downsampling,
          pc_range = pointcloud_range,
          cached_data = True
      ),
      # test=dict(
      #     type=dataset_type,
      #     root_path=data_root,
      #     info_path=test_anno,
      #     test_mode=True,
      #     ann_file=test_anno,
      #     nsweeps=nsweeps,
      #     class_names=class_names,
      #     pipeline=val_pipeline,
      #     samples_count=5,
      # ),
  )
  
  
  optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2))
  # optimizer
  optimizer = dict(
      type="adam", amsgrad=0.0, wd=0.01, fixed_wd=True, moving_average=False,
  )
  lr_config = dict(
      type="one_cycle", lr_max=0.001, moms=[0.95, 0.85], div_factor=10.0, pct_start=0.4,
  )
  
  checkpoint_config = dict(interval=1)
  # yapf:disable
  log_config = dict(
      # interval=1,
      hooks=[
          # dict(type="TextLoggerHook", interval = 5),
          dict(type='WandbLoggerHook', interval = 1, samples_to_log = wand_upload_samples, pc_downsampling = pointcloud_display_downsampling, display_3d_voxels = True, score_threshold = score_threshold),
          # dict(type='TensorboardLoggerHook'),
      ],
  )
  
  # yapf:enable
  # runtime settings
  total_epochs = 300
  device_ids = range(1)
  dist_params = dict(backend="nccl", init_method="env://")
  log_level = "INFO"
  work_dir = './work_dirs/{}/'.format(__file__[__file__.rfind('/') + 1:-3])
  load_from = None
  resume_from = None
  
  workflow = [
      ('train', 2),
      ('val', 1)
  ]