最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PyTorch中view()與?reshape()的區(qū)別詳析

 更新時間:2022年01月28日 09:36:09   作者:你卷我不卷  
這篇文章主要給大家介紹了關于PyTorch中view()?與?reshape()?區(qū)別的相關資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

前言

總之,兩者都是用來重塑tensor的shape的。view只適合對滿足連續(xù)性條件(contiguous)的tensor進行操作,而reshape同時還可以對不滿足連續(xù)性條件的tensor進行操作,具有更好的魯棒性。view能干的reshape都能干,如果view不能干就可以用reshape來處理。別看目錄挺多,但內容很細呀~其實原理并不難啦~我們開始吧~

一、PyTorch中tensor的存儲方式

想要深入理解view與reshape的區(qū)別,首先要理解一些有關PyTorch張量存儲的底層原理,比如tensor的頭信息區(qū)(Tensor)和存儲區(qū) (Storage)以及tensor的步長Stride。不用慌,這部分的原理其實很簡單的(^-^)!

1、PyTorch張量存儲的底層原理

tensor數據采用頭信息區(qū)(Tensor)和存儲區(qū) (Storage)分開存儲的形式,如圖1所示。變量名以及其存儲的數據是分為兩個區(qū)域分別存儲的。比如,我們定義并初始化一個tensor,tensor名為A,A的形狀size、步長stride、數據的索引等信息都存儲在頭信息區(qū),而A所存儲的真實數據則存儲在存儲區(qū)。另外,如果我們對A進行截取、轉置或修改等操作后賦值給B,則B的數據共享A的存儲區(qū),存儲區(qū)的數據數量沒變,變化的只是B的頭信息區(qū)對數據的索引方式。如果聽說過淺拷貝和深拷貝的話,很容易明白這種方式其實就是淺拷貝。

圖1 Torch中Tensor的存儲結構

舉個例子:

import torch
a = torch.arange(5)  # 初始化張量 a 為 [0, 1, 2, 3, 4]
b = a[2:]            # 截取張量a的部分值并賦值給b,b其實只是改變了a對數據的索引方式
print('a:', a)
print('b:', b)
print('ptr of storage of a:', a.storage().data_ptr())  # 打印a的存儲區(qū)地址
print('ptr of storage of b:', b.storage().data_ptr())  # 打印b的存儲區(qū)地址,可以發(fā)現兩者是共用存儲區(qū)
 
print('==================================================================')
 
b[1] = 0    # 修改b中索引為1,即a中索引為3的數據為0
print('a:', a)
print('b:', b)
print('ptr of storage of a:', a.storage().data_ptr())  # 打印a的存儲區(qū)地址,可以發(fā)現a的相應位置的值也跟著改變,說明兩者是共用存儲區(qū)
print('ptr of storage of b:', b.storage().data_ptr())  # 打印b的存儲區(qū)地址
 
 
'''   運行結果   '''
a: tensor([0, 1, 2, 3, 4])
b: tensor([2, 3, 4])
ptr of storage of a: 2862826251264
ptr of storage of b: 2862826251264
==================================================================
a: tensor([0, 1, 2, 0, 4])
b: tensor([2, 0, 4])
ptr of storage of a: 2862826251264
ptr of storage of b: 2862826251264

2、PyTorch張量的步長(stride)屬性

torch的tensor也是有步長屬性的,說起stride屬性是不是很耳熟?是的,卷積神經網絡中卷積核對特征圖的卷積操作也是有stride屬性的,但這兩個stride可完全不是一個意思哦。tensor的步長可以理解為從索引中的一個維度跨到下一個維度中間的跨度。為方便理解,就直接用圖1說明了,您細細品(^-^):

圖2 對張量的stride屬性的理解

舉個例子:

import torch
a = torch.arange(6).reshape(2, 3)  # 初始化張量 a
b = torch.arange(6).view(3, 2)     # 初始化張量 b
print('a:', a)
print('stride of a:', a.stride())  # 打印a的stride
print('b:', b)
print('stride of b:', b.stride())  # 打印b的stride
 
'''   運行結果   '''
a: tensor([[0, 1, 2],
           [3, 4, 5]])
stride of a: (3, 1)
 
b: tensor([[0, 1],
           [2, 3],
           [4, 5]])
stride of b: (2, 1)

二、對“視圖(view)”字眼的理解

視圖是數據的一個別稱或引用,通過該別稱或引用亦便可訪問、操作原有數據,但原有數據不會產生拷貝。如果我們對視圖進行修改,它會影響到原始數據,物理內存在同一位置,這樣避免了重新創(chuàng)建張量的高內存開銷。由上面介紹的PyTorch的張量存儲方式可以理解為:對張量的大部分操作就是視圖操作!

與之對應的概念就是副本。副本是一個數據的完整的拷貝,如果我們對副本進行修改,它不會影響到原始數據,物理內存不在同一位置。

有關視圖與副本,在NumPy中也有著重要的應用??蓞⒖?a target="_blank">這里。

三、view() 和reshape() 的比較

1、對 torch.Tensor.view() 的理解

定義:

view(*shape) → Tensor

作用:類似于reshape,將tensor轉換為指定的shape,原始的data不改變。返回的tensor與原始的tensor共享存儲區(qū)。返回的tensor的size和stride必須與原始的tensor兼容。每個新的tensor的維度必須是原始維度的子空間,或滿足以下連續(xù)條件:

式1 張量連續(xù)性條件

否則需要先使用contiguous()方法將原始tensor轉換為滿足連續(xù)條件的tensor,然后就可以使用view方法進行shape變換了?;蛘咧苯邮褂胷eshape方法進行維度變換,但這種方法變換后的tensor就不是與原始tensor共享內存了,而是被重新開辟了一個空間。

如何理解tensor是否滿足連續(xù)條件吶?下面通過一系列例子來慢慢理解下:

首先,我們初始化一個張量 a ,并查看其stride、storage等屬性:

import torch
a = torch.arange(9).reshape(3, 3)  # 初始化張量a
print('struct of a:\n', a)
print('size   of a:', a.size())    # 查看a的shape
print('stride of a:', a.stride())  # 查看a的stride
 
'''   運行結果   '''
struct of a:
tensor([[0, 1, 2],
        [3, 4, 5],
        [6, 7, 8]])
size   of a: torch.Size([3, 3])
stride of a: (3, 1)   # 注:滿足連續(xù)性條件

把上面的結果帶入式1,可以發(fā)現滿足tensor連續(xù)性條件。

我們再看進一步處理——對a進行轉置后的結果:

import torch
a = torch.arange(9).reshape(3, 3)     # 初始化張量a
b = a.permute(1, 0)  # 對a進行轉置
print('struct of b:\n', b)
print('size   of b:', b.size())    # 查看b的shape
print('stride of b:', b.stride())  # 查看b的stride
 
'''   運行結果   '''
struct of b:
tensor([[0, 3, 6],
        [1, 4, 7],
        [2, 5, 8]])
size   of b: torch.Size([3, 3])
stride of b: (1, 3)   # 注:此時不滿足連續(xù)性條件

 將a轉置后再看最后的輸出結果,帶入到式1中,是不是發(fā)現等式不成立了?所以此時就不滿足tensor連續(xù)的條件了。這是為什么那?我們接著往下看:

首先,輸出a和b的存儲區(qū)來看一下有沒有什么不同:

import torch
a = torch.arange(9).reshape(3, 3)             # 初始化張量a
print('ptr of storage of a: ', a.storage().data_ptr())  # 查看a的storage區(qū)的地址
print('storage of a: \n', a.storage())        # 查看a的storage區(qū)的數據存放形式
b = a.permute(1, 0)                           # 轉置
print('ptr of storage of b: ', b.storage().data_ptr())  # 查看b的storage區(qū)的地址
print('storage of b: \n', b.storage())        # 查看b的storage區(qū)的數據存放形式
 
'''   運行結果   '''
ptr of storage of a:  2767173747136
storage of a: 
  0
 1
 2
 3
 4
 5
 6
 7
 8
[torch.LongStorage of size 9]
ptr of storage of b:  2767173747136
storage of b:
  0
 1
 2
 3
 4
 5
 6
 7
 8
[torch.LongStorage of size 9]

 由結果可以看出,張量a、b仍然共用存儲區(qū),并且存儲區(qū)數據存放的順序沒有變化,這也充分說明了b與a共用存儲區(qū),b只是改變了數據的索引方式。那么為什么b就不符合連續(xù)性條件了吶(T-T)?其實原因很簡單,我們結合圖3來解釋下:

圖3 對張量連續(xù)性條件的理解

轉置后的tensor只是對storage區(qū)數據索引方式的重映射,但原始的存放方式并沒有變化.因此,這時再看tensor b的stride,從b第一行的元素1到第二行的元素2,顯然在索引方式上已經不是原來+1了,而是變成了新的+3了,你在仔細琢磨琢磨是不是這樣的(^-^)。所以這時候就不能用view來對b進行shape的改變了,不然就報錯咯,不信你看下面;

import torch
a = torch.arange(9).reshape(3, 3)             # 初始化張量a
print(a.view(9))
print('============================================')
b = a.permute(1, 0)  # 轉置
print(b.view(9))
 
'''   運行結果   '''
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
============================================
Traceback (most recent call last):
  File "此處打碼", line 23, in <module>
    print(b.view(9))
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.

但是嘛,上有政策下有對策,這種情況下,直接用view不行,那我就先用contiguous()方法將原始tensor轉換為滿足連續(xù)條件的tensor,在使用view進行shape變換,值得注意的是,這樣的原理是contiguous()方法開辟了一個新的存儲區(qū)給b,并改變了b原始存儲區(qū)數據的存放順序!同樣的例子:

import torch
a = torch.arange(9).reshape(3, 3)      # 初始化張量a
print('storage of a:\n', a.storage())  # 查看a的stride
print('+++++++++++++++++++++++++++++++++++++++++++++++++')
b = a.permute(1, 0).contiguous()       # 轉置,并轉換為符合連續(xù)性條件的tensor
print('size    of b:', b.size())       # 查看b的shape
print('stride  of b:', b.stride())     # 查看b的stride
print('viewd      b:\n', b.view(9))    # 對b進行view操作,并打印結果
print('+++++++++++++++++++++++++++++++++++++++++++++++++')
print('storage of a:\n', a.storage())  # 查看a的存儲空間
print('storage of b:\n', b.storage())  # 查看b的存儲空間
print('+++++++++++++++++++++++++++++++++++++++++++++++++')
print('ptr of a:\n', a.storage().data_ptr())  # 查看a的存儲空間地址
print('ptr of b:\n', b.storage().data_ptr())  # 查看b的存儲空間地址
 
'''   運行結果   '''
storage of a:
  0
 1
 2
 3
 4
 5
 6
 7
 8
[torch.LongStorage of size 9]
+++++++++++++++++++++++++++++++++++++++++++++++++
size    of b: torch.Size([3, 3])
stride  of b: (3, 1)
viewd      b:
 tensor([0, 3, 6, 1, 4, 7, 2, 5, 8])
+++++++++++++++++++++++++++++++++++++++++++++++++
storage of a:
 0
 1
 2
 3
 4
 5
 6
 7
 8
[torch.LongStorage of size 9]
storage of b:
 0
 3
 6
 1
 4
 7
 2
 5
 8
[torch.LongStorage of size 9]
+++++++++++++++++++++++++++++++++++++++++++++++++
ptr of a:
 1842671472000
ptr of b:
 1842671472128

由上述結果可以看出,張量a與b已經是兩個存在于不同存儲區(qū)的張量了。也印證了contiguous()方法開辟了一個新的存儲區(qū)給b,并改變了b原始存儲區(qū)數據的存放順序。對應文章開頭提到的淺拷貝,這種開辟一個新的內存區(qū)的方式其實就是深拷貝。

2、對 torch.reshape() 的理解

定義:

torch.reshape(input, shape) → Tensor

作用:與view方法類似,將輸入tensor轉換為新的shape格式。

但是reshape方法更強大,可以認為a.reshape = a.view() + a.contiguous().view()。

即:在滿足tensor連續(xù)性條件時,a.reshape返回的結果與a.view()相同,否則返回的結果與a.contiguous().view()相同。

不信你就看人家官方的解釋嘛,您在細細品:

關于兩者區(qū)別,還可以參考這個鏈接:

What's the difference between reshape and view in pytorch? - Stack Overflow

2021.03.30更新:最近又發(fā)現了pytorch官網對view及reshape原理的闡述,說的很清晰明了,大家可以參考下:

Tensor Views — PyTorch 1.9.0 documentation

放一張該網站上的截圖:

四、總結

torch的view()與reshape()方法都可以用來重塑tensor的shape,區(qū)別就是使用的條件不一樣。view()方法只適用于滿足連續(xù)性條件的tensor,并且該操作不會開辟新的內存空間,只是產生了對原存儲空間的一個新別稱和引用,返回值是視圖。而reshape()方法的返回值既可以是視圖,也可以是副本,當滿足連續(xù)性條件時返回view,否則返回副本[ 此時等價于先調用contiguous()方法在使用view() ]。因此當不確能否使用view時,可以使用reshape。如果只是想簡單地重塑一個tensor的shape,那么就是用reshape,但是如果需要考慮內存的開銷而且要確保重塑后的tensor與之前的tensor共享存儲空間,那就使用view()。

2020.10.23

以上是我個人看了官網的的解釋并實驗得到的結論,所以有沒有dalao知道為啥沒把view廢除那?是不是還有我不知道的地方

2020.11.14

為什么沒把view廢除那?最近偶然看到了些資料,又想起了這個問題,覺得有以下原因:

1、在PyTorch不同版本的更新過程中,view先于reshape方法出現,后來出現了魯棒性更好的reshape方法,但view方法并沒因此廢除。其實不止PyTorch,其他一些框架或語言比如OpenCV也有類似的操作。

2、view的存在可以顯示地表示對這個tensor的操作只能是視圖操作而非拷貝操作。這對于代碼的可讀性以及后續(xù)可能的bug的查找比較友好。

總之,我們沒必要糾結為啥a能干的b也能干,b還能做a不能干的,a存在還有啥意義的問題。就相當于馬云能日賺1個億而我不能,那我存在的意義是啥。。。存在不就是意義嗎?存在即合理,最重要的是我們使用不同的方法可以不同程度上提升效率,何樂而不為?

 到此這篇關于PyTorch中view() 與 reshape()區(qū)別的文章就介紹到這了,更多相關PyTorch view() 與 reshape() 區(qū)別內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解析Anaconda創(chuàng)建python虛擬環(huán)境的問題

    解析Anaconda創(chuàng)建python虛擬環(huán)境的問題

    這篇文章主要介紹了Anaconda創(chuàng)建python虛擬環(huán)境,包括虛擬環(huán)境管理、虛擬環(huán)境中python包管理,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • YOLOv5車牌識別實戰(zhàn)教程(一)引言與準備工作

    YOLOv5車牌識別實戰(zhàn)教程(一)引言與準備工作

    這篇文章主要介紹了YOLOv5車牌識別實戰(zhàn)教程(一)引言與準備工作,在這個教程中,我們將一步步教你如何使用YOLOv5進行車牌識別,幫助你快速掌握YOLOv5車牌識別技能,需要的朋友可以參考下
    2023-04-04
  • Flask常見應用部署方案詳解

    Flask常見應用部署方案詳解

    這篇文章主要介紹了Flask常見應用部署方案詳解的相關資料,需要的朋友可以參考下
    2026-02-02
  • Django 實現將圖片轉為Base64,然后使用json傳輸

    Django 實現將圖片轉為Base64,然后使用json傳輸

    這篇文章主要介紹了Django 實現將圖片轉為Base64,然后使用json傳輸,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Python cookbook(數據結構與算法)從任意長度的可迭代對象中分解元素操作示例

    Python cookbook(數據結構與算法)從任意長度的可迭代對象中分解元素操作示例

    這篇文章主要介紹了Python 數據結構與算法 從任意長度的可迭代象中分解元素操作,結合實例形式分析了Python使用*表達式針對可迭代對象的分解操作相關實現技巧,需要的朋友可以參考下
    2018-02-02
  • Python PyTorch 如何獲取 MNIST 數據

    Python PyTorch 如何獲取 MNIST 數據

    這篇文章主要介紹了Python PyTorch 如何獲取 MNIST 數據,通過示例代碼介紹了PyTorch 保存 MNIST 數據,PyTorch 顯示 MNIST 數據的操作方法,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • python常用的正則表達式大全

    python常用的正則表達式大全

    正則表達式是一個特殊的字符序列,它能幫助你方便的檢查一個字符串是否與某種模式匹配,下面這篇文章主要給大家介紹了關于python常用正則表達式的相關資料,文中通過圖文以及實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • pytorch通過訓練結果的復現設置隨機種子

    pytorch通過訓練結果的復現設置隨機種子

    這篇文章主要介紹了pytorch通過訓練結果的復現設置隨機種子的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • python解析Chrome瀏覽器歷史瀏覽記錄和收藏夾數據

    python解析Chrome瀏覽器歷史瀏覽記錄和收藏夾數據

    大家好,本篇文章主要講的是python解析Chrome瀏覽器歷史瀏覽記錄和收藏夾數據,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • Python?sentence-transformers庫示例詳解

    Python?sentence-transformers庫示例詳解

    Sentence?Transformer是一個Python框架,用于句子、文本和圖像嵌入Embedding,它基于Transformer架構的預訓練模型,并在大量語義相似性數據上進行了微調,能夠捕捉句子之間的深層語義關系,本文給大家介紹Python?sentence-transformers庫的相關知識,感興趣的朋友一起看看吧
    2025-08-08

最新評論

凤山市| 新昌县| 潜江市| 天柱县| 青州市| 固原市| 通山县| 郓城县| 岳普湖县| 五峰| 徐州市| 三台县| 达日县| 钟祥市| 尼玛县| 安新县| 合肥市| 临澧县| 疏附县| 宽城| 丽江市| 台南市| 翁牛特旗| 武夷山市| 会昌县| 张北县| 宁南县| 丹巴县| 资溪县| 宕昌县| 两当县| 灌云县| 新河县| 平乡县| 沁阳市| 资溪县| 泸西县| 平果县| 沽源县| 应城市| 思茅市|