新手小白的pytorch学习第五弹-----pytorch的工作流

我们之前学习了 pytorch 中的基本数据 tensor

今天我们要开始学习 pytorch 的简单工作流程了

数据 -> 构建或选择一个预训练的模型 -> 使得模型适应数据并能够进行预测 -> 评估模型 -> 通过实验提升性能 -> 保存并重新加载你训练的模型

机器学习和深度学习的关键是从过去获得的数据中,创建算法来发现数据中的模式,接着用我们所发现的模式来预测将来。

接下来我们就尝试使用pytorch创建一个模型,主要是一个线性模型

python 复制代码
what_were_covering = { 1:"data(preparing and loading)",
                      2:"build model",
                      3:"fitting the model to data(training)",
                      4:"making predictions and evaluating a model (inference)",
                      5:"saving and loading a model",
                      6:"putting it all together"
}

1 data(preparing and loading)

首先,我们导入必须要的包,同时查看一下pytorch的版本

python 复制代码
import torch
import matplotlib.pyplot as plt
import torch.nn as nn

torch.__version__

'2.3.1+cu118'

机器学习就像一个包含两个方面的游戏:

1 将你的数据(图像、音频、视频、文本等)进行数学的表征

2 创建或者选择模型尽可能好地来学习这些表征

python 复制代码
weights = 0.7
bias = 0.3
start = 0
end = 1
step = 0.02

# 之前我们学习过, unsqueeze(dim=1)就是在列上增加单维度,这样我们的每个数据外面就有一个方括号了
# 这里 dim = 1, 大家可以自己试一试,可以把 unsqueeze(dim=1) 删除看看是什么形状
X = torch.arange(start, end, step).unsqueeze(dim = 1)
y = weights * X + bias

print(X[:10], y[:10])

print(len(X))
print(len(y))

tensor([[0.0000],

[0.0200],

[0.0400],

[0.0600],

[0.0800],

[0.1000],

[0.1200],

[0.1400],

[0.1600],

[0.1800]]) tensor([[0.3000],

[0.3140],

[0.3280],

[0.3420],

[0.3560],

[0.3700],

[0.3840],

[0.3980],

[0.4120],

[0.4260]])

50

50

将我们的数据划分为训练集和测试集

一般训练集占数据的 60%~80%,测试集占 20%~40%

注意:当我们处理真实世界的数据集时,在项目的开始我们就需要划分数据,(测试数据集应该要一直和其他数据集分开),以使得我们的模型在测试集上进行测试,促进模型在它没有遇到过的数据上有更好的泛化性能

python 复制代码
# 划分训练集和测试集
train_split = int (0.8 * len(X))
X_train, y_train = X[:train_split], y[:train_split]
X_test, y_test = X[train_split:], y[train_split:]

len(X_train), len(y_train), len(X_test), len(y_test)

(40, 40, 10, 10)

我们刚开始学习东西搞不明白,最好是将我们学习的内容进行可视化,那让我们来具体看一看这些数据究竟是什么形态的吧!

唔,我还发现优秀的开发者,都比较喜欢把这些功能啥的函数话,那我们也来搞一个函数,功能就是绘画出我们的训练数据、真实值、预测值的函数

python 复制代码
# 我刚开始学东西搞不懂,也喜欢把东西可视化,让我们具体来看看这些数据是什么形态的
# 我还发现优秀的代码编写者都喜欢把一件事情搞成一个函数来进行

def plot_predictions(train_data=X_train,
                     train_labels=y_train,
                     test_data=X_test,
                     test_labels=y_test,
                     predictions=None):
    '''
    plots training data, test data and compares predictions.
    '''
    
    plt.figure(figsize=(10, 7))
    
    # 用蓝色来描绘训练数据, s是size的意思,可以试试其他的值还挺有意思的
    plt.scatter(train_data, train_labels, c="b", s=4, label="Traing data")
    
    # 用绿色来描绘测试数据
    plt.scatter(test_data, test_labels, c="g", s=4, label="Testing data")
    
    if predictions is not None:
        # 用红色来描绘预测数据
        plt.scatter(test_data, predictions, c="r", s=4, label="prediction data")
        
    # 展示标签
    plt.legend(prop={"size":14})
python 复制代码
plot_predictions()

2 build model (创建模型)

python 复制代码
import torch.nn as nn
import torch

class LinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.weights = nn.Parameter(torch.randn(1,
                                                dtype=torch.float),
                                    requires_grad=True)
        self.bias = nn.Parameter(torch.randn(1,
                                             dtype=torch.float),
                                 requires_grad=True)
        
    def forward(self, x):
        return self.weights * x + self.bias
pytorch有四个比较基础且重要的模块,基本都要用到:

torch.nn
torch.optim
torch.utils.data.Dataset
torch.utils.data.DataLoader

(1) torch.nn 包含了计算图的所有构建块(本质上是一系列以特定方式执行的计算)
(2) torch.nn.Module 神经网络模块的基本类,如果使用pytorch创建神经网路,你的模型必须是nn.Module的子类,同时需要实现forward(),我现在懂了,forward()表示前向传播,用数学实现往前传就可以
(3) torch.optim 优化,对梯度的改变进行优化,让它以一种更好的方式进行训练同时减少损失或者说是代价

接着,我们来看看如何查找pytorch模型中的参数内容

首先,我们需要创建一个模型,通过上述创建我们模型的方法,不难发现,我们参数是用 torch.randn()来创建的,是个随机数,因此我们在这里使用torch.manual_seed()使得结果能够复现

python 复制代码
# 由于nn.Parameter是随机的,因此我们使用 manual_seed() 来复现实验
torch.manual_seed(42)

# 创建一个模型实例
model_0 = LinearRegressionModel()

# 查看模型的参数
# 这行代码报错,所以我们有了list
# model_0.parameters() 
# <generator object Module.parameters at 0x0000020AF1316C80>

list(model_0.parameters())

[Parameter containing:

tensor([0.3367], requires_grad=True),

Parameter containing:

tensor([0.1288], requires_grad=True)]

我们也可以使用 .state_dict() 来获得模型的状态(这个模型包含什么内容、参数啥的)
python 复制代码
# 列出 参数的名称和它的内容
model_0.state_dict()

OrderedDict([('weights', tensor([0.3367])), ('bias', tensor([0.1288]))])

我感觉这个 .state_dict() 比 .parameters() 好一些,数据内涵和内容更加清晰

实际上,我们希望从随机参数开始,让模型更新她们,来适应我们数据的最佳参数,就是我们自己定义的 weights 和 bias 值。

使用 torch.inference_mode()进行预测

python 复制代码
# 用模型进行预测
with torch.inference_mode():
    y_preds = model_0(X_test)
python 复制代码
with torch.no_grad():
    y_preds = model_0(X_test)

这是个啥,就是说我们进行训练的时候需要使用梯度来更新我们的参数值,而预测的时候我们是不需要梯度的,少了这个梯度计算的过程能够减少计算,尤其是有大量数据的时候。

上文中的 torch.inference_mode() 和 torch.no_grad() 都是同样 的作用,不过前者是后来更新的,能够更快更方便使用

python 复制代码
# 让我们来进行预测吧
print(f"测试样本的数量:{len(X_test)}")
print(f"预测:{len(y_preds)}")
print(f"预测值:{y_preds}")

测试样本的数量:10

预测:10

预测值:tensor([[0.3982],

[0.4049],

[0.4116],

[0.4184],

[0.4251],

[0.4318],

[0.4386],

[0.4453],

[0.4520],

[0.4588]])

接下来让我们可视化的看一看吧,使用我们自己创建的函数捏
python 复制代码
plot_predictions(predictions=y_preds)


很明显,我们希望预测值和真实值之间差距越小越好,越接近0越好,显然,咱们这个预测是相当不好的

为什么呢?很简单,我们的 weights 和 bias 都是随机的值,它并没有根据我们的训练集生成,所以理所当然的预测值很糟糕

3 训练模型 和 预测评估

大多数情况下,我们是不知道数据理想的参数的,事实上,我们需要写代码看看是否模型能够找到理性的参数值

创建损失函数和使用pytorch的优化器

如果需要更新我们的参数,那么我们就需要损失函数和优化器

loss function:损失函数,一个衡量我们模型的代价的函数,看看我们的模型到底有多差的一个函数。根据预测值和真实值之间的比较,越低越好哈。eg:torch.nn.L1Loss()Mean absolute error平均绝对误差;torch.nn.BCELoss() Binary cross entropy for binary classification进行二分类的
optimizer:优化器,告诉我们的模型如何去更新梯度,同时能更好的降低损失。 eg:Stochastic(随机) gradient desent,torch.optim.SGD(); Adam optimizer,torch.optim.Adam()
同时我们还需要 train 循环和 test 循环来帮助我们实现这个事情

python 复制代码
import torch.optim as optim
loss_fn = nn.L1Loss()
optimizer = optim.SGD(model_0.parameters(), lr=0.01)
python 复制代码
# 开始正式写我们的训练部分了
epochs = 100

# 让我们定义一些容器来存储一些比较重要的内容,同时也可以方便我们画图和理解这些内涵
epoch_count = []
loss_train = []
loss_test_value = []

for epoch in range(epochs):
    # 模型进入训练模式
    model_0.train()
    y_pred = model_0(X_train)
    loss = loss_fn(y_pred, y_train)
    # print(f"loss:{loss}")
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    # print(f"parameters:{model_0.state_dict()}")
    
    # 模型进入评估模式
    model_0.eval()
    with torch.inference_mode():
        y_test_preds = model_0(X_test)
        loss_test = loss_fn(y_test_preds, y_test)
        
        if epoch % 10 == 0:
            epoch_count.append(epoch)
            loss_test_value.append(loss_test.detach().numpy())
            loss_train.append(loss.detach().numpy())
            print(f"Epoch:{epoch} | loss_test_value:{loss_test_value} | loss_train:{loss_train}")
    

一条结果我摘出来了,是这样的,方便大家观看和理解。

Epoch:0 | loss_test_value:[array(0.48106518, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32)]
Epoch:0 | loss_test_value:[array(0.48106518, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32)]

Epoch:10 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32)]

Epoch:20 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32)]

Epoch:30 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32)]

Epoch:40 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32)]

Epoch:50 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32), array(0.09919948, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32), array(0.04167863, dtype=float32)]

Epoch:60 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32), array(0.09919948, dtype=float32), array(0.08886633, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32), array(0.04167863, dtype=float32), array(0.03818933, dtype=float32)]

Epoch:70 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32), array(0.09919948, dtype=float32), array(0.08886633, dtype=float32), array(0.08059376, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32), array(0.04167863, dtype=float32), array(0.03818933, dtype=float32), array(0.0347609, dtype=float32)]

Epoch:80 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32), array(0.09919948, dtype=float32), array(0.08886633, dtype=float32), array(0.08059376, dtype=float32), array(0.07232123, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32), array(0.04167863, dtype=float32), array(0.03818933, dtype=float32), array(0.0347609, dtype=float32), array(0.03132383, dtype=float32)]

Epoch:90 | loss_test_value:[array(0.48106518, dtype=float32), array(0.3463552, dtype=float32), array(0.2172966, dtype=float32), array(0.14464018, dtype=float32), array(0.11360953, dtype=float32), array(0.09919948, dtype=float32), array(0.08886633, dtype=float32), array(0.08059376, dtype=float32), array(0.07232123, dtype=float32), array(0.06473556, dtype=float32)] | loss_train:[array(0.31288138, dtype=float32), array(0.19767132, dtype=float32), array(0.08908726, dtype=float32), array(0.05314853, dtype=float32), array(0.04543797, dtype=float32), array(0.04167863, dtype=float32), array(0.03818933, dtype=float32), array(0.0347609, dtype=float32), array(0.03132383, dtype=float32), array(0.0278874, dtype=float32)]

大家也可以把epochs先设置为1单独看看每一次的loss和模型的参数值,我是自己试过的,可以看到loss一直在变小,模型的参数在逐渐往真实值靠近,还蛮有趣的。

注意到这里有个zero_grad(),我刚开始也不知道它到底有什么作用,现在知道了,由于这是一个循环,那每次循环我们优化器中梯度就会累加,这样很明显是不利于我们进行参数学习的,因此我们使用**zero_grad()**对优化器的梯度进行一个清零的作用。

python 复制代码
plot_predictions(predictions=y_test_preds)

哇哦,epochs=100,也就是说训练100次,我们的预测值就非常的接近真实值了,让我们来看看模型的参数是什么,是不是很接近真实值

python 复制代码
print(f"model_0的参数:{model_0.state_dict()}")
print(f"实际的真实参数值:weights={weights}, bias={bias}")

model_0的参数:OrderedDict([('weights', tensor([0.5784])), ('bias', tensor([0.3513]))])

实际的真实参数值:weights=0.7, bias=0.3

可以看出来,已经在慢慢接近了,证明方向是正确的,让咱们再来100次看看。再运行一次训练部分的代码即可。

python 复制代码
# 开始正式写我们的训练部分了
epochs = 100

# 让我们定义一些容器来存储一些比较重要的内容,同时也可以方便我们画图和理解这些内涵
epoch_count = []
train_loss_values = []
test_loss_values = []

for epoch in range(epochs):
    # 模型进入训练模式
    model_0.train()
    y_pred = model_0(X_train)
    loss = loss_fn(y_pred, y_train)
    
    # print(f"loss:{loss}")
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    # print(f"parameters:{model_0.state_dict()}")
    
    # 模型进入评估模式
    model_0.eval()
    with torch.inference_mode():
        test_pred = model_0(X_test)
        test_loss = loss_fn(test_pred, y_test.type(torch.float))
        
        if epoch % 10 == 0:
            epoch_count.append(epoch)
            test_loss_values.append(test_loss.detach().numpy())
            train_loss_values.append(loss.detach().numpy())
            print(f"Epoch:{epoch} | loss_test_value:{test_loss_values} | loss_train:{train_loss_values}")
    
    

Epoch:0 | loss_test_value:[array(0.05646304, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32)]

Epoch:10 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32)]

Epoch:20 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32)]

Epoch:30 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32)]

Epoch:40 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32)]

Epoch:50 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32), array(0.01647409, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32), array(0.00728353, dtype=float32)]

Epoch:60 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32), array(0.01647409, dtype=float32), array(0.00820156, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32), array(0.00728353, dtype=float32), array(0.00385178, dtype=float32)]

Epoch:70 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32), array(0.01647409, dtype=float32), array(0.00820156, dtype=float32), array(0.00502309, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32), array(0.00728353, dtype=float32), array(0.00385178, dtype=float32), array(0.00893248, dtype=float32)]

Epoch:80 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32), array(0.01647409, dtype=float32), array(0.00820156, dtype=float32), array(0.00502309, dtype=float32), array(0.00502309, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32), array(0.00728353, dtype=float32), array(0.00385178, dtype=float32), array(0.00893248, dtype=float32), array(0.00893248, dtype=float32)]

Epoch:90 | loss_test_value:[array(0.05646304, dtype=float32), array(0.0481905, dtype=float32), array(0.04060482, dtype=float32), array(0.03233228, dtype=float32), array(0.02405975, dtype=float32), array(0.01647409, dtype=float32), array(0.00820156, dtype=float32), array(0.00502309, dtype=float32), array(0.00502309, dtype=float32), array(0.00502309, dtype=float32)] | loss_train:[array(0.02445896, dtype=float32), array(0.02102021, dtype=float32), array(0.01758547, dtype=float32), array(0.01415539, dtype=float32), array(0.01071659, dtype=float32), array(0.00728353, dtype=float32), array(0.00385178, dtype=float32), array(0.00893248, dtype=float32), array(0.00893248, dtype=float32), array(0.00893248, dtype=float32)]

再运行一下这段代码就可以继续绘图了

python 复制代码
plot_predictions(predictions=y_test_preds)

哇,oh my god!又更加的接近了。再看看咱们的参数呢

python 复制代码
print(f"model_0的参数:{model_0.state_dict()}")
print(f"实际的真实参数值:weights={weights}, bias={bias}")

model_0的参数:OrderedDict([('weights', tensor([0.6990])), ('bias', tensor([0.3093]))])

实际的真实参数值:weights=0.7, bias=0.3

very close,非常接近了,BB们,兴不兴奋!

我们刚刚添加了测试的循环的代码,从model_0.eval()开始就是测试循环的代码啦!

现在我们开始尝试着绘画出损失函数的图像吧。

python 复制代码
plt.plot(epoch_count, train_loss_values, label="Train loss")
plt.plot(epoch_count, test_loss_values, label="Test loss")
plt.title("Training and test loss curves")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()

这是运行100次的损失图像,

运行200次的损失图像如下,真的很奇怪,希望以后能懂得为什么会这个样子吧

好,今天真是收获满满,基本上是训练和测试过了一遍,而且咱们还进行了可视化,更加地了解我们的数据了

今天教二年级的小孩英语,他真的是不听,尊嘟快把我结节都气出来了。不生气不生气,人生就像一场戏

BB啊,我跟你说,今天中午吃的紫苏牛蛙,嘎嘎好吃,辣椒炒肉也很好吃,都吃撑了,很开心很开心

BB啊,如果我的文档对你有帮助的话,记得给俺点个赞呐~

靴靴,谢谢!

相关推荐
nuise_12 分钟前
朴素贝叶斯法
人工智能·机器学习·概率论
ehiway30 分钟前
FPGA+GPU+CPU国产化人工智能平台
人工智能·fpga开发·硬件工程·国产化
天天爱吃肉821833 分钟前
碳化硅(SiC)功率器件:新能源汽车的“心脏”革命与技术突围
大数据·人工智能
花王江不语35 分钟前
设计模式学习笔记
笔记·学习·设计模式
前端熊猫1 小时前
CSS Grid 布局学习笔记
css·笔记·学习·grid
奔跑吧邓邓子1 小时前
【Python爬虫(27)】探索数据可视化的魔法世界
开发语言·爬虫·python·数据可视化
萧鼎1 小时前
利用 OpenCV 进行棋盘检测与透视变换
人工智能·opencv·计算机视觉
神秘的土鸡1 小时前
使用Open WebUI下载的模型文件(Model)默认存放在哪里?
人工智能·llama·ollama·openwebui
恋恋西风2 小时前
CT dicom 去除床板 去除床位,检查床去除
python·vtk·dicom·去床板