Python实现卷积神经网络

卷积神经网络与常规的神经网络十分相似,它们都由可以对权重和偏置进行学习的神经元构成。每个神经元接收一些输入,然后执行点积操作,再紧接一个可选的非线性函数。整个网络仍然表示为单可微分的评估函数,整个网络从一端输入原始图像像素,另一端输出类别的概率。其最后一层(全连接层)同样有损失函数,并且我们学习常规神经网络的方法和技巧在这里仍然奏效。

那么卷积神经网络的不同之处是什么?首先卷积网络很明确地假设所有输入都为图像,这就允许我们在结构中对明确的属性进行编码。这就使得前向函数的实现更加高效,并且极大的减少了网络中参数的数量。

卷积神经网络python实现示例源码
公信部禁止发网盘链接,请加群索取。
更多:卷积神经网络

概括地介绍CNN的基本原理 ,并通过阿拉伯字母分类例子具体介绍其实现过程,理论与实践的结合体。

对于卷积神经网络(CNN)而言,相信很多读者并不陌生,该网络近年来在大多数领域都表现优异,尤其是在计算机视觉领域中。但是很多工作人员可能直接调用相关的深度学习工具箱搭建卷积神经网络模型,并不清楚其中具体的原理。本文将简单介绍卷积神经网络(CNN),方便读者大体上了解其基本原理及实现过程,便于后续工作中的实际应用。本文将按以下顺序展开:

  • 了解卷积操作
  • 了解神经网络
  • 数据预处理
  • 了解CNN
  • 了解优化器
  • 理解 ImageDataGenerator
  • 进行预测并计算准确性
  • demo
什么是卷积?

在数学(尤其是函数分析)中,卷积是对两个函数(f和g)的数学运算,以产生第三个函数,该函数表示一个函数的形状如何被另一个修改。

此操作在多个领域都有应用,如概率、统计、计算机视觉、自然语言处理、图像和信号处理、工程和微分方程。该操作在数学上表示为:

什么是人工神经网络?

人工神经网络(ANN)或连接系统是由构成动物大脑的生物神经网络模糊地启发的计算系统。这些系统通过从示例中“学习”以执行任务,通常不需要使用用任何特定规则来编程。

人工神经网络是一个较小的处理单元集合,称为人工神经元,它们与生物神经元相似。

生物神经回路

生物神经回路
神经元之间的互联构成了一个网络模型

人工神经网络

现在,我们开始具体实现。

导入必要的数据包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

import tflearn.data_utils as du
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from keras.optimizers import RMSprop
from keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import confusion_matrix
加载数据集
train_data = pd.read_csv('../input/csvTrainImages 13440x1024.csv', header = None)
train_label = pd.read_csv('../input/csvTrainLabel 13440x1.csv', header = None)
test_data = pd.read_csv('../input/csvTestImages 3360x1024.csv', header = None)
test_label = pd.read_csv('../input/csvTestLabel 3360x1.csv', header = None)
数据集

此处使用的数据集是手写数据集。
trainIamges.csv有1024列和13440行。每列表示图像中的像素,每行表示一张单独的灰度图像。每个像素的取值范围是0到255之间的值。

train_data = train_data.iloc[:,:].values.astype('float32')
train_label = train_label.iloc[:,:].values.astype('int32')-1
test_data = test_data.iloc[:,:].values.astype('float32')
test_label = test_label.iloc[:,:].values.astype('int32')-1
可视化数据集
def row_calculator(number_of_images, number_of_columns):
    if number_of_images % number_of_columns != 0:
        return (number_of_images / number_of_columns)+1
    else:
        return (number_of_images / number_of_columns)

def display_image(x, img_size, number_of_images):
    plt.figure(figsize = (8, 7))
    if x.shape[0] > 0:
        n_samples = x.shape[0]
        x = x.reshape(n_samples, img_size, img_size)
        number_of_rows = row_calculator(number_of_images, 4)
        for i in range(number_of_images):
            plt.subplot(number_of_rows, 4, i+1)
            plt.imshow(x[i])
训练数据集
display_image(train_data, 32, 16)
测试数据集
display_image(test_data, 32, 16)
数据预处理

编码分类变量

什么是分类变量?

在统计学中,分类变量是一个可以承担限制变量之一的变量,基于某些定性属性将每个个体或其他观察单元分配给特定组或名义类别。

简单来说,分类变量的值表示类别或类。

为什么需要编码分类变量?

直接对表示类别的数字执行操作没有意义。因此,需要对其进行分类编码。
阿拉伯字母表中有28个字母。因此,数据集有28个类别。

train_label = du.to_categorical(train_label,28)
标准化
什么是标准化?

进行归一化以使整个数据进入明确定义的范围,一般选择归一化到0到1之间

在神经网络中,不仅要对数据进行标准化,还要对其进行标量化,这样处理的目的是能够更快地接近错误表面的全局最小值。

train_data = train_data/255
test_data = test_data/255

train_data = train_data.reshape([-1, 32, 32, 1])
test_data = test_data.reshape([-1, 32, 32, 1])

对其进行变形操作使得每条数据表示一个平面图像

train_data, mean1 = du.featurewise_zero_center(train_data)
test_data, mean2 = du.featurewise_zero_center(test_data)

按功能划分的零中心将每个样本的中心置零,并指定平均值。如果未指定,则对所有样品评估平均值。

建立CNN
recognizer = Sequential()

recognizer.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu', input_shape = (32,32,1)))
recognizer.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu'))
recognizer.add(MaxPool2D(pool_size=(2,2)))
recognizer.add(Dropout(0.25))

recognizer.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
recognizer.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
recognizer.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))
recognizer.add(Dropout(0.25))

recognizer.add(Flatten())
recognizer.add(Dense(units = 256, input_dim = 1024, activation = 'relu'))
recognizer.add(Dense(units = 256, activation = "relu"))
recognizer.add(Dropout(0.5))
recognizer.add(Dense(28, activation = "softmax"))
最大池化(Max Pooling)是什么?

池化意味着组合一组数据,组合数据的过程中应该遵循一些规则。
根据定义,最大池化选取一组数据中的最大值作为其输出值。

最大池还可以用于减小特征维度,它还可以避免过拟合的发生。

什么是Dropout?

Dropout是一种正则化技术,通过防止对训练数据进行复杂的协同适应来减少神经网络中的过拟合,这是神经网络模型中十分有效的方法之一。“ 丢失”指的是在神经网络中以某一个概率随机地丢弃部分神经单元。

什么是Flatten?

对特征图进行展平,以将多维数据转换为一维特征向量,以供下一层(密集层)使用

什么是密集层?

密集层只是一层人工神经网络,也被称作全连接层。

CNN的优化方法
什么是优化?

优化算法帮助我们最小化(或最大化)目标函数,目标函数只是一个数学函数,取决于模型内部可学习的参数。模型中使用预测变量集(X)计算目标值(Y)。例如,我们将神经网络的权重(W)和偏差(b)值称为其内部可学习参数,用于计算输出值,并在最优解的方向上学习和更新这些参数,即最小化损失网络。这就是神经网络的训练过程。

optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)

本文在这里使用的优化器是RMSprop,点击此处以了解有关RMSprop的更多信息。

recognizer.compile(optimizer = optimizer , loss = "categorical_crossentropy", metrics=["accuracy"])
什么是ImageDataGenerator?

当你的数据集规模比较小时,你可能会应用到图像数据生成器,它用于生成具有实时增强的批量张量图像数据,扩大数据集规模。一般而言,当数据量增多时,模型性能会得更好。以下代码用于批量加载图像:

datagen = ImageDataGenerator(
        featurewise_center=False, 
        samplewise_center=False,  
        featurewise_std_normalization=False,
        samplewise_std_normalization=False,
        zca_whitening=False,
        rotation_range=10,
        zoom_range = 0.1,  
        width_shift_range=0.1, 
        height_shift_range=0.1,
        horizontal_flip=False,
        vertical_flip=False)

datagen.fit(train_data)
CNN拟合训练数据
recognizer.fit_generator(datagen.flow(train_data,train_label, batch_size=100), epochs = 30, verbose = 2, steps_per_epoch=train_data.shape[0] // 100)
做出预测
predictions = recognizer.predict(test_data)
predictions = np.argmax(predictions,axis = 1)
生成混淆矩阵
什么是混淆矩阵?

混淆矩阵是用于总结分类算法性能的一种技术。如果每个类别中的观察数量不等,或者数据集中有两个以上的类,单独的分类准确性可能会产生误导。计算混淆矩阵可以让我们更好地了解分类模型的正确性以及它所犯的错误类型。

cm = confusion_matrix(test_label, predictions)
计算准确性
accuracy = sum(cm[i][i] for i in range(28)) / test_label.shape[0]
print("accuracy = " + str(accuracy))

本文获得了97%的准确度,感兴趣的读者可以自己尝试下。

CNN手写数字识别demo

可以实时查看CNN的工作情况,该demo显示了CNN的工作过程,以及每层输出的特征图。最后该CNN网络经过训练后能够识别手写数字。

文章原标题《Convolutional Neural Network — A Bird’s eye view with an implementation》,译者:海棠,审校:Uncle_LLD。

Python实现卷积神经网络示例

代码见https://github.com/rbtbecontinued/cnn。

目前尚未完全写好,支持随机梯度下降和批量梯度下降,激活函数仅支持sigmoid,输出层为softmax,池化核仅支持average,权值初始化采用Xavier方法。今后会逐渐进行补充和完善。

下面提供一个简单的测试用例。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 20:37:37 2018
@author: 行客Thinker
"""
 
import numpy as np
import matplotlib.pyplot as plt
from convolutional_neural_network import cnn
 
 
def config_net():
    """
    配置网络。
    """
    
    # 输入层
    size_input = np.array([8, 8])
    args_input = ("input", (size_input,))
    
    # C1卷积层
    connecting_matrix_C1 = np.ones([1, 2])
    size_conv_kernel_C1 = np.array([5, 5])
    stride_conv_kernel_C1 = 1
    padding_conv_C1 = 0
    type_activation_C1 = "sigmoid"
    args_C1 = ("convoluting", (connecting_matrix_C1, size_conv_kernel_C1, 
                               stride_conv_kernel_C1, padding_conv_C1, 
                               type_activation_C1))
    
    # S2池化层
    type_pooling_S2 = "average"
    size_pool_kernel_S2 = np.array([2, 2])
    stride_pool_kernel_S2 = 2
    padding_pool_S2 = 0
    type_activation_S2 = "sigmoid"
    args_S2 = ("pooling", (type_pooling_S2, size_pool_kernel_S2, 
                           stride_pool_kernel_S2, padding_pool_S2, 
                           type_activation_S2))
    
    # C3卷积层
    connecting_matrix_C3 = np.ones([2, 2])
    size_conv_kernel_C3 = np.array([2, 2])
    stride_conv_kernel_C3 = 1
    padding_conv_C3 = 0
    type_activation_C3 = "sigmoid"
    args_C3 = ("convoluting", (connecting_matrix_C3, size_conv_kernel_C3, 
                               stride_conv_kernel_C3, padding_conv_C3, 
                               type_activation_C3))
    
    # 输出层
    n_nodes_output = 2
    type_output = "softmax"
    args_output = ("output", (n_nodes_output, type_output))
    
    args = (args_input,
            args_C1,
            args_S2,
            args_C3,
            args_output)
    cnn_net = cnn()
    cnn_net.config(args)
    
    return cnn_net
 
 
n_train = 10000
X_train = 0.2 * np.random.randn(8, 8, n_train)
Y_train = np.random.randint(2, size=n_train)
for i in range(Y_train.shape[0]):
    if Y_train[i] == 0:
        X_train[1, :, i] += np.ones(8)
    elif Y_train[i] == 1:
        X_train[:, 1, i] += np.ones(8)
 
size_batch = 50
n_epochs = 500
cnn_net = config_net()
cnn_net.fit(X_train, Y_train, size_batch=size_batch, n_epochs=n_epochs)
 
n_test = 1000
X_test = 0.2 * np.random.randn(8, 8, n_test)
Y_test = np.random.randint(2, size=n_test)
for i in range(Y_test.shape[0]):
    if Y_test[i] == 0:
        X_test[1, :, i] += np.ones(8)
    elif Y_test[i] == 1:
        X_test[:, 1, i] += np.ones(8)
        
correct_rate = cnn_net.test(X_test, Y_test)
 
plt.figure()
for i in range(cnn_net.layers[1].n_nodes):
    plt.subplot(1, 2, i + 1)
    plt.imshow(cnn_net.layers[1].nodes[i].conv_kernels[0], cmap="gray")
plt.show()

运行结果:

发表评论

邮箱地址不会被公开。 必填项已用*标注