65564


下記のコードを実行すると、エラーが出てしまいました。誰かわかる方よろしくお願いします。

[code]

    # -*- coding: utf-8 -*-
    # original code https://github.com/gabrielhuang/reptile-pytorch
    
    from torch.utils import data
    import os
    import numpy as np
    from PIL import Image
    from torchvision import transforms
    
    from utils import list_files, list_dir
    
    # 画像の読み込み
    def read_image(path, size=None):
        img = Image.open(path, mode='r').convert('L')
        if size is not None:
            img = img.resize(size) #リサイズ
        return img
    
    # イメージキャッシュ
    class ImageCache(object):
        def __init__(self):
            self.cache = {}
    
        def read_image(self, path, size=None):
            key = (path, size)
            if key not in self.cache:
                self.cache[key] = read_image(path, size)
            else:
                pass #print 'reusing cache', key
            return self.cache[key]
    
    # キャッシュ対応データセット
    class FewShot(data.Dataset):
        def __init__(self, paths, meta=None, parent=None):
            self.paths = paths
            self.meta = {} if meta is None else meta
            self.parent = parent
    
        def __len__(self):
            return len(self.paths)
    
        def __getitem__(self, idx):
            path = self.paths[idx]['path']
            if self.parent.cache is None:
                image = read_image(path, self.parent.size)
            else:
                image = self.parent.cache.read_image(path, self.parent.size)
            if self.parent.transform_image is not None:
                image = self.parent.transform_image(image)
            label = self.paths[idx]
            if self.parent.transform_label is not None:
                label = self.parent.transform_label(label)
            return image, label
    
    # メタOmniglot抽象化クラス
    class AbstractMetaOmniglot(object):
    
        def __init__(self, characters_list, cache=None, size=(28, 28),
                     transform_image=None, transform_label=None):
            self.characters_list = characters_list
            self.cache = cache
            self.size = size
            self.transform_image = transform_image
            self.transform_label = transform_label
    
        def __len__(self):
            return len(self.characters_list)
    
        def __getitem__(self, idx):
            return self.characters_list[idx]
    
        def get_random_task(self, N=5, K=1): #小さいタスクを得る
            train_task, __ = self.get_random_task_split(N, train_K=K, test_K=0)
            return train_task
    
        def get_random_task_split(self, N=5, train_K=1, test_K=1):
            train_samples = []
            test_samples = []
            character_indices = np.random.choice(len(self), N, replace=False)
            for base_idx, idx in enumerate(character_indices):
                character, paths = self.characters_list[idx]
                for i, path in enumerate(np.random.choice(paths, train_K + test_K, replace=False)):
                    new_path = {}
                    new_path.update(path)
                    new_path['base_idx'] = base_idx
                    if i < train_K:
                        train_samples.append(new_path)
                    else:
                        test_samples.append(new_path)
            train_task = FewShot(train_samples,
                                meta={'characters': character_indices, 'split':'train'},
                                parent=self
                                )
            test_task = FewShot(train_samples,
                                meta={'characters': character_indices, 'split':'test'},
                                parent=self
                                )
            return train_task, test_task
    
    # メタOmniglotフォルダ
    class MetaOmniglotFolder(AbstractMetaOmniglot):
    
        def __init__(self, root='omniglot', *args, **kwargs):
            # このフォルダには各言語の文字(alphabet)が格納されている
            self.root = root
            self.alphabets = list_dir(root)
            self._characters = {}
            for alphabet in self.alphabets:
                for character in list_dir(os.path.join(root, alphabet)):
                    full_character = os.path.join(root, alphabet, character)
                    character_idx = len(self._characters)
                    self._characters[full_character] = []
                    for filename in list_files(full_character, '.png'):
                        self._characters[full_character].append({
                            'path': os.path.join(root, alphabet, character, filename),
                            'character_idx': character_idx
                        })
            characters_list = np.asarray(self._characters.items())
            AbstractMetaOmniglot.__init__(self, characters_list, *args, **kwargs)
    
    
    class MetaOmniglotSplit(AbstractMetaOmniglot):
    
        pass
    
    # testとtrain用にデータを分ける
    def split_omniglot(meta_omniglot, validation=0.1):
        n_val = int(validation * len(meta_omniglot))
        indices = np.arange(len(meta_omniglot))
        np.random.shuffle(indices)
        train_characters = meta_omniglot[indices[:-n_val]]
        test_characters = meta_omniglot[indices[-n_val:]]
        train = MetaOmniglotSplit(train_characters, cache=meta_omniglot.cache, size=meta_omniglot.size,
                                  transform_image=meta_omniglot.transform_image, transform_label=meta_omniglot.transform_label)
        test = MetaOmniglotSplit(test_characters, cache=meta_omniglot.cache, size=meta_omniglot.size,
                                 transform_image=meta_omniglot.transform_image, transform_label=meta_omniglot.transform_label)
        return train, test
    
    
    # デフォルトの画像変換
    transform_image = transforms.Compose([
        transforms.ToTensor()
    ])
    
    def transform_label(paths):
        return paths['base_idx']
    
    
    if __name__ == '__main__': # 単体テスト用
        meta_omniglot = MetaOmniglotFolder('omniglot',
                                           size=(64, 64),
                                           cache=ImageCache(),
                                           transform_image=transform_image)
    
    
        train, test = split_omniglot(meta_omniglot)
        print('all', len(meta_omniglot))
        print('train', len(train))
        print('test', len(test))
    
        base_task = train.get_random_task()
        print('base_task', len(base_task))
        print('ask once', base_task[0])
        print('ask twice', base_task[0])
    
[/code]

エラーコード

[code]

    Traceback (most recent call last):
      File "omniglot.py", line 158, in <module>
        train, test = split_omniglot(meta_omniglot)
      File "omniglot.py", line 130, in split_omniglot
        n_val = int(validation * len(meta_omniglot))
      File "omniglot.py", line 69, in __len__
        return len(self.characters_list)
    TypeError: len() of unsized object
    
[/code]

解決しました。ありがとうございます。


CC BY-SA 4.0
2020-04-12T06:30:54.340
65552
2020-04-13T04:09:22.023
2020-04-13T04:09:22.023
question
python
TypeError: len() of unsized objectというエラーが出る。


該当の`self.characters_list`の属性情報や内容を見ると、`numpy.ndarray`で`size`が`1`、`shape`が`()`で内容を見ると巨大な`dict_items`が1個だけ入っています。

どうも、`class MetaOmniglotFolder(AbstractMetaOmniglot):`の`def
__init__(...)`の最後で、`characters_list =
np.asarray(self._characters.items())`と変換している部分が適切では無いようです。

どんな形にすれば良いのか、については知識が無いので判りませんが、ここを工夫して何か相応しい型や形式に変換すれば良いのではないでしょうか？

* * *

ちなみに元のソースと思われる[reptile-
pytorch/omniglot.py](https://github.com/gabrielhuang/reptile-
pytorch/blob/master/omniglot.py)を見ると、print文がPython
2.x系のようですね。print文を直した程度ではPython 3.x系には移行出来ていないのかもしれません。

試しに以下の記事を参考に少し改造した所では、一部処理が進みましたが、まだ課題は残っているようです。(というか、以下は適切では無さそうですが、試行錯誤の1例として)  
[Python Dictionaryから 2D numpy array
の変換方法](https://qiita.com/TTsujiGIT/items/a3fb7112baa94527dc52)

>
[code]

>     orderedNames = list(myDict.keys())
>     dataMatrix = np.array([list(myDict[i].values()) for i in orderedNames])
>  
[/code]

上記を参考に、以下のようにしてみました。

[code]

    orderedNames = list(self._characters.keys())
    characters_list = np.array([list(self._characters[i]) for i in orderedNames])
    AbstractMetaOmniglot.__init__(self, characters_list, *args, **kwargs)
    
[/code]

メイン処理の以下の部分は通ったようです。

[code]

    meta_omniglot = MetaOmniglotFolder('omniglot',
                                       size=(64, 64),
                                       cache=ImageCache(),
                                       transform_image=transform_image)
    
    train, test = split_omniglot(meta_omniglot)
    print('all', len(meta_omniglot))
    print('train', len(train))
    print('test', len(test))
    
[/code]

結果は以下3行になりました。

[code]

    all 1623
    train 1461
    test 162
    
[/code]

しかし以下の残りの部分は通らずに、

[code]

    base_task = train.get_random_task()
    print('base_task', len(base_task))
    print('ask once', base_task[0])
    print('ask twice', base_task[0])
    
[/code]

こんなエラーになります。(スクリプトファイル名は"qa0412.py"にしました)

[code]

    Traceback (most recent call last):
      File "qa0412.py", line 162, in <module>
        base_task = train.get_random_task()
      File "qa0412.py", line 73, in get_random_task
        train_task, __ = self.get_random_task_split(N, train_K=K, test_K=0)
      File "qa0412.py", line 81, in get_random_task_split
        character, paths = self.characters_list[idx]
    ValueError: too many values to unpack (expected 2)
    
[/code]

さらには細かいことで上記結果には影響無さそうですが、質問ソースの以下の部分は、

[code]

    test_task = FewShot(train_samples,
    
[/code]

元のソースでは以下になっています。転記ミスではないでしょうか？

[code]

    test_task = FewShot(test_samples,
    
[/code]

* * *

更に続きで、以下を参考に改造してみたら、何か最後まで実行されたようです。  
[Pythonの辞書（dict）のforループ処理（keys, values, items）](https://note.nkmk.me/python-
dict-keys-values-items/)  
[Converting Dictionary to List?
[duplicate]](https://stackoverflow.com/q/1679384/9014308)

処理をこのようにしてみたら、

[code]

    characters_list = np.array([[k,v] for k,v in self._characters.items()])
    AbstractMetaOmniglot.__init__(self, characters_list, *args, **kwargs)
    
[/code]

こんな結果で、何か最後まで実行されたようです。  
正しいかどうかは判りませんが、参考までに。

[code]

    all 1623
    train 1461
    test 162
    base_task 5
    ask once (tensor([[[1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             ...,
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.]]]), {'path': 'omniglot\\Aurek-Besh\\character09\\1045_17.png', 'character_idx': 236, 'base_idx': 0})
    ask twice (tensor([[[1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             ...,
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.],
             [1., 1., 1.,  ..., 1., 1., 1.]]]), {'path': 'omniglot\\Aurek-Besh\\character09\\1045_17.png', 'character_idx': 236, 'base_idx': 0})
    
[/code]


CC BY-SA 4.0
2020-04-12T12:23:32.137
65564
2020-04-13T00:41:00.057
2020-04-13T00:41:00.057
26370
26370
65552
answer