Tensor张量基础与常用方法【Pytorch】

Tensor中文译名为张量,标量是零维张量,向量是一维张量,矩阵是二维张量,矩阵的堆叠是三维张量……

张量的维数可以无穷大,不过由于现实世界是三维的,因此更高维度的图形我们无法想象,但是这并不妨碍我们对高维张量的使用

1. Tensor数据类型

数据类型dtype【Tensor的属性】CPU Tensor类型GPU Tensor类型
16位浮点数torch.float16torch.halftorch.HalfTensortorch.cuda.HalfTensor
32位浮点数torch.float32torch.floattorch.FloatTensortorch.cuda.FloatTensor
64位浮点数torch.float64torch.doubletorch.DoubleTensortorch.cuda.DoubleTensor
8位无符号整数torch.uint8torch.ByteTensortorch.cuda.ByteTensor
8位有符号整数torch.int8torch.CharTensortorch.cuda.CharTensor
16位有符号整数torch.int16torch.shorttorch.ShortTensortorch.cuda.ShortTensor
32位有符号整数torch.int32torch.inttorch.IntTensortorch.cuda.IntTensor
64位有符号整数torch.int64torch.longtorch.LongTensortorch.cuda.LongTensor

2. Tensor创建

  1. torch.Tensor(维度):创建指定维度的Tensor,创建后会有随机初始值,数据类型是torch.FloatTensor

    import torch
    # 创建维度(2,2)的Tensor
    x = torch.Tensor(2, 2)
    print(x)
    
    image-20230331145556564

    torch.CPU Tensor类型(维度):创建指定维度的Tensor,依旧有初始值,不过数据类型由方法名确定

    # 创建维度(2,2)的Tensor,不过数据类型为IntTensor
    y = torch.IntTensor(2, 2)
    print(y.type())
    
    image-20230331150226809
  2. torch.Tensor(list):通过传入的listTensor内容初始化

    import torch
    l = list([[1, 2], [3, 4]])
    # 利用l的内容进行初始化,若想换个数据类型则使用此类型对应的函数构造
    x = torch.Tensor(l)
    print(x)
    
    image-20230331151052566

2.1 特殊布局Tensor创建

使用内置方法创建Tensor时数据类型默认都是FloatTensor,如果需要转换类型,可以使用如下方法👇

import torch
l = list([[1, 1], [2, 2]])
x = torch.Tensor(l)
# 将x转换为torch.IntTensor类型
# 同样的,还有float(),double(),half()等方法可以进行对应转换
x = x.int()
print(x)
image-20230331152605833
  1. torch.zeros(维度):创建元素全为0Tensor

    import torch
    # 创建维度(2,2)的Tensor,不指定类型时默认都是FloatTensor,后续不再说明
    x = torch.zeros(2,2)
    print(x)
    
    image-20230331151249245
  2. torch.eye(维度):创建对角线位置全1,其余位置全0Tensor

    import torch
    # 创建维度(3,3)的Tensor
    x = torch.eye(3, 3)
    print(x)
    
    image-20230331151451085
  3. torch.ones(维度):创建元素全为1Tensor

    import torch
    x = torch.ones(3, 3)
    print(x)
    
    image-20230331151703684
  4. torch.rand(维度):创建将元素初始化为区间[0,1)的随机数Tensor

    torch.randn(维度):创建符合正态分布的随机数Tensor

    import torch
    x = torch.rand(3, 3)
    print(x)
    
    image-20230331154116670
  5. torch.arange(start,end,step):创建一个在区间[start,end)按指定步长step递增的一维Tensor

    import torch
    # 从1开始递增,步长为0.5,最后一个元素小于4
    x = torch.arange(1, 4, 0.5)
    print(x)
    
    image-20230331154545189
  6. torch.linspace(start,end,parts):创建一个在区间[start,end]被均匀划分为parts份的一维Tensor

    import torch
    # 第一个元素是0,最后一个元素是10
    # 总共要划分为5个元素,实际上间隔有4个,因此步长=(end-start)/4=2.5
    x = torch.linspace(0, 10, 5)
    print(x)
    
    image-20230331155618018
  7. torch.from_numpy(ndarray):将Numpyndarray对象转换为Tensor

    import torch
    import numpy as np
    arr = np.array([[1, 2], [3, 4]])
    # 转换后的 Tensor 数据类型与 ndarry 一致
    x = torch.from_numpy(arr)
    print(x)
    
    image-20230331155951169

3. Tensor数学操作

下述方法操作后都需要原对象接受才能发挥作用,方法通常有两种使用方式,一者是Tensor对象.xxx,一者是torch.xxx,使用过程试一下就知道怎么回事了

方法说明
torch.add(a,n)张量a中每个元素加n,或与另一个张量n【维度相同】逐元素相加
torch.mul(a,n)张量a中每个元素乘n,或与另一个张量n【维度相同】逐元素相乘
torch.div(a,n)张量a中每个元素除n,或与另一个张量n【维度相同】逐元素相除
torch.fmod(a,n)torch.remainder(a,n)张量a中每个元素对n求余
torch.abs(a)张量a中的每个元素取绝对值
torch.ceil(a)张量a中的每个元素向上取整
torch.floor(a)张量a中的每个元素向下取整
torch.round(a)张量a中的每个元素取最近的整数【1.112.63
torch.frac(a)张量a中每个元素的分数部分
torch.neg(a)张量a中每个元素取负
torch.reciprocal(a)张量a中每个元素取倒数
torch.log(a)张量a中每个元素的自然对数【以e为底】
torch.pow(a,n)张量a中的每个元素取n次方
torch.exp(a)张量a中的每个元素变为指数,底数为e得到新值
torch.sigmoid(a)张量a中的每个元素代入sigmoid函数
torch.sign(a)张量a中若为正数或0,则1代替;否则-1代替
torch.sqrt(a)张量a中的每个元素取算数平方根,负数则放置nan
torch.dist(in,oth,p)张量in减去oth再求p范数【所有元素p次方之和再开p次方】
torch.mean(a)张量a中所有元素的均值
torch.norm(a)张量a的二范数【元素平方之和再开方】
torch.prod(a)张量a中所有元素之积
torch.sum(a)张量a中所有元素之和
torch.max(a)张量a中所有元素最大值
torch.min(a)张量a中所有元素最小值
torch.clamp(a,max,min)张量a中的元素大于max就取max,小于min就取min,其余不变
import torch
import numpy as np
l = list([[1, 2], [3, 4]])
x = torch.IntTensor(l)
# x中大于3的部分取3,小于2的部分取2
c = x.clamp(max=3, min=2)
print(c)
image-20230331162919641

4. Tensor线性代数

需要操作张量的方法一般来说都会有两种形式,一种是torch.xxx,一种是tensor对象.xxx,看个人习惯使用就好,后边不再说明

  1. torch.dot(a,b):向量a与向量b的点积【也叫内积】,结果是一个数
    a ⃗ ⋅ b ⃗ = a 1 b 1 + a 2 b 2 + . . . + a n b n = ∑ i = 1 n a i b i \vec{a}\cdot\vec{b}=a_1b_1+a_2b_2+...+a_nb_n=\sum_{i=1}^{n}a_ib_i a b =a1b1+a2b2+...+anbn=i=1naibi

    import torch
    a = torch.IntTensor([1, 2, 3])
    b = torch.IntTensor([3, 2, 1])
    # a向量与b向量点积
    c = torch.dot(a, b)
    print(c)
    
    image-20230331194142356
  2. torch.mv(a,b):实现矩阵a与向量b的乘法【不需要手动转置操作】
    image-20230403163153529

    import torch
    a = torch.IntTensor([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
    b = torch.IntTensor([1, 2, 3])
    # a矩阵与b向量相乘
    c = torch.mv(a, b)
    print(c)
    
    image-20230331195212719 image-20230403163337168
  3. torch.mm(a,b):实现矩阵a与矩阵b相乘【矩阵乘法与向量类似,可以看作是多列向量】

    import torch
    a = torch.IntTensor([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
    b = torch.IntTensor([[2, 3, 4], [3, 4, 5], [4, 5, 6]])
    # 矩阵a的第i行与矩阵b的第j列元素点积结果作为c矩阵第i行第j列的元素
    c = torch.mm(a, b)
    print(c)
    
    image-20230331195944292 image-20230403163406770
方法说明
torch.addmm(c,a,b)矩阵a与矩阵b相乘加上矩阵c
torch.addmv(b, a, c)矩阵a与向量b相乘加上向量c【向量是一维张量】
torch.addr(c,a,b)向量a与向量b求外积【列向量乘行向量】加上矩阵c
torch.bmm(b1,b2)两个batch内的矩阵进行批矩阵乘法【目前不知道啥意思】
torch.ger(a,b)求向量a与向量b的外积【即列向量与行向量相乘】
torch.inverse(a)求方阵a的逆矩阵
torch.addbmm(t,b1,b2)将两个batch内的矩阵b1,b2进行批矩阵乘法操作并累加,其结果与矩阵t相加
torch.baddbmm(t,b1,b2)将两个batch内的矩阵b1,b2进行批矩阵乘法操作,结果与另一batch内的矩阵t相加
torch.eig(a,eigenvectors=True)得到方阵a特征值以及对应的特征向量

特征分解中,矩阵分解形式为: A = Q ⋀ Q − 1 其中 Q 与 Q − 1 互为逆矩阵,并且 Q 的列就是 A 的特征值所对应的特征向量 而 ⋀ 为矩阵 A 的特征值组成的对角矩阵 特征分解中,矩阵分解形式为:\\ A=Q \bigwedge Q^{-1} \\ 其中Q与Q^{-1}互为逆矩阵,并且Q的列就是A的特征值所对应的特征向量\\ 而\bigwedge为矩阵A的特征值组成的对角矩阵 特征分解中,矩阵分解形式为:A=QQ1其中QQ1互为逆矩阵,并且Q的列就是A的特征值所对应的特征向量为矩阵A的特征值组成的对角矩阵

import torch
a = torch.Tensor([[-1, 1, 1], [1, -1, 1], [1, 1, -1]])
# eigenvectors参数为True才能得到特征向量
# 求a矩阵的特征值与特征向量
b = torch.eig(a, eigenvectors=True)
print(b)

image-20230331205147057
特征值 x 1 = − 2 ,对应的特征向量为 e i g e n v e c t o r s 中第一列元素,即 [ − 0.8165 0.4082 0.4082 ] 同理,特征值 x 2 = 1 与 x 3 = − 2 对应的对应的特征向量为 e i g e n v e c t o r s 中第二、三列元素 特征值x_1=-2,对应的特征向量为eigenvectors中第一列元素,即 \begin{bmatrix} -0.8165\\ 0.4082\\ 0.4082 \end{bmatrix}\\ 同理,特征值x_2=1与x_3=-2对应的对应的特征向量为eigenvectors中第二、三列元素 特征值x1=2,对应的特征向量为eigenvectors中第一列元素,即 0.81650.40820.4082 同理,特征值x2=1x3=2对应的对应的特征向量为eigenvectors中第二、三列元素
想要验证说法是否正确,只需要拼凑出 Q ⋀ Q − 1 Q⋀Q^{-1} QQ1,若结果能够得到A,则说明我们这个过程是正确的

import torch
# 原矩阵A
a = torch.Tensor([[-1, 1, 1], [1, -1, 1], [1, 1, -1]])
# 对矩阵A求特征值与特征向量
b = torch.eig(a, eigenvectors=True)
# 得到特征向量组成的矩阵Q
Q = b.eigenvectors
# 得到Q矩阵的逆矩阵
Q_inverse = torch.inverse(Q)
# 手动构建⋀矩阵。对角线是特征值,顺序为eigenvalues中特征值的顺序
e = torch.Tensor([[-2, 0, 0], [0, 1, 0], [0, 0, -2]])
# 计算Q矩阵乘⋀矩阵
f = torch.mm(Q, e)
# Q⋀矩阵再乘Q的逆矩阵
g = torch.mm(f, Q_inverse)
# 输出最终结果,若其与矩阵A一致,则说明我们上述判断正确
print(g)
image-20230401131753414

5. Tensor连接与切片

  • torch.cat((a,b,...),维度):将张量a,b,...按照指定维度进行拼接【二维张量中,0代表行拼接,1是列拼接,换个说法就是第0维或者第1维】

    可以这样理解,维度=0,即拼接后会让a[i]中的i变多【原来只有2行,拼接完变4行】;维度=1,即拼接后会让a[i][j]中的j变多【原来只有2列,拼接完变4列】。这种理解方式在高维张量中依然通用

    import torch
    a = torch.IntTensor([[1, 1], [1, 1]])
    b = torch.IntTensor([[2, 2], [2, 2]])
    # a与b张量按行拼接
    c = torch.cat((a, b), 0)
    print(c)
    
    image-20230401142323092
  • torch.chunk(a,parts,维度):将张量a按照指定维度均分为parts块【如果不够分则会切分大小为1的块】,可以通过下标访问不同的块

    # 将上述👆c行分割为2块
    d = torch.chunk(c, 2, 0)
    # 取第1块查看【其实就是张量a】
    print(d[0])
    
    image-20230401142827309
  • torch.t(a):让矩阵a转置

    import torch
    a = torch.IntTensor([[1, 2], [3, 1]])
    b = torch.t(a)
    print(b)
    
    image-20230401143025107
  • torch.split(a,parts,dim):将张量a按照指定维度dim划分为parts块【此时与chunk相同】,parts也可以是tuple,此时每块大小由其内数字决定,没有分配到的会整体组成一大块

    import torch
    a = torch.IntTensor([[1, 1], [1, 1]])
    b = torch.IntTensor([[2, 2], [2, 2]])
    # a与b张量按行拼接
    c = torch.cat((a, b), 0)
    # 将c张量按行划分,第一块大小为3,剩下的所有行构成一块
    d = torch.split(c, (3), 0)
    print(d)
    
    image-20230401145450643
  • torch.index_select(a,dim,index):张量adim维度方向按照index【类型是一阶Tensor】取对应元素

    import torch
    a = torch.IntTensor([[1, 2], [3, 4], [5, 6]])
    b = torch.IntTensor([[2, 2], [2, 2]])
    # 下标分别为0,2
    index = torch.IntTensor([0, 2])
    # 对张量a的第0维取index对应的元素,即a[0],a[2]
    c = torch.index_select(a, 0, index)
    print(c)
    
    image-20230401162753034
  • torch.unbind(a,dim):张量a按照指定维度取切片,返回值是切片的Tensor集合【通俗来说,向量的切片是标量,矩阵切片是向量,三阶张量切片是矩阵(视觉上为“一根柱子”)】
    假设有三阶张量 a m × n × v 则维度 = 0 的切片表达式为: ∑ j = 0 n ∑ k = 0 v a [ i ] [ j ] [ k ] 则维度 = 1 的切片表达式为: ∑ i = 0 m ∑ k = 0 v a [ i ] [ j ] [ k ] 则维度 = 2 的切片表达式为: ∑ i = 0 m ∑ j = 0 n a [ i ] [ j ] [ k ] 假设有三阶张量a_{m\times n\times v}\\ 则维度=0的切片表达式为:\sum_{j=0}^{n}\sum_{k=0}^{v}a[i][j][k]\\ 则维度=1的切片表达式为:\sum_{i=0}^{m}\sum_{k=0}^{v}a[i][j][k]\\ 则维度=2的切片表达式为:\sum_{i=0}^{m}\sum_{j=0}^{n}a[i][j][k] 假设有三阶张量am×n×v则维度=0的切片表达式为:j=0nk=0va[i][j][k]则维度=1的切片表达式为:i=0mk=0va[i][j][k]则维度=2的切片表达式为:i=0mj=0na[i][j][k]

    import torch
    a = torch.IntTensor([[1, 2], [3, 4], [5, 6]])
    # 张量a按照维度=0进行切片
    c = torch.unbind(a, 0)
    print(c)
    
    image-20230401164128373
  • torch.nonzero(a):返回张量a内值不为0的元素索引

    import torch
    a = torch.IntTensor([[1, 2], [3, 4], [5, 0]])
    c = torch.nonzero(a)
    print(c)
    
    image-20230401164448289
  • torch.squeeze(a):对张量降维,如果当前维度是1,就将此维度处理掉

    torch.unsqueeze(a,dim):对张量升维,指定在dim维度升维

    import torch
    a = torch.IntTensor([[[1, 1], [3, 4], [5, 0]]])
    b = torch.squeeze(a)
    print('对三阶张量a降维得到二阶张量b如下:')
    print(b)
    c = torch.unsqueeze(b, 0)
    print('对二阶张量b的0维度升维得到三阶张量c如下:')
    print(c)
    
    image-20230401165924877
  • torch.transpose(a,dim1,dim2):对a张量dim1维度与dim2维度进行转置
    如张量 a m × n × v , d i m 1 = 1 , d i m 2 = 2 则经过 t r a n s p o s e 操作后,张量 a 的结构变为 a m × v × m 如张量a_{m\times n\times v},dim1=1,dim2=2\\ 则经过transpose操作后,张量a的结构变为a_{m\times v\times m} 如张量am×n×vdim1=1,dim2=2则经过transpose操作后,张量a的结构变为am×v×m

    import torch
    a = torch.IntTensor([[[1, 1], [3, 4], [5, 0]]])
    print('张量a的结构为:', a.shape)
    # 对张量a的0维度与1维度转置
    b = torch.transpose(a, 0, 1)
    print('经转置后张量a的结构为:', b.shape)
    
    image-20230401170734053

6. Tensor变形

a.view(形状):将张量a改变为指定形状,当使用-1作为某一维长度时,则这一维会被自动计算

import torch
# 张量a初始形状为[2,2,3]
a = torch.IntTensor(2, 2, 3)
# 将张量a的形状改变为[4,3]
b = a.view(4, 3)
print(b.shape)
image-20230402152742794

7. Tensor自动微分

PytorchAutograd技术可以帮助我们自动求微分值

7.1 微分实例

image-20230402155407309 image-20230402164959934

7.2 基本原理

复杂的计算可以被抽象成一张图,一张复杂的计算图可以分成4个部分:

  1. 叶子节点【图的末端,没有信息流经过,但信息流由此出发】
  2. 中间节点【有信息流经过,信息流经过中间节点来到末端输出叶子节点】
  3. 输出节点
  4. 信息流【可以理解为有用信息集合,如上述求关于 x 1 x_1 x1 的微分,此时 x 1 x_1 x1 就说有用的信息】

微分示例中的 x → \overrightarrow{x} x 是叶子节点、 z → \overrightarrow{z} z 是中间节点、 y → \overrightarrow{y} y 是输出节点,三者都是Tensor

Tensor在自动微分方面有三个重要属性👇:

  • requires_grad:布尔值,默认为False,为True时表示此张量需要自动微分
  • grad:存储张量微分值
  • grad_fn:存储张量微分函数

当叶子节点的requires_gradTrue,信息流经过该节点时,所有中间节点的requires_grad属性都会变为True,只要在输出节点调用反向传播函数backward()Pytorch就会自动求出叶子节点的微分值并更新存储在叶子节点的grad属性中。

需要注意的是:只有叶子节点的grad属性能被更新

7.3 代码示例

import torch
# x是一维张量且值全为 1
x = torch.ones(2)
print('反向传播前,x的grad属性值:', x.grad)
# 我们后边需要计算 y 关于 x 的微分,因此 x 的 requires_grad 属性设置为 True
x.requires_grad = True
# 张量 x 的每个元素都乘 4 得到张量 z
z = x*4
# y 的值等于 z 的二阶范数
# 所谓二阶范数就是 张量内所有元素平方和再开方,与上述微分例子中一致
y = z.norm()
# y 启动反向传播,执行完毕后就能得到 y 关于张量 x 的微分【存储在 x 的 grad 中】
y.backward()
print('反向传播后,x的grad属性值:', x.grad)
image-20230402163933148

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6677.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

即时通讯-6-已读回执的方案设计

背景-为什么展示已读未读 部分即时通讯软件会选择展示给用户已读未读, 主要是快速感知对方的阅读状态, 感觉到自己受重视, 方便做下一步操作。 如果要带点高度的讲,满足软件所代表的关键用户的诉求 什么场景下要展示已读回执 t…

462. 最小操作次数使数组元素相等 II——【Leetcode每日一题】

462. 最小操作次数使数组元素相等 II 给你一个长度为 n 的整数数组 nums ,返回使所有数组元素相等需要的最小操作数。 在一次操作中,你可以使数组中的一个元素加 1 或者减 1 。 示例 1: 输入:nums [1,2,3] 输出:2 …

微信小程序获取手机号47001 data format error hint的完美解答(restTemplate发送post请求)

发现问题 这几天正在搞微信小程序获取手机号功能开发,发现发送post请求接口时候,接口返回如下错误: {"errcode": 47001,"errmsg": "data format error hint: [******] rid: ******" } post请求的url为&…

动态代理原理

一、案例分析 1、引出问题 回到Spring之初控制事务繁琐的问题。 回到Spring之初控制事务繁琐的问题. 考虑一个应用场景∶需要对系统中的某些业务方法做事务管理,拿简单的save和update操作举例。没有加上事务控制的代码如下。 加上事务代码,如下&#x…

大数据平台开发——使用Java和Python调用Shell脚本

大数据平台开发——使用Java和Python调用Shell脚本 背景 在大数据平台开发中,经常会遇到需要调用Shell脚本的场景,倒不是说只能用Shell,毕竟大数据开发到头来一定是个语言无关的事情: 从Hive源码解读大数据开发为什么可以脱离S…

Java进阶

注解 什么是注解 Java注解(Annotation)又称Java标注,是JDK5.0引入的一种注释机制。 Java语言中类、方法、变量、参数和包等都可以被标注。Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Ja…

【Python实操】一行代码就可以自动画出这种艺术画?(详细教程)

文章目录前言一.准备阶段二、开始使用 Discoart1.引入库2.显示/保存/加载配置总结前言 DiscoArt 是一个很牛逼的开源模块,它能根据你给定的关键词自动绘画。 绘制过程是完全可见的,你可以在 jupyter 页面上看见这个绘制的过程: 一.准备阶段…

零拷贝内存 固定内存

一、总览 虚拟内存是一种计算机内存管理的技术,它让程序认为程序自身有一段完整的连续可用的内存(一个地址空间)。当程序运行时所占的内存空间大于物理空间容量,操作系统可以将暂时不用的数据放入到磁盘,用的时候再拿出…

Linux--高级IO--select--0326

目录 IO为什么低效? 1.快速理解五种IO模式 2.五种IO模型 3.非阻塞IO fcntl() 4.IO多路转接 select select fd_set类型 struct timeval*类型 5.Select的代码测试 5.1 问题一:一开始,我们只有一个listen套接字 5.2 问题二&#xff1…

《项目管理知识体系指南(PMBOK)》第7版之8大绩效域

项目绩效域被定义为一组对有效交付项目成果至关重要的相关活动。 《项目管理知识体系指南(PMBOK)》第7版将项目管理划分为干系人、团队、开发方法和生命周期、规划、项目工作、交付、测量、不确定性共8大绩效域。 一、干系人绩效域 解决与干系人相关的…

【对YOLOv8(ultralytics)打印测试结果的调整】(1)使得map值打印显示从0.551变为55.08 (2)打印出FPS

目录1. 最终打印效果2. 做两处更改2.1 修改map显示,在ultralytics-main/ultralytics/yolo/v8/detect/val.py中操作2.2 打印FPS,在ultralytics-main/ultralytics/yolo/engine/validator.py中操作❗❗❗ 兄弟姐妹们,如果看习惯了运行train.py时…

PMP应该如何备考?

PMP现在是新考纲,PMP新版大纲加入了 ACP 敏捷管理的内容,而且还不少,敏捷混合题型占到了 50%,前不久官方也发了通知 8月启用第七版《PMBOK》,大家都觉得考试难度提升了,我从新考纲考完下来,最开…

Moonbeam隆重推出您的个人开发小助手 — — Kapa.ai

Moonbeam为开发者提供内容详细的开发者文档和全天候的Discord支持。但假如:有人可以24/7查看Discord并在15秒之内就回复您的问题 — — 新推出的Kapa.ai机器人使这个假如成为现实。Kapa.ai是一款由ChatGPT支持的AI机器人,可以回答关于在Moonbeam上构建的…

【redis】单线程redis为什么这么快

本文以收录专栏 redis核心技术 前言 本专栏为了帮助大家更好的了解学习redis,同时也是自己记录学习redis的内容,包含了大部分的redis核心技术,分布式锁,主从复制等 目录 专题2-单线程redis为什么这么快 2.1redis只有单线程吗&a…

剑指offer-替换空格

替换空格一、解题思想二、代码的实现三、总结一、解题思想 题目:请实现一个函数 ,把字符串中的每个空格替换成”%20“。例如:输入”We are happy.“,则输出”We%20are%20happy.“。 看到这个题目,我第一想到的是&#…

博客1:YOLOv5车牌识别实战教程:引言与准备工作

摘要:本篇博客介绍了本教程的目标、适用人群、YOLOv5简介和车牌识别的意义和应用场景。为后续章节打下基础,帮助读者了解YOLOv5和车牌识别的相关背景知识。 正文: 车牌识别视频 引言 欢迎来到YOLOv5车牌识别实战教程!在这个教程中,我们将一步步教你如何使用YOLOv5进行车…

【Git Bash】项目开发过程中需要知道 git stash 的用法

目录1. git stash的应用场景2. 常用git stash命令2.1 git stash2.2 git stash save "message"2.3 git stash list2.4 git stash show2.5 git stash show -p2.6 git stash apply2.7 git stash pop2.8 git stash drop stash{num}2.9 git stash clear3. stash只会保存已…

简单记录一下软著申请流程

模板我就不放了,网上很多,随便下几个结合就行了 总体来说,我是2023.2.19号寄出,2023.4.6看到成功了,总共50天左右。 大家确实不需要网上买那种服务,我也是第一次申请,感觉还是挺简单的。只要按…

洛谷B2038奇偶ASCII值判断

洛谷B2038 题目描述 任意输入一个字符,判断其 ASCII 是否是奇数,若是,输出 YES,否则,输出 NO 。 例如,字符 A 的 ASCII 值是 65,则输出 YES,若输入字符 B(ASCII 值是 66)&#xff0…

从零开始学习Kotlin,带你快速掌握该编程语言

前言 Kotlin是一种跨平台的静态编程语言,它可以在JVM、Android、浏览器、iOS等多个平台上运行。Kotlin的语法简洁易懂,具有高度的可读性和可维护性,同时还具有Java所不具备的许多优点。 Kotlin是一种静态类型、面向对象、函数式编程语言&am…