TensorFlow实现CNN对卫星图片的分类

一.数据集准备

数据集共1400张机场或湖泊的图片,因此此分类为简单的二分类问题,通过CNN对数据集进行模型训练,得出相关指标。

数据集如下:

机场

 

湖泊

 

二.读取数据集

  • 数据集路径

     

  • 导入相关模块
    import tensorflow as tf
    import numpy as np
    import matplotlib.pyplot as plt
    import pathlib #使用pathlib对路径对象进行管理
    import random

     

  • 构造路径对象,获取所有图片路径,并打乱数据集
    pic_dir = 'D:/tensorflowDataSet/2_class'    
    pic_root = pathlib.Path(pic_dir)    #构造路径对象
    all_image_path = list(pic_root.glob('*/*'))    #使用正则表达式获取所有图片路径对象
    all_image_path = [str(path) for path in all_image_path]    #获取所有图片路径名
    random.shuffle(all_image_path)    #对数据进行打乱
    all_image_path 
     
    ['D:\\tensorflowDataSet\\2_class\\lake\\lake_272.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_039.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_488.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_342.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_284.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_099.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_522.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_414.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_377.jpg'......

     

  • 根据 2_class目录下的两个分类,构造标签。
    dirPath = pic_root.glob('*/')    #正则构造2_class目录下子级目录airplane,lake的对象
    names = [item.name for item in dirPath]
    name_label = dict([(name,label) for label,name in enumerate(names)])
    name_label
    分类标签
    {'airplane': 0, 'lake': 1}
    

     

  • 将之前所有图片对应到自己的标签上。即找到all_image_path的所有图片对应的标签。
    #图片的父目录代表了数据属于那种类型
    all_image_parent = [pathlib.Path(image_path).parent.name for image_path in all_image_path]
    all_image_label = [name_label[name] for name in all_image_parent]
    all_image_path[:6]
    all_image_label[:6]
    
    检查是否能对应上
    ['D:\\tensorflowDataSet\\2_class\\airplane\\airplane_445.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_436.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_084.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_673.jpg',
     'D:\\tensorflowDataSet\\2_class\\airplane\\airplane_342.jpg',
     'D:\\tensorflowDataSet\\2_class\\lake\\lake_272.jpg']
    
    [0, 0, 1, 0, 0, 1]
    

     

三.读取图片数据,并进行预处理。

  • 定义加载图片的函数。
    def load_pic(path):
        image_binary = tf.io.read_file(path)    #读取图片,二进制数据
        image_tensor = tf.image.decode_jpeg(image_binary,channels=3)  #对图片按照指定格式进行解码,彩色图片RGB,channels=3
        image_tensor = tf.image.resize(image_tensor,[256,256])
        image_tensor = tf.cast(image_tensor,tf.float32)
        image_tensor = image_tensor / 255 #对数据进行归一化,建议使用sklearn模块的MinMaxScaler,StandardScaler,能将数据归一化到[0,1],并服从正态分布,加速模型训练。
        return image_tensor
    
    plt.imshow(load_pic(all_image_path[1]))
     

     

  • 对模型构建输入数据
    path_dataset = tf.data.Dataset.from_tensor_slices(all_image_path) #读取图片路径dataset
    image_dataset = path_dataset.map(load_pic) #加载所有图片
    label_dataset = tf.data.Dataset.from_tensor_slices(all_image_label) #读取标签
    dataset = tf.data.Dataset.zip((image_dataset,label_dataset)) #将图片及对应标签进行拉链
     
  • 划分训练集,测试集 。
    total = len(all_image_path) #图片总数:1400
    test_total = int(total * 0.2) #测试集占20%
    train_total = total - test_total #训练集占80%
    train_ds = dataset.skip(test_total) #跳过20%数据为训练集
    test_ds = dataset.take(test_total) #取前20%数据集为测试集
    train_ds = train_ds.shuffle(train_total).batch(32) #对训练集进行打乱,设置batch,防止一次性加载数据到内存
    test_ds = test_ds.batch(32) #对测试集设置batch,分批次进行训练,防止一次性加载到内存

     

四.模型创建及训练

  •  模型创建
    model = tf.keras.Sequential() #顺序模型
    model.add(tf.keras.layers.Conv2D(64,(3,3),input_shape=(256,256,3),activation='relu')) #卷积层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.Conv2D(64,(3,3),activation='relu')) #卷积层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.MaxPooling2D()) #池化层
    model.add(tf.keras.layers.Conv2D(128,(3,3),activation='relu')) #卷积层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.Conv2D(128,(3,3),activation='relu')) #卷积层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.MaxPooling2D()) #池化层
    model.add(tf.keras.layers.Conv2D(256,(3,3),activation='relu')) #卷积层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.Conv2D(256,(3,3),activation='relu')) #卷积层
    model.add(tf.keras.layers.GlobalAveragePooling2D()) #全局平均池化
    model.add(tf.keras.layers.Dense(256,activation='relu')) #全连接层
    #model.add(tf.keras.layers.BatchNormalization()) #批标准化
    model.add(tf.keras.layers.Dense(1,activation='sigmoid')) #输出层
    model.summary()
    对于如第一个卷积层,为啥Param=1792,首先filter=64,filter的shape为(3,3,3),所以64个filter参数一共为64*3*3*3=1728,加上bias参数64个,共1792,其他层同理可得。
    
    Model: "sequential_3"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d_18 (Conv2D)           (None, 254, 254, 64)      1792      
    _________________________________________________________________
    conv2d_19 (Conv2D)           (None, 252, 252, 64)      36928     
    _________________________________________________________________
    max_pooling2d_6 (MaxPooling2 (None, 126, 126, 64)      0         
    _________________________________________________________________
    conv2d_20 (Conv2D)           (None, 124, 124, 128)     73856     
    _________________________________________________________________
    conv2d_21 (Conv2D)           (None, 122, 122, 128)     147584    
    _________________________________________________________________
    max_pooling2d_7 (MaxPooling2 (None, 61, 61, 128)       0         
    _________________________________________________________________
    conv2d_22 (Conv2D)           (None, 59, 59, 256)       295168    
    _________________________________________________________________
    conv2d_23 (Conv2D)           (None, 57, 57, 256)       590080    
    _________________________________________________________________
    global_average_pooling2d_1 ( (None, 256)               0         
    _________________________________________________________________
    dense_6 (Dense)              (None, 256)               65792     
    _________________________________________________________________
    dense_7 (Dense)              (None, 1)                 257       
    =================================================================
    
    

     

  • 模型编译及训练
    model.compile(optimizer='adam',
                  loss='binary_crossentropy',
                  metrics=['acc'])
    
    二分类,loss使用binary_crossentropy
    多分类,且标签顺序编码,loss使用sparse_categorical_crossentropy
    多分类,且标签使用one-hot,loss使用categorical_crossentropy
     
    record = model.fit(train_ds,
              epochs=10, #迭代次数
              validation_data=test_ds) #训练模型的同时能看到测试集上的表现
    Train for 35 steps, validate for 9 steps
    Epoch 1/10
    35/35 [==============================] - 392s 11s/step - loss: 0.5093 - acc: 0.7295 - val_loss: 0.2761 - val_acc: 0.9321
    Epoch 2/10
    35/35 [==============================] - 387s 11s/step - loss: 0.2142 - acc: 0.9411 - val_loss: 0.2173 - val_acc: 0.9750
    Epoch 3/10
    35/35 [==============================] - 408s 12s/step - loss: 0.1995 - acc: 0.9330 - val_loss: 0.1910 - val_acc: 0.9500
    Epoch 4/10
    35/35 [==============================] - 423s 12s/step - loss: 0.1380 - acc: 0.9589 - val_loss: 0.1417 - val_acc: 0.9679
    Epoch 5/10
    35/35 [==============================] - 416s 12s/step - loss: 0.1347 - acc: 0.9598 - val_loss: 0.1154 - val_acc: 0.9679
    Epoch 6/10
    35/35 [==============================] - 395s 11s/step - loss: 0.1140 - acc: 0.9616 - val_loss: 0.2296 - val_acc: 0.9536
    Epoch 7/10
    35/35 [==============================] - 392s 11s/step - loss: 0.1465 - acc: 0.9500 - val_loss: 0.0979 - val_acc: 0.9714
    Epoch 8/10
    35/35 [==============================] - 461s 13s/step - loss: 0.1425 - acc: 0.9589 - val_loss: 0.1694 - val_acc: 0.9714
    Epoch 9/10
    35/35 [==============================] - 614s 18s/step - loss: 0.1145 - acc: 0.9670 - val_loss: 0.0997 - val_acc: 0.9714
    Epoch 10/10
    35/35 [==============================] - 634s 18s/step - loss: 0.0975 - acc: 0.9652 - val_loss: 0.1824 - val_acc: 0.9714

     

  • 画图 
    plt.plot(record.epoch,record.history.get('acc'),label='acc')
    plt.plot(record.epoch,record.history.get('val_acc'),label='val_acc')
    plt.legend()

    由图能看出,在训练集上的表现不是很好,还需提高模型深度,可增加卷积层及卷积核数量。模型没有表现出过拟合,如果产生过拟合可使用Dropout层或正则化参数进行调整。

五.注意事项及总结

  • 原始数据通过卷积层的shape,如输入数据为(128,128,3),filter=(3,3),filter个数为64,步长=(1,1),则输出有效区域大小为(126,126,64),其他位置用0填充。可见在池化层通过了下采样达到了压缩数据和参数数量效果。
  • 经过卷积后的数据可能参差不齐,在激活函数中可能产生梯度消失及爆炸的情况,可通过批标准化层(tf.keras.layers.BatchNormalization)将卷积后数据标准化,有利于梯度传播。
  • CNN同传统神经网络求权值方法类似,使用BP反向传播求解,在池化层,如Max Pooling,使得这个过程不可求导。在这个计算过程中,算法会记录最大值在每个小区域中的位置,在反向传播时,哪个最大值对下一层有贡献,就将残差传递到该最大值的位置。

     

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,下面是一个使用TensorFlow实现CNN的简单示例: 首先,导入需要的库: ```python import tensorflow as tf from tensorflow.keras import datasets, layers, models ``` 接着,加载数据集(这里以MNIST数据集为例): ```python (train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data() ``` 然后,对数据进行预处理,将像素值缩放到0到1之间: ```python train_images = train_images / 255.0 test_images = test_images / 255.0 ``` 接下来,定义CNN模型。这里使用了三个卷积层和两个池化层,以及一个全连接层和一个输出层: ```python model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(10)) ``` 然后,编译模型,指定损失函数、优化器和评估指标: ```python model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) ``` 最后,训练模型并评估性能: ```python history = model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels)) test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) print(test_acc) ``` 这就是一个简单的使用TensorFlow实现CNN的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值