点击下方卡片,关注“新机器视觉”公众号
视觉/图像重磅干货,第一时间送达
现在机器学习、深度学习的研究日益增多,并且不断成熟,许多人开始走向人工智能学习的领域。从入门到实战,是一个比较好的学习路线。我从开始接触到现在大概1年时间,其中有些时候忙着课程和其他事情,从视频学习到看书,接着尝试实战项目,这一步步走来确实学习到了许多知识。原理知识能够在实际应用中提供创新和优化的方向,而实践则能够进一步加深对理论方面的理解。
1、卷积神经网络
卷积神经网络(Convolutional Neural Network,CNN,又称为ConvNet)有着它特殊的功能,网络中保留了空间信息,因此可以更好地适用于图像分类问题。原理来源于人类视觉生物学数据的启发,视觉基于多个皮质层,每层识别越来越多的结构性信息。我们看到的是很多单个的像素;然后从这些像素中,我们识别出几何组成;再然后……这样越来越多的复杂的元素,如物体、面部、人类躯干、动物等被识别出来。
很明显,图像识别分类问题就是CNN的用武之地。
深度卷积神经网络,是由很多神经网络层组成。卷积层和池化层这两种不同的网络层,经常交互出现。每个滤波器的深度在网络中由左向右增加。最后一部分通常由一个或多个全连接层组成,如下图。
CNN中最基础的操作是卷积,再精确一点,基础CNN所用的卷积是一种2-D卷积。也就是说,kernel只能在x,y上滑动位移,不能进行深度 (跨通道) 位移。
假设输入图像使用tf(TensorFlow)顺序,它在3个信道上的形状为(256,256),这可以表示成(256, 256, 3)。Keras中,添加一个输出维度为32并且每个滤波器为3×3的卷积层,可以写成:
model = Sequential()model.add(Conv2D(32, (3, 3), input_shape=(256, 256, 3))
这就是说,我们用3个输入信道(或输入滤波器)在一个256×256的图像上进行3×3的卷积运算,得到了一个32个信道(输出滤波器)的输出,卷积结果类似下图。
池化,是一种降采样操作,主要目标是降低feature maps的特征空间,或者可以认为是降低feature maps的分辨率。因为feature map参数太多,而图像细节不利于高层特征的抽取。
常用的有最大池化和平均池化。
最大池化:简单地输出最大激活值作为这个区域的观测结果。在Keras中,定义一个2×2的最大池化层:
model.add(MaxPooling2D(pool_size = (2, 2)))
平均池化:把这个区域观察到的激活值取平均值。如上图用平均池化则会得到:[[1.7,4],[3.75,2,5]]
LeNet是一个较简单的卷积神经网络。下图显示了其结构:输入的二维图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层。from keras import backend as Kfrom keras.models import Sequentialfrom keras.layers.convolutional import Conv2Dfrom keras.layers.convolutional import MaxPooling2Dfrom keras.layers.core import Activationfrom keras.layers.core import Flattenfrom keras.layers.core import Densefrom keras.datasets import mnistfrom keras.utils import np_utilsfrom keras.optimizers import SGD, RMSprop, Adamimport numpy as npimport matplotlib.pyplot as plt
# 定义ConvNetclass LeNet: @staticmethod def build(input_shape, classes): model = Sequential() # CONV => RELU => POOL model.add(Conv2D(20, kernel_size=5, padding="same", input_shape=input_shape)) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) # CONV => RELU => POOL model.add(Conv2D(50, kernel_size=5, border_mode="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) # Flatten层到RELU层 model.add(Flatten()) model.add(Dense(500)) model.add(Activation("relu")) # softmax分类器 model.add(Dense(classes)) model.add(Activation("softmax")) return model
1、最先是卷积阶段,我们使用ReLU激活函数,并用最大池化方法。我们的网络将学习20个卷积滤波器,其中每个滤波器的大小都是5×5。输出维度和输入形状相同,因而将是28×28像素。注意,因为二维卷积是我们管道中的第一个阶段,我们必须定义它的input_shape。最大池化操作实现了一个滑窗,它在网络层上滑动,并取水平和垂直各两个像素区域上的最大值。
2、之后的第二个卷积阶段也是用ReLU激活函数,后面再次跟着最大池化方法。把学到的卷积滤波器数量从前面的20增加到50个。在更深的网络层增加滤波器数目是深度学习中一个普遍采用的技术。
3、最后一个全连接网络,它包含500个神经元,其后是具有10个类别的softmax分类器。
使用上一步定义的LeNet卷积神经网络,加载Keras里面封装的MINST图像数据集进行训练。
训练集和测试集划分:
60000 train samples
10000 test samples
完整代码和详细注释如下:
# 网络和训练NB_EPOCH = 5BATCH_SIZE = 128VERBOSE = 1OPTIMIZER = Adam()VALIDATION_SPLIT = 0.2IMG_ROWS, IMG_COLS = 28, 28NB_CLASSES = 10INPUT_SHAPE = (1, IMG_ROWS, IMG_COLS)# 混合并划分训练集和测试集数据(X_train, y_train), (X_test, y_test) = mnist.load_data()K.set_image_dim_ordering("th")# 把它们看成float类型并归一化X_train = X_train.astype('float32')
X_test = X_test.astype('float32')X_train /= 255X_test /= 255# 我们需要使用形状60K×[1×28×28]作为卷积网络的输入X_train = X_train[:, np.newaxis, :, :]X_test = X_test[:, np.newaxis, :, :]print(X_train.shape[0], 'train samples')print(X_test.shape[0], 'test samples')# 将类向量转换成二值类别矩阵y_train = np_utils.to_categorical(y_train, NB_CLASSES)y_test = np_utils.to_categorical(y_test, NB_CLASSES)# 初始化优化器和模型model = LeNet.build(input_shape=INPUT_SHAPE, classes=NB_CLASSES)model.compile(loss="categorical_crossentropy", optimizer=OPTIMIZER, metrics=["accuracy"])history = model.fit(X_train, y_train, batch_size=BATCH_SIZE, epochs=NB_EPOCH, verbose=VERBOSE, validation_split=VALIDATION_SPLIT)score = model.evaluate(X_test, y_test, verbose=VERBOSE)print("Test score:", score[0])print('Test accuracy:', score[1])# 列出全部历史数据print(history.history.keys())# 汇总准确率历史数据plt.plot(history.history['acc'])plt.plot(history.history['val_acc'])plt.title('model accuracy')plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend([
'train', 'test'], loc='upper left')plt.show()# 汇总损失函数历史数据plt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()
经过5个epoch,就获得一个近似99%的准确率,绘制出模型准确率和损失函数的变化图如图。
Test accuracy: 0.9899
在此之前,我总结记录了一些机器学习的实战,包括《机器学习应用——电影评论情感分析模型构建》《多分类器集成学习:多数票机制、Bagging、Adaboost实例分析》《基于sklearn库的机器学习模型与调优实践详细步骤》等,感兴趣的伙伴可以查看,偏向实践更加有趣!
这一篇整理了卷积神经网络的详细内容,了解其原理来龙去脉,通过简单入门项目深入浅出。CNN在图像识别分类的应用广泛,在许多深度学习任务中也会用到CNN神经网络。