📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

PyTorch và ứng dụng cài đặt bài Linear, Logistic và Softmax Regression

AI VIET NAM2:45:06

Transcription

那么,我们开始吧。今天,我们将使用一个Python,一个新框架来安装我们之前用NumPy非常辛苦完成的东西。那么,从你们走工程方向的角度来看,你们会觉得,哦,为什么我们突然要去做那些辛苦的事情呢?为什么我们不直接学习这个呢?那么,在普通工程级别,普通工程师可能会觉得,好吧,那时我可能只能做一些初级的工作,但当我达到更高层次时,我需要构建大型系统,我需要更深入地理解,很多时候我需要改变它,以使其适合我的系统响应,所以那时我需要非常深入地理解,理解很多。所以很多时候,以前,研究和工程是分开的,那时这两个方向非常不同。而现在,它根本没有分开。现在,如果你想进入大公司工作,你必须至少有一篇顶级的论文,他们才会接受你进去做普通的工程师,各位。所以,你们可以尝试搜索那些大公司,这里的大公司不仅仅是像韩国的三星、现代或Facebook那样的老牌公司,甚至包括那些真正意义上想要创造产品的初创公司。因为初创公司必须创造产品并与那些大公司竞争。所以那时产品必须达到世界水平,这时他们会招聘最优秀的人才,专门针对那个领域,那个区域。他们的CEO,他们的领导者会绘制一张包含许多组件的地图,然后他们会招聘最优秀的人。世界第一是不可能的,但要成为符合标准、能做好那部分工作的最优秀人才之一,如何才能达到标准呢?那就很简单,只要有顶级的论文就行了。所以,以前在韩国找工作的时候,刚毕业想找工作时,调查发现就是这样,所以研究和工程之间的距离并不像以前那样遥远,所以如果我们只学表面知识,我们是走不远的,即使我们在公司工作也是如此。所以,这就是为什么我必须站稳脚跟,做很多举重和俯卧撑的原因。在使用这个之前,我觉得非常轻松。好的。今天我们来看看它有多轻松。我们来试试。

那么,今天我们将讨论Python,然后将其应用于我们迄今为止所学的知识,包括线性回归、逻辑回归和softmax回归。那么,现在我们来看看PyTorch是怎样的。PyTorch是由Meta内部的一个团队创建的,该团队的负责人是Jen Colon先生,他即将退休。现在,当前的版本就是这个版本。所以你们可以在Windows和Mac上使用它,但通常在研究中,大家更常在这个操作系统上使用它。那么,当你们安装时,不要安装最新的版本,因为很多时候最新的版本,例如选择最新的操作系统,选择最新的CUDA,可能并不总是最好的,各位。我们应该选择稍微旧一点的版本,它们更稳定。因为每个版本发布时都有其差异,很多时候它与旧版本不同。所以很多系统选择了一个CUDA版本,然后他们深入了解那个CUDA,并且喜欢与那个CUDA兼容。所以很多时候我们也不需要选择最高级的那个。

那么,其他同学听得清楚吗?小战听得不太清楚。那么其他同学还好吗?有没有掉线呢,各位?好的。那么小战请检查一下你那边的网络,其他同学。好的。那么PyTorch有什么呢?其实它没什么特别的。我们有NumPy。NumPy是在CPU加上RAM上运行的。而这个设计不同,它不能很好地并行运行,所以我们才有了GPU显卡。它里面包含了内存和处理器。所以NumPy只能在这个上面运行。所以现在如果想在下面运行,让它能够训练一个大型模型并进行大量并行计算,我们就需要学习PyTorch,其实它的语法和NumPy非常相似。如果NumPy也能在这里运行,那谁还会创建PyTorch呢?所以创建PyTorch的原因就是因为NumPy不能运行。所以我们会发现PyTorch和NumPy非常相似。它唯一的区别是NumPy中我们称之为array,而PyTorch中称之为tensor。所以我们将导入一个名为torch的库。Torch就是那个火炬。然后p是这个在Python语言中安装的。它就在这个库里面。然后我们调用tensor,传入一个列表,它会返回给我们一个tensor,对吗?然后,小德也觉得卡顿了,那么可能今天有些网络卡顿了,各位请耐心一点,如果卡顿严重的话,请告诉我。哦,好的好的,我们可以创建一个tensor。Tensor是PyTorch内部的一种数据类型。我们可以传入一个列表,或者传入一个NumPy数组,然后我们调用from_numpy函数。这个函数我们很少用。所以很多时候我们有这个数据就用,但通常我们很少这样用。我们有random函数。这个random函数让它运行从0到1,给你们试试看。首先,我们导入torch。然后我们经常使用这个.rand函数。那么,这个函数它不是数学中我们通常说的那些函数,它会返回一个数字,因为现在我们是在向量上工作,它总是以向量的形式出现,或者说向量,当我们说向量时,我们会想象一个一维数据,对吗?那么在这里,人们称之为tensor,当说到tensor时,它可以是任何维度的。所以当我们创建这个时,我们必须说明维度,例如我们说创建一个2x3的矩阵。所以当我们调用PyTorch中的函数时,我们总是传入一个形状(shape),告诉它这是一个2x3的矩阵,然后它会生成一个2x3的矩阵,每个位置生成一个从0到1的数字。此外,它还有这个函数,你们猜猜这个函数和下面的函数有什么区别,根据你们到模块6为止的编程经验,它有什么不同呢?当然,它会生成负数,但你们猜猜它多了一个字母n是什么意思?下面的函数有字母n。N是negative吗?不是normal,不是normal integer吗?n怎么会是integer呢?你们猜,哦,正态分布(normal distribution),它是normal的缩写,不是normal_lin,normal_lin是不同的,normal_lin是数据,而normal是高斯分布的一种形式,均值为0,标准差为1,所以它被称为normal,正态分布。所以NumPy中也有这个函数,对吗?加上字母n就是normal。所以这个函数我们将用来在softmax任务中做什么步骤呢,各位?例如在softmax任务中,我们将使用这个函数,你们猜猜这个函数会在softmax函数的哪个步骤中使用?也就是说,我们将生成一个随机数,它近似于0,但围绕着0。那么它会在哪个步骤中呢?在softmax任务中,逻辑回归任务中,还是线性回归任务中?这个函数是用来,没错,用来初始化参数,初始化theta的。好的,稍后我们将用它来初始化theta。N,normal distribution,或者这里我们也有range,只是介绍一下,我从来没用过这个,只是介绍一下。所以基本上我们主要使用这个函数,而这是从列表中创建tensor的方法。现在我来尝试添加一个tensor,它会显示这个。打印一个tensor,它会显示这个。或者我们创建一个tensor,torch.tensor,传入一个列表1 2 3。然后我们运行它,它会打印出这个。好的好的。

这种技术叫做广播(broadcasting),和NumPy中一模一样,所以我会讲得很快。我们有一个tensor,我们有另一个tensor,但它们的形状(shape)不同,这时它会生成一个2x2的矩阵,每个元素都是1,然后将这两个相加得到这个结果,对吗?这是一个一维的tensor,对吗?如果这是一个一维的和一个数字,那么如果我们只传入一个数字加上一个普通数字,它仍然可以做到。所以它也和NumPy一样,对吗?我们可以将两个tensor相加,一个tensor加上一个数字,或者两个tensor进行乘除加减。那么,假设我们有一个tensor和一个数字y,y是数字5。那么我们相减,当这样相减时,这个y会变成广播(broadcasting)。那么y会变成值5。一个全是5的向量会变成这样。那是两个向量,两个tensor相减。我们也可以正常操作。所以它唯一的区别在于我们初始化数据的方式。只是初始化tensor的方式。而所有下面的操作都和普通的Python编程一样,并且和NumPy非常相似。所以我们只要基于NumPy就行了。

好的,此外它还为我们准备了一些东西,也就是说,它是一种编程语言,我们完全可以从头到尾进行正常的编程,但是PyTorch是为深度学习而创建的,所以当然会有一些与我们刚刚学过的东西相关的功能,其中有一个叫做均方误差(Mean Squared Error),我们经常使用它,对吧?均方误差就是我们对每对值取平方,然后相除。

这就是均方误差(Mean Squared Error)。其中我们有一个现成的函数,按理说就应该是这样,对吧?就是torch.min_square_error,但它加了“loss”这个词。加上“loss”这个词有它的原因。原因是这是一个损失函数,以后我们将用它来训练。它还添加了这个包,这意味着这个包是用于神经网络(NN是Neural Network)的,用于我们刚刚学过的那些东西,那些相互连接的节点,比如softmax等等,这被称为神经网络(NN),它还添加了层(layer)。Softmax虽然太简单了,但它也是神经网络最简单的形式之一。

我来试试这个。我们创建两个tensor,对吗?我来重新输入这个。得到什么数字?7.5吗?1 2 3 4 555。我来快速复制一下。1 2 3 4,我们称之为x。然后y等于。传入555。然后我们继续声明。上面我们已经声明了一个名为torch的包。NN是神经网络(neural network)的缩写,点min_square_error_loss。那么这里是什么呢?这里是我们创建这个类(class)。你们记得在面向对象编程中,我们创建一个类,然后通过括号来调用这个类,对吗?所以这里我们称之为min_square_error_loss。现在我们才声明这个loss。现在我们才使用它,我们使用它并打开括号。就像我们在这个类中有一个默认函数一样。这个默认函数会接收x和y的值来计算均方误差。那么这里我们有4的平方等于16,加上3的平方,3的平方是9,等于25,加上2的平方和1的平方是5,再加起来是30,对吗?30除以4是7.5,对吗?res等于什么呢?这些错误我们经常遇到,例如这里它说我们经常遇到数据类型的问题,所以我们必须再声明一行。嗯,这段代码。我先试一下,然后再和你们讨论。它这里也有两个意思,它已经先运行了。所以,我还没有更新幻灯片,各位。抱歉,各位。按理说应该先测试再更新这里的幻灯片。因为这是9个月前的事情了。那是上一期课程。上一期课程的版本是这个,哦,不是,你们知道的,我明白了。幻灯片里是.00,这里我没有.00,我来给你们解释一下。刚才我以为是版本变了,但我试了一下,我先确认一下,然后再告诉你们。我确认了一下,好的。刚才我们没有加.0,所以它会把数据类型理解为整数,因此在这个loss函数中,它不接受整数类型,因为它强制要求这种类型必须是浮点数(float),因为它此时要求程序员说,好的,整数类型是用于标签值(label)的类型。所以那时我们必须清楚这一点。而这里接收的值是均方误差函数的值,这个函数接收预测值(y_hat)和标签值(label)。这里是回归问题中的值,所以它不可能是整数。它必须是小数。所以这里我们必须,如果像刚才那样是整数,我们必须强制转换为浮点数,或者我们加上.00,它就会自动识别为浮点数。好的,各位。

好的,Kathy同学问到正态分布,那个只是提前说一下。至于那个,我们两周后的下一个模块会有一个专门关于初始化的课程。那么这个任务就是均方误差。这段代码描述了均方误差。所以它只是一个为我们完成任务的函数,否则我们现在可以把这两个相减,平方,然后正常求和,对吗?只不过它被设计成方便我们更快地编程。这样我们就能更快地构建神经网络。

好的,这里是关于cat函数(concatenate)。Cat函数是用来连接的,其中axis 0是沿着这个方向,axis 1是沿着这个方向。它和NumPy一样,对吗?所以如果我们沿着dim 0连接,它会沿着这个方向。而如果我们沿着dim 1连接,它会沿着这个方向。它就会变成这样。这个函数以后当我们有图像数据,有文本数据,我们通过一个模型,它会生成一个向量,一个tensor,然后图像数据通过一个模型,它会生成一个向量,抱歉,一个tensor才对。然后还有其他各种数据,每种数据都通过一个专家混合模型(Mixture of Experts),各位。那是现在的一个热门趋势。每个都通过一个模型,然后我们把它们连接起来,拼接起来。

好的,这个和NumPy一模一样,我快速说一下。Argmax沿着维度0。所以这两个。这个是max,这个是max。而argmax沿着维度1是沿着这个方向,对吗?所以我们用max函数来解决哪个问题呢,各位?在softmax任务的哪个步骤?在softmax任务的哪个步骤我们会使用max呢?在最后一步。最后一步是计算准确率(accuracy)的步骤,对吗?所以我们会使用max函数。

好的,这个是新的。这个是新的,而且非常有趣。我来和你们一起做。给一个值为2的tensor。那么这里x等于2,对吗?x最初赋值为2。也就是说,我们计算一个点的导数,那么哪个点必须先写出来呢?x = 2。Tensor是数据,在PyTorch中数据是永远不会改变的。数据是我们加载上来的。我们加载数据是因为数据不会改变。我们训练时就加载数据,数据是永远不会改变的。默认是不改变的。所以如果我们想让它改变,我们想让它成为一个变量值,这个不是变量,各位。上面这些tensor不是变量。一旦创建,它就保持不变。如果我们想要一个新的,我们就必须修改,那时就会生成一个新的。而数据本身,内存本身是不会改变的。因为人们理解数据是永远不会改变的。数据只是读取。例如,如果我们从数据库加载数据,我们只是读取,对吗?我们又不会改变数据。假设我们进行归一化,那时它会保存一个新的变量,然后我们只是读取那个变量。所以PyTorch理解所有被称为数据的东西是永远不会改变的。所以如果我们想改变它本身,想让它像一个变量一样改变其内存区域中的值,那么我们必须添加这个。

现在,我们把它看作一个变量,稍后我将更新它。那么,这样做。现在,首先是y = x的平方,对吗?这个x平方后,再乘以3,然后加上2,得到j,j等于这个。那么,计算J对X的导数,对吗?它将等于J对Y的导数乘以Y对X的导数。那么,J对Y的导数是什么?J对Y的导数是3,乘以Y对X的导数是2x。那么,如果x = 2,J对X的导数将等于12,对吗?它将等于12。那么我来试试看它是否等于12。重新输入这个x,然后我们正常操作,对吗?我们有torch.x,x等于x = 3吧。3.0,请你们帮我计算一下,根据我写出的方程,这时它会等于什么?哦,参数很容易忘记。require_grad,然后你们输入看看,当x = 3,方程如下:方程,嗯,我们还是保持和刚才一样吧,y = x的平方,j = 3 * y + 2,请你们计算一下J对X的导数在这个位置是多少。然后我,它有一个叫做J.backward(),它没有显示给我J.backward(),然后X.grad应该等于18,对吗?38,然后等于18,对吗?好的。现在有同学说,我试一下这个,它报错了,这个不行。你们说不相信,对吗?所以,但是这种好奇心非常好,各位,我自己也是这样,很多时候我必须从书本中学习,仍然会好奇,很多时候我必须亲自尝试才能相信,对吗?我们是程序员,所以它必须有这个。好的好的。

那么这个怎么解释呢?就是当我们有X的时候,嗯,这里的解释就是这张图。当我们在这里构建X时,PyTorch会为我们构建这样一棵树。当它构建出这样一棵树时,就像我们人类看到后可以反向计算导数一样,这时PyTorch有了信息,它也能计算导数。所以计算反向传播(backward)时,它会计算每个位置的导数。计算所有位置的导数。这个位置是这里的y位置,对吗?所以它计算y位置的导数。然后这里是J位置。还有很多其他位置,它会计算所有位置的导数。这里我们允许它成为一个变量。所以我们计算导数,试试看能不能打印出y。看看它是否保存了。我猜它不会保存,因为它不需要保存,因为我们没有告诉它这是一个会改变的变量,它为什么要保存呢,对吗?所以这些内部的计算,人们称之为数据,但是我们不会尝试去实现这个。它会在内部实现,它有一个专门处理这个的,哦,tensor是不会改变的。那么我们有这个就太麻烦了。那么我们有一个名为variable的变量,例如。是吗?它能接收一个列表吗?我想我还没试过。我想不行,各位。不,它不接受。Variable也必须接收一个tensor。直接做可以吗?Torch.autograd.variable,导入这个,然后autograd.variable,试试看autograd.variable导入,传入variable,variable也需要grad,那么我们还用variable干什么呢?我再试一下,让我先让它运行起来。然后我再试试看能不能去掉这个。因为这里我们定义了一个variable,但我们仍然,这是第二种方法,各位。第二种方法,在PyTorch中,我再读一下PyTorch。哦,这里有第二种方法。那么当它创建了variable之后,我想可以去掉这个,我来试试看。现在我先让它运行起来。Autograd.variable,像这样导入torch.autograd,对吗?导入variable。然后在这里创建一个variable,对吗?好的,先创建X,我先让它运行起来。然后我再试它。require_grad等于true,对吗?然后require_grad没有这个。嗯。require_grad等于true。是不是打错了什么地方?哦,英语太差了。那么这样做可以运行吗?好的,可以运行,试试别的。啊,它抓不到,对吗?因为这个本身已经可以训练了,再放入variable有什么意义呢?那就是回到这里。我回到这里。回到这里。好的,没错。没有其他办法了。这个不能直接接收一个列表,所以我们必须通过一个tensor。所以这个variable的方法是,很多时候我们已经有一个tensor,而这个tensor之前仍然是数据,但现在我们想改变它。明白了。好的,我再解释一下。嗯,这里通常我们不能改变,不能计算导数。当我们加上这个时,这时tensor内部有很多东西。那么它内部有那个变量,那个参数,这个类的属性。当我们将这个设置为true时,它就会被使用。那么此外,这是什么?这是我们从一开始就确定x将是一个用于计算导数的变量。但是假设在我们的工作过程中,我们确定,嗯,现在上面已经有很多tensor了,正在同时运行,现在我们确定某个tensor作为变量,那么我们就使用variable,PyTorch也支持我们这样做。除了常规方法之外,我来分析一下这个例子。在这个例子中,我们有4个x,也就是4个输入特征,我们将这四个相加。然后这四个相加得到y。y等于x和y相加。然后y = y的平方。那么当我们计算时,每个位置的导数都等于8,对吗?因为J对Y的导数乘以Y对X的导数,那么它将等于J对Y的导数。

就等于 2y,x 就等于 1。所以这里它会等于 2y。2y 现在在 x = 1 的位置。x = 1 就推导出 y 等于 4,对吗?y 等于 4,所以 2y 相乘就等于 8。所有位置的导数都等于 8。

然后 Võ Hương 问,那么 variable 有很多变量 x variable 是一种将张量转换为一个可以计算导数的方式。再说一遍。

当我们创建一个张量时,首先我们要理解“张量”这个词。张量是多维数据,它可以是任何维度。这里放数字 2,只是为了让它等于一个数字。张量这里它包含一个数字,它就是一个数字,但现在我们这个张量可以创建任意多的东西,对吗?这个张量我们可以创建任何类型的数据。这也是一个张量。或者这里它创建了包含多个数字的张量,或者现在我们创建一个 100x100 的张量也可以。所以,这是一个张量,当我们说到“张量”这个词时,我们理解它就是多维的,任何维度都可以。而且这个张量的所有位置都可以改变,所以它可以计算导数。这是第一种方法。我们从一开始就创建张量,并确定它可以改变。

而这种方法是,某个地方已经有张量了,现在我们希望它改变,那么我们就再嵌套一个这个。那么这两个步骤就等于一个步骤,就是这个步骤。它支持很多种方式。

当我们有了这个,就可以计算导数。稍后我们有一个变量 di,我们调用 backward 函数。那么在这个 X 里面,它有一个属性叫做 .grad,它包含梯度。这样构建它就有了。目前正在使用最新的 PyTorch。

看看版本是多少,兄弟们。看看,嗯,肯定不是最新的,但它也算是新的。torch.get_version 2.3 版本以下是新的吗?在这里看看,这里是 2.9。所以它也稍微有点差距,但影响不大,因为通常从 1.6 开始就饱和了,所以现在它只是添加了一些小东西,添加了一些额外的功能。核心部分已经饱和了。

所以这里我刚才用一个变量演示,现在我用四个可以改变的变量演示,而不是说 variable 就有更多变量,不是的。之后我们这里有几个步骤。稍后我将应用于线性回归问题来解释。这里只介绍函数名。稍后我们将直接应用并查看数字,这样更容易。因为线性回归问题我们已经很了解了,我们会看得更清楚。

我们经常做这样的操作:theta 等于 theta 减去 learning_rate 乘以 loss 的梯度。如果这是一个数字 n 向量,向量也可以。向量就是这样根据 loss 的,而且这个 learning_rate 等于 0.1,那么这个操作就等于这一行。而且它应用于变量 x,那时怎么办?

我来试着应用一下。声明一下:这里我们声明一个库是 torch.optim。Optim 就是 optimization。然后是 .sgd。optimization 等于 .optim optim 不知道为什么这里没有 .sgd。

在 SGD 中,我们分析一下,SGD 会接收一个列表,一个包含那些具有 require_grad 等于 true 属性的张量或变量的列表。variable 就是这个 require_grad 等于 true,或者说是附加了 require_grad 等于 true 的张量,它必须是这种形式。我们把它放在里面,有时候我们有很多变量。我们有变量 x1, x2, x3,抱歉,我们有张量 1, 张量 2, 张量 3,它们是独立的。那时我们把它们组合成一个列表。而在这里我们只有一个变量。这不是很多。这只是一个张量。我们也把它放进去。我们设置学习率是多少呢?X 学习率等于 0.1。我再运行一下上面这个。返回。

这个等于在这个位置的梯度是 18。如果等于 0.1,那么此时我们要做什么?我拿这个地方。这是一个方法,theta 减去 theta t。抱歉。Theta 等于 theta 减去 learning_rate 乘以梯度。它把这个 X 赋值。那么它就理解为 theta 现在就是这个 x,对吗?Theta 就是这个。它将以 learning_rate 等于 0.1 的学习率,沿着梯度的反方向更新这个值。我们怎么做这件事呢?.step。打印 X。再试一下看看对不对。就是 x 现在等于 3,减去 1.8,是不是等于 1.2 呢,各位?明白吗?到这里明白吗?所以就是这样。

这样就完成了。那么所有事情我们都用这个来完成我们的三个问题。我们学过的三个问题。看来它已经全部支持我们了。看来现在我们来试一下吧。就是它能为我们解决 Softmax 具体问题中的什么事情呢,各位?就是有了这个,我们在哪个步骤会轻松很多呢?我们将在 Softmax 问题中的哪个步骤会非常轻松呢?例如,这里会写出来,在 Softmax 问题中,我们有计算梯度的步骤。对的。

还有什么步骤呢?还有什么步骤它也支持我们呢?计算梯度的步骤是最轻松的,对吗?计算梯度的步骤是最麻烦的,而我们在这里只需要调用 backward 函数。至于 step 函数,它支持我们更新 theta,对吗?我们就一直调用 step,对吗?更新 theta。那么我们已经轻松了两个步骤。最后我们只剩下这个步骤,叫做模型构建步骤。模型步骤如何运行,我们必须自己做。所以我们试着用这些知识来应用于线性回归问题看看吧。

好了,看看还有没有别的。这些都是些细枝末节。它有很多种做法。那么各位可以看看它有很多种做法,我们选择记住一种就好。不要记太多。即使是这些,我也记不住。很多时候,当我在教的时候,必须阅读全面的内容才能讲得全面。但当我实际操作时,记住一个就行了。线性回归。

那么在解决线性回归、逻辑回归和 Softmax 回归这三个问题时,在解决过程中会添加新的 Python 知识。各位,我们边解决边添加新知识。否则,如果之前不列举不说明,一次性讲完 Python,之后我们应用时就都忘了,记不住了。所以现在是讲到哪里就说到哪里,这样更容易记住。那么刚才我们学了什么呢?我们看看我们学了什么,我们学了声明上面的 optim。

刚才我们有这个,对吗?导入,我们看看我们已经有什么了。导入这个。那么刚才我们学到的是我们声明了一个 torch 包。然后在这个里面我们只有一个 variable。忽略这个,它太冗长了。我现在把它总结一下,把重要的、我们需要知道的浓缩起来,以便我们更容易地转向新的内容。

创建一个张量的方法,以及创建一个可以将其转换为 theta 的张量的方法。那么 x 现在就是 theta。之后我们构建这个就很正常了。然后构建完成后,我们取最终值。这个值对应着后面的 loss 值。我们调用 backward 函数,它就会反向传播。Backward 是反向传播到那些 require_grad 等于 true 的变量。那么那个变量的 grad 参数就会保存梯度值。

当我们调用完这个之后,我们声明一个 SGD (Stochastic Gradient Descent),这正是我们一直以来所做的方式。我们调用 start 函数,它就会更新 theta 等于 theta 减去 learning_rate 乘以梯度。这样就非常简洁了。所以现在我们再学一些东西来构建模型。现在只剩下模型部分了。好的。好的。

我来写代码了。我来写代码了,朋友们。所以现在我们慢慢写代码。别担心,我会慢慢写代码。或者哪里不清楚就告诉我,我会写代码。我再介绍一个,就是当我们有节点 x1, x2,然后这里是 j2,那么我们连接这个,连接这个,连接这个,连接这个。各位,这总共有多少个参数?如果看这里,它有多少个参数?那么这个叫做全连接层 (fully connected layer)。这是书本上的叫法。在 TensorFlow 中它叫做密集层 (dense layer)。在 PyTorch 中它叫做线性层 (linear layer)。它们都表达了同样的事情,就是我们有一个数据,叫做数据向量 X,我们有一个向量 J。这两个向量里面有许多小小的元素,它们彼此连接,完全连接在一起。这叫做 fully connected,就是完全连接在一起。

那么现在在线性回归问题中,对于这个问题,例如我们有更多的特征,我们有 x1 x2,然后我们在这里生成一个 j 值,我们只有一个 j,就是 y_hat,那么我们全部连接起来,也是完全连接,所以它也是一个 fully connecting。所以回到这里,这个问题我们只有一个节点,这个问题超级简单。我们有一个节点,然后我们生成一个节点 J。这个叫做 add,可以叫做输入层 (input layer)。Input 还是不是 input layer,叫做输入数量。这个是输出,是输出中的节点数量。

那么这里节点数量是 1,节点数量是 1。所以对于这个问题,各位看看这里有多少个变量?在这个简单的线性回归问题中,我们有多少个变量?在只有一个输入特征的线性回归问题中,我们有多少个变量?两个变量,对吗?W 和 B。

好的,我们来看看。import torch.nn as nn。NN 就是 network。之后我们用 nn.linear。这个 Linear 接收一个输入节点,一个输出节点,我称之为线性层。所以这里我们有这个数字是输入节点数。输入节点就是这个。这个是输出节点数量。各位注意一下。

好的,各位应该拿幻灯片。这是我上传的幻灯片版本2。各位记得拿最新的幻灯片。这部分只是用来调试的,但我会和大家一起做,所以有时候这里的函数你们不记得也没关系。因为当我们真正做的时候,代码会非常简洁。但这里我们调试是为了更好地理解 PyTorch。各位,我们理解得越深越好。你们的薪水将取决于你们的理解程度。所以各位尽管自信,有时候为了让程序运行,我们只需要记住那一部分。但为什么我们要学这么多呢?总的来说,各位,因为我们知道得越多,我们就会越扎实。所以有时候我们要为此做好准备,不要给自己设定一个默认值说我们排斥这件事。所以我们要把这看作是我们的思维也会随之而动。所以我们要为学习新知识做好准备。

现在我来打印一下。打印什么?这里面有一个参数叫做 weight,还有一个参数叫做 bias。我猜 weight 有 s,因为它会有很多个 weight bias weight 没有 weight 或者没有 s 吗?试试看。哦,没有 S。好的。那么这里有两个参数。这是 weight,我们有一个参数。它就是一个 require_grad 等于 true 的张量,它就是 theta。它就是定义变量,可以吗?而这个是 bias。

那么各位注意,这里这个是列向量。这是向量形式,这是两个列向量,就像一个一行一列的矩阵,而这是一个只有一个数字的 bias 向量。那么各位注意,当我们有 x1 x2,然后这里是 0,这里是 1,有 j,那么这里我们有 w1 w2 和 b。那么在这里面,在 weight 中,它会以 W1, W2 的形式存储。而 bias 总是只有一个数字 B。

好的,然后我们接下来做什么呢?之后,假设现在有一个新的问题,这里是数字 4,各位猜猜我们有多少个参数?各位,如果这样做,你们快速输入,那么我们有多少个参数呢?各位注意。这里的数字 4 是四个特征,包括数字 1,因为数字 1 是 PyTorch 可以自己处理的。它替我们做了。PyTorch 被创建出来就是为了支持我们,所以它必须能够自己处理。所以在这里我们看到我们总共有 1 2 3 4 5 个变量,对吗?4 + 1 = 5。好的,我在这里停一下,稍后我会讲更复杂的内容。好的,你先停在那里。

然后另一个扩展部分是,当我们在这里创建一个线性层时,它会自动为我们生成参数。它以某种方式自动生成,我们将在下一个模块中查看这种方式是什么。而在这里,我们理解为每次运行它都会为我们生成不同的参数,不同的 theta 值。通常情况下,没有人会赋值。但现在假设我们想给它赋值。我想给它赋值是为了什么呢?为了测试,对吗?那么此时我们可以这样做。因为这些东西当我们打印出来时,我们看到它们是张量。所以现在我们添加另一个属性叫做 data。那么它将允许我们赋值,.data 就是取出那个张量。取出 bias 本身的张量。我们将其赋值为一个张量,一个某个值。这段代码是我为各位演示的代码,以便稍后我们更容易测试。至于这部分,各位不要试图记住这些。因为幻灯片上有,我们观察一下就可以了。

PyTorch 回到哪里?以后在做线性回归问题时,各位只需要记住这段代码就可以了。其中 linear 等于什么?Linear 等于这个。各位记住这一行。各位记住这一行,然后记住这一行,问题就解决了。线性回归问题就只有这些。但我正在补充说明,让各位看到,所以各位要知道,哪些是补充说明,有时候如果太复杂了,我们就观察一下。

好的,假设参数等于 1.0。.data 等于 2.0。那么此时参数就改变了。也就是说现在我们赋值,赋值是为了什么?为了稍后我们测试一下,看看我们是否真的理解 PyTorch,对吗?所以我们现在来试着做这个问题。哪个问题有数字的。这个问题有数字,对吗?现在我们来做这个问题,看看我们是否真的理解 PyTorch。各位根据刚才我们学到的知识来帮助我。很多时候我也记不住。我会和大家一起做。

首先,我们有数据 6.7 和标签 9.1。好的,我们现在来试着做这个,就知道我们是否理解了。W = 0.34,我们把它放在这里,减去 0.34,b = 0.04 0.04。那么现在我们已经有一个线性层了,对吗?我们有一个线性层。这个 Linear 是什么意思?这个 Linear 意味着我们有一个输入节点和一个输出节点。也就是说输入只是一个数字,输出也是一个数字。它是做什么的?它是张量。现在我来给各位演示一下。好的,我给各位演示一下,这个没问题了,对吗?我把这部分删掉。

创建 X 值等于一个张量,.tensor 它是数据。所以这里传入的数据是什么呢?6.7 6.7,然后我们生成 ih 值等于线性层传入 X,看看它能不能运行。H 传入 X,然后这是什么?矩阵 M 2,它必须是一个矩阵。哦,好的,它有问题。我回到这里,我复制这个,这个问题也很有趣,各位帮我观察一下,这是我们打印出来的结果,这是正确的,这是一个线性层,这是线性层的权重和偏置的组织方式,现在我用这种方式重新赋值,它就报错了。为什么呢,各位?各位帮我看看这一行,为什么会这样?

好的,一个 2D,对吗?所以这里我们必须看看它的属性,它的结构是什么。我们必须遵守,不能自己随意创建,对吗?所以,好的,回答 Minh Hoàng 同学的问题,它们是一样的,有两种方式,所以就是这样。这个没问题了,对吗?运行这个。这是我们打印出来的吗?好的,现在我们赋值这个,然后运行。-2.2,各位觉得熟悉吗?我们边做边调试。因为也希望它有错误,这样各位自己做的时候,我们也能通过错误来学习。

好的,6.7 就会得到 -2.23。我们有 -2.23。那么我们已经计算出 y_hat 了。现在我们计算 loss。这个 loss 我们用均方误差 (mean square error),对吗?网络均方误差。好的,我们继续做 loss function。等于 .N 各位有什么问题尽管问。因为这是新的,尽管问,这样我们能理解得更深。均方误差损失。我们必须声明它。我们先创建类,然后才能使用。之后我们才能在这里使用,这里我们需要有 Y,对吗?把 Y 在下面也创建出来,让它更简洁。Y 等于 记住是 9.1。这个问题我们做了很多次,9.1,对吗?9.1。均方误差会得到 loss 值。Loss function 传入 ih 和 y。打印 loss。哦,这个数字也很熟悉,128.5,那么就没问题了。

128.5,然后我再添加这个幻灯片,这样我们就有梯度值了。梯度值将等于 -151 和 -22,对吗?我们来看看,现在计算梯度,我们调用什么呢?忘了。现在计算梯度,各位帮我输入一下,现在计算梯度的步骤是我们要用哪个变量 .backward?我们就取最后一个,是什么呢,各位?我们怎么计算梯度呢?这里我们取什么?我们 .backward 这里。好的,计算梯度吧。各位帮我输入。loss,对吗?Loss .backward,这样它就计算梯度了。它为我们计算了梯度,然后我们更新。

当我们更新时,我们必须声明 optim,对吗?我到上面复制一下,快一点。哪里哪里?这里。这里是计算梯度。这里更新,分开。好的,现在计算梯度。先计算梯度。之后计算梯度,我们必须知道,我再打印出来。哦,打印什么呢?刚才我记得,各位记得我们有 x.grad,对吗?是一个变量,它会有 grad。那么现在我们取出 x。这个 X 是什么?X 包含权重和 bias。权重 bias 在哪里?它在刚才我们从上面取的那个 linear 里面。看。所以这是一个,这是 x。这是一个变量 x,所以这里我们赋值为 X,它得到 -151 和 -22,对吗?

好的,当我们计算完梯度,对的,-151 和 -22。之后我们计算,就有了新数字。这里的新数字是 0.26 和 117,对吗?学习率等于 0.01。好的。学习率等于 0.01。之后我们更新,我们传入一个列表。哦,这部分我再记住一种做法,就是返回这个线性层中的参数,它有一种做法是 .parameter,我猜有 s,试试看,没有这个方法 .parameter。这里有说什么吗?看看 parameter parameters,对吗?Parameters。对的。好的,看看有什么错误。Method object is not variable。缺少什么吗?哦,缺少什么。哦,它不是一个属性,而是一个函数。好的。函数它返回给我们一个列表。它会收集一个包含权重和偏置的张量列表。

嗯,现在我试试打印这个看看行不行。试试看。试试看,它可能会输出一些东西,它输出的是一个 generator 类型,我们可以理解为它是一个列表,其中包含权重和偏置。好的,当我们打印完这个之后,我们运行这个,然后我们会再次打印这两个的值,看看它们是多少,对吗?就这个。这里。R bias 好了。0.26 和 117 是 0.26 117。看。

好的,各位明白吗?那么我们已经完成了线性回归问题了。我最后把代码整理一下,各位会看到代码是这样的:首先保留这个,然后计算 loss 什么的,这些我们只是额外打印出来,对吗?计算 backward,那么这里假设我们不使用这个参数,它就是这样,那么这句话就是这个就是模型。我们理解它就是模型,因为我们的模型很简单,就只有这样。

然后这里我们加载 X 数据,计算 y_hat,然后我们计算 loss。当我们加载样本时,它会是这样。我们加载样本时,它会是这样,对吗?我们有 x 有 Y。之后我们第一步是加载数据,计算 y_hat,计算 loss,然后计算梯度并更新。当然,这些声明我们不能让它这样声明。我们在最上面的模型部分声明。因为之后它会运行循环。所以循环包括取出数据,计算 y_hat,计算 loss,更新,以及计算梯度并更新。我们就这么简洁。

好的,那么线性回归问题就完成了。现在我们想进入 for 循环,我们就运行 for 循环。稍后我将和各位一起做。现在假设我想再运行一次,是吗?那怎么办?想再运行一次,让它出结果,对吗?假设这里它再次运行这里。我把这个复制到这里。好的,运行,那么这里它输出 117 和 0.26,是这里的新变量,对吗?之后现在想再运行一次,看看 loss 是否会降到 0.86。那么再运行一次,我怎么运行呢?

那么此时计算 ih。选择 ih 并计算 loss,打印这个。打印这个,对吗?这里我们计算 ih,然后计算 loss。其中 y 和 x 已经有了。那么我的新 loss 等于 0.86。这是 8.1 和 0.86。8.1 和 0.86,这个数字是从 numpy 生成的,各位。它们是两个独立的,但我基于 numpy 作为标准,作为正确答案,然后我用这个正确答案去测试 PyTorch 是否能得到相同的结果,以便我是否真的理解 PyTorch。目标是这样,这些数字不是从 PyTorch 生成的,它们是从 numpy 生成的,那时将基于普通代码和手动计算。所以所有一切都基于正确的基础。我们从正确的东西开始构建。

好的,那么在线性回归问题中我们学到了什么?我看看这里有什么新的,我们学到了学习方式。但各位不要记住,你们不需要记住这部分。这是我们可以直接将 theta 赋值为一个预设数字的方式。我们可以这样做,但这种操作很少有人做。

什么时候我们在这里测试,我们就测试。然后在这里我们生成一个线性层。这个线性层它的输入就是一个数字,它就是值x。输出是一个节点,它就是y帽。所以这里是y帽等于x乘以w加b。x乘以这个w加b。就是这样。

然后我们计算损失时,我们使用均方误差。就是这样。那么这就是我们计算损失并声明它的方式。然后我们把y放入损失函数,我们有y帽和y。就是这样。

然后我们计算导数时,我们使用一行损失。反向传播会为所有现在不再是张量requires_grad为True的位置计算导数,而是那些线性层,那些线性层。然后线性层内部的那些东西会有导数。然后我们更新。

更新时我们说,好的,更新什么?可能有很多地方有导数,但我们只能更新几个地方。那么我们通过假设我们想更新这个线性层中的参数,来将它们放入那个列表。那么我们就取那个线性层,调用它的parameters函数。然后我们嗯嗯,再添加这一行。Step就是我们更新一次。

然后然后现在我们再做一点。我们做逻辑回归的练习。但是大家对这里有什么问题吗?大家想让我再解释一下这里面的某个部分吗?大家觉得可以吗?如果可以的话,我们就转到逻辑回归的练习,我们还会有一个新的部分,那就是逻辑回归是分类问题而不是回归问题。所以我们需要使用sigmoid函数,然后我们需要使用交叉熵函数。但是首先我们这里可以吗?如果不行,我们去到那个部分会觉得更难,因为我们还没有清楚理解这个。

大家看看我有没有问上面哪一行。好的。Zero CR吗?好的,zero CR是当我们循环,我们使用for循环进行训练时,那时我们会在这里使用zero CR。然后我会按照幻灯片这里说。我们看看这里有什么想法?我会再说一遍这里是我们进行设置。

然后我们声明损失,然后声明优化器。那么这里的第三项是我们有模型。必须构建模型,然后计算损失。那个模型。这是构建模型的模型。我们的模型只有一个线性层。然后计算L。就是这样。然后我们会计算导数,然后我们更新。

那么当我们计算导数时,假设我们有三个样本,那么此时导数的值是不是等于损失对W的导数的值,它是不是等于三个样本的平均值呢?1/3乘以对每个第i个样本的损失对W的导数之和,我们有三个样本。对吗?大家还记得吗,当我们有多个样本时,我们是不是有一个累加变量,然后我们除以3来计算平均值。就是这样。

那么当我们用三个样本训练完之后,稍后我们也会用三个新样本训练。稍后我们也会用三个新样本训练。那么假设在我们的代码中,在我们的for循环代码中,进入for循环,进入for循环。这里我们是针对epoch进行训练,那个数量,然后这里我们是针对batch进行训练,当我们针对batch size进行训练时,这里面我们会计算每个样本的导数。那么外面我们需要什么变量呢?我们需要什么变量,以便稍后当我们运行完所有batch size后,我们会更新一次呢?在计算m个样本的导数时。大家还记得M样本等于2的那个例子吗?那么这里我们需要声明什么变量?什么变量?例如我们有两个变量W和B。那么这里我们会有什么变量,大家还记得代码5中吗?在代码5中,那里有两个变量。看看它有什么变量。

这里大家就打出来吧。进一步解释一下。我们计算每个样本的导数,然后计算完成。然后到这一段,我们会更新。但是在更新之前,我们必须计算一些东西,这里我们必须计算平均值。计算平均梯度。那么为了计算平均值,这里我们需要什么变量呢?变量s,对了。W的梯度之和和B的梯度之和。那么当我们计算总和时,假设它运行了很多次循环。它运行了很多次循环,对吗?

假设我们这里有batch size,我们运行完所有batch size,然后我们这里的batch size是,例如我们有100个样本,我们只运行batch size为10。那么对于每个batch。对于每个batch吗?等等,对于每个batch。难怪难怪我问大家时大家会犹豫,问错了。对于每个batch,我们才计算这个。好的。那么大家的编码水平有时甚至比我还要扎实。啊,这里才是这里才是计算每个导数,我们进入for循环,for x,对吗?这是对于所有,我们取出所有的batch size,然后对于每一个batch size,我们才计算这个。那么它的默认值必须是0。可以是其他值吗?怎么能是其他值呢?因为我们计算累加和,所以一开始必须是0,对吗?那么在正常情况下。所以它的意义就是这样。

也就是说,假设它运行完一个循环,那么它运行完我这里有两个样本,m样本等于2,运行完2个,然后这个会在里面累加一些东西。里面它会累加,然后下来这里计算平均值,然后它会用一个batch size为10的批次更新一次。那么然后它会循环到这里,运行另外10个样本。当运行另外10个样本时,这个值必须是0才行。因为因为怎么能行呢,对吗?因为是10个新样本啊。所以我们必须执行这个操作。

那么为什么我们要明确地执行这个操作,而Python不帮我们做呢?因为因为在深度学习中,有一些算法它需要训练多次才更新一次。总的来说,它是为了让这个框架的灵活性更好。所以这里它不会自动清除,而是让我们主动清除,以便将来我们可以做更多样化的事情。而Python不仅仅是为了最大回归而生,它还为了很多其他事情。所以这里我们必须手动赋值。所以我们需要这个操作。

好的,没关系。所以我们需要第三个。刚才还没打算说第三个,因为要等到我们说到for循环的时候。但是你正好问了,我就直接说了。那么最后我们有这个,假设我刚才用一个样本训练,现在用多个样本训练也是一样的。在Python中,我们训练多个样本和一个样本没有区别,刚才我们的X数据是,我的X在哪里?我这里就是这样放的,对吗?它是一个样本,现在再添加一个样本,看看此时会怎么想,每个样本都变成一行,对吗?现在再训练一个样本。这个样本是什么?等于4.6 5 5.9 4.6,然后y = 5.9。那么此时我们必须查看形状,检查形状是否正常。因为这个是我们自己设置的。而当我直接检查时,我会和大家一起检查。然后看看它能不能运行。现在有一个样本,现在我创建两个样本看看怎么样。

那个不重要。这是它打印出来的注释。那么两个样本它打印出来的是刚才的两个数字是-2.2和这个是-1.5,这边没有,对吗?就是这样。然后就是这个形状,这里我打印出形状给大家看。点shape 21。那么我们有形状是21。

然后接下来我们计算损失。那么当我们自己这样编码时。那么此时我们必须控制形状。因为我们的输入是21,那么我们的Y i也必须相应地是21。所以这里我点reshape 21,只是为了让它们一致。那么我们的损失就是这样,对吗?就是这样。

然后计算反向传播。计算反向传播,然后计算什么,它就正常进行,对吗?那么当我们有一个样本时,我不会注意形状,因为它只是一个数字,它会进行广播。当有多个样本时,我们不注意形状也可以,它也会进行广播,但我不想让它自动广播,我想自己做。那么此时,改变这里的形状,让它和这里的21一致,以便我们让它们匹配。

那么最后这里是刚刚给大家试了两个样本。那么这里我们一次做四个样本。四个样本一次,对吗?这里我们有x。X包含整个这一列。Y包含整个这一列。就是这样。我标记1,这样它就有两个维度。这个它有两个维度,它就是一个4x1的矩阵。这是一个向量。这是一个4维向量。然后经过这里,它会返回给我们输入。我们的输入X。X是4x1。四个样本。每个样本有一个数字。就是这样。因为这里我们只有一个数字。一个特征而已。所以是四个特征,四个样本和一个特征,4x1。4x1放入这里。这是一个形状为4 1的张量返回给我们。就是这样。

那么每个线性数字,每当你们设计线性层时,它只关心一个样本。在设计方面,我们总是认为我们正在为一个样本运行。那么一个样本只有一个数字。那么一个数字输入,一个数字输出。就是这样。那么我们有四个样本,我们就会有四个样本对应的输出。那么对于回归问题,每个样本的输出只有一个数字。所以这里它会输出41。就是这样。

然后这里我们匹配,我们匹配两个,匹配几个形状。就是这样。然后因为我们会使用for循环运行多次,所以在计算导数之前,我们记得将总和设为0。然后这个只是我们额外做的。这是一个与技术无关,也与知识无关的步骤。它只是一种做法,对应于我们在编程时将其设为零,或者这是TensorFlow或Python要求我们做的做法,它不包含任何深奥的知识。我们只要在计算导数之前,记得按照这样的三步方式进行,计算导数和更新。那么这里我们传递了所有的n个样本。

然后当我们想用一个样本进行训练时,这里我们只是切分出来,没有任何改变,它保持原样。没有任何改变。好的,现在我将为逻辑回归问题一步步地做。在逻辑回归问题中,我们将从...开始。逻辑回归,我们关注这张图。那么我们有两个新知识,那就是sigmoid函数和一个名为二元交叉熵的损失函数。那么我们有sigmoid函数,全部都是sigmoid。而这里在网络中我们有二元交叉熵损失。那么现在我将为你们尝试这两个。sigmoid函数,对吗?

那么与其我为sigmoid单独创建一个例子,现在直接用这个例子可以吗?就用这个例子来做给大家看。那么为了准备一个小的函数在这里,必须是损失函数。那么我们有,我们先用sigmoid函数进行二元测试。Sigmoid是我们有.sigmoid,对吗?就是这样。然后现在创建一个x,这里叫做sigmoid层,它是一个层或一个函数都可以。以后它可以单独成为一个层X,0.0和0点,以及1.0,看看等于多少?AD也可以等于XO除以X,嗯,t.sigmoid,对吗?T.sigmoid sigmoid,啊,这里我们必须.sigmoid,检查一下,这里已经理解了,但我检查一下nn中是否有,以便我们统一,让大家在这里不会困惑。试试看有没有。

那么它有。好的,现在我要说的是,目前在幻灯片中,它有这个,在幻灯片中是这个。在幻灯片中给大家举个例子,我们有class sigmoid,我们直接用,就像函数一样。那么这里我们有set sigmoid,我们有set sigmoid,我们直接传入。啊,这个是小写函数了,那么它有什么区别呢?这里只是一个函数,因为sigmoid不包含参数,所以没有太大区别。但是这里是一个层,那么我认为会更多地使用这个,因为它在深度学习中是一个层,所以我们就把它理解为一个层。那么本质上它的运行方式是相同的。如果这里是一个层,那么我们就声明然后像刚才我们使用的方式一样使用。而这里是一个现成的函数。那么现在这样做,大家会觉得困惑,突然一会儿是层,一会儿是函数。所以我将使用层的方式。那么通常那些外部函数,它内部都有一个对应的层。为什么叫层?因为它在神经网络中,所以叫层。就是这样。

那么这个它返回给我的是0,那么等于0.5,对吗?就是这样。1它等于某个值,但是0它会输出0.5。好的,这是sigmoid。那么稍后我们会使用这个sigmoid。那么如果我们使用函数,我们就用小写字母s。

然后此外我们还有二元交叉熵。那么在二元交叉熵中,它会接收y帽。大家注意,在sigmoid的二元交叉熵中,通常我们会理解这里我们有四个样本。第一个样本返回y帽1,抱歉,第一个样本的y帽,然后第一个样本的标签,然后第二个样本的y帽和第二个样本的标签。就像这样。那么此时我们计算,那么它会输出总的损失值。现在单独计算一下,只计算一个。例如我们0.4到1,它们相距很远,看看会输出什么。它输出一个值0.9。例如我们给0.1,它应该更大,对吗?那么它输出2.3。就是这样。在这里假设我们给0.9,那么会输出一个非常小的数字0.1。那么这就是二元交叉熵函数。它就像我们一直在做的函数一样。负log y帽。那么它在这里会为我们计算的是负log 0.9。就是这样。

现在我们基于两个新东西。第一个是损失函数二元交叉熵。第二个是sigmoid函数,用于实现逻辑回归。好的,这是我将一步步实现的最终代码,以便大家更清楚地理解。好的,这里,这只是一个图。我们有两个参数。而在逻辑回归问题中,嗯,我们仍然有x,我们将其连接到j,然后j经过sigmoid,它就会输出y帽。那么这里如果我们有很多x,那么都会连接到j。所以这是一个线性层。那么,例如这里的线性层。输入是3,输出是1。那么对于这个简单的例子,输入是1,输出是1。就是这样。

然后我们有这个。好的,现在我们来试试。已经准备好这个参数了。我会复制。这次我将用两个样本和大家一起编码。这是第一个样本,这是第二个样本。刚才我添加了一个样本,现在用两个样本看看有什么不同,以便大家看到全貌。好的,为了确保,我只复制。只复制真正需要的。这个文件我也上传到云盘了。大家可以在上面获取。

好的,逻辑回归问题,在这个问题中。这个问题我们分析,这个值1对应B,对吗?那么1是乘以B。这是参数B。这是W1。这是W2。那么,这是x1,这是x2。那么,如果我们创建线性层,它将是linear 21。那么,因为这个问题我们有两个特征,对吗?就是这样。好的,有两个特征。所以现在创建一个linear 21,我打印出来看看它的结构是如何存储变量的。

那么这些,尽管稍后我们会训练多个样本,但大家读到这里时,可以理解我们正在为一个样本训练,以便更容易想象。那么因为我们有2个x,所以这里我们有两个W。W1和W2。正在打印权重。那么W1和W2。就是这样。然后打印偏置。偏置我们只有一个偏置。我们再加。而这里大家记住,这里它是一个矩阵。所以这里我们只有一个节点J,所以我们只有一个W。那么如果我们有很多J,那么以后它就是一个多行的矩阵。好的,目前线性层和逻辑回归问题它只有一个J,所以我们只有一行。这里我们有很多列是因为我们有两个特征X,所以我们有两列。就是这样。

好的,现在才赋值0.5。为什么是0.5?因为这里是W1。W2等于0.5和-0.1。所以已经赋值为0.5 5和负负0.1给这个,然后这里是B偏置0.1,这里偏置0.1,那么运行出来这里是0.5和负0.1,这里是0.1,这是用来做什么的?为了重复这张图,看看它是否能重现。

好的,好的,现在才计算什么呢?现在有这两个,有x和theta,那么当然我们不是取x theta或者x theta什么的,我们这里是线性层,我们会使用这个线性层,这个线性层我们就可以想象成,好的,输入是两个节点,输出是一个节点,那么它就是我们有这个输入,这个输出,然后连接起来的动作。那么,它就是这里的动作,例如J,这个是J,那么等于J。X1 X2,那么它等于X1 W1加X2 W2加B。它会自动在某个地方加上B。那么,所以我们只需要声明X。有两个X。一个是J。那么现在已经计算过了。

那么这里就当作我们有这个,对吗?复制到这里。就是这样。现在我重新计算x,x等于这个,那么我复制一下,这样快一点。下面已经创建好x了。X在某个地方,这里,对吗?已经创建好,我会慢慢地重新做,而不是直接给出代码,这样大家更容易跟上。那么创建的是1.5和0.2以及4.1和1.3 1.5。那些数字1就不用管了。数字1是它以后自己做的。现在我们这里就只放入x的值。这是两个特征。而数字1是这张图是向量化的添加。好的,1.5 0.2 4.1和1.3在这里。就是这样。然后我们有这个线性层,这里我们运行出来看看J等于多少。

好的,J等于0.8和2.0。就是这样。J = 0.8。8和2.0。上面有什么数字可以查吗?没有,对吗?这个是直接计算sigmoid了。好的。那么就直接计算sigmoid了。啊,我复制一下,这样快一点。现在我不打字了。复制快一点。在哪里?在上面,对吗?Sigmoid在这里,然后在这里创建sigmoid,然后运行它就会输出y帽,经过sigmoid就是y帽,对吗?然后我们传入j,然后是0.6 69和0.88。好的。0.69和0.88。那么就没问题了。假设这张幻灯片是正确的。就是这样。

那么此时我们看到,好的,0.69和0.88。好的,现在我们计算损失。损失我们用什么呢?这个二元的。二元,我声明。怎么声明呢?T.N. 二元有损失。损失函数。哦,这里它已经有现成的变量了。没关系,可以重复。torch.nn.binary_cross_entropy_loss。然后这个,如果我们之前没有安装numpy,大家就不会理解里面在做什么。它做起来看起来很快,但我们觉得它做得太好了,最终我们不理解它在做什么。这里它会输出L值。就是这样。这个在大家已经编写过numpy代码后才有意义。

然后我嗯嗯,两年前用Keras它更短,但太短不好。太短了,当你想修改什么时会非常困难。修改的需求是非常实际的。我去复制y。我复制快一点。我复制,我把Y直接放在这里,让它更近。y = 01,对吗?y = 01。第一个样本y = 0。第二个样本y = 1。所以是第一个样本。第一个样本y = 0。为什么我不放01呢?那么我给大家试试。首先我先不运行这个。那么我在这里打印形状。这里的形状是2x1,对吗?

那么2x1,y帽是2x1,那么这个y我们也必须做成2x1,以便它们匹配,这样就不需要处理,我们也能控制。所以这里这样赋值,它就是2x1。它就像上面的形状一样。这是2x1。然后计算损失,传入y帽和y,对吗?计算损失时,我们传入y帽和y。然后计算里面的交叉熵什么的,对吗?那么它输出0.65。好的。0.65。对吗?好的,好的,然后现在仍然做对了,因为刚才已经解释过这个了,那么就直接输入这个,尽管我们没有使用for zero c,对吗?

那么我声明,我再声明一遍,让大家看到,重复一遍,让大家更清楚地看到这个声明,复制整个这段。好的,声明这个。然后它会更新某些参数。更新这里的参数。线性层,对吗?传入并调用参数函数,参数是0.01。看看参数是多少,可能不是0.01。我们试试看它是否一样。

好的,然后我调用zero。在我们调用这个函数之前,我们调用zero。反向传播之后,打印出,呃,打印什么?啊,打印这两个。打印这个变量,对吗?就是这样。并打印偏置变量。就是这样。那么,啊,这里这里,对吗?这是两个变量W的导数值。W1 = 0.5,W2 = -0.1。然后不同了?啊,哪个错了?哪个错了,大家?我我我,大家。大家在这里调试,点我损失。那么大家有没有跟着我这里?此时有没有和我一起?正在做什么了?不不,还没还没step。现在再说一遍。目的正在做什么?调用loss.backward函数后,想打印出来看看权重的导数是多少,偏置的导数是多少,但我打印错了,大家帮我修改一下看看。我这样打印不行,那应该怎么打印呢?大家还记得吗?这个是我正在打印权重值,对了。点那个。所以很多时候我们编码时会有错误或bug。那么这里W1 = 0.2,W2 = 0.06 - 0.06。就是这样。然后这个等于0.28,对吗?-0.06,这个B是0.289,好的,对吗?那么就没问题了。

好的,然后我在这里给大家看全貌,如果它对了,我就直接删除这个,让它简洁一点。好的,就当作这个对了。那么现在我才更新。更新我们用什么?就用这个点step。点step啊。就是这样。然后我打印出两个变量,对吗?现在才打印出这两个变量,那么更新就是我们看看变量是如何变化的。就是这样。那么它会输出049减0.09 09,然后这个049这里选择的是W1,-0.09 W2,B=0.07,抱歉,0.097 0.097 1,对吗?也是1。好的。巧合了。通常后面的那些会四舍五入,这个没问题。就是这样。那么我们已经完成了一次逻辑回归问题的运行。就是这样。

逻辑回归问题的一次运行。好的,我才删除,给大家看。就是这样。当然,当我们实际运行时,我们不会在这里声明。当然不会。我们会在上面某个地方声明,对吗?好的,这个也一样,我们会在上面某个地方声明。然后我们不需要这样做。那么这里我们创建,这个是获取数据x,这个y必须放在这里。这个是我们从数据中加载出来的。那么当我们获取数据后,我们计算,我们计算

哎,你看。啊,这个也必须在这里声明。那些需要的东西都要声明。这个是模型,那么这个就是model。我们理解,我们理解它是一个model,它包含那个。Mode它再包含这个才对。看。这俩就是model。然后我们加载数据,计算输出,计算损失,更新。就那样。

然后,然后小河问为什么在zero grad那里要再次解释,为什么有这个step,而在上面做的时候却没有呢?然后,把这个删掉。第一个问题是,如果只运行一轮,那么删掉它能运行吗?答案是可以,但是如果我们运行两轮,也就是for循环的话,就必须有,那为什么呢?那是因为,因为我再说一遍。刚才已经说过这部分了,但我们说得更实际一点。等我一下,我翻一下代码。逻辑回归,大家等一下。哎,我们这里是专门做什么的?然后我们专门做minch。我们必须按照普通的方式编写代码。已经失败了。再试一次,如果不行,就翻回线性回归的课,等我一下。线性回归上面有很多样本了。这里设为0。看这里。每次这个就是一个step,大家从这里到这里。从这里,大家看,从for循环到这里我们更新。更新完成就是一个step。Step就是它执行这个动作,它会累加每个样本的导数,累加起来再除以平均值进行更新。然后它运行到下一个循环。那么在执行之前zero grad的动作,就是把这个全部设为0。如果不设为0,那么旧的导数仍然存在。就是这样。就那样。明白吗?就这么简单,没有什么特别的。好的,就这样。

然后因为之后有一些问题,我们不想,我们想继续做,它就不会为我们默认做。所以我们有没有zero grad?有的,大家。总是,总是有的。刚才在做的时候还没有介绍,因为想一步一步介绍,所以现在绕回来,总是很难,即使是新的反应问题,在计算导数之前,我们总是要清除所有内部变量,全部清除,全部更新,全部重新初始化为0,这样我们才能重新计算导数,很多时候这里面有很多样本,它是累积计算的,好的,这是逻辑回归问题。从总体上看,这是逻辑回归的代码,我们有很多,也是类似的数据。那么这时我们计算y帽,计算损失,然后计算导数并更新,就这样。那么它只有五行代码。而这是损失的声明,优化器的声明。剩下的是模型。好的。

呃,大家对这里有什么问题吗?因为有很多新的知识点,连续不断,对吧?大家有什么问题就直接讨论,以便复习。打开这个给你们看。在这个里面大家还有什么疑问吗?看看有没有什么问题?没有,对吧?已经看到都讨论完了。然后它才有一个这样的,没有问题,对吧?然后我们才有一个,呃,如下,例如y帽1是不是等于,例如我们有2个j1,等等,呃,然后试试y帽而不是y帽1。这不是softmax问题,而是,呃,逻辑回归问题,所以我们用sigmoid,那么它等于什么?1除以1加上e的负j次方,对吧?就是1除以e的负j次方。然后假设我们取对数。那么通常我们是不是计算y帽,y帽等于这个。然后我们计算什么函数,我们就会取y帽的对数,对吧?那么,y帽的对数,我们直接代入,等于1除以1加上e的负j次方的对数。那么它会等于log,log 1等于多少,大家?log 1等于0,对吗?log 1等于多少,对吧?帮我确认一下。log 1等于0。对的。这就是为什么这边是1除以p的对数,对吧?然后减去,减去1加上e的负j次方的对数。看。然后。那么这时我们看到1除以0最终等于这个。然后人们去进行数值分析。这个是人们去分析,然后他们发现,哦,当我们计算这个的时候。那么我们计算这个会比计算这个更稳定。看。为什么呢,可能我得再研究一下,因为它看起来有点长,所以我只取最终结果,就是计算这个。就是我们去计算e的幂,很多时候这个会溢出,然后什么的,所以人们研究发现这个会好一点,只是好一点。所以在计算方面,它的精度更好,也更稳定。人们有证明什么的,但我没有深入阅读。那么这时,与其先计算y帽,然后把这个y帽传给损失函数。损失函数会再计算一次这个。那么很多时候,很多时候它可能效率不高。在softmax问题中我们会看得更清楚。J1产生y帽1,J2到这里,那么y帽1是不是等于E的J1次方加上E的J1次方加上E的J2次方。看。然后,与其我们去计算这个,我们已经计算过一次e的幂了,对吧?然后我们又去计算一次log,这有点奇怪。既有e又去计算log,这有点奇怪。那么这时我们计算这个,它会等于e的j1次方的对数减去,呃,e的j1次方加上e的j2次方的对数,那么它等于j1然后减去这个,对吧?减去这个,其中,呃,这个e,E的J2次方会等于E的J1次方减J1加上J2次方,那么会等于,抱歉,这个,我减J1加上I1会等于J2减J1乘以E的J1次方,代入这里可以吗?不能在这里,那么它会等于log的,呃,这里有公因数,直接提取公因数E的J1次方乘以1加上E的J2次方减J1次方,对吧?然后等于J1减去E的J1次方的对数加上1加上E的J2次方减J1次方的对数。那么这个抵消这个,这个抵消了,对吧?那么最终等于负的1加上E的J2次方减J1次方的对数。那么人们研究发现,分析出来,与其我们用这个公式计算y帽,然后计算对数。那么这时我们只计算这个,直接计算这个。这个是我们直接传入J1和J2,对吧?那么我们直接计算log,它就会计算。也就是说我们不需要计算y帽,因为在计算和数值分析方面,人们分析认为这样更稳定。那是什么意思?那么是什么意思?那么重新运行这个意味着即使是Python的第一个版本,人们也没有意识到。那是因为创建这个版本,第一个Python版本的人,他们不是那边的专家,所以他们也不知道。因为那完全是另一个研究领域。所以很多时候我们,呃,一开始无法知道所有的事情。

Wave,对吧?那么回到这里,它出来是-0.16,对吧?是吗?更新之后,慢慢地,更新之后,这里我们没有更新后的值,很难计算,对吧?这个我们在这里计算。怎么出来不一样了?呃,线性,呃,出来不一样是因为我忘了想复制一份来做另一个,我再给你们描述另一个,抱歉大家。贴在这里。那么这个是0.49,49和-0.09,对吧?这是0.4,0.49和-0.09。看。那么这个完全没问题。但是后来Python他们才看了这边,看了那边,他们发现,啊,有这样一个技术,他们才说,好的。那么这样的技术,技术是怎样的?技术如下,就是别再计算这里了,别再计算y帽了。我们把这个y帽遮起来。因为根据刚才的,我们有负的log 1加上e的j2减j1次方。那么对于其他问题,而对于那个问题,对于逻辑回归,它是不同的公式。那么这时我们只需要传入J就行了,不要传入y帽进行计算,我们计算e的幂,然后过一会儿又取它的对数,很多时候这有点奇怪,因为log和e是相互抵消的,log和幂是相互抵消的,那么很明显,我们只要代入,很多时候我们就能尝试抵消掉一点点,那也会帮助我们减轻负担,所以首先我们这边减少,我们不再计算这个,也不再计算sigmoid,当然我们也不能用这个函数,对吧?那么那时我们会用另一个函数。那时Python会生成另一个新的函数,它是在后面版本出来的函数,所以名字有点奇怪。名字有点奇怪的地方是,因为它是在后面出来的,按理说它应该是默认值,但是默认已经用了这个,所以它反而有一个更难听的名字。with logit。Logit就是J。J就叫做logit了。有没有搞错名字?老师等一下。呃,我们运行这个,运行这个会产生这个,啊,天哪,这里应该代入J才对,对吧?代入y帽有什么用呢?J这个我们编程时经常会犯这个错误,复制粘贴很容易出错。那么还是旧的数字,对吧,大家?0.49和0.09。这就是为什么在Python中有两个函数。一个函数叫做binary cross entropy loss,这是我们理论上脑海中的标准函数。第二个函数是binary cross entropy with logits loss,这意味着输入是j而不是y帽。大家会在这里感到非常惊讶,如果大家听到会觉得,哦,怎么这么奇怪呢?那么那时大家又做了那个奇怪的事情,因为在早期使用keras,使用tensorflow,使用,呃,pytorch的时候,还没有那个版本。后来人们才领悟到,因为他们深入研究才领悟到。最初它总是先有基础的,所以这就是为什么这个才是标准。尽管名字不好听,但这个才是标准。它会帮助我们更好地进行计算。还有一个看起来很奇怪的是,人们只取J,而不是通过幂,而且它不是标准名称,对吧?

那么,那么它就是这个长名字,传入logit,logit就是字母J,所以我们有这个版本,大家。那么我上传到Drive的代码也有这个。有向大家介绍这个。好的,所以,所以总结一下,这个函数必须传入y帽。这是y帽。真正的y帽。通过mo转换y帽。而这个函数,这个函数我们只传入J的值,大家。只有J,然后我们记住这两个。好的,有点乱,大家记一下regr np loss是传入y帽。而这个函数传入J,是为了等一下softmax那里还有一个注释,以免混淆。好的,那么我们完成这个,我们去softmax。我们去softmax,做完就算今天结束了,对吧?

那么,就这样,同样地,呃,我们做softmax什么呢?Softmax我们不再有二元函数,我们有交叉熵函数。那么当人们领悟之后,交叉熵函数他们就不再添加“with logit”这个词了,而是取默认值,并且只有这一种类型。所以交叉熵总是接收J的值,大家。总是如此。注意,所以对于刚才的函数,刚才的是二元的。这个是交叉熵,它只有一种类型接收j,没有接收幂的类型了。那是因为它已经从那里学到了经验。好的,那么我们来看看softmax问题和,呃,逻辑回归问题有什么不同。那么等一下,我会找一下打印出网络结构的那个代码片段,以便大家更容易理解。这里有了,然后softmax就完了,那么在softmax中。现在,我向大家介绍一个叫做NN sequential的东西。刚才只是用了这个,对吧?看。只用了linear。现在我们才有一个叫做nn sequential的东西。它是什么?看。那么刚才如果我只有一个linear,那么我总是只有一个单一的层。现在假设我们有两三层,以后我们把它们堆叠起来,那么这时它就有一个数据结构。我们把这个理解成一个列表就行了。它只是那个列表。在这里面它为我们包含了一个linear。然后以后我们想再添加一个linear,我们就放在这里。再添加一个linear就放在这里。添加sigmoid就放在这里。看。那么sequential就只有这样的作用。然后这样括起来我们很容易看到。那么这个sequential我们理解它是一个模型。模型可以是逻辑回归模型,可以是softmax模型,或者其他什么模型,取决于我们在这里面放了什么。看。那么对于刚才的逻辑回归问题,如果我们使用binary cross entropy函数,它需要sigmoid,那么就会放入nn.sigmoid。那么这就是线性回归模型,抱歉,逻辑回归模型,它包含一个线性层和sigmoid。好的,那么我们有sequential,对吧?那么如果这里放2,这里放2。大家猜猜这里我们有多少个参数,这个sequential模型里面只包含一个linear,就好像它只有linear一样。与其把linear放在外面,不如把它放在模型内部的一个列表中,结果是一样的。看。那么有六个参数,对吧?2乘以3是6,对吧?那么有六个参数。好的,这六个参数都是可训练的参数。以后我们会学到这部分,它有一些不可训练的参数,稍后再说。看。那么这就是这个问题,这就是当我们为softmax问题使用,呃,一个线性层的时候。那么它的输出会是两个节点或更多,对吧?那么这个问题,它有二元分类的例子,那么我们就有两个J节点。分类,呃,三个类别,那么我们就有三个J节点。看。好的。那么这里假设我为哪个问题编写代码呢?我等一下。先说这个。现在我为,呃,这个问题编写代码,对吧?这个问题我们只有一个x,所以简单来说我们有一个linear 1。这是什么,大家?这个问题是,呃,二元分类。那么问号是多少?问号这里是多少呢?等于2,对吧?所以这里它会是linear 1 2,输入是一个x。那么然后我们进行二元分类,两个输出。两个j和两个y帽。那么现在我们试着计算。那么它也类似于我们讨论过的。它只不同在哪里?不同在于我们将使用交叉熵损失函数。而且在这个函数中,它已经从binary cross entropy with logits loss函数中吸取了经验。所以这里我们只传入j就行了。所以这里我们将传入J。所以只有这个是新的。所以与其像刚才讨论的那样重新输入,我已经准备好那段代码了,所以直接翻出来。我们慢慢地重新输入,就像刚才一样。那么直接翻出来。它在,呃,什么问题里?Softmax回归,对吧?好的,我慢慢和大家讨论。就是最初我们创建了一个linear 1 2,我们看看这个变量的结构是怎样的,1 2,那么它有两个V,两个W1 W2,并且它有bias 1和bias 2,然后我先看一下,我们有W命名为0和W1,我们有bias 0和bias 1,那么这时我们才能计算出两个相应的J,对吧?所以回到这里,我们有W0 W1和Bias 1,2,现在我手动设置4个参数,以便我们控制,所以我现在手动设置权重:W等于0.2和-0.1,0.2和-0.1 1,我们看看0.2减0.1,对吧?Bias是0.1和0.5,0.1和0.05,好的。B错了,对吧?B这样做是错的。我们必须注意。它的结构是一维的,那么我们必须做成一维的。如果我们做得不一样,它就会有不同的结果。看。然后我再运行一次,看看它是否正常,是否一样。看,它一样,结构相同吗?这是2 x 1。那么这里也是2 x 1。这是一个一维的,这里也是一维的。那么,就这样。0.2 - 0.1 1.0和0.05。那么,0.2和-0.1,0.1和0.05。好的,我们来计算一下J是多少。这里我们有两个样本。第一个样本是1.4,第二个样本是4.5。看。而y,当我们训练的时候,y我们不需要转换成one-hot编码,它会自动为我们做。第一个y是0,对吧?这里y=0,这里y=1。这是0的one-hot编码。这是1的one-hot编码。看。看。这是y=01,对吧?好的,我们来看看。那么这里先用一个样本计算。用一个样本1.4计算。好的,一个样本1.4,因为,呃,这里我们必须这样放。我们可以这样放,或者像这样放也可以。那么原因是什么?放在,放在课程结束时讨论图像时,大家会看得更清楚。当处理一个真实的,有60,000个样本的问题时,我们会看得更清楚。而现在我们先有一个,好的,一个样本,然后一个样本。一个样本我们必须放入,呃,放入一个张量。但是假设这个样本我们有很多特征怎么办?我们有两三个特征怎么办?所以它才会有这样的形状,因为以后我们有更多特征时,它就会是这样,对吧?所以即使我们有一个样本,它的形状也会是这样放置。一个样本,如果我们有更多,我们有超过一个样本,我们就换行继续做,就这样做。那么我们有两个样本4.5,就是这样。现在我先添加一个样本。一个样本运行出J。那么它会出来是0.38和-0.09,0.38和0.09,可以吗?好的,然后我们计算损失,计算损失,然后计算损失,那么这时我们传入J并直接计算损失,创建这个损失,我们直接传入J,但是我们不计算y帽,大家,损失这里等于y,y设为0,这个张量的0,抱歉,这个样本的0,那么它就会产生损失,然后我们正常更新,就像我们刚才学的那样更新。好的,然后我,然后我会把代码打包到一个里面,供大家观察密码。三个pass backward必须在这里,对吧?然后是step,然后是linear。好的,这是softmax回归。我们最初取出数据。然后我们计算j,只计算j。我们不要计算幂。看。然后我们计算损失,传入j和标签。然后我们计算导数并更新导数。好的,就这样。那么我们基本完成了,这样就完成了所有的问题。

那么回家后,大家如果想确保自己完全理解,就请重新阅读。大家重新阅读那个lesson demo文件。这个文件,大家阅读里面的文件就行了,但是lesson demo是我认为描述最清楚的,应该先读。那么大家读到哪里了?那么当大家能够自己重新做一遍时,当然现在大家什么都记不住。因为我们刚学,大家回去思考思考,然后记下那些函数和类,然后大家能够自己重新实现这三个问题,就算可以了。好的,那么这里我快速说一下sequential。刚才我们有那些层,那么现在sequential是一个概括。以后深度学习我们就会用到这个。sequential本身就是一个序列,一个列表。那么一个层的列表就变成了深度学习。那么今天我们已经,我们已经触及到深度学习了,大家。我们已经摸到深度学习了。下周我们就要进入深度学习了。那么这样的连接叫做全连接层,或者在,呃,Python中是线性层,对吧?那么这个,这个我们用的是linear,对吧?Linear 43,在里面,然后我们放入,我们放入softmax,那么这里只是设计方面,而我们的模型,这是理论上的图,大家。当我们向某人从理论上展示时,我们就给出这样的图。而当涉及到代码时,代码是为了实现,它不代表理论。所以当我们实现的时候,它只到J。那么,这个它自己,这个是它根据损失函数自动运行的。那么,但是当我们显示图片出来,让人们看我们的模型是怎样的时,大家仍然需要画出softmax。好的,例如这里是31,那么这里我们是31。这里是43,那么这里是43,对吧?那么这是一个库,只是用来打印这个。大家不需要记住这个。好的,那么对于softmax问题,那样就已经,就已经是一个softmax问题了,我们不要再把softmax函数放进去。因为交叉熵损失函数,呃,它已经包含了,呃,它已经包含了softmax函数了。好的,那么现在总结一下我们刚才讨论和看过的东西。

好的,这是一个特征x。那么我们线性回归问题的一个特征x。那么这个x,我们有一些参数,它会产生y帽。所以这里是1,对吧?好的,然后它会是11 1。我们这里面有两个参数。这两个参数。那么对于这个问题,我们有三个参数。三个x1 x2 x3。那么x1 x2 x3一个j。那么我们会有linear 31。那么,linear 31再加上一个bias,我们就有四个参数。在其他问题中,这个问题我们更多,那么这时我们数一下它有多少个参数。我们有13个特征。那么这里它会是linear 13 1,它再加上一个参数b就是14。看。那么我们就这样计算。好的,对于逻辑回归问题,参数数量不变。它只不同在于我们使用sigmoid函数。那么如果我们使用loss with logits函数,我们就不需要sigmoid,而如果我们使用binary cross entropy loss函数,那么那时我们就有sigmoid函数,大家把那些记下来,那么如果只是这样,那么我们使用这个损失函数,那么这已经是一个sigmoid模型了,不一定非要放入这个,抱歉,已经是逻辑回归了,不一定非要放入这个sigmoid,这个是11,所以这里是11 1,参数是两个参数,对吧?那么,这个问题有两列。那么这里会是21。因为sigmoid和逻辑回归它只返回一个节点。那么,所以这里是三个参数。这个1 2 3 4,对吧?那么它会是41。那么再加上bias就是5。好的,而对于softmax问题,softmax问题我们有这个损失函数,那么在这个损失函数中它已经集成了softmax函数在里面了,所以这里我们只返回J的值,所以这个的输出只返回J。看。所以这里我们有,我们有,呃,这个我们有一个特征,对吧?但是这是softmax的二元分类问题,所以我们必须有两个节点。看。那么一个节点连接着两个。一个节点连接着两个,也就是说,一个J节点连接着特征和bias。另一个J节点也连接着特征和bias。所以我们有2乘以2等于4,可以吗?我们有四个参数。好的,同样地,这里我们有三三

那个类。所以这里我们会有13。就是这样。那么我们有三个节点,所以3乘以2是6个参数,对吗?然后这个是1 2 3 4 1 2 3。那么我们有四个输入和三个输出。那么我们有3乘以5等于15,对吗?那么我们会有线性层,这里是1 2 3 4是3,所以是线性43,对吗?线性43这里加上3就是5,所以3乘以5等于15,15个参数。

好了,现在我们进入Q部分,然后我稍微讲一下图像。稍微讲一下让大家知道。好了好了,我们结束课程。好了,我们将在25点开始,各位。10:2 10:25 5 啊。

>> [音乐] >> 哦

>> [音乐] >> 呃

>> [音乐]

好了,德同学说要再展示一下softmax,对吗?稍后完成Q部分。那个上面也发了演示所有内容的那个代码。各位也可以从云盘上获取那个文件。好了,我们开始开始。好了。啊 [音乐] 有损失函数哦,各位。就当损失函数不存在。只是在谈论模型。好了,那么这个我们有两个特征,两个特征,我们有三个输出,所以它就是23,对吗?简单来说就是23。好了,然后下一题。

>> [音乐] >> 只有两个,而且两个都坏了。那么刚才说的,在softmax的那个练习里,对吗?那个交叉熵损失函数已经把softmax集成在它里面了。它里面已经自带softmax了。所以在模型设计方面,我们不要再附加softmax,就当我们传递J,以后我们只传递J。那么如果想传递J,它就只通过线性层,这里怎么能再通过softmax呢?也就是说,或者换句话说,在Smart的那个练习里,这个损失函数就在它里面。当这个损失函数运行时,它内部会调用它内部的softmax函数。所以在模型设计方面,我们只需要这样设计就可以了,而不是那样。这样的话,调用两次softmax也可以。这样这样才对。所以是A选项,各位。各位记住这一段。这个这个我们必须记住才能做。而当我们做softmax的练习时,因为softmax是以后深度学习的基础。以后我们会一直使用这个函数。所以当我们在设计模型时,我们只返回J值。在我们传入softmax之前的值,理论上我们会传入softmax,但从代码层面来看,就当去掉softmax。你记住这一段哦。

>> [音乐] [音乐] >> 好了,两个都对是不行的,因为这个地方这个地方,我们总是会有这个的,各位。那个第一个线性层,演示中没有这个,是慢慢地引入知识。意思是还没说,还没来得及说。所以我们总是会有这个,所以特别是我们有for循环,这肯定是毋庸置疑的。那个这个是它有重复。我们演示一次就关机,那没问题。但当我们多次运行训练时,肯定要有这一步。这一步是我们计算求和时将变量设为0的步骤。这个没有啊,所以不行。好了,只能有数字1哦。哦,-1啊,忘了说。各位猜猜看。各位猜猜看,刚才还没说,猜猜看。

>> [音乐] [音乐] >> 好了,等于那个。那么在这里,当我们的输入有一个特征,并且是softmax的练习时,这里是2 1 2,那么通常情况下,这里是输入,这里是输出,这个线性层的输出会是2,两个节点,因为这里是2,所以我们有四个参数,对吗?我们这里有偏置,2乘以2是4。但是当我们用PyTorch训练时,它支持我们用一个样本训练,用m个样本训练,或者用n个样本训练,想训练多少就训练多少。它只要放进去一个样本,就用一个样本训练;放进去10个样本,它就自动训练10个样本。代码没有任何改变。没有任何改变。但是在设计方面,我们正在设计,这里我们正在设计模型,那么在设计时,我们并不关心我们要训练多少个样本。当我们设计时,当我们设计完成后,用一个样本训练还是用n个样本训练都可以。想训练多少就训练多少。所以在Python中,当我们真正训练时,这时我们必须有一个参数来告诉Python我们正在训练多少个样本。所以在设计方面,它会显示数字1 -1。-1意味着它稍后会确定。它在我们实际运行时确定,它就是代表样本数量的数字。例如,我们训练32个样本,32张图片,或者是128张图片。那么这时,当我们实际运行时,我们传入128张图片,它会通过这个线性层。那么通过这个线性层,每张图片都会变成两个节点,变成两个数字。那么这里是128张图片,每张图片都变成两个数字。所以这个-1会在我们真正训练后确定。就是这样。那么这就是样本数量。当我们在NP中操作时,我们是不是有一个n乘以多少的矩阵。N乘以K,其中K是样本数量。N是,抱歉,K是特征数量,而n是样本数量,对吗?所以我们经常会有一个矩阵,这里的每一行都是这个矩阵,对吗?矩阵。矩阵,这里是行数。就是这样,这是行数,而对于每一行,它有两个列,对吗?就是这样,这是每一行有两个列。意思是每个样本都会在每一行上表示。每个样本表示为一行,行数就是样本数量。那么这就是样本数量,对吗?就是这样,和我们一模一样。就是这样,它在这里。好了,我们记住这个。它这里有一个样本数量的概念。选两个选项哦,各位。

>> [音乐] >> 好了。好了,我们来分析一下A B C D。啊,这是一个二元分类问题,这个二元分类就是逻辑回归,逻辑回归就是二元分类问题,对吗?这就是二元分类问题。如果我们采用逻辑回归的方式,那么这里我们有两列,这就是二元分类,那么我们只有一个输出,对吗?逻辑回归是二元分类。那么对于这个问题,从设计层面来说,这个从设计层面我们忽略损失函数的问题。那么对于二元分类问题,如果我们使用逻辑回归方向,并且使用sigmoid。那么输入是数字2。那个输入是数字2,这里都是2了。逻辑回归使用sigmoid的输出是1。那么这里是1。然后我们使用Smil。那么这就是完全可以应用于普通二元分类问题的方法。那个就是,当进行二元分类时,我们有两种方法:要么输出一个节点并使用sigmoid,要么输出两个节点并使用softmax。这是广义的二元分类问题,不一定是逻辑回归或softmax回归。以后我们把分类问题命名为二元分类问题,它前面有很多层,很多线性层堆叠在一起,但是如果我们输出一个节点,就使用sigmoid,这样就可以进行二元分类;如果输出两个节点,就使用softmax,那也只是二元分类而已。各位记住那个公式哦,公式是一个节点J就用sigmoid,两个节点就用softmax,也只是产生二元分类而已。所以这里是A和D,对吗?D是生成两个节点并使用softmax。而这个是生成两个节点使用sigmoid,那不行。两个节点用sigmoid怎么行。Sigmoid的输入只是一个数字而已。它又不是输入两个数字。那个,而这个softmax,softmax的输入必须是多个数字。因为那时它才能计算每种类型的概率。所以B和C不行。A D哦,各位。A和D。好了,也选两个答案。最后一题。

嘿。那么A选项和C选项,对吗?A选项,A选项是符合PyTorch标准的,我们使用交叉熵函数,抱歉,使用交叉熵函数就可以了。这里我们有4有3,那么它就是线性43。这样就可以了。我们把它放入交叉熵函数,可以顺利运行。那个,但是这里题目说我们可以自己重写损失函数。是的,各位。我们自己可以重写。以后会和大家讨论如何自己重写这些层,线性层可以自己重写。然后以后那些激活函数我们也可以自己重写。按照自己的想法重写这些类。那么假设这里我们自己重写损失函数,那么这时我们写一个没有softmax的损失函数。那么这时它就会是C选项。那么假设我们按照这里自己重写。就是这样。那么这里这里为什么错了?这里是什么?这里5就不对了。这里只有4个,那肯定是不对的。而这里也是5,那也不对了。这里只有4个。所以如果答案,如果问题要求选两个,那么这两个是最好的,对吗?好了,你on你dot啊 manipulated。好的。恭喜各位。

好了,看看我们接下来有什么,以及是否还有什么新知识。还有很多新的东西,但是我们学到哪里就讲到哪里,如果我全部讲完而你们还没用到,有时怕你们会忘记。所以我们理论讲到哪里,就讨论PyTorch到哪里。好了,这个只是复习,对吗?我们训练的话,在这个练习里是逻辑回归。逻辑回归的话,这个放在哪里都可以,只要它在这个位置前面就行。那个,有些代码它就直接放在这里,以免我们忘记。而s的话,也请add放在这里,各位放在哪里都可以。那个总的来说,在我们调用这个之前,我们一定要记住在一个循环中调用它。那么,是的,我们对所有样本进行训练,对吗?我们计算输出,计算损失,然后更新。那么这个地方,这是一个逻辑回归问题,所以这个模型只包含一个线性层。因为它本身已经接收了J值。这个这个只是J。这里的输出是J,而不是Y hat。好了,对于softmax问题也是一样。这里我们这个输出也只是J。那个,因为它本身内部已经调用了softmax函数。好了,这就是softmax问题的模型。我们创建了一个Sequential模型,以便我们习惯使用Sequential,但实际上我们只用一个这个也可以。但是这个是一个层,只是一个层,所以很多时候我们只是勉强使用,但实际上我们这样做才是最完整的。它是一种模型,内部包含一个层。好了,而这里,这个部分就像N一样,各位。回去各位分析输入,各位打印出形状,然后各位逐行分析形状哦。刚才我们是直接添加了现成的数据。而这里我们是从这些文件加载。各位读一下代码哦。Ad创建并发送给各位三个文件夹。线性回归、逻辑回归和softmax文件夹,各位只需阅读这三个文件夹中的内容。好了,那么这里我们训练时,这里我们有一个新东西叫做item。Item是很多时候我们有一个这样的张量数据类型。例如我们有6,那么这个地方是张量,那么张量很多时候想取数字6然后给matplotlib显示出来,但matplotlib怎么会理解张量呢?我们只想取数字6,我们点item,它就会返回那个数字6,所以我们经常会有这个。那么各位回去阅读这些文件中的行哦。各位读完后,如果可以的话,自己再写一遍代码。那么这些代码大约95%和ad给各位演示的代码一样。它们只差一个for循环和从CSV文件加载,这些我们已经在前几周做过了。好了,ad再讨论一下,为下一课打开大门。那个,也为了让我们尝试处理一种新的数据类型。啊,这个讨论只在5到10分钟内哦,各位。那个就是,对于图像数据,灰度图像数据,它会以一个网格的形式存储,就像一个矩阵。而且这里我们有P值。P的范围在0到255之间。而对于彩色图像,我们有三个这样的矩阵。那么它代表了红、绿、蓝三种颜色通道,这是通常的方式,但实际上有很多种颜色通道。那个,通常人们会存储红绿蓝,那是对人眼来说最适合的颜色通道。而对于数据处理什么的,有时会有一些颜色通道更好。那个,嗯,有些程序会按照高度、宽度和通道的顺序存储。而另一些程序则按照通道在前、高度、宽度的顺序存储。那么这个就是内存的组织方式。那么现在我们还不需要关心这部分,这是内存的组织方式,就像“好的,图像会存储在一个连续的数组中”,那么它要么存储第一个的红绿蓝,要么存储第二个样本的第二个像素的红绿蓝,以此类推,或者它这样做:它存储第一个像素的红色值,第二个像素的红色值,第三个像素的红色值,然后是第一个的绿色值,第二个的绿色值,第三个的绿色值,以此类推,它有很多种这样的方式。那么我们大致了解一下就可以了。而这些东西很久很久以前,当我们还在使用OpenCV和C语言编程时,操作它会依赖于速度。那么现在重要的是算法。现在这些平台做得非常好了。那么在Python中,那些张量或者那些图像会这样存储。那么这就是图像,这就是MNIST数据。我们有60,000个样本是图像,高度和宽度是28 x 28。就是这样。那么对于softmax问题,各位,这是28 x 28的张量数据,而在softmax中,我们将使用一个线性层,传入第一个参数和第二个参数。那个,传入第一个参数和传入第二个参数。那么这个数字不能是28 x 28,它必须是相乘后的数字,也就是784。所以在我们把这张图片输入softmax之前,我们必须有一个步骤,就是把它拉伸成一个向量。那就是flatten步骤。我们有另一个数据。那么在这里,ad按照类的方式,我们放在这里也可以。我们这里就像我们通常这样声明。那个,现在给类。这里我们有一个名为flat的函数。那么最初我们先flatten,以便将28 x 28拉伸。变成一个包含784个数字的向量,然后我们通过线性层。就是这样。那么这里我们这里通常是28,对吗?那么我们不能直接传入那些J节点。这里我们有10个类别。我们有10个类别,所以我们会有输出,我们有10个节点。所以我们不能传入二维数据。我们必须先flatten,让它变成784个节点,再加上这里的一个节点。这样我们才能做到。那么各位可以再阅读一下这段代码哦。它只差flatten这个地方。各位请再阅读一下。就是这样。好了,那么这个是应用于图像数据。好了,各位啊,哦,这只是阅读部分。也就是说,各位在后面的几个模块我们会更详细地讨论。而今天的课程主要是我们将应用于线性、逻辑回归和softmax问题,所以各位回去请重新做一下演示部分,它有lesson demo Jupiter文件,各位请用ad重新做一遍,然后各位再写一遍代码哦。那么这就是今天课程的结束。各位有什么问题吗?好了,我们讨论2到3分钟哦,各位。因为明天早上在胡志明市有个会议,所以现在就叫车去胡志明市了。啊,各位讨论了吗?好了,这节课后各位做一下练习,然后看视频哦。各位请看视频解答练习,用app。好了好了,各位回去编写今天的课程代码,因为知识点有点多,所以各位要多练习,熟练一下哦。好的,就这样。各位再见。下周再见。好了,啊,各位再见。好了,PyTorch它会在GPU上运行。