一、介紹autograd
torch.autograd 模塊是 PyTorch 中的自動微分引擎。它支持任意數量的計算圖,可以自動執行前向傳遞、後向傳遞和計算梯度,同時提供很多有用的函數來處理各種計算圖。它與程序中的其它部分緊密結合使用,使得使用 PyTorch 構建神經網絡得以簡單而高效實現。
二、期望值反向傳播
我們簡單介紹一下期望值反向傳播(REINFORCE)及其PyTorch實現。期望值反向傳播是一種用於直接優化policy的算法。在許多強化學習任務中,我們需要優化一個策略,使其能夠最大化累積獎勵的期望值。在連續動作空間或高維狀態空間下,直接優化該策略是非常困難的,因此我們通常使用一些策略梯度方法,它們依據一些目標構建策略的估計,並更新策略以優化該估計。
在期望值反向傳播中,我們計算得到目標的期望值,然後對該期望值的對數化為一組權重,分別賦給每一步的回報。然後用一個對策略參數的公式求導。這將給出一組價值函數的梯度,此外,我們還可以使用Torch中的鏈式法則很容易地獲得策略梯度。
import torch
def REINFORCE(policy, episodes, learning_rate):
optimizer = torch.optim.Adam(policy.parameters(), lr=learning_rate) #定義一個優化器
episode_rewards = []
for i in range(episodes):
log_probs = []
rewards = []
state = env.reset()
episode_reward = 0
while(True):
action, log_prob = policy.get_action(state)
new_state, reward, done, _ = env.step(action.item())
log_probs.append(log_prob)
rewards.append(reward)
state = new_state
episode_reward += reward
if done:
break
episode_rewards.append(episode_reward)
# 計算期望梯度,更新策略參數
eps = torch.finfo(torch.float32).eps
discounts = [np.power(0.99, i) for i in range(len(rewards))]
discounts = torch.from_numpy(np.array(discounts, dtype=np.float32)).to(device)
rewards = torch.stack(rewards).to(device)
log_probs = torch.stack(log_probs).to(device)
R = (rewards * discounts).sum(dim=0)
R = (R - R.mean()) / (R.std() + eps) # 標準化策略梯度
policy_loss = (-log_probs * R).sum(dim=0)
optimizer.zero_grad()
policy_loss.backward()
optimizer.step()
return episode_rewards
三、autograd.Function的使用
本節將詳細介紹PyTorch中 autograd.Function 的使用,以及如何使用它們自定義您的操作。在PyTorch中,Variable的每個操作都是如何在計算圖中回溯到其他變量,並且每個操作同樣可以回溯到其他函數。為了允許用戶實現自己的操作,PyTorch為我們提供了一個非常簡單和強大的類」。該autograd.Function類被Pytorch用於允許我們定義隨時可導的用戶自定義運算。
class Exp(Function):
@staticmethod
def forward(ctx, i):
result = i.exp()
ctx.save_for_backward(result)
return result
@staticmethod
def backward(ctx, grad_output):
result, = ctx.saved_variables
return grad_output * result
四、Variable以及在計算圖中的應用
在PyTorch中,算子可以添加到計算圖中,以實現自動求導。在計算圖中,每一個節點都表示一個Tensor,其中一些Tensor節點是輸入節點(InputNode),而其他節點是操作節點(FunctionNode)。在輕鬆編寫深度學習模型時,我們很少手動添加節點和邊,PyTorch很好地隱藏了這些內容並隱式執行了它。 Variable 是 PyTorch 中圖計算的重要概念之一。它是具有梯度的張量,可以直接放入計算圖中,並可以通過它的backward()函數產生梯度信號。
Variable是Tensor的一個封裝,不同的是Variable有 tensor的一些屬性和方法,比如shape,size()等, 同時它有一些附加的屬性,比如grad( Variable的梯度)、requires_grad(是不是需要求 Variable的梯度)、data(保存 Variable的 tensor)等。 我們在需要求 Variable的梯度時才需要調用 backward() 函數.
import torch
from torch.autograd import Variable
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = Variable(torch.Tensor([1.0]), requires_grad=True)
def forward(x):
return x * w
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) * (y_pred - y)
for epoch in range(10):
for x_val, y_val in zip(x_data, y_data):
l = loss(x_val, y_val)
l.backward()
print("grad: ", x_val, y_val, w.grad.data[0])
w.data = w.data - 0.01 * w.grad.data
# Manually zero the gradients after updating weights
w.grad.data.zero_()
五、tensor.detach()函數的應用
在PyTorch中, tensor.detach()函數是用於獲得沒有對原始變量的梯度的新張量的,這也就是一個detachdetensor。總之,當您需要獲取不需要梯度的張量時, detach() 函數非常有用。在使用GPU時,您必須對張量調用detach(),以便在進行數據移動時清除存儲,否則它會導致內存泄漏;因為我們需要計算二階梯度。 沒有從圖中分離張量屬性。因此, detach() 使您可以在不影響計算圖的情況下使用張量。
import torch
tensor = torch.randn(3, requires_grad=True)
print('tensor:', tensor)
# 移動到GPU上
tensor_gpu = tensor.cuda()
# 加點於tensor在GPU上產生的梯度
result_gpu = (tensor_gpu ** 2).sum()
result_gpu.backward()
# TensorFlow,tensor與 tensor_gpu 的梯度不匹配。
# Do a slow transfer back to CPU memory
result = (tensor.detach().cpu() ** 2).sum()
result.backward()
print('tensor_grad:', tensor.grad)
print('tensor_gpu_grad:', tensor_gpu.grad)
原創文章,作者:GLWYF,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/372475.html
微信掃一掃
支付寶掃一掃