<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 2.2 數據操作 在深度學習中,我們通常會頻繁地對數據進行操作。作為動手學深度學習的基礎,本節將介紹如何對內存中的數據進行操作。 在PyTorch中,`torch.Tensor`是存儲和變換數據的主要工具。如果你之前用過NumPy,你會發現`Tensor`和NumPy的多維數組非常類似。然而,`Tensor`提供GPU計算和自動求梯度等更多功能,這些使`Tensor`更加適合深度學習。 > "tensor"這個單詞一般可譯作“張量”,張量可以看作是一個多維數組。標量可以看作是0維張量,向量可以看作1維張量,矩陣可以看作是二維張量。 ## 2.2.1 創建`Tensor` 我們先介紹`Tensor`的最基本功能,即`Tensor`的創建。 首先導入PyTorch: ~~~ ?import torch ~~~ 然后我們創建一個5x3的未初始化的`Tensor`: ~~~ ?x = torch.empty(5, 3) ?print(x) ~~~ 輸出: ~~~ ?tensor([[ 0.0000e+00, 1.5846e+29, 0.0000e+00], ? ? ? ? [ 1.5846e+29, 5.6052e-45, 0.0000e+00], ? ? ? ? [ 0.0000e+00, 0.0000e+00, 0.0000e+00], ? ? ? ? [ 0.0000e+00, 0.0000e+00, 0.0000e+00], ? ? ? ? [ 0.0000e+00, 1.5846e+29, -2.4336e+02]]) ~~~ 創建一個5x3的隨機初始化的`Tensor`: ~~~ ?x = torch.rand(5, 3) ?print(x) ~~~ 輸出: ~~~ ?tensor([[0.4963, 0.7682, 0.0885], ? ? ? ? [0.1320, 0.3074, 0.6341], ? ? ? ? [0.4901, 0.8964, 0.4556], ? ? ? ? [0.6323, 0.3489, 0.4017], ? ? ? ? [0.0223, 0.1689, 0.2939]]) ~~~ 創建一個5x3的long型全0的`Tensor`: ~~~ ?x = torch.zeros(5, 3, dtype=torch.long) ?print(x) ~~~ 輸出: ~~~ ?tensor([[0, 0, 0], ? ? ? ? [0, 0, 0], ? ? ? ? [0, 0, 0], ? ? ? ? [0, 0, 0], ? ? ? ? [0, 0, 0]]) ~~~ 還可以直接根據數據創建: ~~~ ?x = torch.tensor([5.5, 3]) ?print(x) ~~~ 輸出: ~~~ tensor([5.5000, 3.0000]) ~~~ 還可以通過現有的`Tensor`來創建,此方法會默認重用輸入`Tensor`的一些屬性,例如數據類型,除非自定義數據類型。 ~~~ x = x.new_ones(5, 3, dtype=torch.float64) # 返回的tensor默認具有相同的torch.dtype和torch.device print(x) x = torch.randn_like(x, dtype=torch.float) # 指定新的數據類型 print(x) ~~~ 輸出: ~~~ tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], dtype=torch.float64) tensor([[ 0.6035, 0.8110, -0.0451], [ 0.8797, 1.0482, -0.0445], [-0.7229, 2.8663, -0.5655], [ 0.1604, -0.0254, 1.0739], [ 2.2628, -0.9175, -0.2251]]) ~~~ 我們可以通過`shape`或者`size()`來獲取`Tensor`的形狀: ~~~ print(x.size()) print(x.shape) ~~~ 輸出: ~~~ torch.Size([5, 3]) torch.Size([5, 3]) ~~~ > 注意:返回的torch.Size其實就是一個tuple, 支持所有tuple的操作。 還有很多函數可以創建`Tensor`,去翻翻官方API就知道了,下表給了一些常用的作參考。 | 函數 | 功能 | | --- | --- | | Tensor(\*sizes) | 基礎構造函數 | | tensor(data,) | 類似np.array的構造函數 | | ones(\*sizes) | 全1Tensor | | zeros(\*sizes) | 全0Tensor | | eye(\*sizes) | 對角線為1,其他為0 | | arange(s,e,step | 從s到e,步長為step | | linspace(s,e,steps) | 從s到e,均勻切分成steps份 | | rand/randn(\*sizes) | 均勻/標準分布 | | normal(mean,std)/uniform(from,to) | 正態分布/均勻分布 | | randperm(m) | 隨機排列 | 這些創建方法都可以在創建的時候指定數據類型dtype和存放device(cpu/gpu)。 ## 2.2.2 操作 本小節介紹`Tensor`的各種操作。 ### 算術操作 在PyTorch中,同一種操作可能有很多種形式,下面用加法作為例子。 * **加法形式一** ~~~ y = torch.rand(5, 3) print(x + y) ~~~ * **加法形式二** ~~~ print(torch.add(x, y)) ~~~ 還可指定輸出: ~~~ result = torch.empty(5, 3) torch.add(x, y, out=result) print(result) ~~~ * **加法形式三、inplace** ~~~ # adds x to y y.add_(x) print(y) ~~~ > **注:PyTorch操作inplace版本都有后綴"\_", 例如`x.copy_(y), x.t_()`** 以上幾種形式的輸出均為: ~~~ tensor([[ 1.3967, 1.0892, 0.4369], [ 1.6995, 2.0453, 0.6539], [-0.1553, 3.7016, -0.3599], [ 0.7536, 0.0870, 1.2274], [ 2.5046, -0.1913, 0.4760]]) ~~~ ### 索引 我們還可以使用類似NumPy的索引操作來訪問`Tensor`的一部分,需要注意的是:**索引出來的結果與原數據共享內存,也即修改一個,另一個會跟著修改。** ~~~ y = x[0, :] y += 1 print(y) print(x[0, :]) # 源tensor也被改了 ~~~ 輸出: ~~~ tensor([1.6035, 1.8110, 0.9549]) tensor([1.6035, 1.8110, 0.9549]) ~~~ 除了常用的索引選擇數據之外,PyTorch還提供了一些高級的選擇函數: | 函數 | 功能 | | --- | --- | | index\_select(input, dim, index) | 在指定維度dim上選取,比如選取某些行、某些列 | | masked\_select(input, mask) | 例子如上,a\[a>0\],使用ByteTensor進行選取 | | non\_zero(input) | 非0元素的下標 | | gather(input, dim, index) | 根據index,在dim維度上選取數據,輸出的size與index一樣 | 這里不詳細介紹,用到了再查官方文檔。 ### 改變形狀 用`view()`來改變`Tensor`的形狀: ~~~ y = x.view(15) z = x.view(-1, 5) # -1所指的維度可以根據其他維度的值推出來 print(x.size(), y.size(), z.size()) ~~~ 輸出: ~~~ torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5]) ~~~ **注意`view()`返回的新tensor與源tensor共享內存(其實是同一個tensor),也即更改其中的一個,另外一個也會跟著改變。(顧名思義,view僅僅是改變了對這個張量的觀察角度)** ~~~ x += 1 print(x) print(y) # 也加了1 ~~~ 輸出: ~~~ tensor([[1.6035, 1.8110, 0.9549], [1.8797, 2.0482, 0.9555], [0.2771, 3.8663, 0.4345], [1.1604, 0.9746, 2.0739], [3.2628, 0.0825, 0.7749]]) tensor([1.6035, 1.8110, 0.9549, 1.8797, 2.0482, 0.9555, 0.2771, 3.8663, 0.4345, 1.1604, 0.9746, 2.0739, 3.2628, 0.0825, 0.7749]) ~~~ 所以如果我們想返回一個真正新的副本(即不共享內存)該怎么辦呢?Pytorch還提供了一個`reshape()`可以改變形狀,但是此函數并不能保證返回的是其拷貝,所以不推薦使用。推薦先用`clone`創造一個副本然后再使用`view`。[參考此處](https://stackoverflow.com/questions/49643225/whats-the-difference-between-reshape-and-view-in-pytorch) ~~~ x_cp = x.clone().view(15) x -= 1 print(x) print(x_cp) ~~~ 輸出: ~~~ tensor([[ 0.6035, 0.8110, -0.0451], [ 0.8797, 1.0482, -0.0445], [-0.7229, 2.8663, -0.5655], [ 0.1604, -0.0254, 1.0739], [ 2.2628, -0.9175, -0.2251]]) tensor([1.6035, 1.8110, 0.9549, 1.8797, 2.0482, 0.9555, 0.2771, 3.8663, 0.4345, 1.1604, 0.9746, 2.0739, 3.2628, 0.0825, 0.7749]) ~~~ > 使用`clone`還有一個好處是會被記錄在計算圖中,即梯度回傳到副本時也會傳到源`Tensor`。 另外一個常用的函數就是`item()`, 它可以將一個標量`Tensor`轉換成一個Python number: ~~~ x = torch.randn(1) print(x) print(x.item()) ~~~ 輸出: ~~~ tensor([2.3466]) 2.3466382026672363 ~~~ ### 線性代數 另外,PyTorch還支持一些線性函數,這里提一下,免得用起來的時候自己造輪子,具體用法參考官方文檔。如下表所示: | 函數 | 功能 | | --- | --- | | trace | 對角線元素之和(矩陣的跡) | | diag | 對角線元素 | | triu/tril | 矩陣的上三角/下三角,可指定偏移量 | | mm/bmm | 矩陣乘法,batch的矩陣乘法 | | addmm/addbmm/addmv/addr/badbmm.. | 矩陣運算 | | t | 轉置 | | dot/cross | 內積/外積 | | inverse | 求逆矩陣 | | svd | 奇異值分解 | PyTorch中的`Tensor`支持超過一百種操作,包括轉置、索引、切片、數學運算、線性代數、隨機數等等,可參考[官方文檔](https://pytorch.org/docs/stable/tensors.html)。 ## 2.2.3 廣播機制 前面我們看到如何對兩個形狀相同的`Tensor`做按元素運算。當對兩個形狀不同的`Tensor`按元素運算時,可能會觸發廣播(broadcasting)機制:先適當復制元素使這兩個`Tensor`形狀相同后再按元素運算。例如: ~~~ x = torch.arange(1, 3).view(1, 2) print(x) y = torch.arange(1, 4).view(3, 1) print(y) print(x + y) ~~~ 輸出: ~~~ tensor([[1, 2]]) tensor([[1], [2], [3]]) tensor([[2, 3], [3, 4], [4, 5]]) ~~~ 由于`x`和`y`分別是1行2列和3行1列的矩陣,如果要計算`x + y`,那么`x`中第一行的2個元素被廣播(復制)到了第二行和第三行,而`y`中第一列的3個元素被廣播(復制)到了第二列。如此,就可以對2個3行2列的矩陣按元素相加。 ## 2.2.4 運算的內存開銷 前面說了,索引、`view`是不會開辟新內存的,而像`y = x + y`這樣的運算是會新開內存的,然后將`y`指向新內存。為了演示這一點,我們可以使用Python自帶的`id`函數:如果兩個實例的ID一致,那么它們所對應的內存地址相同;反之則不同。 ~~~ x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) y = y + x print(id(y) == id_before) # False ~~~ 如果想指定結果到原來的`y`的內存,我們可以使用前面介紹的索引來進行替換操作。在下面的例子中,我們把`x + y`的結果通過`[:]`寫進`y`對應的內存中。 ~~~ x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) y[:] = y + x print(id(y) == id_before) # True ~~~ 我們還可以使用運算符全名函數中的`out`參數或者自加運算符`+=`(也即`add_()`)達到上述效果,例如`torch.add(x, y, out=y)`和`y += x`(`y.add_(x)`)。 ~~~ x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) torch.add(x, y, out=y) # y += x, y.add_(x) print(id(y) == id_before) # True ~~~ ## 2.2.5 `Tensor`和NumPy相互轉換 我們很容易用`numpy()`和`from_numpy()`將`Tensor`和NumPy中的數組相互轉換。但是需要注意的一點是: **這兩個函數所產生的的`Tensor`和NumPy中的數組共享相同的內存(所以他們之間的轉換很快),改變其中一個時另一個也會改變!!!** > 還有一個常用的將NumPy中的array轉換成`Tensor`的方法就是`torch.tensor()`, 需要注意的是,此方法總是會進行數據拷貝(就會消耗更多的時間和空間),所以返回的`Tensor`和原來的數據不再共享內存。 ### `Tensor`轉NumPy 使用`numpy()`將`Tensor`轉換成NumPy數組: ~~~ a = torch.ones(5) b = a.numpy() print(a, b) a += 1 print(a, b) b += 1 print(a, b) ~~~ 輸出: ~~~ tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.] tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.] tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.] ~~~ ### NumPy數組轉`Tensor` 使用`from_numpy()`將NumPy數組轉換成`Tensor`: ~~~ import numpy as np a = np.ones(5) b = torch.from_numpy(a) print(a, b) a += 1 print(a, b) b += 1 print(a, b) ~~~ 輸出: ~~~ [1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64) [2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64) [3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64) ~~~ 所有在CPU上的`Tensor`(除了`CharTensor`)都支持與NumPy數組相互轉換。 此外上面提到還有一個常用的方法就是直接用`torch.tensor()`將NumPy數組轉換成`Tensor`,需要注意的是該方法總是會進行數據拷貝,返回的`Tensor`和原來的數據不再共享內存。 ~~~ c = torch.tensor(a) a += 1 print(a, c) ~~~ 輸出 ~~~ [4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64) ~~~ ## 2.2.6 `Tensor` on GPU 用方法`to()`可以將`Tensor`在CPU和GPU(需要硬件支持)之間相互移動。 ~~~ # 以下代碼只有在PyTorch GPU版本上才會執行 if torch.cuda.is_available(): device = torch.device("cuda") # GPU y = torch.ones_like(x, device=device) # 直接創建一個在GPU上的Tensor x = x.to(device) # 等價于 .to("cuda") z = x + y print(z) print(z.to("cpu", torch.double)) # to()還可以同時更改數據類型 ~~~ * * * > 注: 本文主要參考[PyTorch官方文檔](https://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html#sphx-glr-beginner-blitz-tensor-tutorial-py)和[此處](https://github.com/chenyuntc/pytorch-book/blob/master/chapter3-Tensor%E5%92%8Cautograd/Tensor.ipynb),與[原書同一節](https://zh.d2l.ai/chapter_prerequisite/ndarray.html)有很大不同。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看