CNN:神经网络在前面的学习中我们已经了解过很多了,其本质就是多层感知机,卷积神经网络其实也一样,但是我们可以将其看成多层感知机的变种。它成功的原因在于其所采用的局部连接和权值共享的方式:
该优点在网络的输入是图像时表现的更为明显,使得图像可以直接作为网络的输入,避免了传统识别算法中复杂的特征提取和数据重建的过程,在二维图像的处理过程中有很大的优势。
2.模型构建:
CNN:首先了解卷积神经网络的四个组件:
model.add(Conv2D(32,(3,3),activation='relu',padding='valid',input_shape=((28,28,1))))
model.add(MaxPool2D(2))
model.add(Flatten())
接下来我主要介绍卷积层和池化层
卷积操作其实并不算复杂,但是他有很多种卷积方式,我们在进行卷积之后输出的图像也会和我们选择的卷积核有关,能够让维度下降、不变、甚至上升。
一般的池化操作我们会使用最大池化,即在选定的部分像素中,我们选择其中最大的一个像素值来作为这一部分的像素的代表,这就使得整体的数据降维,我们生活中常见的马赛克,就是池化操作产生的。
模型相对简单,层数也较少
AlexNet模型:
Conv-Pool-Conv-Pool-Conv-Conv-Conv-Pool-FC-FC-Softmax
VGG-16模型:
Conv-Conv-Pool-Conv-Conv-Pool-Conv-Conv-Conv-Pool-Conv-Conv-Conv-Pool-FC-FC-FC-Softmax
GoogleNet模型(Inception V1)
3.实验过程:
# TensorFlow 卷积池化
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
(x_train,y_train),(x_test,y_test) = tf.keras.datasets.mnist.load_data()
x_train = x_train.reshape((-1,28,28,1))/255.0
x_test = x_test.reshape((-1,28,28,1))/255.0
filter = tf.constant([[-1,-1,-1],[-1,9,1],[-1,-1,-1]],dtype='float32')
filter = tf.reshape(filter,(3,3,1,1))
img = tf.constant(x_train[0:1]/255.0,dtype='float32')
conv_img = tf.nn.conv2d(img,filter,strides=[1,2,2,1],padding='SAME')
pool_img = tf.nn.max_pool(img,[1,2,2,1],[1,2,2,1],padding="VALID")
# window_size,stride
print(conv_img.shape)
plt.subplot(131)
plt.imshow(tf.squeeze(img))
plt.subplot(132)
plt.imshow(tf.squeeze(conv_img))
plt.subplot(133)
plt.imshow(tf.squeeze(pool_img))
plt.show()
由于我们采用的卷积核的特性,将一些较大的值都滤掉了,反观池化,虽然较大的值都保留了,但是同样损失了很多细节。
import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.models import Sequential
(x_train,y_train),(x_test,y_test) = tf.keras.datasets.mnist.load_data()
#tf.keras.datasets.mnist.load_data()
#tf.keras.datasets.fashion_mnist.load_data()
x_train = x_train.reshape((-1,28,28,1))/255.0
x_test = x_test.reshape((-1,28,28,1))/255.0
y_train = tf.keras.utils.to_categorical(y_train,10)
y_test = tf.keras.utils.to_categorical(y_test,10)
model = Sequential()
model.add(Conv2D(32,(3,3),activation='relu',padding='valid',input_shape=((28,28,1))))
model.add(MaxPool2D(2))
model.add(Conv2D(32,(3,3),activation='relu',padding='same'))
model.add(Flatten()) #FC,将二维图片展平成一维向量
model.add(Dense(128,activation='relu'))
model.add(Dense(10,activation='softmax'))
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.categorical_crossentropy,metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=128,epochs=20)
print(model.evaluate(x_test,y_test))
从上述代码中,我们可以发现,这个卷积神经网络中,我们使用了两个卷积层、两个最大池化层、两个全连接层
我们知道,卷积核可以提取突破的特征,初步设想,给定较多的卷积核,便能提取更多特征,那么最后的精度应该会高。所以将原来的卷积核个数翻倍,得到的结果如下:
看来这招在这里并不合适
既然增加卷积核的个数行不通,索性让神经网络变得更深一些
精度下降了,看来单纯地深化神经网络,也不一定就能达到最好的效果,太复杂的模型很有可能会过拟合,导致精度下降。
总的来说对几个常见的卷积神经网络结构有了一定的了解,无非就是卷积、池化、归一化、全连接的各种组合,在调试优化模型的过程中我也进行了很多尝试,有了一定的收获。调参是门技术活,而我只会没脑子的瞎调