pybaseutils 2.0.6__tar.gz → 2.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/PKG-INFO +1 -1
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/__init__.py +1 -1
- pybaseutils-2.0.8/pybaseutils/dataloader/balanced_classes.py +222 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/base_coco.py +1 -1
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/base_dataset.py +2 -2
- pybaseutils-2.0.8/pybaseutils/dataloader/data_resample.py +220 -0
- pybaseutils-2.0.8/pybaseutils/dataloader/parser_image_folder.py +103 -0
- pybaseutils-2.0.8/pybaseutils/dataloader/parser_image_text.py +268 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_labelme.py +1 -1
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_voc.py +1 -1
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_yolo.py +2 -2
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/file_utils.py +55 -15
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/image_utils.py +19 -14
- pybaseutils-2.0.8/pybaseutils/text_utils.py +197 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils.egg-info/PKG-INFO +1 -1
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils.egg-info/SOURCES.txt +5 -1
- pybaseutils-2.0.8/test_py/converter/get_pair_data.py +17 -0
- pybaseutils-2.0.8/test_py/demo2.py +24 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_lableme_vis.py +2 -2
- pybaseutils-2.0.6/test_py/converter/get_pair_data.py +0 -57
- pybaseutils-2.0.6/test_py/demo2.py +0 -29
- pybaseutils-2.0.6/test_py/edit_distance/text_utils.py +0 -241
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/LICENCE +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/README.md +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/audio/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/audio/audio_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/audio/pyaudio_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/audio/vad_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/base64_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/batch_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/build_utils/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/build_utils/cython_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/build_utils/pyarmor_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cluster/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cluster/kmean.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cluster/maxmin_distance.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cluster/similarity.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/color_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/config_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/build_coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/build_cvat.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/build_labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/build_voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/concat_coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_coco2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_coco2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_cvat2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_labelme2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_labelme2cvat.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_labelme2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_labelme2yolo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_voc2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_voc2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_voc2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_voc2yolo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/converter/convert_yolo2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/coords_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cvutils/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cvutils/corner_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cvutils/monitor.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cvutils/mouse_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/cvutils/video_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_coco_det.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_coco_ins.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/parser_coco_kps.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/dataloader/voc_seg_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/QueueTable.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/kalman_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/mean_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/motion_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/filter/pose_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/font_style/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/font_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/geometry_tools.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/heatmap_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/json_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/log.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/logger.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/accuracy.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/average_meter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/class_report.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/plot_pr.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/metrics/plot_roc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/numpy_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pandas_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/plot_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pose/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pose/bones_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pose/human_pose.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pose/pose_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pycpp/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pycpp/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/pycpp/main.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/server/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/server/apm_server.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/setup_config.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/singleton_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/thread_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/time_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracemalloc_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracemalloc_utils2.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/QueueTable.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/kalman_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/mean_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/motion_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/tracking/pose_filter.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/transforms/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/transforms/affine_transform.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/transforms/augment_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/transforms/face_alignment.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/transforms/transform_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/word_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/worker.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils/yaml_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils.egg-info/dependency_links.txt +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils.egg-info/not-zip-safe +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/pybaseutils.egg-info/top_level.txt +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/setup.cfg +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/setup.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/WebCrawler/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/WebCrawler/search_image.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/WebCrawler/search_image_for_baidu.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/action_dataset.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/build_cython.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/build_pyarmor.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/build_service.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/convert_cvat2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/convert_labelme2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/convert_labelme2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/copy_move.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/demo_labelme_crop.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/demo_video_aije.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/demo_voc_crop.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/demo_voc_vis.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/aije/video_convertor.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/main.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/main_read.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/segment.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/speechbrain_asr_indoor_prod.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/audio/speechbrain_demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/captcha/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/captcha/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/class_attribute.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/class_names.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/AffectNet.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/AsianMovie.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/BITVehicle2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/BSTLD2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/CCPD.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/CCPD2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/FL3D_dataset.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/FreiHAND2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/MTFL2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/TT100K.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/WaterMeters1.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/WaterMeters2.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/concat_coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_coco2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_cvat2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_gesture2hand.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_labelme2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_labelme2cvat.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_labelme2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/convert_voc2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/fatigue_driving.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/fdd_dataset.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/handpose2coco.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/insects_for_aichallenger.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/tt100k_utils.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/ua_detrac2voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/ucf101_dataset.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/converter/voc_sbd2labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/build_cython.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/build_pyarmor.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/cryptography_demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/fun_sum.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/main.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/model_des_enctypt.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/cython_build/model_enctypt.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo1.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo3.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_async_await1.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_async_await2.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_coco_vis.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_copy_files.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_copy_files_for_voc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_ffmpy.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_for_pair_file.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_for_polygon.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_for_trt.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_get_file_list.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_gif.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_gif_video.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_image_crop.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_kpts.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_labelme_crop.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_metrics.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_mouse.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_nii.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_pandas.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_plot.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_rename.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_standard_image .py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_standard_video .py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_taichi.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_video.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_voc_crop.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_voc_vis.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_word_similar.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_worker1.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/demo_worker2.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/detector/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/detector/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/detector/detect_face_person.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/detector/predet_labelme.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/edit_distance/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/edit_distance/demo.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/edit_distance/text_matching.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/flask_demo/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/flask_demo/func.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/flask_demo/server.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/image_correction/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/image_correction/demo_correction_v1.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/image_correction/demo_correction_v2.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/image_correction/demo_correction_v3.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/kafka_worker.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/men_tracemalloc.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/performance.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/pose/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/pose/human_pose.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/registry/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/registry/base.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/registry/component.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/registry/main.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/registry/register.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/test_fr/__init__.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/test_fr/demo11.py +0 -0
- {pybaseutils-2.0.6 → pybaseutils-2.0.8}/test_py/test_fr/idcardocr.py +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# -*-coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@Author : panjq
|
|
4
|
+
@E-mail : pan_jinquan@163.com
|
|
5
|
+
@Date : 2019-11-18 14:08:46
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
8
|
+
import math
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_torch_sample(weights,
|
|
12
|
+
num_samples: int,
|
|
13
|
+
replacement: bool = True,
|
|
14
|
+
generator=None):
|
|
15
|
+
'''
|
|
16
|
+
https://blog.csdn.net/caihuanqia/article/details/113258690
|
|
17
|
+
:param weights:weights参数对应的是“样本”的权重而不是“类别的权重”,权重越大,采样次数更多
|
|
18
|
+
:param num_samples:
|
|
19
|
+
:param replacement:
|
|
20
|
+
:param generator:
|
|
21
|
+
:return:
|
|
22
|
+
'''
|
|
23
|
+
import torch.utils.data as torch_utils
|
|
24
|
+
sampler = torch_utils.sampler.WeightedRandomSampler(weights, len(weights))
|
|
25
|
+
return sampler
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def class_weight_to_sample_weight(labels_list: list, class_weight: dict):
|
|
29
|
+
'''
|
|
30
|
+
:param labels_list:lable必须从0开始的,连续的int类型
|
|
31
|
+
:param class_weight:
|
|
32
|
+
:return:
|
|
33
|
+
'''
|
|
34
|
+
sample_weight = [0] * len(labels_list)
|
|
35
|
+
for idx, name in enumerate(labels_list):
|
|
36
|
+
sample_weight[idx] = class_weight[name]
|
|
37
|
+
return sample_weight
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def count_class_samples_nums(labels_list):
|
|
41
|
+
'''
|
|
42
|
+
classes_dict = {cls_id0: nums_of_id0,cls_id1: nums_of_id1,...,}
|
|
43
|
+
classes_dict = {0: 5,1: 5, 2: 2, 3: 2, 4: 4}
|
|
44
|
+
=========
|
|
45
|
+
# nclasses = len(set(labels_list)) # fix a BUG
|
|
46
|
+
nclasses = max(labels_list) + 1
|
|
47
|
+
count = [0] * nclasses
|
|
48
|
+
for name in labels_list:
|
|
49
|
+
count[name] += 1 # item is (img-data, label-id)
|
|
50
|
+
classes_dict = dict(enumerate(count))
|
|
51
|
+
=========
|
|
52
|
+
:param labels_list:lable必须从0开始的,连续的int类型
|
|
53
|
+
:return:
|
|
54
|
+
'''
|
|
55
|
+
count_class = {}
|
|
56
|
+
for name in labels_list:
|
|
57
|
+
try:
|
|
58
|
+
count_class[name] += 1
|
|
59
|
+
except Exception as e:
|
|
60
|
+
count_class[name] = 1
|
|
61
|
+
return count_class
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def create_class_sample_weight_sklearn(labels_list: list, balanced='balanced', weight_type="class_weight"):
|
|
65
|
+
'''
|
|
66
|
+
balanced : dict, 'balanced' or None
|
|
67
|
+
If 'balanced', class weights will be given by
|
|
68
|
+
``n_samples / (n_classes * np.bincount(lt_steps))``.
|
|
69
|
+
If a dictionary is given, keys are classes and values are corresponding class weights.
|
|
70
|
+
If None
|
|
71
|
+
:param labels_list: lable必须从0开始的,连续的int类型
|
|
72
|
+
:param balanced:dict, 'balanced' or None
|
|
73
|
+
If 'balanced', class weights will be given by
|
|
74
|
+
``n_samples / (n_classes * np.bincount(lt_steps))``.
|
|
75
|
+
If a dictionary is given, keys are classes and values
|
|
76
|
+
are corresponding class weights.
|
|
77
|
+
If None is given, the class weights will be uniform.
|
|
78
|
+
:param weight_type: class_weight or sample_weight
|
|
79
|
+
:return:
|
|
80
|
+
'''
|
|
81
|
+
import sklearn
|
|
82
|
+
classes = np.unique(labels_list)
|
|
83
|
+
weight_list = sklearn.utils.class_weight.compute_class_weight(balanced,
|
|
84
|
+
classes,
|
|
85
|
+
labels_list)
|
|
86
|
+
if weight_type == "class_weight":
|
|
87
|
+
class_weight = dict(zip([x for x in classes], weight_list))
|
|
88
|
+
return class_weight
|
|
89
|
+
elif weight_type == "sample_weight":
|
|
90
|
+
class_weight = dict(zip([x for x in classes], weight_list))
|
|
91
|
+
sample_weight = class_weight_to_sample_weight(labels_list, class_weight)
|
|
92
|
+
return sample_weight
|
|
93
|
+
else:
|
|
94
|
+
return weight_list
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def create_class_sample_weight_custom(labels_list, balanced="balanced", weight_type="class_weight"):
|
|
98
|
+
'''
|
|
99
|
+
|
|
100
|
+
:param labels_list:lable必须从0开始的,连续的int类型
|
|
101
|
+
:param balanced:
|
|
102
|
+
:param weight_type: class_weight:返回每个classs的权重
|
|
103
|
+
sample_weight:返回每个labels_list对应的权重
|
|
104
|
+
:param mu:
|
|
105
|
+
:return:
|
|
106
|
+
'''
|
|
107
|
+
count_class = count_class_samples_nums(labels_list)
|
|
108
|
+
n_samples = np.sum(list(count_class.values()))
|
|
109
|
+
classes = count_class.keys()
|
|
110
|
+
n_classes = len(classes)
|
|
111
|
+
class_weight = dict()
|
|
112
|
+
weight = sum(class_weight.values())
|
|
113
|
+
# 计算每个类别的权重:样本越少,权重越大
|
|
114
|
+
for cls in classes:
|
|
115
|
+
cls_num = float(count_class[cls])
|
|
116
|
+
if balanced == "log_balanced":
|
|
117
|
+
mu = 0.15
|
|
118
|
+
score = math.log(mu * n_samples / cls_num)
|
|
119
|
+
class_weight[cls] = score if score > 1.0 else 1.0
|
|
120
|
+
elif balanced == "balanced":
|
|
121
|
+
# score = n_samples / (n_classes * np.bincount(lt_steps))
|
|
122
|
+
score = n_samples / (n_classes * cls_num)
|
|
123
|
+
class_weight[cls] = score
|
|
124
|
+
elif balanced == "auto":
|
|
125
|
+
# N / float(count[i])
|
|
126
|
+
score = n_samples / cls_num
|
|
127
|
+
class_weight[cls] = score
|
|
128
|
+
else:
|
|
129
|
+
raise Exception("Error:{}".format(balanced))
|
|
130
|
+
# loss_weight = {k: v / weight for k, v in class_weight.items()}
|
|
131
|
+
if weight_type == "class_weight":
|
|
132
|
+
return class_weight
|
|
133
|
+
elif weight_type == "sample_weight":
|
|
134
|
+
sample_weight = class_weight_to_sample_weight(labels_list, class_weight)
|
|
135
|
+
return sample_weight
|
|
136
|
+
else:
|
|
137
|
+
raise Exception("Error:{}".format(weight_type))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def create_sample_weight_torch(labels_list, nclasses=None):
|
|
141
|
+
'''
|
|
142
|
+
Make a vector of weights for each image in the dataset, based
|
|
143
|
+
on class frequency. The returned vector of weights can be used
|
|
144
|
+
to create a WeightedRandomSampler for a DataLoader to have
|
|
145
|
+
class balancing when sampling for a training batch.
|
|
146
|
+
images - torchvisionDataset.imgs
|
|
147
|
+
nclasses - len(torchvisionDataset.classes)
|
|
148
|
+
https://discuss.pytorch.org/t/balanced-sampling-between-classes-with-torchvision-dataloader/2703/3
|
|
149
|
+
labels_list = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4]
|
|
150
|
+
weight =[3.6, 3.6, 3.6, 3.6, 3.6, 3.6, 3.6, 3.6, 3.6, 3.6, 9.0, 9.0, 9.0, 9.0, 4.5, 4.5, 4.5, 4.5]
|
|
151
|
+
'''
|
|
152
|
+
if not nclasses:
|
|
153
|
+
nclasses = len(set(labels_list))
|
|
154
|
+
classes_dict = count_class_samples_nums(labels_list)
|
|
155
|
+
count = list(classes_dict.values())
|
|
156
|
+
weight_per_class = [0.] * nclasses
|
|
157
|
+
N = float(sum(count)) # total number of images
|
|
158
|
+
for i in range(nclasses):
|
|
159
|
+
weight_per_class[i] = N / float(count[i])
|
|
160
|
+
weight = [0] * len(labels_list)
|
|
161
|
+
for idx, name in enumerate(labels_list):
|
|
162
|
+
weight[idx] = weight_per_class[name]
|
|
163
|
+
|
|
164
|
+
return weight
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def keras_example(class_weight, sample_weight):
|
|
168
|
+
'''
|
|
169
|
+
在keras,fit函数中调用class_weight,可以通过字典设置每个类别输入权重,比如:cw = {0: 1, 1: 25},
|
|
170
|
+
类别序列可以使用.class_indices获取。
|
|
171
|
+
:param model:
|
|
172
|
+
:param class_weight: Optional dictionary mapping class indices (integers)
|
|
173
|
+
to a weight (float) value, used for weighting the loss function
|
|
174
|
+
(during training only).
|
|
175
|
+
This can be useful to tell the model to
|
|
176
|
+
"pay more attention" to samples from
|
|
177
|
+
an under-represented class.
|
|
178
|
+
:param sample_weight: type->numpy array,用于在训练时调整损失函数(仅用于训练)。
|
|
179
|
+
可以传递一个1D的与样本等长的向量用于对样本进行1对1的加权,或者在面对时序数据时,
|
|
180
|
+
传递一个的形式为(samples,sequence_length)的矩阵来为每个时间步上的样本赋不同的权。
|
|
181
|
+
这种情况下请确定在compile时添加了sample_weight_mode=‘temporal’。
|
|
182
|
+
1.sample_weight会覆盖class_weight,所以二者用其一;
|
|
183
|
+
2.如果仅仅是类不平衡,则使用class_weight,sample_weights则是类内样本之间还不平衡的时候使用。
|
|
184
|
+
3.keras已经在新版本中加入了 class_weight = ‘auto’。
|
|
185
|
+
设置了这个参数后,keras会自动设置class weight让每类的sample对损失的贡献相等。
|
|
186
|
+
4.在设置类别权重的时候,类别序列可以使用train_generator.class_indices获取。
|
|
187
|
+
:return:
|
|
188
|
+
'''
|
|
189
|
+
import tensorflow as tf
|
|
190
|
+
train_dataset = ...
|
|
191
|
+
steps_per_epoch = ...
|
|
192
|
+
model = tf.keras.models.Sequential([
|
|
193
|
+
tf.keras.layers.Dense(512, activation=None, name="fc1")
|
|
194
|
+
])
|
|
195
|
+
model.compile(optimizer='adam',
|
|
196
|
+
loss='sparse_categorical_crossentropy',
|
|
197
|
+
metrics=['accuracy'])
|
|
198
|
+
model.fit(train_dataset,
|
|
199
|
+
steps_per_epoch=steps_per_epoch,
|
|
200
|
+
sample_weight=sample_weight,
|
|
201
|
+
class_weight='auto')
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
if __name__ == "__main__":
|
|
205
|
+
# random labels_dict
|
|
206
|
+
# labels_dict = {0: 2813, 1: 78, 2: 2814, 3: 78, 4: 7914, 5: 248, 6: 7914, 7: 248}
|
|
207
|
+
labels_list = [4, 1, 2, 3, 2, 3, 3, 4, 4, 4, 0]
|
|
208
|
+
print("create_class_sample_weight_custom-------------------------")
|
|
209
|
+
w1 = create_class_sample_weight_custom(labels_list, balanced="balanced", weight_type="class_weight")
|
|
210
|
+
w2 = create_class_sample_weight_custom(labels_list, balanced="balanced", weight_type="sample_weight")
|
|
211
|
+
print("class_weight :{}".format(w1))
|
|
212
|
+
print("labels_list :{}".format(labels_list))
|
|
213
|
+
print("sample_weight:{}".format(w2))
|
|
214
|
+
print("create_class_sample_weight_sklearn-------------------------")
|
|
215
|
+
w2 = create_class_sample_weight_sklearn(labels_list, balanced="balanced", weight_type="class_weight")
|
|
216
|
+
w3 = create_class_sample_weight_sklearn(labels_list, balanced="balanced", weight_type="sample_weight")
|
|
217
|
+
print("class_weight :{}".format(w2))
|
|
218
|
+
print("labels_list :{}".format(labels_list))
|
|
219
|
+
print("sample_weight:{}".format(w3))
|
|
220
|
+
# print(class_weight_to_sample_weight(labels_list, w2))
|
|
221
|
+
# w3 = create_sample_weight_torch(labels_list, nclasses=5)
|
|
222
|
+
# print(w3)
|
|
@@ -200,7 +200,7 @@ class CocoDataset(object):
|
|
|
200
200
|
:return:
|
|
201
201
|
"""
|
|
202
202
|
if isinstance(class_name, str):
|
|
203
|
-
class_name = Dataset.
|
|
203
|
+
class_name = Dataset.read_file(class_name)
|
|
204
204
|
elif isinstance(class_name, list) and "unique" in class_name:
|
|
205
205
|
self.unique = True
|
|
206
206
|
if isinstance(class_name, list) and len(class_name) > 0:
|
|
@@ -66,7 +66,7 @@ class Dataset(object):
|
|
|
66
66
|
:return:
|
|
67
67
|
"""
|
|
68
68
|
if isinstance(class_name, str):
|
|
69
|
-
class_name = Dataset.
|
|
69
|
+
class_name = Dataset.read_file(class_name)
|
|
70
70
|
elif isinstance(class_name, list) and "unique" in class_name:
|
|
71
71
|
self.unique = True
|
|
72
72
|
if isinstance(class_name, list) and len(class_name) > 0:
|
|
@@ -109,7 +109,7 @@ class Dataset(object):
|
|
|
109
109
|
return json_data
|
|
110
110
|
|
|
111
111
|
@staticmethod
|
|
112
|
-
def
|
|
112
|
+
def read_file(filename, split=None):
|
|
113
113
|
"""
|
|
114
114
|
:param filename:
|
|
115
115
|
:param split:分割
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# -*-coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@Author : Pan
|
|
4
|
+
@E-mail :
|
|
5
|
+
@Date : 2021-04-21 09:41:34
|
|
6
|
+
"""
|
|
7
|
+
import random
|
|
8
|
+
import numpy as np
|
|
9
|
+
import math
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ResampleExample(object):
|
|
13
|
+
"""样本均衡,重采样DataResampler的使用方法"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, item_list, label_index=1, shuffle=True, disp=False):
|
|
16
|
+
"""
|
|
17
|
+
:param item_list: item_list=[item_0,item_1,...,item_n],
|
|
18
|
+
item_n= [path/to/image,label]
|
|
19
|
+
:param label_index: label在item_n的index
|
|
20
|
+
:param disp: 是否打印log信息
|
|
21
|
+
"""
|
|
22
|
+
self.disp = disp
|
|
23
|
+
self.shuffle = shuffle
|
|
24
|
+
self.item_list = item_list
|
|
25
|
+
self.resampler = DataResample(self.item_list,
|
|
26
|
+
label_index=label_index,
|
|
27
|
+
shuffle=self.shuffle,
|
|
28
|
+
disp=self.disp)
|
|
29
|
+
|
|
30
|
+
def __len__(self):
|
|
31
|
+
# 更新resampler,实现每个epoch重新采样,避免样本数比较多的类别,没有加入训练
|
|
32
|
+
self.item_list = self.resampler.update(self.shuffle)
|
|
33
|
+
return len(self.item_list)
|
|
34
|
+
|
|
35
|
+
def __getitem__(self, idx):
|
|
36
|
+
image_path = self.item_list[idx][0]
|
|
37
|
+
label_id = self.item_list[idx][1]
|
|
38
|
+
return image_path, label_id
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DataResample(object):
|
|
42
|
+
"""样本均衡,重采样的方法"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, item_list=[], label_index=1, balance="mean", shuffle=True, disp=False):
|
|
45
|
+
"""
|
|
46
|
+
Usage:
|
|
47
|
+
参考:ResampleExample例子的使用方法
|
|
48
|
+
:param item_list:
|
|
49
|
+
:param label_index:
|
|
50
|
+
:param balance:实现样本均衡策略,均衡力度:mean > log > sqrt > y
|
|
51
|
+
"y": 每个label样本数跟原来一样
|
|
52
|
+
"sqrt": 每个label样本取sqrt数,实现样本均衡
|
|
53
|
+
"log": 每个label样本取log数,实现样本均衡
|
|
54
|
+
"mean": 每个label样本取样本平均数,每个label的个数一样
|
|
55
|
+
"""
|
|
56
|
+
self.src_item_list = item_list
|
|
57
|
+
self.label_index = label_index
|
|
58
|
+
self.balance = balance
|
|
59
|
+
self.shuffle = shuffle
|
|
60
|
+
self.disp = disp
|
|
61
|
+
self.class_count = self.get_class_count(self.src_item_list, label_index)
|
|
62
|
+
self.class_item_dict = self.get_class_item_dict(self.src_item_list, label_index)
|
|
63
|
+
self.balance_nums = self.get_balance_nums(self.class_count, self.balance)
|
|
64
|
+
self.item_list = self.update(shuffle=self.shuffle)
|
|
65
|
+
self.class_weight = self.get_class_weight(self.class_count)
|
|
66
|
+
|
|
67
|
+
def __len__(self):
|
|
68
|
+
self.update(shuffle=self.shuffle)
|
|
69
|
+
return len(self.item_list)
|
|
70
|
+
|
|
71
|
+
def update(self, shuffle=False):
|
|
72
|
+
self.item_list = self.get_resample_data(shuffle=shuffle)
|
|
73
|
+
return self.item_list
|
|
74
|
+
|
|
75
|
+
def get_resample_data(self, shuffle=True):
|
|
76
|
+
"""
|
|
77
|
+
获得重采样的数据
|
|
78
|
+
:param item_list:
|
|
79
|
+
:param label_index:
|
|
80
|
+
:param shuffle:
|
|
81
|
+
:return:
|
|
82
|
+
"""
|
|
83
|
+
if self.disp:
|
|
84
|
+
print("class_item_dict:{}".format({k: len(v) for k, v in self.class_item_dict.items()}))
|
|
85
|
+
out_list = []
|
|
86
|
+
for name, per_class_list in self.class_item_dict.items():
|
|
87
|
+
nums = self.balance_nums[name]
|
|
88
|
+
per_list = self.get_sampler(per_class_list, nums, shuffle=shuffle)
|
|
89
|
+
out_list += per_list
|
|
90
|
+
if shuffle:
|
|
91
|
+
random.shuffle(out_list)
|
|
92
|
+
if self.disp:
|
|
93
|
+
# 统计每个类别的个数
|
|
94
|
+
class_count = self.get_class_count(out_list, self.label_index)
|
|
95
|
+
print("resampler count_class :{},total:{}".format(class_count, sum(class_count.values())))
|
|
96
|
+
return out_list
|
|
97
|
+
|
|
98
|
+
def get_balance_nums(self, class_count: dict, balance):
|
|
99
|
+
"""
|
|
100
|
+
获得平衡后,每个样本的数目
|
|
101
|
+
:param class_count:
|
|
102
|
+
:param balance:
|
|
103
|
+
:return:
|
|
104
|
+
"""
|
|
105
|
+
class_name = list(class_count.keys())
|
|
106
|
+
num_samples = sum(class_count.values()) # 总样本数目
|
|
107
|
+
if balance == "mean":
|
|
108
|
+
mean_samples = num_samples * 1.0 / len(class_name) # 平均样本数
|
|
109
|
+
balance_nums = {name: mean_samples for name, c in class_count.items()}
|
|
110
|
+
elif balance == "log":
|
|
111
|
+
# Fix Bug:c=1
|
|
112
|
+
balance_nums = {name: np.log(c + 1) for name, c in class_count.items()}
|
|
113
|
+
elif balance == "sqrt":
|
|
114
|
+
# Fix Bug:c=0
|
|
115
|
+
balance_nums = {name: np.sqrt(c + 1) for name, c in class_count.items()}
|
|
116
|
+
elif balance == "y":
|
|
117
|
+
balance_nums = {name: c for name, c in class_count.items()}
|
|
118
|
+
else:
|
|
119
|
+
raise Exception("Error:{}".format(balance))
|
|
120
|
+
sum_balance = sum(balance_nums.values())
|
|
121
|
+
balance_nums = {name: math.ceil(c / sum_balance * num_samples) for name, c in balance_nums.items()}
|
|
122
|
+
return balance_nums
|
|
123
|
+
|
|
124
|
+
def get_sampler(self, item_list, nums, shuffle=True):
|
|
125
|
+
"""
|
|
126
|
+
提取nums个数,不足nums个时,会进行填充
|
|
127
|
+
:param item_list: 输入样本列表
|
|
128
|
+
:param nums: 需要提取的样本数目
|
|
129
|
+
:param shuffle: 是否随机提取样本
|
|
130
|
+
:return:
|
|
131
|
+
"""
|
|
132
|
+
item_nums = len(item_list)
|
|
133
|
+
if nums > item_nums:
|
|
134
|
+
item_list = item_list * math.ceil(nums / item_nums)
|
|
135
|
+
if shuffle:
|
|
136
|
+
random.shuffle(item_list)
|
|
137
|
+
out_list = item_list[:nums]
|
|
138
|
+
return out_list
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def get_label_list(item_list, label_index):
|
|
142
|
+
labels_list = []
|
|
143
|
+
for item in item_list:
|
|
144
|
+
label = item[label_index]
|
|
145
|
+
labels_list.append(label)
|
|
146
|
+
return labels_list
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def get_class_item_dict(item_list, label_index):
|
|
150
|
+
"""
|
|
151
|
+
获得每一类的样本
|
|
152
|
+
:param item_list:
|
|
153
|
+
:return:
|
|
154
|
+
"""
|
|
155
|
+
class_item_dict = {}
|
|
156
|
+
for item in item_list:
|
|
157
|
+
label = item[label_index]
|
|
158
|
+
try:
|
|
159
|
+
# if label in class_item_dict: # 比较慢,相当于需要查询label是否存在
|
|
160
|
+
class_item_dict[label] += [item]
|
|
161
|
+
except Exception as e:
|
|
162
|
+
class_item_dict[label] = [item]
|
|
163
|
+
return class_item_dict
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def get_class_count(item_list, label_index):
|
|
167
|
+
"""
|
|
168
|
+
统计每个类别的个数
|
|
169
|
+
:param item_list:
|
|
170
|
+
:param label_index: label在item中的序号
|
|
171
|
+
:return:
|
|
172
|
+
"""
|
|
173
|
+
class_count = {}
|
|
174
|
+
for item in item_list:
|
|
175
|
+
label = item[label_index]
|
|
176
|
+
try:
|
|
177
|
+
# if label in class_count: # 比较慢,相当于需要查询label是否存在
|
|
178
|
+
class_count[label] += 1
|
|
179
|
+
except Exception as e:
|
|
180
|
+
class_count[label] = 1
|
|
181
|
+
return class_count
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def get_class_weight(class_count: dict):
|
|
185
|
+
"""
|
|
186
|
+
计算每个label的权重,类别越少,权重越大
|
|
187
|
+
:param class_count:
|
|
188
|
+
:return:
|
|
189
|
+
"""
|
|
190
|
+
n_samples = sum(list(class_count.values()))
|
|
191
|
+
class_weight = {}
|
|
192
|
+
for cls, num in class_count.items():
|
|
193
|
+
score = n_samples / num
|
|
194
|
+
class_weight[cls] = score
|
|
195
|
+
return class_weight
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
from torch.utils.data import Dataset, DataLoader, Sampler
|
|
200
|
+
from utils import torch_tools
|
|
201
|
+
|
|
202
|
+
torch_tools.set_env_random_seed()
|
|
203
|
+
label0 = [["0.1.jpg", 0], ["0.2.jpg", 0], ["0.3.jpg", 0]]
|
|
204
|
+
label1 = [["1.jpg", 1]] * 5
|
|
205
|
+
label2 = [["2.0.jpg", 2], ["2.1.jpg", 2], ["2.2.jpg", 2], ["2.3.jpg", 2], ["2.4.jpg", 2],
|
|
206
|
+
["2.5.jpg", 2], ["2.6.jpg", 2], ["2.7.jpg", 2], ["2.8.jpg", 2]]
|
|
207
|
+
label3 = [["3.1.jpg", 3], ["3.2.jpg", 3], ["3.3.jpg", 3]]
|
|
208
|
+
item_list = label0 + label1 + label2 + label3
|
|
209
|
+
item_list = item_list * 1000000
|
|
210
|
+
print("have item_list:{}".format(len(item_list)))
|
|
211
|
+
dataset_train = ResampleExample(item_list=item_list, label_index=1, shuffle=True, disp=True)
|
|
212
|
+
# dataset_train = ResampleExample(item_list=item_list, label_index=1, disp=False)
|
|
213
|
+
# dataset_train = ResampleExample(item_list=item_list, label_index=1, disp=False)
|
|
214
|
+
batch_size = 4
|
|
215
|
+
dataloader = DataLoader(dataset_train, batch_size, num_workers=0)
|
|
216
|
+
epochs = 2
|
|
217
|
+
for epoch in range(epochs):
|
|
218
|
+
print("{}===".format(epoch) * 10)
|
|
219
|
+
for batch_image, batch_label in iter(dataloader):
|
|
220
|
+
print(batch_image, batch_label)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# --------------------------------------------------------
|
|
4
|
+
# @Author : panjq
|
|
5
|
+
# @Date : 2019-9-20 13:18:34
|
|
6
|
+
# --------------------------------------------------------
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import cv2
|
|
11
|
+
import PIL.Image as Image
|
|
12
|
+
import numpy as np
|
|
13
|
+
import random
|
|
14
|
+
from pybaseutils import image_utils, file_utils
|
|
15
|
+
from pybaseutils.dataloader import parser_image_text
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FolderDataset(parser_image_text.TextDataset):
|
|
19
|
+
def __init__(self, image_dir, class_name=None, transform=None, use_rgb=False, shuffle=False,
|
|
20
|
+
phase="test", disp=False, check=False, **kwargs):
|
|
21
|
+
"""
|
|
22
|
+
:param image_dir: [image_dir]->list or `path/to/image_dir`->str
|
|
23
|
+
:param class_name:
|
|
24
|
+
:param transform: torch transform
|
|
25
|
+
:param shuffle:
|
|
26
|
+
:param disp:
|
|
27
|
+
"""
|
|
28
|
+
super(FolderDataset, self).__init__(filename=image_dir,
|
|
29
|
+
data_root=None,
|
|
30
|
+
class_name=class_name,
|
|
31
|
+
transform=transform,
|
|
32
|
+
shuffle=shuffle,
|
|
33
|
+
use_rgb=use_rgb,
|
|
34
|
+
phase=phase,
|
|
35
|
+
disp=disp,
|
|
36
|
+
check=check,
|
|
37
|
+
**kwargs)
|
|
38
|
+
|
|
39
|
+
def __getitem__(self, index):
|
|
40
|
+
"""
|
|
41
|
+
:param index:
|
|
42
|
+
:return: image,label
|
|
43
|
+
"""
|
|
44
|
+
item = self.item_list[index]
|
|
45
|
+
bbox = item[2:] if len(item) == 6 else []
|
|
46
|
+
image_file, label = item[0], item[1]
|
|
47
|
+
image = self.read_image(image_file, use_rgb=self.use_rgb)
|
|
48
|
+
image = self.crop_image(image, bbox=bbox) if bbox else image
|
|
49
|
+
if self.transform:
|
|
50
|
+
image = Image.fromarray(image)
|
|
51
|
+
image = self.transform(image)
|
|
52
|
+
if image is None:
|
|
53
|
+
index = int(random.uniform(0, self.num_images))
|
|
54
|
+
return self.__getitem__(index)
|
|
55
|
+
return {"image": image, "label": label}
|
|
56
|
+
|
|
57
|
+
def load_dataset(self, filename, data_root="", use_sub=False):
|
|
58
|
+
"""
|
|
59
|
+
保存格式:[path,label] 或者 [path,label,xmin,ymin,xmax,,ymax]
|
|
60
|
+
:param filename:
|
|
61
|
+
:param data_root:
|
|
62
|
+
:return: item_list [path,label] 或者 [path,label,xmin,ymin,xmax,,ymax]
|
|
63
|
+
"""
|
|
64
|
+
if isinstance(filename, str): filename = [filename]
|
|
65
|
+
item_list = []
|
|
66
|
+
for i, dir in enumerate(filename):
|
|
67
|
+
print("loading image from:{}".format(dir))
|
|
68
|
+
if not os.path.exists(dir): raise Exception("image_dir:{}".format(dir))
|
|
69
|
+
paths, labels = file_utils.get_files_labels(dir, postfix=file_utils.IMG_POSTFIX)
|
|
70
|
+
# TODO # 避免多个数据集的相同的label
|
|
71
|
+
if use_sub: labels = [os.path.join(str(i), l) for l in labels]
|
|
72
|
+
data = [[p, l] for p, l in zip(paths, labels)]
|
|
73
|
+
item_list += data
|
|
74
|
+
return item_list
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
from pybaseutils import image_utils
|
|
79
|
+
from torchvision import transforms
|
|
80
|
+
|
|
81
|
+
image_dir = ['/home/PKing/nasdata/release/infrastructure/DMClassification/data/dataset/train']
|
|
82
|
+
input_size = [224, 224]
|
|
83
|
+
rgb_mean = [0., 0., 0.]
|
|
84
|
+
rgb_std = [1.0, 1.0, 1.0]
|
|
85
|
+
transform = transforms.Compose([
|
|
86
|
+
transforms.Resize(input_size),
|
|
87
|
+
transforms.ToTensor(),
|
|
88
|
+
transforms.Normalize(mean=rgb_mean, std=rgb_std),
|
|
89
|
+
])
|
|
90
|
+
dataset = FolderDataset(image_dir=image_dir,
|
|
91
|
+
transform=transform,
|
|
92
|
+
shuffle=True,
|
|
93
|
+
class_name=None,
|
|
94
|
+
resample=True,
|
|
95
|
+
disp=True)
|
|
96
|
+
for i in range(len(dataset)):
|
|
97
|
+
data_info = dataset.__getitem__(i)
|
|
98
|
+
image, label = data_info["image"], data_info["label"]
|
|
99
|
+
image = np.asarray(image).transpose(1, 2, 0) # 通道由[c,h,w]->[h,w,c]
|
|
100
|
+
image = np.asarray(image * 255, dtype=np.uint8)
|
|
101
|
+
label = np.asarray(label, dtype=np.int32)
|
|
102
|
+
print("batch_image.shape:{},batch_label:{}".format(image.shape, label))
|
|
103
|
+
image_utils.cv_show_image("image", image)
|