语义分割-FCN8S(案例)

代码

导包

import tensorflow as tf
import glob
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
from IPython.display import display
import os.path

常量

# 图片大小
IMG_WIDTH=224

AUTOTUNE=tf.data.experimental.AUTOTUNE

# vgg16权重文件
vgg16_h5='/kaggle/input/vgg16-weights-tf-dim-ordering-tf-kernels-notop/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'

获取所有jpg图片路径

# 有3个mat文件
img_paths=glob.glob("/kaggle/input/head-location/images/images/*.jpg")
# png_paths=glob.glob("/kaggle/input/head-location/annotations/annotations/trimaps/*")

print(img_paths[:3])
# print(png_paths[:3])

查看所有图片数量

count_img=len(img_paths)
# count_png=len(png_paths)
print(count_img)
# print(count_png)

获取所有png图片路径

jpg图片和png图片可能不是一一对应的,所以需要根据jpg图片名字,获取png图片路径

png_path="/kaggle/input/head-location/annotations/annotations/trimaps/"
png_paths=[]
def get_png_paths():
    for item in img_paths:
    #     print(item)
        name=os.path.basename(item).split(".")[0]+".png"
#         print(name)
        path=os.path.join(png_path,name)
        png_paths.append(path)
#         print(path)

get_png_paths()    

print(png_paths[0])
print(len(png_paths))

测试:显示jpg和png图片

display(Image.open(img_paths[0]))
display(Image.open(png_paths[0]))

注意: png图片不能正常显示

查看png图片内部数据(关键)

from collections import Counter
def show_png_data():
    arr=np.array(Image.open(png_paths[0]))
    print(type(arr))
    print(arr)
    print("最小数:",np.min(arr))
    print("最大数:",np.max(arr))

    print(Counter(arr.flatten()))

show_png_data()

执行结果:

<class 'numpy.ndarray'>
[[2 2 2 ... 2 2 2]
 [2 2 2 ... 2 2 2]
 [2 2 2 ... 2 2 2]
 ...
 [2 2 2 ... 2 2 2]
 [2 2 2 ... 2 2 2]
 [2 2 2 ... 2 2 2]]
最小数: 1
最大数: 3
Counter({2: 132176, 1: 37847, 3: 17477})

可知png图片的数据只有1,2,3

用matplotlib图片

matplotlib显示特殊图片时,会自行调整,显示成人眼可识别的图片

plt.imshow(Image.open(img_paths[0]))
plt.show()

plt.imshow(Image.open(png_paths[0]))
plt.show()

生成Dataset

ds=tf.data.Dataset.from_tensor_slices((img_paths,png_paths))

测试

for jpg,png in ds.take(2):
    print(jpg)
    print(png)
    print('--')

实现解析图片函数(关键)

def parse_jpg(path):
    img=tf.io.read_file(path)
    img=tf.image.decode_jpeg(img,channels=3)
    img=tf.image.resize(img,(IMG_WIDTH,IMG_WIDTH))
    img=img/255

    return img

下面代码处理png图片时,要-1(这是laben)

def parse_png(path):
    img=tf.io.read_file(path)
    img=tf.image.decode_png(img,channels=1)
    img=tf.image.resize(img,(IMG_WIDTH,IMG_WIDTH))
    img=img-1

    return img
def parse_img(jpg_path,png_path):
    jpg=parse_jpg(jpg_path)
    png=parse_png(png_path)

    return jpg,png

执行函数

ds2=ds.map(parse_img,num_parallel_calls=AUTOTUNE).shuffle(count_img)

分割训练集和测试集

train_count=int(count_img*0.7)

train_ds=ds2.take(train_count)
test_ds=ds2.skip(train_count)

测试图片

for jpg,png in train_ds.take(2):
#     print(jpg.numpy())
#     arr=png.numpy()
#     print(collections.Counter(arr.flatten()))
    plt.imshow(jpg.numpy())
    plt.show()
    png2=np.squeeze(png.numpy())
    plt.imshow(png2)
    plt.show()

准备训练集和测试集

train_ds2=train_ds.shuffle(train_count).batch(8).prefetch(AUTOTUNE)
test_ds2=test_ds.batch(8).prefetch(AUTOTUNE)

train_ds

加载vgg16模型

使用vgg16模型提取图片的特征,所以设置其不可训练

app_vgg16=tf.keras.applications.VGG16(include_top=False,weights=vgg16_h5,input_shape=(IMG_WIDTH,IMG_WIDTH,3))

app_vgg16.trainable=False

app_vgg16.summary()

构建FCN模型(关键)

def build_fcn8_vgg16():

    pool3=app_vgg16.get_layer("block3_pool").output
    print(pool3.shape)
    pool4=app_vgg16.get_layer("block4_pool").output
    print(pool4.shape)

#     卷积层
    print(app_vgg16.name,":",app_vgg16.output.shape)

#     上采样,放大2倍
    o=tf.keras.layers.Conv2DTranspose(512,2,2,padding="same",activation="relu",name="myblock8_conv_convtran")(app_vgg16.output) #padding="same",
    print(o.name,":",o.shape)

#     对pool4进行卷积运算
    o2=tf.keras.layers.Conv2D(512,1,1,activation="relu",padding="same",name="pool4_conv")(pool4)
    print(o2.shape)

    o=tf.add(o,o2,name="myblock8_conv_convtran_add_pool4_conv")

#     上采样,放大2倍
    o = tf.keras.layers.Conv2DTranspose(256, 2, 2, padding="same", activation="relu",name="sum_convtran")(o)

#     对pool3进行卷积运算
    o2=tf.keras.layers.Conv2D(256,1,1,activation="relu",padding="same",name="pool3_conv")(pool3)
    print(o2.shape)    

    o=tf.add(o,o2,name="sum_convtran_add_pool3_conv")

    o=tf.keras.layers.Conv2D(64,3,1,padding="same",activation="relu")(o)
    print(o.shape)

#     对最终结果放大8倍
    o = tf.keras.layers.Conv2DTranspose(3, 8, 8, padding="same", activation="softmax",name="result")(o)

    model=tf.keras.Model(inputs=app_vgg16.input,outputs=[o],name="fcn8s_vgg16")

    print("|"*50)
    model.summary()

    return model



model=build_fcn8_vgg16()

执行结果:

(None, 28, 28, 256)
(None, 14, 14, 512)
vgg16 : (None, 7, 7, 512)
myblock8_conv_convtran/Identity:0 : (None, 14, 14, 512)
(None, 14, 14, 512)
(None, 28, 28, 256)
(None, 28, 28, 64)
||||||||||||||||||||||||||||||||||||||||||||||||||
Model: "fcn8s_vgg16"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_1 (InputLayer)            [(None, 224, 224, 3) 0                                            
__________________________________________________________________________________________________
block1_conv1 (Conv2D)           (None, 224, 224, 64) 1792        input_1[0][0]                    
__________________________________________________________________________________________________
block1_conv2 (Conv2D)           (None, 224, 224, 64) 36928       block1_conv1[0][0]               
__________________________________________________________________________________________________
block1_pool (MaxPooling2D)      (None, 112, 112, 64) 0           block1_conv2[0][0]               
__________________________________________________________________________________________________
block2_conv1 (Conv2D)           (None, 112, 112, 128 73856       block1_pool[0][0]                
__________________________________________________________________________________________________
block2_conv2 (Conv2D)           (None, 112, 112, 128 147584      block2_conv1[0][0]               
__________________________________________________________________________________________________
block2_pool (MaxPooling2D)      (None, 56, 56, 128)  0           block2_conv2[0][0]               
__________________________________________________________________________________________________
block3_conv1 (Conv2D)           (None, 56, 56, 256)  295168      block2_pool[0][0]                
__________________________________________________________________________________________________
block3_conv2 (Conv2D)           (None, 56, 56, 256)  590080      block3_conv1[0][0]               
__________________________________________________________________________________________________
block3_conv3 (Conv2D)           (None, 56, 56, 256)  590080      block3_conv2[0][0]               
__________________________________________________________________________________________________
block3_pool (MaxPooling2D)      (None, 28, 28, 256)  0           block3_conv3[0][0]               
__________________________________________________________________________________________________
block4_conv1 (Conv2D)           (None, 28, 28, 512)  1180160     block3_pool[0][0]                
__________________________________________________________________________________________________
block4_conv2 (Conv2D)           (None, 28, 28, 512)  2359808     block4_conv1[0][0]               
__________________________________________________________________________________________________
block4_conv3 (Conv2D)           (None, 28, 28, 512)  2359808     block4_conv2[0][0]               
__________________________________________________________________________________________________
block4_pool (MaxPooling2D)      (None, 14, 14, 512)  0           block4_conv3[0][0]               
__________________________________________________________________________________________________
block5_conv1 (Conv2D)           (None, 14, 14, 512)  2359808     block4_pool[0][0]                
__________________________________________________________________________________________________
block5_conv2 (Conv2D)           (None, 14, 14, 512)  2359808     block5_conv1[0][0]               
__________________________________________________________________________________________________
block5_conv3 (Conv2D)           (None, 14, 14, 512)  2359808     block5_conv2[0][0]               
__________________________________________________________________________________________________
block5_pool (MaxPooling2D)      (None, 7, 7, 512)    0           block5_conv3[0][0]               
__________________________________________________________________________________________________
myblock8_conv_convtran (Conv2DT (None, 14, 14, 512)  1049088     block5_pool[0][0]                
__________________________________________________________________________________________________
pool4_conv (Conv2D)             (None, 14, 14, 512)  262656      block4_pool[0][0]                
__________________________________________________________________________________________________
tf_op_layer_myblock8_conv_convt [(None, 14, 14, 512) 0           myblock8_conv_convtran[0][0]     
                                                                 pool4_conv[0][0]                 
__________________________________________________________________________________________________
sum_convtran (Conv2DTranspose)  (None, 28, 28, 256)  524544      tf_op_layer_myblock8_conv_convtra
__________________________________________________________________________________________________
pool3_conv (Conv2D)             (None, 28, 28, 256)  65792       block3_pool[0][0]                
__________________________________________________________________________________________________
tf_op_layer_sum_convtran_add_po [(None, 28, 28, 256) 0           sum_convtran[0][0]               
                                                                 pool3_conv[0][0]                 
__________________________________________________________________________________________________
conv2d (Conv2D)                 (None, 28, 28, 64)   147520      tf_op_layer_sum_convtran_add_pool
__________________________________________________________________________________________________
result (Conv2DTranspose)        (None, 224, 224, 3)  12291       conv2d[0][0]                     
==================================================================================================
Total params: 16,776,579
Trainable params: 2,061,891
Non-trainable params: 14,714,688
__________________________________________________________________________________________________

可视化模型

tf.keras.utils.plot_model(model2,to_file="model.png",show_shapes=True)

编译 和 训练

def exe_model():
#     model.compile(optimizer="adam",loss="sparse_categorical_crossentropy",metrics=["acc"])
    model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),loss="sparse_categorical_crossentropy",metrics=["acc"])
    history=model.fit(train_ds2,epochs=20,validation_data=test_ds2)

    return history

history=exe_model()

查看损失值 和 评价值

plt.plot(history.epoch,history.history.get("loss"),label="loss")
plt.plot(history.epoch,history.history.get("val_loss"),label="val_loss")
plt.legend()
plt.show()

plt.plot(history.epoch,history.history.get("acc"),label="acc")
plt.plot(history.epoch,history.history.get("val_acc"),label="val_acc")
plt.legend()
plt.show()

保存模型

model.save("model.h5")

下接:https://www.malaoshi.top/show_1EF54Wt0sPnN.html