Download cjepa/src/custom_codes/misc.py from jimchen2/jimchen2-pendulum-output: direct link, hf CLI and curl.
- Browser
- Download file 6.33 kB
-
https://huggingface.co/jimchen2/jimchen2-pendulum-output/resolve/main/cjepa/src/custom_codes/misc.py
- Command line
-
hf download hf://jimchen2/jimchen2-pendulum-output/cjepa/src/custom_codes/misc.py
-
curl -L -o misc.py https://huggingface.co/jimchen2/jimchen2-pendulum-output/resolve/main/cjepa/src/custom_codes/misc.py
6.33 kB
| import os | |
| import cv2 | |
| import time | |
| import random | |
| import numpy as np | |
| import torch | |
| from torchmetrics import MeanMetric as TorchMeanMetric | |
| from nerv.utils.tensor import to_numpy | |
| def datetime2str(form='%Y-%m-%d_%H-%M-%S'): | |
| datetime = time.strftime(form, time.localtime()) | |
| return datetime | |
| def assert_array_shape(xyz, shapes=()): | |
| """Check array shape. | |
| Args: | |
| xyz (np.ndarray): array | |
| shape (tuple of tuple of ints, optional): possible target shapes, | |
| -1 means arbitrary. Defaults to ((-1, 3)). | |
| """ | |
| if not shapes: | |
| raise ValueError('"shapes" cannot be empty') | |
| if isinstance(shapes[0], int): | |
| shapes = (shapes, ) | |
| flags = {x: True for x in range(len(shapes))} | |
| for idx, shape in enumerate(shapes): | |
| if len(xyz.shape) != len(shape): | |
| flags[idx] = False | |
| for dim, num in enumerate(shape): | |
| if num == -1: | |
| continue | |
| elif xyz.shape[dim] != num: | |
| flags[idx] = False | |
| if sum(flags.values()) == 0: # None of the possible shape works | |
| raise ValueError( | |
| f'Input array {xyz.shape} is not in target shapes {shapes}!') | |
| def array_equal(a, b): | |
| """Compare if two arrays are the same. | |
| Args: | |
| a/b: can be np.ndarray or torch.Tensor. | |
| """ | |
| if a.shape != b.shape: | |
| return False | |
| try: | |
| assert (a == b).all() | |
| return True | |
| except: | |
| return False | |
| def array_in_list(array, lst): | |
| """Judge whether an array is in a list.""" | |
| for v in lst: | |
| if array_equal(array, v): | |
| return True | |
| return False | |
| def set_seed(seed=1, deterministic=False): | |
| """Set the random seed of the environment for reproducibility. | |
| Args: | |
| seed (int): the random seed to set. | |
| deterministic (bool, optional): whether to use deterministic torch | |
| backend. Default: False. | |
| """ | |
| print('Using random seed:', seed) | |
| random.seed(seed) | |
| np.random.seed(seed) | |
| torch.manual_seed(seed) | |
| torch.cuda.manual_seed_all(seed) | |
| if deterministic: | |
| print('Using deterministic pytorch backends') | |
| torch.backends.cudnn.benchmark = False | |
| torch.backends.cudnn.deterministic = True | |
| class AverageMeter(object): | |
| """Computes and stores the average and current value.""" | |
| def __init__(self, device=torch.device('cpu')): | |
| self.reset() | |
| self.device = device | |
| def reset(self): | |
| self.val = 0. | |
| self.avg = 0. | |
| self.sum = 0. | |
| self.count = 0. | |
| def update(self, val, n=1): | |
| self.val = val | |
| self.sum += val * n | |
| self.count += n | |
| self.avg = self.sum / self.count | |
| def compute(self): | |
| return torch.tensor(self.avg).to(self.device) | |
| def to(self, device): | |
| self.device = device | |
| return self | |
| class MeanMetric: | |
| """Compatibility wrapper around `torchmetrics.MeanMetric`. | |
| Provides a small API expected by the codebase: `update(value, weight=1.0)`, | |
| `compute()` and `to(device)`. Works with torchmetrics 1.x and 2.x. | |
| """ | |
| def __init__(self, device, nan_strategy="warn", compute_on_step=True, dist_sync_on_step=False, process_group=None, dist_sync_fn=None): | |
| self.device = device | |
| # create underlying torchmetrics MeanMetric and move to device | |
| self._metric = TorchMeanMetric() | |
| try: | |
| self._metric.to(device) | |
| except Exception: | |
| pass | |
| def update(self, value, weight=1.0): | |
| # torchmetrics MeanMetric.update accepts (value, weight) in recent versions, | |
| # older variations may accept only value — try both. | |
| try: | |
| return self._metric.update(value, weight) | |
| except TypeError: | |
| return self._metric.update(value) | |
| def compute(self): | |
| out = self._metric.compute() | |
| if isinstance(out, torch.Tensor): | |
| return out.to(self.device) | |
| try: | |
| return torch.tensor(out).to(self.device) | |
| except Exception: | |
| return out | |
| def to(self, device): | |
| try: | |
| self._metric.to(device) | |
| except Exception: | |
| pass | |
| self.device = device | |
| return self | |
| def _convert4save_img(array): | |
| """Convert a image array to be saveable.""" | |
| # extend channel axis | |
| if len(array.shape) == 2: | |
| array = np.stack([array] * 3, axis=-1) | |
| # [C, H, W] --> [H, W, C], where C == 3 | |
| if array.shape[0] == 3: | |
| array = array.transpose(1, 2, 0) | |
| return np.ascontiguousarray(array) | |
| def _convert4save_video(array): | |
| """Convert a video array to be saveable.""" | |
| # extend channel axis | |
| if len(array.shape) == 3: | |
| array = np.stack([array] * 3, axis=-1) | |
| # [T, C, H, W] --> [T, H, W, C], where C == 3 | |
| if array.shape[1] == 3: | |
| array = array.transpose(0, 2, 3, 1) | |
| return np.ascontiguousarray(array) | |
| def convert4save(array, is_video=False): | |
| """Check the dtype and value range of input array for save. | |
| Need to convert to [(T), H, W, C] with np.uint8 value range [0, 255]. | |
| Args: | |
| array (np.ndarray or torch.Tensor): array to be converted. | |
| is_video (bool, optional): whether the array is a video or image. | |
| Default: False (means array is an image). | |
| Returns: | |
| np.ndarray: the converted array ready for save (image or video). | |
| """ | |
| array = to_numpy(array) | |
| if 'int' in str(array.dtype): | |
| assert 0 <= array.min() <= array.max() <= 255 | |
| elif 'float' in str(array.dtype): | |
| assert 0. <= array.min() <= array.max() <= 1. | |
| array = np.round(array * 255.).astype(np.uint8) | |
| if is_video: | |
| return _convert4save_video(array) | |
| else: | |
| return _convert4save_img(array) | |
| def save_video(video, save_path, fps=30, codec='mp4v'): | |
| """video: np.ndarray of shape [M, H, W, 3]""" | |
| os.makedirs(os.path.dirname(save_path), exist_ok=True) | |
| video = convert4save(video, is_video=True) | |
| video = video[..., [2, 1, 0]] | |
| H, W = video.shape[-3:-1] | |
| assert save_path.split('.')[-1] == 'mp4' # save as mp4 file | |
| # opencv has opposite dimension definition as numpy | |
| size = [W, H] | |
| out = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*codec), fps, size) | |
| for i in range(video.shape[0]): | |
| out.write(video[i]) | |
| out.release() | |