pytorch01:概念、张量操作、线性回归与逻辑回归

目录

  • 一、pytorch介绍
  • 二、张量简介与创建
    • 2.1什么是张量?
    • 2.2Tensor与Variable
    • 2.3张量的创建
      • [2.3.1 直接创建torch.tensor()](#2.3.1 直接创建torch.tensor())
      • [2.3.2 从numpy创建tensor](#2.3.2 从numpy创建tensor)
    • 2.4根据数值创建
      • [2.4.1 torch.zeros()](#2.4.1 torch.zeros())
      • [2.4.2 torch.zeros_like()](#2.4.2 torch.zeros_like())
      • [2.4.3 torch.ones()和torch.ones_like()](#2.4.3 torch.ones()和torch.ones_like())
      • [2.4.4 torch.full()和torch.full_like()](#2.4.4 torch.full()和torch.full_like())
      • [2.4.5 torch.arange()](#2.4.5 torch.arange())
      • [2.4.6 torch.linspace()](#2.4.6 torch.linspace())
      • [2.4.7 torch.logspace()](#2.4.7 torch.logspace())
      • [2.4.8 torch.eye()](#2.4.8 torch.eye())
    • 2.5依概率分布创建张量
      • [2.5.1 torch.normal()](#2.5.1 torch.normal())
      • [2.5.2 torch.randn()和torch.randn_like()](#2.5.2 torch.randn()和torch.randn_like())
      • [2.5.3 torch.randint ()和torch.randint_like()](#2.5.3 torch.randint ()和torch.randint_like())
      • [2.5.4 torch.randperm()](#2.5.4 torch.randperm())
      • [2.5.5 torch.bernoulli()](#2.5.5 torch.bernoulli())
  • 三、张量的操作
    • [3.1 张量拼接与切分](#3.1 张量拼接与切分)
      • [3.1.1 torch.cat()](#3.1.1 torch.cat())
      • [3.1.2 torch.stack()](#3.1.2 torch.stack())
      • [3.1.3 torch.chunk()](#3.1.3 torch.chunk())
      • [3.1.4 torch.split()](#3.1.4 torch.split())
    • [3.2 张量索引](#3.2 张量索引)
      • [3.2.1 torch.index_select()](#3.2.1 torch.index_select())
      • [3.2.2 torch.masked_select()](#3.2.2 torch.masked_select())
    • [3.3 张量变换](#3.3 张量变换)
      • [3.3.1 torch.reshape()](#3.3.1 torch.reshape())
      • [3.3.2 torch.transpose()](#3.3.2 torch.transpose())
      • [3.3.3 torch.t()](#3.3.3 torch.t())
      • [3.3.4 torch.squeeze()](#3.3.4 torch.squeeze())
      • [3.3.5 torch.unsqueeze()](#3.3.5 torch.unsqueeze())
  • 四、张量的运算
  • 五、线性回归
  • 六、动态图机制
  • 七、逻辑回归
    • [7.1 torch.autograd自动求导系统](#7.1 torch.autograd自动求导系统)
      • [7.1.1 torch.autograd.backward](#7.1.1 torch.autograd.backward)
      • [7.1.2 torch.autograd.grad](#7.1.2 torch.autograd.grad)
      • [7.1.3 自动求导系统注意事项](#7.1.3 自动求导系统注意事项)
    • 7.2逻辑回归
      • [7.2.1 线性回归与对数回归的区别](#7.2.1 线性回归与对数回归的区别)
      • [7.2.2 逻辑回归代码实现](#7.2.2 逻辑回归代码实现)

一、pytorch介绍

1.1pytorch简介

2017年1月,FAIR (FacebookAI Research) 发布PyTorch,PyTorch是在Torch基础上用python语言重新打造的一款深度学习框架,Torch 是采用Lua语言为接口的机器学习框架,但因Lua语言较为小众导致Torch知名度不高。

1.2发展历史

  • 2017年1月正式发布PyTorch
  • 2018年4月更新0.4.0版,支持Windows系统,caffe2正式并入PyTorch
  • 2018年11月更新1.0稳定版,已GitHub 增长第二快的开源项目
  • 2019年5月更新1.1.0版,支持TensorBoard,增强可视化功能
  • 2019年8月更新1.2.0版,更新torchvision,torchaudio 和torchtext,增加更多功能
    2014年10月至2018年02月arXiv论文中深度学习框架提及次数统计,PyTorch的增长速度与TensorFlow一致。

1.3pytorch优点

  • 上手快: 掌握Numpy和基本深度学习概念即可上手
  • 代码简洁灵活: 用nn.module封装使网络搭建更方便;基于动态图机制,更灵活
  • Debug方便: 调试PyTorch就像调试 Python 代码一样简单
  • 文档规范:https://pytorch.org/docs/可查各版本文档
  • 资源多: arXiv中的新算法大多有PyTorch实现
  • 开发者多:GitHub上贡献者(Contributors)已超过1100+
  • 背靠大树: FaceBook维护开发

二、张量简介与创建

2.1什么是张量?

张量是一个多维数组,它是标量、向量、矩阵的高维拓展

在深度学习中,张量(tensor)是一个广泛使用的数学和计算工具,它是多维数组的泛化。以下是对深度学习中张量的一些解释:

1.数据结构: 张量是一个多维数组,可以是一个标量(0维张量,即一个数)、向量(1维张量,例如一行或一列数字)、矩阵(2维张量,例如一个表格或图像)、或者更高维度的数组。

2.Rank(秩): 张量的秩表示张量的维度数量。例如,标量的秩是0,向量的秩是1,矩阵的秩是2。通常,深度学习中的张量秩是可以很大的,因为神经网络中的数据通常是高维的。

3.形状: 张量的形状描述了它每个维度上的大小。例如,一个形状为 (3, 4) 的张量表示一个 3 行 4 列的矩阵。

4.类型: 张量可以包含不同类型的数据,例如整数、浮点数等。在深度学习中,通常使用浮点数张量。

5.操作: 张量上可以进行各种数学运算,如加法、减法、乘法等。这些操作是深度学习中神经网络的基础。

6.自动微分: 在深度学习中,张量通常与自动微分结合使用。自动微分是通过计算图和链式法则来计算梯度,用于训练神经网络。

7.存储和计算优化: 张量在内存中的存储方式通常是连续的,这有助于在硬件上进行高效的计算。深度学习框架使用张量来表示神经网络的参数和输入输出。

8.GPU 加速: 张量的并行性和规则结构使得深度学习中的许多计算可以受益于 GPU 的并行计算能力。因此,深度学习框架通常支持在 GPU 上进行张量操作。

在常见的深度学习框架(如 TensorFlow、PyTorch等)中,张量是核心数据结构,它们提供了丰富的操作和函数来处理张量,支持自动微分、梯度下降等算法,使得深度学习模型的实现更加方便和高效。

2.2Tensor与Variable

Variable是torch.autograd中的数据类型主要用于封装Tensor,进行自动求导

data : 被包装的Tensor
grad : data的梯度
grad fn : 创建Tensor的Function,是自动求导的关键
requires_grad : 指示是否需要梯度
is leaf: 指示是否是叶子结点 (张量)

2.3张量的创建

2.3.1 直接创建torch.tensor()

torch.tensor()

功能:从data创建tensor

• data: 数据, 可以是list, numpy

• dtype : 数据类型,默认与data的一致

• device : 所在设备, cuda/cpu

• requires_grad:是否需要梯度

• pin_memory:是否存于锁页内存

2.3.2 从numpy创建tensor

torch.from_numpy(ndarray)

注意事项: 从torch.from_numpy创建的tensor于原ndarray共享内存,当修改其中一个的数据,另外一个也将会被改动

2.4根据数值创建

2.4.1 torch.zeros()

功能:依size创建全0张量

• size: 张量的形状, 如(3, 3)、(3, 224,224)

• out : 输出的张量

• layout : 内存中布局形式, 有strided,sparse_coo等

• device : 所在设备, gpu/cpu

• requires_grad:是否需要梯度

2.4.2 torch.zeros_like()

功能:依input形状创建全0张量

• intput: 创建与input同形状的全0张量

• dtype : 数据类型

• layout : 内存中布局形式

2.4.3 torch.ones()和torch.ones_like()

功能:依input形状创建全1张量

• size: 张量的形状, 如(3, 3)、(3, 224,224)

• dtype : 数据类型

• layout : 内存中布局形式

• device : 所在设备, gpu/cpu

• requires_grad:是否需要梯度

2.4.4 torch.full()和torch.full_like()

功能:依input形状创建指定数据的张量

• size: 张量的形状, 如(3, 3)

• fill_value : 张量的值

2.4.5 torch.arange()

功能:创建等差的1维张量

注意事项:数值区间为[start, end)

• start : 数列起始值

• end : 数列"结束值"

• step: 数列公差,默认为1

2.4.6 torch.linspace()

功能:创建均分的1维张量

注意事项:数值区间为[start, end]

• start : 数列起始值

• end : 数列结束值

• steps: 数列长度

2.4.7 torch.logspace()

功能:创建对数均分的1维张量

注意事项:长度为steps, 底为base

• start : 数列起始值

• end : 数列结束值

• steps: 数列长度

• base : 对数函数的底,默认为10

2.4.8 torch.eye()

功能:创建单位对角矩阵( 2维张量)

注意事项:默认为方阵

• n: 矩阵行数

• m : 矩阵列数

2.5依概率分布创建张量

2.5.1 torch.normal()

功能:生成正态分布(高斯分布)

• mean : 均值

• std : 标准差

2.5.2 torch.randn()和torch.randn_like()

功能:生成标准正态分布

功能:在区间[0, 1)上,生成均匀分布

• size : 张量的形状

2.5.3 torch.randint ()和torch.randint_like()

功能:区间[low, high)生成整数均匀分布

• size : 张量的形状

2.5.4 torch.randperm()

功能:生成生成从0到n-1的随机排列

• n : 张量的长度

2.5.5 torch.bernoulli()

功能:以input为概率,生成伯努力分布(0-1分布,两点分布)

• input : 概率值

三、张量的操作

3.1 张量拼接与切分

3.1.1 torch.cat()

功能:将张量按维度dim进行拼接

• tensors: 张量序列

• dim : 要拼接的维度

3.1.2 torch.stack()

功能:在新创建的维度dim上进行拼接

• tensors:张量序列

• dim :要拼接的维度

3.1.3 torch.chunk()

功能:将张量按维度dim进行平均切分

返回值:张量列表

注意事项:若不能整除,最后一份张量小于其他张量

• input: 要切分的张量

• chunks : 要切分的份数

• dim : 要切分的维度

3.1.4 torch.split()

功能:将张量按维度dim进行切分

返回值:张量列表

• tensor: 要切分的张量

• split_size_or_sections : 为int时,表示每一份的长度;为list时,按list元素切分

• dim : 要切分的维度

3.2 张量索引

3.2.1 torch.index_select()

功能:在维度dim上,按index索引数据

返回值:依index索引数据拼接的张量

• input: 要索引的张量

• dim: 要索引的维度

• index : 要索引数据的序号

3.2.2 torch.masked_select()

功能:按mask中的True进行索引

返回值:一维张量

• input: 要索引的张量

• mask: 与input同形状的布尔类型张量

3.3 张量变换

3.3.1 torch.reshape()

功能:变换张量形状

注意事项:当张量在内存中是连续时,新张量与input共享数据内存

• input: 要变换的张量

• shape: 新张量的形状

3.3.2 torch.transpose()

功能:交换张量的两个维度

• input: 要变换的张量

• dim0: 要交换的维度

• dim1: 要交换的维度

3.3.3 torch.t()

功能:2维张量转置,对矩阵而言,等价于torch.transpose(input, 0, 1)

3.3.4 torch.squeeze()

功能:压缩长度为1的维度(轴)

• dim: 若为None,移除所有长度为1的轴;若指定维度,当且仅当该轴长度为1时,可以被移除;

3.3.5 torch.unsqueeze()

功能:依据dim扩展维度

• dim: 扩展的维度

四、张量的运算

torch.add()

功能:逐元素计算 input+alpha×other

• input: 第一个张量

• alpha: 乘项因子

• other: 第二个张量

五、线性回归

5.1线性回归概念

5.2 求解步骤

5.3线性回归代码实现

python 复制代码
# -*- coding:utf-8 -*-

import torch
import matplotlib.pyplot as plt

torch.manual_seed(10)

lr = 0.05  # 学习率

# 创建训练数据
x = torch.rand(20, 1) * 10  # x data (tensor), shape=(20, 1)
y = 2 * x + (5 + torch.randn(20, 1))  # y data (tensor), shape=(20, 1)

# 构建线性回归参数
w = torch.randn((1), requires_grad=True)
b = torch.zeros((1), requires_grad=True)

for iteration in range(1000):

    # 前向传播  y=wx+b
    wx = torch.mul(w, x)
    y_pred = torch.add(wx, b)

    # 计算 MSE loss
    loss = (0.5 * (y - y_pred) ** 2).mean()

    # 损失反向传播来得到梯度grad
    loss.backward()

    # 更新参数
    b.data.sub_(lr * b.grad)  # sub_:原地减法操作
    w.data.sub_(lr * w.grad)

    # 清零张量的梯度
    w.grad.zero_()
    b.grad.zero_()

    # 绘图
    if iteration % 20 == 0:

        plt.scatter(x.data.numpy(), y.data.numpy())
        plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5)
        plt.text(2, 20, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
        plt.xlim(1.5, 10)
        plt.ylim(8, 28)
        plt.title("Iteration: {}\nw: {} b: {}".format(iteration, w.data.numpy(), b.data.numpy()))
        plt.pause(0.5)

        # 设置一个终止条件,当loss小于1的时候停止更新
        if loss.data.numpy() < 1:
            break

结果展示:

六、动态图机制

6.1计算图基本概念

计算图是用来描述运算的有向无环图计算图有两个主要元素:结点(Node)和边(Edge)结点表示数据,如向量,矩阵,张量边表示运算,如加减乘除卷积等用计算图表示:y = (x+ w) * (w+1);a = x + w ;b = w + 1 ;y = a * b

6.2 计算图梯度求导

求导流程如下:

6.3 叶子结点

叶子结点:用户创建的结点称为叶子结点,如X 与 W;在torch中有如下图属性,is_leaf: 指示张量是否为叶子结点。

grad_fn: 记录创建该张量时所用的方法(函数)

当x,w使用torch方法创建之后,该属性会保留grad属性,a、b、y都是通过x,w计算得到的,在反向传播之后就会释放梯度,减少内存开销。


代码实现

查看叶子结点

python 复制代码
import torch

w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

a = torch.add(w, x)     # retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)

y.backward()
print(w.grad)

# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)

输出结果:
tensor([5.])
is_leaf:
 True True False False False

查看梯度

python 复制代码
# -*- coding:utf-8 -*-

import torch

w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

a = torch.add(w, x)     # retain_grad()
a.retain_grad()

b = torch.add(w, 1)
b.retain_grad()
y = torch.mul(a, b)

y.backward()
print(w.grad)
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)

输出结果:
tensor([5.])
gradient:
 tensor([5.]) tensor([2.]) tensor([2.]) tensor([3.]) None

注意:a,b,y非叶子结点,所以反向传播之后会清除梯度,所以使用a.grad方法结果是none,需要在中间使用a.retain_grad()方法将a的梯度保留下来。

查看梯度计算方法

python 复制代码
import torch

w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

a = torch.add(w, x)     # retain_grad()
# a.retain_grad()

b = torch.add(w, 1)
# b.retain_grad()
y = torch.mul(a, b)

y.backward()
print(w.grad)
# 查看 grad_fn
print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)

输出结果:
tensor([5.])
grad_fn:
 None None <AddBackward0 object at 0x00000217F70B1330> <AddBackward0 object at 0x00000217F70B1300> <MulBackward0 object at 0x00000217F70B13F0>

从上面结果可以看出,a和b的梯度计算使用的是加法,y梯度使用的是乘法。

6.4 动态图

为什么近几年TensorFlow逐渐被淘汰了,因为TensorFlow使用的任然是静态图,先搭建网络后进行运算,这样会导致效率低下;

6.4.1pytorch动态图

6.4.2TensorFlow静态图

七、逻辑回归

7.1 torch.autograd自动求导系统

7.1.1 torch.autograd.backward

功能:自动求取梯度

• tensors: 用于求导的张量,如 loss

• retain_graph : 保存计算图

• create_graph : 创建导数计算图,用于高阶

求导

• grad_tensors:多梯度权重

7.1.2 torch.autograd.grad

功能:求取梯度

• outputs: 用于求导的张量,如 loss

• inputs : 需要梯度的张量

• create_graph : 创建导数计算图,用于高阶

求导

• retain_graph : 保存计算图

• grad_outputs:多梯度权重

7.1.3 自动求导系统注意事项

  1. 梯度不自动清零
  2. 依赖于叶子结点的结点,requires_grad默认为True
  3. 叶子结点不可执行in-place

7.2逻辑回归

逻辑回归是线性的二分类模型,模型表达式和函数图像如下:

线性回归是分析自变量x与因变量y(标量)之间关系的方法
逻辑回归是分析自变量x与因变量y(概率)之间关系的方法

7.2.1 线性回归与对数回归的区别

7.2.2 逻辑回归代码实现

python 复制代码
# -*- coding: utf-8 -*-

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np

torch.manual_seed(10)

# ============================ step 1/5 生成数据 ============================
sample_nums = 100
mean_value = 1.7
bias = 1
n_data = torch.ones(sample_nums, 2)
x0 = torch.normal(mean_value * n_data, 1) + bias  # 类别0 数据 shape=(100, 2)
y0 = torch.zeros(sample_nums)  # 类别0 标签 shape=(100, 1)
x1 = torch.normal(-mean_value * n_data, 1) + bias  # 类别1 数据 shape=(100, 2)
y1 = torch.ones(sample_nums)  # 类别1 标签 shape=(100, 1)
train_x = torch.cat((x0, x1), 0)  # 在0维进行拼接
train_y = torch.cat((y0, y1), 0)


# ============================ step 2/5 选择模型 ============================
class LR(nn.Module):
    def __init__(self):
        super(LR, self).__init__()
        self.features = nn.Linear(2, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        x = self.features(x)
        x = self.sigmoid(x)
        return x


lr_net = LR()  # 实例化逻辑回归模型

# ============================ step 3/5 选择损失函数 ============================
loss_fn = nn.BCELoss()  # 二分类交叉熵损失函数

# ============================ step 4/5 选择优化器   ============================
lr = 0.01  # 学习率
optimizer = torch.optim.SGD(lr_net.parameters(), lr=lr, momentum=0.9)

# ============================ step 5/5 模型训练 ============================
for iteration in range(1000):

    # 前向传播
    y_pred = lr_net(train_x)

    # 计算 loss
    loss = loss_fn(y_pred.squeeze(), train_y)

    # 反向传播
    loss.backward()

    # 更新参数
    optimizer.step()

    # 清空梯度
    optimizer.zero_grad()

    # 绘图
    if iteration % 20 == 0:

        mask = y_pred.ge(0.5).float().squeeze()  # 以0.5为阈值进行分类
        correct = (mask == train_y).sum()  # 计算正确预测的样本个数
        acc = correct.item() / train_y.size(0)  # 计算分类准确率

        plt.scatter(x0.data.numpy()[:, 0], x0.data.numpy()[:, 1], c='r', label='class 0')
        plt.scatter(x1.data.numpy()[:, 0], x1.data.numpy()[:, 1], c='b', label='class 1')

        w0, w1 = lr_net.features.weight[0]
        w0, w1 = float(w0.item()), float(w1.item())
        plot_b = float(lr_net.features.bias[0].item())
        plot_x = np.arange(-6, 6, 0.1)
        plot_y = (-w0 * plot_x - plot_b) / w1

        plt.xlim(-5, 7)
        plt.ylim(-7, 7)
        plt.plot(plot_x, plot_y)

        plt.text(-5, 5, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
        plt.title("Iteration: {}\nw0:{:.2f} w1:{:.2f} b: {:.2f} accuracy:{:.2%}".format(iteration, w0, w1, plot_b, acc))
        plt.legend()

        plt.show()
        plt.pause(0.5)

        if acc > 0.99:
            break

运行结果:380次迭代之后准确率达到99.5%

相关推荐
寂静山林2 分钟前
UVa 10228 A Star not a Tree?
算法
爱喝白开水a3 分钟前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
takashi_void10 分钟前
如何在本地部署大语言模型(Windows,Mac,Linux)三系统教程
linux·人工智能·windows·macos·语言模型·nlp
OpenCSG15 分钟前
【活动预告】2025斗拱开发者大会,共探支付与AI未来
人工智能·ai·开源·大模型·支付安全
Neverfadeaway15 分钟前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
生命是有光的18 分钟前
【深度学习】神经网络基础
人工智能·深度学习·神经网络
数字供应链安全产品选型22 分钟前
国家级!悬镜安全入选两项“网络安全国家标准应用实践案例”
人工智能·安全·web安全
科技新知34 分钟前
大厂AI各走“开源”路
人工智能·开源
字节数据平台37 分钟前
火山引擎Data Agent再拓新场景,重磅推出用户研究Agent
大数据·人工智能·火山引擎
TGITCIC37 分钟前
LLaVA-OV:开源多模态的“可复现”革命,不只是又一个模型
人工智能·开源·多模态·ai大模型·开源大模型·视觉模型·大模型ai