裂缝检测原本采用分割模型较多,目前我测试了采用hed的裂缝检测;代码采用这个版本的代码是最简洁易懂的,https://github.com/senliuy/Keras_HED_with_model
环境:win10 keras2.2.4
hed.py
from keras.layers import Conv2D, Conv2DTranspose, Input, MaxPooling2D
from keras.layers import Concatenate, Activation
from keras.models import Model
from keras import backend as K
import tensorflow as tf
from keras.optimizers import *def side_branch(x, factor):x = Conv2D(1, (1, 1), activation=None, padding='same')(x)kernel_size = (2*factor, 2*factor)x = Conv2DTranspose(1, kernel_size, strides=factor, padding='same', use_bias=False, activation=None)(x)return xdef hed():# Inputimg_input = Input(shape=(480,480,3), name='input')# Block 1x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)b1= side_branch(x, 1) # 480 480 1x = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='block1_pool')(x) # 240 240 64# Block 2x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)b2= side_branch(x, 2) # 480 480 1x = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='block2_pool')(x) # 120 120 128# Block 3x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)b3= side_branch(x, 4) # 480 480 1x = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='block3_pool')(x) # 60 60 256# Block 4x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)b4= side_branch(x, 8) # 480 480 1x = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='block4_pool')(x) # 30 30 512# Block 5x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x) # 30 30 512b5= side_branch(x, 16) # 480 480 1# fusefuse = Concatenate(axis=-1)([b1, b2, b3, b4, b5])fuse = Conv2D(1, (1,1), padding='same', use_bias=False, activation=None)(fuse) # 480 480 1# outputso1 = Activation('sigmoid', name='o1')(b1)o2 = Activation('sigmoid', name='o2')(b2)o3 = Activation('sigmoid', name='o3')(b3)o4 = Activation('sigmoid', name='o4')(b4)o5 = Activation('sigmoid', name='o5')(b5)ofuse = Activation('sigmoid', name='ofuse')(fuse)# modelmodel = Model(inputs=[img_input], outputs=[o1, o2, o3, o4, o5, ofuse])filepath = './models/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'# load_weights_from_hdf5_group_by_name(model, filepath)adam = Adam(lr = 1e-4, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0001)model.compile(optimizer= adam,loss={'o1': cross_entropy_balanced,'o2': cross_entropy_balanced,'o3': cross_entropy_balanced,'o4': cross_entropy_balanced,'o5': cross_entropy_balanced,'ofuse': cross_entropy_balanced,},metrics={'ofuse': ofuse_pixel_error})return model
损失函数:
def cross_entropy_balanced(y_true, y_pred):"""Implements Equation [2] in https://arxiv.org/pdf/1504.06375.pdfCompute edge pixels for each training sample and set as pos_weights to tf.nn.weighted_cross_entropy_with_logits"""# Note: tf.nn.sigmoid_cross_entropy_with_logits expects y_pred is logits, Keras expects probabilities.# transform y_pred back to logits_epsilon = _to_tensor(K.epsilon(), y_pred.dtype.base_dtype)y_pred = tf.clip_by_value(y_pred, _epsilon, 1 - _epsilon)y_pred = tf.log(y_pred/ (1 - y_pred))y_true = tf.cast(y_true, tf.float32)count_neg = tf.reduce_sum(1. - y_true)count_pos = tf.reduce_sum(y_true)# Equation [2]beta = count_neg / (count_neg + count_pos)# Equation [2] divide by 1 - betapos_weight = beta / (1 - beta)cost = tf.nn.weighted_cross_entropy_with_logits(logits=y_pred, targets=y_true, pos_weight=pos_weight)# Multiply by 1 - betacost = tf.reduce_mean(cost * (1 - beta))# check if image has no edge pixels return 0 else return complete error functionreturn tf.where(tf.equal(count_pos, 0.0), 0.0, cost)
模型输出图:
训练曲线:
效果:
效果相当不错: