佳木斯湛栽影视文化发展公司

主頁 > 知識(shí)庫 > 解決pytorch下只打印tensor的數(shù)值不打印出device等信息的問題

解決pytorch下只打印tensor的數(shù)值不打印出device等信息的問題

熱門標(biāo)簽:客戶服務(wù) 電話運(yùn)營中心 語音系統(tǒng) 百度AI接口 硅谷的囚徒呼叫中心 Win7旗艦版 呼叫中心市場需求 企業(yè)做大做強(qiáng)

torch.Tensor類型的數(shù)據(jù)loss和acc打印時(shí)

如果寫成以下寫法

print('batch_loss: '+str(loss.data)+'batch acc: '+str(acc.data))

則不僅會(huì)打印出loss和acc的值,還會(huì)打印出device信息和 tensor字樣,如下:

如果僅想打印出數(shù)值,使得打印出的信息更加簡潔

則要用以下寫法

print('batch_loss: {:.3f} batch acc: {:.3f}'.format(loss.data, acc.data))

該寫法還可控制輸出格式,結(jié)果類似如下:

補(bǔ)充:關(guān)于pytorch中用plt顯示tensor的問題(tensor轉(zhuǎn)numpy)

問題

圖像的張量結(jié)構(gòu)為(C,H,W),而plt可以顯示的圖片格式要求(H,W,C),C為顏色通道數(shù),可以沒有。

所以問題就是將Tensor(C,H,W)=> numpy(H,W,C)

解決辦法

def transimg(img):
    img = img / 2 + 0.5 # unnormalize
    npimg = img.numpy()
    npimg1 = np.transpose(npimg,(1,2,0)) # C*H*W => H*W*C
    return npimg1

補(bǔ)充:PyTorch代碼調(diào)試?yán)? 自動(dòng)print每行代碼的Tensor信息

本文介紹一個(gè)用于 PyTorch 代碼的實(shí)用工具 TorchSnooper。作者是TorchSnooper的作者,也是PyTorch開發(fā)者之一。

GitHub 項(xiàng)目地址: https://github.com/zasdfgbnm/TorchSnooper

大家可能遇到這樣子的困擾:比如說運(yùn)行自己編寫的 PyTorch 代碼的時(shí)候,PyTorch 提示你說數(shù)據(jù)類型不匹配,需要一個(gè) double 的 tensor 但是你給的卻是 float;再或者就是需要一個(gè) CUDA tensor, 你給的卻是個(gè) CPU tensor。

比如下面這種:

RuntimeError: Expected object of scalar type Double but got scalar type Float

這種問題調(diào)試起來很麻煩,因?yàn)槟悴恢缽哪睦镩_始出問題的。比如你可能在代碼的第三行用 torch.zeros 新建了一個(gè) CPU tensor, 然后這個(gè) tensor 進(jìn)行了若干運(yùn)算,全是在 CPU 上進(jìn)行的,一直沒有報(bào)錯(cuò),直到第十行需要跟你作為輸入傳進(jìn)來的 CUDA tensor 進(jìn)行運(yùn)算的時(shí)候,才報(bào)錯(cuò)。要調(diào)試這種錯(cuò)誤,有時(shí)候就不得不一行行地手寫 print 語句,非常麻煩。

再或者,你可能腦子里想象著將一個(gè) tensor 進(jìn)行什么樣子的操作,就會(huì)得到什么樣子的結(jié)果,但是 PyTorch 中途報(bào)錯(cuò)說 tensor 的形狀不匹配,或者壓根沒報(bào)錯(cuò)但是最終出來的形狀不是我們想要的。這個(gè)時(shí)候,我們往往也不知道是什么地方開始跟我們「預(yù)期的發(fā)生偏離的」。我們有時(shí)候也得需要插入一大堆 print 語句才能找到原因。

TorchSnooper 就是一個(gè)設(shè)計(jì)了用來解決這個(gè)問題的工具。TorchSnooper 的安裝非常簡單,只需要執(zhí)行標(biāo)準(zhǔn)的 Python 包安裝指令就好:

pip install torchsnooper

安裝完了以后,只需要用 @torchsnooper.snoop() 裝飾一下要調(diào)試的函數(shù),這個(gè)函數(shù)在執(zhí)行的時(shí)候,就會(huì)自動(dòng) print 出來每一行的執(zhí)行結(jié)果的 tensor 的形狀、數(shù)據(jù)類型、設(shè)備、是否需要梯度的信息。

安裝完了以后,下面就用兩個(gè)例子來說明一下怎么使用。

例子1

比如說我們寫了一個(gè)非常簡單的函數(shù):

def myfunc(mask, x):
    y = torch.zeros(6)
    y.masked_scatter_(mask, x)
    return y

我們是這樣子使用這個(gè)函數(shù)的:

mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda')
source = torch.tensor([1.0, 2.0, 3.0], device='cuda')
y = myfunc(mask, source)

上面的代碼看起來似乎沒啥問題,然而實(shí)際上跑起來,卻報(bào)錯(cuò)了:

RuntimeError: Expected object of backend CPU but got backend CUDA for argument #2 'mask'

問題在哪里呢?讓我們 snoop 一下!用 @torchsnooper.snoop() 裝飾一下 myfunc 函數(shù):

import torch
import torchsnooper
@torchsnooper.snoop()
def myfunc(mask, x):
    y = torch.zeros(6)
    y.masked_scatter_(mask, x)
    return y

mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda')
source = torch.tensor([1.0, 2.0, 3.0], device='cuda')
y = myfunc(mask, source)

然后運(yùn)行我們的腳本,我們看到了這樣的輸出:

Starting var:.. mask = tensor(6,), int64, cuda:0>
Starting var:.. x = tensor(3,), float32, cuda:0>
21:41:42.941668 call 5 def myfunc(mask, x):
21:41:42.941834 line 6 y = torch.zeros(6)
New var:....... y = tensor(6,), float32, cpu>
21:41:42.943443 line 7 y.masked_scatter_(mask, x)
21:41:42.944404 exception 7 y.masked_scatter_(mask, x)

結(jié)合我們的錯(cuò)誤,我們主要去看輸出的每個(gè)變量的設(shè)備,找找最早從哪個(gè)變量開始是在 CPU 上的。我們注意到這一行:

New var:....... y = tensor(6,), float32, cpu>

這一行直接告訴我們,我們創(chuàng)建了一個(gè)新變量 y, 并把一個(gè) CPU tensor 賦值給了這個(gè)變量。這一行對(duì)應(yīng)代碼中的 y = torch.zeros(6)。于是我們意識(shí)到,在使用 torch.zeros 的時(shí)候,如果不人為指定設(shè)備的話,默認(rèn)創(chuàng)建的 tensor 是在 CPU 上的。我們把這一行改成 y = torch.zeros(6, device='cuda'),這一行的問題就修復(fù)了。

這一行的問題雖然修復(fù)了,我們的問題并沒有解決完整,再跑修改過的代碼還是報(bào)錯(cuò),但是這個(gè)時(shí)候錯(cuò)誤變成了:

RuntimeError: Expected object of scalar type Byte but got scalar type Long for argument #2 'mask'

好吧,這次錯(cuò)誤出在了數(shù)據(jù)類型上。這次錯(cuò)誤報(bào)告比較有提示性,我們大概能知道是我們的 mask 的數(shù)據(jù)類型錯(cuò)了。再看一遍 TorchSnooper 的輸出,我們注意到:

Starting var:.. mask = tensor(6,), int64, cuda:0>

果然,我們的 mask 的類型是 int64, 而不應(yīng)該是應(yīng)有的 uint8。我們把 mask 的定義修改好:

mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda', dtype=torch.uint8)

然后就可以運(yùn)行了。

例子 2

這次我們要構(gòu)建一個(gè)簡單的線性模型:

model = torch.nn.Linear(2, 1)

我們想要擬合一個(gè)平面 y = x1 + 2 * x2 + 3,于是我們創(chuàng)建了這樣一個(gè)數(shù)據(jù)集:

x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
y = torch.tensor([3.0, 5.0, 4.0, 6.0])

我們使用最普通的 SGD 優(yōu)化器來進(jìn)行優(yōu)化,完整的代碼如下:

import torch
model = torch.nn.Linear(2, 1)
x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
y = torch.tensor([3.0, 5.0, 4.0, 6.0])

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
for _ in range(10):
    optimizer.zero_grad()
    pred = model(x)
    squared_diff = (y - pred) ** 2
    loss = squared_diff.mean()
    print(loss.item())
    loss.backward()
    optimizer.step()

然而運(yùn)行的過程我們發(fā)現(xiàn),loss 降到 1.5 左右就不再降了。這是很不正常的,因?yàn)槲覀儤?gòu)建的數(shù)據(jù)都是無誤差落在要擬合的平面上的,loss 應(yīng)該降到 0 才算正常。

乍看上去,不知道問題在哪里。抱著試試看的想法,我們來 snoop 一下子。這個(gè)例子中,我們沒有自定義函數(shù),但是我們可以使用 with 語句來激活 TorchSnooper。把訓(xùn)練的那個(gè)循環(huán)裝進(jìn) with 語句中去,代碼就變成了:

import torch
import torchsnooper
model = torch.nn.Linear(2, 1)
x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
y = torch.tensor([3.0, 5.0, 4.0, 6.0])
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

with torchsnooper.snoop():
    for _ in range(10):
        optimizer.zero_grad()
        pred = model(x)
        squared_diff = (y - pred) ** 2
        loss = squared_diff.mean()
        print(loss.item())
        loss.backward()
        optimizer.step()

運(yùn)行程序,我們看到了一長串的輸出,一點(diǎn)一點(diǎn)瀏覽,我們注意到

New var:....... model = Linear(in_features=2, out_features=1, bias=True)
New var:....... x = tensor(4, 2), float32, cpu>
New var:....... y = tensor(4,), float32, cpu>
New var:....... optimizer = SGD (Parameter Group 0 dampening: 0 lr: 0....omentum: 0 nesterov: False weight_decay: 0)
02:38:02.016826 line 12 for _ in range(10):
New var:....... _ = 0
02:38:02.017025 line 13 optimizer.zero_grad()
02:38:02.017156 line 14 pred = model(x)
New var:....... pred = tensor(4, 1), float32, cpu, grad>
02:38:02.018100 line 15 squared_diff = (y - pred) ** 2
New var:....... squared_diff = tensor(4, 4), float32, cpu, grad>
02:38:02.018397 line 16 loss = squared_diff.mean()
New var:....... loss = tensor(), float32, cpu, grad>
02:38:02.018674 line 17 print(loss.item())
02:38:02.018852 line 18 loss.backward()
26.979290008544922
02:38:02.057349 line 19 optimizer.step()

仔細(xì)觀察這里面各個(gè) tensor 的形狀,我們不難發(fā)現(xiàn),y 的形狀是 (4,),而 pred 的形狀卻是 (4, 1),他們倆相減,由于廣播的存在,我們得到的 squared_diff 的形狀就變成了 (4, 4)。

這自然不是我們想要的結(jié)果。這個(gè)問題修復(fù)起來也很簡單,把 pred 的定義改成 pred = model(x).squeeze() 即可?,F(xiàn)在再看修改后的代碼的 TorchSnooper 的輸出:

New var:....... model = Linear(in_features=2, out_features=1, bias=True)
New var:....... x = tensor(4, 2), float32, cpu>
New var:....... y = tensor(4,), float32, cpu>
New var:....... optimizer = SGD (Parameter Group 0 dampening: 0 lr: 0....omentum: 0 nesterov: False weight_decay: 0)
02:46:23.545042 line 12 for _ in range(10):
New var:....... _ = 0
02:46:23.545285 line 13 optimizer.zero_grad()
02:46:23.545421 line 14 pred = model(x).squeeze()
New var:....... pred = tensor(4,), float32, cpu, grad>
02:46:23.546362 line 15 squared_diff = (y - pred) ** 2
New var:....... squared_diff = tensor(4,), float32, cpu, grad>
02:46:23.546645 line 16 loss = squared_diff.mean()
New var:....... loss = tensor(), float32, cpu, grad>
02:46:23.546939 line 17 print(loss.item())
02:46:23.547133 line 18 loss.backward()
02:46:23.591090 line 19 optimizer.step()

現(xiàn)在這個(gè)結(jié)果看起來就正常了。并且經(jīng)過測試,loss 現(xiàn)在已經(jīng)可以降到很接近 0 了。大功告成。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • Pytorch自定義Dataset和DataLoader去除不存在和空數(shù)據(jù)的操作
  • pytorch Dataset,DataLoader產(chǎn)生自定義的訓(xùn)練數(shù)據(jù)案例
  • PyTorch實(shí)現(xiàn)重寫/改寫Dataset并載入Dataloader
  • 一文弄懂Pytorch的DataLoader, DataSet, Sampler之間的關(guān)系
  • PyTorch 解決Dataset和Dataloader遇到的問題
  • PyTorch 如何自動(dòng)計(jì)算梯度
  • pytorch中F.avg_pool1d()和F.avg_pool2d()的使用操作
  • 我對(duì)PyTorch dataloader里的shuffle=True的理解
  • pytorch 帶batch的tensor類型圖像顯示操作
  • Pytorch 如何查看、釋放已關(guān)閉程序占用的GPU資源
  • pytorch中的squeeze函數(shù)、cat函數(shù)使用
  • Pytorch數(shù)據(jù)讀取之Dataset和DataLoader知識(shí)總結(jié)

標(biāo)簽:安康 海南 濟(jì)南 長沙 山西 喀什 山西 崇左

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《解決pytorch下只打印tensor的數(shù)值不打印出device等信息的問題》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    沁阳市| 汤原县| 重庆市| 兴仁县| 峨边| 澄迈县| 安阳县| 阳新县| 张家港市| 彰化市| 沭阳县| 翁源县| 台中市| 静安区| 英德市| 明星| 微博| 长乐市| 马尔康县| 花莲市| 察哈| 和政县| 巩留县| 二连浩特市| 登封市| 莱州市| 嘉祥县| 绍兴市| 磐石市| 万全县| 玛曲县| 云林县| 揭东县| 宿州市| 太白县| 法库县| 隆子县| 隆尧县| 阜宁县| 西昌市| 崇州市|