DNN的原理:神经网络通过学习大量样本的输入与输出特征之间的关系,以拟合出输入与输出之间的方程,学习完成后,只给它输入特征,它便会可以给出输出特征。神经网络可以分为这么几步:划分数据集、训练网络、测试网络、使用网络。

如下图所示:

以下所有的代码都建议在jupyter notebook中运行

一、导入必要的python软件包

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
%matplotlib inline

#展示高清图
from matplotlib_inline import backend_inline
backend_inline.set_matplotlib_formats('svg')

二、生成均匀分布的随机数:

#生成数据集
X1 = torch.rand(10000,1)
X2 = torch.rand(10000,1)
X3 = torch.rand(10000,1)
X1.shape, X2.shape, X3.shape

显示结果:

三、创建对应的输出函数特征:

Y1 = ((X1 + X2 + X3) < 1).float()
Y2 = ((1 < (X1 + X2 + X3)) & ((X1 + X2 + X3) < 2)).float()
Y3 = ((X1 + X2 + X3) > 2).float()
Y1.shape, Y2.shape, Y3.shape
Data = torch.cat([X1,X2,X3,Y1,Y2,Y3], axis = 1) #整合数据集
Data = Data.to('cuda:0') #导入到GPU进行运算
Data.shape

输出结果:

四、划分训练集和测试集

#划分训练集与测试集
train_size = int(len(Data) * 0.7) #将训练集划分为7成
test_size = len(Data) - train_size #测试集的数量
Data = Data[torch.randperm(Data.size(0)), : ] #打乱数据集
train_Data = Data[:train_size,:]
test_Data = Data[train_size:,:]
train_Data.shape,test_Data.shape

输出结果:

五、搭建神经网络

搭建神经网络时, 以 nn.Module 作为父类, 我们自己的神经网络可直接继承父类的方法与属性, nn.Module 中包含网络各个层的定义。
 

class DNN(nn.Module):
    def __init__(self):
        super(DNN,self).__init__()
        self.net = nn.Sequential( #按顺序搭建各层
            nn.Linear(3,5), nn.ReLU(), #第一层,全连接层
            nn.Linear(5,5), nn.ReLU(), #第二层,全连接层
            nn.Linear(5,5), nn.ReLU(), #第三层,全连接层
            nn.Linear(5,3)             #第四层,全连接层
        )
    def forward(self,x):
        #前向传播
        y = self.net(x) #x是输入数据
        return y        #y是输出数据
model = DNN().to('cuda:0') #把DNN搬到GPU上运行
model

输出结果:

bias为函数的偏置

现在可以打印出前向传播执行时的内部参数:
 

for name, param in model.named_parameters():
    print(f"参数:{name}\n形状:{param.shape}\n数值:{param}\n")

输出结果(部分截图):

六、设置网络的外部参数

#损失函数的选择
loss_fn = nn.MSELoss()
#优化算法的选择
learning_rate = 0.01 #设置学习率
optimizer = torch.optim.SGD(model.parameters(),lr = learning_rate)

七、开始训练该网络

#训练网络
epochs = 1000
losses = [] #记录损失函数变化的列表

#给训练集划分输入与输出
X = train_Data[:, :3] #前三列为输入特征
Y = train_Data[:,-3:] #后三列为输出特征

for epoch in range(epochs):
    Pred = model(X)             #一次前向传播(批量)
    loss = loss_fn(Pred,Y)      #计算损失函数
    losses.append(loss.item())  #记录损失函数的变化
    optimizer.zero_grad()       #清理上一轮滞留的梯度
    loss.backward()             #一次反向传播
    optimizer.step()            #优化内部参数

#绘图
Fig = plt.figure()
plt.plot(range(epochs),losses)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()

输出结果:

八、测试网络

#测试网络

#给测试集划分输入和输出
X = test_Data[:, :3]         #前三列为输入特征
Y = test_Data[:, -3:]        #后三列为输出特征

with torch.no_grad():        #该局部关闭梯度计算功能
    Pred = model(X)          #一次前向传播(批量)
    Pred[:,torch.argmax(Pred,axis=1)] = 1
    Pred[Pred!=1] = 0
    correct = torch.sum((Pred == Y).all(1))  #预测正确的样本
    total = Y.size(0)                        #全部的样本数量
    print(f'测试集精准度:{100 * correct/total} %')

输出结果:(该测试集精准度)

九、保存网络

torch.save(model,'model.pth')

输出结果:

重新导入该模型:

new_model = torch.load('model.pth')

十、重新测试该网络

#给测试集划分输入和输出
X = test_Data[:,:3]
Y = test_Data[:,-3:]

with torch.no_grad():
    Pred = new_model(X)
    Pred[:,torch.argmax(Pred,axis = 1)] = 1
    Pred[Pred != 1] = 0
    correct = torch.sum((Pred == Y).all(1))
    total = Y.size(0)
    print(f'测试集精准度:{100 * correct/total} %')

可以检测出该精准度与保存前的精准度相同

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐