Questions about ImageFolder

yichuan9527: <p>Which data format of the picture that ImageFolder can read?  (pickle, JPG or PNG)</p>

ncullen93: <p>From the code (<code>torchvision.datasets.folder.py</code>), supported formats:</p>
<pre><code class="lang-auto">IMG_EXTENSIONS = [
    '.jpg', '.JPG', '.jpeg', '.JPEG',
    '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP',
]
</code></pre>

yichuan9527: <p>Ok, I found the solution。<br>
<img src="https://discuss.pytorch.org/uploads/default/original/1X/bb2e9ad910ef74c69c9b32d53b5985e4a2665a7e.png" width="642" height="305"><br>
but, how to read labels of pictures</p>

yichuan9527: <p>Thank you very much!<img src="//discuss.pytorch.org/images/emoji/apple/grin.png?v=5" title=":grin:" class="emoji" alt=":grin:"><img src="//discuss.pytorch.org/images/emoji/apple/grin.png?v=5" title=":grin:" class="emoji" alt=":grin:"><br>
But how can I read lables?</p>

xiahouzuoxin: <p>The directory name is the class name I think, also from <a href="http://torchvision.datasets.folder.py" rel="nofollow noopener">torchvision.datasets.folder.py</a></p>
<pre><code>def find_classes(dir):
classes = [d for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))]
classes.sort()
class_to_idx = {classes[i]: i for i in range(len(classes))}
return classes, class_to_idx</code></pre>

ncullen93: <p>The labels are the sub-folders from the main directory. Say you have mnist images separated by digit like this:</p>
<pre><code class="lang-auto">main_dir/
     0/
         img1_digit0.jpg
         img2_digit0.jpg
     1/
         img3_digit1.jpg
         ....
     ....
     9/
        ...
</code></pre>
<p>Then you create an <code>ImageFolder</code> object.</p>
<pre><code class="lang-python">from torchvision.datasets import ImageFolder
from torchvision.transforms import ToTensor
data = ImageFolder(root='main_dir', transform=ToTensor())
</code></pre>
<p>Note that you have the <code>ToTensor()</code> transform to convert from jpg to torch tensor.</p>
<p>Now the unique set of class labels is found easily, but this isn’t the class label for each individual image.</p>
<pre><code class="lang-python">print(data.classes) # ['0','1',..'9']
</code></pre>
<p>And the images can be accessed  by an integer index:</p>
<pre><code class="lang-python">x,y = data[0] # x is the first image as PIL, y is that images class label
</code></pre>
<p>You can easily iterate through these images:</p>
<pre><code class="lang-python">for i in range(len(data)):
    x,y = data[i]
</code></pre>
<p>But for sampling like an iterator, I think you should use <code>DataLoader</code> class:</p>
<pre><code class="lang-python">from torch.utils.data import DataLoader
loader = DataLoader(data)
for x, y in loader:
    print(x) # image
    print(y) # image label
</code></pre>
<p>Now, just FYI - I believe this will sample all the <code>0</code> images first, then all the <code>1</code> images, etc. To shuffle the images instead, you can either set <code>shuffle=True</code> in the <code>DataLoader</code>:</p>
<pre><code class="lang-python">loader = DataLoader(data, shuffle=True)
</code></pre>
<p>Or, you can create an instance of the <code>RandomSampler</code> class found in <code>torch.utils.data.sampler.py</code> and pass that into the <code>DataLoader</code> as the <code>sampler</code> argument:</p>
<pre><code class="lang-python">from torch.utils.data import RandomSampler
sampler = RandomSampler(data)
loader = DataLoader(data, sampler=sampler)
</code></pre>
<p>Also, note that if you want to read in data in a folder of a different type (e.g. numpy arrays), you can make your own function and pass it into the <code>ImageFolder</code> class in the <code>loader</code> argument. This function should take in a file path and return the loaded data.</p>
<pre><code class="lang-python">import numpy as np
def my_numpy_loader(filename):
    return np.load(filename)

data = ImageFolder(root='path/to/numpy/maindir/', loader=my_numpy_loader, transform=ToTensor())
</code></pre>
<p>The <code>ToTensor()</code> transform will do its job to convert the numpy array to a torch tensor. However, unfortunately it seems that all the other transforms (e.g. cropping, flipping, etc) only work on PIL images, so you’ll have to build your own transforms for that.</p>
<p>EDIT: As <a class="mention" href="/u/apaszke">@apaszke</a> notes, you can use the <code>ToPILImage()</code> transform to convert your array to PIL to use the transforms… I’d personally prefer transforms to work directly on torch tensors, but that’s just my opinion.</p>
<p>Example:</p>
<pre><code class="lang-python">import numpy as np
def my_numpy_loader(filename):
    return np.load(filename)
from torchvision.transforms import Compose, ToPILImage, ToTensor, ...
my_transform = Compose([ToPILImage(), ... typical transforms .., ToTensor()])
data = ImageFolder(root='path/to/numpy/maindir/', 
                loader=my_numpy_loader, transform=my_transform)
</code></pre>
<p>Here, you convert numpy -&gt; pil image -&gt; do some transforms -&gt; convert back to torch tensor…</p>

Veril: <p>Speaking of formats, would it be possible to add secondary LSUN datasets to torchvision? ex. bird.<br>
Was somewhat surprised they weren’t supported.</p>
<p><a href="http://www.yf.io/p/lsun" class="onebox" target="_blank" rel="nofollow noopener">http://www.yf.io/p/lsun</a><br>
"20 object categories"<br>
<a href="http://tigress-web.princeton.edu/~fy/lsun/public/release/" class="onebox" target="_blank" rel="nofollow noopener">http://tigress-web.princeton.edu/~fy/lsun/public/release/</a></p>

ncullen93: <p>submit an issue on <a href="https://github.com/pytorch/vision" rel="nofollow noopener">https://github.com/pytorch/vision</a></p>

yichuan9527: <p>Dose pytorch have any functions to read the images from pickle file?</p>

apaszke: <p><a class="mention" href="/u/yichuan9527">@yichuan9527</a> why not use <code>pickle.load</code>? If you want to use it with ImageFolder just provide <code>pickle.load</code> as load function.</p>
<p><a class="mention" href="/u/veril">@Veril</a> yes, if you think there’s a dataset that we don’t have but it would be useful, please open an issue in the vision repo.</p>
<p><a class="mention" href="/u/ncullen93">@ncullen93</a> all the transforms work only on PIL images, but you can use <code>ToPILImage()</code> to convert a tensor back to a PIL image.</p>

FuriouslyCurious: <p>I noticed that ImageFolder can process following structure:</p>
<pre><code>root/dog/xxx.png
root/dog/xxy.png

root/cat/123.png
root/cat/asd932_.png
</code></pre>
<p>My question is, can it process a deeper /nested folder structure? e.g.:</p>
<pre><code>root/mammal/dog/xxx.png
root/mammal/cat/xxy.png

root/avian/pigeon/123.png
root/avian/crow/nsdf3.png
</code></pre>
<p>If yes, would the classes be “mammal, avian”, or would they be “dog, cat, pigeon, crow”?</p>
<p>Thanks!</p>

chenyuntc: <p>it will return an empty dataset. because there is no pictures in folder <code>mamma</code> and <code>avian</code>.</p>
<p>You can just create <strong>softlink</strong> in linux, to make them in the same folder.</p>
<p>Also the source code of <code>Imagefolder</code> is really simple to read and modify, you can inherit it and make some modify. have a try.<br>
like</p>
<pre><code class="lang-auto">class TrainImageFolder(ImageFolder):

    def __getitem__(self, index):
            filename = self.imgs[index]#  'avian/crow/nsdf3.png'
            if filename.split('/')[0] =='avian': label = 0
            ### or 
            # if filename.split('/')[1] =='dog': label = 0
            return super(TrainImageFolder, self).__getitem__(index)[0],  label
</code></pre>

Stefan_Radonjic: <p>Hello everyone! Does anyone know how can i merge two ImageFolder objects into one? If you can look at this issue i would really appreciate it:<br>
<aside class="onebox stackexchange">
  <header class="source">
      <a href="https://datascience.stackexchange.com/questions/27626/perform-different-several-different-torchvision-transforms-on-imagefolder-object" target="_blank" rel="nofollow noopener">datascience.stackexchange.com</a>
  </header>
  <article class="onebox-body">
      <a href="https://datascience.stackexchange.com/users/45907/stefan-radonjic" target="_blank" rel="nofollow noopener">
    <img alt="Stefan Radonjic" src="https://lh5.googleusercontent.com/-zQ0B8tCv38k/AAAAAAAAAAI/AAAAAAAAAAw/bWWd0qZVS8I/photo.jpg?sz=128" class="thumbnail onebox-avatar" width="60" height="60">
  </a>
<h4>
  <a href="https://datascience.stackexchange.com/questions/27626/perform-different-several-different-torchvision-transforms-on-imagefolder-object" target="_blank" rel="nofollow noopener">Perform different several different torchvision.transforms on ImageFolder object</a>
</h4>

<div class="tags">
  <strong>python, deep-learning, gan, pytorch</strong>
</div>

<div class="date">
  asked by
  
  <a href="https://datascience.stackexchange.com/users/45907/stefan-radonjic" target="_blank" rel="nofollow noopener">
    Stefan Radonjic
  </a>
  on <a href="https://datascience.stackexchange.com/questions/27626/perform-different-several-different-torchvision-transforms-on-imagefolder-object" target="_blank" rel="nofollow noopener">11:18PM - 08 Feb 18</a>
</div>

  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>
</p>

ptrblck: <p>You can use <code>ConcatDataset</code> <a href="http://pytorch.org/docs/master/data.html#torch.utils.data.ConcatDataset" rel="nofollow noopener">documentation</a> to merge different <code>Dataset</code> s into one.<br>
However, in your other question you would like to save the randomly transformed images, right?<br>
You could just iterate your Dataset and save the images using PIL. It’s not really common though, since you augment the dataset on the fly without saving it usually.</p>

Stefan_Radonjic: <p>Thank you for your reply ! I just tried implementing the code i saw in the documentation you presented but i ran into an error. Here is a screenshot of my code :<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/2X/8/895ad3d6cffc4ea09de2daa37b0414ef959351fd.png" data-download-href="https://discuss.pytorch.org/uploads/default/895ad3d6cffc4ea09de2daa37b0414ef959351fd" title="problem"><img src="https://discuss.pytorch.org/uploads/default/optimized/2X/8/895ad3d6cffc4ea09de2daa37b0414ef959351fd_2_690x350.png" alt="problem" data-base62-sha1="jB60EebF95AwtdopcPnDmSMVXeR" width="690" height="350" srcset="https://discuss.pytorch.org/uploads/default/optimized/2X/8/895ad3d6cffc4ea09de2daa37b0414ef959351fd_2_690x350.png, https://discuss.pytorch.org/uploads/default/optimized/2X/8/895ad3d6cffc4ea09de2daa37b0414ef959351fd_2_1035x525.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/2X/8/895ad3d6cffc4ea09de2daa37b0414ef959351fd_2_1380x700.png 2x" data-dominant-color="EBEAEA"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">problem</span><span class="informations">1920×975 402 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>Line 42: im trying to merge two datasets which are loaded from the same path but performed different transformations on them - but when i print datasets len it saids 1218 (which is equal to a single dataset not two)<br>
Line 89 (I think) - Error for some reason</p>
<p>I have a small dataset of only 1200 images. My idea was to to load dataset, perform lets say Random Crop on it, then load dataset again but this time perform ColorJitter and then merge those two datasets into one which will result in dataset of 2400 pictures. I wanted to create a dataset of atleast 7200 pictures ( which is 6 transformations each time i load dataset) . Do you by any chance have a better idea?</p>

ptrblck: <p>It’s strange that <code>ConcatDataset</code> does not throw an error, since its <code>__init__</code> function only takes one argument and it looks like you’ve provided two (both datasets).<br>
Try to create the <code>ConcatDataset</code> like this:</p>
<pre><code class="lang-auto">class MyData(Dataset):
    def __init__(self):
        self.data = torch.randn(100)
        
    def __getitem__(self, index):
        return self.data[index]
    
    def __len__(self):
        return len(self.data)
    
data1 = MyData()
data_loader1 = DataLoader(data1, batch_size=1)

for batch_idx, data in enumerate(data_loader1):
    print(batch_idx) # prints to idx 99
    
data2 = MyData()
concat_data = ConcatDataset((data1, data2))
concat_loader = DataLoader(concat_data, batch_size=1)

for batch_idx, data in enumerate(concat_loader):
    print(batch_idx) # prints to idx 199
    
print(len(data_loader1)) # 100
print(len(concat_loader)) # 200
</code></pre>
<p>I cannot see line 89. Would you please post the code snippet?</p>
<p>Generally, you could apply both transformations to your dataset.<br>
Since transformations like <code>RandomCrop</code> are applied randomly, one cannot say it’s doubling your data size.<br>
In each iteration your model will see a random transformation of your input.</p>

Sumesh_Uploader: <p>I was able to concat the data sets but unable to separate the respective image tensors while enumerating. When I just print the data it shows both tensor values in concatenated way. If I try something like the following:<br>
<strong>for batch_idx,(inp1,inp2) in enumerate(concat_loader):</strong><br>
it gives “ValueError: not enough values to unpack (expected 2, got 1)”<br>
If i use zip the enumerator for loop goes into infinite loop.<br>
How to solve this?</p>

ptrblck: <p><code>ConcatDateset</code> will concatenate both datasets on top of each other, so that the number of samples will grow. It won’t return both samples for each index.<br>
If you would like to do that, you could try to adapt this code:</p>
<pre><code class="lang-python">class MyDataset(Dataset):
    def __init__(self, dataset1, dataset2):
        self.dataset1 = dataset1
        self.dataset2 = dataset2
        
    def __getitem__(self, index):
        x1 = self.dataset1[index]
        x2 = self.dataset2[index]
        
        return x1, x2
    
    def __len__(self):
        return len(self.dataset1)


dataset1 = TensorDataset(torch.randn(100, 1))
dataset2 = TensorDataset(torch.randn(100, 1))
dataset = MyDataset(dataset1, dataset2)
</code></pre>

nimning: <p>Hi, Nick</p>
<p>Is there way I can edit the IMG_EXTENSIONS so that the ImageFolder would be able to read more image with .gif and .oct-stream extension?</p>
<p>Best</p>

Alan_Wu: <p>I just have a little question. Say the image folder is like this:<br>
root/dog/xxx.png<br>
root/dog/xxy.png</p>
<p>root/cat/123.png<br>
root/cat/asd932_.png</p>
<p>Then I suppose it’s that the class dog is encoded into [1, 0] as for the first category, And the cat goes to [0, 1], Am I right?</p>