class weightの実装(Pytorch)

point

  • lossをラベルごとに出力
  • lossとweightをかける
  • lossの平均をとる
# weightの算出方法は自由
weights = torch.tensor(df.iloc[:,2:].sum(axis=0))
max = weights.max().item()
weights = max/weights
weights = weights.to(DEVICE)

criterion = nn.BCEWithLogitsLoss(reduction='none') # reductionをnoneに指定

loss = criterion(outputs, labels)
loss = (loss * weights).mean() # weighting

画像を画素値で選別してzipファイルを作成する

  1. パスのリストを取得
  2. 一枚ずつ読み込んで画素値平均を計算
  3. 一定数以下の場合は削除
import glob
import os

path = glob.glob('/content/input/nuclear_membrane/protein/*.png')

for i in path:
  img = cv2.imread(i)
  m = img.mean()
  if m <= 1.5:
    os.remove(i)
    rgb_path = i.replace('protein','rgb')
    os.remove(rgb_path)

!zip -r new_nuclear_membrane.zip protein rgb
!cp new_nuclear_membrane.zip /content/drive/MyDrive/kaggle/HPA/data

mixupの実装

ラベルが1のときに、dfからランダムで画像を1つ選択して元の画像と混ぜ合わせる処理を記述している
mixの割合はrandomの乱数により決定

注意点
random.randint(a, b)
ランダムな整数を返すが、bも範囲に含まれる

class Dataset(Dataset):
    def __init__(self, df, transform):
        self.df = df
        self.label = df.label
        self.transform = transform
        
    def __len__(self):
        return len(self.df)
    
    def __getitem__(self, idx):
        lbl = torch.tensor([self.label[idx]]) # labelをtorch型に変換
        lbl_ohe = F.one_hot(lbl,num_classes=2).view(-1).to(torch.float32) # ohe_hot_encoding化,1次元に変換

        ri = cv2.imread(self.df.red[idx])[...,0]
        gi = cv2.imread(self.df.green[idx])[...,1]
        bi = cv2.imread(self.df.blue[idx])[...,2]
        img = np.stack([ri, gi, bi], axis=-1)
        img = self.transform(image=img)['image']
        
        if lbl == 1:  
          d = random.randrange(6, 10, 1)*0.1
          if d < 1:
            sub_idx = random.randint(0, len(self.df)-1)
            ri = cv2.imread(self.df.red[sub_idx])[...,0]
            gi = cv2.imread(self.df.green[sub_idx])[...,1]
            bi = cv2.imread(self.df.blue[sub_idx])[...,2]

            sub_img = np.stack([ri, gi, bi], axis=-1)
            sub_img = self.transform(image=sub_img)['image']
            
            img = img*d + sub_img*(1-d)

        
        return img, lbl_ohe

TTAの実装(PyTorch)

  1. CFGでTTA定義
  2. datasetでもself.TTA定義
  3. train roopの際に画像をそれぞれ受け取ってGPUに乗せてmodelに入れて平均をとる
class TestData(Dataset):
    def __init__(self, TTA=False):
        self.TTA = TTA

    def __getitem__(self,index):
        if self.TTA:
            imgs =  ...
            imgs2 = imgs.flip(2,3) # 縦横反転(2が縦、3が横)
            imgs3 = torch.rot90(imgs,1,[2,3]) #2,3次元の軸で左に90度回転
            imgs4 = torch.rot90(imgs,-1,[2,3]) #2,3次元の軸で右に90度回転
            return imgs, imgs2, imgs3, imgs3
        else:
            imgs = self.cell_tiles[index] #リスト配列のnumpy画像(3次元)を取得
            imgs = [self.transform()(image=img)['image'] for img in imgs]
            imgs = torch.stack(imgs, 0)
            return imgs


        # 以下、train roopでの実装
        if CFG.TTA:
            testset = TestData(batch_cell_tiles, test_transform, TTA=True)
            testloader = DataLoader(testset,
                                     batch_size=1,
                                     shuffle=False,
                                     num_workers=4,
                                     collate_fn=collate_fn)

            with torch.no_grad():
                model.eval()
                for images, images2, images3, images4 in testloader: # images:all cell image of one test image
                    images = images.to(DEVICE)
                    images2 = images2.to(DEVICE)
                    images3 = images3.to(DEVICE)
                    images4 = images4.to(DEVICE)
                    
                    output = model(images)
                    output = nn.Sigmoid()(output)
                    
                    output2 = model(images2)
                    output2 = nn.Sigmoid()(output2)
                    
                    output3 = model(images3)
                    output3 = nn.Sigmoid()(output3)
                    
                    output4 = model(images4)
                    output4 = nn.Sigmoid()(output4)
                    
                    output = (output+output2+output3+output4)/4

gradient accumulation by PyTorch

Gradeint Accumulation

  1. バックプロパゲーション
  2. lossをaccumulation_stepsで割る
  3. idxをaccumulation_stepsで割って0の場合3以下
  4. optimizerのstep
  5. model.zero_grad()
    ※model.zero_grad()はfor roopに入る前も入れておく
loss = criterion(output, target)
loss = loss / accumulation_steps     
loss.backward()                                 # Backward pass
if (i+1) % accumulation_steps == 0:             # Wait for several backward steps
    optimizer.step()                            # Now we can do an optimizer step
    model.zero_grad()