Giter Site home page Giter Site logo

tristandeleu / pytorch-meta Goto Github PK

View Code? Open in Web Editor NEW
2.0K 44.0 253.0 1.11 MB

A collection of extensions and data-loaders for few-shot learning & meta-learning in PyTorch

Home Page: https://tristandeleu.github.io/pytorch-meta/

License: MIT License

Python 100.00%
pytorch meta-learning few-shot-learning

pytorch-meta's Introduction

Torchmeta

PyPI Build Status Documentation

A collection of extensions and data-loaders for few-shot learning & meta-learning in PyTorch. Torchmeta contains popular meta-learning benchmarks, fully compatible with both torchvision and PyTorch's DataLoader.

Features

  • A unified interface for both few-shot classification and regression problems, to allow easy benchmarking on multiple problems and reproducibility.
  • Helper functions for some popular problems, with default arguments from the literature.
  • An thin extension of PyTorch's Module, called MetaModule, that simplifies the creation of certain meta-learning models (e.g. gradient based meta-learning methods). See the MAML example for an example using MetaModule.

Datasets available

Installation

You can install Torchmeta either using Python's package manager pip, or from source. To avoid any conflict with your existing Python setup, it is suggested to work in a virtual environment with virtualenv. To install virtualenv:

pip install --upgrade virtualenv
virtualenv venv
source venv/bin/activate

Requirements

  • Python 3.6 or above
  • PyTorch 1.4 or above
  • Torchvision 0.5 or above

Using pip

This is the recommended way to install Torchmeta:

pip install torchmeta

From source

You can also install Torchmeta from source. This is recommended if you want to contribute to Torchmeta.

git clone https://github.com/tristandeleu/pytorch-meta.git
cd pytorch-meta
python setup.py install

Example

Minimal example

This minimal example below shows how to create a dataloader for the 5-shot 5-way Omniglot dataset with Torchmeta. The dataloader loads a batch of randomly generated tasks, and all the samples are concatenated into a single tensor. For more examples, check the examples folder.

from torchmeta.datasets.helpers import omniglot
from torchmeta.utils.data import BatchMetaDataLoader

dataset = omniglot("data", ways=5, shots=5, test_shots=15, meta_train=True, download=True)
dataloader = BatchMetaDataLoader(dataset, batch_size=16, num_workers=4)

for batch in dataloader:
    train_inputs, train_targets = batch["train"]
    print('Train inputs shape: {0}'.format(train_inputs.shape))    # (16, 25, 1, 28, 28)
    print('Train targets shape: {0}'.format(train_targets.shape))  # (16, 25)

    test_inputs, test_targets = batch["test"]
    print('Test inputs shape: {0}'.format(test_inputs.shape))      # (16, 75, 1, 28, 28)
    print('Test targets shape: {0}'.format(test_targets.shape))    # (16, 75)

Advanced example

Helper functions are only available for some of the datasets available. However, all of them are available through the unified interface provided by Torchmeta. The variable dataset defined above is equivalent to the following

from torchmeta.datasets import Omniglot
from torchmeta.transforms import Categorical, ClassSplitter, Rotation
from torchvision.transforms import Compose, Resize, ToTensor
from torchmeta.utils.data import BatchMetaDataLoader

dataset = Omniglot("data",
                   # Number of ways
                   num_classes_per_task=5,
                   # Resize the images to 28x28 and converts them to PyTorch tensors (from Torchvision)
                   transform=Compose([Resize(28), ToTensor()]),
                   # Transform the labels to integers (e.g. ("Glagolitic/character01", "Sanskrit/character14", ...) to (0, 1, ...))
                   target_transform=Categorical(num_classes=5),
                   # Creates new virtual classes with rotated versions of the images (from Santoro et al., 2016)
                   class_augmentations=[Rotation([90, 180, 270])],
                   meta_train=True,
                   download=True)
dataset = ClassSplitter(dataset, shuffle=True, num_train_per_class=5, num_test_per_class=15)
dataloader = BatchMetaDataLoader(dataset, batch_size=16, num_workers=4)

Note that the dataloader, receiving the dataset, remains the same.

Citation

Tristan Deleu, Tobias Würfl, Mandana Samiei, Joseph Paul Cohen, and Yoshua Bengio. Torchmeta: A Meta-Learning library for PyTorch, 2019 [ArXiv]

If you want to cite Torchmeta, use the following Bibtex entry:

@misc{deleu2019torchmeta,
  title={{Torchmeta: A Meta-Learning library for PyTorch}},
  author={Deleu, Tristan and W\"urfl, Tobias and Samiei, Mandana and Cohen, Joseph Paul and Bengio, Yoshua},
  year={2019},
  url={https://arxiv.org/abs/1909.06576},
  note={Available at: https://github.com/tristandeleu/pytorch-meta}
}

pytorch-meta's People

Contributors

akreal avatar egrefen avatar eugenelet avatar marccoru avatar marcociccone avatar mmahsereci avatar msiam avatar sleepy-owl avatar tristandeleu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytorch-meta's Issues

Reproducibility is broken with class augmentations

Hi!
Even if you fix the random seed everywhere, when you use class augmentations such as Rotation([90, 180, 270]), results are not always the same.
It took me a while, but I found that it is because class augmentations become unique using a set(), here and this is not stable.
The order of the augmentations might not be the same at different runs!

Bug List

Hi again! I came with a little more bugs this time, hopefully I don't bother you :)

  • CIFARFS imported from torchmeta.datasets returns list index out of range error after BatchMetaDataLoader runs for 2 iterations:

File "/home/ademir/anaconda3/envs/metalearn/lib/python3.7/site-packages/torchmeta/datasets/cifar100/base.py", line 53, in getitem
coarse_label_name, fine_label_name = self.labels[index]
IndexError: list index out of range

  • FC100 from torchmeta.datasets returns file not found error:
    No such file or directory: 'data/cifar100/fine_names.json'

  • miniImageNet, tieredIMageNet and omniglot run without bugs; however I wrote one helper function to visualize support set and query set at each episode. Under a 5 way 5 shot learning scenario, the first 2 labels are always the same. So the code actually generates 4 labels, first label with 10 images and other 3 labels having 5 images each. My code is available here for your validation: https://github.com/andac-demir/FewShotClassification/blob/master/metadata.py

How is it that the Prototypical Nets get high accuracy without training?

If I go into the prototypical nets example and turn off training by using torch.no_grad befoe the tqdm loop and then commenting out the model.zero_grad, loss.backward, and optimizer.step, I get accuracy in the high 70s.

How is this happening? I would expect that accuracy would be 20%. I changed the model by removing BatchNorm and ReLU and it gets high 60s in this case. I thought it could be something to do with the convolutional prior, but then I changed that to just a Linear function and it got accuracy in the high 60s as well.

Is it a bug in the implementation?

Mini-ImageNet download broken?

Running:

from torchmeta.datasets.helpers import miniimagenet
dataset = miniimagenet("data", ways=5, shots=5, test_shots=15, meta_train=True, download=True)

throws the following error:

3089it [00:00, 1760353.95it/s]
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    dataset = miniimagenet("data", ways=5, shots=5, test_shots=15, meta_train=True, download=True)
  File ".../pytorch-meta/torchmeta/datasets/helpers.py", line 126, in miniimagenet
    seed=seed, defaults=defaults, **kwargs)
  File ".../pytorch-meta/torchmeta/datasets/helpers.py", line 34, in helper_with_default
    dataset = klass(folder, num_classes_per_task=ways, **kwargs)
  File ".../pytorch-meta/torchmeta/datasets/miniimagenet.py", line 89, in __init__
    download=download)
  File ".../pytorch-meta/torchmeta/datasets/miniimagenet.py", line 124, in __init__
    self.download()
  File ".../pytorch-meta/torchmeta/datasets/miniimagenet.py", line 178, in download
    with tarfile.open(filename, 'r') as f:
  File "/usr/lib/python3.6/tarfile.py", line 1576, in open
    raise ReadError("file could not be opened successfully")
tarfile.ReadError: file could not be opened successfully

A file data/miniimagenet/mini-imagenet.tar.gz is created, but only of size 3.1kB, instead of the expected 1.1GB.

Downloading the data directly from https://github.com/renmengye/few-shot-ssl-public works fine.

Cannot pass None as argument for target for a dataset.

Similar issue as #27 just with transform=None:

from torchmeta.datasets import Omniglot
from torchmeta.transforms import Categorical, ClassSplitter
from torchmeta.utils.data import BatchMetaDataLoader

dataset = Omniglot("data",
                   num_classes_per_task=5,
                   transform=None,
                   target_transform=Categorical(num_classes=5),
                   class_augmentations=[Rotation([90, 180, 270])],
                   meta_train=True,
                   download=True)
dataset = ClassSplitter(dataset, shuffle=True, num_train_per_class=5, num_test_per_class=15)
dataloader = BatchMetaDataLoader(dataset, batch_size=16, num_workers=4)
inputs, targets = iter(dataloader).next()['train']

results in
TypeError: default_collate: batch must contain tensors, numpy arrays, numbers, dicts or lists; found <class 'PIL.Image.Image'>

Would it be desirable to catch this case?

For how long does the meta batch data loader iterate?

Usually in python iterators stop when the StopIteration exception is raised.

But I saw that the length of the data loader is a strange number (where I expected infinity since it's usually up to the user how many episodes they want to do, which usually corresponds to a batch of tasks sampled).

So when does the data loader stop?

Code I am referencing is from the example: https://github.com/tristandeleu/pytorch-meta/blob/master/examples/maml-higher/train.py

    # Training loop
    with tqdm(dataloader, total=args.num_batches) as pbar:
        for batch_idx, batch in enumerate(pbar):
            model.zero_grad()

is args.num_batches the same as the number of episodes?

the weird size I mentioned:

        print(len(dataloader)) # prints 446400

CIFAR helpers

Is there any reason why there are no helpers for the datasets derived from CIFAR? I would be interested in implementing them, if not.

Number of batches returned correct?

Hi,
First of all, thank you for sharing the data loaders. I have come across a strange behaviour and was wondering if this is the intended behaviour. When sampling batches from the datasets, the sampler does not seem to sample from all images and the number of batches returned is limited to these images.

For example, when sampling from the Omniglot dataset, with 1028 classes and 5 num_classes_per_task, the number of batches returned is equal to C(1028, 5) and seems limited to only 5 images per class. Similarly, when setting num_classes_per_task=1, we get C(1028,1)=1028 batches, which again consist of the same image for each class (with shuffle=True).

Here is a small example. For the num_classes_per_task=1 we see that the number of unique classes that are being sampled is around 647 while the total number of classes is 1028, which is fine as we are randomly sampling. However, the number of unique images sampled is also 647, which indicates that we are really just sampling from one image per class (1028 images in total). Am I missing something?

import random
import torch.optim
from torchvision.transforms import Compose, ToTensor, Resize
from torchmeta.transforms import ClassSplitter, Categorical
from torchmeta.datasets import Omniglot
from torchmeta.utils.data import BatchMetaDataLoader
import numpy as np
from collections import Counter

seed = 0
random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)

print("num_classes_per_task=1")
omniglot_dataset = Omniglot("data",
                   num_classes_per_task=1,
                   transform=Compose([Resize(28), ToTensor()]),
                   meta_train=True,
                   download=True)
omniglot_dataset = ClassSplitter(omniglot_dataset, shuffle=True, num_train_per_class=1)
omniglot_dataloader = BatchMetaDataLoader(omniglot_dataset, batch_size=1, num_workers=1)

batch_list = []
target_list = []
for batch in omniglot_dataloader:
    batch_list.append(np.asarray(batch["train"][0]))
    target_list.append(batch["train"][1][0][0][0])

print("Number of batches: ", len(omniglot_dataloader))
print("Number of unique classes: ", len(Counter(target_list).keys()))
print("Number of unique images: ",np.unique(np.stack(batch_list), axis=0).shape[0])

print("*****")
print("num_classes_per_task=5")
omniglot_dataset = Omniglot("data",
                   num_classes_per_task=5,
                   transform=Compose([Resize(28), ToTensor()]),
                   meta_train=True,
                   download=True)
omniglot_dataset = ClassSplitter(omniglot_dataset, shuffle=True, num_train_per_class=5)
omniglot_dataloader = BatchMetaDataLoader(omniglot_dataset, batch_size=1, num_workers=1)
print("Number of batches: ", len(omniglot_dataloader))

Extension to semi-supervised meta-learning

First of all, thanks a lot for this great library! It really facilitates meta-learning experiments.

I have noticed that semi-supervised data loading is currently not supported in pytorch-meta. Nonetheless, this would be useful to reproduce or expand upon the recent literature on semi-supervised meta-learning (e.g. 'Meta-Learning for Semi-Supervised Few-Shot Classification'). Thus, I would like to add this feature and wanted to ask for some direction.

Semi-supervised meta-learning, as described in the aforementioned paper, has the following requirements at both meta-train and meta-test time:

  • Load K labelled samples from N classes (N-way, K-shot as already provided, where K can be different for the support and query set).
  • From the same N classes load an additional M unlabelled samples, that can never appear in the labelled set.
  • Optionally, load M unlabelled samples from H distractor classes, that are disjunct from the previous N classes.
  • The ratio between labelled and unlabelled samples should be the same within each class and should be a parameter.

Do you have any suggestions which would be the best approach to do this?

One approach might be to have two separate datasets and corresponding dataloaders, one for labelled data and one for unlabelled data (including distractors). One could, for example, pass a random seed and labelled_ratio to restrict the datasets to only use part of the stored data within each ClassDataset. However, I do not know how to guarantee, that the unlabelled dataloader would load the same N classes as used by the labelled dataloader.

Error on FC100

Hi! Thanks for this great library. FC100 doesn't download data. There are a few bugs in fc100.py lines 118-121! I don't know how to fix this. I appreciate if you could take a look.

Is Torchmeta compatible with Dataparallel?

Hi,
is torchmeta compatible with dataparallel?
I have troubles training a MetaModule wrapped by dataparallel. It seems get_subdict has problems with the layer names starting with "module."
Thanks for your help!

Hard time replicating MAML results from the example repos

I am trying to replicate the paper results for MAML after looking at many implementations. I have been struggling to get to 98-99 percent accuracy while using --first-order derivatives as they say is possible in the paper.

I thought it must be something with my implementation so I downloaded and ran the example in this repo and I noticed the same thing.

5-way 1-shot on omniglot converges to 99% train accuracy very quickly but when I add the --first-order option it converges very slowly and hangs around 90% ish accuracy.

Does the --first-order option need a much longer training time, or is it possible that there could be a bug in the example or somewhere in the library which is making this happen?

CombinationRandomSampler does not have __len__ or _num_samples

When using pytorch-meta with pytorch-lightning, we get an AttributeError because pytorch-lightning calls len(sampler) and breaks for the CombinationRandomSampler because it neither defines __len__ nor _num_samples.

This is not a bug from pytorch-meta, but I think it would be nice if the libraries interoperate. I also believe that adding this feature would be as easy as adding

def __len__(self):
  num_classes = len(self.data_source.dataset)
  num_classes_per_task = self.data_source.num_classes_per_task
  return math.comb(num_classes, num_classes_per_task)

I could open a PR with an implementation that works for other Python versions if you are interested in adding this feature. Thanks.

num_workers > 0 for BatchMetaDataLoader causes an AttributeError to be raised when 'spawn' is used as the multiprocessing start method.

I've provided a minimal-ish working example to reproduce the bug. I don't want to use the 'fork' method for multiprocessing for various reasons: avoiding race conditions, deadlocks, and that CUDA isn't supported with this method.

# import pytest

import tqdm
import time

from torchmeta.datasets import TripleMNIST
from torchmeta.transforms import ClassSplitter
from torchmeta.utils.data import BatchMetaDataLoader

from torchvision import transforms

import multiprocessing
multiprocessing.set_start_method('spawn', True)

dataset_path = '~/Downloads'
transform = \
    transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5,), (0.5,)),
    ])
dataset = TripleMNIST(root=dataset_path,
                      transform=transform,
                      target_transform=None,
                      num_classes_per_task=1,
                      meta_train=True,
                      download=True)
dataset = ClassSplitter(dataset, shuffle=True,
                        num_train_per_class=5)
dataloader = BatchMetaDataLoader(dataset,
                                 batch_size=1,
                                 pin_memory=True,
                                 num_workers=2)

def train_on_task_stub(batch):
    time.sleep(.20)

episode = 1
num_episodes = 1000
num_epochs = 10
start_epoch = 1
while episode < num_episodes:
    for i, batch in enumerate(dataloader):
        inputs, targets = batch['train']

        pbar = tqdm.tqdm(total=num_epochs, miniters=num_epochs/100,
                         ncols=180, initial=start_epoch)
        for epoch in range(start_epoch, num_epochs + 1):
            train_batch = [inputs[0], targets[0]]
            train_on_task_stub(train_batch)
            mesg = 'Episode {}/{} Epoch {}/{}:\t'.format(episode,
                                                         num_episodes,
                                                         epoch, num_epochs)
            pbar.update(1)
            pbar.set_description(mesg, refresh=False)
        pbar.close()
    
        if episode >= num_episodes:
            break

        episode += 1
        start_epoch = 1
Can't pickle local object 'batch_meta_collate.<locals>._collate_fn'
  File "/Users/mattie/Projects/pytorch-meta/test.py", line 42, in <module>
    for i, batch in enumerate(dataloader):

I believe the culprit is below. Functions defined within functions are not pickle-able, and pickling is the method used for transporting data between processes when 'spawn' is used. Would you happen to know the best way to rewrite the batch_meta_collate function to prevent this issue?

def batch_meta_collate(collate_fn):
def collate_task(task):
if isinstance(task, TorchDataset):
return collate_fn([task[idx] for idx in range(len(task))])
elif isinstance(task, OrderedDict):
return OrderedDict([(key, collate_task(subtask))
for (key, subtask) in task.items()])
else:
raise NotImplementedError()
def _collate_fn(batch):
return collate_fn([collate_task(task) for task in batch])
return _collate_fn

Miniimagenet Results?

Have you successfully used this library to train Miniimagenet with Prototypical Nets? The highest test accuracy that I have gotten was .52, and that was changing the transforms to additionally Normalize the image tensors and add in a step size scheduler that advances every 20 epochs.

Omniglot: Sampling classes from the same alphabet for one task

Hi,
First of all, thank you for developing and maintaining this repository.

I looked through the code and in particular the Omniglot dataset implementation and may have found one issue:

The OmniglotClassDataset defines each alphabet/character as separate class

labels = sorted([('images_{0}'.format(name), alphabet, character)

Hence, self.num_classes spans the number of classes times the number of alphabets.
Then the CombinationRandomSampler samples random indices from the entire range of classes here

yield tuple(random.sample(range(num_classes), num_classes_per_task))

This leads to classes from different alphabets being samples in the same task. This arguably makes the classification task easier since characters of different alphabets may be easier to separate than characters from the same alphabet.

Is this property intended? One task should include samples from the same alphabet according to my understanding.

This may be solved by a custom CombinationSubsetRandomSampler that only chooses indices from samples of the same alphabet. This would require some additional alphabet-index information in the OmniglotClassDataset or OmniglotDataset.

Thanks again for creating this repository.

ClassSplitter only supports balanced test samples per episode

The authors of TADAM describe in the supplementary material that query samples in each episode are sampled uniformly at random (from the set of data points of all classes instead of K samples per class).
Is this a negligible implementation detail or do you think it's something that's worth adding as a feature in the ClassSplitter?

PIL Imcompatible

Hi!

Thanks for your code! I found a imcompatible problem with PIL.
I install torchmeta(1.3.0), it upgrade my torch to 1.4 and torchvision to 0.5. Then when I run the demo code, it comes up with the error like:

im = new(self.mode, size, fillcolor)
  File "/home/csy/anaconda3/envs/csy_env/lib/python3.7/site-packages/PIL/Image.py", line 2505, in new
    return im._new(core.fill(mode, size, color))
TypeError: function takes exactly 1 argument (3 given)

Then I found in pytorch/vision#1759, where it seems that torchvision (0.5) has some imcompatible problem with PIL. So I downgrade torchvision to 0.4 (it automatically downgrade my torch to 1.2), and it works.

However, as you mention, torchmeta is not compatible with torch == 1.2.0.

But the demo code can work on the combination of these verision: torch (1.2.0), torchvision (0.4.0), PIL (6.2.1)

Looking forward to any other solution.

Best regards,
Shangyu

MetaTest

Hi,
Thanks for this Library

How are we supposed to do meta testing because accuracy u mentioned is of meta train episodes, right?

HTTPError: HTTP Error 404: Not Found (For TCGA)

When trying to call the TCGA dataset with :

import torchmeta
import requests
from torchmeta.datasets.tcga import TCGA
torchmeta.datasets.TCGA("data", meta_train=True, meta_val=False,
meta_test=False, meta_split=None, min_samples_per_class=5, transform=None,
target_transform=None, dataset_transform=None, download=True,
chunksize=100, preload=True)

The program fails with:

Downloading ACC_clinicalMatrix.gz...


HTTPError Traceback (most recent call last)
in ()
5 meta_test=False, meta_split=None, min_samples_per_class=5, transform=None,
6 target_transform=None, dataset_transform=None, download=True,
----> 7 chunksize=100, preload=True)

/usr/local/lib/python3.6/dist-packages/torchmeta/datasets/tcga.py in init(self, root, meta_train, meta_val, meta_test, meta_split, min_samples_per_class, transform, target_transform, dataset_transform, download, chunksize, preload)
112
113 if download:
--> 114 self.download(chunksize)
115
116 self.preloaded = False

/usr/local/lib/python3.6/dist-packages/torchmeta/datasets/tcga.py in download(self, chunksize)
275 print('Downloading {0}.gz...'.format(filename))
276 url = self.clinical_matrix_url.format(cancer)
--> 277 urllib.request.urlretrieve(url, rawpath)
278
279 print('Extracting {0}.gz...'.format(filename))

/usr/lib/python3.6/urllib/request.py in urlretrieve(url, filename, reporthook, data)
246 url_type, path = splittype(url)
247
--> 248 with contextlib.closing(urlopen(url, data)) as fp:
249 headers = fp.info()
250

/usr/lib/python3.6/urllib/request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context)
221 else:
222 opener = _opener
--> 223 return opener.open(url, data, timeout)
224
225 def install_opener(opener):

/usr/lib/python3.6/urllib/request.py in open(self, fullurl, data, timeout)
530 for processor in self.process_response.get(protocol, []):
531 meth = getattr(processor, meth_name)
--> 532 response = meth(req, response)
533
534 return response

/usr/lib/python3.6/urllib/request.py in http_response(self, request, response)
640 if not (200 <= code < 300):
641 response = self.parent.error(
--> 642 'http', request, response, code, msg, hdrs)
643
644 return response

/usr/lib/python3.6/urllib/request.py in error(self, proto, *args)
568 if http_err:
569 args = (dict, 'default', 'http_error_default') + orig_args
--> 570 return self._call_chain(*args)
571
572 # XXX probably also want an abstract factory that knows when it makes

/usr/lib/python3.6/urllib/request.py in _call_chain(self, chain, kind, meth_name, *args)
502 for handler in handlers:
503 func = getattr(handler, meth_name)
--> 504 result = func(*args)
505 if result is not None:
506 return result

/usr/lib/python3.6/urllib/request.py in http_error_default(self, req, fp, code, msg, hdrs)
648 class HTTPDefaultErrorHandler(BaseHandler):
649 def http_error_default(self, req, fp, code, msg, hdrs):
--> 650 raise HTTPError(req.full_url, code, msg, hdrs, fp)
651
652 class HTTPRedirectHandler(BaseHandler):

HTTPError: HTTP Error 404: Not Found

Datasets for few-shot object detection

I wonder if there is anyone already working on curating and putting up a collection of datasets for the few-shot object detection task.

I would be happy to help out if someone is already working on this.

20 ways 1 shots using Omniglot

Hi,
Thanks for the nice work! When I tried 20-way-1-shot on omniglot with BatchMetaloader recently:
dataset = omniglot("data", ways=20, shots=1, test_shots=5, meta_train=True, download=True)
dataloader = BatchMetaDataLoader(dataset, batch_size=16, num_workers=4)`

I got an unexpected error like below:
image
but it is normal when using miniimagenet, so I am a bit confused. Thanks for your help !

How to loop through the whole data-set as in standard training (none episodic)

I wanted to pre-train a model using normal training (no meta-learning or inner adaptation or anything. Just an old fashion pytorch dataloader but use a few-shot learning data set for the pre-training with standard epoch training).

For that do I just do:

    dataset = miniimagenet( 
        args.data_root, 
        ways=args.n_classes, 
        shots=args.k_shot, 
        test_shots=args.k_eval,
        meta_split='train',
        download=False)
    dataloader = data.DataLoader(
        dataset, 
        num_workers=4, 
        pin_memory=True, # to make moving to cuda more efficient 
)

Reproducing results

Hi there, I'd like to ask if it's possible to include tabulated data comparing different approaches using different datasets as found in meta_dataset? Since some papers doesn't use the same split between training, validation and testing, re-implementation is required and I don't think it's necessary. Let me know if such comparison table based on pytorch-meta is provided elsewhere. Thanks!

Other datasets suggested

I guess a few more challenging datasets will be popular in the next coming years. Such as meta-dataset, Imagenet-21k. Can you plz add them?

Pascal5i Fewshot Segmentation

Thanks for the great work.

I am wondering if I can add a loader for pascal5i dataset as a pull request? I think it will greatly benefit the fewshot segmentation community to have it in that repo too.

Bug in Pascal5i dataloader

I am using Pascal5i dataloader through the following code but I am unable to iterate it.

from torchmeta.datasets import Pascal5i
from torchmeta.utils.data import BatchMetaDataLoader
import config

def load_trainloader():
     trainset = Pascal5i("data", num_classes_per_task=config.n, meta_train=True, download=True)
     trainloader = BatchMetDataLoader(trainset, batch_size=config.batch_size, shuffle=True, num_workers=0)

    return trainset, trainloader

_, trainloader = load_trainloader()
batch = next(iter(trainloader))

Error:

TypeError                                Traceback (most recent call last)
<ipython-input-8-e4dc503de88f> in <module>
----> 1 batch = next(iter(trainloader))

~/venv/torch-py3/lib/python3.6/site-packages/torch/utils/data/dataloader.py in __next__(self)
343 
344     def __next__(self):
--> 345         data = self._next_data()
346         self._num_yielded += 1
347         if self._dataset_kind == _DatasetKind.Iterable and \

~/venv/torch-py3/lib/python3.6/site-packages/torch/utils/data/dataloader.py in _next_data(self)
383     def _next_data(self):
384         index = self._next_index()  # may raise StopIteration
--> 385         data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
386         if self._pin_memory:
387             data = _utils.pin_memory.pin_memory(data)

~/venv/torch-py3/lib/python3.6/site-packages/torch/utils/data/_utils/fetch.py in fetch(self, possibly_batched_index)
 42     def fetch(self, possibly_batched_index):
 43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
 45         else:
 46             data = self.dataset[possibly_batched_index]

~/venv/torch-py3/lib/python3.6/site-packages/torch/utils/data/_utils/fetch.py in <listcomp>(.0)
 42     def fetch(self, possibly_batched_index):
 43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
 45         else:
 46             data = self.dataset[possibly_batched_index]

~/venv/torch-py3/lib/python3.6/site-packages/torchmeta/utils/data/dataset.py in __getitem__(self, index)
274                 self.num_classes_per_task - 1, index))
275         assert len(index) == self.num_classes_per_task
--> 276         datasets = [self.dataset[i] for i in index]
277         # Use deepcopy on `Categorical` target transforms, to avoid any side
278         # effect across tasks.

~/venv/torch-py3/lib/python3.6/site-packages/torchmeta/utils/data/dataset.py in <listcomp>(.0)
274                 self.num_classes_per_task - 1, index))
275         assert len(index) == self.num_classes_per_task
--> 276         datasets = [self.dataset[i] for i in index]
277         # Use deepcopy on `Categorical` target transforms, to avoid any side
278         # effect across tasks.

~/venv/torch-py3/lib/python3.6/site-packages/torchmeta/datasets/pascal5i.py in __getitem__(self, index)
146 
147         return PascalDataset((data, masks), class_id, transform=transform,
--> 148             target_transform=target_transform)
149 
150     @property

~/venv/torch-py3/lib/python3.6/site-packages/torchmeta/datasets/pascal5i.py in __init__(self, data, class_id, transform, target_transform)
245     def __init__(self, data, class_id, transform=None, target_transform=None):
246         super(PascalDataset, self).__init__(transform=transform,
--> 247             target_transform=target_transform)
248         self.data, self.masks = data
249         self.class_id = class_id

TypeError: __init__() missing 1 required positional argument: 'index'

I posted the same problem on Pytorch discussion forum and came to realize that the 'index' argument is not made optional which is causing this problem. Can you please look into it?

Documentation incomplete

there are many classes specially in the data loaders that have no docs. This makes it very difficult to use the library.

For example, usually when creating a meta-set one has a number of data-sets. How many data-sets are actually created? Usually in one episode one creates one data-set. Is this how your library does it or how?

Some docs so that it's easier to use would be good.

Comments on episodic learning would be good. Usually I sample a set of meta-tasks (or data-sets from the meta-set) per episode.

error on colab

OSError: cannot identify image file 'data/omniglot/images_background/Japanese_(katakana)/character44/0639_04.png'
Screenshot (44)

misunderstanding of the data size of omniglot

Hi,
I noticed the description of the dataset:
"The Omniglot dataset [1]. A dataset of 1623 handwritten characters from 50 different alphabets.
The meta train/validation/test splits used in [3] are taken from [this repository]. These splits are over 1028/172/423 classes " .
However, when I tested
dataset = omniglot(data_path, ways=6, shots=10, test_shots=15, meta_train=True, download=True)
print(len(dataset))
the result is this huge number: 6689615974037915648,
Also, when I use dataloader, the number of total batch seems not equal 1028.
If I change argument "ways" to bigger than 10, i get this bug: "OverflowError: cannot fit 'int' into an index-sized integer".
Is there any misunderstanding of this dataset here? Thanks for your explanation

Ideas for improving performance

Hi --

I'm curious whether you're aware of any bottlenecks that we might be able to re-write to improve performance? Right now, the dataloader is slowing down my Omniglot metalearner by ~ 50%.

I'm going to profile myself, but figured I'd ask if you knew of particular hot-spots.

Love the library!

~ Ben

Doesn't work with latest torch 1.5.0 update

Traceback (most recent call last):
File "/home/alexc/code/cadam/MAML/main_miniimagenet.py", line 480, in
from torchmeta.utils.data import BatchMetaDataLoader
File "/home/alexc/anaconda3/envs/cadam_new/lib/python3.7/site-packages/torchmeta/init.py", line 1, in
from torchmeta import datasets
File "/home/alexc/anaconda3/envs/cadam_new/lib/python3.7/site-packages/torchmeta/datasets/init.py", line 1, in
from torchmeta.datasets.triplemnist import TripleMNIST
File "/home/alexc/anaconda3/envs/cadam_new/lib/python3.7/site-packages/torchmeta/datasets/triplemnist.py", line 11, in
from torchmeta.datasets.utils import get_asset
File "/home/alexc/anaconda3/envs/cadam_new/lib/python3.7/site-packages/torchmeta/datasets/utils.py", line 3, in
from torchvision.datasets.utils import makedir_exist_ok, check_integrity
ImportError: cannot import name 'makedir_exist_ok' from 'torchvision.datasets.utils' (/home/alexc/anaconda3/envs/cadam_new/lib/python3.7/site-packages/torchvision/datasets/utils.py)

Can you patch these up please and commit :)

[Feature request] CUB

Hi! do you plan to add CUB birds in the future? Feel free to delete this issue if it is not the proper place to ask.

Have a nice day,

Pau

MetaDataLoader shuffle default to true

Hi --

I'm curious what you think about changing the default shuffle parameter in MetaDataLoader to true.

I ran

dataset     = omniglot("./data", meta_split='train', ways=20, shots=1, shuffle=True)
dataloader = BatchMetaDataLoader(dataset, batch_size=16, num_workers=4)

and was getting too-good results. It took a bit of time to track down that BatchMetaDataLoader outputs classes in combinations(range(num_classes), num_shots) order, so the batches are super correlated w/ one another. I can't really imagine a use-case where you'd want this ordering of your batches. Thoughts?

Thanks!
~ Ben

Some doubts

Hi, I really appreciate your great work ! But i have some doubts about details.

  1. for miniimagenet ,in torchmeta.datasets.helpers. I find you use resize(84), why not using data augument such as randomcrop(84)? In addtion to above issue, In turn, the dafault setting of transform is resize, totensor. Why no Normalize?
  2. we run your code on miniimagenet, I find that gpus take up a lot of memory compared to normal code with same setting, a 1080Ti is not enough. Why?
    Looking forward to your reply, thank you!

Can not pass None as argument for target_transform for a dataset.

I've been wanting to implement label-conditioning for certain meta learning tasks, and at the moment, it seems that targets always have to be transformed such that the labels are between 0 - num_classes. If I pass None, then try to fetch inputs and targets, the error below appears:

dataset = DoubleMNIST(..., target_transform=None, ...)
dataset = ClassSplitter(dataset, ...)
dataloader = BatchMetaDataLoader(dataset, ...)
inputs, targets = iter(dataloader).next()['train']

TypeError: default_collate: batch must contain tensors, numpy arrays, numbers, dicts or lists; found <class 'NoneType'>

I've been looking into it, and it seems that if you pass None, a FixedCategory(None) object is created and applied to the target over here:

if self.target_transform is not None:
target = self.target_transform(target)
return (image, target)

(image, target) is returned, where target is changed to (label, None), which eventually causes Pytorch's default_collate function to raise a TypeError once it gets to the None type.

https://github.com/pytorch/pytorch/blob/9d94f56ce02a814fb3c9dfe3fee675420a7e7e30/torch/utils/data/_utils/collate.py#L77-L81

Otherwise, if you pass a Categorical target transform, a Compose object containing that transform is applied to the target, returning (image, transformed_target).

The DoubleMNIST dataset is just one example, as this applies to all datasets that apply a target transform. I was going to modify the check:

if self.target_transform is not None:

to if self.target_transform.transform is not None but that breaks if you provide a target transform, since Compose objects don't have the transform property. Also, I believe the line above is redundant anyways, since a target transform always exists? Even if not provided. Maybe this can be changed somehow?

Conv2d bias kwarg

I had some trouble replicating the results from the MAML paper when using torchmeta, and your example and your other MAML repo as references. I am searching for the problem and I found that the MetaConv2d deviates from the pytorch Conv2d layer because of this line.

bias = params.get('bias', None)

if I replicate that situation in a function it turns out like this which would mean that the default value for bias has been changed to a falsey value in this function

def foo(kwarg=True):
  print(kwarg)

foo(kwarg=None)
# output: None
foo()
# output: True

Should we change it to or does that change the function in some other way?

bias = params.get('bias', True)

How can I use an optimizer with the extracted parameters?

I would like to use an optimizer with the extracted parameters but I keep getting some unexpected behavior like the parameters are still referring to the parameter list in the original model...

model = DropoutNet(in_dim, args.h_dim, out_dim).to(args.device)                                                                                                                                                                                                          optimizer = torch.optim.SGD(model.parameters(), lr=1, weight_decay=1e-4)      

params = OrderedDict(model.parameters())
p_opt = torch.optim.SGD(params.values(), lr=1e-3)

yhat = model(x, params=params)
loss = criterion(y, yhat)

for p in params.values():
  p.grad.add_(loss)

p_opt.step()
p_opt.zero_grad()                                                                     

If I do something like this and then print out the parameters, the parameters in the model will be the same as the ones in the params dict. Is there a better way to do this?

request to be contributors

Hi,

I am a Phd student and working on few shot learning. This is an exciting project. Can i contribute for it? Although you have done a lot, there should be more we can do?

Can you update the dependecy to Pillow which has version more than 7.0.0?

The new version of torch and torchvision was released, and it seems that they utilize Pillow version more than 7.0.0.
But torchmeta has requirements about the pilllow version < 7.0.0, so it made a conflict.

C:\ProgramData\Anaconda3\lib\site-packages\torchmeta\transforms\augmentations.py in call(self, image)
28 raise ValueError()
29 return F.rotate(image, self.angle % 360, self.resample,
---> 30 self.expand, self.center, fill = (0,))
31
32 def hash(self):

C:\ProgramData\Anaconda3\lib\site-packages\torchvision\transforms\functional.py in rotate(img, angle, resample, expand, center, fill)
727 fill = tuple([fill] * 3)
728
--> 729 return img.rotate(angle, resample, expand, center, fillcolor=fill)
730
731

C:\ProgramData\Anaconda3\lib\site-packages\PIL\Image.py in rotate(self, angle, resample, expand, center, translate, fillcolor)
2053 w, h = nw, nh
2054
-> 2055 return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)
2056
2057 def save(self, fp, format=None, **params):

C:\ProgramData\Anaconda3\lib\site-packages\PIL\Image.py in transform(self, size, method, data, resample, fill, fillcolor)
2369 raise ValueError("missing method data")
2370
-> 2371 im = new(self.mode, size, fillcolor)
2372 im.info = self.info.copy()
2373 if method == MESH:

C:\ProgramData\Anaconda3\lib\site-packages\PIL\Image.py in new(mode, size, color)
2577 color = im.palette.getcolor(color)
2578
-> 2579 return im._new(core.fill(mode, size, color))
2580
2581

TypeError: function takes at least 3 arguments (1 given)

Combine DoubleMNIST with TripleMNIST to create MultiMNIST

Something I wanted to do when I included the DoubleMNIST dataset. Changing DoubleMNIST to MultiMNIST and including a flag to decide whether it's Double or Triple should be relatively trivial. This enhancement should also include logic to download the TripleMNIST dataset.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.