PyTorch for Deep Learning & Machine Learning – Full Course(2) - NoTe0x007

Baobao0824

原链接:
https://www.youtube.com/watch?v=V_xro1bcAuA

写在前面

这一系列是我在学习他人的优质课程(博客文章、视频课程等)时所做的学习笔记,根据我自身的水平来进行学习,同时会进行思维的发散,补充原文中没有提到或者有错误的地方。同时也会进行经常性的更新和整理,让它和我的当下的状态更加契合。

这期是pytorch深度学习的第二期,是视频的Chapter 1部分,也就是Pytorch的工作流程。上一期大概看了一周,看视频还是太慢了,所以这期就直接看他的笔记,我认为会快很多。

Introduction to PyTorch Workflow

通常来讲,一个典型的Pytorch工作流程是这样的

  1. 准备和加载数据
  2. 构建模型
  3. 让模型适配数据(训练)
  4. 预测与模型评估(推理)
  5. 模型保存与加载
  6. 全流程整合

首先先加载我们这一章要用的环境。

1
2
3
4
5
6
import torch
from torch import nn # nn包含了Pytorch所有的神经网络构建模块
import matplotlib.pyplot as plt

torch.__version__
# '2.5.1'

示例:创建线性回归模型

Creating a dataset with linear regression

在深度学习中,数据基本上可以是任何事情,例如

  • excel表格
  • 任何种类的图片
  • 视频
  • 广播或音乐等音频
  • DNA
  • 文本

深度学习是这两方面的游戏:

  • 把数据变成数学表示。
  • 建立一个模型来学习数学表示的模式。

为了演示这个过程,作者利用线性回归生成一些已知数据,使用线性回归公式,构造一条具有已知参数的直线,直线方程为$y = 0.7x + 0.3$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 创建已知参数
weight = 0.7
bias = 0.3
# 创建直线
start = 0
end = 1
step = 0.02
X = torch.arange(start, end, step).unsqueeze(dim=1)
y = weight * X + bias
X[:10], y[:10]
# (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]]))
len(X), len(y)
# (50, 50)

Creating training and test sets (the most important concept in ML)

在深度学习中,最重要的事情就是创建训练集和测试集。现在让我们尝试在这个已知的线性回归上创建训练集和测试集。我们从XY中分别拿出前80%做训练集,拿后20%做测试集(即40和10)。

1
2
3
4
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)

为了方便查看这些数据,最重要的就是进行可视化。这个时候就轮到我们的matplotlab出场了,让我们定义一个函数然后调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def plot_predictions(train_data=X_train,
train_labels=y_train,
test_data=X_test,
test_labels=y_test,
predictions=None):
"""
可视化训练集、测试集数据,并对比模型预测结果。
"""
plt.figure(figsize=(10, 7))
# 绘制训练数据(蓝色)
plt.scatter(train_data, train_labels, c="b", s=4, label="Training data")
# 绘制测试数据(绿色)
plt.scatter(test_data, test_labels, c="g", s=4, label="测试集数据")
# 检查是否存在预测值
if predictions is not None:
# 若存在,则绘制预测结果(红色)
plt.scatter(test_data, predictions, c="r", s=4, label="模型预测")
# 显示图例
plt.legend(prop={"size": 14})
plot_predictions()

图像看起来就长这样。

真是笔直的一条线啊
真是笔直的一条线啊

Creating our first PyTorch model

接下来我们就可以开始构建模型了。这个课程将全成使用类来构建模型,所以视频作者让我们先去学习python的面向对象编程。还好我的基本功足够扎实,可以直接来看代码,不需要看python的OOP。

作者不止一次强调了模型的工作原理:从随机初始值(在这个线性回归中就是模型的两个参数WeightBias)开始,观察训练数据,不断调整这些随机值,使其逼近理想值(即我们最开始给的真实值)。

他是如何做到的呢?主要依赖两个核心算法:梯度下降和反向传播。同时视频作者也给出了我们两个视频链接,讲解这两个算法。正好我对这两个算法并不是很熟悉,我可以把这两个视频拿过来看。

梯度下降(这个还是3b1b的视频呢)本质上就是不断接近一个函数的最小值,找到最速下降的地方,也就是梯度的负值。这个函数便是查看输出是否符合预期的成本函数(输入就是每个神经元所需要的那些权重和最后的偏差值)。拿手写识别来举例,如果说答案是什么数字都有,那这个成本函数就很高,而如果答案只给了一个数字很高的概率,那就说明这个成本很低,是对的。

那么如何快速的计算梯度呢?就需要反向传播算法了。还是拿手写数字识别来说,当我们需要代表2的那个神经元变高的时候,我们就反推回去,推高导出它结果的权重或偏置,或者根据上一层已经很高的神经元直接去改进而更改它的值也说不定。

以我的数学能力,我就能掌握这么多,接下来的问题就不是我所能操心的了。我们还是来看看怎么训练吧。这里面我们定义一个LinearRegressionModel类,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建线性回归模型类
class LinearRegressionModel(nn.Module): # <- PyTorch 中几乎所有组件都继承自 nn.Module 基类
def __init__(self):
super().__init__()
self.weights = nn.Parameter(torch.randn(1, requires_grad=True, dtype=torch.float))
# 1 <- 从随机权重开始,尝试将其调整为理想权重
# requires_grad=True <- 该参数是否可以通过梯度下降进行更新?
# dtype=torch.float <- PyTorch 默认偏好使用 torch.float32 数据类型
self.bias = nn.Parameter(torch.randn(1, requires_grad=True, dtype=torch.float))
# 1 <- 从随机偏置开始,尝试将其调整为理想偏置
# requires_grad=True <- 该参数是否可以通过梯度下降进行更新?
# dtype=torch.float <- PyTorch 默认偏好使用 torch.float32 数据类型

# 定义模型计算流程的前向传播方法
def forward(self, x: torch.Tensor) -> torch.Tensor: # <- "x" 代表输入数据
return self.weights * x + self.bias # 这就是线性回归公式

本质上来讲,前向传播就是在定义如何从xy,而我们需要管的权重变量也只有两个,即weightsbias

Discussing important model building classes

构建Pytorch模型需要很多重要的类,例如:

  • torch.nn,包含构建计算图的所有组件(神经网络本质上就是一种计算图)。
  • torch.nn.Parameter,定义模型需要学习的参数,通常我们可以直接使用torch.nn中现成的层,这些层会自动为我们设置好这些参数。
  • torch.nn.Module,所有神经网络模块的基类,如果你继承这个类,必须重写forward()方法,该方法定义了反向传播的具体逻辑。
  • torch.optim,Pytorch中优化器的所在地,它们负责协助执行梯度下降。

同时视频作者也给出了一个速查网页

Checking out the internals of our model

我们已经定义好了模型,接下来就可以创建了,实例化LinearRegressionModel,然后使用parameters()方法来查看模型的参数,或者用state_dict方法来查看名称和值一一对应的参数字典。

1
2
3
4
5
6
7
8
9
torch.manual_seed(42)
model_0 = LinearRegressionModel()
list(model_0.parameters())
# [Parameter containing:
# tensor([0.3367], requires_grad=True),
# Parameter containing:
# tensor([0.1288], requires_grad=True)]
model_0.state_dict()
# OrderedDict([('weights', tensor([0.3367])), ('bias', tensor([0.1288]))])

Making predictions with our model

为了检验模型的预测能力,我们来看看模型基于X_test预测y_test的效果如何。当我们向模型直接传入数据时,模型会对数据执行forward方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
y_preds = model_0(X_test)
y_preds
# tensor([[0.3982],
# [0.4049],
# [0.4116],
# [0.4184],
# [0.4251],
# [0.4318],
# [0.4386],
# [0.4453],
# [0.4520],
# [0.4588]], grad_fn=<AddBackward0>)
with torch.inference_mode():
y_preds = model_0(X_test)
y_preds
# tensor([[0.3982],
# [0.4049],
# [0.4116],
# [0.4184],
# [0.4251],
# [0.4318],
# [0.4386],
# [0.4453],
# [0.4520],
# [0.4588]])
with torch.no_grad():
y_preds = model_0(X_test)
y_preds
# tensor([[0.3982],
# [0.4049],
# [0.4116],
# [0.4184],
# [0.4251],
# [0.4318],
# [0.4386],
# [0.4453],
# [0.4520],
# [0.4588]])

这三种不同的调用方式,决定了是否有梯度追踪、计算图构建,并且决定了内存的大小。

  • 直接调用,它会记录forward中的所有操作,构建一个计算图(即输出的grad_fn=<AddBackward0>),以便后续调用.backward()进行反向传播来计算梯度。不过这样会浪费大量的内存,推荐在训练阶段使用,因为此时你可能需要计算梯度来更新权重。
  • 使用torch.no_grad,输出的张量没有grad_fn,节省了梯度追踪带来的开销,但是依旧可能构建了计算图,最好是在旧版代码或者兼容模式下使用,目前已经不推荐使用了。
  • 使用torch.inference_mode,这是专门为推理设计的模式,不仅关闭了梯度追踪,同时完全禁止构建计算图。是目前官方推荐的最佳实践。

接下来,我们把已经计算完的预期值与之前的数据放在一起进行比较并可视化。

1
plot_predictions(predictions=y_preds)

红色点就是预测的值,似乎和那些数据偏差都很大
红色点就是预测的值,似乎和那些数据偏差都很大

Training a model with PyTorch (intuition building)

训练的核心思想,就是让模型从一组未知的参数(随机初始化)逐步演化为一组已知的参数。衡量模型的偏差程度(有多差)的常用方法是使用损失函数。进行训练所使用的核心组件包括:

  • 损失函数,用于衡量模型预测值与真实理想值之间差距的函数,数值越低越好。
  • 优化器(optimizer),根据模型损失调整模型参数(这个模型中就是Weightbias)以降低损失。

配置优化器时,通常需要设置两个关键参数。

  • params,指定需要优化的模型参数,例如params=model_0.parameters()
  • lr,学习率,这是一个超参数,定义了优化器每一步调整参数的幅度。lr越大,调整幅度就越大。

在Pytorch中,我们还需要实现训练循环和测试循环。

Setting up a loss function and optimizer

1
2
3
4
5
6
7
# 设置损失函数
loss_fn = nn.L1Loss()
# 使用L1损失,即MAE,用预测值与真实值之间的平均绝对距离
# 设置优化器,这里采用随机梯度下降法SGD
optimizer = torch.optim.SGD(params=model_0.parameters(), lr=0.01)
# params:指定需要优化的模型参数(此处就是model_0中的所有参数)
# lr = learning rate,即学习率,目前应该是我们可以调节的最重要的超参数。

那么应该选择哪种损失函数和优化器呢?这取决于具体问题,随着经验的积累我们会掌握针对特定问题集,那些方法有效而哪些无效。例如对于这个例子这种简单的回归问题,使用nn.L1Loss作为损失函数配合torch.optim.SGD()优化器就足够了,但是如果是猫狗大战这种分类问题,可能就需要使用nn.BCELoss,即二元交叉熵损失。

PyTorch training loop intuition

一轮训练循环中需要包含以下核心步骤。

  1. 前向传播,让数据流经模型的forward()方法以生成预测结果。
  2. 计算损失,将前向传播的预测结果与真实标签进行对比,计算损失值。
  3. 反向传播,沿着网络反向计算模型各参数相对于损失的梯度。
  4. 优化器更新,利用优化器根据计算出的梯度调整模型参数,以降低损失。

Running our training loop epoch by epoch

知道了如何进行一个训练循环,那么我们就可以尝试对模型进行训练了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
torch.manual_seed(42)
# 一个epoch(轮次)是对整个数据集完整遍历一次,这是我们手动设置的超参数。
epochs = 200
# 记录不同的值,用于后续绘图或分析。
epoch_count = []
loss_values = []
test_loss_values = []

# 训练阶段
# 0. 遍历数据
for epoch in range(epochs):
# 将模型设置为训练模式
model_0.train()
# PyTorch的训练模式会确保所有需要梯度的参数都启用梯度计算
# 1. 前向传播
y_pred = model_0(X_train)
# 2. 计算损失函数
loss = loss_fn(y_pred, y_train)
# 3. 优化器梯度清零
optimizer.zero_grad()
# 4. 执行反向传播,计算模型各参数相对于损失的梯度
loss.backward()
# 5. 优化器步进,执行梯度下降
optimizer.step()
# 默认情况下优化器的参数更新会在循环中累计,因此在下一轮迭代之前必须在第3步清零。
#测试评估阶段
model_0.eval()
# 切换到评估模式,关闭训练特有的设置,例如Dropout和BatchNorm层等
with torch.inference_mode():
# 进入到推理模式
# 1. 执行前向传播
test_pred = model_0(X_test)
# 计算测试损失
test_loss = loss_fn(test_pred, y_test)
# 打印训练进度
if epoch % 10 == 0:
epoch_count.append(epoch)
loss_values.append(loss)
test_loss_values.append(test_loss)
print(f"Epoch: {epoch} | Loss: {loss} | Test loss: {test_loss}")
# Print out model state_dict()
print(model_0.state_dict())

输出的训练进度如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Epoch: 0 | Loss: 0.31288138031959534 | Test loss: 0.48106518387794495
OrderedDict({'weights': tensor([0.3406]), 'bias': tensor([0.1388])})
Epoch: 10 | Loss: 0.1976713240146637 | Test loss: 0.3463551998138428
OrderedDict({'weights': tensor([0.3796]), 'bias': tensor([0.2388])})
Epoch: 20 | Loss: 0.08908725529909134 | Test loss: 0.21729660034179688
OrderedDict({'weights': tensor([0.4184]), 'bias': tensor([0.3333])})
Epoch: 30 | Loss: 0.053148526698350906 | Test loss: 0.14464017748832703
OrderedDict({'weights': tensor([0.4512]), 'bias': tensor([0.3768])})
Epoch: 40 | Loss: 0.04543796554207802 | Test loss: 0.11360953003168106
OrderedDict({'weights': tensor([0.4748]), 'bias': tensor([0.3868])})
Epoch: 50 | Loss: 0.04167863354086876 | Test loss: 0.09919948130846024
OrderedDict({'weights': tensor([0.4938]), 'bias': tensor([0.3843])})
Epoch: 60 | Loss: 0.03818932920694351 | Test loss: 0.08886633068323135
OrderedDict({'weights': tensor([0.5116]), 'bias': tensor([0.3788])})
Epoch: 70 | Loss: 0.03476089984178543 | Test loss: 0.0805937647819519
OrderedDict({'weights': tensor([0.5288]), 'bias': tensor([0.3718])})
Epoch: 80 | Loss: 0.03132382780313492 | Test loss: 0.07232122868299484
OrderedDict({'weights': tensor([0.5459]), 'bias': tensor([0.3648])})
Epoch: 90 | Loss: 0.02788740023970604 | Test loss: 0.06473556160926819
OrderedDict({'weights': tensor([0.5629]), 'bias': tensor([0.3573])})
Epoch: 100 | Loss: 0.024458957836031914 | Test loss: 0.05646304413676262
OrderedDict({'weights': tensor([0.5800]), 'bias': tensor([0.3503])})
Epoch: 110 | Loss: 0.021020209416747093 | Test loss: 0.04819049686193466
OrderedDict({'weights': tensor([0.5972]), 'bias': tensor([0.3433])})
Epoch: 120 | Loss: 0.01758546754717827 | Test loss: 0.04060482233762741
...
Epoch: 180 | Loss: 0.00893248151987791 | Test loss: 0.005023092031478882
OrderedDict({'weights': tensor([0.6951]), 'bias': tensor([0.2993])})
Epoch: 190 | Loss: 0.00893248151987791 | Test loss: 0.005023092031478882
OrderedDict({'weights': tensor([0.6951]), 'bias': tensor([0.2993])})
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...

Writing testing loop code

我们绘制一下损失曲线看看是什么样的。

1
2
3
4
5
6
plt.plot(epoch_count, np.array(torch.tensor(loss_values).numpy()), label="Train loss")
plt.plot(epoch_count, test_loss_values, label="Test loss")
plt.title("Training and test loss curves")
plt.ylabel("Loss")
plt.xlabel("Epochs")
plt.legend();

这个损失其实就很低了
这个损失其实就很低了

对比训练之后的权重,已经和真实值非常接近了。同时我们画出训练之后模型的预测值的图片。

1
2
3
4
5
6
7
model_0.state_dict()
# OrderedDict([('weights', tensor([0.6990])), ('bias', tensor([0.3093]))])
weight, bias
# (0.7, 0.3)
with torch.inference_mode():
y_preds_new = model_0(X_test)
plot_predictions(predictions=y_preds_new);

可以看出数据是非常接近的了
可以看出数据是非常接近的了

Saving/loading a model

在PyTorch中保存和加载模型,需要掌握下面三种核心方法。

  • torch.save(),将PyTorch对象以Python的pickle序列化格式进行保存。
  • torch.load(),加载已保存的PyTorch对象。
  • torch.nn.Module.load_state_dict(),加载模型已保存的状态字典。

接下来我们对已经训练好的模型进行保存。

1
2
3
4
5
6
7
8
9
10
11
from pathlib import Path
# 创建模型目录
MODEL_PATH = Path("models")
MODEL_PATH.mkdir(parents=True, exist_ok=True)
# 创建模型保存目录
MODEL_NAME = "01_pytorch_workflow_model_0.pth"
MODEL_SAVE_PATH = MODEL_PATH / MODEL_NAME
# 保存模型状态字典
print(f"Saving model to: {MODEL_SAVE_PATH}")
# Saving model to: models/01_pytorch_workflow_model_0.pth
torch.save(obj=model_0.state_dict(),f=MODEL_SAVE_PATH)

我们保存的是模型的状态字典,而非整个模型,因此如果要加载这个模型,我们需要重新实例化一个类,并将保存好的state_dict()加载到这个新实例中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
loaded_model_0 = LinearRegressionModel()
loaded_model_0.load_state_dict(torch.load(f=MODEL_SAVE_PATH))
loaded_model_0.state_dict()
# OrderedDict([('weights', tensor([0.6990])), ('bias', tensor([0.3093]))])
# 用加载的新模型来预测
loaded_model_0.eval()
with torch.inference_mode():
loaded_model_preds = loaded_model_0(X_test)
loaded_model_preds
# tensor([[0.8685],
# [0.8825],
# [0.8965],
# [0.9105],
# [0.9245],
# [0.9384],
# [0.9524],
# [0.9664],
# [0.9804],
# [0.9944]])
# 让原版模型也预测一下看看二者相不相等
model_0.eval()
with torch.inference_mode():
y_preds = model_0(X_test)
y_preds == loaded_model_preds
# tensor([[True],
# [True],
# [True],
# [True],
# [True],
# [True],
# [True],
# [True],
# [True],
# [True]])

执行的时候它会弹出一个FutureWarning,在将来在使用torch.load方法时,会默认将waights_only参数设为true,也就是说让这个方法只能加载张量和基本数据结构,禁止执行代码。

Putting everything together

最后,PyTorch已经有了现成的线性模型供我们使用。我们采用真实的线性模型重新写一次。

真实的线性模型即nn.Linear,他接受两个必须的构造参数:in_featuresout_features,是输入样本和输出样本的大小。完整的训练和可视化代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 我们从头来训练一个Linear模型。
# 假设真实值是y=0.5x+0.2,两个参数分别是k和b
import torch
from torch import nn
import matplotlib.pyplot as plt

device = "cpu"
X = torch.arange(0,100,0.2,dtype=torch.float32).unsqueeze(1)
true_k = 0.5
true_b = 0.2
Y = X*true_k + true_b
train_size = int(X.size()[0] *0.8)
train_X = X[:train_size].to(device)
train_Y = Y[:train_size].to(device)
test_X = X[train_size:].to(device)
test_Y = Y[train_size:].to(device)
epochs = 200
loss_values = []

class TestLinearModel(nn.Module):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
# 我们的模型只需要一个线性层就可以了,他就有这两个参数,不需要再动了
self.linear_layer = nn.Linear(in_features=1, out_features=1)
def forward(self, x:torch.Tensor):
return self.linear_layer(x)

model = TestLinearModel().to(device)
loss_fn = nn.L1Loss()
optimizer = torch.optim.SGD(params=model.parameters(),lr=0.01)
for epoch in range(epochs):
model.train()
pred_Y = model(train_X)
loss = loss_fn(pred_Y, train_Y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch %10 ==0:
loss_values.append(loss)
print(f"Epoch:{epoch},Loss:{loss},State:{model.state_dict()}")

model.eval()
with torch.inference_mode():
pred_Y = model(test_X)
def plot_predictions(train_data=train_X,train_labels=train_Y,test_data=test_X,test_labels=test_Y,predictions=pred_Y):
"""
可视化训练集、测试集数据,并对比模型预测结果。
"""
plt.figure(figsize=(10, 7))
# 绘制训练数据(蓝色)
plt.scatter(train_data, train_labels, c="b", s=4, label="Training data")
# 绘制测试数据(绿色)
plt.scatter(test_data, test_labels, c="g", s=4, label="Test data")
# 检查是否存在预测值
if predictions is not None:
# 若存在,则绘制预测结果(红色)
plt.scatter(test_data, predictions, c="r", s=4, label="Predition")
# 显示图例
plt.legend(prop={"size": 14})
plot_predictions()

输出的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Epoch:0,Loss:59.06752395629883,State:OrderedDict({'linear_layer.weight': tensor([[-0.5922]]), 'linear_layer.bias': tensor([0.6444])})
Epoch:10,Loss:4.604989528656006,State:OrderedDict({'linear_layer.weight': tensor([[0.2046]]), 'linear_layer.bias': tensor([0.6625])})
Epoch:20,Loss:4.547124862670898,State:OrderedDict({'linear_layer.weight': tensor([[0.2032]]), 'linear_layer.bias': tensor([0.6605])})
Epoch:30,Loss:4.489261150360107,State:OrderedDict({'linear_layer.weight': tensor([[0.2018]]), 'linear_layer.bias': tensor([0.6585])})
Epoch:40,Loss:4.431396484375,State:OrderedDict({'linear_layer.weight': tensor([[0.2004]]), 'linear_layer.bias': tensor([0.6565])})
Epoch:50,Loss:4.373531341552734,State:OrderedDict({'linear_layer.weight': tensor([[0.1990]]), 'linear_layer.bias': tensor([0.6545])})
Epoch:60,Loss:4.315667152404785,State:OrderedDict({'linear_layer.weight': tensor([[0.1976]]), 'linear_layer.bias': tensor([0.6525])})
Epoch:70,Loss:4.257802963256836,State:OrderedDict({'linear_layer.weight': tensor([[0.1962]]), 'linear_layer.bias': tensor([0.6505])})
Epoch:80,Loss:4.19993782043457,State:OrderedDict({'linear_layer.weight': tensor([[0.1948]]), 'linear_layer.bias': tensor([0.6485])})
Epoch:90,Loss:4.142073154449463,State:OrderedDict({'linear_layer.weight': tensor([[0.1934]]), 'linear_layer.bias': tensor([0.6465])})
Epoch:100,Loss:4.084209442138672,State:OrderedDict({'linear_layer.weight': tensor([[0.1920]]), 'linear_layer.bias': tensor([0.6445])})
Epoch:110,Loss:4.026343822479248,State:OrderedDict({'linear_layer.weight': tensor([[0.1906]]), 'linear_layer.bias': tensor([0.6425])})
Epoch:120,Loss:3.968479871749878,State:OrderedDict({'linear_layer.weight': tensor([[0.1892]]), 'linear_layer.bias': tensor([0.6405])})
Epoch:130,Loss:3.9106154441833496,State:OrderedDict({'linear_layer.weight': tensor([[0.1878]]), 'linear_layer.bias': tensor([0.6385])})
Epoch:140,Loss:3.8612771034240723,State:OrderedDict({'linear_layer.weight': tensor([[0.1866]]), 'linear_layer.bias': tensor([0.6366])})
Epoch:150,Loss:3.817622184753418,State:OrderedDict({'linear_layer.weight': tensor([[0.1855]]), 'linear_layer.bias': tensor([0.6349])})
Epoch:160,Loss:3.773967981338501,State:OrderedDict({'linear_layer.weight': tensor([[0.1845]]), 'linear_layer.bias': tensor([0.6331])})
Epoch:170,Loss:3.730314016342163,State:OrderedDict({'linear_layer.weight': tensor([[0.1834]]), 'linear_layer.bias': tensor([0.6314])})
Epoch:180,Loss:3.686659812927246,State:OrderedDict({'linear_layer.weight': tensor([[0.1824]]), 'linear_layer.bias': tensor([0.6296])})
Epoch:190,Loss:3.6430046558380127,State:OrderedDict({'linear_layer.weight': tensor([[0.1813]]), 'linear_layer.bias': tensor([0.6279])})

最后的预测结果可视化如下

这个k学的很不错,但是b总是有问题
这个k学的很不错,但是b总是有问题

我们牢记整个训练的流程:前向传播(预测数据),计算损失函数,反向传播,更新梯度。

总结

本次内容是视频课程的Chapter 1部分,我们了解了用torch进行模型训练的大致流程,一个模型最主要的就是层结构、损失函数和优化器。我们以一个非常简单的ground_truth线性模型来跑通了整个流程,在接下来我们或许还会学习其他的神经网络,那么这里的知识就是使用PyTorch的基本功。

  • 标题: PyTorch for Deep Learning & Machine Learning – Full Course(2) - NoTe0x007
  • 作者: Baobao0824
  • 创建于 : 2026-06-03 15:30:47
  • 更新于 : 2026-06-04 14:20:53
  • 链接: https://blog.baobao0824.top//学习笔记NoTe/NT-0x007/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论