tensorflow学习017——卫星图像识别 tf.data 卷积综合实例

五 卫星图像识别 tf.data 卷积综合实例

二分类问题:飞机、湖泊
所有的数据都放在2_class文件夹下的两个文件夹airplane、lake
数据集百度网盘
链接:https://pan.baidu.com/s/1gBOIYvbyu_5p2fQrPy3U9A
提取码:91qk

运行代码(里面的路径改成自己的路径)
from tensorflow import keras
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import glob
import random

#1 获取图片路径和标签

#获取所有图片的路径 列表,每个元素是一个图片的路径
all_image_path = glob.glob(r'E:\WORK\tensorflow\dataset\2_class\*\*.jpg')
#这里获得的路径,前面都是airplane 后面都是lake,所以最好做一个乱序操作
random.shuffle(all_image_path)

label_to_index = {"airplane":0, "lake":1}
index_to_label = dict((v,k) for k, v in label_to_index.items())

# img = all_image_path[100]
# print(label_to_index.get(img.split('\\')[-2]))
# all_labels = [label_to_index.get(img.split("\\")[-2]) for img in all_image_path]
# print(all_labels[-5:])

#2 读取和解码图片

def load_img(path):
    # tensorflow读取图片的二进制形式  是tf.Tensor
    img_raw = tf.io.read_file(path)
    img_tensor = tf.image.decode_jpeg(img_raw,channels=3)  # tf.Tensor 每一个元素的大小都是[0,255] 是uint8
    img_tensor = tf.image.resize(img_tensor, [256,256]) #将所有图片统一大小
    # 转换为float类型
    img_tensor = tf.cast(img_tensor, tf.float32)
    # 归一化
    img_tensor = img_tensor / 255
    return img_tensor

#3 创建Dataset
# img_tensor = load_img(all_image_path[0])
# label = all_labels[0]
# plt.title(index_to_label.get(label))
# plt.imshow(img_tensor.numpy())
# plt.show()
img_ds = tf.data.Dataset.from_tensor_slices(all_image_path)
img_ds = img_ds.map(load_img)
label_ds = tf.data.Dataset.from_tensor_slices(all_labels)

#4 划分训练和测试dataset
img_label_ds = tf.data.Dataset.zip((img_ds,label_ds))
img_count = len(all_image_path)
test_count = int(img_count * 0.2)
train_count = img_count - test_count
train_ds = img_label_ds.skip(test_count) #跳过前test_count个数据
test_ds = img_label_ds.take(test_count) #选择前test_count个数据
BATCH_SIZE = 4
#没有repeat,那么只会迭代一次,因为之前对数据乱序过了,所以这里只需要小范围乱序就行,保证每次迭代数据不一样
train_ds = train_ds.repeat().shuffle(100).batch(BATCH_SIZE)
test_ds = test_ds.batch(BATCH_SIZE)

#5 模型创建
#依次增加卷积核2倍,效果会比较好
model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(64,(3,3),input_shape=(256,256,3),activation='relu'),
    tf.keras.layers.Conv2D(64,(3,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(128,(3,3),activation='relu'),
    tf.keras.layers.Conv2D(128,(3,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(256,(3,3),activation='relu'),
    tf.keras.layers.Conv2D(256,(3,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.GlobalAveragePooling2D(),
    tf.keras.layers.Dense(1024,activation='relu'),
    tf.keras.layers.Dense(256,activation='relu'),
    tf.keras.layers.Dense(1,activation='sigmoid')
])
print(model.summary())

# 6 模型的编译和训练
model.compile(optimizer=tf.keras.optimizers.Adam(0.0001),loss=tf.keras.losses.BinaryCrossentropy(),metrics=['acc'])
step_per_epoch = train_count // BATCH_SIZE
val_step = test_count // BATCH_SIZE
history = model.fit(train_ds,epochs=10, steps_per_epoch=step_per_epoch ,validation_data=test_ds,validation_steps=val_step)


# 7模型预测
def pre_img(img_pth):
    img = load_img(img_pth)
    img = tf.expand_dims(img,axis=0) #转换为4维,输入数据需要4维
    pred = model.predict(img)
    print(index_to_label.get((pred>0.5).astype('int')[0][0])) #结果大于0.5表示是lake 1 ,越接近1表示认为是lake的概率越大

pre_img(r'E:\WORK\tensorflow\dataset\2_class\lake\lake_014.jpg')

批标准化
数据的标准化是将数据按比例缩放,使之落入一个小的特定区间。
不仅在将数据输入模型之前对数据做标准化,在网络的每一次变换之后都应该考虑数据标准化。
批标准化,即使在训练过程中均值和方差随时间变化,也可以适应性地将数据标准化
批标准化解决的问题是梯度消失与梯度爆炸,是一种训练优化方法

优点:
1)在神经网络中使用标准化可以加速收敛
2)有助于梯度传播,因此允许更深的网络,对于有些特别深的网络,只有包含多个BatchNormalization层时才能训练
3)具有正则化的效果
4)提高模型的泛化能力
5)允许更高的学习效率从而加速收敛

BatchNormalization广泛用于Keras内置的许多高级卷积神经网络结构,比如ResNet50、InceptionV3和Xception。
通常在卷积层或密集连接层之后使用
tf.keras.layers.Batchnormalization()

批标准化实现过程:
1)求每一个训练批次数据的均值
2)求每一个训练批次数据的方差
3)数据进行标准化
4)训练参数γ、β
5)输出y通过γ与β的线性变换得到原来的数值

在训练的正向传播中,不会改变当前输出,只记录下γ和β
在反向传播的时候,根据求得的γ和β通过链式求导方式,求出学习速率以至改变权值
对于预测阶段所使用的均值和方差,也是来源于训练集。比如我们在模型训练时就记录下每个batch下的均值和方差,待训练完毕后,我们求整个训练样本的均值和方差期望值,作为我们进行预测时进行BN的均值和方差
参数training: 布尔值,表示图层是在训练模式还是在推理模式下运行。True该图层将使用当前批输入的均值和方差对其输入进行标准化;False该层将使用在训练期间学习的移动统计数据的均值和方差来标准化其输入。

论文中在CNN中一般应作用于非线性激活函数之前,但是实际上放在激活函数之后效果可能会更好,这个其实都可以。

点击查看代码
model.add(tf.keras.layers.Conv2D(64,(3,3)))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))

model.add(tf.keras.layers.Dense(1024))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))

在最后的一层输出Dense后面不需要在标准化了

posted @ 2021-11-25 20:12  白菜茄子  阅读(149)  评论(0编辑  收藏  举报