单层前馈神经网络由 Frank Rosenblatt 在 20 世纪 50 年代末提出。这是深度学习和人工神经网络的起始阶段。在此期间,使用统计机器学习或传统代码编程进行预测。感知器是最早也是最直接的人工神经网络模型之一。尽管是一个简单的模型,感知器已被证明可以成功解决特定的分类问题。
Architecture
感知器是最简单的人工神经网络架构之一。它由弗兰克·罗森布拉特 (Frank Rosenblatt) 于 1957 年代提出。它是最简单的前馈神经网络类型,由完全连接到一层输出节点的单层输入节点组成。它可以学习线性可分离的模式。它使用略有不同类型的人工神经元,称为阈值逻辑单元(TLU)。它由 McCulloch 和 Walter Pitts 在 20 世纪 40 年代首次提出。
为感知器的每个输入节点分配一个权重,指示该输入对输出的重要性。感知器的输出是已通过激活函数运行的输入的加权和,以决定感知器是否将触发。它将输入的加权和计算为:
z = w 1 x 1 + w 1 x 2 + ... + w n x n = X T W
阶跃函数将此加权和与阈值进行比较,如果输入大于阈值则输出 1,否则输出 0,这是感知器最常使用的激活函数。感知器中最常用的阶跃函数是 Heaviside 阶跃函数:
感知器具有单层 阈值逻辑单元,每个 TLU 连接到所有输入。
当一层中的所有神经元都连接到前一层的每个神经元时,它被称为全连接层或密集层。
全连接层的输出可以是:
其中 X 是输入,W 是每个输入神经元的权重,b 是偏差,h 是阶跃函数。
在训练期间,感知器的权重被调整以最小化预测输出和实际输出之间的差异。通常,使用 delta 规则或感知器学习规则等监督学习算法来实现此目的。
这里 w i,j是第 i 个输入和 第 j 个输出神经元之间的权重,xi是第 i 个输入值,y j是 第 j 个实际值和预测值是
学习率。
实现代码
构建单层感知器模型
- 初始化权重和学习率,这里我们考虑输入的权重值数量+1。即+1表示偏差。
- 定义第一个线性层
- 定义激活函数。这里我们使用 Heaviside Step 函数。
- 定义预测
- 定义损失函数。
- 定义训练,权重和偏差相应更新。
- 定义拟合模型。
# 导入必要的库
import numpy as np
# 建立感知器模型
class Perceptron:
def __init__(self, num_inputs, learning_rate=0.01):
# Initialize the weight and learning rate
self.weights = np.random.rand(num_inputs + 1)
self.learning_rate = learning_rate
# 定义第一个线性层
def linear(self, inputs):
Z = inputs @ self.weights[1:].T + + self.weights[0]
return Z
# 定义Heaviside Step函数
def Heaviside_step_fn(self, z):
if z >= 0:
return 1
else:
return 0
# 定义预测
def predict(self, inputs):
Z = self.linear(inputs)
try:
pred = []
for z in Z:
pred.append(self.Heaviside_step_fn(z))
except:
return self.Heaviside_step_fn(Z)
return pred
# 定义损失函数
def loss(self, prediction, target):
loss = (prediction-target)
return loss
# 定义训练
def train(self, inputs, target):
prediction = self.predict(inputs)
error = self.loss(prediction, target)
self.weights[1:] += self.learning_rate * error * inputs
self.weights[0] += self.learning_rate * error
# 适合模型
def fit(self, X, y, num_epochs):
for epoch in range(num_epochs):
for inputs, target in zip(X, y):
self.train(inputs, target)
应用上述定义的模型对乳腺癌数据集进行二元分类
- 导入必要的库
- 加载数据集
- 将输入特征分配给 x
- 将目标特征分配给 y
- 使用适当数量的输入初始化感知器
- 训练模型
- 根据测试数据集进行预测
- 求模型的准确度
import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 生成具有两个类的线性可分离数据集
X, y = make_blobs(n_samples=1000,
n_features=2,
centers=2,
cluster_std=3,
random_state=23)
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.2,
random_state=23,
shuffle=True
)
# 将输入特征缩放为零均值和单位方差
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 设置随机种子遗留
np.random.seed(23)
# 使用适当数量的输入初始化感知器
perceptron = Perceptron(num_inputs=X_train.shape[1])
# 根据训练数据训练感知器
perceptron.fit(X_train, y_train, num_epochs=100)
# 预测
pred = perceptron.predict(X_test)
# 在测试数据上测试经过训练的感知器的准确性
accuracy = np.mean(pred != y_test)
print("准确度:", accuracy)
# 绘制数据集
plt.scatter(X_test[:, 0], X_test[:, 1], c=pred)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
输出:
准确度: 0.975
在 Pytorch 中构建并训练单层感知器模型
import torch
import torch.nn as nn
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 生成具有两个类的线性可分离数据集
X, y = make_blobs(n_samples=1000,
n_features=2,
centers=2,
cluster_std=3,
random_state=23)
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.2,
random_state=23,
shuffle=True
)
# 将输入特征缩放为零均值和单位方差
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 将数据转换为PyTorch张量
X_train = torch.tensor(X_train, dtype=torch.float32, requires_grad=False)
X_test = torch.tensor(X_test, dtype=torch.float32, requires_grad=False)
y_train = torch.tensor(y_train, dtype=torch.float32, requires_grad=False)
y_test = torch.tensor(y_test, dtype=torch.float32, requires_grad=False)
# 重塑目标张量以匹配预测的输出张量
y_train = y_train.reshape(-1, 1)
y_test = y_test.reshape(-1, 1)
torch.random.seed()
# 定义感知器模型
class Perceptron(nn.Module):
def __init__(self, num_inputs):
super(Perceptron, self).__init__()
self.linear = nn.Linear(num_inputs, 1)
# Heaviside Step函数
def heaviside_step_fn(self,Z):
Class = []
for z in Z:
if z >= 0:
Class.append(1)
else:
Class.append(0)
return torch.tensor(Class)
def forward(self, x):
Z = self.linear(x)
return self.heaviside_step_fn(Z)
# 使用适当数量的输入初始化感知器
perceptron = Perceptron(num_inputs=X_train.shape[1])
# 损失函数
def loss(y_pred,Y):
cost = y_pred-Y
return cost
# 学习率
learning_rate = 0.001
# 根据训练数据训练感知器
num_epochs = 10
for epoch in range(num_epochs):
Losses = 0
for Input, Class in zip(X_train, y_train):
# 向前传球
predicted_class = perceptron(Input)
error = loss(predicted_class, Class)
Losses += error
# 感知器学习规则
# 模型参数
w = perceptron.linear.weight
b = perceptron.linear.bias
# 逐步更新模型参数
w = w - learning_rate * error * Input
b = b - learning_rate * error
# 将权重和偏差参数指定给线性层
perceptron.linear.weight = nn.Parameter(w)
perceptron.linear.bias = nn.Parameter(b)
print('Epoch [{}/{}], weight:{}, bias:{} Loss: {:.4f}'.format(
epoch+1,num_epochs,
w.detach().numpy(),
b.detach().numpy(),
Losses.item()))
# 在测试数据上测试经过训练的感知器的准确性
pred = perceptron(X_test)
accuracy = (pred==y_test[:,0]).float().mean()
print("Accuracy on Test Dataset:", accuracy.item())
# 绘制数据集
plt.scatter(X_test[:, 0], X_test[:, 1], c=pred)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
输出:
Epoch [1/10], weight:[[ 0.01072957 -0.7055903 ]], bias:[0.07482227] Loss: 4.0000
Epoch [2/10], weight:[[ 0.0140219 -0.70487624]], bias:[0.07082226] Loss: 4.0000
Epoch [3/10], weight:[[ 0.0175706 -0.70405596]], bias:[0.06782226] Loss: 3.0000
Epoch [4/10], weight:[[ 0.02111931 -0.7032357 ]], bias:[0.06482225] Loss: 3.0000
Epoch [5/10], weight:[[ 0.02466801 -0.7024154 ]], bias:[0.06182225] Loss: 3.0000
Epoch [6/10], weight:[[ 0.02821671 -0.7015951 ]], bias:[0.05882225] Loss: 3.0000
Epoch [7/10], weight:[[ 0.03176541 -0.70077485]], bias:[0.05582226] Loss: 3.0000
Epoch [8/10], weight:[[ 0.03479535 -0.69990206]], bias:[0.05382226] Loss: 2.0000
Epoch [9/10], weight:[[ 0.03782528 -0.69902927]], bias:[0.05182226] Loss: 2.0000
Epoch [10/10], weight:[[ 0.04085522 -0.6981565 ]], bias:[0.04982227] Loss: 2.0000
Accuracy on Test Dataset: 0.9900000095367432
感知器的局限性
感知器是神经网络历史上的一个重要发展,因为它证明了简单的神经网络可以学习对模式进行分类。然而,它的能力是有限的:
感知器模型有一些限制,可能使其不适合某些类型的问题:
- 仅限于线性可分问题。
- 不可分离数据的收敛问题
- 需要标记数据
- 对输入缩放的敏感性
- 缺乏隐藏层
此后,人们开发了更复杂的神经网络,例如多层感知器 (MLP)和卷积神经网络 (CNN) ,以解决这一限制,并且可以学习更复杂的模式。