神经网络与深度学习day07-实践:前馈神经网络实现鸢尾花数据集分类
深入研究鸢尾花数据集
画出数据集中150个数据的前两个特征的散点分布图:
我们再画出第一个特征和第二个特征,第二个特征和第三个特征,第三个特征和第四个特征的分布:
具体代码可以通过看本节4.5.2数据处理 中存在画图代码,由于和数据集相关,放出来估计也不能直接运行出来。
4.5 实践:基于前馈神经网络完成鸢尾花分类
在本实践中,我们继续使用第三章中的鸢尾花分类任务,将Softmax分类器替换为本章介绍的前馈神经网络。
在本实验中,我们使用的损失函数为交叉熵损失;优化器为随机梯度下降法;评价指标为准确率。
4.5.1 小批量梯度下降法
在梯度下降法中,目标函数是整个训练集上的风险函数,这种方式称为批量梯度下降法(Batch Gradient Descent,BGD)。 批量梯度下降法在每次迭代时需要计算每个样本上损失函数的梯度并求和。当训练集中的样本数量 N N N很大时,空间复杂度比较高,每次迭代的计算开销也很大。
为了减少每次迭代的计算复杂度,我们可以在每次迭代时只采集一小部分样本,计算在这组样本上损失函数的梯度并更新参数,这种优化方式称为
小批量梯度下降法(Mini-Batch Gradient Descent,Mini-Batch GD)。
第 t t t次迭代时,随机选取一个包含 K K K个样本的子集 B t \mathcal{B}_t Bt,计算这个子集上每个样本损失函数的梯度并进行平均,然后再进行参数更新。
θ t + 1 ← θ t − α 1 K ∑ ( x , y ) ∈ S t ∂ L ( y , f ( x ; θ ) ) ∂ θ , \theta_{t+1} \leftarrow \theta_t - \alpha \frac{1}{K} \sum_{(\boldsymbol{x},y)\in \mathcal{S}_t} \frac{\partial \mathcal{L}\Big(y,f(\boldsymbol{x};\theta)\Big)}{\partial \theta}, θt+1←θt−αK1(x,y)∈St∑∂θ∂L(y,f(x;θ)),
其中 K K K为批量大小(Batch Size)。 K K K通常不会设置很大,一般在 1 ∼ 100 1\sim100 1∼100之间。在实际应用中为了提高计算效率,通常设置为2的幂 2 n 2^n 2n。
在实际应用中,小批量随机梯度下降法有收敛快、计算开销小的优点,因此逐渐成为大规模的机器学习中的主要优化算法。
此外,随机梯度下降相当于在批量梯度下降的梯度上引入了随机噪声。在非凸优化问题中,随机梯度下降更容易逃离局部最优点。
小批量随机梯度下降法的训练过程如下:
4.5.2 数据处理
构造IrisDataset类进行数据读取,直接上代码:
导入基本库:
import numpy as np
import torch
from torch.utils.data import Dataset,DataLoader
from sklearn import datasets
import copy
import matplotlib
import matplotlib.pyplot as plt
构造加载数据集函数:
#加载数据集
def load_data(shuffle=True):
"""
加载鸢尾花数据
输入:
- shuffle:是否打乱数据,数据类型为bool
输出:
- X:特征数据,shape=[150,4]
- y:标签数据, shape=[150,3]
"""
#加载原始数据
X = np.array(datasets.load_iris()['data'], dtype=np.float32)
y = np.array(datasets.load_iris()['target'], dtype=np.int64)
X = torch.tensor(X)
y = torch.tensor(y)
#数据归一化
X_min = torch.min(X, axis=0)
X_max = torch.max(X, axis=0)
X = (X-X_min.values) / (X_max.values-X_min.values)
#如果shuffle为True,随机打乱数据
if shuffle:
idx = torch.randperm(X.shape[0])
X_new = copy.deepcopy(X)
y_new = copy.deepcopy(y)
for i in range(X.shape[0]):
X_new[i] = X[idx[i]]
y_new[i] = y[idx[i]]
X = X_new
y = y_new
return X, y
class IrisDataset(Dataset):
def __init__(self, mode='train', num_train=120, num_dev=15):
super(IrisDataset, self).__init__()
# 调用第三章中的数据读取函数,其中不需要将标签转成one-hot类型
X, y = load_data(shuffle=True)
if mode == 'train':
self.X, self.y = X[:num_train], y[:num_train]
elif mode == 'dev':
self.X, self.y = X[num_train:num_train + num_dev], y[num_train:num_train + num_dev]
else:
self.X, self.y = X[num_train + num_dev:], y[num_train + num_dev:]
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
def __len__(self):
return len(self.y)
def get_(self):
return self.X,self.y
实例化数据并实现可视化:
torch.manual_seed(12)
train_dataset = IrisDataset(mode='train')
dev_dataset = IrisDataset(mode='dev')
test_dataset = IrisDataset(mode='test')
#训练数据可视化
X00,y00 = train_dataset.get_()
x0=X00[y00==0]
x1=X00[y00==1]
x2=X00[y00==2]
for i in [0,1,2]:
plt.scatter(x0[:,i],x0[:,i+1],c='r',marker='o',label='setosa')
plt.scatter(x1[:,i],x1[:,i+1],c='g',marker='o',label='virgincia')
plt.scatter(x2[:,i],x2