halib 0.1.61__py3-none-any.whl → 0.1.65__py3-none-any.whl

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.
@@ -12,6 +12,7 @@ from abc import ABC, abstractmethod
12
12
  from ..filetype import csvfile
13
13
  from ..common import now_str
14
14
  from ..research.perftb import PerfTB
15
+ from collections import OrderedDict
15
16
 
16
17
  # try to import torch, and torchmetrics
17
18
  try:
@@ -62,11 +63,12 @@ REQUIRED_COLS = ["experiment", "dataset"]
62
63
  CSV_FILE_POSTFIX = "__perf"
63
64
 
64
65
  class PerfCalc(ABC): # Abstract base class for performance calculation
66
+
65
67
  @abstractmethod
66
- def get_exp_torch_metrics(self):
68
+ def get_experiment_name(self):
67
69
  """
68
- Return a dictionary of torchmetrics to be used for performance calculation.
69
- Example: {"accuracy": Accuracy(), "precision": Precision()}
70
+ Return the name of the experiment.
71
+ This function should be overridden by the subclass if needed.
70
72
  """
71
73
  pass
72
74
 
@@ -79,7 +81,22 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
79
81
  pass
80
82
 
81
83
  @abstractmethod
82
- def prepare_exp_data_for_metrics(self, metric_names, *args, **kwargs):
84
+ def get_metrics_info(self):
85
+ """
86
+ Return a list of metric names to be used for performance calculation OR a dictionaray with keys as metric names and values as metric instances of torchmetrics.Metric. For example: {"accuracy": Accuracy(), "precision": Precision()}
87
+
88
+ """
89
+ pass
90
+
91
+ def calc_exp_outdict_custom_fields(self, outdict, *args, **kwargs):
92
+ """Can be overridden by the subclass to add custom fields to the output dictionary.
93
+ ! must return the modified outdict, and a ordered list of custom fields to be added to the output dictionary.
94
+ """
95
+ return outdict, []
96
+
97
+ # ! can be override, but ONLY if torchmetrics are used
98
+ # Prepare the exp data for torch metrics.
99
+ def prepare_torch_metrics_exp_data(self, metric_names, *args, **kwargs):
83
100
  """
84
101
  Prepare the data for metrics.
85
102
  This function should be overridden by the subclass if needed.
@@ -88,76 +105,113 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
88
105
  """
89
106
  pass
90
107
 
91
- @abstractmethod
92
- def get_experiment_name(self):
108
+ def __validate_metrics_info(self, metrics_info):
93
109
  """
94
- Return the name of the experiment.
95
- This function should be overridden by the subclass if needed.
110
+ Validate the metrics_info to ensure it is a list or a dictionary with valid metric names and instances.
96
111
  """
97
- pass
112
+ if not isinstance(metrics_info, (list, dict)):
113
+ raise TypeError(f"Metrics info must be a list or a dictionary, got {type(metrics_info).__name__}")
114
+
115
+ if isinstance(metrics_info, dict):
116
+ for k, v in metrics_info.items():
117
+ if not isinstance(k, str):
118
+ raise TypeError(f"Key '{k}' is not a string")
119
+ if not isinstance(v, Metric):
120
+ raise TypeError(f"Value for key '{k}' is not a torchmetrics.Metric (got {type(v).__name__})")
121
+ elif isinstance(metrics_info, list):
122
+ for metric in metrics_info:
123
+ if not isinstance(metric, str):
124
+ raise TypeError(f"Metric '{metric}' is not a string")
125
+ return metrics_info
126
+ def __calc_exp_perf_metrics(self, *args, **kwargs):
127
+ """
128
+ Calculate the performance metrics for the experiment.
129
+ """
130
+ metrics_info = self.__validate_metrics_info(self.get_metrics_info())
131
+ USED_TORCHMETRICS = isinstance(metrics_info, dict)
132
+ metric_names = metrics_info if isinstance(metrics_info, list) else list(metrics_info.keys())
133
+ out_dict = {metric: None for metric in metric_names}
134
+ out_dict["dataset"] = self.get_dataset_name()
135
+ out_dict["experiment"] = self.get_experiment_name()
136
+ out_dict, custom_fields = self.calc_exp_outdict_custom_fields(
137
+ outdict=out_dict, *args, **kwargs
138
+ )
139
+ if USED_TORCHMETRICS:
140
+ torch_metrics_dict = self.get_metrics_info()
141
+ all_metric_data = self.prepare_torch_metrics_exp_data(
142
+ metric_names, *args, **kwargs
143
+ )
144
+ metric_col_names = []
145
+ for metric in metric_names:
146
+ if metric not in all_metric_data:
147
+ raise ValueError(f"Metric '{metric}' not found in provided data.")
148
+ tmetric = torch_metrics_dict[metric] # torchmetrics instance
149
+ metric_data = all_metric_data[metric] # should be a dict of args/kwargs
150
+ # Inspect expected parameters for the metric's update() method
151
+ sig = inspect.signature(tmetric.update)
152
+ expected_args = list(sig.parameters.values())
153
+ # Prepare args in correct order
154
+ if isinstance(metric_data, dict):
155
+ # Match dict keys to parameter names
156
+ args = [metric_data[param.name] for param in expected_args]
157
+ elif isinstance(metric_data, (list, tuple)):
158
+ args = metric_data
159
+ else:
160
+ raise TypeError(f"Unsupported data format for metric '{metric}'")
98
161
 
99
- def calc_exp_outdict_custom_fields(self, outdict, *args, **kwargs):
100
- """Can be overridden by the subclass to add custom fields to the output dictionary.
101
- ! must return the modified outdict, and a ordered list of custom fields to be added to the output dictionary.
162
+ # Call update and compute
163
+ if len(expected_args) == 1:
164
+ tmetric.update(args) # pass as single argument
165
+ else:
166
+ tmetric.update(*args) # unpack multiple arguments
167
+ computed_value = tmetric.compute()
168
+ # ensure the computed value converted to a scala value or list array
169
+ if isinstance(computed_value, torch.Tensor):
170
+ if computed_value.numel() == 1:
171
+ computed_value = computed_value.item()
172
+ else:
173
+ computed_value = computed_value.tolist()
174
+ col_name = f"metric_{metric}" if "metric_" not in metric else metric
175
+ metric_col_names.append(col_name)
176
+ out_dict[col_name] = computed_value
177
+ else:
178
+ # If torchmetrics are not used, calculate metrics using the custom method
179
+ metric_rs_dict = self.calc_exp_perf_metrics(
180
+ metric_names, *args, **kwargs)
181
+ for metric in metric_names:
182
+ if metric not in metric_rs_dict:
183
+ raise ValueError(f"Metric '{metric}' not found in provided data.")
184
+ col_name = f"metric_{metric}" if "metric_" not in metric else metric
185
+ out_dict[col_name] = metric_rs_dict[metric]
186
+ metric_col_names = [f"metric_{metric}" for metric in metric_names]
187
+ ordered_cols = REQUIRED_COLS + custom_fields + metric_col_names
188
+ # create a new ordered dictionary with the correct order
189
+ out_dict = OrderedDict((col, out_dict[col]) for col in ordered_cols if col in out_dict)
190
+ return out_dict
191
+
192
+ # ! only need to override this method if torchmetrics are not used
193
+ def calc_exp_perf_metrics(self, metric_names, *args, **kwargs):
102
194
  """
103
- return outdict, []
195
+ Calculate the performance metrics for the experiment, but not using torchmetrics.
196
+ This function should be overridden by the subclass if needed.
197
+ Must return a dictionary with keys as metric names and values as the calculated metrics.
198
+ """
199
+ raise NotImplementedError("calc_exp_perf_metrics() must be overridden by the subclass if torchmetrics are not used.")
200
+
104
201
 
105
202
  #! custom kwargs:
106
203
  #! outfile - if provided, will save the output to a CSV file with the given path
107
204
  #! outdir - if provided, will save the output to a CSV file in the given directory with a generated filename
108
205
  #! return_df - if True, will return a DataFrame instead of a dictionary
109
206
 
110
- def calculate_exp_perf_metrics(self, *args, **kwargs):
207
+ def calc_save_exp_perfs(self, *args, **kwargs):
111
208
  """
112
209
  Calculate the metrics.
113
210
  This function should be overridden by the subclass if needed.
114
211
  Must return a dictionary with keys as metric names and values as the calculated metrics.
115
212
  """
116
- metric_names = list(self.get_exp_torch_metrics().keys())
117
- out_dict = {metric: None for metric in metric_names}
118
- out_dict['dataset'] = self.get_dataset_name()
119
- out_dict['experiment'] = self.get_experiment_name()
120
- out_dict, custom_fields = self.calc_exp_outdict_custom_fields(
121
- outdict=out_dict, *args, **kwargs
122
- )
123
- torch_metrics_dict = self.get_exp_torch_metrics()
124
- all_metric_data = self.prepare_exp_data_for_metrics(
125
- metric_names, *args, **kwargs
126
- )
127
- metric_col_names = []
128
- for metric in metric_names:
129
- if metric not in all_metric_data:
130
- raise ValueError(f"Metric '{metric}' not found in provided data.")
131
- tmetric = torch_metrics_dict[metric] # torchmetrics instance
132
- metric_data = all_metric_data[metric] # should be a dict of args/kwargs
133
- # Inspect expected parameters for the metric's update() method
134
- sig = inspect.signature(tmetric.update)
135
- expected_args = list(sig.parameters.values())
136
- # Prepare args in correct order
137
- if isinstance(metric_data, dict):
138
- # Match dict keys to parameter names
139
- args = [metric_data[param.name] for param in expected_args]
140
- elif isinstance(metric_data, (list, tuple)):
141
- args = metric_data
142
- else:
143
- raise TypeError(f"Unsupported data format for metric '{metric}'")
144
-
145
- # Call update and compute
146
- if len(expected_args) == 1:
147
- tmetric.update(args) # pass as single argument
148
- else:
149
- tmetric.update(*args) # unpack multiple arguments
150
- computed_value = tmetric.compute()
151
- # ensure the computed value converted to a scala value or list array
152
- if isinstance(computed_value, torch.Tensor):
153
- if computed_value.numel() == 1:
154
- computed_value = computed_value.item()
155
- else:
156
- computed_value = computed_value.tolist()
157
- col_name = f"metric_{metric}" if 'metric_' not in metric else metric
158
- metric_col_names.append(col_name)
159
- out_dict[col_name] = computed_value
160
-
213
+ out_dict = self.__calc_exp_perf_metrics(*args, **kwargs)
214
+ # pprint(f"Output Dictionary: {out_dict}")
161
215
  # check if any kwargs named "outfile"
162
216
  csv_outfile = kwargs.get("outfile", None)
163
217
  if csv_outfile is not None:
@@ -171,7 +225,8 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
171
225
 
172
226
  # convert out_dict to a DataFrame
173
227
  df = pd.DataFrame([out_dict])
174
- ordered_cols = REQUIRED_COLS + custom_fields + metric_col_names
228
+ # get the orders of the columns as the orders or the keys in out_dict
229
+ ordered_cols = list(out_dict.keys())
175
230
  df = df[ordered_cols] # reorder columns
176
231
 
177
232
  if csv_outfile:
@@ -182,9 +237,17 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
182
237
  else:
183
238
  return out_dict, csv_outfile
184
239
 
240
+ @staticmethod
241
+ def default_exp_csv_filter_fn(exp_file_name: str) -> bool:
242
+ """
243
+ Default filter function for experiments.
244
+ Returns True if the experiment name does not start with "test_" or "debug_".
245
+ """
246
+ return "__perf.csv" in exp_file_name
247
+
185
248
  @classmethod
186
249
  def gen_perf_report_for_multip_exps(
187
- cls, indir: str, exp_perf_csv_pattern="__perf", csv_sep=';'
250
+ cls, indir: str, exp_csv_filter_fn=default_exp_csv_filter_fn, csv_sep=";"
188
251
  ) -> PerfTB:
189
252
  """
190
253
  Generate a performance report by scanning experiment subdirectories.
@@ -289,12 +352,12 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
289
352
  ]
290
353
  if len(exp_dirs) == 0:
291
354
  csv_perf_files = glob.glob(
292
- os.path.join(indir, f"*{exp_perf_csv_pattern}*.csv")
355
+ os.path.join(indir, f"*.csv")
293
356
  )
294
357
  csv_perf_files = [
295
358
  file_item
296
359
  for file_item in csv_perf_files
297
- if exp_perf_csv_pattern in file_item
360
+ if exp_csv_filter_fn(file_item)
298
361
  ]
299
362
  else:
300
363
  # multiple experiment directories found
@@ -302,33 +365,22 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
302
365
  for exp_dir in exp_dirs:
303
366
  # pprint(f"Searching in experiment directory: {exp_dir}")
304
367
  matched = glob.glob(
305
- os.path.join(exp_dir, f"*{exp_perf_csv_pattern}*.csv")
368
+ os.path.join(exp_dir, f"*.csv")
306
369
  )
370
+ matched = [
371
+ file_item
372
+ for file_item in matched
373
+ if exp_csv_filter_fn(file_item)
374
+ ]
307
375
  csv_perf_files.extend(matched)
308
376
 
309
377
  assert (
310
378
  len(csv_perf_files) > 0
311
- ), f"No CSV files matching pattern '{exp_perf_csv_pattern}' found in the experiment directories."
379
+ ), f"No CSV files matching pattern '{exp_csv_filter_fn}' found in the experiment directories."
312
380
 
313
- assert len(csv_perf_files) > 0, f"No CSV files matching pattern '{exp_perf_csv_pattern}' found in the experiment directories."
381
+ assert len(csv_perf_files) > 0, f"No CSV files matching pattern '{exp_csv_filter_fn}' found in the experiment directories."
314
382
 
315
383
  all_exp_perf_df = get_df_for_all_exp_perf(csv_perf_files, csv_sep=csv_sep)
316
384
  csvfile.fn_display_df(all_exp_perf_df)
317
385
  perf_tb = mk_perftb_report(all_exp_perf_df)
318
- return perf_tb
319
-
320
-
321
- def main():
322
- indir = "./zreport/test"
323
- report_outfile = "./zreport/all.csv"
324
- exp_perf_csv_pattern = "__perf"
325
- csv_sep = ";"
326
- perftb = PerfCalc.gen_perf_report_for_multip_exps(
327
- indir, exp_perf_csv_pattern, csv_sep
328
- )
329
- perftb.to_csv(report_outfile, sep=csv_sep)
330
- inspect(perftb)
331
- perftb.plot(save_path="./zreport/test_csv.svg", open_plot=True)
332
-
333
- if __name__ == "__main__":
334
- main()
386
+ return perf_tb
halib/utils/video.py CHANGED
@@ -5,15 +5,17 @@ from ..system import filesys as fs
5
5
 
6
6
 
7
7
  class VideoUtils:
8
+
8
9
  @staticmethod
9
- def get_video_meta_dict(video_path):
10
+ def _default_meta_extractor(video_path):
11
+ """Default video metadata extractor function."""
10
12
  # Open the video file
11
13
  cap = cv2.VideoCapture(video_path)
12
14
 
13
15
  # Check if the video was opened successfully
14
16
  if not cap.isOpened():
15
17
  print(f"Error: Could not open video file {video_path}")
16
- return None, None
18
+ return None
17
19
 
18
20
  # Get the frame count
19
21
  frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
@@ -23,6 +25,7 @@ class VideoUtils:
23
25
 
24
26
  # Release the video capture object
25
27
  cap.release()
28
+
26
29
  meta_dict = {
27
30
  "video_path": video_path,
28
31
  "frame_count": frame_count,
@@ -31,6 +34,17 @@ class VideoUtils:
31
34
  return meta_dict
32
35
 
33
36
  @staticmethod
37
+ def get_video_meta_dict(video_path, meta_dict_extractor_func=None):
38
+ assert os.path.exists(video_path), f"Video file {video_path} does not exist"
39
+ if meta_dict_extractor_func and callable(meta_dict_extractor_func):
40
+ assert meta_dict_extractor_func.__code__.co_argcount == 1, "meta_dict_extractor_func must take exactly one argument (video_path)"
41
+ meta_dict = meta_dict_extractor_func(video_path)
42
+ assert isinstance(meta_dict, dict), "meta_dict_extractor_func must return a dictionary"
43
+ assert 'video_path' in meta_dict, "meta_dict must contain 'video_path'"
44
+ else:
45
+ meta_dict = VideoUtils._default_meta_extractor(video_path=video_path)
46
+ return meta_dict
47
+ @staticmethod
34
48
  def get_video_dir_meta_df(video_dir, video_exts=['.mp4', '.avi', '.mov', '.mkv'], search_recursive=False, csv_outfile=None):
35
49
  assert os.path.exists(video_dir), f"Video directory {video_dir} does not exist"
36
50
  video_files = fs.filter_files_by_extension(video_dir, video_exts, recursive=search_recursive)
@@ -1,180 +1,190 @@
1
- Metadata-Version: 2.1
2
- Name: halib
3
- Version: 0.1.61
4
- Summary: Small library for common tasks
5
- Author: Hoang Van Ha
6
- Author-email: hoangvanhauit@gmail.com
7
- License: UNKNOWN
8
- Platform: UNKNOWN
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
13
- Description-Content-Type: text/markdown
14
- License-File: LICENSE.txt
15
- Requires-Dist: arrow
16
- Requires-Dist: click
17
- Requires-Dist: enlighten
18
- Requires-Dist: kaleido (==0.1.*)
19
- Requires-Dist: loguru
20
- Requires-Dist: more-itertools
21
- Requires-Dist: moviepy
22
- Requires-Dist: networkx
23
- Requires-Dist: numpy
24
- Requires-Dist: omegaconf
25
- Requires-Dist: opencv-python
26
- Requires-Dist: pandas
27
- Requires-Dist: Pillow
28
- Requires-Dist: Pyarrow
29
- Requires-Dist: pycurl
30
- Requires-Dist: python-telegram-bot
31
- Requires-Dist: requests
32
- Requires-Dist: rich
33
- Requires-Dist: scikit-learn
34
- Requires-Dist: matplotlib
35
- Requires-Dist: seaborn
36
- Requires-Dist: plotly
37
- Requires-Dist: pygwalker
38
- Requires-Dist: tabulate
39
- Requires-Dist: itables
40
- Requires-Dist: timebudget
41
- Requires-Dist: tqdm
42
- Requires-Dist: tube-dl
43
- Requires-Dist: wandb
44
- Requires-Dist: dataclass-wizard
45
-
46
- Helper package for coding and automation
47
-
48
- **Version 0.1.61**
49
-
50
- + add `util/video`: add `VideoUtils` class to handle common video-related tasks
51
- + add `util/gpu_mon`: add `GPUMonitor` class to monitor GPU usage and performance
52
-
53
- **Version 0.1.59**
54
-
55
- + add `util/perfcalc`: abstract class for performance calculation. This class need to be inherited and implemented with specific performance calculation logic.
56
-
57
- **Version 0.1.55**
58
-
59
- + add `util/dataclass_util` to help dynamically create `dataclass` classes from dictionary or YAML file, including support for nested dataclasses. From there, we can use `dataclass_wizard` to create a list of `dataclass` classes with the help from ChatGPT.
60
-
61
- **Version 0.1.52**
62
-
63
- + add `research/perftb` module to allow creating and managing performance tables for experiments, including filtering by datasets, metrics, and experiments.
64
-
65
- **Version 0.1.50**
66
-
67
- + add `pprint_local_path` to print local path (file/directory) in clickable link (as file URI)
68
-
69
- + add `research` package to help with research tasks, including `benchquery` for benchmarking queries from dataframe
70
- + add `wandb` module to allow easy sync offline data to Weights & Biases (wandb) and batch clear wandb runs.
71
-
72
- **Version 0.1.47**
73
- + add `pprint_box` to print object/string in a box frame (like in `inspect`)
74
-
75
- **Version 0.1.46**
76
- + filter the warning message of `UserWarning: Unable to import Axes3D.`
77
- + auto_wrap_text for `fn_display_df` to avoid long text in the table
78
-
79
- **Version 0.1.42**
80
- + add <rich_color.py>: add basic color list (for easy usage)
81
-
82
- **Version 0.1.41**
83
- + add <rich_color.py> to display rich color information in <rich> python package (rcolor_str, rcolor_pallet_all, etc.)
84
-
85
- **Version 0.1.40**
86
-
87
- + update <csvfile.py> to use `itables` and `pygwalker` to display dataframe in jupyter notebook.
88
-
89
- **Version 0.1.38**
90
-
91
- + add <torchloader.py> to search for best cfg for torch dataloader (num_workers, batch_size, pin_memory, et.)
92
-
93
- **Version 0.1.37**
94
-
95
- + add <dataset.py> to help split classification dataset into train/val(test)
96
- ---
97
- **Version 0.1.33**
98
-
99
- + add `plot.py` module to plot DL model training history (with columlns: epoch, train_accuracy, val_accuracy, train_loss, val_loss) using `seaborn` and `matplotlib`
100
- ---
101
- **Version 0.1.29**
102
-
103
- + for `tele_noti` module, `kaleido==0.1.*` is required for plotly since `kaleido 0.2.*` is not working (taking for ever to generate image)
104
- ---
105
- **Version 0.1.24**
106
-
107
- + rename `sys` to `system` to avoid conflict with built-in `sys` module
108
- + add `tele_noti` module to send notification to telegram after a specific interval for training progress monitoring
109
- ---
110
- **Version 0.1.22**
111
-
112
- + add `cuda.py` module to check CUDA availability (for both pytorch and tensorflow)
113
- ---
114
- **Version 0.1.21**
115
-
116
- + using `networkx` and `omegaconf` to allow yaml file inheritance and override
117
- ---
118
- **Version 0.1.15**
119
-
120
- + `__init__.py`: add common logging library; also `console_log` decorator to log function (start and end)
121
-
122
- ---
123
-
124
- **Version 0.1.10**
125
-
126
- + filesys: fix typo on "is_exit" to "is_exist"
127
- + gdrive: now support uploading file to folder and return direct link (shareable link)
128
-
129
- **Version 0.1.9**
130
-
131
- + add dependencies requirement.txt
132
-
133
- **Version 0.1.8**
134
-
135
- Fix bugs:
136
-
137
- + [performance] instead of inserting directly new rows into table dataframe, first insert it into in-memory `row_pool_dict`, that fill data in that dict into the actual dataframe when needed.
138
-
139
- ---
140
-
141
- **Version 0.1.7**
142
-
143
- Fix bugs:
144
-
145
- + fix insert into table so slow by allowing insert multiple rows at once
146
-
147
- ---
148
-
149
- **Version 0.1.6**
150
-
151
- New features:
152
-
153
- + add DFCreator for manipulating table (DataFrame) - create, insert row, display, write to file
154
-
155
- ---
156
-
157
- **Version 0.1.5**
158
-
159
- New Features
160
-
161
- + add cmd module
162
- + new package structure
163
-
164
- ---
165
-
166
- **Version 0.1.4**
167
-
168
- New Features
169
-
170
- + add support to create Bitbucket Project from template
171
-
172
- ---
173
-
174
- **Version 0.1.2**
175
-
176
- New Features
177
-
178
- + add support to upload local to google drive.
179
-
180
-
1
+ Metadata-Version: 2.4
2
+ Name: halib
3
+ Version: 0.1.65
4
+ Summary: Small library for common tasks
5
+ Author: Hoang Van Ha
6
+ Author-email: hoangvanhauit@gmail.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.txt
13
+ Requires-Dist: arrow
14
+ Requires-Dist: click
15
+ Requires-Dist: enlighten
16
+ Requires-Dist: kaleido==0.1.*
17
+ Requires-Dist: loguru
18
+ Requires-Dist: more-itertools
19
+ Requires-Dist: moviepy
20
+ Requires-Dist: networkx
21
+ Requires-Dist: numpy
22
+ Requires-Dist: omegaconf
23
+ Requires-Dist: opencv-python
24
+ Requires-Dist: pandas
25
+ Requires-Dist: Pillow
26
+ Requires-Dist: Pyarrow
27
+ Requires-Dist: pycurl
28
+ Requires-Dist: python-telegram-bot
29
+ Requires-Dist: requests
30
+ Requires-Dist: rich
31
+ Requires-Dist: scikit-learn
32
+ Requires-Dist: matplotlib
33
+ Requires-Dist: seaborn
34
+ Requires-Dist: plotly
35
+ Requires-Dist: pygwalker
36
+ Requires-Dist: tabulate
37
+ Requires-Dist: itables
38
+ Requires-Dist: timebudget
39
+ Requires-Dist: tqdm
40
+ Requires-Dist: tube_dl
41
+ Requires-Dist: wandb
42
+ Requires-Dist: dataclass-wizard
43
+ Dynamic: author
44
+ Dynamic: author-email
45
+ Dynamic: classifier
46
+ Dynamic: description
47
+ Dynamic: description-content-type
48
+ Dynamic: license-file
49
+ Dynamic: requires-dist
50
+ Dynamic: requires-python
51
+ Dynamic: summary
52
+
53
+ Helper package for coding and automation
54
+
55
+ **Version 0.1.65**
56
+
57
+ + now use `uv` for venv management
58
+ + `research/perfcalc`: support both torchmetrics and custom metrics for performance calculation
59
+
60
+ **Version 0.1.61**
61
+
62
+ + add `util/video`: add `VideoUtils` class to handle common video-related tasks
63
+ + add `util/gpu_mon`: add `GPUMonitor` class to monitor GPU usage and performance
64
+
65
+ **Version 0.1.59**
66
+
67
+ + add `util/perfcalc`: abstract class for performance calculation. This class need to be inherited and implemented with specific performance calculation logic.
68
+
69
+ **Version 0.1.55**
70
+
71
+ + add `util/dataclass_util` to help dynamically create `dataclass` classes from dictionary or YAML file, including support for nested dataclasses. From there, we can use `dataclass_wizard` to create a list of `dataclass` classes with the help from ChatGPT.
72
+
73
+ **Version 0.1.52**
74
+
75
+ + add `research/perftb` module to allow creating and managing performance tables for experiments, including filtering by datasets, metrics, and experiments.
76
+
77
+ **Version 0.1.50**
78
+
79
+ + add `pprint_local_path` to print local path (file/directory) in clickable link (as file URI)
80
+
81
+ + add `research` package to help with research tasks, including `benchquery` for benchmarking queries from dataframe
82
+ + add `wandb` module to allow easy sync offline data to Weights & Biases (wandb) and batch clear wandb runs.
83
+
84
+ **Version 0.1.47**
85
+ + add `pprint_box` to print object/string in a box frame (like in `inspect`)
86
+
87
+ **Version 0.1.46**
88
+ + filter the warning message of `UserWarning: Unable to import Axes3D.`
89
+ + auto_wrap_text for `fn_display_df` to avoid long text in the table
90
+
91
+ **Version 0.1.42**
92
+ + add <rich_color.py>: add basic color list (for easy usage)
93
+
94
+ **Version 0.1.41**
95
+ + add <rich_color.py> to display rich color information in <rich> python package (rcolor_str, rcolor_pallet_all, etc.)
96
+
97
+ **Version 0.1.40**
98
+
99
+ + update <csvfile.py> to use `itables` and `pygwalker` to display dataframe in jupyter notebook.
100
+
101
+ **Version 0.1.38**
102
+
103
+ + add <torchloader.py> to search for best cfg for torch dataloader (num_workers, batch_size, pin_memory, et.)
104
+
105
+ **Version 0.1.37**
106
+
107
+ + add <dataset.py> to help split classification dataset into train/val(test)
108
+ ---
109
+ **Version 0.1.33**
110
+
111
+ + add `plot.py` module to plot DL model training history (with columlns: epoch, train_accuracy, val_accuracy, train_loss, val_loss) using `seaborn` and `matplotlib`
112
+ ---
113
+ **Version 0.1.29**
114
+
115
+ + for `tele_noti` module, `kaleido==0.1.*` is required for plotly since `kaleido 0.2.*` is not working (taking for ever to generate image)
116
+ ---
117
+ **Version 0.1.24**
118
+
119
+ + rename `sys` to `system` to avoid conflict with built-in `sys` module
120
+ + add `tele_noti` module to send notification to telegram after a specific interval for training progress monitoring
121
+ ---
122
+ **Version 0.1.22**
123
+
124
+ + add `cuda.py` module to check CUDA availability (for both pytorch and tensorflow)
125
+ ---
126
+ **Version 0.1.21**
127
+
128
+ + using `networkx` and `omegaconf` to allow yaml file inheritance and override
129
+ ---
130
+ **Version 0.1.15**
131
+
132
+ + `__init__.py`: add common logging library; also `console_log` decorator to log function (start and end)
133
+
134
+ ---
135
+
136
+ **Version 0.1.10**
137
+
138
+ + filesys: fix typo on "is_exit" to "is_exist"
139
+ + gdrive: now support uploading file to folder and return direct link (shareable link)
140
+
141
+ **Version 0.1.9**
142
+
143
+ + add dependencies requirement.txt
144
+
145
+ **Version 0.1.8**
146
+
147
+ Fix bugs:
148
+
149
+ + [performance] instead of inserting directly new rows into table dataframe, first insert it into in-memory `row_pool_dict`, that fill data in that dict into the actual dataframe when needed.
150
+
151
+ ---
152
+
153
+ **Version 0.1.7**
154
+
155
+ Fix bugs:
156
+
157
+ + fix insert into table so slow by allowing insert multiple rows at once
158
+
159
+ ---
160
+
161
+ **Version 0.1.6**
162
+
163
+ New features:
164
+
165
+ + add DFCreator for manipulating table (DataFrame) - create, insert row, display, write to file
166
+
167
+ ---
168
+
169
+ **Version 0.1.5**
170
+
171
+ New Features
172
+
173
+ + add cmd module
174
+ + new package structure
175
+
176
+ ---
177
+
178
+ **Version 0.1.4**
179
+
180
+ New Features
181
+
182
+ + add support to create Bitbucket Project from template
183
+
184
+ ---
185
+
186
+ **Version 0.1.2**
187
+
188
+ New Features
189
+
190
+ + add support to upload local to google drive.
@@ -30,7 +30,7 @@ halib/online/projectmake.py,sha256=Zrs96WgXvO4nIrwxnCOletL4aTBge-EoF0r7hpKO1w8,4
30
30
  halib/research/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  halib/research/benchquery.py,sha256=FuKnbWQtCEoRRtJAfN-zaN-jPiO_EzsakmTOMiqi7GQ,4626
32
32
  halib/research/dataset.py,sha256=QU0Hr5QFb8_XlvnOMgC9QJGIpwXAZ9lDd0RdQi_QRec,6743
33
- halib/research/perfcalc.py,sha256=qKgoDbXQtyOpRgOjSMUus7r4mgyiH8Gu9o59sd48SAE,15147
33
+ halib/research/perfcalc.py,sha256=F1BYbxQohbS7u3iRtqnKgPmMrWneV6_bEdBumto8h58,18403
34
34
  halib/research/perftb.py,sha256=vazU-dYBJhfc4sK4zFgxOvzeXGi-5TyPHCt20ItiWhY,30463
35
35
  halib/research/plot.py,sha256=-pDUk4z3C_GnyJ5zWmf-mGMdT4gaipVJWzIgcpIPiRk,9448
36
36
  halib/research/torchloader.py,sha256=yqUjcSiME6H5W210363HyRUrOi3ISpUFAFkTr1w4DCw,6503
@@ -47,9 +47,9 @@ halib/utils/dict_op.py,sha256=wYE6Iw-_CnCWdMg9tpJ2Y2-e2ESkW9FxmdBkZkbUh80,299
47
47
  halib/utils/gpu_mon.py,sha256=vD41_ZnmPLKguuq9X44SB_vwd9JrblO4BDzHLXZhhFY,2233
48
48
  halib/utils/listop.py,sha256=Vpa8_2fI0wySpB2-8sfTBkyi_A4FhoFVVvFiuvW8N64,339
49
49
  halib/utils/tele_noti.py,sha256=-4WXZelCA4W9BroapkRyIdUu9cUVrcJJhegnMs_WpGU,5928
50
- halib/utils/video.py,sha256=mJQFHFbijmu3lo0NZk4Ed64Tfa1u5KxNJpd_TuckpPU,2228
51
- halib-0.1.61.dist-info/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
52
- halib-0.1.61.dist-info/METADATA,sha256=1s7ikn1n88Ix9c_rB4OqSY9hmQ12sJMM-LE_4aIDWNM,5039
53
- halib-0.1.61.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
54
- halib-0.1.61.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
55
- halib-0.1.61.dist-info/RECORD,,
50
+ halib/utils/video.py,sha256=ZqzNVPgc1RZr_T0OlHvZ6SzyBpL7O27LtB86JMbBuR0,3059
51
+ halib-0.1.65.dist-info/licenses/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
52
+ halib-0.1.65.dist-info/METADATA,sha256=clqI54I9dybegyKBsPwaJM7cYBOCLYHdzXHEpFAKv_4,5541
53
+ halib-0.1.65.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
+ halib-0.1.65.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
55
+ halib-0.1.65.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5