contents

  • 前馈神经网络(part 3)
    • 写在开头
    • 鸢尾花数据集介绍
      • Iris数据集背景和内容
      • Iris数据集数据
      • Iris数据集使用
        • PCA降维呈现数据
        • 选取前两个特征绘制
    • 实践:基于前馈神经网络完成鸢尾花分类
      • 数据处理
      • 针对大量的数据:小批量梯度下降
      • 模型构建、损失函数、优化器和评价指标
      • Runner类构建
      • 模型训练
      • 模型评价
      • 模型预测
    • 一些小问题
      • 对比Softmax分类和前馈神经网络分类
      • 使用mnist进行FNN实验
    • 写在最后

前馈神经网络(part 3)

写在开头

经过前面的学习,相信大家已经对于前馈神经网络的原理、过程、实现和评估等非常熟悉了,本次我们将使用现实中的一个非常著名的数据集来进行前馈神经网络的应用实验,更加深刻地感受神经网络强大的能力。

鸢尾花数据集介绍

Iris数据集背景和内容

鸢尾花数据集可以说是分类界最为著名的数据集之一了。鸢尾花数据集又称费舍尔鸢尾花数据集或安德森的鸢尾花数据集。是英国统计学家和生物学家罗纳德·费舍尔在其 1936 年的论文《在分类问题中使用多重测量作为线性判别分析的一个例子》中使用并著名的多变量 数据集。这三个物种中的两个是在加斯佩半岛采集的, “都来自同一牧场,同一天采摘,由同一个人用同一仪器同时测量”。
该数据集由来自三种鸢尾花(鸢尾花(setosa)、杂色鸢尾(versicolor)和维吉尼亚鸢尾(virginca))的 50 个样本组成。从每个样品中测量了四个特征:萼片(sepal)和花瓣(petal)的长度和宽度,以厘米为单位。基于这四个特征的结合,Fisher 开发了一个线性判别模型来区分物种。费舍尔的论文发表在《优生学年鉴》上,其中讨论了所含技术在颅相学领域的应用。

Iris数据集数据

该数据集中并不直接包含三种花的图片,而是使用前面介绍的四种测量值加上花的种类组成。下图是这三种花:

下图是这三种画的测量指标和分类数据分布:

Iris数据集使用

PCA降维呈现数据

我们当然可以从网上下载得到Iris数据集并进行读取来使用,但是有一种更方便的方法:直接从库里调(毕竟这个数据集太经典太著名了)。我们这边直接使用sklearn.datasets中的Iris数据集即可。调用和可视化的代码如下,由于直接作图没法直接画出来四维的内容,我们同样使用该库中的PCA降维方法使得数据能够呈现:

from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import matplotlib.pyplot as pltiris_raw = load_iris()
xs,ys = iris_raw.data,iris_raw.targetpca = PCA(2)
xs = pca.fit_transform(xs)
plt.scatter(xs[ys==0][:,0],xs[ys==0][:,1],c='#80e0d8',alpha=.8,label='setosa') # 50块钱的颜色
plt.scatter(xs[ys==1][:,0],xs[ys==1][:,1],c='#664f97',alpha=.8,label='versicolor') # 5块钱的颜色
plt.scatter(xs[ys==2][:,0],xs[ys==2][:,1],c='#e3c7c5',alpha=.8,label='virginica') # 5毛钱的颜色
plt.xticks([])
plt.yticks([])
plt.legend()
plt.title('Iris数据集分布')
plt.show()

效果如下:

选取前两个特征绘制

代码及效果如下:

iris_raw = load_iris()
xs,ys = iris_raw.data,iris_raw.targetplt.scatter(xs[ys==0][:,0],xs[ys==0][:,1],c='#80e0d8',alpha=.8,label='setosa') # 50块钱的颜色
plt.scatter(xs[ys==1][:,0],xs[ys==1][:,1],c='#664f97',alpha=.8,label='versicolor') # 5块钱的颜色
plt.scatter(xs[ys==2][:,0],xs[ys==2][:,1],c='#e3c7c5',alpha=.8,label='virginica') # 5毛钱的颜色
plt.xlabel('sepal length (cm)')
plt.ylabel('sepal width (cm)')
plt.legend()
plt.title('Iris数据集前两个特征分布')
plt.show()

实践:基于前馈神经网络完成鸢尾花分类

数据处理

由于本次我们将使用Softmax进行分类,因此有几个类别就会有几个输出神经元,于是原来的种类编码需要转化为独热编码(one-hot)并将输入和输出均变成tensor然后进行数据集划分等操作。torch自带转化函数如下:

数据转化和分割代码如下:

import torch
from torch.nn.functional import one_hot
xs,ys = iris_raw.data,iris_raw.target
xs, ys = torch.tensor(xs,dtype=torch.long), torch.tensor(ys,dtype=torch.long)
ys = one_hot(ys)
dataset = DatasetGenerator()
dataset.copy_from(torch.hstack([xs,ys]))
dataset.shuffle()
dataset_train, dataset_test = dataset.train_test_split()
dataset_eval,dataset_test = dataset_test[:-10],dataset_test[-10:]

针对大量的数据:小批量梯度下降

Iris数据集由于量不大,训练难度并不会太高,然而当今的很多数据集(如coco2017)都有非常大量的数据。如果还像一开始将所有数据计算后训练进行一次参数更新,计算的复杂度将会非常高。为了减少计算量、达到更加快速收敛的目的,我们可以在每次迭代时只取一部分样本进行计算,基于这一部分样本的损失进行优化,这样的优化方式称为小批量梯度下降。
那么如何在torch中实现这一功能呢?torch中内置一个名为Dataloader的数据集迭代器,通过其能够进行批量数据的构建,本题中我们取批量数为16,代码如下:

from torch.utils.data import DataLoader
dataloader_train = DataLoader(dataset_train,16)
for item in dataloader_train:print(item)

观察输出能够发现,Dataloader将原始数据集分成16个为一批的结果。
同时在使用中,我们还发现有个DataLoader2,这个还是实验性功能,不要用哦:

构建完成后我们需要在训练过程中微调训练的结构,具体的内容将在本文后面部分提及。

模型构建、损失函数、优化器和评价指标

  • 输入层神经元个数为4,输出层神经元个数为3,隐含层神经元个数为6。

由题意很容易构建得到模型结构:

模型代码显然可得:

class Model(torch.nn.Module):def __init__(self):super(Model, self).__init__()self.inp = torch.nn.Linear(4,6)self.ac1 = torch.nn.Sigmoid()self.lay = torch.nn.Linear(6,3)self.ac2 = torch.nn.Softmax(1)def forward(self, x):return self.ac2(self.lay(self.ac1(self.inp(x))))
crit = torch.nn.CrossEntropyLoss
opti = torch.optim.SGD
def acc(test_x, y, y_pred, loss): # 统一接口return (1.0 / y.shape[0]) * torch.sum(torch.argmax(y)==torch.argmax(y_pred))
runner = Runner(Model,crit,opti,lr=0.1)

Runner类构建

由于增加了minibatch,因此我们需要修改模型中对于训练部分的代码,其他部分保持不变:

    def train(self, dataset_train, split_x_y_pos, epochs, dataset_eval, epochs_display):if self.imodel is None:self.imodel = eval('self.model({})'.format(','.join(self.kwargs.get('model_init_params', []))))icriterion = self.criterion()ioptimizer = self.optimizer(self.imodel.parameters(),self.kwargs.get('lr',0.01),self.kwargs.get('momentum',0))accum_loss = []for i in range(1, epochs + 1):for item in dataset_train:train_x, train_y = item[:,:split_x_y_pos],item[:,split_x_y_pos:]out = self.imodel(train_x)loss = icriterion(out, train_y)ioptimizer.zero_grad()loss.backward()ioptimizer.step()accum_loss.append(loss.data.item())if i % epochs_display == 0:print('[{} / {}] loss = {}'.format(i,epochs,accum_loss[-1]), end = ' ')self.eval(dataset_eval,split_x_y_pos)return accum_loss

模型训练

模型训练其实没有什么不同,这边直接给出结果:

模型评价

我们使用评价测试集进行测试:

runner.eval(dataset_test,-3)

得到结果:

模型预测

由于数据过少,我们这边预测使用所有数据,并给出正确与否的可视化:

y_pred = runner.predict(dataset.collections[:,:-3])
runner.test(dataset.collections,-3,acc,'acc')y_pred = torch.argmax(y_pred,axis=1)
y = torch.argmax(dataset.collections[:,-3:],axis=1)plt.scatter(dataset.collections[torch.where(y==y_pred)[0],0],dataset.collections[torch.where(y==y_pred)[0],1],c='#1d998f',alpha=.8,label='true')
plt.scatter(dataset.collections[torch.where(y!=y_pred)[0],0],dataset.collections[torch.where(y!=y_pred)[0],1],c='#cc0000',alpha=.8,label='false')plt.xlabel('sepal length (cm)')
plt.ylabel('sepal width (cm)')
plt.legend()
plt.title('Iris数据集预测结果')
plt.show()

结果如下:

一些小问题

对比Softmax分类和前馈神经网络分类

我们通过修改模型,仅仅将最后一层的softmax改为sigmoid,其他参数均不变,得到最终的结果:

模型预测时准确率也有显著下滑:

可见显然Softmax效果更好。为什么呢?通过Softmax函数就可以将多分类的输出值转换为范围在[0, 1]和为1的概率分布,因此比简单的前馈更加准确。Softmax训练的深度特征,会把整个超空间或者超球,按照分类个数进行划分,保证类别是可分的。

使用mnist进行FNN实验

MNIST 手写数字数据库具有 60,000 个示例的训练集和 10,000 个示例的测试集。 它是 NIST 提供的更大集合的子集。 数字已经过尺寸标准化,并在固定尺寸的图像中居中。对于想要在现实世界数据上尝试学习技术和模式识别方法,同时在预处理和格式化方面花费最少的人来说,它是一个很好的数据库。 ——MNIST 官网介绍

和前面介绍的Iris数据集不同的是,这里面的手写数字都是一张张28×28的灰度图,同时每个图片都有其对应的数字编号:

尽管该数据集更适合在下一张的卷积神经网络中进行使用和实验,但是由于MNIST中图片并不是很大,所以我们同样可以尝试使用前馈神经网络,将每个像素全连接后继续进行前馈神经网络的实验。构建的模型代码及效果如下:

# 数据集创建和处理
dataset = mnist.MNIST('./mnist',download=False if os.path.exists('./mnist/MNIST') else True
)
xs = dataset.data.float().view(-1,784)
ys = one_hot(dataset.targets).float()
dataset = DatasetGenerator()
dataset.copy_from(torch.hstack([xs,ys]))
dataset.shuffle()dataset_train,dataset_test = dataset.train_test_split()
dataloader = DataLoader(dataset_train,32,True)# 模型构建
class Model(nn.Module):def __init__(self):super(Model, self).__init__()self.hidden = nn.Linear(784,1176) # 28 * 28 = 784self.activ1 = nn.Sigmoid()self.output = nn.Linear(1176,10)self.activ2 = nn.Softmax()def forward(self,x):return self.activ2(self.output(self.activ1(self.hidden(x))))# 损失函数、优化器、正确计算、runner
crit = torch.nn.CrossEntropyLoss
opti = torch.optim.SGD
def acc(test_x, y, y_pred, loss): # 统一接口return (1.0 / y.shape[0]) * torch.sum(torch.argmax(y,axis=1)==torch.argmax(y_pred,axis=1))
runner = Runner(Model,crit,opti,lr=0.1)runner.train(dataloader,-10,10,None,1)
runner.test(dataset_test,-10,acc,'acc')

由于我可怜的商务本实在是运行不动这个非常非常慢的网络,这边只训练10代并输出结果。
没想到准确率还不错,结果如下:


准确率居然有90%多!分析下来应该是由于数据集各种图片非常非常多,加上小批量梯度下降,让模型的准确度变得很高。

写在最后

已经做了好几周的前馈神经网络了,这个网络包含了很多入门的概念和以后都将会用到的很多技术(神经元、损失函数、激活函数等等)。
最后,作为总结,思维导图奉上:

[2022-10-13]神经网络与深度学习第3章-前馈神经网络(part3)相关推荐

  1. [2022-10-06]神经网络与深度学习第3章-前馈神经网络(part2)

    contents 前馈神经网络(part 2) 写在开头 自动梯度计算 torch中自动梯度的封装 简介 过程内容 对比 模型简化 直接创建 利用预定义算子重新实现前馈神经网络 使用pytorch预定 ...

  2. 神经网络与深度学习(五)前馈神经网络(2)自动梯度计算和优化问题

    注:本次使用的数据集依旧是前两章的Moon1000数据集  from nndl.dataset import make_moons [详细代码见 神经网络与深度学习(五)前馈神经网络(1)--二分类任 ...

  3. 神经网络与深度学习(五)前馈神经网络(3)鸢尾花分类

    目录 4.5实践:基于前馈神经网络完成鸢尾花分类 深入研究鸢尾花数据集 4.5.1 小批量梯度下降法 4.5.1.1 数据分组 4.5.2 数据处理 4.5.2.2 用DataLoader进行封装 4 ...

  4. [翻译] 神经网络与深度学习 第三章 提升神经网络学习的效果 - Chapter 3 Improving the way neural networks learn

    目录: 首页 译序 关于本书 关于习题和难题 第一章 利用神经网络识别手写数字 第二章 反向传播算法是如何工作的 > 第三章 提升神经网络学习的效果 第四章 可视化地证明神经网络可以计算任何函数 ...

  5. 【神经网络与深度学习】第一章 使用神经网络来识别手写数字

    人类的视觉系统,是大自然的奇迹之一. 来看看下面一串手写的数字: 大多数人可以毫不费力地认出这些数字是504192.这种轻松是欺骗性的,我们觉得很轻松的一瞬,其实背后过程非常复杂. 在我们大脑的每个半 ...

  6. 花书+吴恩达深度学习(一)前馈神经网络(多层感知机 MLP)

    目录 0. 前言 1. 每一个神经元的组成 2. 梯度下降改善线性参数 3. 非线性激活函数 4. 输出单元 4.1. 线性单元 4.2. sigmoid 单元 4.3. softmax 单元 5.  ...

  7. [翻译] 神经网络与深度学习 第六章 深度学习 - Chapter 6 Deep learning

    目录: 首页 译序 关于本书 关于习题和难题 第一章 利用神经网络识别手写数字 第二章 反向传播算法是如何工作的 第三章 提升神经网络学习的效果 第四章 可视化地证明神经网络可以计算任何函数 第五章 ...

  8. [2022-09-20]神经网络与深度学习第2章-simple classification

    contents classification 写在开头 Logistic 回归 数据集构建 DatasetGenerator类 数据生成和可视化 模型构建 损失函数 模型优化 评价指标 完善Runn ...

  9. 图像处理神经网络python_深度学习使用Python进行卷积神经网络的图像分类教程

    深度学习使用Python进行卷积神经网络的图像分类教程 好的,这次我将使用python编写如何使用卷积神经网络(CNN)进行图像分类.我希望你事先已经阅读并理解了卷积神经网络(CNN)的基本概念,这里 ...

最新文章

  1. 《深入理解计算机系统》第七章读书笔记
  2. php html自动打开新页面大小,HTML_html 用超链接打开新窗口其可控制窗口属性,1、html超链接打开的窗口大小 - phpStudy...
  3. DOS命令大全(转)
  4. 封装一个流水号ID生成器:id-spring-boot-starter
  5. 学计算机买电脑显卡1605ti够吗,铭瑄GTX1660Ti显卡值得买吗 铭瑄GTX1660Ti终结者显卡评测...
  6. 如何防止线程死锁java_Java 并发编程:如何防止在线程阻塞与唤醒时死锁
  7. c语言中变量可以用x1表示没,你必须知道的495个C语言问题 读书笔记
  8. jmeter基本教程
  9. Sprintboot 解压Zip文件,ZipEntry的zipEntry.getSize()为-1的问题
  10. java 字符长度判断_java判断中文字符串长度的简单实例
  11. VMware Ubuntu18.10与Win10共享文件夹
  12. android egl使用方法,Android EGL整理
  13. Inspector工具使用
  14. java 动态密码错误_什么是OTP:Java一次动态密码、付款码原理
  15. 数据驱动运营,为门店开拓第二增长曲线。
  16. 如何通过重写hashCode()方法将偏向锁性能提高4倍?
  17. 栈和队列、堆、堆栈的区别?
  18. Python安装Github包,离线包和在线包
  19. 职场撕逼中如何保护自己
  20. Android studio 电话号码归属地查询app简易版

热门文章

  1. ts里变量定义any报错Unexpected any. Specify a different type.
  2. earth power oracle,平行世界 | 他「抛弃」绘画从事摄影,将绘画与摄影结合在一起,创造了电影般的震撼场景,邀请我们与他一起穿越黑暗世界的旅程...
  3. Linux系统配置VLAN
  4. 数据全量、增量、比较更新
  5. IntelliJ IDEA 之 jdk Language level
  6. [Matlab] Matlab中rand,randn,rands和randi函数使用
  7. miRNA的特征、功能及识别方法等详解
  8. Linux修改root密码
  9. 如何打开Mysql数据库文件
  10. python 实现腾讯企业邮箱发送邮件