浅谈Attention UNet
1 理论
其中,g就是解码部分的矩阵,xl是编码(左边)的矩阵,x经过乘于系数(完成Attention)和g一起concat,进入下一层解码。
数学公式:
2 实践
Pytorch Attention Unet:
class Attention_block(nn.Module):
def __init__(self,F_g,F_l,F_int):
super(Attention_block,self).__init__()
self.W_g = nn.Sequential(
nn.Conv2d(F_g, F_int, kernel_size=1,stride=1,padding=0,bias=True),
nn.BatchNorm2d(F_int)
)
self.W_x = nn.Sequential(
nn.Conv2d(F_l, F_int, kernel_size=1,stride=1,padding=0,bias=True),
nn.BatchNorm2d(F_int)
)
self.psi = nn.Sequential(
nn.Conv2d(F_int, 1, kernel_size=1,stride=1,padding=0,bias=True),
nn.BatchNorm2d(1),
nn.Sigmoid()
)
self.relu = nn.ReLU(inplace=True)
def forward(self,g,x):
g1 = self.W_g(g)
x1 = self.W_x(x)
psi = self.relu(g1+x1)
psi = self.psi(psi)
return x*psi
numpy 版本理解:
import numpy as np
a = np.array([[1,1,0],[0,1,0],[1,1,1]])
b = np.array([[1,0,0],[0,1,0],[1,0,1]])
import torch
#m = nn.Sigmoid()
#print(m(torch.from_numpy(a).float()))
n_dim = 2
w1 = np.random.normal(0, 1, (a.shape[0],n_dim))
w2 = np.random.normal(0, 1, (b.shape[0],n_dim))
w3 = np.random.normal(0, 1, (n_dim,1))
def relu(x):
return x*(x>0)
def sigmoid(x):
return 1/(1+ np.exp(-x))
#
res = np.matmul((np.matmul(a,w1) + np.matmul(b,w2)),w3)
resRelu = relu(res)
resSigmoid= sigmoid(resRelu)
final = a*resSigmoid
print('a:\n', a)
print('\nb\n',b)
print('\n final a:\n',final)
输出:
a:
[[1 1 0]
[0 1 0]
[1 1 1]]
b
[[1 0 0]
[0 1 0]
[1 0 1]]
final a:
[[0.84840315 0.84840315 0. ]
[0. 0.70498539 0. ]
[0.58395277 0.58395277 0.58395277]]
这里,可以看出,Attention的作用就是调整权重。
3 疑问与理解
使用两个矩阵相乘,第一次相乘是,g,x之间的权重分配,第二次相乘是,每个像素的权重分配。
参考:
1 GitHub源码:Attention U-Net: Learning Where to Look for the Pancreas ;
2 Pytorch attention Unet;