卷积神经网络模型
卷积神经网络(简称 CNN)是一种专为图像输入而设计的网络。它最明显的特征就是具有三个层次,卷积层,池化层,全连接层。
借用一张图,下图很好的表示了什么是卷积(提取特征),什么是池化(减少数据量),而全连接层就是一个简单普通的神经网络。
如下代码,该代码定义了一个卷积神经网络。其中仅有一个简单的函数前向传播forward函数
,这个函数的功能其实就是输入数据,给出预测,并不复杂。
from numpy import argmax, vstack
from sklearn.metrics import accuracy_score
from torch.nn import Module, Conv2d, ReLU, MaxPool2d, Linear, CrossEntropyLoss, Softmax
from torch.nn.init import kaiming_uniform_, xavier_uniform_
from torch.optim import SGD
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import Compose, ToTensor, Normalize
# 定义模型
class CNN(Module):
def __init__(self, n_channels):
# 模型属性
super(CNN, self).__init__()
# 隐藏层1。采用了Conv2d函数,n_channels输入数据的通道(彩色RGB图像为3),out_channels即输出的通道数量,kernel_size卷积核的大小
self.hidden1 = Conv2d(n_channels, 32, kernel_size=(3, 3))
kaiming_uniform_(self.hidden1.weight, nonlinearity='relu') # 初始化权重
self.act1 = ReLU() # 激活函数
# 池化层1。二维最大池化(Max Pooling)层,kernel_size池化窗口的大小,stride池化窗口的滑动步长
self.pool1 = MaxPool2d((2, 2), stride=(2, 2))
# 隐藏层2
self.hidden2 = Conv2d(32, 32, kernel_size=(3, 3))
kaiming_uniform_(self.hidden2.weight, nonlinearity='relu')
self.act2 = ReLU()
# 池化层2
self.pool2 = MaxPool2d((2, 2), stride=(2, 2))
# 全连接层
self.hidden3 = Linear(5 * 5 * 32, 100)
kaiming_uniform_(self.hidden3.weight, nonlinearity='relu')
self.act3 = ReLU()
# 输出层
self.hidden4 = Linear(100, 10)
xavier_uniform_(self.hidden4.weight)
self.act4 = Softmax(dim=1)
# 前向传播
def forward(self, X):
# 输入到隐藏层1
X = self.hidden1(X)
X = self.act1(X)
X = self.pool1(X)
# 输入到隐藏层2
X = self.hidden2(X)
X = self.act2(X)
X = self.pool2(X)
# 扁平化
X = X.view(-1, 4 * 4 * 50)
# 输入到隐藏层3
X = self.hidden3(X)
X = self.act3(X)
# 输入到输出层
X = self.hidden4(X)
X = self.act4(X)
return X
然后准备数据,开始划分训练集和测试集
# 准备数据集
def prepare_data(path):
# 定义标准化
trans = Compose([ToTensor(), Normalize((0.1307,), (0.3081,))])
# 加载数据集
train = MNIST(path, train=True, download=True, transform=trans)
test = MNIST(path, train=False, download=True, transform=trans)
# 创建 DataLoader
train_dl = DataLoader(train, batch_size=64, shuffle=True)
test_dl = DataLoader(test, batch_size=1024, shuffle=False)
return train_dl, test_dl
所准备是数据如下图,是一种手写数字,通过识别图片分析来得到答案
然后我们就要看是训练模型了
# 训练模型
def train_model(train_dl, model):
criterion = CrossEntropyLoss() # 损失函数
# 定义优化器,SGD(随机梯度下降),lr学习率,momentum动量,用于加速 SGD 在相关方向上的收敛,并抑制震荡
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
# 枚举 epochs
for epoch in range(10):
# 枚举 mini batches
for i, (inputs, tragets) in enumerate(train_dl):
# 梯度清零
optimizer.zero_grad()
# 计算模型输出
yhat = model(inputs)
# 计算损失
loss = criterion(yhat, tragets)
# 反向传播,通过pytorch的自动求导系统(Autograd)间接地影响模型的参数
loss.backward()
# 升级模型权重,然后优化器根据反向传播所存储的数据来优化
optimizer.step()
训练完模型,还要评估一下模型的准确率
# 评估模型
def evaluate_model(test_dl, model):
predictions, actuals = list(), list()
for i, (inputs, tragets) in enumerate(test_dl):
# 在测试集上评估模型
yhat = model(inputs)
# 转化为 numpy 数据类型
yhat = yhat.detach().numpy()
actual = tragets.numpy()
# 转化为类标签
yhat = argmax(yhat, axis=1)
# 为 stack 格式化数据集
actual = actual.reshape(len(actual), 1)
yhat = yhat.reshape(len(yhat), 1)
# 保存
predictions.append(yhat)
actuals.append(actual)
predictions, actuals = vstack(predictions), vstack(actuals)
# 计算准确度
acc = accuracy_score(actuals, predictions)
return acc
最后我们利用如下代码开始运行
# 准备数据
path = './'
train_dl, test_dl = prepare_data(path)
print(len(train_dl.dataset), len(test_dl.dataset))
# 定义网络
model = CNN(1)
train_model(train_dl, model)
acc = evaluate_model(test_dl, model)
print('Accuracy: %.3f' % acc)
多层感知机模型
from numpy import vstack, argmax
from pandas import read_csv
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import LabelEncoder
from torch import Tensor
from torch.nn import Module, Linear, ReLU, Softmax, CrossEntropyLoss
from torch.nn.init import kaiming_uniform_, xavier_uniform_
from torch.optim import SGD
from torch.utils.data import Dataset, random_split, DataLoader
# 数据集定义
class CSVDataset(Dataset):
# 导入数据集
def __init__(self, path):
# 导入数据集
df = read_csv(path, header=None)
# 设置神经网络的输入与输出
self.X = df.values[:, :-1]
self.y = df.values[:, -1]
# 确保输入数据是浮点数
self.X = self.X.astype('float32')
# 使用浮点型标签编码原输出
self.y = LabelEncoder().fit_transform(self.y)
# 定义获取数据集长度的方法
def __len__(self):
return len(self.X)
# 定义获取某一行数据的方法
def __getitem__(self, idx):
return [self.X[idx], self.y[idx]]
# 在类内部定义划分训练集和测试集的方法
def get_splits(self, n_test = 0.33):
# 确定训练集和测试集的尺寸
test_size = round(len(self.X) * n_test)
train_size = len(self.X) - test_size
# 根据尺寸划分训练集和测试集并返回
return random_split(self, [train_size, test_size])
# 模型定义
class MLP(Module):
# 定义模型属性
def __init__(self, n_inputs):
super(MLP, self).__init__()
# 隐藏层1(输入)
self.hidden1 = Linear(n_inputs, 10)
kaiming_uniform_(self.hidden1.weight, nonlinearity='relu')
self.act1 = ReLU()
# 隐藏层2
self.hidden2 = Linear(10, 8)
kaiming_uniform_(self.hidden2.weight, nonlinearity='relu')
self.act2 = ReLU()
# 隐藏层3(输出)
self.hidden3 = Linear(8, 3)
xavier_uniform_(self.hidden3.weight)
self.act3 = Softmax(dim=1)
# 前向传播
def forward(self, X):
# 输入
X = self.hidden1(X)
X = self.act1(X)
# 隐藏层2
X = self.hidden2(X)
X = self.act2(X)
# 输出
X = self.hidden3(X)
X = self.act3(X)
return X
# 准备数据集
def prepare_data(path):
# 导入数据集
dataset = CSVDataset(path)
train, test = dataset.get_splits()
train_dl = DataLoader(train, batch_size=32, shuffle=True)
test_dl = DataLoader(test, batch_size=1024, shuffle=False)
return train_dl, test_dl
# 训练模型
def train_model(train_dl, model):
# 定义优化器
criterion = CrossEntropyLoss()
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
# 枚举 epochs
for epoch in range(500):
# 枚举 mini batches
for i, (inputs, targets) in enumerate(train_dl):
# 梯度清除
optimizer.zero_grad()
# 计算模型输出
yhat = model(inputs)
# 计算损失
loss = criterion(yhat, targets)
# 反向传播
loss.backward()
# 更新
optimizer.step()
def evaluate_model(test_dl, model):
predictions, actuals = list(), list()
for i, (inputs, targets) in enumerate(test_dl):
# 在测试集上评估模型
yhat = model(inputs)
# 转化为 numpy 数据类型
yhat = yhat.detach().numpy()
actual = targets.numpy()
# 转化为类标签
yhat = argmax(yhat, axis=1)
# 为 stacking reshape 矩阵
actual = actual.reshape((len(actual), 1))
yhat = yhat.reshape((len(yhat), 1))
# 保存
predictions.append(yhat)
actuals.append(actual)
predictions, actuals = vstack(predictions), vstack(actuals)
# 计算准确度
acc = accuracy_score(actuals, predictions)
return acc
# 对一行数据进行类预测
def predict(row, model):
# 转换源数据
row = Tensor([row])
# 做出预测
yhat = model(row)
# 转化为 numpy 数据类型
yhat = yhat.detach().numpy()
return yhat
# 准备数据
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv'
train_dl, test_dl = prepare_data(path)
print(len(train_dl), len(test_dl))
# 定义网络
model = MLP(4)
# 训练模型
train_model(train_dl, model)
# 评估模型
acc = evaluate_model(test_dl, model)
print('Accuracy: %.3f' % acc)
# 进行单个预测
row = [5.1,3.5,1.4,0.2]
yhat = predict(row, model)
print('Predicted: %s (class=%d)' % (yhat, argmax(yhat)))
这个就比较简单了,最简单的感知机(最简单的两层神经网络),这里只不过是多层的感知机。它的思想还是比较好理解的,主要是如何针对不同的应用来实现它