大家好,欢迎来到IT知识分享网。
目录
1.安装
下面这个网址有具体安装步骤
【PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】】https://www.bilibili.com/video/BV1hE411t7RN?vd_source=1b9a0d7cc95ffe0bada9111b709b98a4
https://zh-v2.d2l.ai/chapter_installation/index.html
笔者用的是conda环境的pytorch,大家也记得装一下,讲解的代码都是基于pytorch的。
如果想要其他替换的代码,可以自主在上面链接书中找一下。
如果安装不懂的后台踢就行
2.预备知识
2.1数据操作
2.11.Tensor基础
(1)Tensor定义
中文名字叫做张量(可以视为多维数组)
基于 标量 向量 矩阵 来看张量,上述三个分别为零维,一维,二维张量
(2)GPU和CPU
- CPU:CPU更适合处理复杂逻辑和少量线程的计算任务。它拥有少量的核心,但每个核心都能处理复杂的任务和逻辑。在处理逻辑复杂、条件分支多的任务上,CPU具有优势。然而,在处理深度学习中大量并行计算任务时,CPU的效率相对较低。由于CPU并非专为大规模并行计算设计,其计算速度在处理这类任务时可能无法满足需求。
- GPU:GPU则专为并行计算而设计,拥有大量的小核心,这些小核心适合并行执行相似的任务。在深度学习中,GPU针对大量并行处理的任务(如矩阵乘法、卷积等)表现出色,可以大大缩短计算时间。GPU的并行计算能力在处理深度学习中的计算密集型任务时,通常远超CPU,能够提供更高的计算效率。
(3)Tensor数据类型
分为GPU和CPU两种变体
在PyTorch中,量化是一种将浮点计算转换为定点计算的技术,旨在减少模型的大小、加速推理过程,同时尽量保持模型的精度
以下是一些基本操作
(4)Tensor的创建
共享内存….
import torch # 创建 形状为 2x3x4 的张量, 默认用 0 填充 t = torch.Tensor(2, 3, 4) print(type(t)) # <class 'torch.Tensor'> print(t.type()) # torch.FloatTensor print(t.dtype) # torch.float32 print(t.size()) # torch.Size([2, 3, 4]) print(t.shape) # torch.Size([2, 3, 4]) print(t) """ tensor([[[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]], [[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]]) """ # 使用预先存在的数据 (Python序列 或 numpy.ndarray) 创建张量 t = torch.Tensor([[1, 2, 3], [4, 5, 6]]) print(t.dtype) # torch.float32 print(t) """ tensor([[1., 2., 3.], [4., 5., 6.]]) """
(5)数学运算
import torch t = torch.zeros((2, 3)) # size 可以以 序列的形式传入, 也可以以 *size 的形式传入 print(t, t.dtype) """ tensor([[0., 0., 0.], [0., 0., 0.]]) torch.float32 """ t0 = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int8) t = torch.ones_like(t0) # size 和 dtype 都保持与 t0 一致 print(t) """ tensor([[1, 1, 1], [1, 1, 1]], dtype=torch.int8) torch.int8 """ t = torch.full((3, 5), 100) print(t) """ tensor([[100, 100, 100, 100, 100], [100, 100, 100, 100, 100], [100, 100, 100, 100, 100]]) """ t = torch.eye(3, 5) print(t) """ tensor([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.]]) """ t = torch.arange(0, 10, 1) print(t) """ tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ t = torch.linspace(0, 10, 5) print(t) """ tensor([ 0.0000, 2.5000, 5.0000, 7.5000, 10.0000]) """ t = torch.rand((1, 5)) print(t) """ tensor([[0.7706, 0.1781, 0.2407, 0.4579, 0.0864]]) """ t = torch.randint(0, 9, (3, 5)) print(t) """ tensor([[3, 4, 8, 2, 7], [5, 8, 7, 0, 7], [0, 0, 8, 1, 8]]) """ t = torch.randn((3, 6)) print(t) """ tensor([[ 0.9932, -1.1636, -0.3698, -0.6131, 0.0571, 0.6054], [-0.5878, -0.1389, -1.6374, -0.2527, 0.3637, -0.3284], [-0.9119, 0.3085, 0.8913, 0.9905, 0.6498, -0.7845]]) """
(6)索引和切片
可以参考csdn中tensor基础讲解,在此就不罗嗦了
(7)连接cat
同上
(8)拆分chunk
import torch t = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8]]) print(t.shape) # torch.Size([2, 5]) print(t) """ tensor([[1, 2, 3, 4], [5, 6, 7, 8]]) """ for x in torch.chunk(t, chunks=2, dim=0): print(x) """ tensor([[1, 2, 3, 4]]) tensor([[5, 6, 7, 8]]) """ for x in torch.chunk(t, chunks=2, dim=1): print(x) """ tensor([[1, 2], [5, 6]]) tensor([[3, 4], [7, 8]]) """
这里需要了解dim=0和等于1的区别
一个是 外维 一个是内维
dim范围是-2到1(在这里的范围)
dim范围和输入的维度有关
2.12 常用的操作入门
import torch x=torch.arange(12) print([x]) print(x.shape) a=x.reshape(3,-1) print(a) y=x.reshape(3,4) print(y) print(y.shape) print(y.numel()) print(torch.zeros(3,4)) print(torch.ones(3,4)) print(torch.randn(2,3,4))#随机梯度 print(torch.rand(9))#随机0,1
arange(12)表示0到11顺序的矩阵
print([x])是在print(x)整体的输出在加[]而不是仅仅在矩阵外面加一层括号
x.shape表示这个矩阵的大小,比如x就是一维矩阵,而y就是3*4的矩阵
x.reshape(3,4)表示把一维矩阵转换为二维矩阵,好用多用,但是记得两个矩阵的元素数量需要相同不然就报错了
x.reshape(3,-1)等同于x.reshape(3,4)也等同于x.reshape(-1,4),因为上面我们以及定义了x的元素个数总共有12个,所以给定矩阵的行数或者列数的一个,系统自动就转换了
后面的东西前面都见过了就不赘述了
2.13运算符
import torch # x=torch.tensor([1,2,3,4]) # y=torch.tensor([5,6,7,8]) # print(x+y) # print(x/y) # print(xy) # print(x.exp())#指数 # print(torch.exp(y)) a=torch.arange(12,dtype=torch.float64).reshape(3,4) b=torch.tensor([[4,3,2,1],[8,7,6,5],[4,3,2,1]]) print(a) print(b) print(a<b) print(a==b) # print(torch.cat((a,b),dim=0))#dim范围在-2到1 # print(torch.cat((a,b),dim=1)) # print(torch.cat((a,b),dim=-1)) # print(torch.cat((a,b),dim=-2)) print(a.sum())
这个运算结果就不展示了,大家自己动手探索一下
特别是cat的几种连接方式
2.14广播机制
广播机制就是两个形状不同的矩阵,通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状
看上面图片,我用的是第一个矩阵加第二个矩阵哈,所以你一一对应,第一行就是0+0,0+1,0+2
第二行1+0,1+1,1+2以此类推
2.15索引和切片
import torch a=torch.arange(12,dtype=torch.float64).reshape(3,4) # print(a) # print(a[-1]) # print(a[1:3]) # a[0,1]=9 # print(a) a[0:1,:1]=12 print(a) a[0:1,:]=12 print(a) a[0:1,-1:]=12 print(a)
注释部分的输出也在下面这个图片里
a[-1]就是最后一行
a[1:3]就是第二行和最后一行,记得是从1开始,但不包含3,如果把3改为2,那么就只输出第一行了,还有记得是从0开始计数
a[0,1]j就是把对应的位置数值进行修改
这里留一个问题,
a[0:1,-1:]=12 print(a)这行代码其实正常运行与下面图片输出不符,大家可以把a重置自己运行一遍
2.16节省内存
import torch a=torch.arange(12,dtype=torch.float64).reshape(3,4) b=torch.tensor([[4,3,2,1],[8,7,6,5],[4,3,2,1]]) print(id(a)) c=torch.zeros_like(a) print(id(c)) c[:]=a+b #c=a+b是不行的 print(id(c)) # a+=b # print(id(a)) # a+=b # print(id(a)) # a+=b # print(id(a)) # a+=b # print(id(a)) # a+=b # print(id(a)) # for i in range(100): #重复了100次依旧没有改变 # a += b # print(id(a))
运行一些操作可能会导致为新结果分配内存。 例如,如果我们用Y = X + Y
,我们将取消引用Y
指向的张量,而是指向新分配的内存处的张量
我们可以使用切片表示法将操作的结果分配给先前分配的数组,例如Y[:] = <expression>
。 为了说明这一点,我们首先创建一个新的矩阵Z
,其形状与另一个Y
相同, 使用zeros_like
来分配一个全0的块。
如果在后续计算中没有重复使用X
, 我们也可以使用X[:] = X + Y
或X += Y
来减少操作的内存开销。
2.17张量标量转换
张量转标量用.item()
标量转张量用.tensor()【比如说一个numpy数组c,可以
d=torch.tensor(c)来转为张量
2.2数据预处理
数据预处理一般用pandas库
pandas库啊,你用用就知道咋样了
一般啊,你先用os库创建个文件夹,存放人工数据集
在一顿操作进行命名,然后求值的时候你可能会遇到求平均值.mean()好用多用
最后处理缺失值(NaN)
摘抄于书中便于大家理解(主要我有点瞌睡了,不好意思):通过位置索引iloc
,我们将data
分成inputs
和outputs
, 其中前者为data
的前两列,而后者为data
的最后一列。 对于inputs
中缺少的数值,我们用同一列的均值替换“NaN”项。
pandas库真是好库
- Series:一维数组,可以存储任何数据类型(整数、字符串、浮点数、Python 对象等),每个元素都有一个标签(索引)。
- DataFrame:二维的、表格型的数据结构,可以看作是由多个 Series 组成的字典(共享同一个索引)
这是他的核心结构,第一次见他还是爬虫处理数据时,好久了啊,旧码重写,就像旧事重提。
2.3线性代数
明天更新啊哈哈
———————————————————————————————————————————
早上好朋友们 今天是7.10号,初中朋友要同学聚会,可惜这次去不了了…
2.31标量
标量由只有一个元素的张量表示
x = torch.tensor(3.0) y = torch.tensor(2.0)
2.32向量
向量可以被视为标量值组成的列表。 这些标量值被称为向量的元素(element)或分量(component)
x = torch.arange(4)
2.33张量
基于 标量 向量 矩阵 来看张量,上述三个分别为零维,一维,二维张量
引入矩阵的转置概念:假设有一个3*4的矩阵,转置之后就成了4*3的矩阵
这个就是转置的样式,假设B=A转置,那么A【ij】=B【ji】
两个矩阵的按元素乘法称为Hadamard积(Hadamard product)
假设A和B都是3*4的有序矩阵,那么A*B的每一个结果就是A【ij】*B【ij】
tips:将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘
2.34降维
我们先理解axis
对矩阵内的元素我们常常使用求和操作,正常的.sum()会将矩阵内所有的元素进行求和
假设我们有一个形状为(m, n, p)
的三维张量,其axis
的范围可以解释如下:
axis = 0
:沿着第一个维度(大小为m的维度)进行操作。axis = 1
:沿着第二个维度(大小为n的维度)进行操作。axis = 2
:沿着第三个维度(大小为p的维度)进行操作。axis = -1
:与axis = 2
相同,也是沿着第三个维度(大小为p的维度)进行操作。axis = -2
:沿着第二个维度(大小为n的维度)进行操作,与axis = 1
相同
然后我们以实际例子来验证
由结果不难发现,axis=0时把(2,3,4)中的2压缩了,生成了一个(3,4)的矩阵
大家可以试试更多维度的张量,axis范围处于最大维度的正负数之间
2.35点积
这个就是x,y向量点积的表示方法
点积的结果:相同位置的按元素乘积的和
torch.dot(x,y)为代码形式
2.36矩阵向量积
学会了点积就会向量积了
a的行向量中每一个元素与相对应的b的元素相乘再加和得到向量积输出
比如说14=0*0+1*1+2*2+3*3
2.37矩阵相乘
分析一下42=0*0+1*3+2*6+3*9也就是a矩阵的第一行元素与b向量的第一列元素分别相乘再求和
也就是进行第一个矩阵行数m*第二个矩阵列数n次向量积运算
2.38范数
矩阵范数分为四类:列范数,行范数,l2范数和F范数
1..列范数,就是每一列绝对值求和中的最大值
比如说这个矩阵求每一列绝对值求和为【6,14,4】
那么列范数就是14
2.行范数,就是每一行绝对值求和中的最大值
依旧按上面矩阵为例每一行绝对值求和为【8,3,13】
3. 2范数
矩阵a转置a的最大特征值下的平方根
先算a转置*a
入e-a=0转置a中入为最大特征值
求这个入是线代中求特征值的
4.F范数就是各个元素平方和再开根
2.4微积分
2.41导数和微分
这里提一个东西
如果出现:OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.的报错
import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"#在程序中发现了多个 OpenMP 运行时库的初始化。这可能会导致性能下降或产生错误结果,因为多个运行时库之间的交互可能会导致混乱。 #上述代码可以避免报错
以f(x)=3×2-4*x为例,内容都体现在代码注释里了
import torch import numpy as np from matplotlib_inline import backend_inline from matplotlib import pyplot as plt from d2l import torch as d2l def f(x): return 3 * x 2 - 4 * x def numerical_lim(f, x, h): return (f(x + h) - f(x)) / h h = 0.1 for i in range(5): print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}') h *= 0.1#使h接近于0 def use_svg_display(): #@save """使用svg格式在Jupyter中显示绘图""" backend_inline.set_matplotlib_formats('svg') def set_figsize(figsize=(3.5, 2.5)): """设置matplotlib的图表大小""" use_svg_display() d2l.plt.rcParams['figure.figsize'] = figsize def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend): """设置matplotlib的轴 设置matplotlib Axes对象的属性。 参数: axes (matplotlib.axes.Axes): 需要设置的Axes对象。 xlabel (str): X轴的标签。 ylabel (str): Y轴的标签。 xlim (tuple): X轴的范围,格式为(最小值, 最大值)。 ylim (tuple): Y轴的范围,格式为(最小值, 最大值)。 xscale (str): X轴的比例尺,如'linear', 'log'等。线性比例尺和对数比例尺 yscale (str): Y轴的比例尺,如'linear', 'log'等。 legend (list of tuples, optional): 图例项,格式为[(label1, line1), (label2, line2), ...] 其中label是字符串,line是Axes上的线对象。 """ axes.set_xlabel(xlabel) axes.set_ylabel(ylabel) axes.set_xscale(xscale) axes.set_yscale(yscale) axes.set_xlim(xlim) axes.set_ylim(ylim) if legend: axes.legend(legend) axes.grid()#添加网格线 #@save def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None, ylim=None, xscale='linear', yscale='linear',#linear指的是线性刻度 fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None): # ax.plot(x, y1, fmts[0], label='Data 1') # 使用'-'线型 # ax.plot(x, y2, fmts[1], label='Data 2') # 使用'm--'线型,m代表品红色 # ax.plot(x, y3, fmts[2], label='Data 3') # 使用'g-.'线型,g代表绿色 # ax.plot(x, y4, fmts[3], label='Data 4') # 使用'r:'线型,r代表红色 """绘制数据点""" if legend is None: legend = [] set_figsize(figsize) axes = axes if axes else d2l.plt.gca()#获取当前坐标轴 # 如果X有一个轴,输出True def has_one_axis(X): return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list) and not hasattr(X[0], "__len__")) ''' hasattr(X, "ndim") and X.ndim == 1: 这部分首先检查X是否具有ndim属性。在NumPy数组中,ndim属性表示数组的维度数。 如果X具有ndim属性,并且X.ndim == 1,即X是一个一维数组,那么这部分条件为真。 isinstance(X, list) and not hasattr(X[0], "__len__"): 这部分首先检查X是否是一个列表(list)。 如果X是列表,接下来检查列表中的第一个元素(X[0])是否没有__len__方法。在Python中,许多容器类型(如列表、元组、字符串等)都有__len__方法,用于返回容器中元素的数量。如果一个对象没有__len__方法,那么它通常不是容器类型,也就是说,它不是另一个列表、元组、字符串等。 如果X是列表,并且其第一个元素不是容器类型(即没有__len__方法),那么这部分条件为真。''' if has_one_axis(X): X = [X] if Y is None: X, Y = [[]] * len(X), X ''' X, Y = [[]] * len(X), X:这行代码做了两件事。 首先,它创建了一个与X长度相同的列表列表(二维列表),其中每个内部列表都是空的([[]] * len(X))。 然后,它将原始的X赋值给Y。''' elif has_one_axis(Y): Y = [Y] if len(X) != len(Y): X = X * len(Y) axes.cla()#清除坐标轴内容 for x, y, fmt in zip(X, Y, fmts): if len(x): axes.plot(x, y, fmt) else: axes.plot(y, fmt) set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend) x = np.arange(0, 3, 0.1) plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']) plt.show()
2.42偏导数和梯度
一、定义
- 偏导数(Partial Derivative):
- 偏导数用于多变量函数,它描述了函数在一个特定变量方向上的变化率,而其他变量保持不变。
- 例如,对于函数f(x,y),其关于x的偏导数表示为∂x∂f,关于y的偏导数表示为∂y∂f。
- 梯度(Gradient):
- 梯度是一个矢量,它包含了一个多变量函数所有偏导数的信息。
- 对于函数f(x,y),其梯度是一个二维向量,表示为∇f=(∂x∂f,∂y∂f)。对于更高维的函数f(x1,x2,…,xn),其梯度则是一个n维向量。
二、关系
- 梯度是偏导数的向量形式:
- 梯度将函数在各个方向上的偏导数组合成一个向量,这个向量在几何上表示了函数在该点处变化最快的方向。
- 因此,可以说梯度是偏导数的集合,以向量的形式呈现。
- 梯度方向与变化率:
- 梯度的方向是函数在该点处变化最快的方向(即最陡峭的方向),而梯度的模(长度)则表示了这种变化率的大小。
- 换句话说,梯度不仅告诉我们函数在哪个方向上变化最快,还告诉我们这种变化的速度有多快
可以参考哔哩哔哩中的梯度动画进行理解
2.43自动微分
import torch x = torch.arange(4.0) x x.requires_grad_(True) # 等价于x=torch.arange(4.0,requires_grad=True) x.grad # 默认值是None
x.requires_grad_是在设置随后的操作之后能够计算x的梯度
x.grad是存储x的梯度
y = 2 * torch.dot(x, x) y
然后x
是一个长度为4的向量,计算x
和x
的点积,得到了我们赋值给y
的标量输出。 接下来,通过调用反向传播函数来自动计算y
关于x
每个分量的梯度,并打印这些梯度。
y.backward() x.grad
tips:在PyTorch中,每次调用.backward()
后,PyTorch会保留计算的梯度,但如果你再次调用.backward()
而不先清零梯度(使用optimizer.zero_grad()
或x.grad.zero_()
),PyTorch会累加梯度而不是覆盖它们。然而,这通常不会导致x.grad
为None
,除非在调用.backward()
之前或之后显式地将x.grad
设置为None
。
另外x得为向量,标量可不行
2.44分离计算
z与y,x有关,y与x有关
z与两个变量有关,想求x的偏导,就得先用一个u存放y的数值视作常数。
x.grad.zero_() y = x * x u = y.detach() z = u * x z.sum().backward() x.grad == u
.detach()就是创建一个与y一样的张量给u
计算图(Computational Graph)是一个用于表示和存储所有操作(如加法、乘法、激活函数等)及其依赖关系的结构。当你对张量(Tensor)进行操作时,PyTorch会自动构建一个计算图来跟踪这些操作。这个计算图对于自动微分(Automatic Differentiation)至关重要,因为它允许PyTorch在需要时反向遍历图来计算梯度。
就是啥吧,你z只想影响x,不想影响y与x的梯度,这个时候就需要u暂时顶替一下
x成绩不好,z是老师要找家长,x怕父母知道了影响家庭和睦,所以找来u来充当父母去跟老师谈话。
2.5概率
求我现在是否晚饭的概率
先掷一个骰子吧
fair_probs = torch.ones([6]) / 6 multinomial.Multinomial(1, fair_probs).sample()
.sample()是把样本都取出来
6个样本只有一个是1其他都是0
multinomial.Multinomial(10, fair_probs).sample()
这个的话就是掷10次骰子看每个反向的次数
如果是概率的话就除以掷的次数
2.51概率论知识
1.任意概率不为0
2.总概率为1
3.联合概率,也就是a和b同时发生
4.贝叶斯定理
想象你是一位侦探,正在调查一起案件。你有两个嫌疑人,我们称他们为A和B。在没有进一步证据的情况下,你根据初步调查认为A和B的作案嫌疑是相等的,即各占50%的嫌疑。然而,随着调查的深入,你发现了一些新的线索,这些线索可能与案件有关,也可能与嫌疑人有关。
贝叶斯定理的比喻:
- 先验概率:在没有新线索之前,你认为A和B的作案嫌疑各为50%。这里的50%就是先验概率,它是你根据已知信息(即初步调查)对事件发生的概率所做的估计。
- 新线索(证据):调查过程中,你发现了一个重要的指纹线索,经过比对发现该指纹与嫌疑人A的指纹相匹配。这个指纹线索就是新的证据,它会影响你对A和B作案嫌疑的判断。
- 似然率(调整因子):指纹线索与A相匹配这一事实,增加了A作案的可能性,同时降低了B作案的可能性。这个增加或减少的比例就是似然率或调整因子。在这个比喻中,似然率可能非常高,因为指纹是高度个人化的证据。
- 后验概率:结合先验概率和新线索的似然率,你可以计算出在发现指纹线索后A和B的作案嫌疑。这个新的嫌疑比例就是后验概率。由于指纹线索与A高度匹配,因此A的后验概率会远高于50%,而B的后验概率则会相应降低。
具体计算:
虽然在这个比喻中我们没有进行具体的数值计算,但贝叶斯定理的公式可以帮助我们进行这样的计算。如果设A作案为事件A,指纹线索为事件B,则贝叶斯定理可以表示为:
P(A|B) = P(B|A) * P(A) / P(B)
其中:
- P(A|B) 是后验概率,即在发现指纹线索后A作案的概率。
- P(B|A) 是似然率,即如果A作案,则发现指纹线索的概率。
- P(A) 是先验概率,即在没有新线索之前A作案的概率。
- P(B) 是指纹线索出现的总概率,它可以通过全概率公式计算得到。
期望和方差呢,都蛮不错的
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/135481.html