import cv2
import math
import random
import numpy as np
import matplotlib.pyplot as plt
import time
import tensorflow as tf
from tensorflow import keras
import torch
import torch.nn as nn
import torch.nn.functional as F
 #想和大神交朋友或想软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"或公#众#号:"卧看星河"。
N_ACTIONS = 8

lr, EPSILON_0, EPSILON_f, beta, N = 0.1, 0.9, 0.01, 0.5, 100  #2000
episode_number, n = N, 50  # 50
MEMORY_CAPACITY = 1000  # 50
TARGET_REPLACE_ITER = 100
BATCH_SIZE = 32
TARGET_UPDATE_FREQ = 200

ng = 0  #初始贪婪动作数

# 载入栅格图
def load_grid(data_dir):
    grid = np.load(data_dir)
    grid = np.where(grid == 0, 0, -1)  # 根据条件map==0,为true时(满足)输出0,否则输出-1
    grid[0,0], grid[-1, -1] = 1, 1

    # 需要清除的障碍物坐标列表
    obstacles_to_clear = []
    # obst1
    obst1 = []
    for ox in range(8, 10 + 1):  # (2, 8)
        for oy in range(2, 9 + 1):
            obst1.append((oy, ox))
    # print(obst1)
    # obst2
    obst2 = []
    obst2_site = [(3, 30), (3, 30 + 1), (4, 31), (4, 31 + 1), (5, 32), (5, 32 + 1),
                  (6, 33)]  # (3, 30), (4, 31), (5, 32), (6, 33)
    for obst22 in obst2_site:
        ox = obst22[1] + 1
        for oy in range(obst22[0], obst22[0] + 29 + 1):
            ox -= 1
            obst2.append((oy, ox))
    # print(obst2)
    # obst3
    obst3 = []
    obst3_site = [(23, 42), (23, 42 + 1), (24, 43), (24, 43 + 1), (25, 44), (25, 44 + 1), (26, 45)]
    for obst33 in obst3_site:
        ox = obst33[1] + 1
        for oy in range(obst33[0], obst33[0] + 23 + 1):
            ox -= 1
            obst3.append((oy, ox))
    # print(obst3)
    obstacles_to_clear.extend(obst1)
    obstacles_to_clear.extend(obst2)
    obstacles_to_clear.extend(obst3)

    # 循环批量将障碍物坐标标记为可通行状态
    for obstacle in obstacles_to_clear:
        grid[obstacle] = 0

    return grid

start_time = time.time()  # 记录开始时间

class Structure_Env():
    # 可用行点 0 障碍物点 -1 起始点  终点  当前运动位置点 1
    def __init__(self, grid_data):
        super(Structure_Env, self).__init__()
        self.action_space = ['u', 'ru', 'r', 'rd', 'd', 'ld', 'l', 'lu']
        # self.n_actions = len(self.action_space)
        self.grid_data = grid_data
        self.size = self.grid_data.shape[0]
        # 绘制最终路径的字典
        self.d, self.f, self.r_0 = {}, {}, 0  # 1000  目标点
        self.r_obst = -100  # -100  撞壁
        self.r_ed = -10  # -10  遍历过的点
        #self.r_ = -0.01 * d_R_G    # 其他
        # 字典的 Key
        self.j = 0
        # 首次填写字典(达到目标点)
        self.c = True
        # 最长路径的步数
        self.longest = 0
        # 最短路径的步数⭐
        self.shortest = 0
    def grid(self):
        self.display = np.ones((600, 600, 3), dtype=np.uint8) * 255
        for i in range(self.size + 1):
            cv2.line(self.display, (int(i * 600 / self.size), 0),
                     (int(i * 600 / self.size), 600), (0, 0, 0), 1)
            cv2.line(self.display, (0, int(i * 600 / self.size)),
                     (600, int(i * 600 / self.size)), (0, 0, 0), 1)
        # 障碍点
        for x in range(self.size):
            for y in range(self.size):
                if self.grid_data[y][x] == -1:
                    cv2.rectangle(
                        self.display,
                        (int(x * 600 / self.size), int(y * 600 / self.size)),
                        (int((x + 1) * 600 / self.size),
                         int((y + 1) * 600 / self.size)), (0, 0, 0), -1)
        # 起始点 start    绿
        cv2.rectangle(self.display,
                    (0, 0),
                    (int((0 + 1) * 600 / self.size),
                    int((0 + 1) * 600 / self.size)), (0, 255, 0), -1)
        # 目标点 goal    红
        cv2.rectangle(self.display,
                    (int((self.size - 1) * 600 / self.size),
                    int((self.size - 1) * 600 / self.size)),
                    (int((self.size) * 600 / self.size),
                    int((self.size) * 600 / self.size)), (0, 0 , 255), -1)
        cv2.imshow('grid', self.display)
        cv2.waitKey(1)

    def move(self, state):
        #state = state.cpu().detach().numpy()
        (y, x) = state
        # 保存当前移动点的位置,以便下一次清除
        self.prev_x, self.prev_y = x, y
        # 清除上一个移动点的位置
        cv2.rectangle(
            self.display,
            (int(self.prev_x * 600 / self.size), int(self.prev_y * 600 / self.size)),
            (int((self.prev_x + 1) * 600 / self.size),
             int((self.prev_y + 1) * 600 / self.size)), (255, 236, 139), -1)

        # 更新移动点的位置
        cv2.rectangle(
            self.display,
            (int(x * 600 / self.size), int(y * 600 / self.size)),
            (int((x + 1) * 600 / self.size),
             int((y + 1) * 600 / self.size)), (238,220,130), -1)

        # 起始点 start    绿
        cv2.rectangle(self.display,
                      (0, 0),
                      (int((0 + 1) * 600 / self.size),
                       int((0 + 1) * 600 / self.size)), (0, 255, 0), -1)


        cv2.imshow('grid', self.display)
        cv2.waitKey(1)  # 等待1毫秒后继续执行

    def reset(self):
        self.reward = 0
        self.grid_data[self.grid_data > 1] = 0
        self.grid_data[0, 0] = 4
        self.state_0 = (0, 0)
        return (self.state_0)
        # return (self.y, self.x)   # (纵,横) → (行,列)

    # 动作
    def step(self, action, state):
        # 转换回 NumPy 数组
        #state = state.cpu().detach().numpy()
        # ['u'0, 'ru'1, 'r'2, 'rd'3, 'd'4, 'ld'5, 'l'6, 'lu'7 ]
        scaling_factor, miu, goal_state = 0.1, 5, (self.size - 1, self.size - 1)
        change = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]]
        self.x1 = min(self.size - 1, max(0, state[1] + change[int(action)][0]))
        self.y1 = min(self.size - 1, max(0, state[0] + change[int(action)][1]))
 #想和大神交朋友或想软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"或公#众#号:"卧看星河"。
        # 两点间的欧氏距离
        self.s_ = np.array((self.y1, self.x1))
        self.goal_s = np.array(goal_state)
        self.d_R_G = np.sqrt(np.sum(np.square(self.s_ - self.goal_s)))
        self.r_ = -0.01 * self.d_R_G  # 其他
        current_position = np.array([self.y1, self.x1])

        # 若碰撞边界/碰撞障碍物,则会与上一状态相同,返回原位
        if np.array_equal(current_position, state) or self.grid_data[self.y1][self.x1] == -1:    ###########################
            self.r_H = self.r_obst
            self.done = False
            self.next_s = state
            # self.d = {}
            # self.i = 0
        # 斜行⭐
        elif (action % 2) == 1:  # 动作数为奇数
            self.x_0 = min(self.size - 1, max(0, state[1] + change[0][0]))  # 列
            self.y_0 = min(self.size - 1, max(0, state[0] + change[0][1]))  # 行
            self.x_2 = min(self.size - 1, max(0, state[1] + change[2][0]))
            self.y_2 = min(self.size - 1, max(0, state[0] + change[2][1]))
            self.x_4 = min(self.size - 1, max(0, state[1] + change[4][0]))
            self.y_4 = min(self.size - 1, max(0, state[0] + change[4][1]))
            self.x_6 = min(self.size - 1, max(0, state[1] + change[6][0]))
            self.y_6 = min(self.size - 1, max(0, state[0] + change[6][1]))
            # 约束条件,旁边有障碍时禁止斜行
            if action == 1:
                #  斜行时有障碍物则不动作回原位
                if (self.grid_data[self.y_0][self.x_0] == -1) or (self.grid_data[self.y_2][self.x_2] == -1):
                    self.r_H = self.r_obst
                    self.done = False
                    self.next_s = state  # 'obstacle'
                    # 清空字典和 i
                    # self.d = {}
                    # self.i = 0
                #  遍历过下一状态点,回原位不动作
                elif self.grid_data[self.y1][self.x1] == 4:
                    self.r_H = self.r_ed
                    self.done = False
                    self.next_s = (self.y1, self.x1)
                else:
                    self.r_H = self.r_   #scaling_factor * math.exp(-miu * self.d_R_G)
                    self.next_s = (self.y1, self.x1)
                    self.done = False
                    self.grid_data[self.y1][self.x1] = 4

            if action == 3:
                if (self.grid_data[self.y_4][self.x_4] == -1) or (self.grid_data[self.y_2][self.x_2] == -1):
                    self.r_H = self.r_obst
                    self.done = False
                    self.next_s = state  # 'obstacle'

                elif self.grid_data[self.y1][self.x1] == 4:
                    self.r_H = self.r_ed
                    self.done = False
                    self.next_s = (self.y1, self.x1)
                else:
                    self.r_H = self.r_   #scaling_factor * math.exp(-miu * self.d_R_G)
                    self.next_s = (self.y1, self.x1)
                    self.done = False
                    self.grid_data[self.y1][self.x1] = 4

            if action == 5:
                if (self.grid_data[self.y_4][self.x_4] == -1) or (self.grid_data[self.y_6][self.x_6] == -1):
                    self.r_H = self.r_obst
                    self.done = False
                    self.next_s = state  # 'obstacle'

                elif self.grid_data[self.y1][self.x1] == 4:
                    self.r_H = self.r_ed
                    self.done = False
                    self.next_s = (self.y1, self.x1)
                else:
                    self.r_H = self.r_   #scaling_factor * math.exp(-miu * self.d_R_G)
                    self.next_s = (self.y1, self.x1)
                    self.done = False
                    self.grid_data[self.y1][self.x1] = 4

            if action == 7:
                if (self.grid_data[self.y_0][self.x_0] == -1) or (self.grid_data[self.y_6][self.x_6] == -1):
                    self.r_H = self.r_obst
                    self.done = False
                    self.next_s = state  # 'obstacle'

                elif self.grid_data[self.y1][self.x1] == 4:
                    self.r_H = self.r_ed
                    self.done = False
                    self.next_s = (self.y1, self.x1)
                else:
                    self.r_H = self.r_   #scaling_factor * math.exp(-miu * self.d_R_G)
                    self.next_s = (self.y1, self.x1)
                    self.done = False
                    self.grid_data[self.y1][self.x1] = 4

            # 若碰撞边界,返回原位
            for m in range(N_ACTIONS):
                if action != m:  # 已选动作与循环动作不同
                    self.xm = min(self.size - 1, max(0, state[1] + change[int(m)][0]))
                    self.ym = min(self.size - 1, max(0, state[0] + change[int(m)][1]))
                    if (self.y1, self.x1) == (self.ym, self.xm):  # 所选动作与循环动作在移动后状态相同,表示超过边界
                        self.r_H = self.r_obst
                        self.done = False
                        self.next_s = state

        # 直行
        elif (action % 2) != 1:
            # 动作后区域遍历过
            if self.grid_data[self.y1][self.x1] == 4:
                self.r_H = self.r_ed
                self.done = False
                self.next_s = (self.y1, self.x1)
            else:
                self.r_H = self.r_   #scaling_factor * math.exp(-miu * self.d_R_G)
                self.next_s = (self.y1, self.x1)
                self.done = False
                self.grid_data[self.y1][self.x1] = 4

        # 达到目标点
        if np.array_equal(current_position, (self.size - 1, self.size - 1)):  # self.next_s == (self.size, self.size):
            self.r_H = self.r_0
            self.done = True

        return self.r_H, self.next_s, self.d_R_G, self.done  # (行,列)

    def update(self, i, done, next_sta):
        # 将找到的路线坐标写入字典
        self.d[i] = next_sta

        if done:
            # 如果是第一次找到路径,或者找到了新的最短路径
            if self.c or len(self.d) < self.shortest:
                # 更新最短路径信息
                self.shortest = len(self.d)
                # 更新最短路径
                self.f = dict(self.d)
                self.longest = len(self.d)  # 更新最长路径

            # 如果找到了新的最长路径
            elif len(self.d) > self.longest:
                # 更新最长路径信息
                self.longest = len(self.d)

            # 第一次找到路径后,将 c 置为 False
            if self.c:
                self.c = False
# 显示搜索到的路径
    def final(self):
        print('最短路径:', self.shortest)
        print('最长路径:', self.longest)


def trans_torch(data):
    return np.array(data)

#神经网络
class Net(nn.Module):  # 三层全连接

    def __init__(self):
        super(Net, self).__init__()
        self.f1 = nn.Linear(2, 32)
        self.f2 = nn.Linear(32, 16)
        #优势流 f3
        self.advantage_stream = nn.Linear(16, 8)
        #值流
        self.value_stream = nn.Linear(16, 1)
        self.init_params()
    def init_params(self):
        for sub_model in self.modules():
            if isinstance(sub_model, nn.Conv2d):
                nn.init.kaiming_normal_(sub_model.weight, mode='fan_out')
                if sub_model.bias is not None:
                    nn.init.constant_(sub_model.bias, 0)
            elif isinstance(sub_model, nn.Linear):
                nn.init.normal_(sub_model.weight, std=0.001)
                if sub_model.bias is not None:
                    nn.init.constant_(sub_model.bias, 0)
    def forward(self, x):
        x = F.relu(self.f1(x))
        action = F.relu(self.advantage_stream(F.relu(self.f2(x))))
        value = F.relu(self.value_stream(F.relu(self.f2(x))))
        # 组合值和优势
        q_values = value + (action - action.mean(dim=1, keepdim=True))  # 对抗架构
        return q_values  # action


# Heuristic SA-Dyna-Q
class D3QN:
    def __init__(self, size):
         self.discount_fact=0.95
         self.size = size
         self.eval_net, self.target_net = Net(), Net()  # DQN需要使用两个神经网络
         self.learn_step_counter = 0  # 用于target更新计时,100次更新一次
         self.memory_counter = 0  # 记忆库记数
         self.memory = list(np.zeros((MEMORY_CAPACITY, 4)))  # 初始化记忆库
         self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=lr)  # torch 的优化器
         self.loss_func = nn.MSELoss()  # 均方误差公式

    def choose_action(self, state, k):    # state_i 第几个状态
        state = torch.unsqueeze(torch.FloatTensor(state), 0)
        self.EPSILON_k= EPSILON_f + (( EPSILON_0 - EPSILON_f)/( 1 + math.exp(beta * ( k - N/2))))   # 第k次迭代
        # 这里只输入一个 sample,x为场景
        if np.random.uniform() < self.EPSILON_k:
           self.action = np.array([np.random.randint(0, N_ACTIONS)
                               ])  # 比如np.random.randint(0,2)是选择1或0
        else:
            q_values= self.eval_net.forward(state)  # 将场景输入Q估计神经网络
            self.action = torch.max(q_values, 1)[1].data.numpy()  # 返回动作最大值及其索引   输出每一行最大值的索引,并转化为numpy ndarray形式
        return self.action

    def store_transition(self, s, a, r, s_):
        index = self.memory_counter % MEMORY_CAPACITY  # 确定在buffer中的行数    记忆库记数%5000
        self.memory[index] = [s, a, r, s_]
        self.memory_counter += 1

    def learn(self):
        # target net 参数更新,每100次
        if self.learn_step_counter % TARGET_REPLACE_ITER == 0:
            self.target_net.load_state_dict(self.eval_net.state_dict())  #load
        self.learn_step_counter += 1

        sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE)
        b_s = []
        b_a = []
        b_r = []
        b_s_ = []
        for i in sample_index:
            b_s.append(self.memory[i][0])   #添加
            b_a.append(np.array(self.memory[i][1], dtype=np.int32))
            b_r.append(np.array([self.memory[i][2]], dtype=np.int32))
            b_s_.append(self.memory[i][3])
        b_s = torch.FloatTensor(np.array(b_s))  # 取出s   类型转换, 将list ,numpy转化为tensor。
        b_a = torch.LongTensor(np.array(b_a))  # 取出a     表示包含整数(整型数据)的张量(tensor)
        b_r = torch.FloatTensor(np.array(b_r))  # 取出r
        b_s_ = torch.FloatTensor(np.array(b_s_))  # 取出s_
        q_eval = self.eval_net(b_s).gather(1, b_a)  #  shape (batch, 1) 找到action的Q估计(关于gather使用下面有介绍)   根据索引找值

        #q_next = self.target_net(b_s_).detach()  # q_next 不进行反向传递误差, 所以 detach Q_target    detach:返回一个新的 Tensor  ###?????
        #q_target = b_r + self.discount_fact * q_next.max(1)[0].unsqueeze(1)
        # 使用目标网络计算最大优势值
        q_target_next = self.target_net(b_s_)
        # 分离状态值和优势值
        v_next = q_target_next.mean(dim=1, keepdim=True)  # 计算状态值
        a_next = q_target_next - v_next  # 计算优势值
        q_target_next = v_next + a_next.max(1)[0].unsqueeze(1)  # 计算目标 Q 值
        # 计算目标 Q 值
        q_target = b_r + self.discount_fact * q_target_next  # shape (batch, 1)
        loss = self.loss_func(q_eval, q_target)  #计算误差
        # 计算, 更新 eval net
        self.optimizer.zero_grad()  # 把梯度置零
        loss.backward()  # 反向传播求梯度
        self.optimizer.step()  # 更新所有参数
    def update_target_network(self):
        # 将在线网络的权重复制到目标网络
        self.target_net.load_state_dict(self.eval_net.state_dict())

    # 绘制结果
    def plot_results(self, steps, all_reward):
        # plt.tight_layout()  # 调整图之间的距离
        # Steps
        plt.figure()
        plt.plot(np.arange(len(steps)), steps, color='#FFC125')
        plt.title('Episode via steps')
        plt.xlabel('Episode')
        plt.ylabel('Steps')

        # Reward
        plt.figure()
        plt.plot(np.arange(len(all_reward)), all_reward, color='#8EE5EE')
        plt.title('Episode via reward')
        plt.xlabel('Episode')
        plt.ylabel('Reward')

        # 显示图
        plt.show()



if __name__ == "__main__":
    model ={}   # dict() 初始化模型
    grid_dir = r"./50-15.npy"  # 50-15  10-10
    grid = load_grid(grid_dir)
    env = Structure_Env(grid)
    d3qn = D3QN(size=env.size)
    # 记录结果
    all_accomplish=0  # 训练完成后,抵达目标总数
    accomplish = 0  # 实现目标次数
    all_reward = []  # 结果列表中所有 episodes 的总奖励
    steps = []  # 绘制结果列表中所有 episodes 的 steps

    k = 0

    for k in range(episode_number):

        env.grid()  # 初始化窗口(生成栅格)
        state = env.reset()    # 初始化state  消除智能体痕迹
        state = trans_torch(state)      # map = trans_torch(map)
        i = 0  # 初始步数
        r_t = 0  # 初始奖励
        accumulate_r = 0  # 累计奖励
        # state_i = 0  # 当前位置对应的 Q 表行数
        for step in range(5000):
        #while True:
            env.move(state)   # 移动
            action = d3qn.choose_action(state, k)  # 选择动作
            r_t, next_state, d_R_G, done = env.step(action, state)  # env.step(action)
            next_state = trans_torch(next_state)
            env.update(i, done, next_state)  # 将新状态写入 d 字典
            # 存记忆
            d3qn.store_transition(state, action, r_t, next_state)  # map → state
            if d3qn.memory_counter > MEMORY_CAPACITY :
                d3qn.learn()  # 记忆库满了就进行学习
                # 每隔一定步数更新目标网络
                if k % TARGET_UPDATE_FREQ == 0:  # TARGET_UPDATE_FREQ 是预设的更新频率
                    d3qn.update_target_network()
            # 累计当前Episode的 Steps数
            i += 1
            # 从状态转变中学习并计算奖励
            accumulate_r += r_t
            # update
            state = next_state

            # 成功次数
            if d_R_G == 0:
               accomplish += 1

            # 当 agent 到达目标时, 记录当前总步数和总奖励
            if done:
                steps += [i]
                all_reward += [accumulate_r]
                break

        k = k + 1  # 训练次数
        print(k)

    # 成功率
    all_accomplish += accomplish
    print('成功率:', all_accomplish/episode_number*100, '%')

    # 显示最终路径
    env.final()
    # 将Q表保存为.npy文件 
    #np.save('nnew1111111122.npy', dqn.q_eval)
    # 绘制结果
    print(steps)
    print(all_reward)
    d3qn.plot_results(steps, all_reward)

end_time = time.time()  # 记录结束时间
elapsed_time = end_time - start_time  # 计算经过的时间
print(f"代码运行时间: {elapsed_time} 秒")
print(f"训练的运行时间: {elapsed_time:.2f}秒")
 #想和大神交朋友或想软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"或公#众#号:"卧看星河"。

这段 Python 代码实现了一个基于深度确定性策略梯度(Deep Deterministic Policy Gradient,DDPG)算法的智能体在一个二维网格环境中的路径规划任务。具体功能如下:

一、环境设置与初始化

  • 导入了所需的 Python 库,包括 cv2(用于图像处理和显示)、math、random、numpy、matplotlib.pyplot、time、tensorflow、torch 等。
  • 定义了一些常量,如 N_ACTIONS(动作空间大小)、lr(学习率)、EPSILON_0(初始探索率)、EPSILON_f(最终探索率)、beta(探索率衰减参数)、N(总训练步数)、episode_number(训练的 episodes 数)、MEMORY_CAPACITY(记忆库容量)、TARGET_REPLACE_ITER(目标网络更新间隔)、BATCH_SIZE(每次更新的批量大小)和 TARGET_UPDATE_FREQ(目标网络更新频率)。
  • 定义了 load_grid 函数,用于加载网格地图数据,并对地图中的障碍物进行处理,将可通行的障碍物位置标记为 0。
  • 创建了 Structure_Env 类,用于表示环境。在环境类中,初始化了动作空间、网格数据、环境大小等属性。定义了 grid 方法用于绘制网格环境,move 方法用于在环境中移动智能体的位置并显示,reset 方法用于重置环境状态,step 方法用于执行一个动作,根据动作和环境状态计算奖励、下一个状态、欧氏距离和是否结束等信息,update 方法用于更新找到的路径信息,final 方法用于显示最终的路径信息。
  • 定义了 trans_torch 函数,用于将数据转换为 PyTorch 的张量形式。

二、神经网络定义

  • 定义了 Net 类,继承自 nn.Module,这是 PyTorch 中定义神经网络的基类。在 Net 类的 __init__ 方法中,定义了网络的结构,包括两个全连接层 f1 和 f2,以及分别用于计算优势流和值流的两个线性层 advantage_stream 和 value_stream。还使用 init_params 方法初始化网络参数。forward 方法用于定义前向传播过程,通过一系列的 ReLU 激活函数和线性变换,最终计算出 Q 值。

三、D3QN 类实现

  • 定义了 D3QN 类,用于实现 DDPG 算法。在 __init__ 方法中,初始化了折扣因子 discount_fact、环境大小 size,创建了评估网络 eval_net 和目标网络 target_net,初始化了学习步数计数器 learn_step_counter、记忆库计数器 memory_counter 和记忆库 memory,创建了优化器 optimizer 和损失函数 loss_func。
  • choose_action 方法根据当前状态和训练步数选择动作,使用了 ϵ\epsilonϵ-贪婪策略,在一定概率下进行随机探索,否则根据评估网络选择动作。
  • store_transition 方法用于将状态、动作、奖励和下一个状态存储到记忆库中。
  • learn 方法用于进行网络的学习和训练,每隔一定步数更新目标网络,从记忆库中随机采样一批数据,计算 Q 值估计和目标 Q 值,使用均方误差损失函数计算损失,并通过反向传播和优化器更新评估网络的参数。
  • update_target_network 方法用于将评估网络的参数复制到目标网络中,实现目标网络的更新。
  • plot_results 方法用于绘制训练过程中的步数和奖励随训练步数的变化曲线。

四、主程序流程

  • 在主程序中,首先创建了一个空的字典 model,用于存储模型相关信息(在代码中未实际使用)。
  • 加载网格地图数据 grid,创建 Structure_Env 环境实例 env 和 D3QN 模型实例 d3qn。
  • 初始化一些记录变量,如 all_accomplish(训练完成后抵达目标的总数)、accomplish(实现目标的次数)、all_reward(所有 episodes 的总奖励)和 steps(所有 episodes 的步数)。
  • 开始进行训练循环,对于每个 episode:
    • 调用 env.grid 方法绘制网格环境。
    • 调用 env.reset 方法重置环境状态。
    • 初始化步数 i、奖励 r_t 和累计奖励 accumulate_r。
    • 在每个时间步中:
      • 调用 env.move 方法移动智能体位置并显示。
      • 调用 d3qn.choose_action 方法根据当前状态选择动作。
      • 调用 env.step 方法执行动作,更新环境状态、奖励、欧氏距离和是否结束等信息,并将新状态写入路径字典。
      • 调用 d3qn.store_transition 方法将状态、动作、奖励和下一个状态存储到记忆库中。
      • 如果记忆库已满,调用 d3qn.learn 方法进行网络学习和训练,并根据设定的频率更新目标网络。
      • 累计当前 episode 的步数 i 和奖励 accumulate_r。
      • 判断是否到达目标,如果到达目标,将当前步数和累计奖励添加到相应的列表中,并跳出循环。
  • 计算成功率,即成功到达目标的次数占总训练次数的比例。
  • 调用 env.final 方法显示最终的路径信息。
  • 绘制训练结果的步数和奖励曲线,使用 d3qn.plot_results 方法。
  • 记录代码运行的开始时间和结束时间,计算运行时间并打印输出。

总的来说,这段代码实现了一个基于深度神经网络的智能体在二维网格环境中的探索和学习过程,通过不断与环境交互,优化网络参数,以找到从起始位置到目标位置的最短路径,同时还记录了训练过程中的奖励和步数等信息,并进行了可视化展示。 想和大神交朋友或想软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"或公#众#号:“卧看星河”。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐