计算机视觉是深度学习中最酷的应用之一,它让计算机能够像人类一样“看”和理解图像。想象一下,计算机可以自动识别照片中的物体、人脸,甚至可以读懂交通标志。这一切听起来是不是很神奇?其实,这一切都离不开深度学习中的卷积神经网络(CNN)。今天,我们就来深入了解一下CNN是如何工作的。
5.1 卷积神经网络简介
先来看下卷积神经网络(CNN)是什么。
CNN是一种专门用于处理图像数据的神经网络。它的灵感来源于人类视觉系统的工作方式。想象一下,当你看到一张照片时,你的大脑会先识别出照片中的边缘、纹理等基本特征,然后逐步组合这些特征,最终识别出照片中的物体。CNN的工作原理也是类似的,它通过多层的卷积操作来逐步提取图像的特征。
我们来看一个简单的CNN结构。
from keras import layers
from keras import modelsmodel = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
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(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
这里,我们用Conv2D
层来提取图像的特征,用MaxPooling2D
层来减少特征图的尺寸。最后,我们用Flatten
层将特征图展平为一维向量,然后用Dense
层进行分类。
这个网络可以用来做什么呢?
我们可以用它来识别照片中的猫和狗。想象一下,你有一堆猫和狗的照片,你想让计算机自动识别出哪些是猫,哪些是狗。这就是一个典型的二分类问题。
5.2 在小型数据集上从头开始训练一个卷积神经网络
好,下面我们来看看如何用CNN解决一个实际问题。
假设你有一个小型的数据集,包含2000张猫和狗的照片,你想用这些照片训练一个CNN模型。虽然数据量不大,但CNN依然可以很好地工作。
我们先来看看数据预处理。
我们需要将照片的尺寸调整为统一的大小(比如150×150),并将像素值归一化到0到1之间。这样可以让神经网络的学习过程更加稳定。
from keras.preprocessing.image import ImageDataGeneratortrain_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)train_generator = train_datagen.flow_from_directory(train_dir, # 训练数据目录target_size=(150, 150), # 调整照片大小batch_size=20,class_mode='binary') # 因为是二分类问题validation_generator = test_datagen.flow_from_directory(validation_dir, # 验证数据目录target_size=(150, 150),batch_size=20,class_mode='binary')
接下来,我们开始训练模型。
我们用fit_generator
方法来训练模型,训练100个epoch。
history = model.fit_generator(train_generator,steps_per_epoch=100, # 每个epoch的步数epochs=100,validation_data=validation_generator,validation_steps=50)
训练完成后,我们在测试集上评估模型的性能。
test_generator = test_datagen.flow_from_directory(test_dir, # 测试数据目录target_size=(150, 150),batch_size=20,class_mode='binary')test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)
print('Test accuracy:', test_acc)
结果怎么样呢?
你会发现,这个简单的CNN在测试集上的准确率可以达到82%左右。这说明CNN能够很好地学习照片中的特征,识别出猫和狗。
5.3 使用预训练的卷积神经网络
下面我们来看看如何利用预训练的模型来提升性能。
预训练的模型是在大规模数据集(比如ImageNet)上训练好的模型。这些模型已经学习到了很多通用的图像特征,我们可以直接利用这些特征来解决自己的问题。
我们来加载一个预训练的模型:VGG16。
from keras.applications import VGG16conv_base = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
这里,weights='imagenet'
表示我们加载的是在ImageNet数据集上预训练好的权重。include_top=False
表示我们不加载模型的顶部分类层,因为我们有自己的分类任务。
接下来,我们在预训练模型的基础上添加自己的分类器。
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
然后,我们冻结预训练模型的权重,只训练我们添加的分类器。
conv_base.trainable = False
最后,我们开始训练模型。
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=validation_generator,validation_steps=50)
训练完成后,我们在测试集上评估模型的性能。
test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)
print('Test accuracy:', test_acc)
你会发现,利用预训练模型后,模型的准确率可以达到96%左右。
5.4 卷积神经网络的可视化
最后,我们来看看如何可视化CNN学到的特征。
可视化可以帮助我们理解CNN是如何工作的。我们可以可视化中间层的激活,看看CNN是如何逐步提取图像特征的。
我们先来看看如何可视化中间层的激活。
from keras.models import Modellayer_outputs = [layer.output for layer in model.layers[:8]]
activation_model = Model(inputs=model.input, outputs=layer_outputs)img_tensor = ... # 加载一张测试图片
activations = activation_model.predict(img_tensor)
这里,activations
是一个列表,包含了每个中间层的激活。我们可以将这些激活可视化,看看CNN是如何逐步提取图像特征的。
我们还可以可视化CNN的过滤器。
过滤器是CNN用来检测图像中特定模式的工具。我们可以生成一个输入图像,让某个过滤器的激活最大化,从而可视化这个过滤器。
from keras import backend as Klayer_name = 'block3_conv1'
filter_index = 0
layer_output = model.get_layer(layer_name).output
loss = K.mean(layer_output[:, :, :, filter_index])grads = K.gradients(loss, model.input)[0]
grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
iterate = K.function([model.input], [loss, grads])input_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128.
step = 1.
for i in range(40):loss_value, grads_value = iterate([input_img_data])input_img_data += grads_value * stepimg = input_img_data[0]
这里,img
就是让某个过滤器激活最大化的输入图像。我们可以将它可视化,看看这个过滤器检测的是什么模式。
总结
我们从卷积神经网络(CNN)的基本结构讲起,了解了它如何通过卷积操作逐步提取图像特征。我们还学习了如何用CNN解决实际问题,比如识别照片中的猫和狗。我们还探讨了如何利用预训练的模型来提升性能,以及如何可视化CNN学到的特征。