自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

超全總結!玩轉Pytorch張量(Tensor)!

開發(fā)
在深度學習領域,PyTorch是一個廣泛應用的開源庫,Tensor之于PyTorch就好比是array之于Numpy或者DataFrame之于Pandas,都是構建了整個框架中最為底層的核心數(shù)據(jù)結構。

一、什么是張量(Tensor)?

在深度學習領域,PyTorch是一個廣泛應用的開源庫,Tensor之于PyTorch就好比是array之于Numpy或者DataFrame之于Pandas,都是構建了整個框架中最為底層的核心數(shù)據(jù)結構。Pytorch中的所有操作都是在張量的基礎上進行的。

PyTorch官網(wǎng)對其的定義如下:

也就是說,一個Tensor是一個包含單一數(shù)據(jù)類型的多維矩陣。通常,其多維特性用三維及以上的矩陣來描述,例如下圖所示:單個元素為標量(scalar),一個序列為向量(vector),多個序列組成的平面為矩陣(matrix),多個平面組成的立方體為張量(tensor)。

當然,張量也無需嚴格限制在三維及以上才叫張量,就像矩陣也有一維、二維矩陣乃至多維矩陣之分一樣。

「在深度學習的范疇內,標量、向量和矩陣也可分為稱為零維張量、一維張量、二維張量?!?/p>

二、為什么深度學習要搞出Tensor?

熟悉機器學習的小伙伴們應該都知道,有監(jiān)督機器學習模型的輸入X通常是多個特征列組成的二維矩陣,輸出y是單個特征列組成的標簽向量或多個特征列組成的二維矩陣。那么深度學習中,為何要定義多維矩陣Tensor呢?

深度學習當前最成熟的兩大應用方向莫過于CV和NLP,其中CV面向圖像和視頻,NLP面向語音和文本,二者分別以卷積神經(jīng)網(wǎng)絡和循環(huán)神經(jīng)網(wǎng)絡作為核心基礎模塊,且標準輸入數(shù)據(jù)集都是至少三維以上。其中,

  • 圖像數(shù)據(jù)集:至少包含三個維度(樣本數(shù)Nx圖像高度Hx圖像寬度W);如果是彩色圖像,則還需增加一個通道C,包含四個維度(NxHxWxC);如果是視頻幀,可能還需要增加一個維度T,表示將視頻劃分為T個等時長的片段。
  • 文本數(shù)據(jù)集:包含三個維度(樣本數(shù)N×序列長度L×特征數(shù)H)。

因此,輸入學習模型的輸入數(shù)據(jù)結構通常都要三維以上,這也就促使了Tensor的誕生。

三、Tensor創(chuàng)建

Pytorch可基于給定數(shù)據(jù)手動創(chuàng)建Tensor,并提供了多種方式:

1.使用torch.tensor()函數(shù)直接創(chuàng)建

在PyTorch中,torch.tensor()函數(shù)用于直接從Python的數(shù)據(jù)結構(如列表、元組或NumPy數(shù)組)中創(chuàng)建一個新的張量。

"""
data:數(shù)據(jù),可以是list,numpy
dtype:數(shù)據(jù)類型,默認與data對應
device:張量所在的設備(cuda或cpu)
requires_grad:是否需要梯度
pin_memory:是否存于鎖存內存
"""
torch.tensor(data,dtype=None,device=None,requires_grad=False,pin_memory=False)

pin_memor用于實現(xiàn)鎖頁內存,創(chuàng)建DataLoader時,設置pin_memory=True,則意味著生成的Tensor數(shù)據(jù)最開始是屬于內存中的鎖頁內存,這樣將內存的Tensor轉義到GPU的顯存就會更快一些。

以下是使用torch.tensor()創(chuàng)建張量的基本示例:

import numpy as np
import torch
arr = np.ones((3, 3))
'''
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
'''
print(arr)
# ndarray的數(shù)據(jù)類型:float64
print("ndarray的數(shù)據(jù)類型:", arr.dtype)
t= torch.tensor(arr)
'''
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
'''
print(t)

如需創(chuàng)建一個放在GPU的數(shù)據(jù),則可做如下修改,運行結果同上。

import numpy as np
import torch
device= torch.device("cuda" if torch.cuda.is_available() else 'cpu')
arr = np.ones((3, 3))
print("ndarray的數(shù)據(jù)類型:", arr.dtype)
t = torch.tensor(arr, device=device)
print(t)

2.從numpy創(chuàng)建Tensor

torch.from_numpy(ndarray)

利用該方法創(chuàng)建的tensor與原ndarray共享內存,當修改其中一個數(shù)據(jù),另外一個也會被更新。

import numpy as np
import torch
# 創(chuàng)建一個numpy數(shù)組
numpy_array = np.array([[1, 2, 3], [4, 5, 6]])

# 從numpy數(shù)組創(chuàng)建一個Tensor,并保持數(shù)據(jù)共享(更改Tensor內容會同時改變numpy數(shù)組)
tensor_from_numpy = torch.from_numpy(numpy_array)
print(tensor_from_numpy)

# 輸出:
# tensor([[1, 2, 3],
#         [4, 5, 6]], dtype=torch.int32)

# 修改tensor,array也會被修改
print("# -----------修改tensor--------------*")
t[0, 0] = -1
print("numpy array: ", arr)
# 輸出:
# numpy array:  [[-1  2  3]
#               [ 4  5  6]]
print("tensor : ", t)
# 輸出:
# tensor([[-1, 2, 3],
#         [4, 5, 6]], dtype=torch.int32)

3.根據(jù)數(shù)值創(chuàng)建張量

(1) torch.zeros():根據(jù)size創(chuàng)建全0張量

'''
size:張量的形狀
out:輸出的張量,如果指定了out,torch.zeros()返回的張量則會和out共享同一個內存地址
layout:內存中的布局方式,有strided,sparse_coo等。如果是稀疏矩陣,則可以設置為sparse_coo以減少內存占用
device:張量所在的設備(cuda或cpu)
requires_grad:是否需要梯度
'''
torch.zeros(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
import torch
out_t = torch.tensor([1])
print(f"out_t初始值:{out_t}")
#指定out
t = torch.zeros((3, 3), out=out_t)
print(f"t:\n{t}")
print(f"out_t更新值:\n{out_t}")
# id是取內存地址,t和out_t是同一個內存地址
print(id(t), id(out_t), id(t) == id(out_t))

運行結果如下,由此可見,和out_t最終共享同一個內存地址。

out_t初始值:tensor([1])
t:
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])
out_t更新值:
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])
2083081770704 2083081770704 True

(2) torch.zeros_like:根據(jù)input形狀創(chuàng)建全0張量

torch.zeros_like(input, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format)

同理還有全1張量的創(chuàng)建:torch.ones(),torch.ones_like()

(3) torch.full() & torch.full_like():創(chuàng)建自定義某一數(shù)值的張量。

'''
size:張量的形狀,例如(3,3)
fill_value:張量中每一個元素的值。
'''

torch.full(size, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

例如:

import torch
t = torch.full((4, 4), 10)
print(t)
'''
tensor([[10, 10, 10, 10],
        [10, 10, 10, 10],
        [10, 10, 10, 10],
        [10, 10, 10, 10]])
'''

(4) 創(chuàng)建等差的一維張量。

?注意區(qū)間為:[start,end)。

'''
start:數(shù)列起始值,默認為0
end:數(shù)列結束值,開區(qū)間,取不到結束值
step:數(shù)列公差,默認為1
'''
torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

例如:

import torch
t = torch.arange(2, 10, 2)
print(t) # tensor([2, 4, 6, 8])

(5) torch.linspace():創(chuàng)建均分的一維張量

?注意區(qū)間為:[start,end]。

'''
step:數(shù)列長度(元素個數(shù))
'''
torch.linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
import torch
t = torch.linspace(2, 10, 3)
print(t) # tensor([ 2.,  6., 10.])

(6) torch.logspace():創(chuàng)建對數(shù)均分的一維張量

?注意區(qū)間為:[start,end]。

'''
step:數(shù)列長度(元素個數(shù))
base:對數(shù)函數(shù)的底,默認為 10
'''
torch.logspace(start, end, steps, base=10, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
import torch
t = torch.logspace(2, 4, 3)
print(t) # tensor([100.,  1000., 10000.])

(7) torch.eye():創(chuàng)建單位對角矩陣(2維張量)

?默認輸出方陣。

'''
n: 矩陣行數(shù)。因為是方陣,通常只設置n
m: 矩陣列數(shù)
'''
torch.eye(n, m=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
import torch
t = torch.eye(3)
h = torch.eye(3,4)
print(f"t:{t}")
print(f"h:{h}")

運行結果如下:

t:tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])
h:tensor([[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.]])

4.根據(jù)概率創(chuàng)建張量

(1) torch.normal():生成正態(tài)分布(高斯分布)

?返回一個張量,包含從給定參數(shù)means、std的離散正態(tài)分布中抽取的隨機數(shù)。

'''
mean:均值
std:標準差
'''
torch.normal(mean, std, *, generator=None, out=None)

包含4種模式:

  • mean為標量,std為標量,此時需要設置size。
import torch
t_normal = torch.normal(0., 1., size=(4,))
# t_normal:tensor([ 0.7098,  1.5432, -0.1568, -0.6350])
print(f"t_normal:{t_normal}")

mean為張量,std為標量。

import torch
mean = torch.arange(1, 5, dtype=torch.float)
std = 1
t_normal = torch.normal(mean, std)
'''
mean:tensor([1., 2., 3., 4.])
std:1
'''
print("mean:{}\nstd:{}".format(mean, std))
#tensor([2.2450, 1.0230, 2.0299, 4.5855])
print(t_normal)

這4個數(shù)采樣分布的均值不同,但是方差都是 1。

  • mean為標量,std為張量。
import torch
std = torch.arange(1, 5, dtype=torch.float)
mean = 2
t_normal = torch.normal(mean, std)
'''
mean:2
std:tensor([1., 2., 3., 4.])
'''
print("mean:{}\nstd:{}".format(mean, std))
# tensor([ 1.8482,  4.8143, -3.5074,  4.2010])
print(t_normal)
  • mean為張量,std為張量。
import torch
mean = torch.arange(1, 5, dtype=torch.float)
std = torch.arange(1, 5, dtype=torch.float)
t_normal = torch.normal(mean, std)
'''
mean:tensor([1., 2., 3., 4.])
std:tensor([1., 2., 3., 4.])
'''
print("mean:{}\nstd:{}".format(mean, std))
# tensor([ 0.8195, -3.9112,  4.8498,  2.3934])
print(t_normal)

其中0.8195是從正態(tài)分布N(1,1)中采樣得到的,-3.9112是從正態(tài)分布N(2,2)中采樣得到的,其他數(shù)字以此類推。

四、Tensor屬性

1.Tensor形狀

張量具有如下形狀屬性:

  • Tensor.ndim:張量的維度,例如向量的維度為1,矩陣的維度為2。
  • Tensor.shape:張量每個維度上元素的數(shù)量。
  • Tensor.shape[n]:張量第n維的大小。第n維也稱為軸(axis)。
  • Tensor.numel:張量中全部元素的個數(shù)。

如下是創(chuàng)建一個四維Tensor,并通過圖形直觀表達以上幾個概念的關系。

import torch
Tensor=torch.ones([2,3,4,5])
print("Number of dimensions:", Tensor.ndim)
print("Shape of Tensor:", Tensor.shape)
print("Elements number along axis 0 of Tensor:", Tensor.shape[0])
print("Elements number along the last axis of Tensor:", Tensor.shape[-1])
print('Number of elements in Tensor: ', Tensor.numel())  #用.numel表示元素個數(shù)

Tensor的axis、shape、dimension、ndim之間的關系如下圖所示。

2.Tensor數(shù)據(jù)類型

torch.dtype屬性標識了torch.Tensor的數(shù)據(jù)類型。PyTorch有八種不同的數(shù)據(jù)類型:

例如:

import torch
Tensor=torch.ones([2,3,4,5])
# Data Type of every element: torch.float32
print("Data Type of every element:", Tensor.dtype)

3.Tensor所在設備

如圖所示,我們可以看到每種類型的數(shù)據(jù)都有一個CPU和一個GPU版本,因此我們對張量進行處理的時候需要指定一個設備,它要么是CPU要么是GPU,這是數(shù)據(jù)被分配的位置,這決定了給定張量的張量計算位置。

Pytorch支持多種設備的使用,我們可以用torch.device來創(chuàng)建一個設備,并指定索引,例如:

device=torch.device('cuda:0')

輸出結果為:device(type='cuda',index=0),可看到類型為'cuda',即GPU,索引0表示為第一個GPU。

五、Tensor操作

1.形狀重置

Tensor的shape可通過torch.reshape接口來改變。例如:

import torch
Tensor =torch.tensor([[[1, 2, 3, 4, 5],
                        [6, 7, 8, 9, 10]],
                      [[11, 12, 13, 14, 15],
                        [16, 17, 18, 19, 20]],
                      [[21, 22, 23, 24, 25],
                        [26, 27, 28, 29, 30]]])
print("the shape of Tensor:", Tensor.shape)
#利用reshape改變形狀
reshape_Tensor = torch.reshape(Tensor, [2, 5, 3])
print("After reshape:\n", reshape_Tensor)

從輸出結果看,將張量從[3, 2, 5]的形狀reshape為[2, 5, 3]的形狀時,張量內的數(shù)據(jù)不會發(fā)生改變,元素順序也沒有發(fā)生改變,只有數(shù)據(jù)形狀發(fā)生了改變。

在指定新的shape時存在一些技巧:

  • -1 表示這個維度的值是從Tensor的元素總數(shù)和剩余維度自動推斷出來的。因此,有且只有一個維度可以被設置為-1。
  • 0 表示該維度的元素數(shù)量與原值相同,因此shape中0的索引值必須小于Tensor的維度(索引值從 0 開始計,如第 1 維的索引值是 0,第二維的索引值是 1)。

例如:

# 直接指定目標 shape
origin:[3, 2, 5] reshape:[3, 10] actual: [3, 10]
# 轉換為 1 維,維度根據(jù)元素總數(shù)推斷出來是 3*2*5=30
origin:[3, 2, 5] reshape:[-1] actual: [30]
# 轉換為 2 維,固定一個維度 5,另一個維度根據(jù)元素總數(shù)推斷出來是 30÷5=6
origin:[3, 2, 5] reshape:[-1, 5]      actual: [6, 5]
# reshape:[0, -1]中 0 的索引值為 0,按照規(guī)則
# 轉換后第 0 維的元素數(shù)量與原始 Tensor 第 0 維的元素數(shù)量相同,為3
# 第 1 維的元素數(shù)量根據(jù)元素總值計算得出為 30÷3=10。
origin:[3, 2, 5] reshape:[0, -1]      actual: [3, 10]
# reshape:[3, 1, 0]中 0 的索引值為 2
# 但原 Tensor 只有 2 維,無法找到與第 3 維對應的元素數(shù)量,因此出錯。
origin:[3, 2] reshape:[3, 1, 0]       error:

另外還可以通過如下方式改變shape:

  • torch.squeeze:可實現(xiàn)Tensor的降維操作,即把Tensor中尺寸為1的維度刪除。
  • torch.unsqueeze:可實現(xiàn)Tensor的升維操作,即向Tensor中某個位置插入尺寸為1的維度。
  • torch.flatten,將Tensor的數(shù)據(jù)在指定的連續(xù)維度上展平。
  • torch.transpose,對Tensor的數(shù)據(jù)進行重排。

2.索引和切片

通過索引或切片方式可訪問或修改Tensor。

(1) 「訪問Tensor」

import torch
ndim_2_Tensor = torch.tensor([[0, 1, 2, 3],
                               [4, 5, 6, 7],
                               [8, 9, 10, 11]])
print("Origin Tensor:\n", ndim_2_Tensor.numpy())
#索引或切片的第一個值對應第 0 維,第二個值對應第 1 維,
#依次類推,如果某個維度上未指定索引,則默認為 :
#所以下面兩種操作結果一樣
print("First row:", ndim_2_Tensor[0].numpy())
print("First row:", ndim_2_Tensor[0, :].numpy())
print("First column:", ndim_2_Tensor[:, 0].numpy())
print("Last column:", ndim_2_Tensor[:, -1].numpy())
print("All element:\n", ndim_2_Tensor[:].numpy())
print("First row and second column:", ndim_2_Tensor[0, 1].numpy())

(2) 「修改Tensor」

與訪問張量類似,可以在單個或多個軸上通過索引或切片操作來修改張量。

import torch
ndim_2_Tensor = torch.ones([2, 3])
ndim_2_Tensor = ndim_2_Tensor.to(torch.float32)
print('Origin Tensor:\n ', ndim_2_Tensor)
# 修改第1維為0
ndim_2_Tensor[0] = 0
print('change Tensor:\n ', ndim_2_Tensor)
# 修改第1維為2.1
ndim_2_Tensor[0:1] = 2.1
print('change Tensor:\n ', ndim_2_Tensor)
# 修改全部Tensor
ndim_2_Tensor[...] = 3
print('change Tensor:\n ', ndim_2_Tensor)

3.Tensor運算

張量支持包括基礎數(shù)學運算、邏輯運算、矩陣運算等100余種運算操作。

數(shù)學運算:

x.abs()                       # 逐元素取絕對值
x.ceil()                      # 逐元素向上取整
x.floor()                     # 逐元素向下取整
x.round()                     # 逐元素四舍五入
x.exp()                       # 逐元素計算自然常數(shù)為底的指數(shù)
x.log()                       # 逐元素計算x的自然對數(shù)
x.reciprocal()                # 逐元素求倒數(shù)
x.square()                    # 逐元素計算平方
x.sqrt()                      # 逐元素計算平方根
x.sin()                       # 逐元素計算正弦
x.cos()                       # 逐元素計算余弦
x.add(y)                      # 逐元素加
x.subtract(y)                 # 逐元素減
x.multiply(y)                 # 逐元素乘(積)
x.divide(y)                   # 逐元素除
x.mod(y)                      # 逐元素除并取余
x.pow(y)                      # 逐元素冪
x.max()                       # 指定維度上元素最大值,默認為全部維度
x.min()                       # 指定維度上元素最小值,默認為全部維度
x.prod()                      # 指定維度上元素累乘,默認為全部維度
x.sum()                       # 指定維度上元素的和,默認為全部維度

邏輯運算:

x.isfinite()                  # 判斷Tensor中元素是否是有限的數(shù)字,即不包括inf與nan
x.equal_all(y)                # 判斷兩個Tensor的全部元素是否相等,并返回形狀為[1]的布爾類Tensor
x.equal(y)                    # 判斷兩個Tensor的每個元素是否相等,并返回形狀相同的布爾類Tensor
x.not_equal(y)                # 判斷兩個Tensor的每個元素是否不相等
x.less_than(y)                # 判斷Tensor x的元素是否小于Tensor y的對應元素
x.less_equal(y)               # 判斷Tensor x的元素是否小于或等于Tensor y的對應元素
x.greater_than(y)             # 判斷Tensor x的元素是否大于Tensor y的對應元素
x.greater_equal(y)            # 判斷Tensor x的元素是否大于或等于Tensor y的對應元素
x.allclose(y)                 # 判斷兩個Tensor的全部元素是否接近

矩陣運算:

x.t()                         # 矩陣轉置
x.transpose([1, 0])           # 交換第 0 維與第 1 維的順序
x.norm('fro')                 # 矩陣的弗羅貝尼烏斯范數(shù)
x.dist(y, p=2)                # 矩陣(x-y)的2范數(shù)
x.matmul(y)                   # 矩陣乘法

4.Tensor廣播機制

深度學習任務中,通常不可避免會遇到需要使用較小形狀的Tensor與較大形狀的Tensor執(zhí)行計算的情況。此時,則需要將較小形狀的Tensor擴展到與較大形狀的Tensor一樣的形狀,以便于匹配計算,但是又「不會」對較小形狀Tensor進行「數(shù)據(jù)拷貝」操作,從而「提升算法實現(xiàn)的運算效率」。這即是廣播機制。

Tensor廣播機制通常遵循如下規(guī)則:

  • 每個 Tensor 至少為一維 Tensor。
  • 從最后一個維度向前開始比較兩個Tensor的形狀,需要滿足如下條件才能進行廣播:
  • 兩個Tensor的維度大小相等;或者其中一個Tensor的維度為1;或者其中一個Tensor的維度不存在。

例如:

兩個Tensor的形狀一致,可以廣播。

import torch

x = torch.ones((2, 3, 4))
y = torch.ones((2, 3, 4))
z = x + y
print(z)
# tensor([[[2., 2., 2., 2.],
         [2., 2., 2., 2.],
         [2., 2., 2., 2.]],

         [[2., 2., 2., 2.],
         [2., 2., 2., 2.],
         [2., 2., 2., 2.]]])
print(z.shape)
# torch.Size([2, 3, 4])

從最后一個維度向前依次比較:第一次y的維度大小為1,第二次x的維度大小為1,第三次x和y的維度大小相等,第四次y的維度不存在,所以x和y可以廣播。

import torch

x = torch.ones((2, 3, 1, 5))
y = torch.ones((3, 4, 1))

z = x + y
print(z.shape)
# torch.Size([2, 3, 4, 5])

從最后一個維度向前依次比較:第一次比較:4不等于6,不可廣播。

x = torch.ones((2, 3, 4))
y = torch.ones((2, 3, 6))
# z = x + y
# ValueError: (InvalidArgument) Broadcast dimension mismatch.

兩個Tensor進行廣播后的結果Tensor的形狀計算規(guī)則如下:

  • 如果兩個 Tensor 的形狀的長度不一致,會在較小長度的形狀矩陣前部添加 1,直到兩個 Tensor 的形狀長度相等。
  • 保證兩個 Tensor 形狀相等之后,每個維度上的結果維度就是當前維度上的較大值。

例如,y的形狀長度為2,小于x的形狀長度3,因此會在 y 的形狀前部添加 1,結果就是 y 的形狀變?yōu)閇1, 3, 1]。廣播之后z的形狀為[2,3,4],且z的每一維度上的尺寸,將取x和y對應維度上尺寸的較大值,如第0維x的尺寸為2,y的尺寸為1,則z的第0維尺寸為2。

import torch

x = torch.ones((2, 1, 4))
y = torch.ones((3, 1))
z = x + y
print(z.shape)
# torch.Size([2, 3, 4])

廣播機制運行過程如下圖:

圖片圖片

責任編輯:趙寧寧 來源: 數(shù)據(jù)科學與AI
相關推薦

2021-11-05 12:59:51

深度學習PytorchTenso

2024-05-10 12:59:58

PyTorch人工智能

2024-12-31 07:00:00

2021-12-29 09:00:36

Go文件syscall

2020-09-15 15:50:33

Python編程語言代碼

2024-01-05 17:15:21

pytorchtensor深度學習

2024-06-11 07:34:58

C#字符串性能

2017-09-05 10:20:30

PyTorchTensorPython

2011-09-02 14:59:15

2025-01-20 08:00:00

圖像增強深度學習AI

2019-09-17 14:16:57

工具代碼開發(fā)

2024-03-22 15:32:21

機器學習算法

2024-10-22 15:51:42

PyTorch張量

2009-10-21 17:02:51

綜合布線施工經(jīng)驗

2010-03-15 15:45:50

2023-01-03 17:31:52

2024-10-16 10:03:13

2015-05-27 14:55:45

2022-01-03 16:08:36

深度學習PyTorchNumPy

2017-12-29 21:49:36

信息安全網(wǎng)絡攻擊漏洞
點贊
收藏

51CTO技術棧公眾號