全连接神经网络 -2

搭建网络并可视化
在数据准备、探索和可视化分析后,下面搭建需要使用的全连接神经网络分类器。网络的每个全连接隐藏层由nn.Linear()函数和nn.ReLU()函数构成,其中nn.ReLU()表示使用激活函数ReLU。构建全连接层分类网络的程序如下所示:

## 全连接网络
class MLPclassifica(nn.Module):
	def __init__(self):
		super(MLPclassifica,self).__init__()
		## 定义第一个隐藏层
		self.hidden1 = nn.Sequential(
			nn.Linear(in_features = 57, ## 第一个隐藏层的输入,数据的特征数
					  out_features = 30, ## 第一个隐藏层的输出,神经元的数量
					  bias=True ## 默认会有偏执),
			nn.ReLU()
		)
		## 定义第二个隐藏层
		self.hidden2 = nn.Sequential(
			nn.Linear(30,10),
			nn.ReLU()
		)
		## 分类层
		self.classifica = nn.Sequential(
			nn.Linear(10,2),
			nn.Sigmoid()
		)
	## 定义网络的前向传播路径
	def forward(self,x):
		fc1 = self.hidden1(x)
		fc2 = self.hidden2(fc1)
		output = self.classifica(fc2)
		## 输出为两个隐藏层和输出层
		return fc1, fc2, output

上面的程序定义了一个MLPclassifica函数类,其网络结构中含有hidden1和hidden2两个隐藏层,分别包含30和10个神经元以及1个分类层classifica,并且分类层使用Sigmoid函数作为激活函数。由于数据有57个特征,所以第一个隐藏层的输入特征为57,而且该数据为二分类问题,所以分类层有2个神经元。在定义完网络结构后,需要定义网络的正向传播过程,分别输出了网络的两个隐藏层fc1、fc2以及分类层的输出output。
针对定义好的MLPclassifica()函数类,使用mlpc = MLPclassifica()得到的全连接网络mlpc,并利用torchviz库中的make_dot函数,将网络结构进行可视化,程序如下所示:

## 输出网络结构
mlpc = MLPclassifica()
## 使用 make_dot 可视化网络
x = torch。randn(1,57).requires_grad_(True)
y = mlpc(x)
Mymlpcvis = make_dot(y, params=dict(list(mlpc.named_parameters()))+[('x',x)])
Mymlpcvis

得到的网络结构传播过程的可视化结构展示了MLP网络的每个层需要训练参数的情况。


使用未预处理的数据训练模型
在网络搭建完毕后,首先使用未标准化的训练数据训练模型,然后利用未标准化的测试数据验证模型的泛化能力,分析网络在未标准化的数据集中是否也能很好地拟合数据。首先将未标准化的数据转化为张量,并且将张量处理为数据加载器,可使用如下所示的程序:

## 将数据转化为张量
X_train_nots = torch.from_numpy(X_train.astype(np.float32))
y_train_t = torch.from_numpy(y_train.astype(np.int64))
X_test_nots = torch.from_numpy(X_test.astype(np.float32))
y_test_t = torch.from_numpy(y_test.astype(np.int64))
## 将训练集转化为张量后,使用 TensorDataset 将 X 和 Y 整理到一起
train_data_nots = Data.TensorDataset(X_train_nots,y_train_t)
## 定义一个数据加载器,将训练数据集进行批量处理
train_nots_loader = Data.DataLoader(
	dataset = train_data_nots, ## 使用的数据集
	batch_size = 64, ## 批处理样本大小
	shuffle = True, ## 每次迭代前打乱数据
	num_workers = 1,
)

在上面的程序中,为了模型正常的训练,需要将数据集X转化为32位浮点型的张量,以及将Y转化为64位整型的张量,将数据设置位加载器,将Data.TensorDataset()函数和Data.DataLoader()结合在一起使用。在上述数据加载器中每个batch包含64个样本。
数据准备完毕后,需要使用训练集对全连接神经网络mlpc进行训练和测试。在优化模型时,优化函数使用torch.optim.Adam(),损失函数使用交叉熵损失函数nn.CrossEntropyLoss()。为了观察网络在训练过程中损失的变化情况以及在测试集上预测精度的变化,可以使用HiddenLayer库,将相应数值的变化进行可视化。模型的训练和相关可视化程序如下所示。

## 定义优化器
optimizer = torch.optim.Adam(mlpc.parameters(),lr=0.01)
loss_func = nn.CrossEntropyLoss()	## 二分类损失函数
## 记录训练过程的指标
history1 = h1.History()
## 使用 Canvas 进行可视化
canvas1 = h1.Canvas()
print_step = 25
## 对模型进行迭代训练,对所有的数据训练 epoch 轮
for epoch in range(15):
	## 对训练数据的加载器进行迭代计算
	for step, (b_x,b_y) in enumerate(train_nots_loader):
		## 计算每个 batch 的损失
		_,_,output = mplc(b_x)					## MLP 在训练 batch 上的输出
		train_loss = loss_func(output, b_y)		## 二分类交叉熵损失函数
		optimizer.zero_grad()					## 每个迭代步的梯度初始化为 0
		train_loss.backward()					## 损失的后向传播,计算梯度
		optimizer.step()						## 使用梯度进行优化
		niter = epoch*len(train_loader)+step+1
		## 计算每经过print_step次迭代后的输出
		if niter % print_step = 0:
			_,_,output = mlpc(X_test_nots)
			_,pre_lab = torch.max(output,1)
			test_accuracy = accuracy_score(y_test_t,pre_lab)
			## 为history添加epoch,损失和精度
			history1.log(niter, train_loss=train_loss,test_accuracy=test_accuracy)
			## 使用两个图像可视化损失函数和精度
			with canvas1:
				canvas1.draw_plot(history1["train_loss"])
				canvas1.draw_plot(history1["test_accuracy"])

上面的程序对训练数据集进行了5个epoch的训练,在网络训练过程中,每经过25次迭代就对测试集进行一次预测,并且将迭代次数、训练集上损失函数的取值、模型在测试集上的识别精度都使用history1.log()函数进行保存,在使用canvas1,draw_plot()函数将损失函数大小、预测精度实时可视化出来,得到的模型训练过程可以看出,损失函数一直在波动,并没有收敛到一个平稳的数值区间,在测试集上的精度也具有较大的波动范围,而且最大精度低于72%。说明使用未标准化的数据集训练的模型并没有训练效果,即MLP分类器没有收敛。
导致这样的原因可能较多,例如:

  1. 数据没有经过标准化处理,所以网络没有收敛。
  2. 使用的训练数据样本太少,导致网络没有收敛。
  3. 搭建的MLP网络使用的神经元太多或者太少,所以网络没有收敛。

使用预处理后的数据训练模型
MLP分类器没有收敛的原因可以有多个,但是最可能的原因是数据没有进行标准化预处理。为了验证猜想的正确性,使用标准化数据集重新对上面的MLP网络进行训练,探索是否会得到收敛的模型。首先对标准化后的数据进行预处理,得到数据加载器。

## 将数据转化为张量
X_train_t = torch.from_numpy(X_train_s.astype(np.float32))
y_train_t = torch.from_numpy(y_train.astype(np.int64))
X_test_t = torch.from_numpy(X_test_s.astype(np.float32))
y_test_t = torch.from_numpy(y_test.astype(np.int64))
## 将训练集转化为张量后,使用 TensorDataset 将 X 和 Y 整理到一起
train_data = Data.TensorDataset(X_train_t, y_train_t)
## 定义一个数据加载其,将训练数据集进行批量处理
train_loader = Data.DataLoader(
	dataset = train_data,	## 使用的数据集
	batch_size = 64,		## 批处理样本大小
	shuffle = True,			## 每次迭代前打乱数据
	num_workers = 1,
)

在训练数据和测试数据准备好后,使用与之前相似的程序,训练全连接神经网络分类器,程序如下:

## 定义优化器
optimizer = torch.optim.Adam(mlpc.parameters(),lr=0.01)
loss_func = nn.CrossEntropyLoss()		## 二分类损失函数
## 记录训练过程的指标
history1 = h1.History()
## 使用 Canvas 进行可视化
canvas1 = h1.Canvas()
print_step = 25
## 对模型进行迭代训练,对所有的数据训练 epoch 轮
for epoch in range(15):
	## 对训练数据的加载器进行迭代计算
	for step, (b_x,b_y) in enumerate(train_loader):
		##计算每个 batch 的损失
		_,_,output = mlpc(b_x)		## MLP在训练batch上的输出
		train_loss = loss_func(output, b_y)		## 二分类交叉熵损失函数
		optimizer.zero_grad()		## 每个迭代步的梯度初始化为0
		train_loss.backward()		## 损失的后向传播,计算梯度
		optimizer.step()			## 使用梯度进行优化
		niter = epoch*len(train_loader)+step+1
		##计算每经过print_step次迭代后的输出
		if niter % print_step=0:
			_,_,output=mlpc(X_test_t)
			_,pre_lab=torch.max(output,1)
			test_accuracy=accuracy_score(y_test_t,pre_lab)
			## 为history添加epoch,损失和精度
			history1.log(niter, train_loss=train_loss,
						 test_accuarcy=test_accuracy)
			## 使用两个图像可视化损失函数和精度
			with canvas1 :
				canvas1.draw_plot(history1["train_loss"])
				canvas1.draw_plot(history1["test_accuracy"])

在上面的程序中,利用了标准化处理后的数据集对网络进行训练,并且在网络训练过程中,每经过25次迭代就对标准化的测试集进行一次预测。同样将迭代次数、训练集上的损失函数取值、模型在测试集上的识别精度都是用history1.log()函数进行保存,并且使用canvas1.draw_plot()函数将损失函数大小、预测精度实时可视化出来,得到模型训练过程。
从图中得到了标准化数据训练的分类器,并且损失函数最终收敛到一个平稳的数值区间,在测试集上的精度也得到了收敛,预测精度稳定在90%以上。说明模型在使用标准化数据后得到有效的训练。即数据标准化预处理对MLP网络非常重要。
在获得收敛的模型后,可以在测试集上计算模型的垃圾邮件识别最终精度,程序代码如下所示:

## 计算模型在测试集上的最终精度
_,_,output = mlpc(X_test_t)
_,pre_lab = torch.max(output,1)
test_accuracy = accuracy_score(y_test_t,pre_lab)
print("test_accuracy:",test_accuracy)

在上述模型中首先使用了mlpc()对测试集进行预测,得到每个测试集的输出,然后使用torch.max()计算每个样本预测得到的类别,接着使用accuracy_score()函数计算模型的识别精度。从输出结果中可以发现,训练好的全连接神经网络在测试集上的识别精度为93.56%。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值