mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-06 12:20:52 +01:00
* Redo tensor repr to make it less verbose * fix empty tensor * fix scaled scalars * update for device-dtype split * address comments * removed repeated lines * address comments * add cuda to device string
209 lines
7.1 KiB
Python
209 lines
7.1 KiB
Python
import math
|
|
import torch
|
|
from functools import reduce
|
|
from sys import float_info
|
|
|
|
|
|
class __PrinterOptions(object):
|
|
precision = 4
|
|
threshold = 1000
|
|
edgeitems = 3
|
|
linewidth = 80
|
|
|
|
|
|
PRINT_OPTS = __PrinterOptions()
|
|
SCALE_FORMAT = '{:.5e} *\n'
|
|
|
|
|
|
# We could use **kwargs, but this will give better docs
|
|
def set_printoptions(
|
|
precision=None,
|
|
threshold=None,
|
|
edgeitems=None,
|
|
linewidth=None,
|
|
profile=None,
|
|
):
|
|
r"""Set options for printing. Items shamelessly taken from NumPy
|
|
|
|
Args:
|
|
precision: Number of digits of precision for floating point output
|
|
(default = 8).
|
|
threshold: Total number of array elements which trigger summarization
|
|
rather than full `repr` (default = 1000).
|
|
edgeitems: Number of array items in summary at beginning and end of
|
|
each dimension (default = 3).
|
|
linewidth: The number of characters per line for the purpose of
|
|
inserting line breaks (default = 80). Thresholded matrices will
|
|
ignore this parameter.
|
|
profile: Sane defaults for pretty printing. Can override with any of
|
|
the above options. (any one of `default`, `short`, `full`)
|
|
"""
|
|
if profile is not None:
|
|
if profile == "default":
|
|
PRINT_OPTS.precision = 4
|
|
PRINT_OPTS.threshold = 1000
|
|
PRINT_OPTS.edgeitems = 3
|
|
PRINT_OPTS.linewidth = 80
|
|
elif profile == "short":
|
|
PRINT_OPTS.precision = 2
|
|
PRINT_OPTS.threshold = 1000
|
|
PRINT_OPTS.edgeitems = 2
|
|
PRINT_OPTS.linewidth = 80
|
|
elif profile == "full":
|
|
PRINT_OPTS.precision = 4
|
|
PRINT_OPTS.threshold = float('inf')
|
|
PRINT_OPTS.edgeitems = 3
|
|
PRINT_OPTS.linewidth = 80
|
|
|
|
if precision is not None:
|
|
PRINT_OPTS.precision = precision
|
|
if threshold is not None:
|
|
PRINT_OPTS.threshold = threshold
|
|
if edgeitems is not None:
|
|
PRINT_OPTS.edgeitems = edgeitems
|
|
if linewidth is not None:
|
|
PRINT_OPTS.linewidth = linewidth
|
|
|
|
|
|
def _get_min_log_scale():
|
|
min_positive = float_info.min * float_info.epsilon # get smallest denormal
|
|
if min_positive == 0: # use smallest normal if DAZ/FTZ is set
|
|
min_positive = float_info.min
|
|
return math.ceil(math.log(min_positive, 10))
|
|
|
|
|
|
def _number_format(tensor, min_sz=-1):
|
|
int_mode = not tensor.dtype.is_floating_point
|
|
_min_log_scale = _get_min_log_scale()
|
|
min_sz = max(min_sz, 2)
|
|
tensor = torch.DoubleTensor(tensor.size()).copy_(tensor).abs_().view(tensor.nelement())
|
|
|
|
pos_inf_mask = tensor.eq(float('inf'))
|
|
neg_inf_mask = tensor.eq(float('-inf'))
|
|
nan_mask = tensor.ne(tensor)
|
|
invalid_value_mask = pos_inf_mask + neg_inf_mask + nan_mask
|
|
if invalid_value_mask.all():
|
|
example_value = 0
|
|
else:
|
|
example_value = tensor[invalid_value_mask.eq(0)][0]
|
|
tensor[invalid_value_mask] = example_value
|
|
if invalid_value_mask.any():
|
|
min_sz = max(min_sz, 3)
|
|
|
|
exp_min = tensor.min()
|
|
if exp_min != 0:
|
|
exp_min = math.floor(math.log10(exp_min)) + 1
|
|
else:
|
|
exp_min = 1
|
|
exp_max = tensor.max()
|
|
if exp_max != 0:
|
|
exp_max = math.floor(math.log10(exp_max)) + 1
|
|
else:
|
|
exp_max = 1
|
|
|
|
scale = 1
|
|
exp_max = int(exp_max)
|
|
prec = PRINT_OPTS.precision
|
|
if int_mode:
|
|
if exp_max > prec + 1:
|
|
format = '{{:11.{}e}}'.format(prec)
|
|
sz = max(min_sz, 7 + prec)
|
|
else:
|
|
sz = max(min_sz, exp_max + 1)
|
|
format = '{:' + str(sz) + '.0f}'
|
|
else:
|
|
if exp_max - exp_min > prec:
|
|
sz = 7 + prec
|
|
if abs(exp_max) > 99 or abs(exp_min) > 99:
|
|
sz = sz + 1
|
|
sz = max(min_sz, sz)
|
|
format = '{{:{}.{}e}}'.format(sz, prec)
|
|
else:
|
|
if exp_max > prec + 1 or exp_max < 0:
|
|
sz = max(min_sz, 7)
|
|
scale = math.pow(10, max(exp_max - 1, _min_log_scale))
|
|
else:
|
|
if exp_max == 0:
|
|
sz = 7
|
|
else:
|
|
sz = exp_max + 6
|
|
sz = max(min_sz, sz)
|
|
format = '{{:{}.{}f}}'.format(sz, prec)
|
|
return format, scale, sz
|
|
|
|
|
|
def _scalar_str(self, fmt, scale):
|
|
scalar_str = fmt.format(self.item() / scale)
|
|
# The leading space for positives is ugly on scalars, so we strip it
|
|
return scalar_str.lstrip()
|
|
|
|
|
|
def _vector_str(self, indent, fmt, scale, sz, summarize):
|
|
element_length = sz + 3
|
|
elements_per_line = int(math.floor((PRINT_OPTS.linewidth - indent) / (element_length)))
|
|
char_per_line = element_length * elements_per_line
|
|
|
|
if summarize and self.size(0) > 2 * PRINT_OPTS.edgeitems:
|
|
data = ([fmt.format(val.item() / scale) for val in self[:PRINT_OPTS.edgeitems]] +
|
|
[' ...'] +
|
|
[fmt.format(val.item() / scale) for val in self[-PRINT_OPTS.edgeitems:]])
|
|
else:
|
|
data = [fmt.format(val.item() / scale) for val in self]
|
|
|
|
data_lines = [data[i:i + elements_per_line] for i in range(0, len(data), elements_per_line)]
|
|
lines = [', '.join(line) for line in data_lines]
|
|
return '[' + (',' + '\n' + ' ' * (indent + 1)).join(lines) + ']'
|
|
|
|
|
|
def _tensor_str(self, indent, fmt, scale, sz, summarize):
|
|
dim = self.dim()
|
|
|
|
if dim == 0:
|
|
return _scalar_str(self, fmt, scale)
|
|
if dim == 1:
|
|
return _vector_str(self, indent, fmt, scale, sz, summarize)
|
|
|
|
if summarize and self.size(0) > 2 * PRINT_OPTS.edgeitems:
|
|
slices = ([_tensor_str(self[i], indent + 1, fmt, scale, sz, summarize)
|
|
for i in range(0, PRINT_OPTS.edgeitems)] +
|
|
['...'] +
|
|
[_tensor_str(self[i], indent + 1, fmt, scale, sz, summarize)
|
|
for i in range(len(self) - PRINT_OPTS.edgeitems, len(self))])
|
|
else:
|
|
slices = [_tensor_str(self[i], indent + 1, fmt, scale, sz, summarize) for i in range(0, self.size(0))]
|
|
|
|
tensor_str = (',' + '\n' * (dim - 1) + ' ' * (indent + 1)).join(slices)
|
|
return '[' + tensor_str + ']'
|
|
|
|
|
|
def _str(self):
|
|
if self.is_sparse:
|
|
size_str = str(tuple(self.shape)).replace(' ', '')
|
|
return '{} of size {} with indices:\n{}and values:\n{}'.format(
|
|
self.type(), size_str, self._indices(), self._values())
|
|
|
|
prefix = 'tensor('
|
|
indent = len(prefix)
|
|
summarize = self.numel() > PRINT_OPTS.threshold
|
|
|
|
suffix = ')'
|
|
if not torch._C._is_default_type_cuda():
|
|
if self.device.type == 'cuda':
|
|
suffix = ', device=\'' + str(self.device) + '\'' + suffix
|
|
else:
|
|
if self.device.type == 'cpu' or torch.cuda.current_device() != self.device.index:
|
|
suffix = ', device=\'' + str(self.device) + '\'' + suffix
|
|
|
|
if self.dtype != torch.get_default_dtype() and self.dtype != torch.int64:
|
|
suffix = ', dtype=' + str(self.dtype) + suffix
|
|
|
|
if self.numel() == 0:
|
|
tensor_str = '[]'
|
|
else:
|
|
fmt, scale, sz = _number_format(self)
|
|
if scale != 1:
|
|
prefix = prefix + SCALE_FORMAT.format(scale) + ' ' * indent
|
|
tensor_str = _tensor_str(self, indent, fmt, scale, sz, summarize)
|
|
|
|
return prefix + tensor_str + suffix
|