2021-08-05

20210807

学习成果(软件)

 

  1.  写在前面
  • 你学一类知识,如果怎么学都学不会的话,那一定是你的方法没有把握好,或者你找的教学资料有问题;人类的知识体系拾级而上,由简入繁,所有看似复杂的知识体系,必然有一个简单理论根基。无论如何都学不会的话,是教学资料或者老师的问题。
  • 人生的道路有很多艰辛和曲折,群居而处,不能事事称心如意。生活还是要继续的话,我们只能把握住那些我们可以把握的。尺有所长,寸有所短,有些事情,或许是注定的。不该为了留不住的人和事,空耗了热情,悲喜和人生。生活应该更潇洒一些。
  1. 增强学习
    1. 一个游戏

  

如上图所示,这是一个CartPole的小游戏,下面黑色的框框代表一个移动体,小车,小车在二维的平面上移动,但是同时要保持上面的木条不会倾斜。

  • 输入,输入很简单0或者1,当输入0的时候,小车向左边转动;当输入1的时候,小车向右边移动;
  • 状态,小车和木条总共有四个状态,分别是车的位置,杆子的角度,车速,角度变化率;
  • 游戏终止条件:当木条与垂直方向的夹角超过15deg,或者小车的位置离开了途中的界面,游戏即终止。因此必须保证小车不离开图中的横线,同时尽量让木条保持垂直;
  • 奖励:每次输入一个工作,游戏便给出一个奖励,奖励值为+1。

通过上面的论述,大家很容易想到路面上到处可见的二轮平衡车。正是如此,传统的平衡车通过PID(比例,积分,微分)算法,比较精巧的让平衡车处于一个动态平衡的状态。抛开PID算法,我们可以通过一个DQN机器学习算法,也达到相同的效果。

    1. 增强学习概念

强化学习问题可以描述为agent从environment中获取观察的state和获取reward,并产生action作用于environment。如上图描述所示。用数学语言描述就是Markov Decision Process(MDP)。

具体来说agent就是我们要建立的机器学习的模型(model),environment即是我们这里研究的CartPole游戏。Environment的输出包括state和reward,还有相关的信息(比如游戏是否结束)。Model获取这些信息,判定下一步如何操作,是0(左转)还是1(右转)。

一个简单的例子,木条的角度是(-10度),角速度是(-2deg/s),那说明木条再往左倾斜,这时候系统应该判定小车向左转,输出动作为(0)。一个训练好的模型,应该能够根据environment当前的状态自动判断下一个动作,让小车和木条保持在正确的位置,不会触发游戏阶数,从而获得更高的收益(reward)。

    1. Q learning 算法

此处的Q Learning,即上面我们所说的提高Reward的算法。我们已经知道了系统的游戏规则,该怎么做,才能获取最大的收益呢?

我们如何根据我们当前所处的状态,从最大化收益的角度,去判断下一步的动作呢?如果一个过程,它包含的动作的有限的,我们通过学习,得到每一步的动作的值,那我们选择价值最大的那一个动作,我们的收益不就最大了么。实际正是如此。我们观看如下的例子。

 如图所示,现有一个5房间的房子,房间与房间之间通过门连接,编号0到4,5号是房子外边,即我们的终点。我们将agent随机放在任一房间内,每打开一个房门返回一个reward。下图为房间之间的抽象关系图,箭头表示agent可以从该房间转移到与之相连的房间,箭头上的数字代表reward值。

 由此,我们得到初步的Q-Table:

  这是最开始的Q Table,可以看到,最开始的时候,只有与Goal Gate直接相连的几个action是由价值的。其他的state和action的组合,因为不能直接到达Goal Gate,是没有价值的。这显然不应该是最终的合理状态。

试想,当我们处在3的位置,虽然3不能直接达到5,但是3可以到达4,4可以达到5,因此,3—>4的这个动作,应该是有价值的。并且,3—>4的价值,跟4—>5的这个动作的价值有关。怎么把这个关系对应起来呢?按照如下公式:

其中,Q(St,At) 为当前状态St在动作At下的价值(此时为3—>4的价值0),RSt+1为4的当前价值,Q(St+1,a)为4在动作a下的价值maxa Q(St+1,a)为一些列的动作中,价值最大的那个,比如4可以去0,也可以去3,也可以去5,价值最大的肯定是4—>5,因此 此处maxa Q(St+1,a)=100。

α决定了当前Q值向target q值的渐进速度,如果让α = 1,target q值将会全部赋给当前q值,这也是q-learning算法的简化版本.我们将使用这个简化公式来表示下面的计算过程.

Q(St ,At​)←Rt+1 +λ amax​Q(St+1​ ,a)

这个公式的直接意义是,当前的状态在某个动作a下的价值,取决于下一个状态(当前状态通过a到达)所有动作价值的最大值。λ是一个(0~1)之间的数,表示一种衰减,即未来的价值不能全部反应到当前状态。具体算法的流程如下:

  • 设置λ参数,reward矩阵R(初始的Q Table);
  • 初始化Q矩阵为0
  • 对于每一个episode(从开始到目标成为一个episode):
  • 随机选择一个初始房间
  • 从当前状态的所有可能的action中选择一个
  • 计算简化公式
  • 直到到达goal,结束

针对上面的例子,具体的程序如下:

import numpy as np
GAMMA
= 0.8
Q = np.zeros((6,6))
R=np.asarray([[-1,-1,-1,-1,0,-1],
   [
-1,-1,-1,0,-1,100],
   [
-1,-1,-1,0,-1,-1],
   [
-1,0, 0, -1,0,-1],
   [
0,-1,-1,0,-1,100],
   [
-1,0,-1,-1,0,100]])
def getMaxQ(state):
    return
max(Q[state, :])
def QLearning(state):
   
curAction = None
    for
action in range(6):
        if
(R[state][action] == -1):
           
Q[state, action]=0
       
else:
           
curAction = action
            Q
[state,action]=R[state][action]+GAMMA * getMaxQ(curAction)
count=0
while count<200:
    for
i in range(6):
       
QLearning(i)
   
count+=1
print
(Q/5)

Q Table 

Action

0

1

2

3

4

5

State

0

0

0

0

0

80

0

1

0

0

0

64

0

100

2

0

0

0

64

0

0

3

0

80

51.2

0

80

0

4

64

0

0

64

0

100

5

0

80

0

0

80

100

通过以上更新后的表格,我们可以了解,假如我们处在0的位置,怎么才能达到组大的收益呢?0—>4—>5,收益最大,直接到达Goal Gate。这便是Q Learning 的意义。

    1. 回到CartPole

以上的例子中,action state是确定的,数目有限,因此可以通过表格的形式,比较详尽的列举出来。但是对于复杂的控制过程,比如AlphaGO面临的围棋的步数,机械控制领域的角度,力度等,状态变量和动作变量是多维度,连续变化的,不可能通过表格一一列举。此时要用一个函数,来模拟我们的StateQ Table, 这便引出了DQN( Deep Q Learning)。即依赖于深度神经网络的Q Learning策略。

DQN中有两个神经网络,第一个是参数相对固定的网络,我们称之为target-net,用来预测下一步的q-target的数值,另外一个网络用来反向传播,进行参数调整,用来获取q-eval评估。q_eval的网络target_net的参数也会定期进行修剪和更新,更新q_target网络的参数就是直接将q_eval的参数复制过来并进行修剪。

我们的损失函数实际上就是q_target减q_eval的结果。

训练的数据是从记忆库中随机提取的,记忆库记录了每个状态和接下来的行动,奖励,和下个状态的结果(s,a,r,s’)。我们在python中使用deque,当数据存满的时候下一数据就会覆盖掉记忆库中的第一个数据。

state_model用来反向传播优化参数。state_model计算出当前状态下,输入当前动作能得出的预测收益值。我们向DQNetWork输入的是当前状态,预测在当前状态下,分别执行两个操作的收益值Q1和Q2。然后将[Q1,Q2]和输入action的one_hot矩阵进行逐元素相乘,获得在特定输入action下的收益值q_eval。state_model预测出的结果q_eval要向target_model预测出的q_target靠近。也就是说state_model计算出的q_eval是向理论上的最大收益或者惩罚收益靠近。

我们向DQNetWork输入一个状态,分别执行两个操作,得到两个收益值,我们取两个收益值中较大的那个收益对应的action作为当前状态应该执行的动作。因为在这个动作下,获得的收益最高

前面有提到过,q_eval要向target_model预测出的q_target靠近,所以我们用一个简单的均方误差计算q_eval和q_target之间的差距,并将其作为损失函数进行反向传播,从而优化参数。在这期间,target_model的DQNetWork网络参数定期根据state_model的DQNetWork参数进行复制,修剪。因为target_model是不进行反向传播来优化参数的。

# -*- coding: utf-8 -*-
# import the necessary packages

import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F
import numpy as np
import gym

# 1. Define some Hyper Parameters
BATCH_SIZE = 32  # batch size of sampling process from buffer
LR = 0.01  # learning rate
EPSILON = 0.9  # epsilon used for epsilon greedy approach
GAMMA = 0.9  # discount factor
TARGET_NETWORK_REPLACE_FREQ = 100  # How frequently target netowrk updates
MEMORY_CAPACITY = 2000  # The capacity of experience replay buffer

env = gym.make("CartPole-v0"# Use cartpole game as environment
env = env.unwrapped
N_ACTIONS
= env.action_space.# 2 actions
N_STATES = env.observation_space.shape[0# 4 states

ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(),
                             
int) else env.action_space.sample().shape  # to confirm the shape


# 2. Define the network used in both target net and the net for training

class Net(nn.Module):
    def
__init__(self):
       
# Define the network structure, a very simple fully connected network
       
super(Net, self).__init__()
       
# Define the structure of fully connected network
       
self.fc1 = nn.Linear(N_STATES, 10# layer 1
       
self.fc1.weight.data.normal_(0, 0.1# in-place initilization of weights of fc1
       
self.out = nn.Linear(10, N_ACTIONS# layer 2
       
self.out.weight.data.normal_(0, 0.1# in-place initilization of weights of fc2

   
def forward(self, x):
       
# Define how the input data pass inside the network
       
x = self.fc1(x)
       
x = F.relu(x)
       
actions_value = self.out(x)
       
return actions_value


# 3. Define the DQN network and its corresponding methods
class DQN(object):
    def
__init__(self):
       
# -----------Define 2 networks (target and training)------#
       
self.eval_net, self.target_net = Net(), Net()
       
# Define counter, memory size and loss function
       
self.learn_step_counter = # count the steps of learning process
        
self.memory_counter = # counter used for experience replay buffer

        # ----Define the memory (or the buffer), allocate some space to it. The number
        # of columns depends on 4 elements, s, a, r, s_, the total is N_STATES*2 + 2---#
       
self.memory = np.zeros((MEMORY_CAPACITY, N_STATES * 2 + 2))

       
# ------- Define the optimizer------#
       
self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=LR)

       
# ------Define the loss function-----#
       
self.loss_func = nn.MSELoss()

   
def choose_action(self, x):
       
# This function is used to make decision based upon epsilon greedy

       
x = torch.unsqueeze(torch.FloatTensor(x), 0# add 1 dimension to input state x
        # input only one sample
       
if np.random.uniform() < EPSILON# greedy
            # use epsilon-greedy approach to take action
           
actions_value = self.eval_net.forward(x)
           
# print(torch.max(actions_value, 1))
            # torch.max() returns a tensor composed of max value along the axis=dim and corresponding index
            # what we need is the index in this function, representing the action of cart.
            
action = torch.max(actions_value, 1)[1].data.numpy()
           
action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE# return the argmax index
       
else:  # random
           
action = np.random.randint(0, N_ACTIONS)
           
action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
       
return action

   
def store_transition(self, s, a, r, s_):
       
# This function acts as experience replay buffer       
       
transition = np.hstack((s, [a, r], s_))  # horizontally stack these vectors
        # if the capacity is full, then use index to replace the old memory with new one
       
index = self.memory_counter % MEMORY_CAPACITY
       
self.memory[index, :] = transition
       
self.memory_counter += 1

   
def learn(self):
       
# Define how the whole DQN works including sampling batch of experiences,
        # when and how to update parameters of target network, and how to implement
        # backward propagation.

        # update the target network every fixed steps
        
if self.learn_step_counter % TARGET_NETWORK_REPLACE_FREQ == 0:
           
# Assign the parameters of eval_net to target_net
           
self.target_net.load_state_dict(self.eval_net.state_dict()) # load parameter of eval_net
       
self.learn_step_counter += 1

       
# Determine the index of Sampled batch from buffer
       
sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE# randomly select some data from buffer
        # extract experiences of batch size from buffer.
       
b_memory = self.memory[sample_index, :]
       
# extract vectors or matrices s,a,r,s_ from batch memory and convert these to torch Variables
        # that are convenient to back propagation
       
b_s = Variable(torch.FloatTensor(b_memory[:, :N_STATES]))
       
# convert long int type to tensor
       
b_a = Variable(torch.LongTensor(b_memory[:, N_STATES:N_STATES + 1].astype(int)))
       
b_r = Variable(torch.FloatTensor(b_memory[:, N_STATES + 1:N_STATES + 2]))
       
b_s_ = Variable(torch.FloatTensor(b_memory[:, -N_STATES:]))

       
# calculate the Q value of state-action pair
       
q_eval = self.eval_net(b_s).gather(1, b_a# (batch_size, 1)
        # calculate the q value of next state
       
q_next = self.target_net(b_s_).detach()  # detach from computational graph, don't back propagate
        # select the maximum q value
        # print(q_next)
        # q_next.max(1) returns the max value along the axis=1 and its corresponding index
       
q_target = b_r + GAMMA * q_next.max(1)[0].view(BATCH_SIZE, 1# (batch_size, 1)
       
loss = self.loss_func(q_eval, q_target)

       
self.optimizer.zero_grad()  # reset the gradient to zero
       
loss.backward()
       
self.optimizer.step()  # execute back propagation for one step


'''
--------------Procedures of DQN Algorithm------------------
'''

# create the object of DQN class
dqn = DQN()

# Start training
print("\nCollecting experience...")
for i_episode in range(400):
   
# play 400 episodes of cartpole game
   
s = env.reset()
   
ep_r = 0
   
while True:
       
env.render()
       
# take action based on the current state
       
a = dqn.choose_action(s)
       
# obtain the reward and next state and some other information
       
s_, ra, done, info = env.step(a) #observation, reward, done, info obervation

        # modify the reward based on the environment state
       
x, x_dot, theta, theta_dot = s_ #:有四个量,分别表示车的位置,杆子的角度,车速,角度变化率
       
r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8 #位置限制-位置/位置的限制-0.8
       
r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5
       
r = r1 + r2



       
# store the transitions of states
       
dqn.store_transition(s, a, r, s_)

       
ep_r += r
       
# if the experience repaly buffer is filled, DQN begins to learn or update
        # its parameters.      
       
if dqn.memory_counter > MEMORY_CAPACITY:
           
dqn.learn()
           
if done:
               
print('Ep: ', i_episode, ' |', 'Ep_r: ', round(ep_r, 2))

       
if done:
           
# if game is over, then skip the while loop.
           
break
       
# use next state to update the current state.
       
s = s_ 

    1. DQN注释
  • Eval_net 网络的作用是什么?

Eval_net 网络用以预测对应的状态下,对应得两个动作(0或1)的Q值;Q_eval函数输入的是一带四个参数的变量(s),分别是车的位置,杆子的角度,车速,角度变化率,输出的是两个Q value,分别对应两个动作。

  • Target_net的作用是什么?

Target_net的网络用以得到当前的状态下真实的Q值,本例中,Q value用角度和位置的加权,作为Q value,这是当前状态下的R(t+1),同时用Target_net预测下一个状态下的Qvalue,并且按照之前的加权原则与R(t+1)相加,作为本次动作下Q Value的Label值。

  • Loss function 如何发挥作用?

Eval_net和Target_net二者的均方差,就是DQN程序的loss,启动反向传输,优化Eval_net网络,使得Eval_net和Target_net得到的Q Value之差达到最低。

  • 如何更新Target_net网络?

按照以上的顺序优化Eval_net,那么,Eval_net是可以学习到一些知识的,一定的时间以后,就可以更新Target_net,确保学习到的知识可以被Target_net保存下来。Target_net直接load Eval_net的参数即可。

    1. DQN学习效果

从上面的图形可以看出,通过学习,Environment可以很好的平衡木条。

 Figure 2‑1 系统训练以前的游戏效果

 Figure 2‑2 系统训练以后的游戏效果

 Figure 2‑3 总的训练效果

上图为250次训练的Reward的分布,总的来说,Reward随着训练次数的增加,稳步的上升。不过 也是有一些回退。这大概跟动作选取的策略有关。

在选择动作的时候,我们并不是一味的按照最大的Q Value选择Action,而是按照一定的概率,随机选择(10%)。这里的10%随机性,我理解为Exploration和exploitation之间的折衷,这是机器学习算法领域一种通用的做法。增加系统的Robustness。

  1. 总结

机器学习是有趣并且有意义的事情。值得我们去探究其中的奥秘。

下面会继续研究增强学习在IC设计领域的应用,以及Vision Transformer技术的行业应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值