本文利用波士顿房产数据来搭建一个简单的线性神经网络,代码有详细的注释,帮助理解整个搭建流程。
代码链接:https://gitee.com/ury-u/pytorch.git
(lab_log.txt有详细介绍每个文件夹的作用)
案例演示:
import torch
# 1、解析数据
import numpy as np
import re
ff = open("housing.data").readlines()
data = []
for item in ff:
out = re.sub(r"\s{2,}"," ",item).strip() # 由于原数据间隔的空格长度不一致,因此,将多个空格都合并成一个空格,然后去掉换行符
#print(out)
data.append(out.split(" "))
data = np.array(data).astype(float) # 数据类型转换
#print(data.shape)
Y = data[:,-1] # 选取最后一列作为标签
X = data[:,0:-1] # 选取处理最后一列的所有列作为特征
# 划分数据集
X_train = X[0:496,...] # 索引从 0 到 495行
Y_train = Y[0:496,...]
X_test = X[496:,...] # 索引从496 到 最后一行
Y_test = Y[496:,...]
# 2、搭建网络——回归网络
class Net(torch.nn.Module):
def __init__(self,n_feature,n_output): # 初始化传入特征和输出
super(Net,self).__init__() # 继承父类
self.hidden = torch.nn.Linear(n_feature,100) # 加入一个隐藏层
self.predict = torch.nn.Linear(100,n_output)
def forward(self,x):
out = self.hidden(x) # 调用该隐藏层
out = torch.relu(out) # 加入非线性运算,使模型表达能力变得更强
out = self.predict(out)
return out
# 初始化该网络
net = Net(13,1) # 输入特征13个,输出标签1个
# 3、定义LOSS
loss_func = torch.nn.MSELoss() # 定义均方误差损失
# 4、定义优化器
optimizer = torch.optim.Adam(net.parameters(),lr=0.001) # 采用SGD作为优化器,传入参数和学习率
# 5、训练模型
for i in range(10000): # 假设迭代训练1000次
x_data = torch.tensor(X_train,dtype=torch.float32)
y_data = torch.tensor(Y_train,dtype=torch.float32)
pred = net.forward(x_data) # 网络的前向运算
# print(pred.shape)
# print(y_data.shape) # 可以看到pred比y_data多一个维度1,因此可以删除该维度或者在y_data上增加一个维度
pred = torch.squeeze(pred) # 删除维度为1的维度
loss = loss_func(pred,y_data) * 0.001 # 计算损失函数,如果计算结果的loss为nan,有可能是该值十分大,因此可以降低它的倍数
optimizer.zero_grad() # 首先将神经网络参数的梯度置为0
loss.backward() # 进行反向传播
optimizer.step() # 将优化好的参数对网络进行更新
print("ite:{},loss_train:{}".format(i,loss)) # 打印迭代次数和loss的变化
#print(pred[0:10])
#print(y_data[0:10])
''' 如果结果loss仍然很大,那么可以调整迭代次数、学习率、或者优化器等来优化模型,还包括添加隐藏层、动态学习率等方法 '''
# 6、测试
x_data = torch.tensor(X_test,dtype=torch.float32)
y_data = torch.tensor(Y_test,dtype=torch.float32)
pred = net.forward(x_data)
pred = torch.squeeze(pred)
loss_test = loss_func(pred,y_data) * 0.001
print("ite:{},loss_test:{}".format(i,loss_test))
''' 由于当前样本数量不多,因此训练集和测试集之间的分布有较大的差异,可能导致训练误差和测试误差相差较大 '''
# 保存模型
torch.save(net,"model/model.pkl") # 方法一:保存整个模型
#torch.load(“”) # 加载模型
#torch.save(net.state_dict(),"params.pkl") # 方法二:只保存参数
#net.load_state_dict("") # 加载模型
重新定义一个脚本,用于加载刚刚保存的模型。代码示例:
import torch
import numpy as np
import re
# 引入net类的定义
class Net(torch.nn.Module):
def __init__(self,n_feature,n_output): # 初始化传入特征和输出
super(Net,self).__init__() # 继承父类
self.hidden = torch.nn.Linear(n_feature,100) # 加入一个隐藏层
self.predict = torch.nn.Linear(100,n_output)
def forward(self,x):
out = self.hidden(x) # 调用该隐藏层
out = torch.relu(out) # 加入非线性运算,使模型表达能力变得更强
out = self.predict(out)
return out
# 解析数据
ff = open("housing.data").readlines()
data = []
for item in ff:
out = re.sub(r"\s{2,}"," ",item).strip() # 由于原数据间隔的空格长度不一致,因此,将多个空格都合并成一个空格,然后去掉换行符
data.append(out.split(" "))
data = np.array(data).astype(float) # 数据类型转换
Y = data[:,-1] # 选取最后一列作为标签
X = data[:,0:-1] # 选取处理最后一列的所有列作为特征
X_train = X[0:496,...] # 索引从 0 到 495行
Y_train = Y[0:496,...]
X_test = X[496:,...] # 索引从496 到 最后一行
Y_test = Y[496:,...]
# 加载模型
net= torch.load("model/model.pkl")
# 定义误差函数
loss_func = torch.nn.MSELoss()
# 测试
x_data = torch.tensor(X_test,dtype=torch.float32)
y_data = torch.tensor(Y_test,dtype=torch.float32)
pred = net.forward(x_data)
pred = torch.squeeze(pred)
loss_test = loss_func(pred,y_data) * 0.001
print("loss_test:{}".format(loss_test))