线性回归机器学习
思路-构建模型-训练-预测
torch.nn.mseLoss()均方误差损失。计算预测值与实际值的平方均值
import numpy as np #numpy用于处理数值数组
import torch #torch是PyTorch库,用于构建和训练神经网络
import matplotlib.pyplot as plt #matplotlib.pyplot用于数据可视化
x = np.array([1, 2, 0.5, 2.5, 2.6, 3.1], dtype=np.float32).reshape((-1, 1))
y = np.array([3.7, 4.6, 1.65, 5.68, 5.98, 6.95], dtype=np.float32).reshape(-1, 1)
这里定义了输入数据x和对应的目标数据y。x是一个包含6个数值的一维数组,通过reshape((-1, 1))将其转换为一个形状为(6, 1)的二维数组,这是因为PyTorch中的线性层通常期望输入数据是二维的。同样,y也被转换为形状为(6, 1)的二维数组。
线性回归模型构建
class LinearRegressionModel(torch.nn.Module):
def __init__(self, input_dim, output_dim)://初始化
super(LinearRegressionModel, self).__init__()//继承torch
self.linear = torch.nn.Linear(input_dim, output_dim)
def forward(self, x):
out = self.linear(x)
return out
1. class LinearRegressionModel(torch.nn.Module):这是定义了一个名为 LinearRegressionModel 的类,它继承自 torch.nn.Module。torch.nn.Module 是 PyTorch 中所有神经网络模块的基类,继承它意味着 LinearRegressionModel 类可以利用 torch.nn.Module 的一些特性和功能,比如自动管理模型参数、支持模型的训练和评估等流程。
2. def __init__(self, input_dim, output_dim)::这是类的初始化方法。__init__ 方法在创建类的实例时会被自动调用,这里的 input_dim 和 output_dim 是该方法的参数,用于指定输入特征的维度和输出的维度。
3. super(LinearRegressionModel, self).__init__():这行代码调用了父类 torch.nn.Module 的 __init__ 方法,目的是在初始化 LinearRegressionModel 类的实例时,先正确地执行父类的初始化逻辑,为后续的操作做好准备。
4. self.linear = torch.nn.Linear(input_dim, output_dim):在 LinearRegressionModel 类的实例中创建了一个名为 linear 的属性,它是 torch.nn.Linear 类的一个实例。torch.nn.Linear 类用于实现线性变换,input_dim 和 output_dim 分别作为输入特征维度和输出维度传递给它,这样就定义了一个线性层。
5. def forward(self, x)::这是定义了一个前向传播方法。在 PyTorch 中,自定义的神经网络模型类必须实现 forward 方法,来指定数据在模型中的流动方向和计算过程。这里的 x 是输入数据,out = self.linear(x) 表示将输入数据 x 传入前面定义的 linear 线性层进行计算,最后返回计算结果 out。
总体来说,这段代码构建了一个简单的线性回归模型类 LinearRegressionModel,它继承自 torch.nn.Module,内部包含一个线性层 linear,并定义了数据的前向传播过程。
def __init__(self, input_dim, output_dim):
• __init__方法是类的构造函数,它接收输入维度input_dim和输出维度output_dim作为参数,并在其中定义了一个线性层self.linear。
• forward方法定义了模型的前向传播逻辑,它接收输入数据x,通过线性层计算得到输出out并返回。
在 Python 类中,def __init__(self, input_dim, output_dim): 是类的构造函数(也称为初始化方法)的定义语句:
1. def:这是 Python 中用于定义函数的关键字,这里定义的是类中的一个特殊函数(方法)。
2. __init__:这是 Python 中一个特殊的方法名,被称为构造函数或初始化方法。当使用类创建一个新的实例(对象)时,Python 会自动调用这个方法来进行对象的初始化操作,比如设置对象的初始属性值等。
3. self:在 Python 类的方法中,self 是一个约定俗成的参数名,它指向类的实例本身。通过 self,可以在方法内部访问和操作实例的属性和其他方法。在调用类的方法时,Python 会自动将实例本身作为 self 参数传递进去,所以在调用方法时不需要显式传递 self。
4. input_dim 和 output_dim:这是构造函数定义的两个参数,它们是用户在创建类的实例时需要传入的参数值。在你之前展示的代码中,input_dim 表示输入数据的维度,output_dim 表示输出数据的维度,用于初始化线性回归模型中的线性层(torch.nn.Linear)。例如:
super(LinearRegressionModel, self).__init__()
self.linear = torch.nn.Linear(input_dim, output_dim)
torch.nn.Linear是PyTorch中的一个类,在某种意义上可以认为它类似于一个API(应用程序接口),但更准确地说它是构建神经网络时用于创建线性层的工具。以下是具体介绍:
• 功能实现:它用于实现全连接层,即线性变换。该类能够对输入数据进行线性变换,计算公式为y = xA^T + b,其中x是输入数据,A是权重矩阵,b是偏置向量,y是输出数据。在构建神经网络时,通过实例化torch.nn.Linear类来创建线性层,定义输入特征维度和输出特征维度,就能对输入数据进行线性变换操作。
• 参数管理:torch.nn.Linear类在实例化时会自动创建和管理权重和偏置参数。这些参数是可学习的,在神经网络训练过程中,会根据损失函数的反向传播来更新这些参数,以优化模型的性能。
• 与其他模块协作:它可以很方便地与PyTorch中的其他神经网络模块和函数配合使用。比如可以将它与激活函数模块(如torch.nn.ReLU)组合,构建具有非线性映射能力的神经网络;也能与其他类型的层(如卷积层torch.nn.Conv2d)一起,构建更复杂的神经网络架构。
在使用时,通常像这样实例化:linear_layer = torch.nn.Linear(in_features, out_features),其中in_features是输入特征的维度,out_features是输出特征的维度。然后就可以将输入数据传入这个线性层进行计算,如output = linear_layer(input)。
input_dim = 1//构建输入输出维度
output_dim = 1
model = LinearRegressionModel(input_dim, output_dim)、、这行代码创建了一个 LinearRegressionModel 类的实例 model,并将前面定义的 input_dim 和 output_dim 作为参数传递给构造函数,这样就实例化了一个线性回归模型,模型内部包含一个输入维度为 1、输出维度为 1 的线性层。
criterion = torch.nn.MSELoss()//这里创建了一个损失函数对象 criterion,使用的是均方误差(Mean Squared Error, MSE)损失函数。在回归问题中,均方误差是一种常用的衡量预测值与真实值之间差异的方法,它计算的是预测值与真实值之差的平方的平均值。
learning_rate = 0.01//学习率
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)//5. optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate):
这行代码创建了一个优化器对象 optimizer,使用的是随机梯度下降(Stochastic Gradient Descent, SGD)优化算法。model.parameters() 用于获取模型中所有可学习的参数(在这个例子中就是线性层的权重和偏置),lr=learning_rate 则将前面定义的学习率传递给优化器,优化器将根据计算得到的梯度和学习率来更新模型的参数,以最小化损失函数。
for epoch in range(100):
inputs = torch.from_numpy(x).requires_grad_()
labels = torch.from_numpy(y)
1.inputs = torch.from_numpy(x).requires_grad_():
使用torch.from_numpy将numpy数组x转换为torch的张量(tensor)对象inputs。
requires_grad_()方法用于设置这个张量需要计算梯度,因为在后续反向传播过程中,我们需要计算损失函数关于输入数据的梯度,以便更新模型参数。
2.将numpy数组y转换为torch张量对象labels,表示数据的真实标签。
3.• x 是模型的输入数据,模型的参数会根据输入数据 x 来计算输出,在反向传播过程中,需要计算损失函数关于输入数据以及模型参数的梯度,以便更新模型参数。对 x 调用 requires_grad_() 就是为了让PyTorch追踪对 x 的操作,从而能够计算梯度。
• y 是真实标签数据,它在训练过程中只是作为参考来计算损失,不需要计算关于 y 的梯度来更新它自身,因为它不是模型要学习和调整的参数或变量,所以一般不需要设置 requires_grad。
optimizer.zero_grad()//调用优化器的zero_grad()方法,将模型中所有参数的梯度清零。在每次计算新的梯度之前,必须先将之前的梯度清零,否则梯度会累加,导致更新结果错误。
outputs = model(inputs)//将输入数据inputs传入模型model中,通过调用模型的forward方法(在LinearRegressionModel类中定义的),得到模型的预测输出outputs。
loss = criterion(outputs, labels)// loss = criterion(outputs, labels):
使用之前定义的均方误差损失函数criterion,计算模型预测输出outputs和真实标签labels之间的损失值loss。
loss.backward()//调用损失值loss的backward方法,执行反向传播算法。这一步会根据链式法则计算损失函数关于模型中所有可学习参数的梯度,并将梯度存储在每个参数的grad属性中。
optimizer.step()//调用优化器的step方法,根据计算得到的梯度和设置的学习率,更新模型中的可学习参数。
loss.backward()通常与optimizer.zero_grad()和optimizer.step()一起使用。optimizer.zero_grad()在loss.backward()之前调用,用于清空之前积累的梯度,确保每次反向传播计算的梯度是基于当前批次数据的。optimizer.step()在loss.backward()之后调用,根据存储在grad属性中的梯度值来更新模型参数。
print('epoch {}, loss {}'.format(epoch + 1, loss.item()))//打印当前训练的轮数(epoch + 1)和对应的损失值(loss.item())。loss.item()用于获取loss张量中的标量值并打印出来,方便观察模型在训练过程中损失值的变化情况。
model.eval()
with torch.no_grad():
predicted = model(torch.from_numpy(x))
plt.scatter(x, y)
plt.plot(x, predicted.numpy(), 'r')
plt.show()
1. model.eval():
在深度学习中,许多模型(比如含有 Dropout 层或 Batch Normalization 层的模型)在训练和评估阶段的行为是不同的。Dropout 层在训练时会随机“丢弃”一部分神经元,以防止过拟合,而在评估时需要让所有神经元都参与计算;Batch Normalization 层在训练时会根据当前批次的数据计算均值和方差来进行归一化,而在评估时则使用训练过程中保存的全局均值和方差。调用 model.eval() 就是将模型设置为评估模式,确保模型在推理时的行为是正确的。
2. with torch.no_grad():
在 PyTorch 中,默认情况下,对张量的操作会记录计算图以便进行反向传播来计算梯度,从而更新模型参数。然而,在评估模型性能时,我们并不需要计算梯度,因为我们不想更新模型参数。with torch.no_grad() 这个上下文管理器会暂停 PyTorch 的自动求导功能,在这个代码块内的所有操作都不会计算梯度。这不仅可以提高计算效率,还能节省内存,因为不需要为梯度计算和存储额外的信息。
3. predicted = model(torch.from_numpy(x)):
torch.from_numpy(x) 这部分代码的作用是将一个 NumPy 数组 x 转换为 PyTorch 的 Tensor 类型。因为 PyTorch 的模型只能接受 Tensor 类型的输入。然后,model(torch.from_numpy(x)) 将转换后的 Tensor 输入到模型 model 中,模型根据其内部的结构和已学习到的参数对输入进行前向传播计算,最终返回预测结果,并将其赋值给 predicted 变量。
4. plt.scatter(x, y):
这里使用了 matplotlib 库的 scatter 函数。scatter 函数用于绘制散点图,x 是横坐标数据,y 是纵坐标数据。通过这个函数,我们可以将真实的数据点在二维平面上可视化出来,直观地看到数据的分布情况。
5. plt.plot(x, predicted.numpy(), 'r'):
predicted.numpy() 是将 PyTorch 的 Tensor 类型的预测结果 predicted 转换为 NumPy 数组,以便 matplotlib 能够处理。plt.plot(x, predicted.numpy(), 'r') 这行代码使用 plot 函数绘制一条线图,x 作为横坐标,预测结果 predicted 转换后的 NumPy 数组作为纵坐标,'r' 表示这条线的颜色为红色。通过绘制这条线,我们可以直观地看到模型的预测值与真实数据之间的关系。
6. plt.show():
show 函数是 matplotlib 库中用于显示图形的函数。当调用 plt.show() 时,之前绘制的散点图和线图会在一个窗口中显示出来,这样我们就可以直观地观察模型的预测效果了。
源码及效果图
import numpy as np import torch import matplotlib.pyplot as plt from onnxslim.core import optimize x = np.array([1, 2, 0.5, 2.5, 2.6, 3.1], dtype=np.float32).reshape((-1, 1)) y = np.array([3.7, 4.6, 1.65, 5.68, 5.98, 6.95], dtype=np.float32).reshape(-1, 1) class LinearRegressionModel(torch.nn.Module): def __init__(self, input_dim, output_dim): super(LinearRegressionModel, self).__init__() self.linear = torch.nn.Linear(input_dim, output_dim) def forward(self, x): out = self.linear(x) return out input_dim = 1 output_dim = 1 model = LinearRegressionModel(input_dim, output_dim) criterion = torch.nn.MSELoss() learning_rate = 0.01 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) for epoch in range(100): inputs = torch.from_numpy(x).requires_grad_() labels = torch.from_numpy(y) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() print('epoch {}, loss {}'.format(epoch + 1, loss.item())) # 绘制结果 model.eval() with torch.no_grad(): predicted = model(torch.from_numpy(x)) plt.scatter(x, y) plt.plot(x, predicted.numpy(), 'r') plt.show()