1、为什么使用卷积神经网络
前馈神经网络也叫做全连接网络。缺点有以下几个:
- 在图像识别中会将多维向量平铺成一维向量,会丢失像素点之间的距离关系。
- 无法将局部的权重应用到其他位置,带来的后果就是,如果在一个图像的右上角有一只猫,可以正确分类;当这只猫出现在左下角时,无法正确识别。(没有平移不变性)
1.1、神经网络处理图像
import numpy as np
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, BatchNormalization
from tensorflow.keras import utils
from tensorflow.keras import regularizers
from tensorflow.keras.datasets import mnist
"""
【1】数据获取
"""
# 【(60000, 28, 28) (60000,)】 (10000, 28, 28) (10000,)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
# print(x_train[10], y_train[10])
"""
【2】数据处理
"""
# 特征值:转类型,再归一化 【(60000, 784) (10000, 784)】
x_train = x_train.reshape(60000, 784).astype("float32")
x_test = x_test.reshape(10000, 784).astype("float32")
x_train /= 255
x_test /= 255
# 目标值:one-hot编码
y_train = utils.to_categorical(y_train, 10)
y_test = utils.to_categorical(y_test, 10)
"""
【3】模型构建 (512,512,10)
"""
model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(512, kernel_regularizer=regularizers.l2(0.001)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(10))
model.add(Activation('softmax'))
"""
【4】模型编译与训练
"""
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(x_train, y_train, epochs=4, validation_data=(x_test, y_test), batch_size=128, verbose=1)
"""
【5】模型保存
"""
model.save("model.h5")
1.2、模型加载
import numpy as np
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, BatchNormalization
from tensorflow.keras import utils
from tensorflow.keras import regularizers
from tensorflow.keras.datasets import mnist
"""
【1】数据获取
"""
# 【(60000, 28, 28) (60000,)】 (10000, 28, 28) (10000,)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
# print(x_train[10], y_train[10])
"""
【2】数据处理
"""
# 特征值:转类型,再归一化 【(60000, 784) (10000, 784)】
x_train = x_train.reshape(60000, 784).astype("float32")
x_test = x_test.reshape(10000, 784).astype("float32")
x_train /= 255
x_test /= 255
# 目标值:one-hot编码
y_train = utils.to_categorical(y_train, 10)
y_test = utils.to_categorical(y_test, 10)
"""
【3】模型加载
"""
load_model = tf.keras.models.load_model("model.h5")
load_model.evaluate(x_test, y_test, verbose=1)
2、卷积神经网络基础
卷积神经网络就是让权值在不同位置共享的神经网络。解决了上述的不足即局部连接和空间共享。
局部连接如下图所示:
在前面说,前馈神经网络时说到,如果将图片向量表示,就失去了平面结构信息,在输出时,卷积神经网络依然保留了矩阵的排列方式。如下图:
其实,经过一个卷积计算后得到一个神经元,比如上面蓝色的0,这个神经元叫做“Convolved Feature”或“Activation Map”或“Feature Map”。
3、LeNet-5案例
LeNet-5卷积神经网络的整体框架:
特征映射:一幅图在经过卷积操作后得到结果称为特征图。LeNet-5共有8层,包含输入层,每层都包含可训练参数;每个层有多个特征映射(每个特征映射通过一种卷积核(或者叫滤波器)提取输入的一种特征,然后每个特征映射有多个神经元。C层代表的是卷积层,通过卷积操作,可以使原信号特征增强,并且降低噪音。 S层是一个降采样层(或者叫池化层),利用图像局部相关性的原理,对图像进行子抽样,可以减少数据处理量同时保留有用信息。
3.1、结构
tf.keras.layers.Conv2D(
filters, kernel_size, strides=(1, 1), padding='valid', data_format=None,
dilation_rate=(1, 1), activation=None, use_bias=True,
kernel_initializer='glorot_uniform', bias_initializer='zeros',
kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, bias_constraint=None, **kwargs
)
从这个函数的定义能看出来,filters ,kernel_size过滤器个数和卷积核尺寸,这是两个位置参数,没有默认值,必须给。下列的filters卷积核个数为8的时候,输出的通道数就是8。
计算公式:输入图像的大小为nxn,卷积核的大小为mxm,步长为s, 为输入图像两端填补p个零(zero padding),那么卷积操作之后输出的大小为(n - m + 2p) / s + 1。
(1)LeNet-5的输入是一个32×32灰度图像,它通过第一个卷积层,带有6个特征图或过滤器,大小为5x5,步长为1。 图像的尺寸从32x32x1变为28x28x6。
(2)LeNet-5应用平均池化层或分采样层,过滤器大小为2x2,步长为2。 得到的图像维数将减少到14x14x6。
(3) 同上述两步骤,第三层是卷积层,16个特征图大小为5x5,步幅为1,得到10x10x16。第四层是池化层,平均池化层过滤器大小为2x2,步幅为2,得到5x5x16。
(4)第五层是全连接的卷积层,有120个特征映射,每个特征映射的大小为1×1。 C5中的120个单元每一个都连接到第四层S4中的所有400个节点(5x5x16)。400->120。
(5)第六层是84个单元的全连接层, 最后一层,有一个全连接的输出层y,有10个可能的值,对应于从0到9的数字。
3.2代码
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dense
"""
【1】加载数据集
"""
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
"""
【2】数据处理
"""
# 卷积神经网络输入要求:NHWC(数量,高度,宽度,通道数)
train_images = tf.reshape(train_images, (train_images.shape[0], train_images.shape[1], train_images.shape[2], 1))
print(train_images.shape)
test_images = tf.reshape(test_images, (test_images.shape[0], test_images.shape[1], test_images.shape[2], 1))
print(test_images.shape)
"""
【3】模型构建
"""
net = tf.keras.models.Sequential([
# 6个5*5的卷积核
Conv2D(filters=6, kernel_size=5, activation="sigmoid", input_shape=(28, 28, 1)),
MaxPool2D(pool_size=2, strides=2),
# 16个5*5的卷积核
Conv2D(filters=16, kernel_size=5, activation="sigmoid"),
MaxPool2D(pool_size=2, strides=2),
# 维度调整为1维
Flatten(),
Dense(120, activation="sigmoid"),
Dense(84, activation="sigmoid"),
Dense(10, activation="softmax")
])
print(net.summary())
"""
【4】模型编译和训练
"""
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)
# 目标值没有使用one-hot,所以使用sparse_categorical_crossentropy
net.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# 划分验证集
net.fit(train_images, train_labels, epochs=5, batch_size=128, validation_split=0.1, verbose=1)
"""
【5】模型评估
"""
print("测试集*" * 100)
net.evaluate(test_images, test_labels, verbose=1)
4、结构变迁
参考:
CNN卷积函数Conv2D()各参数的含义及用法_园游会的魔法糖的博客-CSDN博客_conv2d参数解释