Lecture 03 学习讲义
正文
工具
按问题查找
Lecture 03为什么同时训练 1×1 读出和 FCN · 实现代码

为什么同时训练 1×1 读出和 FCN · 实现代码

独立阅读

按问题继续

前景/背景/mIoU口径、RGB到mask训练、FCN与1×1读出及边界

展开完整实现代码
%%writefile -a lab11_segmentation.py
def binary_metrics(pred,target):
    ious=[]
    for cls in [0,1]:
        inter=((pred==cls)&(target==cls)).sum().item();union=((pred==cls)|(target==cls)).sum().item()
        ious.append(inter/union)
    return {'background_IoU':ious[0],'foreground_IoU':ious[1],'mIoU_two_classes':sum(ious)/2,
            'pixel_accuracy':float((pred==target).float().mean()),'error_pixels':int((pred!=target).sum())}

def sampling_warmup(out):
    mask=torch.zeros((8,8),dtype=torch.long);mask[2:6,3:7]=1
    coarse=F.avg_pool2d(mask.float()[None,None],2)
    nearest=F.interpolate(coarse,scale_factor=2,mode='nearest')[0,0]>=.5
    bilinear=F.interpolate(coarse,scale_factor=2,mode='bilinear',align_corners=False)[0,0]>=.5
    nm=binary_metrics(nearest,mask);bm=binary_metrics(bilinear,mask)
    assert abs(nm['foreground_IoU']-2/3)<1e-12
    assert abs(nm['background_IoU']-5/6)<1e-12
    assert abs(nm['mIoU_two_classes']-.75)<1e-12 and nm['error_pixels']==8
    # Bilinear interpolates probabilities/logits; categorical labels use nearest.
    fig,axes=plt.subplots(1,4,figsize=(10,3))
    for ax,data,title in zip(axes,[mask,coarse[0,0],nearest,bilinear],['Known mask','2x2 average','Nearest >=0.5','Bilinear >=0.5']):
        ax.imshow(data,cmap='gray',vmin=0,vmax=1,interpolation='nearest');ax.set_title(title);ax.axis('off')
    fig.tight_layout();fig.savefig(out/'sampling-warmup.png',dpi=150);plt.close(fig)
    return {'nearest':nm,'bilinear_align_corners_false':bm,'identity':'known-mask resampling only; no image model'}

class PixelReadout(nn.Module):
    """A learned softmax regression at every RGB pixel; no spatial receptive field."""
    def __init__(self):super().__init__();self.readout=nn.Conv2d(3,3,1)
    def forward(self,x,mode='bilinear'):return self.readout(x)

class SmallFCN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fine=nn.Sequential(nn.Conv2d(3,12,3,padding=1),nn.ReLU(),nn.Conv2d(12,12,3,padding=1),nn.ReLU())
        self.coarse=nn.Sequential(nn.Conv2d(12,24,3,stride=2,padding=1),nn.ReLU(),nn.Conv2d(24,32,3,stride=2,padding=1),nn.ReLU(),nn.Conv2d(32,32,3,padding=1),nn.ReLU())
        self.head=nn.Conv2d(32,3,1);self.skip=nn.Conv2d(12,3,1)
    def forward(self,x,mode='bilinear'):
        fine=self.fine(x);coarse_logits=self.head(self.coarse(fine))
        kw={'align_corners':False} if mode=='bilinear' else {}
        return F.interpolate(coarse_logits,size=x.shape[-2:],mode=mode,**kw)+self.skip(fine)

def with_ignore(masks):
    masks=masks.clone();masks[:,0,:]=255;masks[:,-1,:]=255;masks[:,:,0]=255;masks[:,:,-1]=255
    # A fixed small region represents missing annotation, not another semantic class.
    masks[:,20:23,20:23]=255
    return masks