机器学习&深度学习实践笔记(一):pytorch基础与线性回归

最近开始了机器学习与深度学习的学习与编程,大概也还是磕磕绊绊的走过来了,便记录一下历程与心得

线性回归理论

线性回归模型概述

线性回归的内容就是我们假设一些数据,输出(标签)与输入之间存在线性关系,也就是可以用 y = w T x + b y=w^Tx+b y=wTx+b来表示,然后我们需要找到一组最合适的的 w 与 b w与b wb,来使得模型最符合真实情况,在这里我们将我们的模型叫做H模型,因为吴恩达课程中说的就是一个hypothesis(也就是假设),我们想让我们的假设最接近真实情况

数据集

在这里,我们将数据集这样定义
{ ( x ( 1 ) , y ( 1 ) ) , ( x ( 2 ) , y ( 2 ) ) , ⋯   , ( x ( N ) , y ( N ) ) } \{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),\cdots,(x^{(N)},y^{(N)})\} {(x(1),y(1)),(x(2),y(2)),,(x(N),y(N))}里面的每一个样本的数学形式是这样的 ( x ( i ) , y ( i ) ) , i = 1 , 2 , ⋯   , N (x^{(i)},y^{(i)}),i=1,2,\cdots,N (x(i),y(i)),i=1,2,,N,其中 x x x被称为输入, y y y被称为标签或者输出, i i i表示第几个样本
当然也有的教程或者书里面是采用下标定义的
{ ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯   , ( x N , y N ) } \{(x_1,y_1),(x_2,y_2),\cdots,(x_N,y_N)\} {(x1,y1),(x2,y2),,(xN,yN)}这里的 x x x y y y一般是不同形状的,比如说在目标检测或者图像分类里面, x x x是一个图像数据(大概理解为就是一个矩阵或者三维数组), y y y代表这个图像的标签,比如说有五类图像,这个 y y y属于第几类,或者在房价预测里面, x x x就是一个向量,包括了某一个房子可以量化的各种特征(比如说面积,地理位置等等), y y y表示这个房子的售价,可能不太符合大家对向量的认知,但是这里看成一个数据对就可以,也就是相互关联的一对数据,这个也是后面程序中数据集的数学定义

损失函数

我们有了假设模型,那么我们怎么去判断这个模型是不是接近甚至等于真实模型呢?比如说我们想预测房价,那么我们根据一套房子的各种特征去进行预测,那么预测值是不是就接近或者等于它实际的售价呢?如果H模型接近甚至等于真实模型,那么我们就认为它是一个好模型,如果相差甚远,那么这个模型就不好,所以我们需要判断这个模型的好坏。
因为输入输出都是连续变量,所以我们可以想到距离这个概念,我们是不是可以把预测值和真实值之间的距离当做判断指标?
我们设这个判断模型好坏的函数叫做 L L L,也就是损失函数,理解为真实模型与H模型之间的差距,也就是不同模型之间的损失
所以我们第一眼想这么定义损失函数:直接作差
L = y ^ − y = w T x + b − y L=\hat{y}-y=w^Tx+b-y L=y^y=wTx+by也就是使用 H H H模型的预测值 y ^ \hat{y} y^和真实值 y y y之间的距离作为损失,但是只在一个样本上衡量损失没有意义,我们需要在数据集上做衡量
L = ∑ i = 1 N ( y ^ ( i ) − y ( i ) ) = ∑ i = 1 N ( w T x ( i ) + b − y ( i ) ) L=\sum^N_{i=1}(\hat{y}^{(i)}-y^{(i)})=\sum^N_{i=1}(w^Tx^{(i)}+b-y^{(i)}) L=i=1N(y^(i)y(i))=i=1N(wTx(i)+by(i))
但是我们发现了一个弊端,就是这个距离是带有正负的,不同样本之间会出现相互抵消距离的情况,假如说有两个样本 ( 0 , 1 ) , ( 1 , 0 ) (0,1),(1,0) (0,1)(1,0),那么明显 y = − x + 1 y=-x+1 y=x+1才是一个最合适的 H H H模型,但是我们发现 y = x y=x y=x也可以实现损失为0的情况,甚至还会出现损失为负的情况,所以我们需要改进模型。两个样本然后我们想到的是绝对值函数,可以让距离变为非负,或者平方函数,也可以,所以我们就使用新的损失函数
然后我们想让损失函数最小,这样就可以得到最接近真实模型的 H H H模型,那么我们怎么让模型损失函数最小呢?
我们发现,在这个线性模型里面,损失函数的取值完全取决于 w w w b b b两个参数,所以损失函数也可以记为
L = L ( w , b ) L=L(w,b) L=L(w,b)然后我们发现,这就是一个多元函数,然后我们联想到导数——函数对自变量的的变化率,那么我们就可以求偏导
在这里我们发现,使用绝对值的损失函数难以求导,所以我们使用平方差的损失函数
L ( w , b ) = ∑ i = 1 N ∥ ( w T x i + b ) − y i ∥ 2 L(w,b)=\sum\limits^N_{i=1}\Vert(w^Tx_i+b)-y_i\Vert^2 L(w,b)=i=1N(wTxi+b)yi2分别对 w w w b b b求偏导
L ( w , b ) = ∑ i = 1 N ∥ ( w T x i + b ) − y i ∥ 2 = ∑ i = 1 N [ ( w T x i + b ) 2 − 2 y i ( w T x i + b ) + y i 2 ] ∂ L ( w , b ) ∂ w = ∑ i = 1 N x i ( w T x i + b − y i ) 可以看到,对 w 的 偏导数也是一个与 x 同型的向量 ∂ L ( w , b ) ∂ b = 2 ∑ i = 1 N ( b + w T x i − y i ) \begin{aligned} L(w,b)&=\sum\limits^N_{i=1}\Vert(w^Tx_i+b)-y_i\Vert^2 \\ &=\sum\limits^N_{i=1}\left[ (w^Tx_i+b)^2-2y_i(w^Tx_i+b)+y_i^2 \right]\\ \frac{ \partial L(w,b) }{ \partial w }&=\sum\limits^N_{i=1}x_i\left( w^Tx_i+b-y_i \right)\\ 可以看到,对w的&偏导数也是一个与x同型的向量\\ \frac{ \partial L(w,b) }{ \partial b }&=2\sum\limits^N_{i=1}\left(b+w^Tx_i-y_i\right)\\ \end{aligned}\\ L(w,b)wL(w,b)可以看到,对wbL(w,b)=i=1N(wTxi+b)yi2=i=1N[(wTxi+b)22yi(wTxi+b)+yi2]=i=1Nxi(wTxi+byi)偏导数也是一个与x同型的向量=2i=1N(b+wTxiyi)然后我们联想一下,在 x = x 0 x=x_0 x=x0处的函数导数为正的话,当 x x x增大,函数值变大,当 x x x减小,函数值减小,当导数为负的时候, x x x增大函数值减小, x x x减小函数值增大,那么我们是不是可以通过不断计算导数来说实现损失函数的最小呢?答案是肯定的
w = w − ∂ L ( w , b ) ∂ w w=w-\frac{ \partial L(w,b) }{ \partial w} w=wwL(w,b) b = b − ∂ L ( w , b ) ∂ b b=b-\frac{ \partial L(w,b) }{ \partial b} b=bbL(w,b)
这样,我们就可以实现让模型朝着损失函数最小化的方向移动

PyTorch基础

我们想让电脑进行计算,而不是人工去计算,这样才可以实现人工智能,所以我们就需要进行编程,幸运的是,随着人工智能的发展,已经有了非常多的人工智能编程框架出现,里面包括了多种非常强大的框架,这样我们无需纠结于程序的细枝末节,而是专注于整体框架和理论。
我们选用的是PyTorch框架,这个框架对于初学者友好,而且部署方便,目前深度学习科研领域的主流框架也是PyTorch,至于为什么不选择TensorFlow,是因为目前TensorFlow的API函数各种混乱,会对初学者造成巨大阻碍,相比之下PyTorch的函数就兼容性很好。
我们创建一个文件,在开头进行导包

import torch

首先,PyTorch的基本数据类型是张量,PyTorch的各种运算也是基于张量进行的,所以理解张量,是进行深度学习编程最重要的一步。
什么是张量呢?张量就是可以进行数学运算的多维数组,如果直接这样说的话,大家可能也无法理解,那我们就从最简单的概念说起。
数列大家是否还记得?一个下标为整数的序列,大家在各种编程语言里面也可能接触过各种程序里面的数列,比如说C++中的一维数组,Python中的列表等等,这些数据结构的特征很明显,有一个下标或者索引,然后是由相同或者不同数据元素构成的序列,为了不出现歧义,我们只考虑元素类型相同的情况。
Python里面列表是这样

list=[10,20,30,40,50]
print(list[0])

这个其实就可以看成一个数列,只有一个维度,维度所代表的属性不同,就可以表示不同的信息
比如说我们可以让让这个维度表示时间(等间隔的情况),然后我们可以用这个数列表示气温变化情况,房价变化情况等等
比如说我们设下标 i i i代表第几个小时,那么一天内的气温就可以这样表示
q 0 , q 1 , ⋯   , q i , ⋯   , q 23 , i = 0 , 1 , ⋯   , 23 q_0,q_1,\cdots,q_i,\cdots,q_{23},i=0,1,\cdots,23 q0,q1,,qi,,q23,i=0,1,,23这样可以表示0点到23点间每个小时所测得的气温数据
这个维度也可以表示其他属性,比如我们有100个要卖的房子,那么这个维度表示的就是样本序号,比如说我们可以用一个长度为100的数列表示这一百个房子的售价,下标代表是哪一个样本
a 0 , a 1 , ⋯   . a 99 a_0,a_1,\cdots.a_{99} a0,a1,.a99
到这里,大家可能有所明悟,一个数列,就是一个一维张量,有一个维度,包含了有相同属性的不同数据,这个数据可以来自于一个对象的某种会变化的属性(如某地一天的气温),也可以来自不同对象的同一特征(如一百个房子就有一百个售价),但是都是一种信息,比如说一天的气温都是温度,而不是湿度,一百个房子的售价也都是价格信息,而不是其他信息。
然后我们动手创建一个一维张量

t1=torch.tensor([1,2,3,4])

这里,我们是使用torch库中的tensor方法创建张量,我们可以传入数列来初始化,然后就可以返回一个一维张量,长度为4,可以使用下标索引的方法来调用不同位置的元素
那么,二维张量呢?其实就是两个维度,每个维度代表一种信息,比如说我们想表示十个地区一天内的气温信息,可不可以呢?那么我们就可以使用一个二维张量来表示,这个张量有两个维度,第一个维度表示不同的地区,第二个维度表示气温,类似于矩阵

猜你喜欢

转载自blog.csdn.net/qq_46202265/article/details/129121523
今日推荐