使用深度学习对手写数字分类-基于opencv和python的学习笔记(二十一)

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/weixin_44474718/article/details/88203920

一、实现第一个感知器

# 实现第一个感知机
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from sklearn.datasets.samples_generator import make_blobs
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建Perceptron对象来模拟分类器的实现
class Perceptron(object):
    def __init__(self, lr=0.01, n_iter=10):            # 学习率:lr=0.01, 迭代次数:n_iter=10
        """Constructor

        Parameters
        ----------
        lr : float
            Learning rate.
        n_iter : int
            Number of iterations after which the algorithm should
            terminate.
        """
        self.lr = lr
        self.n_iter = n_iter

    def fit(self, X, y):                              # 输入数据样本X和标签y
        """Fit the model to data

        Parameters
        ----------
        X : array-like
            Feature matrix, <n_samples x n_features>
        y : array-like
            Vector of target labels, <n_samples x 1>
        """
        self.weights = np.zeros(X.shape[1])   # 创建权重数组:self.weights,每个对应各个特征:X.shape[1],初始化为0
        self.bias = 0.0                              # 偏项初始化为:0
        for _ in range(self.n_iter):
            for xi, yi in zip(X, y):
                delta = self.lr * (yi - self.predict(xi))
                self.weights += delta * xi
                self.bias += delta

    def predict(self, X):
        """Predict target labels

        Parameters
        ----------
        X : array-like
            Feature matrix, <n_samples x n_features>

        Returns
        -------
        Predicted target labels, +1 or -1.

        Notes
        -----
        Must run `fit` first.
        """
        # Whenever the term (X * weights + bias) >= 0, we return
        # label +1, else we return label -1
        return np.where(((np.dot(X, self.weights) + self.bias )>= 0), 1, -1)

# 生成练习数据集
X, y = make_blobs(n_samples=100, centers=2,cluster_std=2.2, random_state=42)   # make_blobs:返回值为0或者1
y = 2 * y - 1                                                                  # 得到标签为0或者1的y

# 数据显示
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], s=100, c=y)
plt.xlabel('x1')
plt.ylabel('x2')
# plt.savefig('perceptron-data.png')
plt.title('感知器分类器的样本数据')
plt.show()

# 实例化感知器对象
p = Perceptron(lr=0.1, n_iter=10)
p.fit(X, y)                              # 调用fit函数来优化参数
print('权重: ',p.weights,'偏项:',p.bias)
print('准确率:',accuracy_score(p.predict(X), y))

# 决策边界的可视化
def plot_decision_boundary(classifier, X_test, y_test):
    # create a mesh to plot in
    h = 0.02  # step size in mesh
    x_min, x_max = X_test[:, 0].min() - 1, X_test[:, 0].max() + 1
    y_min, y_max = X_test[:, 1].min() - 1, X_test[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))

    X_hypo = np.c_[xx.ravel().astype(np.float32),yy.ravel().astype(np.float32)]
    zz = classifier.predict(X_hypo)
    zz = zz.reshape(xx.shape)

    plt.contourf(xx, yy, zz, cmap=plt.cm.coolwarm, alpha=0.8)
    plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, s=200)
plt.figure(figsize=(10, 6))
plot_decision_boundary(p, X, y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('决策边界的可视化')
plt.show()

# 应用到线性不可分的数据上
X, y = make_blobs(n_samples=100, centers=2,cluster_std=5.2, random_state=42)
y = 2 * y - 1

plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], s=100, c=y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('性线不可分')
plt.show()

p = Perceptron(lr=0.1, n_iter=10)
p.fit(X, y)
print('性线不可分准确率:',accuracy_score(p.predict(X), y))

plt.figure(figsize=(10, 6))
plot_decision_boundary(p, X, y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('决策边界的可视化')
plt.show()

二、理解多层感知器(在OpenCV中实现)

多层感知器(multilayer perceptron ,MLP):为了创建非线性决策边界,我们可以把多个感知器合并成为一个更大的网络。

设置mlp分类器:

mlp.setActivationFunction: 定义激活函数
mlp.setTrainMethod: 定义训练方法
mlp.setTermCriteria: 定义终止条件

除了性线激活函数, OpenCV 提供的激活函数

cv2.ml.ANN_MLP_IDENTITY: 线性激活函数, f(x)=x
cv2.ml.ANN_MLP_SIGMOID_SYM: 对称的 sigmoid 函数 (双曲正切), f(x)=β(1−exp(−αx))/(1+exp(−αx)). α 控制函数的斜率, β 定义输出的上限和下限。
cv2.ml.ANN_GAUSSIAN: 高斯函数 (贝尔曲线), f(x)=βexp(−αx2). α 控制函数的斜率, β 定义输出的上限。

在OpenCV中正确使用sigmoid函数:α=2.5 and β=1.0,把输入的值处理到[0, 1]

训练方法

cv2.ml.ANN_MLP_BACKPROP: 反向传播算法

cv2.ml.ANN_MLP_RPROP: rprop算法,弹性反向传播算法。

# 使用OpenCV实现多层感知器

from sklearn.datasets.samples_generator import make_blobs
import numpy as np
from sklearn.preprocessing import OneHotEncoder
import cv2
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建数据样本
X_raw, y_raw = make_blobs(n_samples=100, centers=2,cluster_std=5.2, random_state=42)
X = X_raw.astype(np.float32)

enc = OneHotEncoder(sparse=False, dtype=np.float32)
y = enc.fit_transform(y_raw.reshape(-1, 1))            # 使用独热编码来表示目标标签

mlp = cv2.ml.ANN_MLP_create()                          # 创建MLP
n_input = 2                                            # 输入层的两个特征
n_hidden = 8                                           # 隐藏层的特征个数
n_output = 2                                           # 输出层的两个标签
mlp.setLayerSizes(np.array([n_input, n_hidden, n_output]))
mlp.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 2.5, 1.0)    # 设置激活函数:SIGMOID

# 激活函数的可视化
alpha = 2.5
beta = 1.0
x_sig = np.linspace(-1.0, 1.0, 100)
y_sig = beta * (1.0 - np.exp(-alpha * x_sig))
y_sig /= (1 + np.exp(-alpha * x_sig))
plt.figure(figsize=(10, 6))
plt.plot(x_sig, y_sig, linewidth=3)
plt.xlabel('x')
plt.ylabel('y')
plt.title('激活函数的可视化')
plt.show()

mlp.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP)                      # 训练方法:反向传播算法
term_mode = cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS
term_max_iter = 300                                              # 迭代次数
term_eps = 0.01                                                  # 误差范围
mlp.setTermCriteria((term_mode, term_max_iter, term_eps))        # 指定结束需要满足的标准

# 训练和测试MLP分类器
mlp.train(X, cv2.ml.ROW_SAMPLE, y)
_, y_hat = mlp.predict(X)

print('MLP分类器的准确度:',accuracy_score(y_hat.round(), y))

# 决策边界的可视化
def plot_decision_boundary(classifier, X_test, y_test):
    # create a mesh to plot in
    h = 0.02  # step size in mesh
    x_min, x_max = X_test[:, 0].min() - 1, X_test[:, 0].max() + 1
    y_min, y_max = X_test[:, 1].min() - 1, X_test[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))

    X_hypo = np.c_[xx.ravel().astype(np.float32),
                   yy.ravel().astype(np.float32)]
    _, zz = classifier.predict(X_hypo)
    zz = np.argmax(zz, axis=1)                  # 把独热编码转化成标签对应的数字
    zz = zz.reshape(xx.shape)
    plt.contourf(xx, yy, zz, cmap=plt.cm.coolwarm, alpha=0.8)
    plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, s=200)
plt.figure(figsize=(10, 6))
plot_decision_boundary(mlp, X, y_raw)
plt.title('决策边界的可视化')
plt.show()

三、了解深度学习

熟悉keras

keras的核心数据结构是一个模型,和OpenCV的分类器的对象很相似。

Sequential:在一个线性堆栈中排列神经网络的不同层。

接下来的层可以一个一个的添加到模型中。在keras中,层不仅包含神经元,它们也执行一个函数。一些核心层类型如下所示:

Dense: 这是一个紧密连接的层。一层中的神经元与前一层的每个神经元相连接。.

Activation: 激活函数. Keras provides a whole range of activation functions, 包括 OpenCV’s 恒等函数(linear), 双曲正弦 (tanh), 反曲压缩函数 (sigmoid), softmax 函数 (softmax),

Reshape: This reshapes an output to a certain shape.

还有一些其他层用于对输入进行算术或者几何操作计算:

Convolutional layers(卷积层): 用于指定一个用于卷积输入层的核,这样就可以执行如Sobel滤波或者在一维二维三维上应用高斯核的操作.

Pooling layers(池化层): 这些层在输入上进行最大池化操作,输出神经元的活动是由最活跃的输入神经元提供的。.

扫描二维码关注公众号,回复: 6146831 查看本文章

Dropout: 这个层在每次更新时随机把一部分输入单元设置为0.是一种在过程中注入噪声的方法,使其更具鲁棒性。

Embedding: 这个层对类别数据进行编码,与sklearn 中的preprocessing模块中的一些函数类似。

GaussianNoise: 这个层应用了附加的以0为中心的高斯噪音,使其更具鲁棒性。

指定训练方法:

梯度随机下降(stochastic gradient descent (‘sgd’)): 前面讨论过
均方根传播(root mean square propagation (‘RMSprop’)): 这是一种对于每个参数自适应学习率的方法
自适应矩估计adaptive moment estimation (‘Adam’): 由均方根传播和其他方法改进

损失函数:

均方误差(mean squared error (‘mean_squared_error’)): 前面讨论过

铰链损失(hinge loss (‘hinge’)): 这个方法是SVM等常用的最大边缘分类器。

from keras.models import Sequential
from sklearn.datasets.samples_generator import make_blobs
from keras.layers import Dense
import numpy as np

model = Sequential()

# 使用两个输入一个输出的dense层来实现感知器,权重初始化为0
model.add(Dense(1, activation='linear', input_dim=2,
                kernel_initializer='zeros'))
model.compile(optimizer='sgd',loss='mean_squared_error',
              metrics=['accuracy'])
X, y = make_blobs(n_samples=100, centers=2, cluster_std=2.2, random_state=42)

# 多少次迭代:epochs=400, 样本:batch_size=100, 是否随机化:shuffle=False, 是否输出更新进度:verbose=0
model.fit(X, y, epochs=400, batch_size=100, shuffle=False, verbose=0)
print(model.evaluate(X, y))    # 结果的第一个值:均方误差,   第二个值:准确率

四、手写数字分类

4.1 使用OpenCV构建一个多层感知器

数据集预处理:

1、剧中放置:如果特征出现偏置,对于神经网络来说很难找到训练样本中的共性。
2、缩放:对于缩放到相同的尺寸非常重要。
3、类别特征表示:目标标签是独热编码的很重要,这样我们可以在输出层有10个神经元,对应于0-9这10个不同的类。

参数解释:

y_train_pre = enc.fit_transform(y_train.reshape(-1, 1))

reshape(-1, 1) 表示n行1列的数据
enc.fit_transform把训练数据集的标签从一个以0-9的整数表示的<n_samples x 1>向量转换为一个由浮点数0.0或1.0表示的<n_samples x 10>矩阵。

设置学习率:0的5次方 个数量级的样本,学习率设置为10的负5次方。

# 使用OpenCV构建一个多层感知器
from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import OneHotEncoder
import cv2
from sklearn.metrics import accuracy_score

# 载入数据集
(X_train, y_train), (X_test, y_test) = mnist.load_data()
print(X_train.shape, y_train.shape)                   # 数据格式
print(np.unique(y_train))                             # 找到y_train中所有出现的值

# 数据可视化
plt.figure(figsize=(16, 6))
for i in range(10):
    plt.subplot(2, 5, i + 1)
    plt.imshow(X_train[i, :, :], cmap='gray')
    plt.axis('off')
# plt.savefig('mnist-examples.png')
plt.show()

# 数据预处理
enc = OneHotEncoder(sparse=False, dtype=np.float32)        # 创建独热编码器
# 把训练数据集的标签从一个以0-9的整数表示的<n_samples x 1>向量转换为一个由浮点数0.0或1.0表示的<n_samples x 10>矩阵。
y_train_pre = enc.fit_transform(y_train.reshape(-1, 1))    # reshape(-1, 1) 表示n行1列,得到10行1列的数据
y_test_pre = enc.fit_transform(y_test.reshape(-1, 1))

# 为了使用OpenCV 进行下面的处理
# X_train_pre是0-255之间的整数三维矩阵<n_samples x 28 x 28>。
# 我们希望拥有的是一个浮点数表示的二维矩阵<n_samples x n_features>,n_features为28*28=784.
X_train_pre = X_train.astype(np.float32) / 255.0
X_train_pre = X_train_pre.reshape((X_train.shape[0], -1))
X_test_pre = X_test.astype(np.float32) / 255.0
X_test_pre = X_test_pre.reshape((X_test.shape[0], -1))

# 使用OpenCV训练一个MLP
mlp = cv2.ml.ANN_MLP_create()
mlp.setLayerSizes(np.array([784, 512, 512, 10]))    # 分别设置每层的特征数,输入784 输出10个
mlp.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 2.5, 1.0)   # 设置激活函数
mlp.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP)                       # 设置训练方法
mlp.setBackpropWeightScale(0.0001)         # 设置学习率,10的5次方 个数量级的样本,学习率设置为10的负5次方。
term_mode = cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS    # 指定终止标准
term_max_iter = 10
term_eps = 0.01
mlp.setTermCriteria((term_mode, term_max_iter, term_eps))

mlp.train(X_train_pre, cv2.ml.ROW_SAMPLE, y_train_pre)            # 训练

_, y_hat_train = mlp.predict(X_train_pre)
print('训练集上的准确率:',accuracy_score(y_hat_train.round(), y_train_pre))
_, y_hat_test = mlp.predict(X_test_pre)
print('测试集上的准确率:',accuracy_score(y_hat_test.round(), y_test_pre))

4.2 使用Keras构建一个深度神经网络

通过在特征矩阵中添加更多的维度来保留输入图像的二维性质

X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1) # 转换为四维矩阵, # 维度为n_features * 28 * 28 * 1

通过独热编码,可以确保目标标签的每个类都可以分配到输出层中的一个神经元

# 使用Keras构建一个深度神经网络
import numpy as np
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import Activation
from keras.layers import MaxPooling2D, Dropout
from keras.layers import Flatten, Dense

# 数据预处理
np.random.seed(1337)
(X_train, y_train), (X_test, y_test) = mnist.load_data()
print(X_train.shape)
# 通过在特征矩阵中添加更多的维度来保留输入图像的二维性质
img_rows, img_cols = 28, 28
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)  # 转换为四维矩阵,
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)     # 维度为n_features * 28 * 28 * 1
input_shape = (img_rows, img_cols, 1)
X_train = X_train.astype('float32') / 255.0                         # 转换到0-1之间的32为浮点数
X_test = X_test.astype('float32') / 255.0
# 进行独热编码,确保目标标签的每个类都可以分配到输出层中的一个神经元
n_classes = 10
Y_train = np_utils.to_categorical(y_train, n_classes)
Y_test = np_utils.to_categorical(y_test, n_classes)

# 创建卷积神经网络
model = Sequential()
n_filters = 32
kernel_size = (3, 3)                                              # 定义卷积层的核为3*3像素的二维卷积
model.add(Conv2D(n_filters, (kernel_size[0], kernel_size[1]),
                 padding='valid',input_shape=input_shape))        # 添加卷积层

model.add(Activation('relu'))                                     # 添加激活函数
model.add(Conv2D(n_filters, (kernel_size[0], kernel_size[1])))    # 添加卷积层
model.add(Activation('relu'))
# 添加池化层
pool_size = (2, 2)
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Dropout(0.25))

model.add(Flatten())                         # 拉平模型传入到softmax中
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(n_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='adadelta',metrics=['accuracy'])    # 使用交叉熵损失函数和adadelta算法
model.fit(X_train, Y_train, batch_size=128, epochs=12,
          verbose=0, validation_data=(X_test, Y_test))      # 拟合模型
print('模型准确度:',model.evaluate(X_test, Y_test, verbose=1))


猜你喜欢

转载自blog.csdn.net/weixin_44474718/article/details/88203920