主頁 >  其他 > (pytorch復現)基于深度強化學習(CNN+dueling network/DQN/DDQN/D3QN)的自適應車間調度(JSP)

(pytorch復現)基于深度強化學習(CNN+dueling network/DQN/DDQN/D3QN)的自適應車間調度(JSP)

2021-12-28 07:27:56 其他

為了深入學習各種深度學習網路和強化學習的結合,實作了一下下列文章:

Research on Adaptive Job Shop Scheduling Problems Based on Dueling Double DQN | IEEE Journals & Magazine | IEEE Xplore

狀態、動作、獎勵函式及實驗的簡單介紹可參考:

基于深度強化學習的自適應作業車間調度問題研究_松間沙路的博客-CSDN博客_強化學習調度

整體代碼復現可見個人Github:Aihong-Sun/DQN-DDQN-Dueling_networ-D3QN-_for_JSP: pytorch implementation of DQN/DDQN/Dueling_networ/D3QN for job shop scheudling problem (github.com)

1 狀態特征提取

首先從特征提取開始,原文的狀態特征為3個網格矩陣,如下:

于是搭建CNN進行特征提取:

不太了解CNN的可以參考:卷積神經網路(CNN)詳解 - 知乎 (zhihu.com)

self.conv1=nn.Sequential(
            nn.Conv2d(
                in_channels=3,  
                out_channels=6,
                kernel_size=3,
                stride=1,
                padding=1,  
            ),      # output shape (3,J_num,O_max_len)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2,ceil_mode=False)  
        )

1.1 卷積層

上訴狀態可看作是長、寬為工件數、工件最大工序數(若不相等時取最大,但原文涉及的算例都為工序數相等),深度為3的一個影像,于是in_channels=3,out_channels可按自己的需求進行設計,這里我設為6,即有6個卷積核,輸出的影像的深度就為6,為保證圖片的長寬不變(便于后面針對不同工件數、工序數的全連接層的計算),用0在影像邊緣處進行填充,計算方法如下:

假設Jnum=6,O_max_len=6,于是,令卷積核kernel_size=3,stride=1,padding=1,此時,W2=(6-3+2)/1+1=6,H2=(6-3+2)/1+1=6,于是圖片大小沒變,

1.2 池化層

它的作用是用來逐漸降低資料體的空間尺寸,這樣的話就能減少網路中引數的數量,使得計算資源耗費變少,也能有效控制過擬合,

池化層使用 MAX 操作,對輸入資料體的每一個深度切片獨立進行操作,改變它的空間尺寸,最常見的形式是匯聚層使用尺寸2x2的濾波器,以步長為2來對每個深度切片進行降采樣,

這里設定kernel_size=2,即對影像縮小一般,ceil_mode=False,即針對工件為奇數的情況,比如Jnum=7,Omax_len=7,影像縮小邊緣的數則不取,于是生成新的影像大小為(3,3),若ceil_mode=False,生成新的影像大小則為(4,4).

2 動作

動作為17條規則,具體可見上訴給出的個人Github

3DQN/DDQN/Dueling Network/D3QN

3.1 DQN與DDQN

下面第一個式子為DQN的目標函式,第二個式子為DDQN的目標函式:

DDQN與DQN大部分都相同,只有一步不同,那就是在選擇Q(s_{t+1},a_{t+1})的程序中,DQN總是選擇Target Q網路的最大輸出值,而DDQN不同,DDQN首先從Q網路中找到最大輸出值的那個動作,然后再找到這個動作對應的Target Q網路的輸出值,這么做的原因是傳統的DQN通常會高估Q值得大小,兩者代碼差別如下:

 if self.double:      #當為DQN時
            # q_eval
            q_eval = self.eval_net(batch_state).gather(1, batch_action)
            q_next_eval=self.eval_net( batch_next_state).detach()
            q_next = self.target_net(batch_next_state).detach()
            q_a=q_next_eval.argmax(dim=1)
            q_a=torch.reshape(q_a,(-1,len(q_a)))
            q_target = batch_reward + self.GAMMA * q_next.gather(1, q_a)
        else:       #當為DDQN時
            #q_eval
            q_eval = self.eval_net(batch_state).gather(1,batch_action)
            q_next = self.target_net(batch_next_state).detach()
            q_target = batch_reward + self.GAMMA * q_next.max(1)[0].view(self.BATCH_SIZE, 1)

        loss = self.loss_func(q_eval, q_target)

        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

3.2 DQN 與Dueling Network

Dueling network 是一篇來自2015年的論文,這篇論文提出了一個新的網路架構,這個架構不但提高了最終效果,而且還可以和其他的演算法相結合以獲取更加優異的表現,

之前的DQN網路在將圖片卷積獲取特征之后會輸入幾個全連接層,經過訓練直接輸出在該state下各個action的價值也就是Q(s,a),而Dueling network則不同,它在卷積網路之后引出了兩個不同的分支,一個分支用于預測state的價值,另一個用于預測每個action的優勢,最后將這兩個分支的結果合并輸出Q(s,a),兩者的網路結構如下(上為DQN,下為Dueling network)

代碼上的區別:

DQN:

class CNN_FNN(nn.Module):
    """docstring for Net"""
    def __init__(self,J_num,O_max_len):
        super(CNN_FNN, self).__init__()
        # summary(self.conv1,(3,6,6))
        self.fc1 = nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)
        self.fc2 = nn.Linear(258,258)
        self.out = nn.Linear(258,17)

    def forward(self,x):
        x=self.conv1(x)
        x=x.view(x.size(0),-1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.relu(x)
        action_prob = self.out(x)
        return action_prob

Dueling Network:

class CNN_dueling(nn.Module):
    def __init__(self,J_num,O_max_len):
        super(CNN_dueling, self).__init__()
        self.conv1=nn.Sequential(
            nn.Conv2d(
                in_channels=3,  #input shape (3,J_num,O_max_len)
                out_channels=6,
                kernel_size=3,
                stride=1,
                padding=1,  #使得出來的圖片大小不變P=(3-1)/2,
            ),      # output shape (3,J_num,O_max_len)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2,ceil_mode=False)  #output shape:  (6,int(J_num/2),int(O_max_len/2))
        )
        # summary(self.conv1,(3,6,6))
        self.val_hidden = nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)
        self.adv_hidden=nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)

        self.val=nn.Linear(258,1)
        self.adv = nn.Linear(258,17)

    def forward(self,x):
        x=self.conv1(x)
        x=x.view(x.size(0),-1)

        val_hidden = self.val_hidden(x)
        val_hidden = F.relu(val_hidden)

        adv_hidden = self.adv_hidden(x)
        adv_hidden = F.relu(adv_hidden)

        val = self.val(val_hidden)
        adv = self.adv(adv_hidden)

        adv_ave = torch.mean(adv, dim=1, keepdim=True)
        x = adv + val - adv_ave
        return x

Dueling架構的好處:

(1)Dueling network與DQN最主要的不同就是將State與action進行了一定程度的分離,雖然最終的輸出依然相同,但在計算的程序中,state不再完全依賴于action的價值來進行判斷,可以進行單獨的價值預測,這其實是十分有用的,模型既可以學習到某一個state的價值是多少,也可以學習到在該state下不同action的價值是多少,它可以對環境中的state和action進行相對獨立而又緊密結合的觀察學習,可以進行更靈活的處理,同時在某些state中,action的選擇并不會對state產生影響,這時候Dueling模型就可以有更加強大的表現,

(2)在具有多個冗余或者近似的動作時,Dueling可以比DQN更快的識別出策略中的正確操作,

作者在論文中給出了兩個不同的改進公式,需要提前說明的是,這兩個公式的最終效果是類似的,都可以使用:

不同點在于,第一個公式是每一個A都減去A的最大值,第二個公式是每一個A都減去A的平均值,這樣即使V和A都分別加減同樣的的常數,最終的結果也不會相同,

3.3 D3QN

D3QN(Dueling Double DQN)是結合了Dueling DQN和Double DQN的優點,

4 調參及相關說明

關于這種自定義環境,收斂是需要通過不斷調參實作的,之前看到一篇文章比較好的講了調參程序,大家可以參考一下:

啟人zhr:強化學習中的調參經驗與編程技巧(on policy 篇)

5 部分代碼展示

5.1 JSP_Env.py

import copy
import matplotlib.pyplot as plt
import numpy as np

def Gantt(Machines):
    plt.rcParams['font.sans-serif'] = ['Times New Roman']  # 如果要顯示中文字體,則在此處設為:SimHei
    plt.rcParams['axes.unicode_minus'] = False  # 顯示負號
    M = ['red', 'blue', 'yellow', 'orange', 'green', 'palegoldenrod', 'purple', 'pink', 'Thistle', 'Magenta',
         'SlateBlue', 'RoyalBlue', 'Cyan', 'Aqua', 'floralwhite', 'ghostwhite', 'goldenrod', 'mediumslateblue',
         'navajowhite', 'navy', 'sandybrown', 'moccasin']
    Job_text = ['J' + str(i + 1) for i in range(100)]
    Machine_text = ['M' + str(i + 1) for i in range(50)]

    for i in range(len(Machines)):
        for j in range(len(Machines[i].start)):
            if Machines[i].finish[j] - Machines[i].start[j]!= 0:
                plt.barh(i, width=Machines[i].finish[j] - Machines[i].start[j],
                         height=0.8, left=Machines[i].start[j],
                         color=M[Machines[i]._on[j]],
                         edgecolor='black')
                plt.text(x=Machines[i].start[j]+(Machines[i].finish[j] - Machines[i].start[j])/2 - 0.1,
                         y=i,
                         s=Job_text[Machines[i]._on[j]],
                         fontsize=12)
    plt.show()

class Machine:
    def __init__(self,idx):
        self.idx=idx
        self.start=[]
        self.finish=[]
        self._on=[]
        self.end=0

    def handling(self,Ji,pt):
        s=self.insert(Ji,pt)
        # if self.end<=Ji.end:
        #     s=Ji.end
        # else:
        #     s=self.end
        e=s+pt
        self.start.append(s)
        self.finish.append(e)
        self.start.sort()
        self.finish.sort()
        self._on.insert(self.start.index(s),Ji.idx)
        if self.end<e:
            self.end=e
        Ji.update(s,e)

    def Gap(self):
        Gap=0
        if self.start==[]:
            return 0
        else:
            Gap+=self.start[0]
            if len(self.start)>1:
                G=[self.start[i+1]-self.finish[i] for i in range(0,len(self.start)-1)]
                return Gap+sum(G)
            return Gap

    def judge_gap(self,t):
        Gap = []
        if self.start == []:
            return Gap
        else:
            if self.start[0]>0 and self.start[0]>t:
                Gap.append([0,self.start[0]])
            if len(self.start) > 1:
                Gap.extend([[self.finish[i], self.start[i + 1]] for i in range(0, len(self.start) - 1) if
                            self.start[i + 1] - self.finish[i] > 0 and self.start[i + 1] > t])
                return Gap
            return Gap

    def insert(self,Ji,pt):
        start=max(Ji.end,self.end)
        Gap=self.judge_gap(Ji.end)
        if Gap!=[]:
            for Gi in Gap:
                if Gi[0]>=Ji.end and Gi[1]-Gi[0]>=pt:
                    return Gi[0]
                elif Gi[0]<Ji.end and Gi[1]-Ji.end>=pt:
                    return Ji.end
        return start

class Job:
    def __init__(self,idx,max_ol):
        self.idx=idx
        self.start=0
        self.end=0
        self.op=0
        self.max_ol=max_ol
        self.Gap=0
        self.l=0

    def wether_end(self):
        if self.op<self.max_ol:
            return False
        else:
            return True

    def update(self,s,e):
        self.op+=1
        self.end=e
        self.start=s
        self.l=self.l+e-s

class JSP_Env:
    def __init__(self,n,m,PT,M):
        self.n,self.m=n,m
        self.O_max_len=len(PT[0])
        self.PT=copy.copy(PT)
        self.M=M
        self.finished=[]
        self.Num_finished=0
        self.g=0


    def Create_Item(self):
        self.Jobs=[]
        for i in range(self.n):
            Ji=Job(i,len(self.PT[i]))
            self.Jobs.append(Ji)
        self.Machines=[]
        for i in range(self.n):
            Mi=Machine(i)
            self.Machines.append(Mi)

    def C_max(self):
        m=0
        for Mi in self.Machines:
            if Mi.end>m:
                m=Mi.end
        return m

    def reset(self):
        self.u=0
        self.P = 0  # total working time
        self.finished=[]
        self.Num_finished=0
        done=False
        self.Create_Item()
        self.S1_Matrix = np.array(copy.copy(self.PT))
        self.S2_Matrix = np.zeros_like(self.S1_Matrix)
        self.S3_Matrix = np.zeros_like(self.S1_Matrix)
        self.s=np.stack((self.S1_Matrix,self.S2_Matrix,self.S3_Matrix),0)
        # s=self.s.flatten()
        return self.s,done

    def Gap(self):
        G=0
        for Mi in self.Machines:
            G+=Mi.Gap()
        return G/self.C_max()

    def U(self):
        C_max = self.C_max()
        return self.P/(self.m*C_max)

    def step(self,action):
        # print(action)
        done=False
        # if action in self.finished:
        #     s=self.s.flatten()
        #     return s,-999,done
        Ji=self.Jobs[action]
        op=Ji.op
        # print('a',action,op)
        pt=self.PT[action][op]
        self.P+=pt
        self.s[0][action][op] = 0
        Mi=self.Machines[self.M[action][op]]
        Mi.handling(Ji,pt)
        self.s[1][action][op]=Ji.end
        if Ji.wether_end():
            self.finished.append(action)
            self.Num_finished+=1
        if self.Num_finished==self.n:
            done=True
        Gap=self.Gap()
        self.s[2][action][op] =Gap
        u=self.U()
        r=u-self.u
        self.u=u
        # s=self.s.flatten()
        return self.s,r,done


if __name__=="__main__":

    from Dataset.data_extract import change
    from Actor_Critic_for_JSP.action_space import Dispatch_rule
    import random
    n, m, PT, MT = change('ft', 6)
    print(PT)
    print()
    jsp=JSP_Env(n, m, PT, MT)
    os1=[]
    for i in range(len(PT)):
        for j in range(len(PT[i])):
            os1.append(i)
    s,done=jsp.reset()
    while not done:
        a=random.randint(0,16)
        print('dispatch rule',a)
        a=Dispatch_rule(a,jsp)
        print('this is action',a)
        s, r, done=jsp.step(a)
        print(r)
        print(done)
        os1.remove(a)
        shape=len(s)
    Gantt(jsp.Machines)
    print(jsp.C_max())

5.2 RL_network.py

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

class CNN_FNN(nn.Module):
    """docstring for Net"""
    def __init__(self,J_num,O_max_len):
        super(CNN_FNN, self).__init__()
        # summary(self.conv1,(3,6,6))
        self.fc1 = nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)
        self.fc2 = nn.Linear(258,258)
        self.out = nn.Linear(258,17)

    def forward(self,x):
        x=self.conv1(x)
        x=x.view(x.size(0),-1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.relu(x)
        action_prob = self.out(x)
        return action_prob


class CNN_dueling(nn.Module):
    def __init__(self,J_num,O_max_len):
        super(CNN_dueling, self).__init__()
        self.conv1=nn.Sequential(
            nn.Conv2d(
                in_channels=3,  #input shape (3,J_num,O_max_len)
                out_channels=6,
                kernel_size=3,
                stride=1,
                padding=1,  #使得出來的圖片大小不變P=(3-1)/2,
            ),      # output shape (3,J_num,O_max_len)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2,ceil_mode=False)  #output shape:  (6,int(J_num/2),int(O_max_len/2))
        )
        # summary(self.conv1,(3,6,6))
        self.val_hidden = nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)
        self.adv_hidden=nn.Linear(6*int(J_num/2)*int(O_max_len/2), 258)

        self.val=nn.Linear(258,1)
        self.adv = nn.Linear(258,17)

    def forward(self,x):
        x=self.conv1(x)
        x=x.view(x.size(0),-1)

        val_hidden = self.val_hidden(x)
        val_hidden = F.relu(val_hidden)

        adv_hidden = self.adv_hidden(x)
        adv_hidden = F.relu(adv_hidden)

        val = self.val(val_hidden)
        adv = self.adv(adv_hidden)

        adv_ave = torch.mean(adv, dim=1, keepdim=True)
        x = adv + val - adv_ave
        return x

5.3 Agent.py

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from Actor_Critic_for_JSP.Agent.RL_network import CNN_FNN,CNN_dueling
from Actor_Critic_for_JSP.Memory.Memory import Memory
from Actor_Critic_for_JSP.Memory.PreMemory import preMemory

class Agent():
    """docstring for DQN"""
    def __init__(self,n,O_max_len,dueling=False,double=False,PER=False):
        self.double=double
        self.PER=PER
        self.GAMMA=1
        self.n=n
        self.O_max_len=O_max_len
        super(Agent, self).__init__()
        if dueling:
            self.eval_net, self.target_net = CNN_dueling(self.n,self.O_max_len), CNN_dueling(self.n,self.O_max_len)
        else:
            self.eval_net, self.target_net = CNN_FNN(self.n, self.O_max_len), CNN_FNN(self.n, self.O_max_len)
        self.Q_NETWORK_ITERATION=100
        self.BATCH_SIZE=256
        self.learn_step_counter = 0
        self.memory_counter = 0
        if PER:
            self.memory = preMemory()
        else:
            self.memory = Memory()
        self.EPISILO=0.8
        self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=0.00001)
        self.loss_func = nn.MSELoss()

    def choose_action(self, state):
        state=np.reshape(state,(-1,3,self.n,self.O_max_len))
        state=torch.FloatTensor(state)
        # print(state.size())
        # state = torch.unsqueeze(torch.FloatTensor(state), 0) # get a 1D array
        if np.random.randn() <= self.EPISILO:# greedy policy
            action_value = self.eval_net.forward(state)
            action = torch.max(action_value, 1)[1].data.numpy()[0]
            # action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
        else: # random policy
            action = np.random.randint(0,17)
            # action = action if ENV_A_SHAPE ==0 else action.reshape(ENV_A_SHAPE)
        self.EPISILO=min(0.001,self.EPISILO-0.00001)
        return action

    def PER_error(self,state, action, reward, next_state):

        state = torch.FloatTensor(np.reshape(state, (-1, 3, self.n, self.O_max_len)))
        next_state= torch.FloatTensor(np.reshape(next_state, (-1, 3, self.n, self.O_max_len)))
        p=self.eval_net.forward(state)
        p_=self.eval_net.forward(next_state)
        p_target=self.target_net(state)

        if self.double:
            q_a=p_.argmax(dim=1)
            q_a=torch.reshape(q_a,(-1,len(q_a)))
            qt=reward+self.GAMMA*p_target.gather(1,q_a)
        else:
            qt=reward+self.GAMMA*p_target.max(1)[0].view(self.BATCH_SIZE, 1)
        qt=qt.detach().numpy()
        p=p.detach().numpy()
        errors=np.abs(p[0][action]-qt[0][0])
        return errors

    def store_transition(self, state, action, reward, next_state):
        if self.PER:
            errors=self.PER_error(state, action, reward, next_state)
            self.memory.remember((state, action, reward, next_state), errors)
            self.memory_counter += 1
        else:
            self.memory.remember((state, action, reward, next_state))
            self.memory_counter+=1

    def learn(self):

        #update the parameters
        if self.learn_step_counter % self.Q_NETWORK_ITERATION ==0:
            self.target_net.load_state_dict(self.eval_net.state_dict())
        self.learn_step_counter+=1

        batch=self.memory.sample(self.BATCH_SIZE)

        #sample batch from memory
        batch_state=np.array([o[0] for o in batch])
        batch_next_state= np.array([o[3] for o in batch])
        batch_action=np.array([o[1] for o in batch])
        batch_reward=np.array([o[1] for o in batch])


        batch_action = torch.LongTensor(np.reshape(batch_action, (-1, len(batch_action))))
        batch_reward =  torch.LongTensor(np.reshape(batch_reward, (-1, len(batch_reward))))

        batch_state=torch.FloatTensor(np.reshape(batch_state, (-1, 3, self.n, self.O_max_len)))
        batch_next_state =torch.FloatTensor(np.reshape(batch_next_state, (-1, 3, self.n, self.O_max_len)))

        if self.double:
            # q_eval
            q_eval = self.eval_net(batch_state).gather(1, batch_action)
            q_next_eval=self.eval_net( batch_next_state).detach()
            q_next = self.target_net(batch_next_state).detach()
            q_a=q_next_eval.argmax(dim=1)
            q_a=torch.reshape(q_a,(-1,len(q_a)))
            q_target = batch_reward + self.GAMMA * q_next.gather(1, q_a)
        else:
            #q_eval
            q_eval = self.eval_net(batch_state).gather(1,batch_action)
            q_next = self.target_net(batch_next_state).detach()
            q_target = batch_reward + self.GAMMA * q_next.max(1)[0].view(self.BATCH_SIZE, 1)

        loss = self.loss_func(q_eval, q_target)

        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

5.4 train.py

from Actor_Critic_for_JSP.JSP_env import JSP_Env,Gantt
import matplotlib.pyplot as plt
from Actor_Critic_for_JSP.Dataset.data_extract import change
from Actor_Critic_for_JSP.action_space import Dispatch_rule
from Actor_Critic_for_JSP.Agent.Agent import Agent

def main(Agent,env,batch_size):
    Reward_total = []
    C_total = []
    rewards_list = []
    C = []

    episodes = 8000
    print("Collecting Experience....")
    for i in range(episodes):
        print(i)
        state,done = env.reset()
        ep_reward = 0
        while True:

            action = Agent.choose_action(state)

            a=Dispatch_rule(action,env)
            try:
                next_state, reward, done = env.step(a)
            except:
                print(action,a)

            Agent.store_transition(state, action, reward, next_state)
            ep_reward += reward
            if Agent.memory_counter >= batch_size:
                Agent.learn()
                if done and i%1==0:
                    ret, f, C1, R1 = evaluate(i,Agent,env)
                    Reward_total.append(R1)
                    C_total.append(C1)
                    rewards_list.append( ep_reward)
                    C.append(env.C_max())
            if done:
                # Gantt(env.Machines)
                break
            state = next_state
    x = [_ for _ in range(len(C))]
    plt.plot(x, rewards_list)
    # plt.show()
    plt.plot(x, C)
    # plt.show()
    return Reward_total,C_total

def evaluate(i,Agent,env):
    returns = []
    C=[]
    for  total_step in range(10):
        state, done = env.reset()
        ep_reward = 0
        while True:
            action = Agent.choose_action(state)
            a = Dispatch_rule(action, env)
            try:
                next_state, reward, done = env.step(a)
            except:
                print(action,a)
            ep_reward += reward
            if done == True:
                fitness = env.C_max()
                C.append(fitness)
                break
        returns.append(ep_reward)
    print('time step:',i,'','Reward :',sum(returns)/10 ,'','C_max:',sum(C) /10)
    return sum(returns) / 10,sum(C) /10,C,returns


if __name__ == '__main__':
    import pickle
    import os

    n, m, PT, MT = change('la', 16)

    f=r'.\result\la'
    if not os.path.exists(f):
        os.mkdir(f)
    f1=os.path.join(f,'la'+'16')
    if not os.path.exists(f1):
        os.mkdir(f1)
    print(n, m, PT, MT)
    env = JSP_Env(n, m, PT, MT)
    # (0,0)CNN+FNN+DQN (1,0):CNN+Dueling network+DQN (0,1):CNN+FNN+DDQN (1,1):CNN+Dueling network+DDQN
    agent=Agent(env.n,env.O_max_len,1,1)
    Reward_total,C_total=main(agent,env,100)
    print(os.path.join(f1, 'C_max' + ".pkl"))
    with open(os.path.join(f1, 'C_max' + ".pkl"), "wb") as f2:
        pickle.dump(C_total, f2, pickle.HIGHEST_PROTOCOL)
    with open(os.path.join(f1, 'Reward' + ".pkl"), "wb") as f3:
        pickle.dump(Reward_total, f3, pickle.HIGHEST_PROTOCOL)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/395017.html

標籤:AI

上一篇:模仿學習與強化學習的結合(原理講解與ML-Agents實作)

下一篇:R語言dplyr包使用bind_rows函式縱向合并兩個dataframe(行生長)、使用bind_cols函式橫向合并兩個dataframe(列生長)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more