Caffe2 - Python API
A deep learning, cross platform ML framework
__init__.py
1 """
2 The testing package contains testing-specific utilities.
3 """
4 
5 import torch
6 import random
7 
8 FileCheck = torch._C.FileCheck
9 
10 __all__ = [
11  'assert_allclose', 'make_non_contiguous', 'rand_like', 'randn_like'
12 ]
13 
14 rand_like = torch.rand_like
15 randn_like = torch.randn_like
16 
17 
18 def assert_allclose(actual, expected, rtol=None, atol=None, equal_nan=True):
19  if not isinstance(actual, torch.Tensor):
20  actual = torch.tensor(actual)
21  if not isinstance(expected, torch.Tensor):
22  expected = torch.tensor(expected, dtype=actual.dtype)
23  if expected.shape != actual.shape:
24  expected = expected.expand_as(actual)
25  if rtol is None or atol is None:
26  if rtol is not None or atol is not None:
27  raise ValueError("rtol and atol must both be specified or both be unspecified")
28  rtol, atol = _get_default_tolerance(actual, expected)
29 
30  close = torch.isclose(actual, expected, rtol, atol, equal_nan)
31  if close.all():
32  return
33 
34  # Find the worst offender
35  error = (expected - actual).abs()
36  expected_error = atol + rtol * expected.abs()
37  delta = error - expected_error
38  delta[close] = 0 # mask out NaN/inf
39  _, index = delta.reshape(-1).max(0)
40 
41  # TODO: consider adding torch.unravel_index
42  def _unravel_index(index, shape):
43  res = []
44  for size in shape[::-1]:
45  res.append(int(index % size))
46  index = int(index // size)
47  return tuple(res[::-1])
48 
49  index = _unravel_index(index.item(), actual.shape)
50 
51  # Count number of offenders
52  count = (~close).long().sum()
53 
54  msg = ('Not within tolerance rtol={} atol={} at input{} ({} vs. {}) and {}'
55  ' other locations ({:2.2f}%)')
56 
57  raise AssertionError(msg.format(
58  rtol, atol, list(index), actual[index].item(), expected[index].item(),
59  count - 1, 100 * count / actual.numel()))
60 
61 
62 def make_non_contiguous(tensor):
63  if tensor.numel() <= 1: # can't make non-contiguous
64  return tensor.clone()
65  osize = list(tensor.size())
66 
67  # randomly inflate a few dimensions in osize
68  for _ in range(2):
69  dim = random.randint(0, len(osize) - 1)
70  add = random.randint(4, 15)
71  osize[dim] = osize[dim] + add
72 
73  # narrow doesn't make a non-contiguous tensor if we only narrow the 0-th dimension,
74  # (which will always happen with a 1-dimensional tensor), so let's make a new
75  # right-most dimension and cut it off
76 
77  input = tensor.new(torch.Size(osize + [random.randint(2, 3)]))
78  input = input.select(len(input.size()) - 1, random.randint(0, 1))
79  # now extract the input of correct size from 'input'
80  for i in range(len(osize)):
81  if input.size(i) != tensor.size(i):
82  bounds = random.randint(1, input.size(i) - tensor.size(i))
83  input = input.narrow(i, bounds, tensor.size(i))
84 
85  input.copy_(tensor)
86  return input
87 
88 
89 def get_all_dtypes():
90  return [torch.uint8, torch.int8, torch.int16, torch.int32, torch.int64,
91  torch.float16, torch.float32, torch.float64]
92 
93 
94 # 'dtype': (rtol, atol)
95 _default_tolerances = {
96  'float64': (1e-5, 1e-8), # NumPy default
97  'float32': (1e-4, 1e-5), # This may need to be changed
98  'float16': (1e-3, 1e-3), # This may need to be changed
99 }
100 
101 
102 def _get_default_tolerance(a, b=None):
103  if b is None:
104  dtype = str(a.dtype).split('.')[-1] # e.g. "float32"
105  return _default_tolerances.get(dtype, (0, 0))
106  a_tol = _get_default_tolerance(a)
107  b_tol = _get_default_tolerance(b)
108  return (max(a_tol[0], b_tol[0]), max(a_tol[1], b_tol[1]))
Module caffe2.python.layers.split.