naïve _version_2

27098 ワード

https://pytorch.org/tutorials/beginner/data_loading_tutorial.html
https://www.youtube.com/channel/UCpujNlw4SUpgTU5rrDXH0Jw
こちらを強くお勧めします
結論は関数は内蔵されているがclassは自分で作成されている.
損失も大きな奇跡だ.

class custom_dataset(Dataset):
    
    def __init__(self, inputs_dir , targets_dir, transform = None):
        
        self.inputs_dir = inputs_dir 
        self.inputs_list =  os.listdir(inputs_dir)
        
        self.targets_dir = targets_dir
        self.targets_list =  os.listdir(targets_dir)      
        
        self.transform = transform
            
        
        
    def __len__(self):
        return len(self.inputs_list)
    
    def __getitem__(self,idx):
        os.chdir(self.inputs_dir)
        input_image = Image.open(self.inputs_list[idx])
        
        os.chdir(self.targets_dir)
        target_image = Image.open(self.targets_list[idx])
        
        if self.transform:
            a = self.transform(input_image)
            b = self.transform(input_image)

            
        return ( a,b )
        
最初はそうしましたが、問題がflipであれば、出力とtargetとは異なります.すなわち、2つの独立した変換です.
だから私は1つの変換で2つを適用したいのですが、list、dict、tupleが1つしかないかもしれません.
そこで、inputとtargetを同時に受信させるclassを作成したいと思います.
変換は次のようになります.

transforms.Compose([transforms.Resize((224,224), interpolation = Image.NEAREST),    
                                     transforms.RandomHorizontalFlip(),
                                     transforms.ToTensor()])
                                     
中の要素はそのように書いて、内蔵のclassを利用して、私は自分でします.
もちろん、Classificationのようにtargetがintであればtargetに変換を適用する必要はないので、どうでもいい.(上図のように)
次のコードは、公式ドキュメントと上のYouTubeビデオから取得したコードで、dictを原則としています.
まず、dictを受信するためにデータセットを再作成します.
class custom_dataset(Dataset):
    
    def __init__(self, inputs_dir , targets_dir, transform = None):
        
        self.inputs_dir = inputs_dir 
        self.inputs_list =  os.listdir(inputs_dir)
        
        self.targets_dir = targets_dir
        self.targets_list =  os.listdir(targets_dir)      
        
        self.transform = transform
            
        
        
    def __len__(self):
        return len(self.inputs_list)
    
    def __getitem__(self,idx):
    
        os.chdir(self.inputs_dir)
        input_image = Image.open(self.inputs_list[idx])
        
        os.chdir(self.targets_dir)
        target_image = Image.open(self.targets_list[idx])
        
        combine = {'input':input_image, 'target':target_image}
        
        if self.transform:
            combine = self.transform(combine)

            
        return (combine['input'] , combine['target'])
        
Transsformationクラスを作成します.
class RandomFlip(object):
    
    def __call__(self, combine):
    
        inputs = combine['input']
        targets = combine['target']

        inputs_np = np.array(inputs) #물론 flip을 먼저하면 np로 바뀌어있긴하다. 하지만 항상 flip을 하는것은 아니니까
        targets_np = np.array(targets)


        if np.random.rand() > 0.5:   # 좌우
            inputs_np = np.fliplr(inputs_np)
            targets_np = np.fliplr(targets_np)

        if np.random.rand() > 0.5:   # 상하
            inputs_np = np.flipud(inputs_np)
            targets_np = np.flipud(targets_np)

        combine = {'input': inputs_np, 'target': targets_np}  #출력은 np type이다.

        return combine
class ToTensor(object):
    def __call__(self, combine):
    
        inputs = combine['input']
        targets = combine['target']

        inputs_np = np.array(inputs)
        targets_np = np.array(targets)
        
        inputs_tensor = torch.from_numpy(inputs_np)
        targets_tensor = torch.from_numpy(targets_np)
        
        inputs_np_trans = np.transpose(inputs_tensor, (2,0,1))
        targets_np_trans = np.transpose(targets_tensor.unsqueeze(2), (2,0,1))

        
        combine = {'input':inputs_np_trans, 'target':targets_np_trans}

        return combine
ちなみに、次のResizeはテンソルのみを対応させているので、このpostの順に変換を構築すべきです.

class Resize(object):
    
    def __init__(self, output_size, mode):
        
        self.output_size = output_size
        self.mode = mode
    
    def __call__(self, combine):
        
        # ToTensor 이후라고 가정하니까 
        inputs_tensor = combine['input']
        targets_tensor = combine['target']
        
        inputs_rescaled = torch.nn.functional.interpolate(inputs_tensor.unsqueeze(dim=0).float(), size = self.output_size, mode = self.mode).squeeze(dim=0)
        targets_rescaled = torch.nn.functional.interpolate(targets_tensor.unsqueeze(dim=0).float(), size = self.output_size, mode = self.mode).squeeze(dim=0)
        
        combine = {'input':inputs_rescaled, 'target':targets_rescaled }

        return combine
なぜsqeeze処理をしたのかを聞くことができます.補間ソースコードを見ると、次元を追加するのが望ましい処理です.
path_train_inputs = '/home/mskang/hyeokjong/cancer/2018/task1/train_input_pad'
path_train_targets = '/home/mskang/hyeokjong/cancer/2018/task1/train_targets_pad'

transformation = transforms.Compose([
                                    RandomFlip(),
                                    ToTensor(), 
                                    Resize((200,200), mode ='nearest')
                                      ])

train_dataset = custom_dataset(path_train_inputs, path_train_targets, transformation  )




batch_size = 4

train_dl = DataLoader(train_dataset, batch_size, shuffle=True,
                      num_workers=4, pin_memory=True)

for i,j in train_dl:
    inputs, targets = i,j
    break

plt.imshow(np.array(np.transpose(inputs[0],(1,2,0))).astype(np.uint8))
plt.imshow(np.array(np.transpose(targets[0],(1,2,0))).astype(np.uint8),cmap='gray')
運転がよい.
また、CEEを使用するには、targetをチャネル方向に押し出す必要があります.
その他の記事があります