- 一、案例描述
- 二、代码详解
- 2.1 根据直线方程构造数据集
- 2.2 构建数据迭代器
- 2.3 定义模型
- 2.4 模型评价指标函数
- 2.5 编译和训练
- 2.6 输出结果可视化
- 2.7 模型评估
- 三、完整代码
上一篇文章【PyTorch实战案例(一)——利用PyTorch实现线性回归算法(基础)】,介绍了PyTorch实现线性回归的基础算法,使用预定义好的层构建了一个单层神经网络,本文将介绍利用PyTorch实现线性回归的进阶算法,通过构建LinearRegression类实现线性回归。
案例为:利用PyTorch设计神经网络拟合直线y=Wx+b,其中W=[2,-3.4]T , b=4.2。 该案例有两个特征,分别是W的两个维度,有一个标签,为输出y。
二、代码详解 2.1 根据直线方程构造数据集定义构造数据集函数:
#根据带有噪声的线性模型构造一个人造数据集
def synthetic_data(w,b,num_examples):
'''生成y=wx+b+e(噪声)'''
x=torch.normal(0,1,(num_examples,len(w))) # 形状:num_examples*len(w)
y=torch.matmul(x,w)+b # 形状:num_examples
y+=torch.normal(0,0.01,y.shape)
return x,y.reshape(-1,1) #将y转成列向量
接着,将w和b的真实值传入构造数据集,构造400个数据集样本:
# y=Wx+b W=[2,-3.4]T b=4.2
true_w=torch.tensor([2,-3.4])
true_b=4.2
n=400 #样本数量
features,labels=synthetic_data(true_w,true_b,n) #生成数据features和labels
我们也可以利用matplotlib库对features和labels进行可视化操作:
# 将features和labels进行可视化
plt.figure(figsize = (12,5))
ax1 = plt.subplot(121)
ax1.scatter(features[:,0],labels, c = "b",label = "features[:,0]")
ax1.legend()
plt.xlabel("x1")
plt.ylabel("y",rotation = 0)
ax2 = plt.subplot(122)
ax2.scatter(features[:,1],labels, c = "g",label = "features[:,1]")
ax2.legend()
plt.xlabel("x2")
plt.ylabel("y",rotation = 0)
运行结果:
构建数据迭代器代码如下:
ds = data.TensorDataset(features,labels) #构建数据迭代器
ds_train,ds_valid = data.random_split(ds,[int(400*0.7),400-int(400*0.7)])
dl_train = data.DataLoader(ds_train,batch_size = 10,shuffle=True,num_workers=2)
dl_valid = data.DataLoader(ds_valid,batch_size = 10,num_workers=2)
random_split函数将数据集随机拆分为给定长度的非重叠新数据集,这里将训练集和测试集按比例7:3拆分,然后利用DataLoader函数对其进行加载。
2.3 定义模型这里利用了torchkeras库,定义模型代码如下:
# 定义模型
from torchkeras import Model
class LinearRegression(Model):
def __init__(self):
super(LinearRegression, self).__init__()
self.fc = nn.Linear(2,1) #线性层
def forward(self,x):
return self.fc(x)
model = LinearRegression()
torchkeras 是在pytorch上实现的仿keras的高层次Model接口。有了它,就可以像Keras那样,对pytorch构建的模型进行summary,compile,fit,evaluate , predict五连击。
可以利用compile()查看模型结构:
#输出模型结构
model.summary(input_shape = (2,))
模型结构如下:
Layer (type)Output ShapeParam#Linear-1[-1, 1]3Total params: 3 Trainable params: 3 Non-trainable params: 0
2.4 模型评价指标函数平均绝对误差(Mean Absolute Error,MAE): M A E = 1 n ∑ i = 1 n ∣ y ^ i − y i ∣ MAE=\frac{1}{n}\sum_{i=1}^n{|\hat{y}_i-y_i|} MAE=n1i=1∑n∣y^i−yi∣
其范围为[0,+∞),当预测值与真实值完全吻合时等于0,即完美模型;误差越大,该值越大。
定义MAE函数:
#MAE——平均绝对误差
def mean_absolute_error(y_pred,y_true):
return torch.mean(torch.abs(y_pred-y_true))
平均绝对百分比误差(Mean Absolute Percentage Error,MAPE): M A P E = 100 % n ∑ i = 1 n ∣ y ^ i − y i y i ∣ MAPE=\frac{100\%}{n}\sum_{i=1}^n{\left| \frac{\hat{y}_i-y_i}{y_i} \right|} MAPE=n100%i=1∑n∣∣∣∣yiy^i−yi∣∣∣∣
其范围为[0,+∞),MAPE为0%表示完美模型,MAPE大于100%则表示劣质模型。
可以看到,MAPE跟MAE很像,就是多了个分母。
【注意】:当真实值有数据等于0时,存在分母0除问题,该公式不可用,所以一般同时在分子和分母上加一个较小的数值防止出现error。
定义MAPE评价指标:
#MAPE——平均绝对百分比误差
def mean_absolute_percent_error(y_pred,y_true):
absolute_percent_error = (torch.abs(y_pred-y_true)+1e-7)/(torch.abs(y_true)+1e-7)
return torch.mean(absolute_percent_error)
2.5 编译和训练
compile()用于配置训练模型(编译),fit()用于训练模型 代码如下:
model.compile(loss_func = nn.MSELoss(),
optimizer= torch.optim.Adam(model.parameters(),lr = 0.01),
metrics_dict={"mae":mean_absolute_error,"mape":mean_absolute_percent_error})
dfhistory = model.fit(200,dl_train = dl_train, dl_val = dl_valid,log_step_freq = 20)
损失函数利用MSELoss(),优化器采用Adam优化器,学习率为0.01,metrics_dict参数指定在训练和测试期间的模型评估标准,这里指定MAE和MAPE作为评估标准。最后利用fit()函数训练模型,训练200次,fit函数返回History对象,History类对象包含两个属性,分别为epoch和history,epoch为训练轮数,history为字典类型,默认包含val_loss,val_acc,loss,acc四个key值,由于这里在compile()函数中加入mae和mape,因此这里的history字典中包含6个key值。如下所示: 训练完成后,可以查看w和b的值:
#查看w和b的值
w = model.state_dict()["fc.weight"]
b=model.state_dict()["fc.bias"]
w,b
2.6 输出结果可视化
利用最终训练出来的w和b可以进行最终输出结果可视化:
#结果可视化
plt.figure(figsize = (12,5))
ax1 = plt.subplot(121)
ax1.scatter(features[:,0],labels, c = "b",label = "features[:,0]")
ax1.plot(features[:,0],w[0,0]*features[:,0]+b[0],"-r",linewidth = 5.0,label = "model")
ax1.legend()
plt.xlabel("x1")
plt.ylabel("y",rotation = 0)
ax2 = plt.subplot(122)
ax2.scatter(features[:,1],labels, c = "g",label = "features[:,1]")
ax2.plot(features[:,1],w[0,1]*features[:,1]+b[0],"-r",linewidth = 5.0,label = "model")
ax2.legend()
plt.xlabel("x2")
plt.ylabel("y",rotation = 0)
运行结果:
定义模型评估可视化函数:
def plot_metric(dfhistory, metric):
train_metrics = dfhistory[metric]
val_metrics = dfhistory['val_'+metric]
epochs = range(1, len(train_metrics) + 1)
plt.plot(epochs, train_metrics, 'bo--')
plt.plot(epochs, val_metrics, 'ro-')
plt.title('Training and validation '+ metric)
plt.xlabel("Epochs")
plt.ylabel(metric)
plt.legend(["train_"+metric, 'val_'+metric])
plt.show()
查看训练集和验证集的损失:
plot_metric(dfhistory,"loss")
查看训练集和验证集的MAPE:
plot_metric(dfhistory,"mape")
在测试模式下评估模型性能:
# 评估
model.evaluate(dl_valid)
运行结果: {‘val_loss’: 0.0001073539030282215, ‘val_mae’: 0.008271524915471673, ‘val_mape’: 0.0075647564566073315}
使用模型进行预测:
# 使用模型进行预测
dl = data.DataLoader(data.TensorDataset(features))
model.predict(dl)[0:10]
运行结果: tensor([[ 3.1832], [-1.5471], [12.1956], [ 6.6161], [ 1.7743], [ 3.5524], [ 6.3739], [ 3.3306], [ 7.2390], [ 2.9116]])
三、完整代码完整代码可以参考:https://download.csdn.net/download/didi_ya/40510830
ok,以上便是本文的全部内容了,看完了之后记得一定要亲自独立动手实践一下呀~