一、 定义和公式
1. 图像卷积运算:图像矩阵*Filter
2. 池化层实现维度缩减(最大法&平均法)
3. 卷积神经网络 CNN 介绍、特点、问题
4. 经典的CNN模型:LeNet-5,AlexNet,VGG-16
4.1 LeNet-5
4.2 AlexNet
4.3 VGG-16
二、 代码实战
1. 建立CNN模型实现猫狗图像识别,并对新图像进行预测
1.1 CNN结构图
1.2 建立CNN模型实现猫狗图像识别
1.3 对新图像进行预测
2. 基于VGG-16模型,构建MLP,实现猫狗识别
2.1 使用VGG-16结构提取单个图像特征
2.2 使用VGG-16结构批量提取图像特征
2.3 根据图像特征数据,分离数据,建立MLP,计算测试数据预测准确率
2.4 下载新图片,对其进行预测
图像识别任务提出问题:
- 逻辑回归:对一个28*28像素的图像进行自动识别,要建立一个逻辑回归模型,将图像数据转换成28行*28列的数组,每个数据在0-255之间,然后进行非线性预测,使用多项式作为决策边界的逻辑回归预测,待训练参数的数量巨大
- MLP/ANN:将28*28转换为数组后的数据作为输入,然后建立2个隐藏层的MLP结构,每个隐藏层各有392个神经元,通过summary方法可以查看结构中要训练的参数量比逻辑回归小,但当图片像素高如500*400并有RGB三个通道时,使用MLP模型要训练的参数量巨大
- 卷积处理:为了进一步减少训练参数的数量而使用的简化模型,先提取出图像中的关键信息(如轮廓),再建立MLP模型进行训练及预测
图像卷积运算Convolution:对图像矩阵与滤波器矩阵进行对应相乘再求和运算,转化得到新的矩阵,用于快速定位图像中的某些特征,如轮廓
核心:计算机根据样本图片,自动寻找合适的轮廓过滤器,对新图片进行轮廓匹配
RGB图像的卷积:对RGB三个通道分别求卷积再相加
池化层:为了减少训练数据的参数,按照一个固定规则对图像矩阵进行处理,将其转换为更低维度的矩阵,设置合理池化参数保留主要信息
最大法池化MaxPooling:找到窗口中最大的数,作为新数据给新矩阵
pooling size:窗口大小
stride:窗口滑动步长,每次移动2*2格
平均法池化AvgPooling:对窗口内数据求平均值
卷积神经网络:把卷积、池化、MLP先后连接在一起,组成卷积神经网络
流程:
- 6*6图片 --矩阵-->
- 3*3Filter --卷积-->
- 4*4新数组 --Relu--> --池化-->
- 2*2新矩阵 --全连接-->
- MLP模型
Relu函数:f(x)=max(x,0)
Sigmoid函数:
在某个范围内导数很小,然而对MLP求解就是求导,那么当大于/小于一定范围时很难求导,因为太小会导致迭代很慢,但Relu可以解决这个问题
CNN特点:
- 参数共享 Parameter Sharing:同一个特征过滤器可用于整张图片
- 稀疏连接 Sparsity of Coneections:生成的特征图片每个节点只与原图片中特定节点连接,与其它窗口不相关
卷积运算导致的问题:
- 图像被压缩,造成信息丢失
- 边缘信息使用少,容易被忽略,即矩阵四个角落的值只被窗口使用了一次
为了解决这个问题,使用图像填充Padding:通过在图像左右两边各增加一个像素,使其在卷积运算后维持原图大小
流程:
说明:
- 6个Filters,每个Filter的窗口大小:5*5
- 池化滑动窗口大小:s=1
- 卷积输出层维度=输入层维度-Filter窗口大小+stride滑动窗口大小,32-5+1=28
- 池化输出层维度=(输入层维度-f窗口尺寸)/s池化滑动窗口大小+1,(28-2)/2+1=14
- 最后一个池化层的输出需要建立一个全连接层,作为MLP模型的输入,使用激活函数sigmoid将输入输出进行神经关联
- 每个FC是一个全连接层
- 共十个输出结果
输入:32*32灰度图,1个通道Channel
训练参数:约6w个
特点:
- 随着网络越深,图像的高度和宽度缩小,通道增加(即Filter,提取图片特征)
- 卷积与池化先后成对使用
- 使用sigmoid作为激活函数
流程:
说明:
- Filter的窗口大小11*11
- (227-11)/4+1=55
- 多次卷积可以提取出图像中更复杂的信息
- same:对图像做填充,保证输入和输出的行/列像素一样
输入:227*227*3 RGB图,3个通道
训练参数:约6千万个
特点:
- 适用于识别较为复杂的彩色图,可识别1000种类别
- 结构比LeNet更复杂,使用Relu作为激活函数
- 应用于计算机视觉
流程:
说明:
- 由于AlexNet模型中卷积层的Filter的窗口大小和滑动步长等参数经常变化,不够稳定,为了解决这个问题,提出VGG-16模型
- 多次卷积操作来提取轮廓信息
输入:227*227*3 RGB图,3个通道
训练参数:约1亿多
特点:
- 所有卷积层Filters宽和高都是3*3,步长s=1,图像填充Padding都是same convolution
- 所有池化层Filters宽和高都是2*2,步长s=2,都使用最大化池化方法MaxPooling
- 相比AlexNet,有更多的Filter用于提取轮廓信息,准确度更高
- Filter越多,模型越稳定
卷积层采用Relu作为输出时对激活函数
'''
基于dataset\training_set数据,根据提供的结构,建立CNN模型,识别图片中的猫/狗,计算预测准确率
'''
# 1. load the data
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale=1./255)# 1./255:归一化,图像的灰度值都除以255
training_set = train_datagen.flow_from_directory('./dataset/training_set',target_size=(50,50),batch_size=32,class_mode='binary') # flow_from_directory 文件路径
# batch_size:每次选32张图片进行反向梯度搜索来求解cnn,size越小,损失函数越不稳定
# class_mode:模式为二分类
# 2. 确认输入数据标签
training_set.class_indices
#3. 建立CNN模型 set up the cnn model
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dense
#创建顺序模型的实例
model = Sequential()
#卷积层
model.add(Conv2D(32,(3,3),input_shape=(50,50,3),activation='relu')) # 32个filters,每个3*3,输入像素为50*50*3通道
#池化层
model.add(MaxPool2D(pool_size=(2,2))) # 默认s=1
#卷积层
model.add(Conv2D(32,(3,3),activation='relu'))
#池化层
model.add(MaxPool2D(pool_size=(2,2)))
#flattening layer
model.add(Flatten()) # 将(m行*n列)转换成(m*n行1列)
#FC layer
model.add(Dense(units=128,activation='relu'))
#输出层
model.add(Dense(units=1,activation='sigmoid'))
# 4. 配置模型参数 configure the model
model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy']) # 每次训练完后用accuracy进行评估
# 5. 查看模型每层的结构,及多少参数
model.summary()
# 6. 训练模型 train the model
model.fit_generator(training_set,epochs=20) # 因为是通过keras中的ImageGenerator生成图像的,所以训练时要用fit_generator
# 7. 计算训练数据集的准确率,用evaluate_generator方法 accuracy on the training data
accuracy_train = model.evaluate_generator(training_set)
print(accuracy_train)
# 8. 计算测试数据集的准确率 accuracy on the test data
test_set = train_datagen.flow_from_directory('./dataset/test_set',target_size=(50,50),batch_size=32,class_mode='binary')
accuracy_test = model.evaluate_generator(test_set)
print(accuracy_test)
'''
从网站下载猫/狗图片,对其进行预测
'''
# 9. 加载单个狗图片,对其进行归一化,维度转换,及预测
from keras.preprocessing.image import load_img, img_to_array
pic_dog = 'dog.jpg'
pic_dog = load_img(pic_dog,target_size=(50,50))
pic_dog = img_to_array(pic_dog)
pic_dog = pic_dog/255
pic_dog = pic_dog.reshape(1,50,50,3)
result = model.predict_classes(pic_dog)
print(result) # 结果为[[1]]
# 10. 加载单个猫图片,对其进行归一化,维度转换,及预测
pic_cat = 'cat1.jpg'
pic_cat = load_img(pic_cat,target_size=(50,50))
pic_cat = img_to_array(pic_cat)
pic_cat = pic_cat/255
pic_cat = pic_cat.reshape(1,50,50,3)
result = model.predict_classes(pic_cat)
print(result) # 结果为[[0]]
# 11. 获取类别序列
training_set.class_indices # {'cats': 0, 'dogs': 1}
# 12. 在多张图中预测其类别 make prediction on multiple images
import matplotlib as mlp
font2 = {'family' : 'SimHei',
'weight' : 'normal',
'size' : 20,
}
mlp.rcParams['font.family'] = 'SimHei'
mlp.rcParams['axes.unicode_minus'] = False
from matplotlib import pyplot as plt
from matplotlib.image import imread
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import load_model
a = [i for i in range(1,10)]
fig = plt.figure(figsize=(10,10))
for i in a:
img_name = str(i)+'.jpg'
img_ori = load_img(img_name, target_size=(50, 50))
img = img_to_array(img_ori)
img = img.astype('float32')/255
img = img.reshape(1,50,50,3)
result = model.predict_classes(img)
img_ori = load_img(img_name, target_size=(250, 250))
plt.subplot(3,3,i)
plt.imshow(img_ori)
plt.title('预测为:狗狗' if result[0][0] == 1 else '预测为:猫咪')
plt.show()
使用VGG16的结构提取图像特征,再根据特征建立mlp模型,实现猫狗图像识别。训练/测试数据:dataset\data_vgg:
1.对数据进行分离、计算测试数据预测准确率
2.从网站下载猫/狗图片,对其进行预测
mlp模型一个隐藏层,10个神经元
'''
单个图像预处理,使用VGG16结构提取图像特征
'''
# 1. load the data
from keras.preprocessing.image import load_img,img_to_array
img_path = '1.jpg'
img = load_img(img_path,target_size=(224,224))
img = img_to_array(img)
type(img)
# 2. 加载VGG-16模型结构
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
import numpy as np
model_vgg = VGG16(weights='imagenet',include_top=False)
x = np.expand_dims(img,axis=0)
x = preprocess_input(x)
print(x.shape)
# 3. 使用vgg模型提取图像特征
features = model_vgg.predict(x)
print(features.shape)
#4. 建立全连接层flatten
features = features.reshape(1,7*7*512)
print(features.shape)
# 5. 可视化数据 visualize the data
%matplotlib inline
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(5,5))
img = load_img(img_path,target_size=(224,224))
plt.imshow(img)
'''
任务1:批量图片预处理,用VGG16的结构提取批量图像特征
'''
# 1. 导入库
from keras.preprocessing.image import img_to_array,load_img
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
import numpy as np
# 2. 创建vgg16模型实例
model_vgg = VGG16(weights='imagenet', include_top=False)
# 3. 定义一个图片加载方法 define a method to load and preprocess the image
def modelProcess(img_path,model):
img = load_img(img_path, target_size=(224, 224))
img = img_to_array(img)
x = np.expand_dims(img,axis=0)
x = preprocess_input(x)
x_vgg = model.predict(x)
x_vgg = x_vgg.reshape(1,25088)
return x_vgg
# 4. 查看指定文件夹包含的文件名列表 list file names of the training datasets
import os
folder = "dataset/data_vgg/cats"
dirs = os.listdir(folder)
# 5. 生成各个图片路径 generate path for the images
img_path = []
for i in dirs:
if os.path.splitext(i)[1] == ".jpg":
img_path.append(i)
img_path = [folder+"//"+i for i in img_path]
# 6. 多图像预处理 preprocess multiple images
features1 = np.zeros([len(img_path),25088])
for i in range(len(img_path)):
feature_i = modelProcess(img_path[i],model_vgg)
print('preprocessed:',img_path[i])
features1[i] = feature_i
folder = "dataset/data_vgg/dogs"
dirs = os.listdir(folder)
img_path = []
for i in dirs:
if os.path.splitext(i)[1] == ".jpg":
img_path.append(i)
img_path = [folder+"//"+i for i in img_path]
features2 = np.zeros([len(img_path),25088])
for i in range(len(img_path)):
feature_i = modelProcess(img_path[i],model_vgg)
print('preprocessed:',img_path[i])
features2[i] = feature_i
# 7. 结果标签 label the results
print(features1.shape,features2.shape)
y1 = np.zeros(300)
y2 = np.ones(300)
# 8. 生成训练数据集 generate the training data
X = np.concatenate((features1,features2),axis=0)
y = np.concatenate((y1,y2),axis=0)
y = y.reshape(-1,1)
print(X.shape,y.shape)
'''
任务2:根据任务1提取的图像特征建立MLP模型,对数据进行分离、计算测试数据预测准确率(mlp模型一个隐藏层,10个神经元)
'''
# 1. split the training and test data
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=50)
print(X_train.shape,X_test.shape,X.shape)
# 2. 建立MLP模型set up the mlp model
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(units=10,activation='relu',input_dim=25088))
model.add(Dense(units=1,activation='sigmoid'))
model.summary()
# 3. configure the model
model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])
# 4. train the model
model.fit(X_train,y_train,epochs=50)
# 5. 计算训练数据集的预测准确率
from sklearn.metrics import accuracy_score
y_train_predict = model.predict_classes(X_train)
accuracy_train = accuracy_score(y_train,y_train_predict)
print(accuracy_train) # 0.98
# 6. 计算测试数据集的准确率
y_test_predict = model.predict_classes(X_test)
accuracy_test = accuracy_score(y_test,y_test_predict)
print(accuracy_test) # 0.97
'''
任务3:从网站下载猫/狗图片,对其进行预测
'''
# 加载新图片
img_path = 'cat1.jpg'
img = load_img(img_path,target_size=(224,224))
img = img_to_array(img)
x = np.expand_dims(img,axis=0)
x = preprocess_input(x)
features = model_vgg.predict(x)
features = features.reshape(1,7*7*512)
result = model.predict_classes(features)
print(result)
# coding:utf-8
import matplotlib as mlp
font2 = {'family' : 'SimHei',
'weight' : 'normal',
'size' : 20,
}
mlp.rcParams['font.family'] = 'SimHei'
mlp.rcParams['axes.unicode_minus'] = False
from matplotlib import pyplot as plt
from matplotlib.image import imread
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import load_model
#from cv2 import load_img
a = [i for i in range(1,10)]
fig = plt.figure(figsize=(10,10))
for i in a:
img_name = str(i)+'.jpg'
img_path = img_name
img = load_img(img_path, target_size=(224, 224))
img = img_to_array(img)
x = np.expand_dims(img,axis=0)
x = preprocess_input(x)
x_vgg = model_vgg.predict(x)
x_vgg = x_vgg.reshape(1,25088)
result = model.predict_classes(x_vgg)
img_ori = load_img(img_name, target_size=(250, 250))
plt.subplot(3,3,i)
plt.imshow(img_ori)
plt.title('预测为:狗狗' if result[0][0] == 1 else '预测为:猫咪')
plt.show()