神经网络中最基本的成分是神经元。每个神经元与其他神经元相连,当它“兴奋”时,就会向相连的神经元发送化学物质,从而改变这些神经元内的电位;如果某神经元的电位超过了一个“阈值”(threshold),那么它就会被激活,即“兴奋”起来,向其他神经元发送化学物质.
MP神经元模型:神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与神经元的阈值进行比,然后通过激活函数处理以产生神经元的输出。
两个常见的激活函数:
感知机(Perceptron)由两层神经元组成,输入层接收外界输入信号后传递给输出层,输出层是 M-P神经元,亦称“阈值逻辑单元”:
感知机容易实现逻辑与、或、非:
如果存在一个线性超平面两类模式分开,则感知机可收敛;否则振荡,如下图的异或
要解决非线性可分问题,需要多层功能神经元。
两层感知机:输入层和输出层加一层隐含层
多层前馈神经网络:每一层神经元全互连,神经元之间不存在同层连接,也不存在跨层连接
误差逆传播算法(BP算法)是迄今最成功的神经学习网络(通常说BP网络时指的是多层前馈神经网络)。
训练集: D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x m , y m ) } , x i ∈ R d , y i ∈ R l , D=\{(\boldsymbol{x}_1,\boldsymbol{y}_1),(\boldsymbol{x}_2,\boldsymbol{y}_2),\ldots,(\boldsymbol{x}_m,\boldsymbol{y}_m)\},\boldsymbol{x}_i\in\mathbb{R}^d,\boldsymbol{y}_i\in\mathbb{R}^l, D={(x1,y1),(x2,y2),…,(xm,ym)},xi∈Rd,yi∈Rl,
输入 d d d个属性,输出 l l l维向量。
则采用输入层 d d d个神经元 x x x、 q q q个隐层神经元 b b b、输出层 l l l个神经元 y y y的多层前馈神经网络(BP网络)。
临时变量:输入层为第 i i i个神经元、隐层为第 h h h个神经元、输出层为第 j j j层神经元
连接权:输入层第i个神经元与隐层第h个神经元的连接权为 v i h v_{ih} vih、隐层第 h h h个神经元与输出层第 j j j个神经元的连接权为 w h j w_{hj} whj
阈值:隐层第 h h h个神经元的阈值: γ h \gamma_{h} γh、输出层第 j j j个神经元的阈值: θ j \theta _j θj
输入:第 h h h个神经元的输入为 α h = ∑ i = 1 d v i h x i \alpha_h=\sum_{i=1}^dv_{ih}x_i αh=∑i=1dvihxi,输出层第 j j j个神经元的为 β j = ∑ h = 1 q w h j b h \beta_{j}=\sum_{h=1}^{q}w_{hj}b_{h} βj=∑h=1qwhjbh
假设激活函数使用Sigmoid函数。假定神经网络的输出为 y k = ( y ^ 1 k , y ^ 2 k , … , y ^ l k ) y_{k}=(\hat{y}_{1}^{k}, \hat{y}_{2}^{k},\ldots,\hat{y}_{l}^{k}) yk=(y^1k,y^2k,…,y^lk),即 y ^ j k = f ( β j − θ j ) \hat{y}_j^k=f (\beta_j-\theta_j) y^jk=f(βj−θj) 网络均方误差为 E k = 1 2 ∑ j = 1 l ( y ^ j k − y j k ) 2 E_k=\frac12\sum_{j=1}^l(\hat{y}_j^k-y_j^k)^2 Ek=21j=1∑l(y^jk−yjk)2
需要确定的参数:
g j = − ∂ E k ∂ y ^ j k ⋅ ∂ y ^ j k ∂ β j = − ( y ^ j k − y j k ) f ′ ( β j − θ j ) = y ^ j k ( 1 − y ^ j k ) ( y j k − y ^ j k ) . \begin{aligned} g_j& =-\frac{\partial E_{k}}{\partial\hat{y}_{j}^{k}}\cdot\frac{\partial\hat{y}_{j}^{k}}{\partial\beta_{j}} \\ &=-(\hat{y}_{j}^{k}-y_{j}^{k})f^{\prime}(\beta_{j}-\theta_{j}) \\ &=\hat{y}_j^k(1-\hat{y}_j^k)(y_j^k-\hat{y}_j^k). \end{aligned} gj=−∂y^jk∂Ek⋅∂βj∂y^jk=−(y^jk−yjk)f′(βj−θj)=y^jk(1−y^jk)(yjk−y^jk).
Δ w h j = η g j b h Δ θ j = − η g j Δ v i h = η e h x i Δ γ h = − η e h \begin{gathered} \Delta w_{hj} =\eta g_{j}b_{h} \\ \Delta\theta_{j} =-\eta g_{j} \\ \Delta v_{ih} =\eta e_hx_i \\ \Delta\gamma_{h} =-\eta e_{h} \end{gathered} Δwhj=ηgjbhΔθj=−ηgjΔvih=ηehxiΔγh=−ηeh
e h = − ∂ E k ∂ b h ⋅ ∂ b h ∂ α h = − ∑ j = 1 l ∂ E k ∂ β j ⋅ ∂ β j ∂ b h f ′ ( α h − γ h ) = ∑ j = 1 l w h j g j f ′ ( α h − γ h ) = b h ( 1 − b h ) ∑ j = 1 l w h j g j \begin{aligned} e_{h}& =-\frac{\partial E_k}{\partial b_h}\cdot\frac{\partial b_h}{\partial\alpha_h} \\ &=-\sum_{j=1}^{l}\frac{\partial E_{k}}{\partial\beta_{j}}\cdot\frac{\partial\beta_{j}}{\partial b_{h}}f^{\prime}(\alpha_{h}-\gamma_{h}) \\ &=\sum_{j=1}^lw_{hj}g_jf^{\prime}(\alpha_h-\gamma_h) \\ &=b_h(1-b_h)\sum_{j=1}^lw_{hj}g_j \end{aligned} eh=−∂bh∂Ek⋅∂αh∂bh=−j=1∑l∂βj∂Ek⋅∂bh∂βjf′(αh−γh)=j=1∑lwhjgjf′(αh−γh)=bh(1−bh)j=1∑lwhjgj
误差逆传播算法
输入:训练集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x m , y m ) } D=\{(\boldsymbol{x}_1,\boldsymbol{y}_1),(\boldsymbol{x}_2,\boldsymbol{y}_2),\ldots,(\boldsymbol{x}_m,\boldsymbol{y}_m)\} D={(x1,y1),(x2,y2),…,(xm,ym)},学习率 η \eta η
过程:
在(0,1)范围内随机初始化网络中所有连接权和阈值
repeat:
for (xk, yk) in D :
计算当前样本的输出y'k
计算输出层神经元的梯度项g_j
计算隐层神经元的梯度项e_h
更新连接权w_hj,v_ih与阈值theta_j,gamma_h
end for
until 达到停止条件
输出:连接权与阈值确定的多层前馈神经网络
基于梯度的搜索中,我们从某些初始解出发,迭代寻找最优参数值.每次迭代中,我们先计算误差函数在当前点的梯度,然后根据梯度确定搜索方向.例如,由于负梯度方向是函数值下降最快的方向,因此梯度下降法就是沿着负梯度方向搜索最优解.若误差函数在当前点的梯度为零,则已达到局部极小,更新量将为零,这意味着参数的迭代更新将在此停止.然而,如果误差函数具有多个局部极小,则不能保证找到的解是全局最小.
在现实任务中,人们常采用以下策略来试图“跳出”局部极小,从而进一步接近全局最小:
上述用于跳出局部极小的技术大多是启发式,理论上.尚缺乏保障.
RBF(径向基函数)网络是一种常用于模式识别和函数逼近任务的人工神经网络。RBF网络由三层组成:输入层、具有径向基函数神经元的隐藏层和输出层:
RPF网络可表示为 φ ( x ) = ∑ i = 1 q w i ρ ( x , c i ) \varphi(\boldsymbol{x})= \sum_{i=1}^{q}w_{i}\rho( \boldsymbol{x},\boldsymbol{c}_{i}) φ(x)=i=1∑qwiρ(x,ci)常用高斯径向基函数: ρ ( x , c i ) = e − β i ∥ x − c i ∥ 2 \rho(\boldsymbol{x} ,\boldsymbol{c}_{i}) = e^{-\beta_{i}\| \boldsymbol{x}-\boldsymbol{c}_{i} \|^{2}} ρ(x,ci)=e−βi∥x−ci∥2
ART(自适应共振理论)网络是一种人工神经网络,旨在模拟大脑处理和组织信息的方式。ART网络在涉及模式识别、分类和聚类等任务中非常有用。
ART网络的简要工作原理:
SOM(Self-Organizing Map,自组织映射)网络是一种常用的无监督学习算法,用于聚类、可视化和特征提取等任务。它是一种基于神经网络的数据降维和模式识别方法。
SOM网络的基本原理:
SOM网络能够有效地对高维数据进行降维和聚类,同时保留了输入数据的拓扑结构。它在可视化数据、模式识别、图像处理等领域具有广泛应用。
级联相关网络(Cascade Correlation Network)是一种神经网络结构,它具有自适应的网络拓扑和动态构建连接的能力。级联相关网络用于解决神经网络训练中的困难问题。
级联相关网络的基本原理:
级联相关网络的一个重要特点是它可以自动决定网络的结构和复杂度。网络会在训练过程中根据任务的需求动态地增加隐藏层神经元,从而适应更复杂的模式。
Elman网络是一种递归神经网络(Recurrent Neural Network,RNN)结构,也称为简单循环神经网络(Simple Recurrent Neural Network)。它是一种具有反馈连接的前馈神经网络,用于处理序列数据和时序任务。
Elman网络的基本结构:
Elman网络在序列建模、语言模型、预测、语音识别和自然语言处理等任务中具有广泛的应用。它可以通过反向传播算法进行训练,也可以使用其他适当的优化算法进行参数更新。
Boltzmann机(Boltzmann Machine)是一种基于概率的生成式神经网络模型。它由基本的随机二值神经元组成,这些神经元以随机方式相互连接,并使用能量函数进行训练和学习。
Boltzmann机的要点:
需要注意的是,传统的Boltzmann机存在训练和计算复杂度高的问题。为了解决这些问题,出现了改进的变种,如受限玻尔兹曼机(Restricted Boltzmann Machine,RBM)和深度信念网络(Deep Belief Network,DBN),它们在Boltzmann机的基础上进行了简化和扩展。
深度学习(Deep Learning)是一种机器学习方法,旨在模仿人脑的神经网络结构和工作方式来处理和学习复杂的数据。深度学习通过构建深层次的神经网络模型,利用大量的数据进行训练,并自动学习数据的特征表示和抽象层次,从而实现高效的模式识别和数据分析。
深度学习的要点:
深度学习的发展得益于算力的提升、数据的丰富和算法的创新。它已经成为人工智能领域的重要技术,并在许多实际问题中展现出强大的建模和预测能力。
网上给出的基本网络结构:
然而在本数据集中,输入图不是1*32*32,是1*28*28。所以正确的网络结构应该是
level | input | stride | output | |
1 | 1*28*28 | 6*5*5 | 1 | 6*24*24 |
MaxPool | 6*24*24 | MaxPool | 2 | 6*12*12 |
2 | 6*12*12 | 16*5*5 | 1 | 16*8*8 |
MaxPool | 16*8*8 | MaxPool | 2 | 16*4*4 |
Flatten | 16*4*4 | Flatten | 256 | |
3FC | 256 | FC | 120 | |
4FC | 120 | FC | 84 | |
5FC | 84 | FC | 10 |
# -*-coding =utf-8 -*-
import torch
import matplotlib.pyplot as plt
import torchvision
# 定义数据转换
transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
# 加载数据集
batch_size=32
path = r'05data'
train_dataset = torchvision.datasets.MNIST(root=path, train=True,transform=transform,download =False)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataset = torchvision.datasets.MNIST(root=path, train=True,transform=transform,download =False)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
# loader.shape=1875*[32*1*28*28,32]
# 数据集可视化
from sklearn.preprocessing import MinMaxScaler
# 归一化转为[0,255]
transfer=MinMaxScaler(feature_range=(0, 255))
def visualize_loader(batch,predicted=''):
# batch=[32*1*28*28,32]
imgs=batch[0].squeeze().numpy() # 消squeeze()一维
fig, axes = plt.subplots(4, 8, figsize=(12, 6))
labels=batch[1].numpy()
if str(predicted)=='':
predicted=labels
for i, ax in enumerate(axes.flat):
ax.imshow(imgs[i])
ax.set_title(predicted[i],color='black' if predicted[i]==labels[i] else 'red')
ax.axis('off')
plt.tight_layout()
plt.show()
# loader.shape=1875*[32*1*28*28,32]
for batch in train_loader:
break
visualize_loader(batch)
在PyTorch的torch.nn模块中,卷积函数Conv2d的输入张量的形状应为[batch_size, channels, height, width]对应数据集,无需修改(在一些架构中,可能是[batch_size, height, width, channels])。
# 创建模型
import torch
import torch.nn as nn
import torch.optim as optim
# 定义模型
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=5, stride=1)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1)
self.flatten=nn.Flatten()
self.fc3 = nn.Linear(256, 120)
self.fc4 = nn.Linear(120, 84)
self.fc5 = nn.Linear(84, 10)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.conv2(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.flatten(x)
x = self.fc3(x)
x = self.relu(x)
x = self.fc4(x)
x = self.relu(x)
x = self.fc5(x)
return x
打印模型结构
model = CNN()
print(model)
CNN(
(conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
(relu): ReLU()
(maxpool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(flatten): Flatten(start_dim=1, end_dim=-1)
(fc3): Linear(in_features=256, out_features=120, bias=True)
(fc4): Linear(in_features=120, out_features=84, bias=True)
(fc5): Linear(in_features=84, out_features=10, bias=True)
)
import torch.optim as optim
num_epochs=1
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
correct = 0
total = 0
for images, labels in train_loader:
images = images.to(device)
labels = labels.to(device)
# 前向传播
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 统计准确率
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
running_loss += loss.item()
train_loss = running_loss / len(train_loader)
train_accuracy = correct / total
# 在测试集上评估模型
model.eval()
test_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
test_loss += loss.item()
test_loss = test_loss / len(test_loader)
test_accuracy = correct / total
# 打印训练过程中的损失和准确率
print(f"Epoch [{epoch+1}/{num_epochs}] - Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}")
Epoch [1/1] - Train Loss: 0.0154, Train Accuracy: 0.9951, Test Loss: 0.0109, Test Accuracy: 0.9964
#保存模型
#torch.save(model.state_dict(), '05model.pth')
# 创建一个新的模型实例
model = CNN()
# 加载模型的参数
model.load_state_dict(torch.load('05model.pth'))
# 测试
for batch in test_loader:
break
imgs=batch[0]
outputs = model(imgs)
_, predicted = torch.max(outputs.data, 1)
predicted=predicted.numpy()
print(predicted)
visualize_loader(batch,predicted)
上图中可视化了其中的32次预测,只有第三行第四列的“8”被预测为“5”,其余均是正确。
在测试集的总体预测准确度为99.64%,正确率挺高的。