最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

[Quant 1.2] 一些Pytorch基礎(chǔ)

2022-06-08 04:27 作者:安平生一人好_  | 我要投稿

視頻鏈接:https://www.youtube.com/watch?v=c36lUUr864M

因?yàn)槲覜](méi)學(xué)過(guò)Pytorch,所以需要從基礎(chǔ)開(kāi)始了。

這一篇的示例要用三個(gè)package

import torch
import numpy as np
import matplotlib.pyplot as plt

1. 數(shù)據(jù)類(lèi)型tensor的建立

  • 建立不同維度的0-tensor

一維長(zhǎng)度為3的0-tensor

torch.empty(3)

#tensor([1.1210e-44, -0.0000e+00, 0.0000e+00])

二維?2%5Ctimes3%0A?的0-tensor

torch.empty(2,3)

# tensor([[9.8091e-45, 0.0000e+00, 0.0000e+00],
# ? ? ? ? [0.0000e+00, 0.0000e+00, 0.0000e+00]])

三維 2%5Ctimes%203%5Ctimes%204?的0-tensor

torch.empty(2,3,4)

#tensor([[[ 2.9147e-43, ?0.0000e+00, -1.1201e-19, ?4.5779e-41],
# ? ? ? ? ? [ 6.0009e+36, ?4.5779e-41, ?0.0000e+00, ?7.0065e-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],
# ? ? ? ? ? [ 0.0000e+00, ?0.0000e+00, ?0.0000e+00, ?0.0000e+00],
# ? ? ? ? ? [ 1.4013e-45, ?0.0000e+00, ?0.0000e+00, ?0.0000e+00]]])


  • 建立不同維度的1-tensor

二維?2%5Ctimes%202%0A 的1-tensor

torch.ones(2,2)

# tensor([[1., 1.],
# ? ? ? ? [1., 1.]])


  • 建立不同維度的隨機(jī)tensor

torch.rand(2,2)

# tensor([[0.2246, 0.5603],
# ? ? ? ? [0.5463, 0.8566]])
  • 建立不同維度的隨機(jī)整數(shù)tensor

建立一個(gè)三維?3%5Ctimes%203%20%5Ctimes%203 的隨機(jī)整數(shù)矩陣,元素的范圍是?%5B2%2C8)?區(qū)間內(nèi)的整數(shù)

x = torch.randint(2,8,(3,3,3))
x

# tensor([[[5, 3, 3],
# ? ? ? ? ?[5, 7, 7],
# ? ? ? ? ?[2, 3, 4]],

# ? ? ? ? [[5, 3, 7],
# ? ? ? ? ?[4, 6, 5],
# ? ? ? ? ?[3, 4, 5]],

# ? ? ? ? [[7, 5, 7],
# ? ? ? ? ?[3, 6, 2],
# ? ? ? ? ?[2, 7, 7]]])
  • 以list為argument建立tensor

利用list建立一個(gè)?2%20%5Ctimes%202%0A 的tensor

my_ten = torch.tensor([[2.5,0.1],[1,2]])

my_ten
# tensor([[2.5000, 0.1000],
# ? ? ? ? [1.0000, 2.0000]])

my_ten.size()
# ?torch.Size([2, 2])


  • 設(shè)定tensor中的數(shù)據(jù)類(lèi)型

建立一個(gè)二維?2%20%5Ctimes%202 的1-tensor,要求tensor里面的元素的類(lèi)型是浮點(diǎn)數(shù)float16

x = torch.ones(2,2,dtype=torch.float16)

# tensor([[1., 1.],
# ? ? ? ? [1., 1.]], dtype=torch.float16)
  • 設(shè)定tensor是否可以用來(lái)求梯度

建立一個(gè)二維?2%20%5Ctimes%203 的隨機(jī)tensor,要求tensor可以用來(lái)求梯度

torch.rand(2,3,requires_grad = True)

# tensor([[0.9961, 0.2444, 0.6532],
# ? ? ? ? [0.5307, 0.6206, 0.5152]], requires_grad=True)

在后面,我們會(huì)把tensor放入某種函數(shù)。這個(gè)函數(shù)的輸入是一個(gè)多維的tensor,輸出是一個(gè)scaler。如果這個(gè)多維tensor有requires_grad = True,那么我們就可以用backward()求函數(shù)在此多維tensor上的梯度;如果這個(gè)多維tensor有requires_grad = False,那么在使用backward()求梯度的時(shí)候,interpreter就會(huì)報(bào)錯(cuò)。


2. 數(shù)據(jù)類(lèi)型tensor的一些操作

  • Tensor的相加與相減

x = torch.rand(2,3)
y = torch.rand(2,3)
x, y
# (tensor([[0.5501, 0.8308, 0.2830],
# ? ? ? ? ?[0.4184, 0.3558, 0.0589]]),
# ?tensor([[0.3422, 0.9984, 0.7679],
# ? ? ? ? ?[0.2108, 0.6127, 0.6060]]))

x + y
# tensor([[0.8923, 1.8292, 1.0509],
# ? ? ? ? [0.6291, 0.9684, 0.6648]])

x.add(y)
# tensor([[0.8923, 1.8292, 1.0509],
# ? ? ? ? [0.6291, 0.9684, 0.6648]])

x, y 
# (tensor([[0.5501, 0.8308, 0.2830],
# ? ? ? ? ?[0.4184, 0.3558, 0.0589]]),
# ?tensor([[0.3422, 0.9984, 0.7679],
# ? ? ? ? ?[0.2108, 0.6127, 0.6060]]))

用 '+' 將tensor相加會(huì)創(chuàng)建新的tensor,原來(lái)的tensor不會(huì)改變。對(duì)應(yīng)的,我們知道 '-' 也有相似的作用。

這里面 '+' 和 '-' 可以用函數(shù) .add() 和 .sub() 來(lái)代替,用這兩個(gè)方法相加或者相減同樣創(chuàng)建新的tensor,并不會(huì)改變?cè)璽ensor x和y的值。

x = torch.randint(2,(2,3))
x
# tensor([[1, 0, 1],
# ? ? ? ? [0, 0, 1]])

x.add_(1)
# tensor([[2, 1, 2],
# ? ? ? ? [1, 1, 2]])

x.sub_(1)
# tensor([[1, 0, 1],
# ? ? ? ? [0, 0, 1]])

但是如果我們?cè)?.add()?和?.sub() 后面加了下劃線,那么 .add_()?和?.sub_() 就會(huì)改變其作用對(duì)象的值。在這個(gè)例子中,x的值被改變了兩次。?這種操作在pytorch中很常見(jiàn),很多method不加下劃線就會(huì)創(chuàng)建新的變量,而加下劃線的話就會(huì)在改變?cè)瓉?lái)的變量。


  • Tensor的切片slicing

x = torch.rand(5,3)
x
# tensor([[0.8021, 0.0619, 0.2424],
# ? ? ? ? [0.1589, 0.9536, 0.5429],
# ? ? ? ? [0.3194, 0.4105, 0.3977],
# ? ? ? ? [0.4445, 0.5245, 0.5164],
# ? ? ? ? [0.2404, 0.9453, 0.9572]])

x[1,:]
# tensor([0.1589, 0.9536, 0.5429])

tensor的切片和ndarray的切片方式一樣。在上面的例子中,我們要slice這個(gè)?5%5Ctimes%203?tensor的第一行


  • Tensor的變形reshape

x = torch.rand(5,3)
x
# tensor([[0.8021, 0.0619, 0.2424],
# ? ? ? ? [0.1589, 0.9536, 0.5429],
# ? ? ? ? [0.3194, 0.4105, 0.3977],
# ? ? ? ? [0.4445, 0.5245, 0.5164],
# ? ? ? ? [0.2404, 0.9453, 0.9572]])

y = x.view(15)
y
# tensor([0.8021, 0.0619, 0.2424, 0.1589, 0.9536, 0.5429, 0.3194, 0.4105, 0.3977,
# ? ? ? ? 0.4445, 0.5245, 0.5164, 0.2404, 0.9453, 0.9572])
 
y = x.view(-1,5)
y
# tensor([[0.8021, 0.0619, 0.2424, 0.1589, 0.9536],
# ? ? ? ? [0.5429, 0.3194, 0.4105, 0.3977, 0.4445],
# ? ? ? ? [0.5245, 0.5164, 0.2404, 0.9453, 0.9572]])

通過(guò) .view() 函數(shù),我們可以將tensor展成我們想要的size。

y = x.view(15) 是將剛剛的?5%5Ctimes%203?tensor展成 1%20%5Ctimes%2015

y = x.view(-1,5) 則是將?5%20%5Ctimes%203?tensor展成?%3F%20%5Ctimes%205,這個(gè)?在函數(shù)輸入中用-1代替,其具體數(shù)值會(huì)自行決定,例如這個(gè)statement就相當(dāng)于 y = x.view(3,5)


3. 數(shù)據(jù)類(lèi)型tensor的gradient

我們前面提到過(guò)了tensor里面可以?xún)?nèi)含一個(gè)叫requires_grad的argument。這個(gè)argument是bool類(lèi)型,它決定著是否可以對(duì)這個(gè)tensor求gradient。

例如我們可以在建立一個(gè)tensor變量的時(shí)候來(lái)決定它是否可以被求梯度

torch.randn(2,3,requires_grad=True)
# tensor([[ 2.1278, ?1.1417, ?0.6102],
# ? ? ? ? [-1.3501, ?0.5458, ?2.5938]], requires_grad=True)

建立一個(gè)二維?2%5Ctimes%203?的隨機(jī)tensor,元素服從標(biāo)準(zhǔn)正態(tài)分布,且這個(gè)tensor可以求梯度。


除了在建立tensor的時(shí)候決定這個(gè)argument之外,我們還可以修改已建立的tensor的argument requires_grad。一共有三種方法:

x = torch.randn(3,requires_grad=True)
x

# tensor([-1.1794, ?1.0465, -1.3400], requires_grad=True)

1. .detach()

y = x.detach()
y

# tensor([-1.1794, ?1.0465, -1.3400])

通過(guò) x.detach() ,我們建立了一個(gè)全新的tensor,這個(gè)tensor是不可以求梯度的


2. .with torch.no_grad():

with torch.no_grad():
 ? ?y = x + 2
 ? ?print(y)
 ? ?
# tensor([0.8206, 3.0465, 0.6600])

在這個(gè)statemtent下面,我們可以忽略一個(gè)tensor本身是否可以求梯度的性質(zhì)來(lái)對(duì)它進(jìn)行一些操作。我們忽略了x可以求梯度的性質(zhì),把x的每一個(gè)元素加2,再把加了2之后的tensor賦值給一個(gè)新的變量y。所以我們最終輸出的tensor y是不能夠求梯度的。


3. .requires_grad_(False)

x.requires_grad_(False)

# tensor([-1.4181, ?0.3631, -0.7994])

回憶上面的 .add_() 和 .sub_(),以下劃線結(jié)尾的method會(huì)改變其作用的tensor本身。這里也是一樣,例子里面我們直接改變了x的性質(zhì),讓x不能夠被求梯度。


3. 求梯度:backward函數(shù)和.grad

我目前的感覺(jué)是,如果我們對(duì)一個(gè)tensor進(jìn)行各種操作(加減乘除,所有元素求和,求所有元素平均值等elementwise或者tensor-wise的操作),得到一個(gè)新的?1%20%5Ctimes%201 的tensor,再把這個(gè)tensor賦值給另一個(gè)變量的話,pytorch會(huì)記住我們對(duì)初始tensor進(jìn)行變換的過(guò)程。

簡(jiǎn)而言之,我們對(duì)tensor A操作,最終得到了1%20%5Ctimes%201?tensor B,pytorch會(huì)自動(dòng)建立由A到B的函數(shù)關(guān)系。


我們考慮一個(gè)二元函數(shù):

f(x%2Cy)%20%3D%20e%5Ex%20%2B%20ln(y)

這個(gè)函數(shù)的梯度是

%5Cbegin%7Balign%7D%0A%5Cnabla%20f%20%26%20%3D%20(%5Cfrac%7B%5Cpartial%20f%7D%7B%5Cpartial%20x%7D%2C%5Cfrac%7B%5Cpartial%20f%7D%7B%5Cpartial%20y%7D)%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%26%20%3D%20(e%5Ex%2C%5Cfrac%7B1%7D%7By%7D)%0A%5Cend%7Balign%7D

因此,當(dāng)(x%2Cy)%20%3D%20(1%2C2)的時(shí)候,梯度就是

%5Cnabla%20f%7C_%7Bx%3D1%2C%20y%3D2%7D%20%3D%20(e%2C%5Cfrac%7B1%7D%7B2%7D)

如果我們嘗試用pytorch去求函數(shù)f 在?(1%2C2)?處的梯度的話,等價(jià)的pytorch代碼是

my_tensor = torch.tensor([1,2],requires_grad = True,dtype = torch.float64)
my_res = torch.exp(my_ten[0]) + torch.log(my_ten[1])
my_res.backward()
print(my_tensor.grad)
print(my_res)

# tensor([2.7183, 0.5000], dtype=torch.float64)
# tensor(3.4114, dtype=torch.float64, grad_fn=<AddBackward0>)

第一行,建立一個(gè)tensor?(1%2C2),就是我們想要求梯度的位置,記住一定要要求requires_grad = True

第二行,建立tensor?(1%2C2)?(my_tensor)和目標(biāo)?tensor (my_res)之間的聯(lián)系。用自然語(yǔ)言敘述就是,將tensor的第0項(xiàng)的自然指數(shù)和tensor第一項(xiàng)的自然對(duì)數(shù)相加。

第三行,通過(guò)my_res.backward() ,我們求my_res在my_tensor上面的梯度。前兩行代碼對(duì)pytorch指示的my_tensor和my_res之間的聯(lián)系就是上面提到的f(x%2Cy)?

第四行,我們通過(guò)my_tensor.grad得到函數(shù)在tensor?(1%2C2)上面的梯度


值得注意的是,每當(dāng)我們像第二行那樣建立了一次自變量和因變量的聯(lián)系之后,我們只能對(duì)應(yīng)的求一次梯度。如果建立一個(gè)聯(lián)系卻求兩次梯度的話,intuitively相等的新梯度會(huì)覆蓋之前求出來(lái)的舊梯度,但是實(shí)際上pytorch會(huì)對(duì)這種行為報(bào)錯(cuò)。簡(jiǎn)而言之,建立一次聯(lián)系只能求一次梯度。


weights = torch.ones(4,requires_grad = True)

for epoch in range(2):
 ? ?model_output = (weights*3).sum()
 ? ?
 ? ?model_output.backward()
 ? ?
 ? ?print(weights.grad)
 ? ?
# tensor([3., 3., 3., 3.])
# tensor([6., 6., 6., 6.])

在上面的代碼中,每次求梯度之前,我們都會(huì)跑一行代碼 model_output = (weights*3).sum() 來(lái)重新建立聯(lián)系。即使每一次循環(huán)中這個(gè)聯(lián)系是完全不變的,我們也要重新跑,否則backward會(huì)報(bào)錯(cuò)。


但是新的問(wèn)題出現(xiàn)了,在兩次循環(huán)中,建立的聯(lián)系還有自變量tensor (weights)都是不變的,但是兩次求出來(lái)的梯度卻不一樣。這是因?yàn)?.grad是自變量tensor的性質(zhì),在我們第二次求函數(shù)在自變量tensor上面的梯度時(shí),第二次求出來(lái)的梯度會(huì)和第一次求出來(lái)的梯度疊加。因此,在這個(gè)循環(huán)中,每當(dāng)我們得到了想要的自變量tensor的梯度之后,為了不影響下次循環(huán),應(yīng)該使用加一行 weights.grad.zero_() 把之前求出來(lái)的梯度清0。正確的代碼是:

weights = torch.ones(4,requires_grad = True)

for epoch in range(2):
 ? ?model_output = (weights*3).sum()
 ? ?
 ? ?model_output.backward()
 ? ?
 ? ?print(weights.grad)
 ? ?
 ? ?weights.grad.zero_()
 ?
# tensor([3., 3., 3., 3.])
# tensor([3., 3., 3., 3.])


4. 小練習(xí):下面這個(gè)函數(shù)在哪里取最小值

f(x%2Cy)%20%3D%20x%5E2%20%2B%20xy%20%2B%20y%5E2%20%2B%20x%20%2B%20y

這個(gè)用first order condition,最小值在(-%5Cfrac%7B1%7D%7B3%7D%2C-%5Cfrac%7B1%7D%7B3%7D)處取,我就不詳細(xì)寫(xiě)了。

x_list = []
y_list = []

i = 0
lr = 0.05
x = torch.randn(2,requires_grad = True)
while (i < 10000):
 ? ?y = x[0]**2 + x[0] * x[1] + x[1]**2 + x[0] + x[1]
 ? ?y.backward()
 ? ?if abs(x.grad).mean() < 1/100000:
 ? ? ? ?break
 ? ?#print(x) tensor([-0.0180, -1.1985], requires_grad=True)
 ? ?x = x - lr * x.grad
 ? ?#print(x) tensor([-0.0063, -1.1278], grad_fn=<SubBackward0>)
 ? ?x.detach_() ?
 ? ?x.requires_grad_(True)
 ? ?#print(x) tensor([-0.0063, -1.1278], requires_grad=True)
 ? ?i += 1
 ? ?
 ? ?x_list.append(x.detach().numpy()[0])
 ? ?y_list.append(x.detach().numpy()[1])
x

# tensor([-0.3333, -0.3333], requires_grad=True)

等價(jià)的,也可以

i = 0
lr = 0.05
x = torch.randn(2,requires_grad = True)
while (i < 10000):
 ? ?y = x[0]**2 + x[0] * x[1] + x[1]**2 + x[0] + x[1]
 ? ?y.backward()
 ? ?if abs(x.grad).mean() < 1/100000:
 ? ? ? ?break
 ? ?#print(x) tensor([-0.6739, -0.4994], requires_grad=True)
 ? ?with torch.no_grad():
 ? ? ? ?x -= lr * x.grad
 ? ?#print(x) tensor([-0.6316, -0.4658], requires_grad=True)
 ? ?x.grad.zero_()
 ? ?i += 1

x

# tensor([-0.3333, -0.3333], requires_grad=True)

最后可視化一下,看看隨著迭代逐漸逼近真實(shí)解的過(guò)程。

fig,ax = plt.subplots(1,figsize=(10,4))
ax.scatter(x_list,y_list,label='Estimated minimum')
ax.scatter(-1/3,-1/3,label='True minimum')
ax.legend()


[Quant 1.2] 一些Pytorch基礎(chǔ)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
江油市| 龙泉市| 大庆市| 财经| 方正县| 福建省| 和平县| 旌德县| 双峰县| 衡阳市| 军事| 民勤县| 辛集市| 五原县| 高台县| 长寿区| 江孜县| 罗山县| 子长县| 新昌县| 桑日县| 定陶县| 鄄城县| 潍坊市| 从江县| 海盐县| 临沧市| 磐石市| 裕民县| 贡嘎县| 化德县| 廊坊市| 固始县| 麦盖提县| 汶上县| 日土县| 周宁县| 博白县| 哈巴河县| 呈贡县| 濮阳市|