| | import numpy as np |
| | import torchvision.utils as vutils |
| |
|
| |
|
| | def get_np_imgrid(array, nrow=3, padding=0, pad_value=0): |
| | ''' |
| | achieves the same function of torchvision.utils.make_grid for |
| | numpy array |
| | ''' |
| | |
| | n, h, w, c = array.shape |
| | row_num = n // nrow + (n % nrow != 0) |
| | gh, gw = row_num*h + padding*(row_num-1), nrow*w + padding*(nrow - 1) |
| | grid = np.ones((gh, gw, c), dtype=array.dtype) * pad_value |
| | for i in range(n): |
| | grow, gcol = i // nrow, i % nrow |
| | off_y, off_x = grow * (h + padding), gcol * (w + padding) |
| | grid[off_y : off_y + h, off_x : off_x + w] = array[i] |
| | return grid |
| |
|
| |
|
| | def split_np_imgrid(imgrid, nimg, nrow, padding=0): |
| | ''' |
| | reverse operation of make_grid. |
| | args: |
| | imgrid: HWC image grid |
| | nimg: number of images in the grid |
| | nrow: number of columns in image grid |
| | return: |
| | images: list, contains splitted images |
| | ''' |
| | row_num = nimg // nrow + (nimg % nrow != 0) |
| | gh, gw, _ = imgrid.shape |
| | h, w = (gh - (row_num-1)*padding)//row_num, (gw - (nrow-1)*padding)//nrow |
| | images = [] |
| | for gid in range(nimg): |
| | grow, gcol = gid // nrow, gid % nrow |
| | off_i, off_j = grow * (h + padding), gcol * (w + padding) |
| | images.append(imgrid[off_i:off_i+h, off_j:off_j+w]) |
| | return images |
| |
|
| |
|
| | class MDTableConvertor: |
| | |
| | def __init__(self, col_num): |
| | self.col_num = col_num |
| | |
| | def _get_table_row(self, items): |
| | row = '' |
| | for item in items: |
| | row += '| {:s} '.format(item) |
| | row += '|\n' |
| | return row |
| |
|
| | def convert(self, item_list, title=None): |
| | ''' |
| | args: |
| | item_list: a list of items (str or can be converted to str) |
| | that want to be presented in table. |
| | |
| | title: None, or a list of strings. When set to None, empty title |
| | row is used and column number is determined by col_num; Otherwise, |
| | it will be used as title row, its length will override col_num. |
| | |
| | return: |
| | table: markdown table string. |
| | ''' |
| | table = '' |
| | if title: |
| | col_num = len(title) |
| | table += self._get_table_row(title) |
| | else: |
| | col_num=self.col_num |
| | table += self._get_table_row([' ']*col_num) |
| | table += self._get_table_row(['-'] * col_num) |
| | for i in range(0, len(item_list), col_num): |
| | table += self._get_table_row(item_list[i:i+col_num]) |
| | return table |
| | |
| |
|
| | def visual_dict_to_imgrid(visual_dict, col_num=4, padding=0): |
| | ''' |
| | args: |
| | visual_dict: a dictionary of images of the same size |
| | col_num: number of columns in image grid |
| | padding: number of padding pixels to seperate images |
| | ''' |
| | im_names = [] |
| | im_tensors = [] |
| | for name, visual in visual_dict.items(): |
| | im_names.append(name) |
| | im_tensors.append(visual) |
| | im_grid = vutils.make_grid(im_tensors, |
| | nrow=col_num , |
| | padding=0, |
| | pad_value=1.0) |
| | layout = MDTableConvertor(col_num).convert(im_names) |
| | |
| | return im_grid, layout |
| |
|
| |
|
| | def count_parameters(model, trainable_only=False): |
| | return sum(p.numel() for p in model.parameters()) |
| | |
| | |
| |
|
| | class WarmupExpLRScheduler(object): |
| | def __init__(self, lr_start=1e-4, lr_max=4e-4, lr_min=5e-6, rampup_epochs=4, sustain_epochs=0, exp_decay=0.75): |
| | self.lr_start = lr_start |
| | self.lr_max = lr_max |
| | self.lr_min = lr_min |
| | self.rampup_epochs = rampup_epochs |
| | self.sustain_epochs = sustain_epochs |
| | self.exp_decay = exp_decay |
| | |
| | def __call__(self, epoch): |
| | if epoch < self.rampup_epochs: |
| | lr = (self.lr_max - self.lr_start) / self.rampup_epochs * epoch + self.lr_start |
| | elif epoch < self.rampup_epochs + self.sustain_epochs: |
| | lr = self.lr_max |
| | else: |
| | lr = (self.lr_max - self.lr_min) * self.exp_decay**(epoch - self.rampup_epochs - self.sustain_epochs) + self.lr_min |
| | |
| | return lr |