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