继续创作,加速成长!这是我参与「日新计划 10 月更文挑战」的第22天,点击查看活动概况

前言

因为这个时刻联系(好吧其实是我懒),咱们的话就只写了这个最简略的一个BaseLine版别。那么后边还有Lite,Plus版别,差异的话便是神经网络模型的一个差异,其他的思维都是相同的。那么为什么不写后边的版别呢,一方面是懒,另一方面是,这样搞,我后边怎样水呀。并且一步到位的话,这个阅读量仍是挺大的。那么后续的版别什么时分更新呢,这个不急,并且改善的点也很简略。

那么本文也是,TSP系列的第三篇文章,也是作为一个拓宽文章,那么关于原理部分的话,这儿就不细说了,需求必定的基础进行观看。

强化学习

那么咱们这边所运用到的强化学习算法呢仍是这个DDPG,为什么用这个,待会在模型阐述的时分我会进行阐明。那么咱们这边简略聊一下DDPG,之后的话结合到咱们详细的TSP求解傍边。

强化学习

强化学习是机器学习范畴之一,受到行为心理学的启发,首要重视智能体怎么在环境中采纳不同的举动,以最大极限地提高累积奖赏。

轻松解决TSP问题之强化学习(BaseLine)

关键概念

关于强化学习这儿边首要有几个概念。

智能体

强化学习的本体,作为学习者或者决议计划者。

环境

强化学习智能体以外的一切,首要由状况调集组成。

状况

一个表明环境的数据,状况集则是环境中一切或许的状况。

动作

智能体能够做出的动作,动作集则是智能体能够做出的一切动作。

奖赏

智能体在履行一个动作后,取得的正/负反馈信号,奖赏集则是智能体能够取得的一切反馈信息。

战略

强化学习是从环境状况到动作的映射学习,称该映射联系为战略。通俗的理解,即智能体怎么挑选动作的思考进程称为战略。

目标

智能体自动寻觅在连续时刻序列里的最优战略,而最优战略通常指最大化长时间累积奖赏。

因而,强化学习实践上是智能体在与环境进行交互的进程中,学会最佳决议计划序列。

根本结构

强化学习首要由智能体和环境组成。因为智能体与环境的交互方法与生物跟环境的交互方法相似,因而能够认为强化学习是一套通用的学习结构,是通用人工智能算法的未来。 强化学习的根本结构如图所示,智能体经过状况、动作、奖赏与环境进行交互。

轻松解决TSP问题之强化学习(BaseLine)

在线学习(简述)

这儿先做一个简述,后边咱们会进行深化一点的探讨。 关于强化学习呢,还能够划分:在线学习和离线学习。在论文傍边运用的DDPG,运用的是在线学习战略,所以本文也是简略说一下在线学习和离线学习。

这儿以QLearn 为代表

轻松解决TSP问题之强化学习(BaseLine)

离线学习(简述)

离线学习其实和在线学习相似,差异在于挑选动作的时分,离线学习单纯依照价值最大的去现在。而在线学习的话仍是有必定概率来挑选并不是当时价值最大的动作。

轻松解决TSP问题之强化学习(BaseLine)

实践核心代码的差异:

Q Learn

def QLearning():
    QTable = Init(N_STATES, ACTIONS)  
    for ecpho in range(ECPHOS): 
        step_counter = 0
        S = 0
        # 是否回合完毕
        isWin = False
        updateEnvShow(S, ecpho, step_counter)
        while not isWin:
            #挑选行为
            A = ChoseAction(S, QTable)
            # 得到当时行为会得到的Reward,以及下一步的情况
            S_, R = GetReward(S, A)
            # 预算的(状况-行为)值
            q_predict = QTable.loc[S, A]
            if S_ != 'win':
                # 实践的(状况-行为)值 这个便是相似与G1
                q_target = R + GAMMER * QTable.iloc[S_, :].max()
            else:
                #  实践的(状况-行为)值 (回合完毕)
                q_target = R
                isWin = True    
            QTable.loc[S, A] += ALPHA * (q_target - q_predict)  #  QTable 更新
            S = S_  # 探索者移动到下一个 state
            # 环境更新显现
            updateEnvShow(S, ecpho, step_counter+1)
            step_counter += 1
    return QTable

轻松解决TSP问题之强化学习(BaseLine)
Sarsa 离线学习

def SARSA():
    QTable = Init(N_STATES, ACTIONS)
    for ecpho in range(ECPHOS):
        step_counter = 0
        S = 0
        # 是否回合完毕
        isWin = False
        updateEnvShow(S, ecpho, step_counter)
        A = ChoseAction(S, QTable)  # 先初始化挑选行为
        while not isWin:
            S_, R = GetReward(S, A)
            try:
                A_ = ChoseAction(S_, QTable)
            except:
                # 这儿阐明已经到了结尾(假如报错)
                pass
            q_predict = QTable.loc[S, A]
            if S_ != 'win':
                q_target = R + GAMMER * QTable.iloc[S_, :].max()
            else:
                q_target = R
                isWin = True
            QTable.loc[S, A] += ALPHA * (q_target - q_predict)  #  QTable 更新
            S = S_  
            A = A_  
            updateEnvShow(S, ecpho, step_counter+1)
            step_counter += 1
    return QTable

关于离线学习而言,假如从上面的代码来改的话,那么只需求把动作挑选函数的概率调整为1,并且先提前挑选一个价值最大的动作即可。

无论是关于在线学习仍是离线学习,其意图都是需求得到这样一张表:

轻松解决TSP问题之强化学习(BaseLine)

Qlearn

现在咱们来好好的聊了里边的一些大体的细节。

马尔可夫决议计划

咱们这儿只讲大约几个和QLearn 联系比较严密的东西。 里边比较详细的关于这个的是 概率论 这儿边有说到。 这个是强化学习的一个理论支撑,相似于梯度下降,微分对神经网络

马尔科夫链

那么首要咱们的第一点是马尔可夫链:这个东西便是一系列或许发生的状况。

例如:一个人刚起床,他有或许先刷牙,然后洗脸,然后上课。 或者这个人 起床,洗澡,刷牙,然后上课。 用一条链来表明便是:

刷牙-洗脸-上课 洗澡-刷牙-上课

战略

轻松解决TSP问题之强化学习(BaseLine)

累计报答

轻松解决TSP问题之强化学习(BaseLine)
这个首要是看到马尔可夫链,当时的状况对后边是有关联的。

值函数

轻松解决TSP问题之强化学习(BaseLine)

他们之间的对应联系大致如下图:

轻松解决TSP问题之强化学习(BaseLine)

详细表现

强化学习便是数学原理是根据马尔可夫来的,那么在实践的表现傍边的意图是为了求取一个表格Q。 这个表格Q,其实便是:

轻松解决TSP问题之强化学习(BaseLine)
依照前面的粒子便是这个玩意:
轻松解决TSP问题之强化学习(BaseLine)

在咱们实践上开端的时分Q表咱们是不知道的,所以咱们会有一个初始化,之后输入当时的状况和下一步的动作,会得到当时假如挑选了这个动作,那么将得到的奖赏,以及下一个状况,咱们先经过q(s,a)能够得到。可是除此之外,因为咱们实践上Q表一开端是随机的,所以是需求进行不断完善,收敛的,所以咱们还需求不断更新咱们的Q表。

所以在咱们的实践代码里边仍是有不相同的。

轻松解决TSP问题之强化学习(BaseLine)

DQN神经网络

这个首要是因为论文中说到了DDPG,假如不说这个DQN 的话,这个DDPG很难说下去,那么论文也很难讲下去,这篇论文的难点在于知识面较广,实践算法其实不难。

DQN 其实和QLearn是相同的,差异在于,本来的Q表从一个表,一个有实体的表,变成了一个神经网络。意图是为了,经过神经网络去拟合那个Q表,因为在实践进程傍边,假如需求将一切的状况和动作价值存起来是不或许的假如它的状况很多的话。所以需求一个神经网络来做拟合。 伪代码如下:

轻松解决TSP问题之强化学习(BaseLine)

轻松解决TSP问题之强化学习(BaseLine)

编码细节

在咱们本来的时分,运用Q表

轻松解决TSP问题之强化学习(BaseLine)

可是现在的话,因为咱们是直接运用了这种“特别的表”所以咱们能够单独运用两个神经网络去分别代表实践和估计(预测)

轻松解决TSP问题之强化学习(BaseLine)
轻松解决TSP问题之强化学习(BaseLine)
而咱们的丢失函数便是让q_eval 和 q_target 变小 所以:
轻松解决TSP问题之强化学习(BaseLine)
这儿的loss_func 是nn.MSELoss()

DDPG

从上面的内容,你会发现,这个玩意和传统的Qlearn没太大差异仅仅很奇妙地运用了神经网络,最终仍是要得到一个关于每一个动作的打分,然后去依照那个得分去挑选分高的动作,换一句话说是,这个神经网络仍是只能得到对应动作的价值,例如 上下左右,然后选价值最大的,如 上 这个动作。

可是在我实践的PSO问题傍边,我想要的是一组解,也便是你直接告诉我w c1 c2 取哪些值?

所以现在直接运用DQN 就很难了,明显这玩意貌似只能挑选出一个动作,而我的w c1 c2 不或许是一个动作,假如把他看作是一个动作的话,那么你将有 无量个动作挑选,假定有范围,那便是可数无量个动作。

为了解决那个问题,所以有了DDGP,也便是我想要直接得到一组动作,你直接告诉我 w c1 c2取得哪些值?

怎样做,没错,再来一个神经网络。 详细怎样做,如下图:

轻松解决TSP问题之强化学习(BaseLine)

Actor 网络直接生成一个动作,然后 本来在DQN的那个网络在这儿是Critic 网络 去点评,这个点评其实便是在DQN里边的那个网络,输入一个S,和 A 得到一个价值,现在这个价值变成了评分。

轻松解决TSP问题之强化学习(BaseLine)

丢失函数便是这样:

轻松解决TSP问题之强化学习(BaseLine)

TSP模型树立

ok,随便聊了一下这个玩意(尽管我知道你一看出来了,上面的内容是copy我以前的博文的,狗头)

根本流程

首要的话,咱们希望的流程是这样的:

轻松解决TSP问题之强化学习(BaseLine)

重点是说,咱们希望便是这个Net能够直接输出一组概率,所以的话,咱们刚好用这个DDPG。

所以的话这个是为啥用这个网络哈。

网络模型

现在的话咱们需求用到这个DDPG,所以的话咱们也是有两个网络的,一共是四个网络运行。这个的话,懂得都懂,实践上咱们能够做到只用2个网络,并且实践上我也做到过,作用其实差不多。那么咱们的网络大约长这个姿态。

Actor

这个其实没啥好说的,这个很简略的,可是优化点就在这边。

import torch
from torch import nn
import torch.nn.functional as F
class Actor(nn.Module):
    """
    这个是咱们的Actor网络
    """
    def __init__(self,state,out):
        super(Actor, self).__init__()
        """
        The network structure is modified
        """
        self.fc1 = nn.Linear(state,64)
        self.fc1.weight.data.normal_(0, 0.1)
        self.fc2 = nn.Linear(64,64)
        self.fc2.weight.data.normal_(0, 0.1)
        self.fc3 = nn.Linear(64,64)
        self.fc3.weight.data.normal_(0,0.1)
        self.out = nn.Linear(64,out)
    def forward(self,x):
        x = self.fc1(x)
        x = F.leaky_relu(x)
        x = self.fc2(x)
        x = F.leaky_relu(x)
        x = self.fc3(x)
        x = F.leaky_relu(x)
        x = self.out(x)
        x = torch.tanh(x)
        return x

Critic网络

这个网络的话,其实也很简略,便是多了个东西罢了。

from torch import nn
import torch.nn.functional as F
class Critic(nn.Module):
    """
    这个是咱们的Critic网络,因为DQN很难去直接表明三维消息
    假如要就需求一个映射表,这个映射表的动作也是很杂乱的,仍是需求一个Net
    所以的话咱们这边仍是直接挑选运用这个DDPG
    """
    def __init__(self,state_dim,action_dim):
        """
        :param state_action:
        """
        super(Critic,self).__init__()
        self.fc1_status = nn.Linear(state_dim,64)
        self.fc1_status.weight.data.normal_(0,0.1)
        self.fc1_actions = nn.Linear(action_dim,64)
        self.fc1_actions.weight.data.normal_(0,0.1)
        self.fc2_status= nn.Linear(64,32)
        self.fc2_status.weight.data.normal_(0,0.1)
        self.fc2_actions = nn.Linear(64,32)
        self.fc2_actions.weight.data.normal_(0,0.1)
        self.fc5 = nn.Linear(32,16)
        self.fc5.weight.data.normal_(0,0.1)
        self.out = nn.Linear(16,1)
        self.out.weight.data.normal_(0,0.1)
    def forward(self,status,actions):
        status = self.fc1_status(status)
        status = F.leaky_relu(status)
        status = self.fc2_status(status)
        actions = self.fc1_actions(actions)
        actions = F.leaky_relu(actions)
        actions = self.fc2_actions(actions)
        net = status+actions
        net = F.leaky_relu(net)
        net = self.fc5(net)
        net = F.leaky_relu(net)
        out  = self.out(net)
        return out

输入输出

OK,那么接下来的话,咱们便是来聊聊 说完了这个,咱们来界说一下输入以及输出,咱们的状况是怎么输入的,咱们怎么从输出得到一组途径。

输入

这部分的代码在这儿:

轻松解决TSP问题之强化学习(BaseLine)

咱们这边的话,咱们这个仍是用矩阵表明这个城市,咱们输入的是城市将的一个间隔矩阵,以及咱们的这个当时的较优途径(初始化的时分他们是0,当然这儿其实随机生成一些很小的数会更好)。所以的值都是经过归一化处理后的。

输出

神经网络输出,这部分首要是指咱们的这个Actor网络,它输出的也是一组二维向量,得到的维度是: (城市个数+扩充个数)x 城市个数。

之后的话经过咱们的softmax能够变成一组概率,经过概率咱们将生成一组途径。 详细的代码在这。

  def getRoward(self,status,actions,isShow):
        """
        回来当时环境的下一个动作,以及奖赏。
        留意status和actions都是numpy类型的
        :param isShow 表明要不要输出当时最好的一个途径
        :return:
        """
        #核算当时下一个的状况
        probabilitys = self.transform.TransProbability(actions)
        #将actions,status重新转化为numpy类型
        status = status.detach().numpy()
        actions = actions.detach().numpy()
        """
        经过概率生成咱们的途径
        """
        path_out = []
        for probability in probabilitys:
            probability /= probability.sum()
            path_out.append(np.random.choice(self.city_node, (actions[0].shape), p=probability,replace=False))
        fits = []
        for path in path_out:
            fits.append(self.comp_fit(path))
        great_fits = np.argsort(fits)[:self.extend]
        great_actions = actions[great_fits,:]
        status[self.city_num:,:]=(great_actions)/(self.city_num-1)
        #核算奖赏
        great_dist = fits[great_fits[0]]
        R = self.tanh(self.best_dist-great_dist)
        if(self.best_dist>great_dist):
            self.best_dist = great_dist
            self.best_path = path_out[great_fits[0]]
        if(isShow):
            self.out_path(self.best_path,self.best_dist)
        return status,R

在这儿的话,咱们也是给出了这个Reward函数。

环境编写

之后的话,咱们确认好了输入,输出之后,咱们就能够开端编写环境了。

这个首要是强化学习部分的,将咱们的TSP问题嵌入到咱们的环境里边。

"""
根据TSP规划的强化学习模拟环境
"""
import numpy as np
import math
from DDPG.BaseLine.Transform import Transform
import matplotlib.pyplot as plt
class Env(object):
    def __init__(self,Map,extend=0.2):
        """
        :param Map: 这个Map便是咱们城市的一个矩阵,是表明方位的一个矩阵
        """
        self.Map = Map
        self.city_num = len(self.Map)
        self.__matrix_distance = self.__matrix_dis()
        self.city_node = [node for node in range(self.city_num)]
        self.best_dist = float("inf")
        self.best_path = None
        self.transform = Transform()
        self.extend = int(self.city_num*extend)
        self.tolerate_threshold = 0
        self.tanh = math.tanh
    def __matrix_dis(self):
        res = np.zeros((self.city_num, self.city_num))
        for i in range(self.city_num):
            for j in range(i + 1, self.city_num):
                res[i, j] = np.linalg.norm(self.Map[i, :] - self.Map[j, :])
                res[j, i] = res[i, j]
        return res
    def draw_path(self,path):
        ## 制作初始化的途径图
        fig, ax = plt.subplots()
        x = self.Map[:, 0]
        y = self.Map[:, 1]
        ax.scatter(x, y, linewidths=0.1)
        for i, txt in enumerate(range(1, len(self.Map) + 1)):
            ax.annotate(txt, (x[i], y[i]))
        #获取头结点
        ax.cla()
        res0 = path
        x0 = x[res0]
        y0 = y[res0]
        for i in range(len(self.Map) - 1):
            plt.quiver(x0[i], y0[i], x0[i + 1] - x0[i], y0[i + 1] - y0[i], color='r', width=0.005, angles='xy', scale=1,
                       scale_units='xy')
        plt.quiver(x0[-1], y0[-1], x0[0] - x0[-1], y0[0] - y0[-1], color='r', width=0.005, angles='xy', scale=1,
                   scale_units='xy')
        plt.show()
        plt.pause(0.1)
    def comp_fit(self, one_path):
        """
        核算,咱们这个途径的长度,例如A-B-C-D
        :param one_path:
        :return:
        """
        res = 0
        for i in range(self.city_num - 1):
            res += self.__matrix_distance[one_path[i], one_path[i + 1]]
        res += self.__matrix_distance[one_path[-1], one_path[0]]
        return res
    def reset(self):
        """
        初始化环境,并且回来当时的状况
        这块首要是将当时的节点的次序给他还有这个矩阵
        :return:
        """
        max_distance = np.max(self.__matrix_distance)
        status = np.zeros((self.city_num+self.extend, self.city_num))
        status[:self.city_num,:] = (self.__matrix_distance)/(max_distance)
        return status
    def out_path(self, one_path,fitNess):
        """
        输出咱们的途径次序
        :param one_path:
        :return:
        """
        res = str(one_path[0] + 1) + '-->'
        for i in range(1, self.city_num):
            res += str(one_path[i] + 1) + '-->'
        res += str(one_path[0] + 1) + '\n'
        self.draw_path(one_path)
        print("最短道路为:",res)
        print("此刻的最短路程是:",fitNess)
    def getRoward(self,status,actions,isShow):
        """
        回来当时环境的下一个动作,以及奖赏。
        留意status和actions都是numpy类型的
        :param isShow 表明要不要输出当时最好的一个途径
        :return:
        """
        #核算当时下一个的状况
        probabilitys = self.transform.TransProbability(actions)
        #将actions,status重新转化为numpy类型
        status = status.detach().numpy()
        actions = actions.detach().numpy()
        """
        经过概率生成咱们的途径
        """
        path_out = []
        for probability in probabilitys:
            probability /= probability.sum()
            path_out.append(np.random.choice(self.city_node, (actions[0].shape), p=probability,replace=False))
        fits = []
        for path in path_out:
            fits.append(self.comp_fit(path))
        great_fits = np.argsort(fits)[:self.extend]
        great_actions = actions[great_fits,:]
        status[self.city_num:,:]=(great_actions)/(self.city_num-1)
        #核算奖赏
        great_dist = fits[great_fits[0]]
        R = self.tanh(self.best_dist-great_dist)
        if(self.best_dist>great_dist):
            self.best_dist = great_dist
            self.best_path = path_out[great_fits[0]]
        if(isShow):
            self.out_path(self.best_path,self.best_dist)
        return status,R
if __name__ == '__main__':
    data = np.array([16.47, 96.10, 16.47, 94.44, 20.09, 92.54,
                     22.39, 93.37, 25.23, 97.24, 22.00, 96.05, 20.47, 97.02,
                     17.20, 96.29, 16.30, 97.38, 14.05, 98.12, 16.53, 97.38,
                     21.52, 95.59, 19.41, 97.13, 20.09, 92.55]).reshape((14, 2))
    env = Env(data)
    print(env.reset())

那么运用到的依靠类是这个:

"""
将TSP所结构的环境进行反馈,转换,送入Actor网络以及将Actor的输出,转化为对应的序列
"""
import math
import torch
class Transform(object):
    def __init__(self):
        self.pow = math.pow
    def TransProbability(self,NetOut):
        """
        :param NetOut: 由神经网络输出的一组结果,我要将其得到一个概率
        留意NetOut是一个tensor
        :return:
        """
        Probability = torch.softmax(NetOut,dim=1)
        return Probability.detach().numpy()

这儿边还包含了可视化的一些内容。

预练习

之后的话便是咱们的预练习了。 这部分的话我不想多说了,便是强化学习那一套,把刚刚的示例图变成代码。

from DDPG.BaseLine.Env import Env
from DDPG.BaseLine.Actor import Actor
from DDPG.BaseLine.Critic import Critic
import torch
from torch import nn
import numpy as np
class DDPGTSP(object):
    """
    咱们这儿的话就直接运用cpu了,就不去运用这个GPU了
    """
    def __init__(self,Map,extend=0.2,
                 memory_capacity_critic=20,lr_actor=0.01,lr_critic=0.01,
                 epsilon=0.9,gamma=0.9,batch_size_critic=10,
                 target_replace_iter=5
                 ):
        self.Map = Map
        self.extend = extend
        self.env = Env(self.Map,extend=self.extend)
        self.memory_capacity_critic = memory_capacity_critic
        self.lr_actor = lr_actor
        self.lr_critic = lr_critic
        self.epsilon = epsilon
        self.gamma = gamma
        self.batch_size_critic = batch_size_critic
        self.target_replace_iter = target_replace_iter
        """
        创立网络,界说优化器,丢失函数等等
        """
        self.status_dim = self.actions_dim = self.env.city_num
        self.actor_eval,self.actor_target = Actor(self.status_dim,self.status_dim),\
                                            Actor(self.status_dim, self.status_dim)
        self.eval_net_critic, self.target_net_critic = Critic(self.status_dim,self.actions_dim),\
                                                       Critic(self.status_dim,self.actions_dim)
        self.opt_actor = torch.optim.Adam(self.actor_eval.parameters(), lr=self.lr_actor)
        self.opt_critic = torch.optim.Adam(self.eval_net_critic.parameters(), lr=self.lr_critic)
        self.learn_step_count = 0
        self.memory_count = 0
        """
        因为咱们输出的便是二维的,所以咱们的记忆库是三维的
        (当然也能够挑选直接打平变成二维的),可是这儿是3维的
        s,a,r,s_
        """
        self.memory = np.zeros((self.memory_capacity_critic, self.env.extend+self.env.city_num,
                                self.status_dim + self.actions_dim + self.status_dim + 1)
                               )
        self.loss_func_critic = nn.MSELoss()
    def remember(self, s, a, r, s_):
        """
        存储记忆
        :param s: 当时的状况
        :param a: 当时状况对应的动作组
        :param r: 当时的取得的奖赏
        :param s_:下一个时刻的状况
        :return:
        """
        transition = np.hstack((s, a.detach().numpy(), [[r] for _ in range(a.shape[0])], s_))
        index = self.memory_count % self.memory_capacity_critic
        self.memory[index, :] = transition
        self.memory_count += 1
    def savaMould(self, net, path):
        """
        :return:
        """
        torch.save(net.state_dict(), path)
    def loadMould(self, path_actor, path_critic):
        """
        :return:
        """
        self.actor_eval.load_state_dict(torch.load(path_actor))
        self.eval_net_critic.load_state_dict(torch.load(path_critic))
    def loadMouldActor(self, path_actor):
        """
        :return:
        """
        self.actor_eval.load_state_dict(torch.load(path_actor))
    def loadMouldCritic(self, path_critic):
        """
        :return:
        """
        self.eval_net_critic.load_state_dict(torch.load(path_critic))
    def train_cirtic(self):
        """
        负责练习咱们的critic评分网络
        :return:
        """
        self.learn_step_count += 1
        if self.learn_step_count % self.target_replace_iter == 0:
            self.target_net_critic.load_state_dict(self.eval_net_critic.state_dict())
            self.actor_target.load_state_dict(self.actor_eval.state_dict())
        SelectMemory = np.random.choice(self.memory_capacity_critic, self.batch_size_critic)
        selectM = self.memory[SelectMemory, :]
        S_s = torch.FloatTensor(selectM[:,:,:self.status_dim])
        S_a = torch.FloatTensor(selectM[:,:,self.status_dim:self.status_dim + self.actions_dim].astype(int))
        S_r = torch.FloatTensor(selectM[:,:,self.status_dim + self.actions_dim:self.status_dim + self.actions_dim + 1])
        S_s_ = torch.FloatTensor(selectM[:,:,-self.status_dim:])
        q_eval = self.eval_net_critic(S_s,S_a)
        S_a_ = self.actor_target(S_s_)
        b = torch.normal(mean=torch.full((self.batch_size_critic,self.env.extend+self.env.city_num,self.status_dim), 0.0),
                         std=torch.full((self.batch_size_critic,self.env.extend+self.env.city_num,self.status_dim), 0.5))
        S_a_ = S_a_ + b
        q_next = self.target_net_critic(S_s_,S_a_).detach()
        q_target = S_r + self.gamma * q_next.max(-1)[0].view(self.batch_size_critic,self.env.extend+self.env.city_num,1)
        loss = self.loss_func_critic(q_eval, q_target)
        self.opt_critic.zero_grad()
        loss.backward()
        self.opt_critic.step()
    def train_actor(self,status_tensor)->torch.tensor:
        """
        杂乱对actor网络进行练习
        :return:
        """
        out_actor = self.actor_eval(status_tensor)
        loss = -torch.mean(self.eval_net_critic(status_tensor,out_actor))
        self.opt_actor.zero_grad()
        loss.backward()
        self.opt_actor.step()
        return out_actor
def trainTsp(data,actor_path="./actor.pth",critic_path="./critic.pth",
                 epoch=10,iteration=1000,
                 show_iter = 200
                 ):
        """
        完结对咱们的一个DDPG的TSP问题的一个练习求解
        这儿首要便是两件工作
        1.完结咱们的一个练习
        2.得到一个模型
        :return:
        """
        ddpgTsp = DDPGTSP(data)
        for epoch in range(epoch):
            status = ddpgTsp.env.reset()
            for iter in range(iteration):
                isShow = False
                if((iter+1)%show_iter==0):
                    """
                    每30次咱们显现一下
                    """
                    print("No:", epoch, "in epoch No:", (iter + 1), "times")
                    isShow = True
                status_tensor = torch.tensor(status, dtype=torch.float, requires_grad=True)
                out_action = ddpgTsp.train_actor(status_tensor)
                next_status,reward = ddpgTsp.env.getRoward(status_tensor,out_action,isShow)
                ddpgTsp.remember(status, out_action, reward, next_status)
                if (ddpgTsp.memory_count > ddpgTsp.memory_capacity_critic):
                    ddpgTsp.train_cirtic()
                status = next_status
            print("No",epoch,"-->the best way is:", ddpgTsp.env.best_dist)
            print("No",epoch,"-->the best way is:", ddpgTsp.env.best_path)
        ddpgTsp.savaMould(ddpgTsp.actor, actor_path)
        ddpgTsp.savaMould(ddpgTsp.eval_net_critic, critic_path)
        print("Task completed, the model has been saved.Coding by Huterox fun! ")
if __name__ == '__main__':
    data = np.array([16.47, 96.10, 16.47, 94.44, 20.09, 92.54,
                     22.39, 93.37, 25.23, 97.24, 22.00, 96.05, 20.47, 97.02,
                     17.20, 96.29, 16.30, 97.38, 14.05, 98.12, 16.53, 97.38,
                     21.52, 95.59, 19.41, 97.13, 20.09, 92.55]).reshape((14, 2))
    ddpgTsp = DDPGTSP(data)
    trainTsp(ddpgTsp.Map,epoch=100,iteration=300)

模型运用

之后的话便是咱们的这个模型的运用了,因为咱们这边是相当于预练习了一个模型的,那么接下来就能够运用这个玩意来快速优化的。那么一起这部分的代码如下:

import torch
import numpy as np
from DDPG.BaseLine.Train import DDPGTSP
class TSPBaseLine(object):
    def __init__(self,data
                 ,actor_path="./actor.pth",
                 critic_path = "./critic.pth",
                 extend=0.2,
                 memory_capacity_critic=20, lr_actor=0.01, lr_critic=0.01,
                 epsilon=0.9, gamma=0.9, batch_size_critic=10,
                 target_replace_iter=5
                 ):
        self.ddpgTsp = DDPGTSP(data,extend,
                 memory_capacity_critic, lr_actor, lr_critic,
                 epsilon, gamma, batch_size_critic,
                 target_replace_iter)
        self.ddpgTsp.loadMouldActor(actor_path)
        self.ddpgTsp.loadMouldCritic(critic_path)
    def run(self,times=60):
        status = self.ddpgTsp.env.reset()
        for iter in range(times):
            isShow=False
            if((iter+1)%times==0):
                isShow=True
            status_tensor = torch.tensor(status, dtype=torch.float, requires_grad=True)
            out_action = self.ddpgTsp.train_actor(status_tensor)
            next_status, reward = self.ddpgTsp.env.getRoward(status_tensor, out_action, isShow)
            self.ddpgTsp.remember(status, out_action, reward, next_status)
            if (self.ddpgTsp.memory_count > self.ddpgTsp.memory_capacity_critic):
                self.ddpgTsp.train_cirtic()
            status = next_status
        distance = self.ddpgTsp.env.best_dist
        path = self.ddpgTsp.env.best_path
        return path,distance
if __name__ == '__main__':
    data = np.array([16.47, 96.10, 16.47, 94.44, 20.09, 92.54,
                     22.39, 93.37, 25.23, 97.24, 22.00, 96.05, 20.47, 97.02,
                     17.20, 96.29, 16.30, 97.38, 14.05, 98.12, 16.53, 97.38,
                     21.52, 95.59, 19.41, 97.13, 20.09, 92.55]).reshape((14, 2))
    tspBaseLine = TSPBaseLine(data)
    tspBaseLine.run()

一起咱们的项目结构是这样的:

轻松解决TSP问题之强化学习(BaseLine)

这儿留意到,咱们这边运用的时分仍是让它在迭代了60次才输出的,首要原因是这个玩意,练习的次数太少了,不可,并且强化学习嘛,也确实再跑的时分有那些缺点,并且是一起练习两个模型,所以的话,需求练习更久。

作用测试

轻松解决TSP问题之强化学习(BaseLine)

剖析优化

比照,遗传和PSO的话,这个作用其实更差一点。 这个最小值应该是29左右。横竖作用不是很好,这个原因的话其实也很简略,一方面是参数的设置问题,这个得慢慢来,调参大师嘛,另一个便是咱们的这个模型的感知能力的问题。

咱们这边的话其实是输入到一个二维的矩阵,所以的话,其实这个时分,咱们完全能够考虑卷积,经过卷积操作去感知。

之后的话,便是咱们一开端说的三个臭皮匠,赛过一个诸葛亮,咱们还能够在卷积的基础上,运用多智能体,这儿的话我还有一个方案也是copy PSO算法的一个思维,在多Agent的基础上引入个别间的学习,加快收敛。哈?你说CPU冒烟了,不好意思听不见!