版权声明:本文为博主原创文章,未经博主允许不得转载。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
(池化层): 这些层在输入上进行最大池化操作,输出神经元的活动是由最活跃的输入神经元提供的。.
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))