Commit 47800d49 authored by Sasank Chilamkurthy's avatar Sasank Chilamkurthy
Browse files

Merge branch 'master' of github.com:pytorch/vision

parents 4d7f70b5 ad1dac49
...@@ -280,7 +280,7 @@ to be atleast 224. ...@@ -280,7 +280,7 @@ to be atleast 224.
The images have to be loaded in to a range of [0, 1] and then The images have to be loaded in to a range of [0, 1] and then
normalized using `mean=[0.485, 0.456, 0.406]` and `std=[0.229, 0.224, 0.225]` normalized using `mean=[0.485, 0.456, 0.406]` and `std=[0.229, 0.224, 0.225]`
An example of such normalization can be found in `the imagenet example here` <https://github.com/pytorch/examples/blob/42e5b996718797e45c46a25c55b031e6768f8440/imagenet/main.py#L89-L101> An example of such normalization can be found in the imagenet example `here <https://github.com/pytorch/examples/blob/42e5b996718797e45c46a25c55b031e6768f8440/imagenet/main.py#L89-L101>`__
Transforms Transforms
========== ==========
...@@ -410,7 +410,7 @@ computing the ``(min, max)`` over all images. ...@@ -410,7 +410,7 @@ computing the ``(min, max)`` over all images.
``pad_value=<float>`` sets the value for the padded pixels. ``pad_value=<float>`` sets the value for the padded pixels.
`Example usage is given in this notebook` <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91> Example usage is given in this `notebook <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`__
``save_image(tensor, filename, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)`` ``save_image(tensor, filename, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
...@@ -11,7 +11,7 @@ VERSION = '0.1.9' ...@@ -11,7 +11,7 @@ VERSION = '0.1.9'
requirements = [ requirements = [
'numpy', 'numpy',
'pillow', 'pillow >= 4.1.1',
'six', 'six',
'torch', 'torch',
] ]
......
...@@ -86,7 +86,7 @@ class Tester(unittest.TestCase): ...@@ -86,7 +86,7 @@ class Tester(unittest.TestCase):
owidth = random.randint(5, 12) * 2 owidth = random.randint(5, 12) * 2
result = transforms.Compose([ result = transforms.Compose([
transforms.ToPILImage(), transforms.ToPILImage(),
transforms.Scale((owidth, oheight)), transforms.Scale((oheight, owidth)),
transforms.ToTensor(), transforms.ToTensor(),
])(img) ])(img)
assert result.size(1) == oheight assert result.size(1) == oheight
...@@ -94,7 +94,7 @@ class Tester(unittest.TestCase): ...@@ -94,7 +94,7 @@ class Tester(unittest.TestCase):
result = transforms.Compose([ result = transforms.Compose([
transforms.ToPILImage(), transforms.ToPILImage(),
transforms.Scale([owidth, oheight]), transforms.Scale([oheight, owidth]),
transforms.ToTensor(), transforms.ToTensor(),
])(img) ])(img)
assert result.size(1) == oheight assert result.size(1) == oheight
...@@ -150,7 +150,7 @@ class Tester(unittest.TestCase): ...@@ -150,7 +150,7 @@ class Tester(unittest.TestCase):
assert output.size[0] == width + padding[0] + padding[2] assert output.size[0] == width + padding[0] + padding[2]
assert output.size[1] == height + padding[1] + padding[3] assert output.size[1] == height + padding[1] + padding[3]
def test_pad_raises_with_invalide_pad_sequence_len(self): def test_pad_raises_with_invalid_pad_sequence_len(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
transforms.Pad(()) transforms.Pad(())
...@@ -264,6 +264,22 @@ class Tester(unittest.TestCase): ...@@ -264,6 +264,22 @@ class Tester(unittest.TestCase):
assert np.allclose(img_data_short.numpy(), to_tensor(img_short).numpy()) assert np.allclose(img_data_short.numpy(), to_tensor(img_short).numpy())
assert np.allclose(img_data_int.numpy(), to_tensor(img_int).numpy()) assert np.allclose(img_data_int.numpy(), to_tensor(img_int).numpy())
def test_tensor_rgba_to_pil_image(self):
trans = transforms.ToPILImage()
to_tensor = transforms.ToTensor()
img_data = torch.Tensor(4, 4, 4).uniform_()
img = trans(img_data)
assert img.mode == 'RGBA'
assert img.getbands() == ('R', 'G', 'B', 'A')
r, g, b, a = img.split()
expected_output = img_data.mul(255).int().float().div(255)
assert np.allclose(expected_output[0].numpy(), to_tensor(r).numpy())
assert np.allclose(expected_output[1].numpy(), to_tensor(g).numpy())
assert np.allclose(expected_output[2].numpy(), to_tensor(b).numpy())
assert np.allclose(expected_output[3].numpy(), to_tensor(a).numpy())
def test_ndarray_to_pil_image(self): def test_ndarray_to_pil_image(self):
trans = transforms.ToPILImage() trans = transforms.ToPILImage()
img_data = torch.ByteTensor(4, 4, 3).random_(0, 255).numpy() img_data = torch.ByteTensor(4, 4, 3).random_(0, 255).numpy()
......
import torch
import torchvision.utils as utils
import unittest
class Tester(unittest.TestCase):
def test_make_grid_not_inplace(self):
t = torch.rand(5, 3, 10, 10)
t_clone = t.clone()
utils.make_grid(t, normalize=False)
assert torch.equal(t, t_clone), 'make_grid modified tensor in-place'
utils.make_grid(t, normalize=True, scale_each=False)
assert torch.equal(t, t_clone), 'make_grid modified tensor in-place'
utils.make_grid(t, normalize=True, scale_each=True)
assert torch.equal(t, t_clone), 'make_grid modified tensor in-place'
def test_make_grid_raises_with_variable(self):
t = torch.autograd.Variable(torch.rand(3, 10, 10))
with self.assertRaises(TypeError):
utils.make_grid(t)
with self.assertRaises(TypeError):
utils.make_grid([t, t, t, t])
if __name__ == '__main__':
unittest.main()
...@@ -10,7 +10,7 @@ def check_integrity(fpath, md5): ...@@ -10,7 +10,7 @@ def check_integrity(fpath, md5):
md5o = hashlib.md5() md5o = hashlib.md5()
with open(fpath, 'rb') as f: with open(fpath, 'rb') as f:
# read in 1MB chunks # read in 1MB chunks
for chunk in iter(lambda: f.read(1024 * 1024 * 1024), b''): for chunk in iter(lambda: f.read(1024 * 1024), b''):
md5o.update(chunk) md5o.update(chunk)
md5c = md5o.hexdigest() md5c = md5o.hexdigest()
if md5c != md5: if md5c != md5:
......
...@@ -8,10 +8,10 @@ __all__ = ['DenseNet', 'densenet121', 'densenet169', 'densenet201', 'densenet161 ...@@ -8,10 +8,10 @@ __all__ = ['DenseNet', 'densenet121', 'densenet169', 'densenet201', 'densenet161
model_urls = { model_urls = {
'densenet121': 'https://download.pytorch.org/models/densenet121-241335ed.pth', 'densenet121': 'https://download.pytorch.org/models/densenet121-a639ec97.pth',
'densenet169': 'https://download.pytorch.org/models/densenet169-6f0f7f60.pth', 'densenet169': 'https://download.pytorch.org/models/densenet169-b2777c0a.pth',
'densenet201': 'https://download.pytorch.org/models/densenet201-4c113574.pth', 'densenet201': 'https://download.pytorch.org/models/densenet201-c1103571.pth',
'densenet161': 'https://download.pytorch.org/models/densenet161-17b70270.pth', 'densenet161': 'https://download.pytorch.org/models/densenet161-8d451a50.pth',
} }
......
...@@ -109,6 +109,9 @@ def to_pil_image(pic): ...@@ -109,6 +109,9 @@ def to_pil_image(pic):
mode = 'I' mode = 'I'
elif npimg.dtype == np.float32: elif npimg.dtype == np.float32:
mode = 'F' mode = 'F'
elif npimg.shape[2] == 4:
if npimg.dtype == np.uint8:
mode = 'RGBA'
else: else:
if npimg.dtype == np.uint8: if npimg.dtype == np.uint8:
mode = 'RGB' mode = 'RGB'
......
...@@ -10,8 +10,8 @@ def make_grid(tensor, nrow=8, padding=2, ...@@ -10,8 +10,8 @@ def make_grid(tensor, nrow=8, padding=2,
Args: Args:
tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W) tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
or a list of images all of the same size. or a list of images all of the same size.
nrow (int, optional): Number of rows in grid. Final grid size is nrow (int, optional): Number of images displayed in each row of the grid.
(B / nrow, nrow). Default is 8. The Final grid size is (B / nrow, nrow). Default is 8.
padding (int, optional): amount of padding. Default is 2. padding (int, optional): amount of padding. Default is 2.
normalize (bool, optional): If True, shift the image to the range (0, 1), normalize (bool, optional): If True, shift the image to the range (0, 1),
by subtracting the minimum and dividing by the maximum pixel value. by subtracting the minimum and dividing by the maximum pixel value.
...@@ -26,14 +26,13 @@ def make_grid(tensor, nrow=8, padding=2, ...@@ -26,14 +26,13 @@ def make_grid(tensor, nrow=8, padding=2,
See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_ See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_
""" """
if not (torch.is_tensor(tensor) or
(isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):
raise TypeError('tensor or list of tensors expected, got {}'.format(type(tensor)))
# if list of tensors, convert to a 4D mini-batch Tensor # if list of tensors, convert to a 4D mini-batch Tensor
if isinstance(tensor, list): if isinstance(tensor, list):
tensorlist = tensor tensor = torch.stack(tensor, dim=0)
numImages = len(tensorlist)
size = torch.Size(torch.Size([numImages]) + tensorlist[0].size())
tensor = tensorlist[0].new(size)
for i in irange(numImages):
tensor[i].copy_(tensorlist[i])
if tensor.dim() == 2: # single image H x W if tensor.dim() == 2: # single image H x W
tensor = tensor.view(1, tensor.size(0), tensor.size(1)) tensor = tensor.view(1, tensor.size(0), tensor.size(1))
...@@ -45,6 +44,7 @@ def make_grid(tensor, nrow=8, padding=2, ...@@ -45,6 +44,7 @@ def make_grid(tensor, nrow=8, padding=2,
tensor = torch.cat((tensor, tensor, tensor), 1) tensor = torch.cat((tensor, tensor, tensor), 1)
if normalize is True: if normalize is True:
tensor = tensor.clone() # avoid modifying tensor in-place
if range is not None: if range is not None:
assert isinstance(range, tuple), \ assert isinstance(range, tuple), \
"range has to be a tuple (min, max) if specified. min and max are numbers" "range has to be a tuple (min, max) if specified. min and max are numbers"
...@@ -70,14 +70,14 @@ def make_grid(tensor, nrow=8, padding=2, ...@@ -70,14 +70,14 @@ def make_grid(tensor, nrow=8, padding=2,
xmaps = min(nrow, nmaps) xmaps = min(nrow, nmaps)
ymaps = int(math.ceil(float(nmaps) / xmaps)) ymaps = int(math.ceil(float(nmaps) / xmaps))
height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding) height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)
grid = tensor.new(3, height * ymaps + 1 + padding // 2, width * xmaps + 1 + padding // 2).fill_(pad_value) grid = tensor.new(3, height * ymaps + padding, width * xmaps + padding).fill_(pad_value)
k = 0 k = 0
for y in irange(ymaps): for y in irange(ymaps):
for x in irange(xmaps): for x in irange(xmaps):
if k >= nmaps: if k >= nmaps:
break break
grid.narrow(1, y * height + 1 + padding // 2, height - padding)\ grid.narrow(1, y * height + padding, height - padding)\
.narrow(2, x * width + 1 + padding // 2, width - padding)\ .narrow(2, x * width + padding, width - padding)\
.copy_(tensor[k]) .copy_(tensor[k])
k = k + 1 k = k + 1
return grid return grid
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment