PyTorch for Deep Learning & Machine Learning – Full Course(1) - NoTe0x006
写在前面
这一系列是我在学习他人的优质课程(博客文章、视频课程等)时所做的学习笔记,根据我自身的水平来进行学习,同时会进行思维的发散,补充原文中没有提到或者有错误的地方。同时也会进行经常性的更新和整理,让它和我的当下的状态更加契合。
最近在弄百度的比赛,所以必须把我的AI技能提上日程了。我必须要好好掌握机器学习的主要流程,能够自己不借助AI,从头训练一个模型,我觉得这才是达到目的了。
基本概念介绍
Welcome and “what is deep learning?”
机器学习是将数据变成数,然后去寻找这些数中的模式。那么如何找到这些模式呢,就是各种算法了。
而深度学习是机器学习的一个子集,pytorch经常用来写深度学习代码,但是它也可以写一些机器学习的代码。作者用做烤鸡举例:传统编程是给你原材料和规则,让你输出一个烤鸡;而机器学习算法是给你原材料和烤鸡,让你发现做烤鸡的规则。
Why use machine/deep learning?
为什么我们要用机器学习或者深度学习呢?对于一个过于复杂的问题,你能想出所有的规则吗?例如我们想造一辆自动驾驶的汽车,让你写出所有驾驶规则,即使你开了很长时间的车,你还是列举不完,毕竟规则实在是太多了。视频作者用了一个用户的评论:它可以量化宇宙中的一切事物。他还分享了一本叫做《Google’s Machine Learning Handbook》的书,等到我以后有机会就拿去读吧。
The number one rule of ML
什么时候要用机器学习呢?那首先就是传统方法失效的时候,深度学习就可能有帮助。还有就是环境持续变化,它可以学习新的场景,未来根据需要进行调整。或者你有很大的数据集,
什么场景是典型的不适合使用机器学习的地方呢?首先是你需要可解释性的地方;其次是传统方法更好的时候;还有就是当错误不可接受的时候;最后就是当时没有足够数据的时候。
Machine learning vs deep learning
机器学习适合成列的表格数据,也就是结构化数据;而深度学习适合非标准化的数据,也就是各种不同的数据例如图片、自然语言之类的。
一些适合结构化数据的典型算法有(在深度学习出现之后,这些都被称作浅层算法):
- 随机森林
- 梯度提升模型
- 朴素贝叶斯
- 最近邻
- 支持向量机
深度学习的典型方法有下面这些:
- 神经网络
- 全连接神经网络
- 卷积神经网络CNN
- 循环神经网络RNN
- Transformer
Anatomy of neural networks
作者没直接下定义,而是让你google一下到底什么是神经网络,他还推荐了3b1b的视频,有很多种自己的定义。
数据在进入神经网络之前,会被转化成各种数,即数值编码;然后将他们传入神经网络。各种不同的神经网络都遵循输入、操作、输出这三部分,而神经网络会自己学会这些表征。最终输出一个权重,我们可以将这个权重转化为人类能够理解的格式。
神经网络分为三部分:输入层、隐藏层和输出层。隐藏层的数量不一,例如Resnet152,总共有152个隐藏层。每一层的神经元数量也可以不一样。例如视频作者给出的网络,输入层有2个神经元,隐藏层有3个而输出层有一个。一般我们谈论神经网络的架构,指的就是这个层数和神经元数量。每一层之间都用线性或(和)非线性的函数相结合。

Different learning paradigms
深度学习有不同的范式。
首先是监督学习。当你有数据和标签的时候可以用监督学习,例如做烤鸡的例子,你有大量的原材料(数据),还有很多正确的输出示例。再比如猫狗大战,你有很多张猫狗的照片,而且你知道一张照片是猫还是狗。
然后是无监督/自监督学习,是你拥有数据本身,但是没有标签,例如猫狗大战中,你只有猫狗的照片,而不知道他们哪张是猫哪张是狗。
最后是迁移学习,借鉴一个模型中学到的范式,然后将数据集转移到另一个模式。例如我们有一个猫狗大战的监督学习模型,我可以把这个转移到我们自己的模型中。
还有一个作者没提到的范式就是强化学习,是agent和环境交互,环境根据agent的动作给出奖赏让agent继续学习。
本视频主要关注的两个内容就是监督学习和迁移学习。
What can deep learning be used for?
深度学习会用在什么方面?这个问题简直是太水了。我只知道transformer是深度学习,那么这就说明只要想碰transformer都要先弄明白深度学习。不过作者还是给了我们一些使用深度学习的场合。
- 推荐系统(不得不说油管的推荐系统确实很烂)
- 机器翻译
- 语音识别
- 计算机视觉(YOLO是吧)
- NLP
深层次来讲,机器翻译和语言识别是seq2seq,因为你输出一个序列,然后输出一个序列。而计算机视觉和NLP是分类回归,他预测了一个问题,例如判断一个邮件是否是垃圾文件。
What is/why PyTorch?
什么是pytorch?他直接给出了一张图
- 最受欢迎的研究型深度学习框架
- 用 Python 编写高效的深度学习代码(可在单个 GPU/多个 GPU 上运行)
- 能调用众多预训练深度学习模型(Torch Hub / torchvision.models)
- 全流程覆盖:数据预处理、模型构建、在应用/云端部署模型
- 最初由 Facebook/Meta 内部设计并使用(现已开源,特斯拉、微软、OpenAI 等企业也在采用)
视频作者还推荐了一个网站,叫做code with papers,这是一个用来追踪机器学习论文代码的网站,你可以用它来看各个论文中给出的代码。说实话现在有这么好的深度学习框架,完全不需要从头开始搭建,很多东西你都可以先放一放,例如transformer到底为什么这么做之类的(我感觉)。
他还介绍了一下GPU和TPU,GPU我们都知道这里不赘述了;而TPU是Tensor Processing Unit,在现在的通用场景中显然GPU更好用,毕竟个人用户不可能搞TPU过来。
What are tensors?
什么是Tensor,让我先去问一下AI。从数学的本职上来说,他就是一个n维的数组,有多个轴(只有2个轴的你才能称之为矩阵),在pytorch中它给多维数组套了一层功能壳,除了存储原始数值,还会存储数据类型、存储位置和计算属性等。本视频的作者给出的定义,它就是任何数据的数字表述形式。
同时视频作者给出了一个典型的pytorch工作流程。

- 准备数据
- 构建或选择一个预训练模型;选择损失函数和优化器;构建训练循环
- 将模型拟合到数据并做出预测
- 评估模型
- 通过实验改进
- 保存并重新加载训练好的模型
Important resources
在正式开始代码之前,作者也介绍了一些重要的基本资源
如果要写代码的话,可以直接从资源中下载对应的jupyter notebook。
Getting setup
他介绍了 google colab网站,这是一个在线使用Jupyter notebook的地方,同时会给你免费的GPU和NPU来使用。由于我不需要在线使用,那么我就在本地使用,毕竟我手里有conda环境,这个还是在毕设的时候弄得,如果这个模型不支持mps的话,我就会在那上面跑。项目中的SETUP.md也给了安装的方法。不过我就不需要看了,这些环境还是不会难倒我的。
1 | import torch |
我们当前环境的torch版本是2.5.1,远大于视频的1.10.0,不过大多数的基础操作应该还是没问题的。如果有问题的话就再去看看最新的代码怎么弄,毕竟现在也不需要AI来帮我生成代码了,这说明我根本没理解,也没看懂训练代码应该怎么做。
张量的基础操作
Introduction to tensors
Tensor是深度学习的基本模块和数据的基础。首先我们可以创建一个标量(scalar)也就是没有任何维度的数字。
1 | scalar = torch.tensor(7) |
直接输出scalar,可以发现他是tensor(7)也就是一个标量7。
同时视频作者把Tensor的官方文档放在这里了,如果你需要查阅的话点击这个链接就可以了。
那么一个标量有哪些属性呢?在本系列的文档中,尤其是涉及到jupyter notebook的,如果碰见一个单个的变量,那么下一行注释就是他的值。
1 | scalar.ndim |
item方法可以把一个Tensor转换为普通的python类型,例如这个标量中的int。
1 | scalar.item() |
接下来我们创建一个向量。
1 | vector = torch.tensor([7,7]) |
看一下这个向量的维度
1 | vector.ndim |
为什么只有一个维度呢?这是因为他是一个一维的数组,和0相比较而言,他不是一个点而是一条线,这解释了为什么维度是1。
shape方法可以看它的形状。
1 | vector.shape |
看维度有一个更简单的方法就是看方括号的对数,而这里的形状是2*1,所以是2。
接下来我们再尝试创建一个矩阵
1 | MATRIX = torch.tensor([ |
根据方括号的对数,我们很容易发现他是二维的,真的是这样吗?
1 | MATRIX.ndim |
事实上还真是这样,那么假如我给他一个一维的索引会输出什么呢?
1 | MATRIX[0] |
那么这个矩阵的形状我们也应该非常清楚了,会是2*2。
1 | MATRIX.shape |
虽然刚才的那些变量维数各不相同,但是全都是Tensor类型的变量。接下来我们再看看真正的3维的Tenser。
1 | TENSOR = torch.tensor([[[1, 2, 3], |
很显然,这个张量的维度是3维。
1 | TENSOR.ndim |
那么他的形状是怎么样的?是$3 \times 3 \times 1$还是$1 \times 3 \times 3$?
1 | TENSOR.shape |
很显然,最外面一层中括号里面只有一个中括号,所以第一维的大小是1,而不是3,那么他的第一维就应该是那个矩阵,真的是这样的吗?
1 | TENSOR[0] |
还真的是这样。这里有一张图片来解释这件事。

你可以这么理解,维度数越大,取的方括号的层数越深。我觉得其实还是挺好理解的。只要你想的话,你甚至还可以这么操作
1 | TENSOR[0][1][2] |
取的是0层矩阵的第1个行和第2个列,那么就是9(在本网站中当我用阿拉伯数字的时候是0开始,用汉字数字的时候是从一开始)
在推荐的标准中,矩阵和张量变量的命名最好是大写,而标量和向量是小写的则最好。
Creating tensors
接下来我们介绍一下随机张量。为什么要用随机张量?因为许多神经网络的学习方式是从随机张量开始,然后调整这些随机数来更好的表示数据。随机数->查看数据->更新随机数->查看数据->更新随机数…
那么如何创建一个随机张量呢?假设我们要创建一个3乘4大小的随机张量。
1 | random_tensor = torch.rand(3,4) |
接下来我们可以尝试创建一个形状类似于图像张量的随机张量,例如
1 | random_image_size_tensor = torch.rand(size=(3, 224, 224)) |
关于图像张量的直观展示就像下面的图片。

接下来我们看全0和全1张量。
1 | zeros = torch.zeros(size=(3, 4)) |
还有一个重要的参数我们还没看,就是数据类型。
1 | ones.dtype |
除非我们指定,否则默认创建的张量数据类型就是torch.float32
接下来我们如何创建一个范围张量呢?
1 | one_to_ten = torch.arange(start=1, end=11, step=1) |
注意到,它的区间是左闭右开,这些参数都很常见,这里不再赘述了。
假如说我们有一个特定的张量形状,想在别的地方复制,但是你不记得到底是什么形状,就可以使用这种like方法。
1 | ten_zeros = torch.zeros_like(input=one_to_ten) |
Tensor datatypes
假如说我们让张量的类型为None,会发生什么事情?可以尝试一下。
1 | float_32_tensor = torch.tensor([3.0, 6.0, 9.0],dtype=None) |
结果还是torch.float32,这是因为float32是pytorch的默认数据类型,即使指定为None,也会将其设为float32。那么除了float32,别的是不是可以的?假设我们给换成了float16可以吗,显然是可以的。
1 | float_32_tensor = torch.tensor([3.0, 6.0, 9.0],dtype=torch.float16) |
作者说初学pytorch和深度学习最常见的三个错误就是:
- 张量数据类型不对
- 张量形状错误
- 张量不在正确的设备中
除了dtype参数,我们还有两个最重要的参数,分别是device和requires_grad。
device代表你要使用这个张量的设备。默认情况下,设备是cpu如果你有CUDA环境就可以把设备改成cudarequires_grad参数代表你是否需要进行梯度追踪。
我们如何改变已有张量的数据类型呢。假设我们要把float32转为float16,可以这样做:
1 | float_16_tensor = float_32_tensor.type(torch.float16) |
当然,数据类型除了不同的float,还有整数类型。
1 | int_64_tensor = torch.tensor([3, 6, 9], dtype=torch.long) |
如果我们把两个不同类型的张量相乘,他们的结果是什么类型呢?我们可以测试一下:
1 | result_a = float_32_tensor * int_64_tensor |
这样看来,规则大抵就是全部转成两边精度最高的那个类型(颇有以前学习C语言时候的感觉了)不过在模型训练的时候,我们最好还是保证数据类型的一致性。
Tensor attributes (information about tensors)
针对刚才的三个问题,我们在检查张量的属性的时候就有三个重要的属性可以来看。
- 张量数据类型不对:
dtype - 张量形状错误:
shape - 张量不在正确的设备中:
device
例如我们随便找个张量。
1 | some_tensor = torch.rand(3, 4) |
Manipulating tensors
张量的运算包括:
- 加
- 减
- 按元素数乘
- 除
- 矩阵乘法
1 | tensor = torch.tensor([1, 2, 3]) |
作者更推荐我们直接使用运算符号而不是方法,因为这样看起来更加的直观。
Matrix multiplication
在这一节中它会教我们很多矩阵的运算。矩阵的点乘我是不需要他来教的。
首先,我们有矩阵的按元素乘法,就是让两个同样大小的矩阵的对应元素相乘得出结果。
1 | tensor * tensor |
对于矩阵乘法来说,有一个专门的运算符@,不过我们也可以用torch.matmul方法。
1 | torch.matmul(tensor, tensor) |
在pytorch中,一维张量相乘的结果其实是向量的点积,没有行向量与列向量之分。如果你想要达到真正的矩阵乘法,你需要让两个张量都是二维的。
1 | tensor_a = torch.randn(size=(3,1)) |
这个东西才是真正的矩阵乘法。
作者同样给我们演示了一下,pytorch自带的方法要比自己手动实现要快得多,那是肯定的毕竟python本身是C语言写的,直接用C语言写的方法肯定是更快的。
1 | %%time |
torch.mm也可以用作矩阵乘法的简写,不过一维张量是不能用的(那我用@岂不是更简单)。
1 | torch.mm(tensor,tensor) |
作者提醒我们注意矩阵乘法中的维度,也就是行和列,对于学过考研数学线性代数的人来说,这个根本就不是问题。同时他也为我们推荐了一个网站,可以方便的计算矩阵乘法。
同时作者在这里介绍了矩阵的转置,我们已经用过了,不再需要他介绍了,直接跳到下一个片段。
Finding the min, max, mean & sum
先创建本节需要用到的张量。
1 | x = torch.arange(1, 100, 10) |
最大值和最小值都可以通过两种方式,一个是torch下面的方法,一个是张量下面的方法
1 | torch.min(x), x.min() |
平均值应该也是遵循一样的原则,我们就试试看。
1 | torch.mean(x), x.mean() |
居然不行哎,他必须要float或者复数才能求平均值,因此我们需要转一下数据类型。
1 | torch.mean(x.type(torch.float32)), x.type(torch.float32).mean() |
最后是求和。
1 | torch.sum(x), x.sum() |
那么我们想知道,到底最小值和最大值出现在哪个下标中呢?,我们需要借助argmin和argmax方法。
1 | x.argmin(), x.argmax() |
的确是最小值和最大值,这个东西感觉比min和max要更加的好用。为了保持API的一致性,pytorch几乎所有的操作返回的都是tensor,这样可以方便进行运算,这也是为什么这两个方法不返回int。
Reshaping, viewing and stacking
这一节我们会学习和形状相关的方法,包括:
- reshape,将输入张量调整为指定的形状。
- view,返回一个具有特定形状的输入张量的视图,但该视图与原张量共享内存。
- stacking,将多个张量在垂直方向(vstack)或水平方向(hstack)上进行组合。
- squeeze,移除张量中所有维度为1的维度。
- unsqueeze,在目标张量中增加一个维度为1的维度。
- permute,返回输入张量,其维度按照特定方式进行了重新排列(交换)
首先我们先定义这一节需要用到的张量x。
1 | x = torch.arange(1., 10.) |
我们先尝试使用reshape,最简单的使用方式是给张量添加一个维度,或者也可以将它变成其他的形状。
1 | x_reshaped = x.reshape(1, 9) |
只要保证它的尺寸能够符合最后有9个元素就可以,不管是1乘9还是3乘3都可以办得到,注意到reshape方法不改变原来变量的值。
接下来我们尝试使用view函数。
1 | z = x.view(1, 9) |
看起来似乎都差不多啊,到底有什么区别呢?区别就在于reshape可能会隐式的复制数据,而view要求张量在内存上连续。在实践中还是推荐首先使用reshape(毕竟你都搞深度学习了,还管内存干嘛)。
作者使用了一个例子来说明共享内存。现在我们改变z中的元素,再看看x的元素有没有变化。
1 | z[:, 0] = 5 |
这个变化是我没想到的,改变了z的元素,x中对应的元素也会改变,即使他们形状不同。
接下来我们看stack方法是如何使用的。
1 | x_stacked = torch.stack([x, x, x, x], dim=0) |
在第0个维度上相加,竖着叠出了4行的x张量,在第1个维度上相加,那就是把x竖过来放了。对于向量之间的叠加,就只能在0和1维上进行。可能你以为vstack和hstack只是stack方法在dim取0或1时的特例罢了吗,但是事实真的是这样吗?
1 | x_stacked = torch.vstack([x,x,x]) |
注意到,竖直的叠放其实是从上往下叠放,而hstack则是从左往右叠放,在向量中不会出现类似于上面dim=1时的stack方法。实际上,stack方法要求所有的输入张量必须是完全相同的形状,而且输出维度比输入维度多一维。使用stack方法,当dim=1时,要将原来的形状为(9,)的张量的第1维插入4,最终的张量形状就变成了(9,4)。
我们再使用一个2维的矩阵,来感受一下。
1 | t_a = torch.arange(0,6).reshape(2,3) |
下面这两张图分别是dim等于1和2时候的效果:


这些图片都是用TorchCat生成的。
Squeezing, unsqueezing and permuting
接下来我们来看剩下的方法。squeeze方法可以清除掉张量中所有的单维空间。例如
1 | x_reshaped, x_reshaped.shape |
对应的,unsqueeze方法会在对应的位置添加一个单维。
1 | x_squeezed, x_squeezed.shape |
最后是permute方法,他能够将张量按照你想要的维度来重排。同时这只是一种视角变换,两个张量是共享内存的。例如:
1 | x_original = torch.rand(size=(5, 4, 3)) |
Selecting data (indexing)
这一节中我们学习如何选取数据,就是如何正确的使用pytorch的下标。如果你用过numpy的话,你会发现这二者使用下标其实是差不多的。先介绍一下我们本节要用到的张量。
1 | x = torch.arange(1, 10).reshape(1, 3, 3) |
根据你中括号的多少,决定了你是在选择第0维度、第1维还是第2维。
1 | x[0] |
你可以用:来选择一个维度里面所有的元素。
1 | x[0,:, 1] |
其他基础操作
PyTorch and NumPy
pytorch和Numpy可以进行很好的互动,二者之间的数据可以互转。
- 想把numpy中的数据转成torch,使用
torch.from_numpy()。 - 想把torch张量转成numpy数据,使用
torch.Tensor.numpy()。
1 | import torch |
注意到转换之后的张量数据类型是float64,因为这是numpy的默认数据类型。
把torch张量转成numpy数组也是同样的。注意到转换之后的数组数据类型是float32,这说明二者互转的时候都不会变动对面的数据类型,原先的数据类型是啥转过来之后还是啥。
1 | tensor = torch.ones(7) |
同时,这两个变量并不共享同一块内存。例如:
1 | array = array + 1 |
Reproducibility
为了保证实验可复现,我们需要降低随机性。他在介绍随机种子。神经网络的工作模式是:从随机数开始->张量操作->更新这些数让他们更好的代表数据->继续…
1 | random_tensor_A = torch.rand(3, 4) |
因此我们需要自己设置随机种子。
1 | RANDOM_SEED = 42 |
当然了,如果你忘了更新随机种子的话,同一个种子产生的两个不同变量依旧是不相等的,我怀疑是你每次十三薪设置种子就会将随机数生成器的历史清空,这样他生成的永远是这个种子的第一个随机数。
1 | RANDOM_SEED = 42 |
Accessing a GPU
在这一节我们将学习如何在GPU上运行pytorch以加快运行速度。在没有CUDA出现之前可以说神经网络远没有现在这么发达,用显卡计算神经网络真是一个天才的想法。
首先先看看怎么获取GPU。有以下几种方法:
- 最简单:使用Google Colab以获取免费GPU,这是本视频作者使用的方式。
- 用自己的显卡:需要一些设置,并且你需要掏钱,有很多选项,如果我以后有钱我可能真的会掏钱买一个本地跑的大模型(突然想起来视频发布的年代还没有大模型,还是挺令人感叹的,时间过得真快,我已经不知道在没有大模型之前到底是如何工作和学习的了)。
- 使用云计算:例如GCP,AWS,Azure。可惜我只知道autodl。
在本系列教程中我应该就直接用mps了,毕竟也不跑很大的模型,直接这么用就行了。
在命令行中,查看你的英伟达显卡配置使用的是nvidia-smi命令,想要在jupyter notebook中使用命令行的话,只需要在命令前面加一个!即可。
1 | !nvidia-smi |
作者使用的是 Tesla T100,这个显卡说实话我都没听过。我也好奇那些算力集群里用的是公版显卡还是厂商自定的显卡。
查看你的环境中是否能使用CUDA(或者mps),只需要下面这个方法:
1 | torch.cuda.is_available() |
在日常写的时候,我们总是希望能够写出设备无关的代码,所以标准的设备无关变量就是这样的。
1 | device = "cuda" if torch.cuda.is_available() else "cpu" |
你也可以通过方法来查看自己当前环境下的GPU数量。
1 | torch.cuda.device_count() |
pytorch官网在这里给出了一份最佳实践,非常适合单文件脚本运行的时候使用。
1 | import argparse |
Setting up device agnostic code
在这节我们来看如何实际使用这块显卡。在默认创建变量的时候,张量都是在CPU中的,我们可以通过查看device字段来查看它在哪个设备上运算。
1 | tensor = torch.tensor([1, 2, 3]) |
那么如何将张量移动到对应的设备上呢?也非常的简单,直接用to方法即可,如果设备不存在的话它就会直接报错了。
1 | tensor_on_gpu = tensor.to(device) |
当张量在GPU上时,是不能将其转为numpy数组的,因为它存在了显存中,而numpy变量是进不了显存的,都存在了内存中。当出现这种情况的时候,只需要将其复制到cpu就好了,使用cpu()方法即可。
1 | tensor_on_gpu.numpy() |
总结
这一部分是视频的Chapter 0,讲了很多的基础操作,为接下来的正式流程做了铺垫。但是视频上讲的东西都有,同时视频节奏又太慢,所以接下来我就不看视频了,直接看对应的notebook了。
- 标题: PyTorch for Deep Learning & Machine Learning – Full Course(1) - NoTe0x006
- 作者: Baobao0824
- 创建于 : 2026-06-02 14:32:30
- 更新于 : 2026-06-02 14:32:30
- 链接: https://blog.baobao0824.top//学习笔记NoTe/NT-0x006/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。