---
# System prepended metadata

title: Policy Gradient
tags: [Tag(Reinforcement learning)]

---

# Policy Gradient
###### tags: `Tag(Reinforcement learning)`
## **Policy π**
* a network with parameter θ
* input 為對於環境state的觀察，output為機器採取的行為，且在output layer中每個neuron代表一個行為
* network會給予每個action一個機率
## env、actor與reward間的關係
* **Trajectory τ**: 由一個episode中所有的(s,a) pair組成 
* **Pθ(τ)**: 在policy θ下，某個episode發生τ的機率

    ![](https://i.imgur.com/kfbEDGo.png)
    
* **Reward function**: 
    * 僅能計算Reward期望值
        ![](https://i.imgur.com/uQJA4ci.png)
    
    * **如何最佳化?** ==採用Gradient ascent==
    若在st執行at，使R(τ)為正，則增加Pθ(st|at)機率，反之則減少
    ![](https://i.imgur.com/eFOpwWP.png)
* **training過程**
:warning: **每次sample的data只能使用一次**
    1. 先以actor跟環境互動蒐集多個trajectory τ(τ1,τ2...)
    2. 利用Gradient ascent更新參數(依照上面算式)
    3. model(policy)更新後，再以新的policy蒐集data
    4. 回到第一步，繼續蒐集，並更新policy
* **實作想法**
將訓練過程視為分類問題，(s,a)pair data中a視為ground truth，而模型根據s輸出的action機率，必須與ground truth越近越好，因此，可利用minimize cross entropy來最佳化，但由於是要最大化reward，所以目標式必須加上一個負號
    ![](https://i.imgur.com/O34SD0Y.png)

## Tips
1. **Add a Baseline**
    * **理由**: 
    由於我們只能sample有限數量的data，若所有R(τ)皆是正的，則未sample到的(s,a)pair機率就會下降，例如:只sample到左右但未sample到上下，則上下的action機率就會降低，然上下只是因為未sample到，不是因為他們不適當
    * **方法**: R(τ)減掉一個base值，而base值可從計算R(τ)的平均值而得
2. **Assign Suitable Credit**
    * **理由**: 
    所有的action皆weighted同樣的weight是不合理的，action有先後順序，對episode最後的reward帶來的影響不同
    * **方法**: 
        1. 將R(τ)(整場遊戲的reward)改為在time t所執行的action at，從時間點t一直到遊戲結束所加總得到的reward
        ![](https://i.imgur.com/cOdt6ZV.png)

        2. 加上discount factor，因為離time t越遠的action與在time t所得到的reward關係越小
       ![](https://i.imgur.com/QRHrpli.png)
3. **Advantage function**
    * R(τ)-b可視為Advantage function Aθ(st,at)
    * 評估在某個state s執行某個action a相較於其他action有多好
    =>**由critic預估**
## Code
```python=
class PolicyNet(torch.nn.Module):
    def __init__(self, state_dim, hidden_dim, action_dim):
        super(PolicyNet, self).__init__()
        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)
        self.fc2 = torch.nn.Linear(hidden_dim, action_dim)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        return F.softmax(self.fc2(x), dim=1)
    
class REINFORCE:
    def __init__(self, state_dim, hidden_dim, action_dim, learning_rate, gamma,
                 device):
        self.policy_net = PolicyNet(state_dim, hidden_dim,
                                    action_dim).to(device)
        self.optimizer = torch.optim.Adam(self.policy_net.parameters(),
                                          lr=learning_rate)  # 使用Adam优化器
        self.gamma = gamma  # 折扣因子
        self.device = device

    def take_action(self, state):  # 根据动作概率分布随机采样
        state = torch.tensor([state], dtype=torch.float).to(self.device)
        probs = self.policy_net(state)
        action_dist = torch.distributions.Categorical(probs)
        action = action_dist.sample()
        return action.item()

    def update(self, transition_dict):
        reward_list = transition_dict['rewards']
        state_list = transition_dict['states']
        action_list = transition_dict['actions']

        G = 0
        self.optimizer.zero_grad()
        for i in reversed(range(len(reward_list))):  # 从最后一步算起
            reward = reward_list[i]
            state = torch.tensor([state_list[i]],
                                 dtype=torch.float).to(self.device)
            action = torch.tensor([action_list[i]]).view(-1, 1).to(self.device)
            log_prob = torch.log(self.policy_net(state).gather(1, action))
            G = self.gamma * G + reward
            loss = -log_prob * G  # 每一步的损失函数
            loss.backward()  # 反向传播计算梯度
        self.optimizer.step()  # 梯度下降
```

L<sup>PG</sup>(θ) = E<sub>t</sub> [ r<sub>t</sub> * A<sub>t</sub> * (π<sub>θ</sub>(a<sub>t</sub>|s<sub>t</sub>) / π<sub>θ<sub>old</sub></sub>(a<sub>t</sub>|s<sub>t</sub>)) ]

L<sup>CLIP</sup>(θ) = E<sub>t</sub> [ min( r<sub>t</sub>(θ) * A<sub>t</sub>,  clip(r<sub>t</sub>(θ), 1-ε, 1+ε) * A<sub>t</sub> ) ]

r_t(θ) = π<sub>θ</sub>(a<sub>t</sub>|s<sub>t</sub>) / π<sub>θ<sub>old</sub></sub>(a<sub>t</sub>|s<sub>t</sub>)


