DNN是深度神经网络框架,可以进行分类的工作。今天我们用DNN简单写一个区分正负数的模型,了解DNN的读取训练集数据和训练的流程。
一、构建网络
首先我们先写一下,DNN的网络框架
class DNN(nn.Module):
def __init__(self):
super(DNN, self).__init__() #继承父类方法
self.fc1 = nn.Linear(1,8) # 输入层 -》 隐藏层
self.relu = nn.ReLU() # 激活函数
self.fc2 = nn.Linear(8,2) # 隐藏层 -》 输出层
#正向传播函数
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
在这里我们简单构建了一个DNN网络的框架。
其中输入层节点数为1,隐藏层节点数为8,输出层节点数为2
输入层用来输入数据,我们判断一个数的正负,只要输入一个数即可。
隐藏层用来进行运算,我们设置节点为8
输出层用来进行输出,我们想生成正数的概率和负数的概率,一共两个值,所以我们设置节点数为2
其中我们在中间加入了激活函数,激活函数可以使模型更加容易收敛,可以更加快速的达到训练模型的效果
forward()函数属于前向传播函数,前向传播就是数据经过输入层、隐藏层、输出层的计算后,输出的结果。
我们可以简单测试一下,我们的模型是否构建成功。
import torch
import torch.nn as nn
class DNN(nn.Module):
def __init__(self):
super(DNN, self).__init__() #继承父类方法
self.fc1 = nn.Linear(1,8) # 输入层 -》 隐藏层
self.relu = nn.ReLU() # 激活函数
self.fc2 = nn.Linear(8,2) # 隐藏层 -》 输出层
#正向传播函数
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
#实例化模型
net = DNN()
#测试数据
test_data = [0.2]
#list转tensor
test_data = torch.tensor(test_data, dtype=torch.float32)
result = net(test_data)
print(result)
#输出 tensor([-0.0007, 0.2415], grad_fn=<AddBackward0>)
我们的神经模型,可以进行输出,而且正确输出两个节点,表示正数和负数的概率,虽然答案不对,但是表示神经网络构建成功。
在这里注意,神经网络框架不能直接放入listl列表进行运算,必须将列表转换成tensor格式才能进行运算。
二、设置数据集
我们知道神经网络是通过训练集,将训练数据提取特征和其标签进行比对进行训练的。我们希望进行训练后,训练数据进过模型计算后,能够更加接近于标签数据。这就需要们准备数据集。
我们可以简单写一点数据集的例子
train_data = [[0.1], [0.5], [-0.2], [0.8], [-0.1]] #训练数据
train_labels = [[1,0], [1,0], [0,1], [1,0], [0,1]] #训练标签
可以看到我们定义了五个训练数据,其中0.1为训练数据,对应的标签是[1,0],表示为正数的概率为1,为负数的概率为0
#列表转tensor
train_data = torch.tensor(train_data, dtype=torch.float32)
train_labels = torch.tensor(train_labels, dtype=torch.float32)
最后别忘了转换为tensor格式
三、模型训练
进行模型训练,我们需要定义损失函数、梯度优化函数
#网络实例化
net = DNN()
#切换成训练模式
net.train()
# 定义损失函数和优化器
criterion = nn.MSELoss() # 计算损失值函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.01) # 使用随机梯度下降优化器
# 训练网络
num_epochs = 1000 # 训练的轮数
for epoch in range(num_epochs): # 迭代每一轮
for inputs, labels in zip(train_data, train_labels): # 遍历每一个训练样本和其标签
optimizer.zero_grad() # 清空梯度缓存
outputs = net(inputs) # 前向传播,计算预测值
loss = criterion(outputs, labels) # 计算预测值和期望值之间的差,以这个值作为参考,反向传播,训练模型
loss.backward() # 反向传播,计算梯度值
optimizer.step() # 更新权重,进行一次参数更新
# 每轮结束后打印损失值
print(f"Epoch {epoch+1}, Loss: {loss.item()}")
这里我们将训练数据和标签数据以此取出,首先把训练数据放到神经网络中进行计算,会得到一个预测值,但预测值和我们预想的结果有差。这时我们取出标签数据,将预测值和标签数据求差,计算损失值,通过损失值,反向传播,更新模型参数,进行模型训练。
如果没有错误可以看到loss值正在下降
Epoch 1, Loss: 0.7478383183479309
Epoch 2, Loss: 0.683431088924408
Epoch 3, Loss: 0.629726231098175
Epoch 4, Loss: 0.5848070383071899
Epoch 5, Loss: 0.5464605093002319
Epoch 6, Loss: 0.5142878890037537
Epoch 7, Loss: 0.48720893263816833
Epoch 8, Loss: 0.46432948112487793
Epoch 9, Loss: 0.4449082314968109
Epoch 10, Loss: 0.4283304214477539
Epoch 11, Loss: 0.4140870273113251
Epoch 12, Loss: 0.4017573595046997
Epoch 13, Loss: 0.3909949064254761
Epoch 14, Loss: 0.38151484727859497
Epoch 15, Loss: 0.37308403849601746
Epoch 16, Loss: 0.365511953830719
Epoch 17, Loss: 0.35864341259002686
Epoch 18, Loss: 0.3523522615432739
Epoch 19, Loss: 0.3465362787246704
Epoch 20, Loss: 0.34111258387565613
Epoch 21, Loss: 0.3360139727592468
Epoch 22, Loss: 0.3311862051486969
Epoch 23, Loss: 0.32658541202545166
Epoch 24, Loss: 0.32217592000961304
Epoch 25, Loss: 0.3179289698600769
Epoch 26, Loss: 0.3138209581375122
Epoch 27, Loss: 0.30983278155326843
Epoch 28, Loss: 0.30594879388809204
Epoch 29, Loss: 0.30215632915496826
Epoch 30, Loss: 0.2984447181224823
也就是说明预测结果更加接近期望结果
四、模型应用
训练好了模型,可以测试模型是否能预测结果。
#切换eval模式
net.eval()
test_data = [0.6]
#转tensor
test_data = torch.tensor(test_data, dtype=torch.float32)
result = net(test_data)
print(result)
#tensor([0.9525, 0.0463], grad_fn=<AddBackward0>)
print(int(result.argmax()))
# 0
我们直接将数据丢进eval,可以得到正数的负数的概率
可见0.6 正数的概率为0.95,这是我们使用argmax函数,可以获取最大元素的下标,也就是0,也就说神经网络的预测结果是正数,和我们的预测相符,表明神经网络训练效果不错。
接下来是完整代码
import torch
import torch.nn as nn
class DNN(nn.Module):
def __init__(self):
super(DNN, self).__init__() #继承父类方法
self.fc1 = nn.Linear(1,8) # 输入层 -》 隐藏层
self.relu = nn.ReLU() # 激活函数
self.fc2 = nn.Linear(8,2) # 隐藏层 -》 输出层
#正向传播函数
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# 训练数据和标签
train_data = [[0.1], [0.5], [-0.2], [0.8], [-0.1]] # 5个训练样本,每个样本有1个特征
train_labels = [[1,0], [1,0], [0,1], [1,0], [0,1]]
#列表转tensor
train_data = torch.tensor(train_data, dtype=torch.float32) # 去掉内部的列表括号
train_labels = torch.tensor(train_labels, dtype=torch.float32)
#网络实例化
net = DNN()
#切换成训练模式
net.train()
# 定义损失函数和优化器
criterion = nn.MSELoss() # 计算损失值函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.01) # 使用随机梯度下降优化器
# 训练网络
num_epochs = 100 # 训练的轮数
for epoch in range(num_epochs): # 迭代每一轮
for inputs, labels in zip(train_data, train_labels): # 遍历每一个训练样本和其标签
optimizer.zero_grad() # 清空梯度缓存
outputs = net(inputs) # 前向传播,计算预测值
loss = criterion(outputs, labels) # 计算预测值和期望值之间的差,以这个值作为参考,反向传播,训练模型
loss.backward() # 反向传播,计算梯度值
optimizer.step() # 更新权重,进行一次参数更新
# 每轮结束后打印损失值
print(f"Epoch {epoch+1}, Loss: {loss.item()}")
net.eval()
test_data = [0.6]
test_data = torch.tensor(test_data, dtype=torch.float32)
result = net(test_data)
print(result)
print(int(result.argmax()))