感知机的定义与概念
-
感知机是一种二分类的线性分类模型,属于人工神经网络的基础单元。由Frank Rosenblatt于1957年提出,用于解决线性可分问题。
-
感知机的模型结构
-
输出:特征向量
-
权重:
-
偏置:标量b
-
激活函数:
-
输出:
-
感知机的计算过程
- 给定输入x,权重w,和偏置b,感知机输出:
其中的<w,x>的含义是向量w与向量x做内积。
- 例如有特征向量(x1, x2),则计算过程可以表示为:
这样子就可以在线性方程中将数据划分为正、负两类。
感知机的损失函数
-
感知机的训练需要优化参数w和b,所以我们需要定义一个损失函数,用损失函数的结果优化模型参数。
-
最简单的方式就是定义误分类样本与直线的距离。
-
对应感知机来说也可以用以下公式
其中的为输入,为样本预测的标签。
- 又由于感知机关心的是怎么将两类样本正确的分类开,对正确分类的样本点到决策函数的距离大小并不关心,因此我们可以省略其中这样子我们就得到了最后的损失函数。
感知机的训练实例
-
感知机的训练过程如下:
初始化权重 w = 0 偏置 b = 0 重复epoch迭代次数 计算线性输出[<w,>+b] 若线性输出≥0则预测值=1否则预测值=0 更新w = w + lr(学习率) · (-) · 更新b = b + lr(学习率) · (-)
-
以下是一个感知机训练的例子
class Perceptron:
def __init__(self, learning_rate=0.01, epochs=100):
self.lr = learning_rate # 学习率
self.epochs = epochs # 迭代次数
self.weights = None # 权重
self.bias = 0 # 偏置
def fit(self, X, y):
n_samples, n_features = X.shape
self.weights = np.zeros(n_features) # 初始化权重为0
for _ in range(self.epochs):
for idx, x_i in enumerate(X):
linear_output = np.dot(x_i, self.weights) + self.bias
y_pred = 1 if linear_output >= 0 else 0 # 阶跃函数
update = self.lr * (y[idx] - y_pred) # 权重更新量
self.weights += update * x_i # 更新权重
self.bias += update # 更新偏置量
def predict(self, X):
linear_output = np.dot(X, self.weights) + self.bias
return np.where(linear_output >= 0, 1, 0) # 返回预测标签(0或1)
-
接下来我们通过生成随机样本来验证该感知机的可行性
生成数据的代码如下:
# 生成两类线性可分数据 np.random.seed(42) X_class1 = np.random.randn(50, 2) + np.array([2, 2]) # 类别1(标签1) X_class0 = np.random.randn(50, 2) + np.array([-2, -2]) # 类别0(标签0) X = np.vstack((X_class1, X_class0)) # 垂直堆叠,增加行数 y = np.array([1] * 50 + [0] * 50) # 标签 -
并绘制出原本数据分布
# 绘制原始数据 plt.scatter(X[:, 0], X[:, 1], c=y, cmap='bwr', edgecolors='k') plt.title("Original Data") plt.show() -
接下来我们用该数据对感知机进行训练,并输出权重与偏置
# 初始化并训练感知机 perceptron = Perceptron(learning_rate=0.1, epochs=50) perceptron.fit(X, y) # 打印学到的权重和偏置 print(f"权重: {perceptron.weights}, 偏置: {perceptron.bias}") -
最后我们绘制出分类之后的数据分布
# 绘制决策边界 def plot_decision_boundary(X, y, model): # 确定绘制范围 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 # 生成网格点 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01)) # 预测整个网络的类别 Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape) # 绘制边界与样本点 plt.contourf(xx, yy, Z, alpha=0.3, cmap='bwr') plt.scatter(X[:, 0], X[:, 1], c=y, cmap='bwr', edgecolors='k') plt.title("Perceptron Decision Boundary") plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.show() plot_decision_boundary(X, y, perceptron) -
最后结果如图所示
完整代码如下:
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, learning_rate=0.01, epochs=100):
self.lr = learning_rate # 学习率
self.epochs = epochs # 迭代次数
self.weights = None # 权重
self.bias = 0 # 偏置
def fit(self, X, y):
n_samples, n_features = X.shape
self.weights = np.zeros(n_features) # 初始化权重为0
for _ in range(self.epochs):
for idx, x_i in enumerate(X):
linear_output = np.dot(x_i, self.weights) + self.bias
y_pred = 1 if linear_output >= 0 else 0 # 阶跃函数
update = self.lr * (y[idx] - y_pred) # 权重更新量
self.weights += update * x_i # 更新权重
self.bias += update # 更新偏置量
def predict(self, X):
linear_output = np.dot(X, self.weights) + self.bias
return np.where(linear_output >= 0, 1, 0) # 返回预测标签(0或1)
# 生成两类线性可分数据
np.random.seed(42)
X_class1 = np.random.randn(50, 2) + np.array([2, 2]) # 类别1(标签1)
X_class0 = np.random.randn(50, 2) + np.array([-2, -2]) # 类别0(标签0)
X = np.vstack((X_class1, X_class0)) # 垂直堆叠,增加行数
y = np.array([1] * 50 + [0] * 50) # 标签
# 绘制原始数据
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='bwr', edgecolors='k')
plt.title("Original Data")
plt.show()
# 初始化并训练感知机
perceptron = Perceptron(learning_rate=0.1, epochs=50)
perceptron.fit(X, y)
# 打印学到的权重和偏置
print(f"权重: {perceptron.weights}, 偏置: {perceptron.bias}")
# 绘制决策边界
def plot_decision_boundary(X, y, model):
# 确定绘制范围
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 生成网格点
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
np.arange(y_min, y_max, 0.01))
# 预测整个网络的类别
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
# 绘制边界与样本点
plt.contourf(xx, yy, Z, alpha=0.3, cmap='bwr')
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='bwr', edgecolors='k')
plt.title("Perceptron Decision Boundary")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
plot_decision_boundary(X, y, perceptron)
感知机总结以及其所存在的问题
-
感知机作为最早存在的二分类模型之一,它的求解算法十分简单。但是它也存在一个比较严重的问题,感知机只能产生线性切割面,无法处理XOR问题。
-
XOR问题即当数据分布无法使用一条线性函数将其区分的话,那么感知机将无法进行求解。
如图所示,该图中的数据分布无法通过一条线性可分的函数进行求解分类,所以感知机对这类问题将无法进行求解。为了解决该问题,我们便引入了多层感知机来求解该问题。