0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

PyTorch教程-2.1.數(shù)據(jù)操作

李秀珍 ? 來(lái)源:ht_liu ? 作者:ht_liu ? 2023-06-02 09:35 ? 次閱讀

為了完成任何事情,我們需要一些方法來(lái)存儲(chǔ)和操作數(shù)據(jù)。通常,我們需要對(duì)數(shù)據(jù)做兩件重要的事情:(i)獲取它們;(ii) 一旦它們進(jìn)入計(jì)算機(jī)就對(duì)其進(jìn)行處理。如果沒(méi)有某種存儲(chǔ)方式,獲取數(shù)據(jù)是沒(méi)有意義的,所以首先,讓我們動(dòng)手操作n維數(shù)組,我們也稱(chēng)之為張量。如果您已經(jīng)了解 NumPy 科學(xué)計(jì)算包,那么這將是一件輕而易舉的事。對(duì)于所有現(xiàn)代深度學(xué)習(xí)框架,張量類(lèi)ndarray在 MXNet、 TensorPyTorch 和 TensorFlow 中)類(lèi)似于 NumPy ndarray,但增加了一些殺手級(jí)功能。首先,張量類(lèi)支持自動(dòng)微分。其次,它利用 GPU 來(lái)加速數(shù)值計(jì)算,而 NumPy 只能在 CPU 上運(yùn)行。這些特性使神經(jīng)網(wǎng)絡(luò)既易于編碼又能快速運(yùn)行。

2.1.1. 入門(mén)

首先,我們導(dǎo)入 PyTorch 庫(kù)。請(qǐng)注意,包名稱(chēng)是 torch.

import torch

To start, we import the np (numpy) and npx (numpy_extension) modules from MXNet. Here, the np module includes functions supported by NumPy, while the npx module contains a set of extensions developed to empower deep learning within a NumPy-like environment. When using tensors, we almost always invoke the set_np function: this is for compatibility of tensor processing by other components of MXNet.

from mxnet import np, npx npx.set_np()
import jax from jax import numpy as jnp

To start, we import tensorflow. For brevity, practitioners often assign the alias tf.

import tensorflow as tf

張量表示一個(gè)(可能是多維的)數(shù)值數(shù)組。對(duì)于一個(gè)軸,張量稱(chēng)為向量。具有兩個(gè)軸的張量稱(chēng)為矩陣k>2軸,我們刪除專(zhuān)門(mén)的名稱(chēng)并僅將對(duì)象稱(chēng)為 kth 階張量。

PyTorch 提供了多種函數(shù)來(lái)創(chuàng)建預(yù)填充值的新張量。例如,通過(guò)調(diào)用,我們可以創(chuàng)建一個(gè)均勻分布值的向量,從 0(包括)開(kāi)始到(不包括)arange(n)結(jié)束。n默認(rèn)情況下,間隔大小為 1. 除非另有說(shuō)明,否則新張量存儲(chǔ)在主內(nèi)存中并指定用于基于 CPU 的計(jì)算。

x = torch.arange(12, dtype=torch.float32) x
tensor([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])

這些值中的每一個(gè)都稱(chēng)為張量的一個(gè)元素。張量 x包含 12 個(gè)元素。我們可以通過(guò)其方法檢查張量中元素的總數(shù)numel

x.numel()
12

MXNet provides a variety of functions for creating new tensors prepopulated with values. For example, by invoking arange(n), we can create a vector of evenly spaced values, starting at 0 (included) and ending at n (not included). By default, the interval size is 1. Unless otherwise specified, new tensors are stored in main memory and designated for CPU-based computation.

x = np.arange(12) x
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])

Each of these values is called an element of the tensor. The tensor x contains 12 elements. We can inspect the total number of elements in a tensor via its size attribute.

x.size
12
x = jnp.arange(12) x
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
Array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], dtype=int32)
x.size
12

TensorFlow provides a variety of functions for creating new tensors prepopulated with values. For example, by invoking range(n), we can create a vector of evenly spaced values, starting at 0 (included) and ending at n (not included). By default, the interval size is 1. Unless otherwise specified, new tensors are stored in main memory and designated for CPU-based computation.

x = tf.range(12, dtype=tf.float32) x
<tf.Tensor: shape=(12,), dtype=float32, numpy=
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.],
   dtype=float32)>

Each of these values is called an element of the tensor. The tensor x contains 12 elements. We can inspect the total number of elements in a tensor via the size function.

tf.size(x)
<tf.Tensor: shape=(), dtype=int32, numpy=12>

我們可以通過(guò)檢查其屬性來(lái)訪問(wèn)張量的形狀(沿每個(gè)軸的長(zhǎng)度)shape。因?yàn)槲覀冊(cè)谶@里處理的是一個(gè)向量,所以它只shape包含一個(gè)元素并且與大小相同。

x.shape
torch.Size([12])
x.shape
(12,)
x.shape
(12,)
x.shape
TensorShape([12])

我們可以通過(guò)調(diào)用 來(lái)改變張量的形狀而不改變它的大小或值reshape例如,我們可以將形狀為 (12,) 的向量轉(zhuǎn)換為形狀為 (3, 4) 的x 矩陣。X這個(gè)新張量保留了所有元素,但將它們重新配置為矩陣。請(qǐng)注意,我們向量的元素一次排成一行,因此 .x[3] == X[0, 3]

X = x.reshape(3, 4) X
tensor([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.]])
X = x.reshape(3, 4) X
array([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.]])
X = x.reshape(3, 4) X
Array([[ 0, 1, 2, 3],
    [ 4, 5, 6, 7],
    [ 8, 9, 10, 11]], dtype=int32)
X = tf.reshape(x, (3, 4)) X
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.]], dtype=float32)>

請(qǐng)注意,指定每個(gè)形狀組件reshape是多余的。因?yàn)槲覀円呀?jīng)知道張量的大小,所以我們可以在給定其余部分的情況下計(jì)算出形狀的一個(gè)組成部分。例如,給定大小的張量 n和目標(biāo)形狀(h,w), 我們知道 w=n/h. 要自動(dòng)推斷形狀的一個(gè)組件,我們可以-1為應(yīng)該自動(dòng)推斷的形狀組件放置一個(gè)。在我們的例子中,我們可以等效地調(diào)用or 而不是調(diào)用。x.reshape(3, 4)x.reshape(-1, 4)x.reshape(3, -1)

從業(yè)者通常需要使用初始化為包含全零或全一的張量。我們可以通過(guò)函數(shù)構(gòu)造一個(gè)所有元素都設(shè)置為零且形狀為 (2, 3, 4) 的張量zeros。

torch.zeros((2, 3, 4))
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.]]])
np.zeros((2, 3, 4))
array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

    [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]])
jnp.zeros((2, 3, 4))
Array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

    [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]], dtype=float32)
tf.zeros((2, 3, 4))
<tf.Tensor: shape=(2, 3, 4), dtype=float32, numpy=
array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

    [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]], dtype=float32)>

類(lèi)似地,我們可以通過(guò)調(diào)用創(chuàng)建一個(gè)全部為 1 的張量ones。

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

    [[1., 1., 1., 1.],
     [1., 1., 1., 1.],
     [1., 1., 1., 1.]]])
np.ones((2, 3, 4))
array([[[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]],

    [[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]]])
jnp.ones((2, 3, 4))
Array([[[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]],

    [[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]]], dtype=float32)
tf.ones((2, 3, 4))
<tf.Tensor: shape=(2, 3, 4), dtype=float32, numpy=
array([[[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]],

    [[1., 1., 1., 1.],
    [1., 1., 1., 1.],
    [1., 1., 1., 1.]]], dtype=float32)>

我們經(jīng)常希望從給定的概率分布中隨機(jī)(且獨(dú)立地)采樣每個(gè)元素。例如,神經(jīng)網(wǎng)絡(luò)的參數(shù)通常是隨機(jī)初始化的。以下代碼片段創(chuàng)建了一個(gè)張量,其中的元素取自標(biāo)準(zhǔn)高斯(正態(tài))分布,均值為 0,標(biāo)準(zhǔn)差為 1。

torch.randn(3, 4)
tensor([[ 1.4251, -1.4341, 0.2826, -0.4915],
    [ 0.1799, -1.1769, 2.3581, -0.1923],
    [ 0.8576, -0.0719, 1.4172, -1.3151]])
np.random.normal(0, 1, size=(3, 4))
array([[ 2.2122064 , 1.1630787 , 0.7740038 , 0.4838046 ],
    [ 1.0434403 , 0.29956347, 1.1839255 , 0.15302546],
    [ 1.8917114 , -1.1688148 , -1.2347414 , 1.5580711 ]])
# Any call of a random function in JAX requires a key to be # specified, feeding the same key to a random function will # always result in the same sample being generated jax.random.normal(jax.random.PRNGKey(0), (3, 4))
Array([[ 1.1901639 , -1.0996888 , 0.44367844, 0.5984697 ],
    [-0.39189556, 0.69261974, 0.46018356, -2.068578 ],
    [-0.21438177, -0.9898306 , -0.6789304 , 0.27362573]],   dtype=float32)
tf.random.normal(shape=[3, 4])
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[-1.198586 , -0.04204642, -0.6005369 , 1.4371548 ],
    [ 0.08375237, 0.947974 , 1.6228461 , 1.1598791 ],
    [ 0.58289856, -0.76583815, -0.36692864, 1.727855 ]],
   dtype=float32)>

最后,我們可以通過(guò)提供(可能嵌套的)包含數(shù)字文字的 Python 列表為每個(gè)元素提供精確值來(lái)構(gòu)造張量。在這里,我們構(gòu)建了一個(gè)包含列表列表的矩陣,其中最外層的列表對(duì)應(yīng)于軸 0,內(nèi)部列表對(duì)應(yīng)于軸 1。

torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
tensor([[2, 1, 4, 3],
    [1, 2, 3, 4],
    [4, 3, 2, 1]])
np.array([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
array([[2., 1., 4., 3.],
    [1., 2., 3., 4.],
    [4., 3., 2., 1.]])
jnp.array([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
Array([[2, 1, 4, 3],
    [1, 2, 3, 4],
    [4, 3, 2, 1]], dtype=int32)
tf.constant([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
<tf.Tensor: shape=(3, 4), dtype=int32, numpy=
array([[2, 1, 4, 3],
    [1, 2, 3, 4],
    [4, 3, 2, 1]], dtype=int32)>

2.1.2. 索引和切片

與 Python 列表一樣,我們可以通過(guò)索引(從 0 開(kāi)始)訪問(wèn)張量元素。要根據(jù)元素相對(duì)于列表末尾的位置訪問(wèn)元素,我們可以使用負(fù)索引。最后,我們可以通過(guò)切片(例如,)訪問(wèn)整個(gè)索引范圍X[start:stop],其中返回值包括第一個(gè)索引(start但不包括最后一個(gè)stop)。最后,當(dāng)只有一個(gè)索引(或切片)被指定為kth階張量,它沿軸 0 應(yīng)用。因此,在下面的代碼中,[-1]選擇最后一行并 [1:3]選擇第二行和第三行。

X[-1], X[1:3]
(tensor([ 8., 9., 10., 11.]),
 tensor([[ 4., 5., 6., 7.],
     [ 8., 9., 10., 11.]]))

除了讀取之外,我們還可以通過(guò)指定索引來(lái)寫(xiě)入矩陣的元素。

X[1, 2] = 17 X
tensor([[ 0., 1., 2., 3.],
    [ 4., 5., 17., 7.],
    [ 8., 9., 10., 11.]])
X[-1], X[1:3]
(array([ 8., 9., 10., 11.]),
 array([[ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.]]))

Beyond reading, we can also write elements of a matrix by specifying indices.

X[1, 2] = 17 X
array([[ 0., 1., 2., 3.],
    [ 4., 5., 17., 7.],
    [ 8., 9., 10., 11.]])
X[-1], X[1:3]
(Array([ 8, 9, 10, 11], dtype=int32),
 Array([[ 4, 5, 6, 7],
    [ 8, 9, 10, 11]], dtype=int32))
# JAX arrays are immutable. jax.numpy.ndarray.at index # update operators create a new array with the corresponding # modifications made X_new_1 = X.at[1, 2].set(17) X_new_1
Array([[ 0, 1, 2, 3],
    [ 4, 5, 17, 7],
    [ 8, 9, 10, 11]], dtype=int32)
X[-1], X[1:3]
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 8., 9., 10., 11.], dtype=float32)>,
 <tf.Tensor: shape=(2, 4), dtype=float32, numpy=
 array([[ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.]], dtype=float32)>)

Tensors in TensorFlow are immutable, and cannot be assigned to. Variables in TensorFlow are mutable containers of state that support assignments. Keep in mind that gradients in TensorFlow do not flow backwards through Variable assignments.

Beyond assigning a value to the entire Variable, we can write elements of a Variable by specifying indices.

X_var = tf.Variable(X) X_var[1, 2].assign(9) X_var
<tf.Variable 'Variable:0' shape=(3, 4) dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
    [ 4., 5., 9., 7.],
    [ 8., 9., 10., 11.]], dtype=float32)>

如果我們想為多個(gè)元素分配相同的值,我們?cè)谫x值操作的左側(cè)應(yīng)用索引。例如,訪問(wèn)第一行和第二行,其中 獲取沿軸 1(列)的所有元素。雖然我們討論了矩陣的索引,但它也適用于向量和二維以上的張量。[:2, :]:

X[:2, :] = 12 X
tensor([[12., 12., 12., 12.],
    [12., 12., 12., 12.],
    [ 8., 9., 10., 11.]])
X[:2, :] = 12 X
array([[12., 12., 12., 12.],
    [12., 12., 12., 12.],
    [ 8., 9., 10., 11.]])
X_new_2 = X_new_1.at[:2, :].set(12) X_new_2
Array([[12, 12, 12, 12],
    [12, 12, 12, 12],
    [ 8, 9, 10, 11]], dtype=int32)
X_var = tf.Variable(X) X_var[:2, :].assign(tf.ones(X_var[:2,:].shape, dtype=tf.float32) * 12) X_var
<tf.Variable 'Variable:0' shape=(3, 4) dtype=float32, numpy=
array([[12., 12., 12., 12.],
    [12., 12., 12., 12.],
    [ 8., 9., 10., 11.]], dtype=float32)>

2.1.3. 操作

現(xiàn)在我們知道如何構(gòu)建張量以及如何讀取和寫(xiě)入它們的元素,我們可以開(kāi)始使用各種數(shù)學(xué)運(yùn)算來(lái)操縱它們。最有用的工具之一是 逐元素操作。這些將標(biāo)準(zhǔn)標(biāo)量運(yùn)算應(yīng)用于張量的每個(gè)元素。對(duì)于將兩個(gè)張量作為輸入的函數(shù),逐元素運(yùn)算對(duì)每對(duì)對(duì)應(yīng)元素應(yīng)用一些標(biāo)準(zhǔn)二元運(yùn)算符。我們可以從從標(biāo)量映射到標(biāo)量的任何函數(shù)創(chuàng)建一個(gè)逐元素函數(shù)。

在數(shù)學(xué)符號(hào)中,我們用簽名表示這樣的一元標(biāo)量運(yùn)算符(接受一個(gè)輸入 f:R→R. 這只是意味著函數(shù)從任何實(shí)數(shù)映射到其他實(shí)數(shù)。大多數(shù)標(biāo)準(zhǔn)運(yùn)算符都可以按元素應(yīng)用,包括一元運(yùn)算符,如ex.

torch.exp(x)
tensor([162754.7969, 162754.7969, 162754.7969, 162754.7969, 162754.7969,
    162754.7969, 162754.7969, 162754.7969,  2980.9580,  8103.0840,
     22026.4648, 59874.1406])
np.exp(x)
array([1.0000000e+00, 2.7182817e+00, 7.3890562e+00, 2.0085537e+01,
    5.4598148e+01, 1.4841316e+02, 4.0342880e+02, 1.0966332e+03,
    2.9809580e+03, 8.1030840e+03, 2.2026465e+04, 5.9874141e+04])
jnp.exp(x)
Array([1.0000000e+00, 2.7182817e+00, 7.3890562e+00, 2.0085537e+01,
    5.4598152e+01, 1.4841316e+02, 4.0342880e+02, 1.0966332e+03,
    2.9809580e+03, 8.1030840e+03, 2.2026465e+04, 5.9874141e+04],   dtype=float32)
tf.exp(x)
<tf.Tensor: shape=(12,), dtype=float32, numpy=
array([1.0000000e+00, 2.7182817e+00, 7.3890562e+00, 2.0085537e+01,
    5.4598148e+01, 1.4841316e+02, 4.0342877e+02, 1.0966332e+03,
    2.9809580e+03, 8.1030840e+03, 2.2026465e+04, 5.9874141e+04],
   dtype=float32)>

同樣,我們表示二元標(biāo)量運(yùn)算符,它通過(guò)簽名將成對(duì)的實(shí)數(shù)映射到一個(gè)(單個(gè))實(shí)數(shù) f:R,R→R. 給定任意兩個(gè)向量uv 形狀相同,和一個(gè)二元運(yùn)算符f,我們可以產(chǎn)生一個(gè)向量 c=F(u,v)通過(guò)設(shè)置 ci←f(ui,vi)對(duì)全部i, 在哪里ci,ui, 和viith向量的元素 c,u, 和v. 在這里,我們產(chǎn)生了向量值 F:Rd,Rd→Rd通過(guò) 將標(biāo)量函數(shù)提升為元素向量運(yùn)算。+加法 ( )、減法 ( -)、乘法 ( *)、除法 ( /) 和求冪 ( )的常見(jiàn)標(biāo)準(zhǔn)算術(shù)運(yùn)算符**都已提升為任意形狀的相同形狀張量的元素運(yùn)算。

x = torch.tensor([1.0, 2, 4, 8]) y = torch.tensor([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y
(tensor([ 3., 4., 6., 10.]),
 tensor([-1., 0., 2., 6.]),
 tensor([ 2., 4., 8., 16.]),
 tensor([0.5000, 1.0000, 2.0000, 4.0000]),
 tensor([ 1., 4., 16., 64.]))
x = np.array([1, 2, 4, 8]) y = np.array([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y
(array([ 3., 4., 6., 10.]),
 array([-1., 0., 2., 6.]),
 array([ 2., 4., 8., 16.]),
 array([0.5, 1. , 2. , 4. ]),
 array([ 1., 4., 16., 64.]))
x = jnp.array([1.0, 2, 4, 8]) y = jnp.array([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y
(Array([ 3., 4., 6., 10.], dtype=float32),
 Array([-1., 0., 2., 6.], dtype=float32),
 Array([ 2., 4., 8., 16.], dtype=float32),
 Array([0.5, 1. , 2. , 4. ], dtype=float32),
 Array([ 1., 4., 16., 64.], dtype=float32))
x = tf.constant([1.0, 2, 4, 8]) y = tf.constant([2.0, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 3., 4., 6., 10.], dtype=float32)>,
 <tf.Tensor: shape=(4,), dtype=float32, numpy=array([-1., 0., 2., 6.], dtype=float32)>,
 <tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 2., 4., 8., 16.], dtype=float32)>,
 <tf.Tensor: shape=(4,), dtype=float32, numpy=array([0.5, 1. , 2. , 4. ], dtype=float32)>,
 <tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 1., 4., 16., 64.], dtype=float32)>)

除了按元素計(jì)算,我們還可以執(zhí)行線性代數(shù)運(yùn)算,例如點(diǎn)積和矩陣乘法。我們將在2.3 節(jié)中詳細(xì)說(shuō)明這些內(nèi)容。

我們還可以將多個(gè)張量連接在一起,將它們首尾相連形成一個(gè)更大的張量。我們只需要提供一個(gè)張量列表并告訴系統(tǒng)沿著哪個(gè)軸連接。下面的示例顯示了當(dāng)我們沿行(軸 0)與列(軸 1)連接兩個(gè)矩陣時(shí)會(huì)發(fā)生什么。我們可以看到第一個(gè)輸出的 axis-0 長(zhǎng)度 (6) 是兩個(gè)輸入張量的軸 0 長(zhǎng)度之和 (3+3); 而第二個(gè)輸出的 axis-1 長(zhǎng)度 (8) 是兩個(gè)輸入張量的 axis-1 長(zhǎng)度之和 (4+4).

X = torch.arange(12, dtype=torch.float32).reshape((3,4)) Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0., 1., 2., 3.],
     [ 4., 5., 6., 7.],
     [ 8., 9., 10., 11.],
     [ 2., 1., 4., 3.],
     [ 1., 2., 3., 4.],
     [ 4., 3., 2., 1.]]),
 tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
     [ 4., 5., 6., 7., 1., 2., 3., 4.],
     [ 8., 9., 10., 11., 4., 3., 2., 1.]]))
X = np.arange(12).reshape(3, 4) Y = np.array([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) np.concatenate([X, Y], axis=0), np.concatenate([X, Y], axis=1)
(array([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.],
    [ 2., 1., 4., 3.],
    [ 1., 2., 3., 4.],
    [ 4., 3., 2., 1.]]),
 array([[ 0., 1., 2., 3., 2., 1., 4., 3.],
    [ 4., 5., 6., 7., 1., 2., 3., 4.],
    [ 8., 9., 10., 11., 4., 3., 2., 1.]]))
X = jnp.arange(12, dtype=jnp.float32).reshape((3, 4)) Y = jnp.array([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) jnp.concatenate((X, Y), axis=0), jnp.concatenate((X, Y), axis=1)
(Array([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.],
    [ 2., 1., 4., 3.],
    [ 1., 2., 3., 4.],
    [ 4., 3., 2., 1.]], dtype=float32),
 Array([[ 0., 1., 2., 3., 2., 1., 4., 3.],
    [ 4., 5., 6., 7., 1., 2., 3., 4.],
    [ 8., 9., 10., 11., 4., 3., 2., 1.]], dtype=float32))
X = tf.reshape(tf.range(12, dtype=tf.float32), (3, 4)) Y = tf.constant([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) tf.concat([X, Y], axis=0), tf.concat([X, Y], axis=1)
(<tf.Tensor: shape=(6, 4), dtype=float32, numpy=
 array([[ 0., 1., 2., 3.],
    [ 4., 5., 6., 7.],
    [ 8., 9., 10., 11.],
    [ 2., 1., 4., 3.],
    [ 1., 2., 3., 4.],
    [ 4., 3., 2., 1.]], dtype=float32)>,
 <tf.Tensor: shape=(3, 8), dtype=float32, numpy=
 array([[ 0., 1., 2., 3., 2., 1., 4., 3.],
    [ 4., 5., 6., 7., 1., 2., 3., 4.],
    [ 8., 9., 10., 11., 4., 3., 2., 1.]], dtype=float32)>)

有時(shí),我們想通過(guò)邏輯語(yǔ)句構(gòu)造一個(gè)二元張量。個(gè)例子。對(duì)于每一個(gè)位置,如果相等,則結(jié)果中相應(yīng)的條目取值,否則取值。X == Yi, jX[i, j]Y[i, j]10

X == Y
tensor([[False, True, False, True],
    [False, False, False, False],
    [False, False, False, False]])
X == Y
array([[False, True, False, True],
    [False, False, False, False],
    [False, False, False, False]])
X == Y
Array([[False, True, False, True],
    [False, False, False, False],
    [False, False, False, False]], dtype=bool)
X == Y
<tf.Tensor: shape=(3, 4), dtype=bool, numpy=
array([[False, True, False, True],
    [False, False, False, False],
    [False, False, False, False]])>

將張量中的所有元素相加得到一個(gè)只有一個(gè)元素的張量。

X.sum()
tensor(66.)
X.sum()
array(66.)
X.sum()
Array(66., dtype=float32)
tf.reduce_sum(X)
<tf.Tensor: shape=(), dtype=float32, numpy=66.0>

2.1.4. 廣播

到目前為止,您已經(jīng)知道如何對(duì)兩個(gè)相同形狀的張量執(zhí)行逐元素二元運(yùn)算。在某些條件下,即使形狀不同,我們?nèi)匀豢梢酝ㄟ^(guò)調(diào)用廣播機(jī)制來(lái)執(zhí)行元素二元運(yùn)算。廣播根據(jù)以下兩步過(guò)程進(jìn)行:(i)通過(guò)沿長(zhǎng)度為 1 的軸復(fù)制元素來(lái)擴(kuò)展一個(gè)或兩個(gè)數(shù)組,以便在此轉(zhuǎn)換之后,兩個(gè)張量具有相同的形狀;(ii) 對(duì)結(jié)果數(shù)組執(zhí)行逐元素操作。

a = torch.arange(3).reshape((3, 1)) b = torch.arange(2).reshape((1, 2)) a, b
(tensor([[0],
     [1],
     [2]]),
 tensor([[0, 1]]))
a = np.arange(3).reshape(3, 1) b = np.arange(2).reshape(1, 2) a, b
(array([[0.],
    [1.],
    [2.]]),
 array([[0., 1.]]))
a = jnp.arange(3).reshape((3, 1)) b = jnp.arange(2).reshape((1, 2)) a, b
(Array([[0],
    [1],
    [2]], dtype=int32),
 Array([[0, 1]], dtype=int32))
a = tf.reshape(tf.range(3), (3, 1)) b = tf.reshape(tf.range(2), (1, 2)) a, b
(<tf.Tensor: shape=(3, 1), dtype=int32, numpy=
 array([[0],
    [1],
    [2]], dtype=int32)>,
 <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>)

因?yàn)?/font>ab3×11×2 矩陣,它們的形狀不匹配。廣播產(chǎn)生了更大的3×2a 通過(guò)在按元素添加之前沿列復(fù)制矩陣和b沿行復(fù)制矩陣來(lái)創(chuàng)建矩陣。

a + b
tensor([[0, 1],
    [1, 2],
    [2, 3]])
a + b
array([[0., 1.],
    [1., 2.],
    [2., 3.]])
a + b
Array([[0, 1],
    [1, 2],
    [2, 3]], dtype=int32)
a + b
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[0, 1],
    [1, 2],
    [2, 3]], dtype=int32)>

2.1.5. 節(jié)省內(nèi)存

運(yùn)行操作可能會(huì)導(dǎo)致將新內(nèi)存分配給主機(jī)結(jié)果。例如,如果我們寫(xiě),我們?nèi)∠?/font>曾經(jīng)指向的張量 ,而是指向新分配的內(nèi)存。我們可以用 Python 的函數(shù)來(lái)演示這個(gè)問(wèn)題,它為我們提供了被引用對(duì)象在內(nèi)存中的確切地址。請(qǐng)注意,在我們運(yùn)行之后,指向不同的位置。這是因?yàn)?Python 首先求值,為結(jié)果分配新的內(nèi)存,然后指向內(nèi)存中的這個(gè)新位置。Y = X + YYYid()Y = Y + Xid(Y)Y + XY

before = id(Y) Y = Y + X id(Y) == before
False
before = id(Y) Y = Y + X id(Y) == before
False
before = id(Y) Y = Y + X id(Y) == before
False
before = id(Y) Y = Y + X id(Y) == before
False

由于兩個(gè)原因,這可能是不受歡迎的。首先,我們不想一直在不必要地分配內(nèi)存。機(jī)器學(xué)習(xí)中,我們通常有數(shù)百兆字節(jié)的參數(shù)并且每秒更新所有這些參數(shù)多次。只要有可能,我們都希望就地執(zhí)行這些更新其次,我們可能會(huì)從多個(gè)變量中指向相同的參數(shù)。如果我們沒(méi)有就地更新,我們必須小心更新所有這些引用,以免引發(fā)內(nèi)存泄漏或無(wú)意中引用過(guò)時(shí)的參數(shù)。

幸運(yùn)的是,執(zhí)行就地操作很容易。Y我們可以使用切片表示法將操作的結(jié)果分配給先前分配的數(shù)組: 。為了說(shuō)明這個(gè)概念,我們覆蓋張量的值,在初始化它之后,使用 ,使其具有與 相同的形狀。Y[:] = Zzeros_likeY

Z = torch.zeros_like(Y) print('id(Z):', id(Z)) Z[:] = X + Y print('id(Z):', id(Z))
id(Z): 139763606871712
id(Z): 139763606871712

X如果在后續(xù)計(jì)算中不重用的值,我們也可以使用or來(lái)減少操作的內(nèi)存開(kāi)銷(xiāo)。X[:] = X + YX += Y

before = id(X) X += Y id(X) == before
True

Fortunately, performing in-place operations is easy. We can assign the result of an operation to a previously allocated array Y by using slice notation: Y[:] = . To illustrate this concept, we overwrite the values of tensor Z, after initializing it, using zeros_like, to have the same shape as Y.

Z = np.zeros_like(Y) print('id(Z):', id(Z)) Z[:] = X + Y print('id(Z):', id(Z))
id(Z): 140447312694464
id(Z): 140447312694464

If the value of X is not reused in subsequent computations, we can also use X[:] = X + Y or X += Y to reduce the memory overhead of the operation.

before = id(X) X += Y id(X) == before
True
# JAX arrays do not allow in-place operations

Variables are mutable containers of state in TensorFlow. They provide a way to store your model parameters. We can assign the result of an operation to a Variable with assign. To illustrate this concept, we overwrite the values of Variable Z after initializing it, using zeros_like, to have the same shape as Y.

Z = tf.Variable(tf.zeros_like(Y)) print('id(Z):', id(Z)) Z.assign(X + Y) print('id(Z):', id(Z))
id(Z): 140457113440208
id(Z): 140457113440208

Even once you store state persistently in a Variable, you may want to reduce your memory usage further by avoiding excess allocations for tensors that are not your model parameters. Because TensorFlow Tensors are immutable and gradients do not flow through Variable assignments, TensorFlow does not provide an explicit way to run an individual operation in-place.

However, TensorFlow provides the tf.function decorator to wrap computation inside of a TensorFlow graph that gets compiled and optimized before running. This allows TensorFlow to prune unused values, and to reuse prior allocations that are no longer needed. This minimizes the memory overhead of TensorFlow computations.

@tf.function def computation(X, Y): Z = tf.zeros_like(Y) # This unused value will be pruned out A = X + Y # Allocations will be reused when no longer needed B = A + Y C = B + Y return C + Y computation(X, Y)
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[ 8., 9., 26., 27.],
    [24., 33., 42., 51.],
    [56., 57., 58., 59.]], dtype=float32)>

2.1.6. 轉(zhuǎn)換為其他 Python 對(duì)象

轉(zhuǎn)換為 NumPy 張量 ( ndarray),反之亦然,很容易。torch Tensor 和 numpy array 將共享它們的底層內(nèi)存,通過(guò)就地操作改變一個(gè)也會(huì)改變另一個(gè)。

A = X.numpy() B = torch.from_numpy(A) type(A), type(B)
(numpy.ndarray, torch.Tensor)

Converting to a NumPy tensor (ndarray), or vice versa, is easy. The converted result does not share memory. This minor inconvenience is actually quite important: when you perform operations on the CPU or on GPUs, you do not want to halt computation, waiting to see whether the NumPy package of Python might want to be doing something else with the same chunk of memory.

A = X.asnumpy() B = np.array(A) type(A), type(B)
(numpy.ndarray, mxnet.numpy.ndarray)
A = jax.device_get(X) B = jax.device_put(A) type(A), type(B)
(numpy.ndarray, jaxlib.xla_extension.Array)

Converting to a NumPy tensor (ndarray), or vice versa, is easy. The converted result does not share memory. This minor inconvenience is actually quite important: when you perform operations on the CPU or on GPUs, you do not want to halt computation, waiting to see whether the NumPy package of Python might want to be doing something else with the same chunk of memory.

A = X.numpy() B = tf.constant(A) type(A), type(B)
(numpy.ndarray, tensorflow.python.framework.ops.EagerTensor)

要將大小為 1 的張量轉(zhuǎn)換為 Python 標(biāo)量,我們可以調(diào)用函數(shù) item或 Python 的內(nèi)置函數(shù)。

a = torch.tensor([3.5]) a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3)
a = np.array([3.5]) a, a.item(), float(a), int(a)
(array([3.5]), 3.5, 3.5, 3)
a = jnp.array([3.5]) a, a.item(), float(a), int(a)
(Array([3.5], dtype=float32), 3.5, 3.5, 3)
a = tf.constant([3.5]).numpy() a, a.item(), float(a), int(a)
(array([3.5], dtype=float32), 3.5, 3.5, 3)

2.1.7. 概括

張量類(lèi)是深度學(xué)習(xí)庫(kù)中存儲(chǔ)和操作數(shù)據(jù)的主要接口。張量提供多種功能,包括構(gòu)造例程;索引和切片;基礎(chǔ)數(shù)學(xué)運(yùn)算;廣播; 內(nèi)存高效分配;以及與其他 Python 對(duì)象之間的轉(zhuǎn)換。

2.1.8. 練習(xí)

  1. 運(yùn)行本節(jié)中的代碼。把條件語(yǔ)句改成 or ,然后看看你能得到什么樣的張量。X == YX < YX > Y

  2. 將廣播機(jī)制中按元素操作的兩個(gè)張量替換為其他形狀,例如 3 維張量。結(jié)果和預(yù)期的一樣嗎?

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7118

    瀏覽量

    89342
  • gpu
    gpu
    +關(guān)注

    關(guān)注

    28

    文章

    4764

    瀏覽量

    129180
  • pytorch
    +關(guān)注

    關(guān)注

    2

    文章

    808

    瀏覽量

    13310
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Pytorch模型訓(xùn)練實(shí)用PDF教程【中文】

    對(duì) PyTorch 提供的數(shù)據(jù)增強(qiáng)方法(22 個(gè))、權(quán)值初始化方法(10 個(gè))、損失函數(shù)(17 個(gè))、優(yōu)化器(6 個(gè))及 tensorboardX 的方法(13 個(gè))進(jìn)行了詳細(xì)介紹。本教程分為四章
    發(fā)表于 12-21 09:18

    Pytorch入門(mén)之的基本操作

    Pytorch入門(mén)之基本操作
    發(fā)表于 05-22 17:15

    PyTorch如何入門(mén)

    PyTorch 入門(mén)實(shí)戰(zhàn)(一)——Tensor
    發(fā)表于 06-01 09:58

    pytorch模型轉(zhuǎn)換需要注意的事項(xiàng)有哪些?

    和記錄張量上的操作,不會(huì)記錄任何控制流操作。 為什么不能是GPU模型? 答:BMNETP的編譯過(guò)程不支持。 如何將GPU模型轉(zhuǎn)成CPU模型? 答:在加載PyTorch的Python模型
    發(fā)表于 09-18 08:05

    什么是張量,如何在PyTorch操作張量?

    Kirill Dubovikov寫(xiě)的PyTorch vs TensorFlow?—?spotting the difference比較了PyTorch和TensorFlow這兩個(gè)框架。如果你想
    的頭像 發(fā)表于 10-12 08:58 ?1.6w次閱讀

    PyTorch構(gòu)建自己一種易用的計(jì)算圖結(jié)構(gòu)

    PNNX項(xiàng)目 PyTorch Neural Network eXchange(PNNX)是PyTorch模型互操作性的開(kāi)放標(biāo)準(zhǔn).
    的頭像 發(fā)表于 02-01 14:26 ?1221次閱讀

    PyTorch教程之數(shù)據(jù)操作

    為了完成任何事情,我們需要一些方法來(lái)存儲(chǔ)和操作數(shù)據(jù)。通常,我們需要對(duì)數(shù)據(jù)做兩件重要的事情:(i)獲取它們;(ii) 一 旦它們進(jìn)入計(jì)算機(jī)就對(duì)其進(jìn)行處理。如果沒(méi)有某種存儲(chǔ)方式,獲取數(shù)據(jù)是沒(méi)有意義
    發(fā)表于 06-02 11:05 ?0次下載
    <b class='flag-5'>PyTorch</b>教程之<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>操作</b>

    PyTorch教程之數(shù)據(jù)預(yù)處理

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程之數(shù)據(jù)預(yù)處理.pdf》資料免費(fèi)下載
    發(fā)表于 06-02 14:11 ?0次下載
    <b class='flag-5'>PyTorch</b>教程之<b class='flag-5'>數(shù)據(jù)</b>預(yù)處理

    PyTorch教程3.3之綜合回歸數(shù)據(jù)

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程3.3之綜合回歸數(shù)據(jù).pdf》資料免費(fèi)下載
    發(fā)表于 06-05 15:48 ?0次下載
    <b class='flag-5'>PyTorch</b>教程3.3之綜合回歸<b class='flag-5'>數(shù)據(jù)</b>

    PyTorch教程14.6之對(duì)象檢測(cè)數(shù)據(jù)

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程14.6之對(duì)象檢測(cè)數(shù)據(jù)集.pdf》資料免費(fèi)下載
    發(fā)表于 06-05 11:23 ?0次下載
    <b class='flag-5'>PyTorch</b>教程14.6之對(duì)象檢測(cè)<b class='flag-5'>數(shù)據(jù)</b>集

    PyTorch入門(mén)須知 PyTorch教程-2.1. 數(shù)據(jù)操作

    為了完成任何事情,我們需要一些方法來(lái)存儲(chǔ)和操作數(shù)據(jù)。通常,我們需要對(duì)數(shù)據(jù)做兩件重要的事情:(i)獲取它們;(ii) 一旦它們進(jìn)入計(jì)算機(jī)就對(duì)其進(jìn)行處理。如果沒(méi)有某種存儲(chǔ)方式,獲取數(shù)據(jù)是沒(méi)有意義的,所以
    的頭像 發(fā)表于 06-05 15:14 ?681次閱讀

    PyTorch如何訓(xùn)練自己的數(shù)據(jù)

    PyTorch是一個(gè)廣泛使用的深度學(xué)習(xí)框架,它以其靈活性、易用性和強(qiáng)大的動(dòng)態(tài)圖特性而聞名。在訓(xùn)練深度學(xué)習(xí)模型時(shí),數(shù)據(jù)集是不可或缺的組成部分。然而,很多時(shí)候,我們可能需要使用自己的數(shù)據(jù)集而不是現(xiàn)成
    的頭像 發(fā)表于 07-02 14:09 ?1921次閱讀

    pytorch如何訓(xùn)練自己的數(shù)據(jù)

    本文將詳細(xì)介紹如何使用PyTorch框架來(lái)訓(xùn)練自己的數(shù)據(jù)。我們將從數(shù)據(jù)準(zhǔn)備、模型構(gòu)建、訓(xùn)練過(guò)程、評(píng)估和測(cè)試等方面進(jìn)行講解。 環(huán)境搭建 首先,我們需要安裝PyTorch??梢酝ㄟ^(guò)訪問(wèn)
    的頭像 發(fā)表于 07-11 10:04 ?581次閱讀

    pycharm如何調(diào)用pytorch

    與PyCharm結(jié)合使用,可以提高開(kāi)發(fā)效率和代碼質(zhì)量。 安裝PyTorch 2.1 檢查Python版本 在安裝PyTorch之前,請(qǐng)確保您的Python版本為3.6或更高。可以通過(guò)以下命令檢查
    的頭像 發(fā)表于 08-01 15:41 ?678次閱讀

    PyTorch 數(shù)據(jù)加載與處理方法

    PyTorch 是一個(gè)流行的開(kāi)源機(jī)器學(xué)習(xí)庫(kù),它提供了強(qiáng)大的工具來(lái)構(gòu)建和訓(xùn)練深度學(xué)習(xí)模型。在構(gòu)建模型之前,一個(gè)重要的步驟是加載和處理數(shù)據(jù)。 1. PyTorch 數(shù)據(jù)加載基礎(chǔ) 在
    的頭像 發(fā)表于 11-05 17:37 ?466次閱讀