1、Coordinate Attention
原论文:Coordinate Attention for Efficient Mobile Network Design
参考资料:将位置信息嵌入通道注意力!NUS提出新机制,显著提高卷积特征表达|CVPR2021
import tensorflow as tf from tensorflow import keras class CoordAtt(keras.layers.Layer): def __init__(self, filters, reduction=16, **kwargs): super(CoordAtt, self).__init__(**kwargs) self.fc1 = keras.Sequential([ keras.layers.Conv2D(filters//reduction, 1, use_bias=False), keras.layers.BatchNormalization(), keras.layers.ReLU() ]) self.xfc = keras.layers.Conv2D(filters, 1, activation='sigmoid') self.yfc = keras.layers.Conv2D(filters, 1, activation='sigmoid') def call(self, inputs): shape = tf.shape(inputs) # (batch, h, w, c) xap = tf.math.reduce_mean(inputs, axis=2, keepdims=True) # (batch, h, 1, c) yap = tf.math.reduce_mean(inputs, axis=1, keepdims=True) # (batch, 1, w, c) xap_transpose = tf.transpose(xap, perm=[0,2,1,3]) # (batch, 1, h, c) merge = tf.concat([xap_transpose, yap], axis=2) # (batch, 1, h w, c) fc = self.fc1(merge) # (batch, 1, h w, c//r) xat_transpose, yat = tf.split(fc, [shape[1], shape[2]], axis=2) # (batch, 1, h, c//r) (batch, 1, w, c//r) xac_transpose, yac = self.xfc(xat_transpose), self.yfc(yat) # (batch, 1, h, c) (batch, 1, w, c) xac = tf.transpose(xac_transpose, perm=[0,2,1,3] # (batch, h, 1, c) return inputs * xac * yac # (batch, h, w, c) * (batch, h, 1, c) * (batch, 1, w, c)
2、SoftPool(2D)
原论文:Refining activation downsampling with SoftPool
参考资料:在深度学习中阅读各种池化方法!
import tensorflow as tf from tensorflow import keras class SoftPool(keras.layers.Layer): def __init__(self, pool_size=(2, 2), **kwargs): super(SoftPool, self).__init__(**kwargs) self.pool_size = pool_size def call(self, inputs): e_x = tf.math.exp(inputs) # (batch, height, width, channel) e_x_sum = tf.math.reduce_sum(e_x, axis=-1, keepdims=True) # (batch, height, width, 1) top = keras.layers.AveragePooling2D(self.pool_size)(inputs*e_x_sum) # (batch, height/2, width/2, channel) bottom = keras.layers.AveragePooling2D(self.pool_size)(e_x_sum) # (batch, height/2, width/2, 1) return tf.math.divide_no_nan(top, bottom) # (batch, height/2, width/2, channel)
评价指标适用于二分类:F_beta、IoU、Kappa
import tensorflow as tf class F1(tf.keras.metrics.Metric): # beta价值决定了召回率的比例,beta>1.召回率的影响比精度大 def __init__(self, beta=1, name='F1', **kwargs): super(F1, self).__init__(name=name, **kwargs) self.Pre = tf.keras.metrics.Precision() self.Rec = tf.keras.metrics.Recall() self.beta = self.add_weight(name='beta', initializer='zeros') self.beta.assign_add( beta ) def update_state(self, y_true, y_pred, sample_weight=None): self.Pre.update_state(y_true, y_pred, sample_weight=sample_weight) self.Rec.update_state(y_true, y_pred, sample_weight=sample_weight) def result(self): total = self.Pre.result() * self.beta**2 self.Rec.result() return (1 self.beta**2 )*self.Pre.result()*self.Rec.result() / (total 1e-8) def reset_states(self): self.Pre.reset_states() self.Rec.reset_states() class IoU(tf.keras.metrics.Metric): # intersection of union def __init__(self, name='IoU', **kwargs): super(IoU, self).__init__(name=name, **kwargs) self.TP = self.add_weight(name='tp', initializer='zeros') self.FP = self.add_weight(name='fp', initializer='zeros') self.FN = self.add_weight(name='fn', initializer='zeros') def update_state(self, y_true, y_pred, sample_weight=None): y_true = tf.cast(tf.reshape(y_true, (-1,)), dtype=tf.float32) y_pred = tf.cast(tf.reshape(y_pred, (-1,)), dtype=tf.float32) y_pred = tf.cast(y_pred > 0.5, dtype=tf.float32) tp = y_true*y_pred fp = (1-y_true)*y_pred fn = y_true*(1-y_pred) if sample_weight is not None: w = tf.cast(tf.reshape(sample_weight, (-1,)), dtype=tf.float32) tp *= w fp *= w fn *= w self.TP.assign_add( tf.math.reduce_sum(tp) ) self.FP.assign_add( tf.math.reduce_sum(fp) ) self.FN.assign_add( tf.math.reduce_sum(fn) ) def result(self): total = self.TP selfFP + self.FN + 1e-8
return self.TP / total
def reset_states(self):
self.TP.assign(0.0)
self.FP.assign(0.0)
self.FN.assign(0.0)
class Kappa(tf.keras.metrics.Metric):
# 只适用于二分类的Kappa系数
def __init__(self, name='Kappa', **kwargs):
super(Kappa, self).__init__(name=name, **kwargs)
self.TP = self.add_weight(name='tp', initializer='zeros')
self.FP = self.add_weight(name='fp', initializer='zeros')
self.FN = self.add_weight(name='fn', initializer='zeros')
self.TN = self.add_weight(name='tn', initializer='zeros')
def update_state(self, y_true, y_pred, sample_weight=None):
y_true = tf.cast(tf.reshape(y_true, (-1,)), dtype=tf.float32)
y_pred = tf.cast(tf.reshape(y_pred, (-1,)), dtype=tf.float32)
y_pred = tf.cast(y_pred > 0.5, dtype=tf.float32)
tp = y_true*y_pred
fp = (1-y_true)*y_pred
fn = y_true*(1-y_pred)
tn = (1-y_true)*(1-y_pred)
if sample_weight is not None:
w = tf.cast(tf.reshape(sample_weight, (-1,)), dtype=tf.float32)
tp *= w
fp *= w
fn *= w
tn *= w
self.TP.assign_add( tf.math.reduce_sum(tp) )
self.FP.assign_add( tf.math.reduce_sum(fp) )
self.FN.assign_add( tf.math.reduce_sum(fn) )
self.TN.assign_add( tf.math.reduce_sum(tn) )
def result(self):
total = self.TP + self.FP + self.FN + self.TN + 1e-8
pre1 = (self.TP + self.FN) * (self.TP + self.FP)
pre2 = (self.TN + self.FN) * (self.TN + self.FP)
pre = (pre1 + pre2) / total**2
oa = (self.TP + self.TN) / total
return (oa - pre) / (1 - pre)
def reset_states(self):
self.TP.assign(0.0)
self.FP.assign(0.0)
self.FN.assign(0.0)
self.TN.assign(0.0)
if __name__=='__main__':
m = F1()
m.update_state([[0, 1, 1, 1], [1, 0, 1, 1]], [[0, 0, 1, 0], [0, 0, 1, 1]])
print('F1:', m.result().numpy()) # F1: 0.6666667
m = F1(beta = 2)
m.update_state([[0, 1, 1, 1], [1, 0, 1, 1]], [[0, 0, 1, 0], [0, 0, 1, 1]])
print('F2:', m.result().numpy()) # F2: 0.5555556
m = IoU()
m.update_state([[0, 1, 1, 1], [1, 0, 1, 1]], [[0, 0, 1, 0], [0, 0, 1, 1]])
print('IoU:', m.result().numpy()) # IoU: 0.5
m = Kappa()
m.update_state([[0, 1, 1, 1], [1, 0, 1, 1]], [[0, 0, 1, 0], [0, 0, 1, 1]])
print('Kappa:', m.result().numpy()) # Kappa: 0.33333334
print(m.name)
适用于二类语义分割的损失函数:balanced crossentropy、dice loss、focal loss、tversky loss
import tensorflow as tf
def balanced_crossentropy(y_true, y_pred):
y = tf.keras.layers.Flatten()(y_true)
y_hat = tf.keras.layers.Flatten()(y_pred)
_b = tf.math.reduce_sum(y, axis=-1)/(256*256)
# sigmoid 在输入参数非常大或非常小的情况下,会给出边界值1或者0
pred1 = tf.clip_by_value(y_hat, 1e-10, 0.99999)
pred0 = tf.clip_by_value(1-y_hat, 1e-10, 0.99999)
loss1 = tf.math.reduce_sum(y*tf.math.log(pred1), axis=-1)
loss0 = tf.math.reduce_sum((1-y)*tf.math.log(pred0), axis=-1)
loss_bce = -(1-_b)*loss1 -_b*loss0
return tf.math.reduce_mean(loss_bce)
def dice_loss(y_true, y_pred, delta=1):
y = tf.keras.layers.Flatten()(y_true)
y_hat = tf.keras.layers.Flatten()(y_pred)
total = tf.math.reduce_sum(y, axis=-1) + tf.math.reduce_sum(y_hat, axis=-1) + delta
loss_dice = 1 - 2*tf.math.reduce_sum(y*y_hat, axis=-1)/total
return tf.math.reduce_mean(loss_dice)
def focal_loss(y_true, y_pred, alpha=0.25, gamma=2):
y = tf.keras.layers.Flatten()(y_true)
y_hat = tf.keras.layers.Flatten()(y_pred)
pred1 = tf.clip_by_value(y_hat, 1e-10, 0.99999)
pred0 = tf.clip_by_value(1-y_hat, 1e-10, 0.99999)
loss1 = tf.math.reduce_sum( y * (1-y_hat)**gamma * tf.math.log(pred1), axis=-1)
loss0 = tf.math.reduce_sum( (1-y) * (y_hat)**gamma * tf.math.log(pred0), axis=-1)
loss_focal = -alpha*loss1 -(1-alpha)*loss0
return tf.math.reduce_mean(loss_focal)
def tversky_loss(y_true, y_pred, alpha=0.5, beta=0.5, delta=1):
y = tf.keras.layers.Flatten()(y_true)
y_hat = tf.keras.layers.Flatten()(y_pred)
tp = tf.math.reduce_sum(y*y_hat, axis=-1)
fp = tf.math.reduce_sum((1-y)*y_hat, axis=-1)
fn = tf.math.reduce_sum(y*(1-y_hat), axis=-1)
loss_tversky = tp/(tp + alpha*fp + beta*fn + delta)
return tf.math.reduce_mean(loss_tversky)
1、GPU使用基础设置
import os
import tensorflow as tf
# 指定程序运行使用的显卡
os.environ['CUDA_VISIBLE_DEVICES'] = '0,2,3'
# 动态分配显存
gpus = tf.config.experimental.list_physical_devices("GPU")
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
2、训练过程中的loss和指标值可视化
import matplotlib.pyplot as plt
def Visualization(H, names, save_path):# 可视化
shape = np.shape(names)
fig,ax = plt.subplots(shape[0], shape[1], figsize=(shape[1]*8, shape[0]*6)) # 宽、高
for i in range(shape[0]):
for j in range(shape[1]):
ax[i,j].set_xlabel('Epoch')
ax[i,j].set_ylabel(names[i][j])
ax[i,j].plot(H.history[names[i][j]], '-b.', label='train_'+names[i][j])
ax[i,j].plot(H.history['val_'+names[i][j]], '-r.', label='val_'+names[i][j])
ax[i,j].legend(loc='best')
# plt.show()
plt.savefig(save_path)