当前位置:   article > 正文

【神经网络】(4) 卷积神经网络(CNN),自定义网络,案例:彩色图像10分类_卷积神经网络怎么自定义输入

卷积神经网络怎么自定义输入

各位同学大家好,今天和大家分享一下TensorFlow2.0中如何使用函数方法自定义卷积神经网络。

1. 导入数据

获取系统自带的10分类图像数据,50k张用于训练,10k张用于测试。

  1. # 10分类卷积神经网络
  2. import tensorflow as tf
  3. from tensorflow import keras
  4. from tensorflow.keras import Sequential,optimizers,layers,datasets
  5. #(1)数据获取
  6. (x,y), (x_test, y_test) = datasets.cifar10.load_data()
  7. # 查看数据
  8. print('x.shape:',x.shape,'y.shape:',y.shape)
  9. print('x_test.shape:',x_test.shape,'y_test.shape:',y_test.shape)
  10. print('y[:5]:',y[:5])
  11. # x.shape: (50000, 32, 32, 3) y.shape: (50000, 1)
  12. # x_test.shape: (10000, 32, 32, 3) y_test.shape: (10000, 1)
  13. #(2)图像可视化
  14. import matplotlib.pyplot as plt
  15. for i in range(10):
  16. plt.subplot(2,5,i+1)
  17. plt.imshow(x[i])
  18. plt.xticks([])
  19. plt.yticks([])
  20. plt.show()


2. 数据预处理

将图像的每个像素值从[0,255]映射到[-1,1]之间,由于目标值y的shape为[b,1]需要把shape为1的轴挤压掉tf.squeeze(),留下分类数值。对所有的训练和测试数据集重新洗牌.shuffle(),但不打乱x和y之间的对应关系。每次迭代从数据集中取出128个样本,.batch(128)

  1. #(3)数据预处理
  2. def processing(x,y):
  3. x = 2 * tf.cast(x, tf.float32) / 255.0 - 1 # [-1,1]
  4. y = tf.cast(y, tf.int32)
  5. return(x,y)
  6. # 构造训练集数据集
  7. y = tf.squeeze(y, axis=1) # 挤压掉shape=1的轴
  8. train_ds = tf.data.Dataset.from_tensor_slices((x,y))
  9. train_ds = train_ds.map(processing).shuffle(10000).batch(128) # 打乱数据集,每次迭代取128个数据
  10. # 构造测试集数据集,不需要onehot编码,需要和预测结果比较
  11. y_test = tf.squeeze(y_test, axis=1)
  12. test_ds = tf.data.Dataset.from_tensor_slices((x_test,y_test))
  13. test_ds = test_ds.map(processing).shuffle(10000).batch(128)
  14. # 构造迭代器,查看划分是否正确
  15. sample = next(iter(train_ds)) # 每次运行从数据集中取出一组xy
  16. print('x_batch:', sample[0].shape, 'y_batch:', sample[1].shape)
  17. # x_batch: (64, 128, 128, 3) y_batch: (64, 3)

3. 构造网络

使用函数方法自定义网络各层,layers.BatchNormalization()为batchnorm层,在把输入送入至非线性函数之前,能有效的将数据控制在一定的范围内,使网络更稳定,收敛更快。如果使用该层,训练集和测试集的使用的方法不同,训练时需要指定net(x, training=True)BN层的参数在正反向传播过程中会被优化更新测试时指定net(x, training=False)。BN层的参数在正反向传播过程中不会被更新。

  1. #(4)网络构造
  2. # 自定义网络层
  3. def CNN(classes, input_shape):
  4. # 输入层
  5. inputs = tf.keras.Input(shape=input_shape)
  6. # 卷积层
  7. x = layers.Conv2D(32, kernel_size=(3,3), strides=1, kernel_regularizer=keras.regularizers.l2(0.001), padding='same', activation='relu')(inputs)
  8. x = layers.Conv2D(32, kernel_size=(3,3), strides=1, padding='same')(x)
  9. # BN层
  10. x = layers.BatchNormalization()(x)
  11. # relu层
  12. x = layers.Activation('relu')(x)
  13. # 池化层
  14. x = layers.MaxPool2D(pool_size=(2,2), strides=2, padding='same')(x)
  15. # unit2
  16. x = layers.Conv2D(64, kernel_size=(3,3), strides=1, kernel_regularizer=keras.regularizers.l2(0.001), padding='same', activation='relu')(x)
  17. x = layers.Conv2D(64, kernel_size=(3,3), strides=1, padding='same')(x)
  18. # BN层
  19. x = layers.BatchNormalization()(x)
  20. # relu层
  21. x = layers.Activation('relu')(x)
  22. # 池化层
  23. x = layers.MaxPool2D(pool_size=(2,2), strides=2, padding='same')(x)
  24. # Flatten层 连接卷积层和全连接层
  25. x = layers.Flatten()(x)
  26. # 全连接层
  27. x = layers.Dense(128, activation='relu')(x)
  28. # Dropout层
  29. x = layers.Dropout(0.2)(x)
  30. # 全连接层
  31. x = layers.Dense(64, activation='relu')(x)
  32. # Dropout层
  33. x = layers.Dropout(0.2)(x)
  34. # logits层,不转为概率
  35. outputs = layers.Dense(classes)(x)
  36. # 构建网络
  37. model = keras.Model(inputs=inputs, outputs=outputs)
  38. # 返回网络结构
  39. return model
  40. # 传入函数所需参数
  41. model = CNN(10, (32, 32, 3)) # 指定10个分类,输入的一张图片的shape为(32,32,3)
  42. # 查看网络结构
  43. model.summary()
  44. # 指定优化器
  45. optimizer = optimizers.Adam(lr=0.0001, beta_1=0.9, beta_2=0.99)

 网络结构如下图所示,param代表每一层参数个数

  1. Model: "model"
  2. _________________________________________________________________
  3. Layer (type) Output Shape Param #
  4. =================================================================
  5. input_1 (InputLayer) [(None, 32, 32, 3)] 0
  6. conv2d (Conv2D) (None, 32, 32, 32) 896
  7. conv2d_1 (Conv2D) (None, 32, 32, 32) 9248
  8. batch_normalization (BatchN (None, 32, 32, 32) 128
  9. ormalization)
  10. activation (Activation) (None, 32, 32, 32) 0
  11. max_pooling2d (MaxPooling2D (None, 16, 16, 32) 0
  12. )
  13. conv2d_2 (Conv2D) (None, 16, 16, 64) 18496
  14. conv2d_3 (Conv2D) (None, 16, 16, 64) 36928
  15. batch_normalization_1 (Batc (None, 16, 16, 64) 256
  16. hNormalization)
  17. activation_1 (Activation) (None, 16, 16, 64) 0
  18. max_pooling2d_1 (MaxPooling (None, 8, 8, 64) 0
  19. 2D)
  20. flatten (Flatten) (None, 4096) 0
  21. dense (Dense) (None, 128) 524416
  22. dropout (Dropout) (None, 128) 0
  23. dense_1 (Dense) (None, 64) 8256
  24. dropout_1 (Dropout) (None, 64) 0
  25. dense_2 (Dense) (None, 10) 650
  26. =================================================================
  27. Total params: 599,274
  28. Trainable params: 599,082
  29. Non-trainable params: 192
  30. _________________________________________________________________

4. 网络训练

为了得到和model.fit()一样的效果,训练过程和测试过程都计算一下损失和准确率,并将每一次迭代的结果保存下来。指定model(x, trainin=True)更新BN层参数。计算交叉熵损失时,categorical_crossentropy(y, logits, from_logits=True)logits为每张图片属于各个分类的实数值,指定from_logits=Truelogits会自动经过softmax函数变成概率再和真实值y比较,提高了网络的稳定性。

  1. # 保存每次循环的损失和准确率
  2. train_loss_list = []
  3. train_acc_list = []
  4. test_loss_list = []
  5. test_acc_list = []
  6. # 大循环
  7. for epochs in range(10): # 循环10次
  8. print('---------------')
  9. print('epochs:', epochs)
  10. #(5)网络训练
  11. total_sum = 0
  12. total_correct = 0
  13. total_loss = 0
  14. for step, (x,y) in enumerate(train_ds):
  15. # 梯度跟踪
  16. with tf.GradientTape() as tape:
  17. # 前行传播,[b,32,32,3]=>[b,10]
  18. logits = model(x, trainin=True) # 得到logits层输出后的10分类数值
  19. # 计算准确率
  20. # 将logits层输出结果转概率
  21. prob = tf.nn.softmax(logits, axis=1)
  22. # 找到概率最大值对应的索引
  23. predict = tf.argmax(prob, axis=1, output_type=tf.int32)
  24. # 预测值和真实值是否相同
  25. correct = tf.cast(tf.equal(predict, y), tf.int32)
  26. # 计算预测对了几个
  27. correct_sum = tf.reduce_sum(correct)
  28. # 计算总个数
  29. total_correct += correct_sum # 总预测对了几个
  30. total_sum += x.shape[0] # 总共有多少参与
  31. # 计算损失
  32. y = tf.one_hot(y, depth=10) # 真实值y是onehot编码后的
  33. # 计算交叉熵损失
  34. CE = tf.losses.categorical_crossentropy(y, logits, from_logits=True)
  35. # 计算每个batch的平均损失
  36. loss = tf.reduce_mean(CE)
  37. # 记录batch总损失
  38. loss_sum = tf.reduce_sum(CE)
  39. total_loss += loss_sum
  40. # 梯度计算
  41. grads = tape.gradient(loss, model.trainable_variables) # 对所有的权重和偏置计算梯度
  42. # 更新梯度
  43. optimizer.apply_gradients(zip(grads, model.trainable_variables))
  44. # 每100个batch打印一次损失
  45. if step%100 == 0:
  46. print('step:', step, 'loss:', loss.numpy())
  47. # 保存训练的准确率和损失
  48. # 计算每次循环的准确率
  49. train_acc = total_correct/total_sum
  50. train_acc_list.append(train_acc)
  51. # 计算每次循环的损失
  52. train_loss = total_loss/total_sum
  53. train_loss_list.append(train_loss)
  54. # 每次循环后打印一次
  55. print('train_acc:', train_acc.numpy(), 'train_loss:', train_loss.numpy())

5. 网络测试

用和训练过程相同的方法计算损失和准确率,但不需要更新梯度,将每一次迭代的结果保存下来。

  1. #(6)网络测试
  2. total_sum = 0
  3. total_correct = 0
  4. total_loss = 0
  5. for (x,y) in test_ds:
  6. # 前向传播,得到输出层结果
  7. logits = model(x, training=False) # 不更新BN层参数
  8. # 转换成每张图片属于每个分类的概率
  9. prob = tf.nn.softmax(logits, axis=1)
  10. # 概率最大的值的索引
  11. predict = tf.argmax(prob, axis=1, output_type=tf.int32)
  12. # 预测值和真实值比较,相同返回1
  13. correct = tf.cast(tf.equal(predict, y), dtype=tf.int32)
  14. # 计算相同的个数之和
  15. correct_sum = tf.reduce_sum(correct)
  16. # 计算准确率
  17. total_correct += int(correct_sum) # 预测对了几个
  18. total_sum += x.shape[0] # 一共有多少个参与预测
  19. # 计算测试集损失
  20. y = tf.one_hot(y, depth=10) # 测试集的目标进行onehot编码后与预测得到的结果计算交叉熵损失
  21. loss = tf.reduce_sum(tf.losses.categorical_crossentropy(y, logits, from_logits=True)) # 每一个batch的总损失
  22. total_loss += loss # 记录整个循环的损失和
  23. # 每个大循环计算一次损失及准确率
  24. test_loss = total_loss/total_sum
  25. test_acc = total_correct/total_sum
  26. print('test_loss:', test_loss.numpy(),'test_acc:', test_acc)
  27. # 保存
  28. test_loss_list.append(test_loss)
  29. test_acc_list.append(test_acc)

6. 结果展示

网络迭代10次之后,准确率提高了44%,没有出现过拟合现象。

  1. ---------------------------------------
  2. epochs: 0
  3. step: 0 loss: 3.0574064
  4. step: 100 loss: 1.9813004
  5. step: 200 loss: 1.7280517
  6. step: 300 loss: 1.6263434
  7. train_acc: 0.33082 train_loss: 1.8415068
  8. test_loss: 2.096799 test_acc: 0.2592
  9. ---------------
  10. ---------------------------------------
  11. .......................................
  12. ---------------------------------------
  13. epochs: 9
  14. step: 0 loss: 0.78702605
  15. step: 100 loss: 0.7967223
  16. step: 200 loss: 0.82377315
  17. step: 300 loss: 1.0987799
  18. train_acc: 0.69934 train_loss: 0.8607509
  19. test_loss: 0.8950623 test_acc: 0.6914

7. 模型评估

绘制训练集和验证集的准确率和损失的对比曲线,来对网络优个直观的感受。可见前10次迭代收敛平缓,效果较好,随着迭代次数的增加可能会出现过拟合现象。

  1. epochs_range = range(len(train_loss_list)) # 横坐标,网络循环了几次
  2. # 准确率曲线
  3. plt.figure(figsize=(10,5))
  4. plt.subplot(1,2,1)
  5. plt.plot(epochs_range, train_acc_list, label='Training_acc')
  6. plt.plot(epochs_range, test_acc_list, label='validation_acc')
  7. plt.legend()
  8. plt.title('Accuracy')
  9. # 损失曲线
  10. plt.subplot(1,2,2)
  11. plt.plot(epochs_range, train_loss_list, label='Training_loss')
  12. plt.plot(epochs_range, test_loss_list, label='validation_loss')
  13. plt.legend()
  14. plt.title('Loss')

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/901661
推荐阅读
相关标签
  

闽ICP备14008679号