• 文章目录Nash-QLearning智能体创建一个矩阵环境策略训练Minimax-QLearning¶WoLF-PHC(Policy hill-climbing algorithm) Nash-QLearning 论文：Nash Q-learning for general-sum stochastic games 链接：...
文章目录Nash-QLearning智能体创建一个矩阵环境策略训练WoLF-PHC(Policy hill-climbing algorithm)智能体创建一个矩阵环境训练Minimax-QLearning¶
Nash-QLearning
论文：Nash Q-learning for general-sum stochastic games
链接：http://www.jmlr.org/papers/volume4/hu03a/hu03a.pdf
智能体
import numpy as np
import nashpy

class NashQLearner():
def __init__(self,
alpha=0.1,
policy=None,
gamma=0.99,
ini_state="nonstate",
actions=None):

self.alpha = alpha
self.gamma = gamma
self.policy = policy
self.actions = actions
self.state = ini_state

# q values (my and opponent)
self.q, self.q_o = {}, {}
self.q[ini_state] = {}
self.q_o[ini_state] = {}

# nash q value
self.nashq = {}
self.nashq[ini_state] = 0

# pi (my and opponent)
self.pi, self.pi_o = {}, {}
self.pi[ini_state] = np.repeat(1.0/len(self.actions), len(self.actions))
self.pi_o[ini_state] = np.repeat(1.0/len(self.actions), len(self.actions))

self.previous_action = None
self.reward_history = []
self.pi_history = []

def act(self, training=True):
if training:
action_id = self.policy.select_action(self.pi[self.state])
action = self.actions[action_id]
self.previous_action = action
else:
action_id = self.policy.select_greedy_action(self.pi)
action = self.actions[action_id]

return action

def observe(self, state="nonstate", reward=None, reward_o=None, opponent_action=None, is_learn=True):
"""
observe next state and learn
"""
if is_learn:
self.check_new_state(state) # if the state is new state, extend q table
self.learn(state, reward, reward_o, opponent_action)

def learn(self, state, reward, reward_o, opponent_action):
self.reward_history.append(reward)
self.q[state][(self.previous_action, opponent_action)] = self.compute_q(state, reward, opponent_action, self.q)
self.q_o[state][(self.previous_action, opponent_action)] = self.compute_q(state, reward_o, opponent_action, self.q_o)

self.pi[state], self.pi_o[state] = self.compute_pi(state)
self.nashq[state] = self.compute_nashq(state)

self.pi_history.append(self.pi[state][0])

def compute_q(self, state, reward, opponent_action, q):
if (self.previous_action, opponent_action) not in q[state].keys():
q[state][(self.previous_action, opponent_action)] = 0.0
q_old = q[state][(self.previous_action, opponent_action)]
updated_q = q_old + (self.alpha * (reward + self.gamma*self.nashq[state] - q_old))

return updated_q

def compute_nashq(self, state):
"""
compute nash q value
"""
nashq = 0
for action1 in self.actions:
for action2 in self.actions:
nashq += self.pi[state][action1]*self.pi_o[state][action2] * \
self.q[state][(action1, action2)]

return nashq

def compute_pi(self, state):
"""
compute pi (nash)
"""
q_1, q_2 = [], []
for action1 in self.actions:
row_q_1, row_q_2 = [], []
for action2 in self.actions:
joint_action = (action1, action2)
row_q_1.append(self.q[state][joint_action])
row_q_2.append(self.q_o[state][joint_action])
q_1.append(row_q_1)
q_2.append(row_q_2)

game = nashpy.Game(q_1, q_2)
equilibria = game.support_enumeration()
pi = []
for eq in equilibria:
pi.append(eq)

return pi[0][0], pi[0][1]

def check_new_state(self, state):
"""
if the state is new state, extend q table
"""
if state not in self.q.keys():
self.q[state] = {}
self.q_o[state] = {}
for action1 in self.actions:
for action2 in self.actions:
if state not in self.pi.keys():
self.pi[state] = np.repeat(
1.0/len(self.actions), len(self.actions))
self.v[state] = np.random.random()
if (action1, action2) not in self.q[state].keys():
self.q[state][(action1, action2)] = np.random.random()
self.q_o[state][(action1, action2)] = np.random.random()

创建一个矩阵环境
class MatrixGame():
def __init__(self):
self.reward_matrix = self._create_reward_table()

def step(self, action1, action2):
r1 = self.reward_matrix[0][action1][action2]
r2 = self.reward_matrix[1][action1][action2]

return None, r1, r2

def _create_reward_table(self):
reward_matrix = [
[[1, -1], [-1, 1]],
[[-1, 1], [1, -1]]
]

return reward_matrix


策略
class EpsGreedyQPolicy():
def __init__(self, epsilon=.1, decay_rate=1):
self.epsilon = epsilon
self.decay_rate = decay_rate

def select_action(self, q_values):
assert q_values.ndim == 1
nb_actions = q_values.shape[0]

if np.random.uniform() < self.epsilon:
action = np.random.random_integers(0, nb_actions-1)
else:
action = np.argmax(q_values)

return action

def select_greedy_action(self, q_values):
assert q_values.ndim == 1
action = np.argmax(q_values)

return action

训练
import matplotlib.pyplot as plt

if __name__ == '__main__':
nb_episode = 1000

agent1 = NashQLearner(alpha=0.1, policy=EpsGreedyQPolicy(), actions=np.arange(2))
agent2 = NashQLearner(alpha=0.1, policy=EpsGreedyQPolicy(), actions=np.arange(2))

game = MatrixGame()
for episode in range(nb_episode):
action1 = agent1.act()
action2 = agent2.act()

_, r1, r2 = game.step(action1, action2)

agent1.observe(reward=r1, reward_o=r2, opponent_action=agent2.previous_action)
agent2.observe(reward=r2, reward_o=r1, opponent_action=agent1.previous_action)

plt.plot(np.arange(len(agent1.pi_history)), agent1.pi_history, label="agent1's pi(0)")
plt.plot(np.arange(len(agent2.pi_history)), agent2.pi_history, label="agent2's pi(0)")
plt.xlabel("episode")
plt.ylabel("pi(0)")
plt.legend()
plt.show()

WoLF-PHC(Policy hill-climbing algorithm)
论文：Rational and Convergent Learning in Stochastic Games
链接：http://www.cs.cmu.edu/~mmv/papers/01ijcai-mike.pdf
智能体
import numpy as np

class WoLFAgent():

def __init__(self, alpha=0.1, delta=0.0001, actions=None, high_delta=0.004, low_delta=0.002):
self.alpha = alpha
self.actions = actions
self.last_action_id = None
self.q_values = self._init_q_values()
self.pi = [(1.0/len(actions)) for idx in range(len(actions))]
self.pi_average = [(1.0/len(actions)) for idx in range(len(actions))]
self.high_delta = high_delta
self.row_delta = low_delta

self.pi_history = [self.pi[0]]
self.reward_history = []
self.conter = 0

def _init_q_values(self):
q_values = {}
q_values = np.repeat(0.0, len(self.actions))
return q_values

def act(self, q_values=None):
action_id = np.random.choice(np.arange(len(self.pi)), p=self.pi)
self.last_action_id = action_id
action = self.actions[action_id]
return action

def observe(self, reward):
self.reward_history.append(reward)
self.q_values[self.last_action_id] = ((1.0 - self.alpha) * self.q_values[self.last_action_id]) + (self.alpha * reward)
self._update_pi_average()
self._update_pi()

def _update_pi_average(self):
self.conter += 1
for aidx, _ in enumerate(self.pi):
self.pi_average[aidx] = self.pi_average[aidx] + (1/self.conter)*(self.pi[aidx]-self.pi_average[aidx])
if self.pi_average[aidx] > 1: self.pi_average[aidx] = 1
if self.pi_average[aidx] < 0: self.pi_average[aidx] = 0

def _update_pi(self):
delta = self.decide_delta()
max_action_id = np.argmax(self.q_values)
for aidx, _ in enumerate(self.pi):
if aidx == max_action_id:
update_amount = delta
else:
update_amount = ((-delta)/(len(self.actions)-1))
self.pi[aidx] = self.pi[aidx] + update_amount
if self.pi[aidx] > 1: self.pi[aidx] = 1
if self.pi[aidx] < 0: self.pi[aidx] = 0
self.pi_history.append(self.pi[0])

def decide_delta(self):
"""
comfirm win or lose
"""
expected_value = 0
expected_value_average = 0
for aidx, _ in enumerate(self.pi):
expected_value += self.pi[aidx]*self.q_values[aidx]
expected_value_average += self.pi_average[aidx]*self.q_values[aidx]

if expected_value > expected_value_average: # win
return self.row_delta
else:   # lose
return self.high_delta

创建一个矩阵环境
class MatrixGame():
def __init__(self):
self.reward_matrix = self._create_reward_table()

def step(self, action1, action2):
r1, r2 = self.reward_matrix[action1][action2]

return None, r1, r2

def _create_reward_table(self):
reward_matrix = [
[[1, -1], [-1, 1]],
[[-1, 1], [1, -1]]
]

return reward_matrix

训练
import matplotlib.pyplot as plt
import pandas as pd

if __name__ == '__main__':
nb_episode = 1000

actions = np.arange(2)
agent1 = WoLFAgent(alpha=0.1, actions=actions, high_delta=0.0004, low_delta=0.0002)
agent2 = WoLFAgent(alpha=0.1, actions=actions, high_delta=0.0004, low_delta=0.0002)

game = MatrixGame()
for episode in range(nb_episode):
action1 = agent1.act()
action2 = agent2.act()

_, r1, r2 = game.step(action1, action2)

agent1.observe(reward=r1)
agent2.observe(reward=r2)

print(agent1.pi)
print(agent2.pi)
plt.plot(np.arange(len(agent1.pi_history)),agent1.pi_history, label="agent1's pi(0)")
plt.plot(np.arange(len(agent2.pi_history)),agent2.pi_history, label="agent2's pi(0)")

plt.ylim(0, 1)
plt.xlabel("episode")
plt.ylabel("pi(0)")
plt.legend()
plt.show()

Minimax-QLearning¶
论文：Markov games as a framework for multi-agent reinforcement learning
链接：https://www2.cs.duke.edu/courses/spring07/cps296.3/littman94markov.pdf
TODO


展开全文
• 智能体位置随机生成 所有智能体位置全局可知 目标多边形位置给定 所有个体运行相同算法，根据环境来决定自己动作。 目标：形成均匀多边形分布，所谓的 ‘均匀’ 效果如下图：即是多边形上间距相等 问题拆分...
初始条件：

智能体位置随机生成
所有智能体位置全局可知
目标多边形位置给定
所有个体运行相同算法，根据环境来决定自己动作。
目标：形成均匀多边形分布，所谓的  ‘均匀’ 效果如下图：即是多边形上间距相等

问题拆分：

抵达均匀多边形
均匀化分布

1 .抵达均匀多边形：

'''code = 'utf-8'''
'''author = peng'''

import copy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
import time

NUM = 10  #设置无人机数量
MOVE_DISTANCE = 0.3
JianCeError = 0.1
'''根据无人机数量NUM得出边界最大容量数量   :    MAXNUM'''
if ((NUM - 4)/4)%1==0:
MAXNUM = (NUM - 4)/4
else:MAXNUM = int((NUM - 4)/4) +1
'''JIANJU是调整单位距离'''
JIANJU = 50 /(MAXNUM+1)
x = np.random.randint(1, 100, NUM)
y = np.random.randint(1, 100, NUM)
# x = [36,37,38,39]
# y = [36,37,38,39]
Point_list = []
for i in range(NUM):
Point_list.append([x[i], y[i]])
DING_LIST = [[25, 25], [75, 25], [75, 75], [25, 75]]
DingX, DingY = [], []
for each in DING_LIST:
DingX.append(each[0])
DingY.append(each[1])
DingX.append(DING_LIST[0][0])
DingY.append(DING_LIST[0][1])
fig, ax = plt.subplots()
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
sc = ax.scatter(x, y, color='r', alpha=0.7,marker='1',linewidth = 10)
ax.plot(DingX, DingY, color = 'black',linestyle = ':')

class Point():
MOVE_DISTANCE = MOVE_DISTANCE
JianCeError = JianCeError
MAXNUM = MAXNUM
JIANJU = JIANJU
tiaozheng_aim = None
def __init__(self,id):
self.id = id
def decide(self,list = copy.deepcopy(DING_LIST)):
if self.tiaozheng_aim == None:   #调整目标定下来就不需要改变了
nearest = self.detect_nearest(list) #检测最近顶点
ID = self.occupy(nearest)    #检测占领者
if ID == self.id :
self.update(nearest)
pass       #自己占领
elif ID == None:self.update(nearest)  #无人占领，往该方向移动
else:# self.update([50,50])
if self.tiaozheng_aim:     #调整成功
self.update(self.tiaozheng_aim)
else:                      #调整失败
# print(list)
list2 = copy.deepcopy(list) #深复制防出错
list2.remove(nearest)
# print(list)
return self.decide(list2)
else:self.update(self.tiaozheng_aim) #有调整目标，直接移往该方向

order = obj_list[ID].send() #1,0
if order == None:return None
for each in DING_LIST:
d = self.distance_calculate(each, Point_list[ID])
if d < self.JianCeError:
identity = DING_LIST.index(each)
aim = copy.deepcopy(DING_LIST[identity])
count = self.MAXNUM - order  #1,2
if count % 2 == 0:  # 偶数顺时针
if identity == 3:
aim[0] += self.JIANJU * (count / 2)
return aim
elif identity == 2:
aim[1] -= self.JIANJU * (count / 2)
return aim
elif identity == 1:
aim[0] -= self.JIANJU * (count / 2)
return aim
else:
aim[1] += self.JIANJU * (count / 2)
return aim
elif identity == 3:  # 奇数逆时针
aim[1] -= self.JIANJU * (int((count / 2))+1)
return aim
elif identity == 2:
aim[0] -= self.JIANJU * (int((count / 2))+1)
return aim
elif identity == 1:
aim[1] += self.JIANJU * (int((count / 2))+1)
return aim
else:
aim[0] += self.JIANJU * (int((count / 2))+1)
return aim

def detect_nearest(self,list):
init_distance = self.distance_calculate(Point_list[self.id], list[0])
count, i = 0, 0
for each in list:
D = self.distance_calculate(Point_list[self.id], each)
if D < init_distance:
init_distance = D
count = i
i += 1
return list[count]
def distance_calculate(self, A, B):  # [1,1],[2,2] 得1.4142135623730951
return pow(pow(abs(A[0] - B[0]), 2) + pow(abs(A[1] - B[1]), 2), 0.5)
def update(self,aim):
self_pot = copy.deepcopy(Point_list[self.id])
x = np.array([aim[0] - self_pot[0], aim[1] - self_pot[1]])  # 方向向量
y = np.array([1, 0])  # x轴方向
Lx = np.sqrt(x.dot(x))  # x.dot(x) 点乘自己，相当于向量模平方
Ly = np.sqrt(y.dot(y))
if Lx > self.MOVE_DISTANCE:
cos_angle = x.dot(y) / (Lx * Ly)
angle = np.arccos(cos_angle)  # 0.....pi
if x[0] >= 0 and x[1] >= 0:
self_pot[0] = self_pot[0] + self.MOVE_DISTANCE * abs(np.cos(angle))
self_pot[1] = self_pot[1] + self.MOVE_DISTANCE * np.sin(angle)
elif x[0] <= 0 and x[1] >= 0:
self_pot[0] = self_pot[0] - self.MOVE_DISTANCE * abs(np.cos(angle))
self_pot[1] = self_pot[1] + self.MOVE_DISTANCE * np.sin(angle)
elif x[0] <= 0 and x[1] <= 0:
self_pot[0] = self_pot[0] - self.MOVE_DISTANCE * abs(np.cos(angle))
self_pot[1] = self_pot[1] - self.MOVE_DISTANCE * np.sin(angle)
else:
self_pot[0] = self_pot[0] + self.MOVE_DISTANCE * abs(np.cos(angle))
self_pot[1] = self_pot[1] - self.MOVE_DISTANCE * np.sin(angle)
Point_list[self.id] = self_pot
else:
Point_list[self.id] = aim
def occupy(self,nearest):
for each in Point_list :
d = self.distance_calculate(each,nearest)
if d < self.JianCeError:
ID = Point_list.index(each)
return ID
return None
def send(self):
'''self.MAXNUM = 2 ,则输出 1,0'''
if self.MAXNUM <= 0:
return None  # 告诉询问着索要失败
else:
self.MAXNUM -= 1
return self.MAXNUM

obj_list = [Point(i) for i in range(0, NUM)]  # 返回生成的NUM个对象的列表

comp_li = None
def gen():  # 绘图函数里面用的数据来源
global comp_li
while True:
li = []
for i in range(NUM):
obj_list[i].decide()

for each in Point_list:
li.append(each)
if comp_li == li:
print('抵达边界完成，停留3秒')
time.sleep(3)
exit()
else:comp_li = copy.deepcopy(li)
with open('set.py','w') as f:
f.write('POINT_LIST = '+ str(li))
yield li

def update(N_list):
sx, sy = [], []
for each in N_list:
sx.append(each[0])
sy.append(each[1])
sc.set_offsets(np.c_[sx, sy])
return sc

ani = animation.FuncAnimation(fig, update, frames=gen, interval=1)
plt.show()

初始分布随机生成：

抵达多边形后分布：

均匀化后分布：

均匀化算法思路：

class Point（）
def __init__(id):
self.id = id
def decide():
'''决策函数，执行后更改全局变量 POINT_LIST '''
return None

obj_list = [Point(i) for i in range(0, len(Point_list))]  # 返回生成的NUM个对象的列表

while True:
'''依次执行每个个体的决策函数，更改自身位置，迭代器返回全局变量 POINT_LIST'''
for i in range(NUM):
obj_list[i].decide()
yield POINT_LIST

###############################################################################################
关于决策函数：
def decide（）：
""" mmid 指 前后邻点的中点 与 自己位置 相连的 中点 """
找到前后邻点，计算出  mmid =((pre + next)/2 + my)/2

'''移到目标点'''
move（mmid）

##################################################################################################
关于位置移动的处理 ：

idea：为了解决在顶点处移动无人机算法表达难度过大的问题提出将均匀多边形链表化的设想，即是把多边形等距划分，将每一个点位置存入链表中，移动无人机只需考虑其在链表上索引变动即可。

具体实现代码：

'''重写 13 '''
'''基本ok 只差停下函数'''
'''哇 终于TM的停下来了'''

import copy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
import time
from set import POINT_LIST
Move_Distance = 20   # 20 * 0.01 =0.2
Ting_Distance = 3
# POINT_LIST = [[41.66666666666667, 25], [25, 41.66666666666667], [41.66666666666667, 75], [75, 25], [25, 75], [75, 58.33333333333333], [75, 75], [58.33333333333333, 75], [25, 25], [75, 41.66666666666667], [25, 58.33333333333333], [58.33333333333333, 25]]
# Point_list = [[25, 50.0], [75, 43.75], [43.75, 25], [25, 75], [25, 43.75], [75, 68.75], [56.25, 25], [62.5, 75], [50.0, 25], [75, 62.5], [25, 68.75], [31.25, 75], [25, 25], [31.25, 25], [25, 31.25], [75, 50.0], [37.5, 25], [56.25, 75], [75, 25], [75, 75], [75, 31.25], [25, 62.5], [37.5, 75], [68.75, 25], [75, 37.5], [25, 37.5], [25, 56.25], [68.75, 75], [62.5, 25], [43.75, 75]]
# Point_list = [[25, 25], [75, 75], [25, 75], [75, 25], [50, 25]]
# Point_list = [[25, 43.75], [25, 56.25], [50.0, 25], [75, 37.5], [68.75, 75], [43.75, 75], [62.5, 25], [75, 43.75], [25, 75], [25, 25], [56.25, 25], [25, 68.75], [75, 50.0], [31.25, 75], [25, 62.5], [75, 68.75], [31.25, 25], [25, 31.25], [62.5, 75], [75, 62.5], [56.25, 75], [75, 56.25], [37.5, 25], [75, 25], [75, 31.25], [25, 37.5], [68.75, 25], [37.5, 75], [43.75, 25]]
Point_list = POINT_LIST
NUM = len(Point_list)
# print(NUM)
DING_LIST = [[25, 25], [75, 25], [75, 75], [25, 75]]
DingX, DingY, x, y = [], [], [], []
for each in DING_LIST:
DingX.append(each[0])
DingY.append(each[1])
for each in Point_list:
x.append(each[0])
y.append(each[1])
DingX.append(DING_LIST[0][0])
DingY.append(DING_LIST[0][1])
fig, ax = plt.subplots()
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
sc = ax.scatter(x, y, color='r', alpha=0.7,marker='1',linewidth = 10)
ax.plot(DingX, DingY, color = 'black',linestyle = ':')

'''以间隔0.01生成齿轮链表'''

def chain_make():
Tooth_Chain = []
Tooth_Chain.append([25, 25])
for i in np.arange(25.01, 75, 0.01):
Tooth_Chain.append([i, 25])
Tooth_Chain.append([75, 25])
for i in np.arange(25.01, 75, 0.01):
Tooth_Chain.append([75, i])
Tooth_Chain.append([75, 75])
for i in np.arange(74.99, 25.0, -0.01):
Tooth_Chain.append([round(i, 2), 75])
Tooth_Chain.append([25, 75])
for i in np.arange(74.99, 25, -0.01):
Tooth_Chain.append([25, round(i, 2)])

def distance_calculate(A, B):  # [1,1],[2,2] 得1.4142135623730951
return pow(pow(abs(A[0] - B[0]), 2) + pow(abs(A[1] - B[1]), 2), 0.5)

Tooth_Chain = chain_make()
Tooth_Len = len(Tooth_Chain)
for a in Point_list:
for b in Tooth_Chain:
d = distance_calculate(a, b)
if d <= 0.005:      # Point_list数据有问题
a.append(Tooth_Chain.index(b))

def takeThird(elem):
return elem[2]

class Point():
next_dis = 200001
def __init__(self, id):
''' self.  pre_id    next_id     id  这三个是在Point_list中的位置'''
self.id = id
if my_id == 0:
elif my_id == NUM - 1:
else:

def decide(self):
if pre_chain_index < next_chain_index:
a = pre_chain_index
b = next_chain_index
else:
a = pre_chain_index
b = next_chain_index + 20000
if abs(self_chain_index - (a+b)/2 ) < 100 : pass
else:

if pre_chain_index < next_chain_index:  # 正常情况
self.next_dis = next_chain_index - self_chain_index
mmid = ((next_chain_index + pre_chain_index) / 2 + self_chain_index) / 2
# print('pre:', pre_chain_index, ' ', 'self', self_chain_index, ' ', 'next:', next_chain_index)
else:
self.next_dis = next_chain_index - self_chain_index + 20000
if self.next_dis>= 20000 :
self.next_dis -= 20000
mmid = ((next_chain_index + Tooth_Len + pre_chain_index) / 2 + self_chain_index) / 2
# print('pre:', pre_chain_index, ' ', 'self', self_chain_index, ' ', 'next:', next_chain_index)

if abs(mmid - self_chain_index) <= Ting_Distance:
if mmid % 1 == 0:
self.move(int(mmid))
elif self_chain_index > mmid:  # 在目标顺市针方向
self.move(int(mmid) + 1)
else:
self.move(int(mmid))
elif mmid > self_chain_index:
self.move(self_chain_index + Move_Distance)
else:
self.move(self_chain_index - Move_Distance)

def move(self, aim):
if aim >= Tooth_Len: aim -= Tooth_Len
li = copy.deepcopy(Tooth_Chain[aim])
li.append(aim)

def judge(list):
d = 20000/NUM
for each in list :
if abs(each - d) > 100:
return False
return True

def gen():
while True:
# print('')
li = []
# panduanls=[]
# if vari > ? :
for i in range(NUM):
obj_list[i].decide()
# panduanls.append(obj_list[i].next_dis)
# else:continue
# if judge(panduanls):
#     print("均匀化分布算法执行完毕，停留3秒")
#     time.sleep(3)
#     exit()
yield li

def update(N_list):
sx, sy = [], []
for each in N_list:
sx.append(each[0])
sy.append(each[1])
sc.set_offsets(np.c_[sx, sy])
return sc

obj_list = [Point(i) for i in range(0, len(Point_list))]  # 返回生成的NUM个对象的列表
ani = animation.FuncAnimation(fig, update, frames=gen, interval=2)

plt.show()

###均匀化代码需要数据POINT_LIST,可以用代码中注释掉的数据看效果。

编队过程中碰撞问题解决办法：高度错开

三维效果演示：

三维演示代码已上传。


展开全文
• 本篇美文将把单智能体多智能体强化学习基本概念做个初步介绍。主要围绕：什么是单智能体强化学习？单智能体强化学习中基本算法分类？为啥提出多智能体强化学习？多智能体强化学习基本概念？来进行介绍，大佬请自动...

如图所示，瞧这美美的发际线，是本人，错不了。本人，打酱油的栋栋拐，立个flag，坚持更随笔。在座的各位，Hello啊。
单智能体、多智能体强化学习基本概念什么是单智能体强化学习？单智能体强化学习中基本算法分类？为啥提出多智能体强化学习？多智能体强化学习基本概念？多智能体强化学习基本现状？参考
什么是单智能体强化学习？

1、如图所示，单智能体强化学习的设置由两部分组成：一个智能体和环境。
2、模型描述：马尔可夫决策过程，即<状态集S、动作集A、奖励R、状态转移概率P、奖励衰减因子、探索率、策略>，最大的特性为下一时刻的状态和奖励，只与前一时刻的状态与动作有关，与更早之前的状态与行为无关，详细分析见基于马尔可夫过程的强化学习入门。
3、强化学习的原理：强化学习是让智能体以试错的方式来进行学习。智能体某个行为策略导致了好的奖赏，智能体产生这个行为策略的形式就会加强。智能体需要学习的就是：在一个环境中如何选择动作来获得最大奖励。其中，奖励值与智能体在环境中的任务息息相关。另外，智能体需要的主要学习任务是行为策略。其中，行为策略的学习目标是最优策略，也就是使用这样的策略，让智能体在特定环境中获得最大奖励值，从而实现任务目标。
4、强化学习的目标：在每个状态下发现最优策略来使期望的折扣奖励最大化。
5、强化学习可以解决的问题：可以描述为智能体在于环境交互过程中通过学习策略来达到回报最大化或实现特定目标的问题。目前，被广泛应用在各个领域。
单智能体强化学习中基本算法分类？
强化学习中有很多算法来寻找最优策略。另外，算法有很多分类。
3、单步更新（游戏中每一步都在更新，可以边玩边学习：QLearning、Sarsa、升级版的policy
4、在线学习（必须我本人在场，边玩边学：一般只有一个策略，最常见的是e-贪婪，即SARSA算法）、离线学习（从过往的经验里，但是过往的经验没必要是自己的：一般有两个策略，常见的是e-贪婪来选择新的动作，另一个贪婪法更新价值函数，即，常见的Q-Learning）。
5、千万注意，一定要明确不同的强化学习算法的优缺点以便于求解不同类型的问题。比如：Q-Learning适合解决低纬度且离散动作及状态空间，DQN适合解决低纬度动作和高纬度状态空间、DDPG适合求解高纬度（连续）动作空间及状态空间。
6、详细分类，见后文附带的链接。
为啥提出多智能体强化学习？
*自然是传统的集中式单智能体强化学习某些场景下不适用奥。废话不多说，讲道理！ *

1–传统的多智能体RL算法中，每个智能体走势在不断学习且改进其策略。由此，从每个智能体的角度来看，环境是不稳定的，不利于收敛。而传统的单智能体强化学习，需要稳定的环境
2–由于环境的不稳定，无法通过仅改变智能体本身的策略来适应动态不稳定的环境。
3–由于环境的不稳定，无法直接使用经验回放等DQN技巧。
4–因为大量智能体的交互会导致不可避免的反馈开销。更重要的是，生成的马尔可夫过程通常很难处理。用于MDP的数值求解技术遭受所谓的“维数诅咒”，这使它们在计算上不可行。
所以，多智能体强化学习被提出。
多智能体强化学习基本概念？

1-如图所示，多智能体系统中至少有两个智能体。另外，智能体之间存在着一定的关系，如合作关系，竞争关系，或者同时存在竞争与合作的关系。每个智能体最终所获得的回报不仅仅与自身的动作有关系，还跟对方的动作有关系。
2-多智能体强化学习的描述：马尔可夫博弈。也就是说，状态转换符合马尔可夫过程，关系符合博弈。可以表示为<N,S,A,Ri,T>，其中，N表示的是智能体的集合，S表示的是环境的状态空间、Ai表示的是智能体i的动作空间，A=A1A2…An表示为联合动作，R表示智能体i的奖励，T为状态转换函数。
3-一般来说，在马尔可夫博弈中，每个智能体的目标为找到最优策略来使它在任意状态下获得最大的长期累积奖励。
多智能体强化学习基本现状？
1-多智能体强化学习研究成果较少，并且多智能体强化学习没有系统的网络课程。另外，多智能体强化学习算法缺少系统的开源代码。再就是多智能体强化学习所涉及到的理论知识更多，如马尔科夫决策过程，博弈论等。
2-本人学习代码会参考Open AI提供的开源代码。强化学习对于代码能力要求好高，拐拐灰常菜，呜呜呜呜呜呜呜，再不学就失业啦。
3-UCL的汪军老师结合MFG与MARL，提出了MFMARL对于解决部分超密集问题有效。在这里有详细证明嗷。拐拐好笨丫。
参考
多智能体现状、基本定义
强化学习算法详细分类
在座的各位，未完待续啊。拐拐🐖愿大家开学愉快。Happy!!!


展开全文
写这篇的目的主要是总结一下最近对MADDPG这篇文章的学习过程。其中对文章的实验部分理解还不够深刻，如果某些该领域的大神能看到这篇博客的话，诚挚希望您们提供一些建议和指导！

算法对应的论文：《Multi-Agent Actor-Critic for Mixed Cooperative-Competitive Environments》
原文章翻译：https://blog.csdn.net/qiusuoxiaozi/article/details/79066612

1.2 算法简介
文章其实是先有个将DDPG算法应用到多智能体环境的一个baseline算法，再对此算法做了两种改进，改进的思路也就是不断放松之前智能体能获得其他智能体策略这一非常强的假设。
Baseline（基本方法）——对DDPG的改进
Baseline的算法就是将DDPG这一单智能体的深度强化学习actor-critic的方法进行扩展，使其适用于多智能体环境，基本思想依然是中心化训练和去中心化的执行（Centralized training and Decentralized execution），即在训练过程中每一个智能体的critic网路都会收集所有智能体的状态和动作信息，但在训练阶段，只由每个智能体的actor网络根据局部信息（即智能体自己的动作和状态）做出决策，该思想也是该算法的第一个特点。第二个特点就是该算法不要求环境是如何变化的信息（Environment Dynamics），也不要求智能体之间的通讯方法（differential communication channel）。

智能体actor网络的梯度公式可以之间跳到伪代码部分。
两种其他改进
推断其他智能体的策略（Inferring Policies of Other Agents）
思路就是将critic网络中的target value（该值是在每个智能体都知道其他智能体的策略的假设下计算得到的）换成一个由每个智能体的approximate policy计算出来的值，这个approximate policy又是最大化智能体的log probability得到的（引入entropy regularizer熵正则化项）

策略集成（Agents with Policy Ensembles）
思想是针对MARL中的环境非平稳的问题，在竞争环境中，智能体的策略可能对他们的竞争者的行为过拟合，因此当竞争者策略变化的时候，智能体的策略就可能无效。所以该方法关注如何提升智能体学到的策略的鲁棒性。
该方法基本内容就是训练K个不同策略的集合，目标函数也随之变化，文章里也给出了该损失函数的梯度计算公式。

（这一部分的代码可以在github的issue里找到，之后解决完baseline的一些实验问题之后学习一下这部分代码）
1.3 论文中的伪代码

伪代码中的要点已经用红框标出，下面总结一下：

replay buffer存储的信息是所有智能体的状态，动作，奖赏和下一个状态。
与DDPG一样，用于更新critic网络参数的target value y要用到target policy network输出的动作。
与DDPG，两类target network都是通过soft replacement方法更新。

1.4 论文中的实验部分（文中+附录）
基础实验部分
（policy network结构：两层MLP，激活函数是ReLU, 智能体之间传递的信息是通过Gumbel-Softmax estimator计算的），超参数的设定（见程序）
具体实验细节:（按场景分类）
i. 第一个是合作通信cooperative communication场景（包括listener和speaker）
在该场景下，传统的DRL方法如DQN, AC, first-order TRPO, DDPG，REINFORCE算法都学不到正确表现。文章中指出这些方法失败的原因是缺少持续的梯度信号（the lack of a consistent gradient signal），作者观测的现象是：当listener的目标只是重构对speaker的observation时，传统方法可以work，另外如果智能体、Landmark的初始位置固定的时候，也可以work. 也就说明之前提出的MARL算法只能在short time horizons情况下工作。
第二个实验结果是在25000 episodes之后，对比各方法的policy learning success rate
第三个实验结果是统计不同算法下，智能体到达target landmark的episodes占比（这个指标并不等同于智能体的正确策略，因为即便学到了正确的策略，智能体也不一定完全占据目标，详细可以参考文章中的视频链接），还有到目标的平均距离 (percentage of targets reached)
ii. 三个场景：cooperative navigation, predator-prey, covert communication
实验结果2：每个episode的碰撞次数，智能体到目标的平均距离。并将智能体的数量从3个增加到6个(实验用的智能体网络模型是2层全连接，每层128各神经元)
b. predator-prey
实验结果：在两种场景下分别进行实验
第一种场景：prey的速度快30%，统计Predator抓到prey的次数(per episode)------Average number of prey touches by predator per episode
第二种场景：prey的速度快一倍100%, 统计Predator抓到prey的次数(per episode)
(实验用的智能体网络模型是2层全连接，每层128各神经元)
c. covert communication
d. physical deception（智能体数量分别为：N=2, N=4）
实验结果：
将上述表格里的数据做归一化处理画出直方图，所用统计量是归一化的agent score。
验证对baseline算法的改进：
对比单一策略和策略集成（policy ensembles），3种策略集成在三种场景下进行实验：

keep away, N=M=1
physical deception, N=2
predator-prey N=4,L=1

评估:
这一部分是总结对openAi官方代码的分析，并做了一些简单的实验。
2.1 如何在MPE（Multi-Agent Particle Environment）环境中运行该算法？
我是在win10下，tensorflow 1.13（1.14也可以）, python 3.6.8环境进行的。最关键的就是把MPE环境的multiagent文件夹拷贝到MADDPG工程目录下，也要保证gym是安装成功的。调参的话直接调整train.py中的parse_args()函数即可。
跑通之后，如果要切换环境的话需要把要把/tmp/policy文件夹删掉重新开始，否则会出现checkpoint不一致的问题。训练结束之后，可以手动创建learning_curves文件夹以存pickle文件，把下面这句话中的None改为任意str类。测试阶段也需要将benchmark_files文件夹添加到experiments下。
parser.add_argument("--exp-name", type=str, default='', help="name of the experiment")

2.2 一些代码分析
代码结构及各部分功能
./experiments/train.py contains code for training MADDPG on the MPE （用于在MPE环境中训练MADDPG算法的代码），里面还定义了网络结构，是全连接层MLP，隐藏层有64个单元。
./maddpg/trainer/maddpg.py: core code for the MADDPG algorithm（MADDPG算法的核心代码）
./maddpg/trainer/replay_buffer.py: replay buffer code for MADDPG（实现经验重放buffer的代码）
./maddpg/common/distributions.py: useful distributions used in maddpg.py（maddpg.py中要用到的分布）
./maddpg/common/tf_util.py: useful tensorflow functions used in maddpg.py（maddpg.py中要用到的tensorflow函数）
下面根据以上的代码结构一个个分析代码。
具体代码解析
maddpg.py
该文件中包含1个类，4个函数，该类中调用这4个函数以完成相应的功能函数。
4个函数：discount_with_dones； make_update_exp； p_train； q_train
1个类：MADDPGAgentTrainer(AgentTrainer)
详细分析：
p_train(make_obs_ph_n, act_space_n, p_index, p_func, q_func, optimizer, grad_norm_clipping=None, local_q_func=False, num_units=64, scope="trainer", reuse=None):
基本过程：
（p_train函数中相当于创建了placeholder并构建静态图，可以通过调用返回的信息来输出对应值）
创建policy network:
设定action的概率分布类型（pdtype），和概率的值
建立observation和actions的placeholder
并且定义policy网络结构（MLP）, 并存储network的参数，并赋予这些参数概率分布
判断训练的算法是什么：
如果是DDPG，就将local_q_func标记为True，
并将该智能体的局部observation和actions传入给q网络
定义critic网络（传入Policy网络得到的输出动作，全局信息）
定义用于训练policy network的损失函数（q网络的均值），优化器
定义用于输出损失函数、输出动作具体值的callable function，之后的调用相当于feed_dict操作
创建target policy network:
定义target p网络的结构，并存储其网络中的参数
用软更新方式更新target policy网络参数
得到target p网络的输出，即动作值
返回的信息：act, train, update_target_p, {'p_values': p_values, 'target_act': target_act}
（train的输出是训练网络的loss）

这里再补充一些细节并总结：

首先第一步是设置placeholder（只不过这里的代码比较绕，本质上一样）

确定actor网络的输入：每个智能体自己的Observations, 但需要注意的是这些observation是否包括其他智能体的一些信息取决于环境中有关observation部分的设计。

如果使用的是连续动作空间，那么这里的actor network的输出属于Gaussian数据类型，action实际的输出维度是2*action_space[agent_idx]，将网络的输出分为了Mean和Logstd两个部分，最终action的输出的公式为: $\mu + \exp(\log\sigma) \cdot \mathcal N(0,1)$，这里的的$\mu$是维数为action_space[agent_idx]的向量，该表达式中的 $\mathcal N(0,1)$ 的shape与$\mu$一样。目前这里得到的只是placeholder，而之后的U.funtion用于tensorflow常用的feed_dict操作进行静态图激活。 比如连续动作空间的维度设定为[3,3,3,3]，则p网络的参数为（以下为举例）：

action网络的目标函数是：q网络的输出（q网络的输入是所有的actions和Observations）+正则项（以action网络输出为基础），整个目标就是最小化-q

optimizer.minimize()本身分两步：
第一步是optimizer.compute_gradients(objective, var_list=variable list of one network)，返回一个元组：(gradient of variable, variables included)，并在这一步使用tf.clip_by_norm()对其进行clip操作;  第二步是optimizer.apply_gradients(gradients)，将clip之后的梯度用于更新。

q_train(make_obs_ph_n, act_space_n, q_index, q_func, optimizer, grad_norm_clipping=None, local_q_func=False, scope="trainer", reuse=None, num_units=64):
（q_train函数中相当于创建了placeholder并构建静态图，需要通过调用返回的信息来输出对应值）
创建q network:
设定action的概率分布类型（pdtype），和概率的值
建立observation、actions和target q value的placeholder
判断训练的算法是什么：
如果是DDPG，就将local_q_func标记为True，
并将该智能体的局部observation和actions传入给q网络。
定义critic网络（传入Policy网络得到的输出动作），并获取网络参数（以便后续的软更新）
定义用于q网络更新的损失函数, 优化器
定义用于输出损失函数、输出动作具体值的callable function，用于之后调用喂数据。
创建target network:
定义target q网络的结构，并存储其网络中的参数
用软更新方式更新target q网络参数
得到target q网络的输出，即Q值
返回的信息：train, update_target_q, {'q_values': q_values, 'target_q_values': target_q_values}
（train的输出是训练网络的loss）

两个函数的唯一差异就是损失函数的设定。 代码中理解有困难的Python, tensorflow要点我放到了最后一部分。
a. 类初始化函数由两部分组成：
# 定义相关参数：智能体所用trainer的name, trainer的model，状态空间维度，agent的索引Index等
# 定义policy training network, critic training network （用p_train和q_train）
用到了tf_util.py中的Function函数
# 创建replay buffer

b. action：返回动作
def action(self, obs)
根据观测值进行动作选择（应该是神经网络的输入为状态，输出为动作）

c. experience: 将experience数据存到replay buffer中
def experience(self, obs, act, rew, new_obs, done, terminal)
experience的数据为：s, a, r, s_（现在的状态，动作，奖赏值，下一个状态）

d. preupdate
def preupdate(self)

e. update函数
def update(self, agents, t)

update函数的结构：
step 1. 不进行update的两个条件：
# replay buffer的长度小于最大长度，也就是replay_buffer的数据不够的时候不进行update操作
# 如果没到指定的循环次数，不更新。即每隔一定的循环更新一次

step 2. 获取每个智能体在Replay buffer中的数据：根据从batch_data中采样得来的数据，将这些数据分别以列表形式存储

step 3. 训练q网络:
用到q_train函数计算Q网络的输出值，以计算target q value
用获得的target q value计算q网络的loss
计算policy network的loss
更新target policy和target q network的参数（p_update，q_update）

train.py
5个函数:
parse_args()
该函数的目的就是定义训练所需要的参数，基本有以下几类：

环境相关参数
训练用的超参数定义
checkpointing（用于存储数据和模型）
测试阶段的参数

mlp_model(input, num_outputs, scope, reuse=False, num_units=64, rnn_cell=None)：
定义用于各个agent的网络结构，这里使用的是全连接层。
make_env(scenario_name, arglist, benchmark=False)：
该函数用于调用MPE环境，详细环境的API可以参考MPE中的代码。
get_trainers(env, num_adversaries, obs_shape_n, arglist)：
train(arglist)：
用arglist的参数，定义整个的训练过程，训练的过程如下：
创建环境和每个智能体的训练网络、初始化所有变量
(如有必要，加载之前存储的模型参数)
主循环部分：
获取所有智能体的动作列表（每一个智能体）
环境根据所有智能体的actions, 进行step操作(以获取新的状态、奖赏、done、info)
收集experience，并将其存储到replay buffer中：
先存储每个训练器的experience
用step得到的新的状态信息更新原来的状态信息
累计reward值（一个是episode整个的reward，另一个是agent的reward）
如果一个episode结束，则重置环境，更新step=0，重新分别向episode reward，agent_reward列表中添加一个0
根据是否benchmark, display进行不同操作：
如果是benchmark==True，就对learned policy进行测试，然后存储数据
如果是display==True, 就对环境进行渲染env.render()
训练网络（更新网络参数）
每隔一些steps （save_rate），存储训练好的模型，并格式化输出损失、训练所消耗的时间等
存储最后一次训练的模型产生的数据（智能体、全局的奖赏）

具体代码参考openAI官方代码。
common/tf_util.py
重点看了下_Function类，该类的基本目的就是简化tf的feed_dict过程。
function函数和_Function类：
I. function函数的输入输出：
输入：将要输入数据的placeholders
输出：将要根据placeholders进行计算的表达式, 返回Lambda函数
（需要用到python中的lambda函数）
II. function函数的流程：
判断outputs的形式：是list, dict或者其他形式
如果是list: 返回_Function的对象，输出也是list
如果是dict, 返回_Function对象，输出是dict
其他情况，返回_Function对象的第一个元素

# _Function类：
初始化:
检查constructor中的inputs是否是TfInput的一个子类
（TfInput是PlacholderTfInput, BatchInput, Uint8Input的父类,后两者是PlacholderTfInput的子类）
对类内的变量进行赋值

_feed_input()
更新feed_dict的值，向其添加新的键值对

__call__(*args, *kwargs)函数：（让_Function的对象能被调用）
该函数的目的就是将给_Function()对象的输入，作为feed_dict传给Placeholder，最后输出激活placeholder之后的值。

replay_buffer.py
初始化__init__和长度__len__：
_storage
_maxsize
_next_idx

清除操作：
_storage清空；_next_idx清零

类内的函数method：
如果索引超过当前存储数据的长度，则添加这些数据
如果索引小于当前存储数据的长度，则替换该位置之前的数据
索引值自加1之后对storage maxsize求余，保证该数值不会超过最大存储长度
ii. _encode_sample
将每个智能体的数据汇总成一个更长的list，这些数据包括：obses_t, actions, rewards, obses_tp1, dones
iii. make_index
从存储器中随机抽取batch_size长度的数据
iv. make_latest_index:
先从当前Index倒叙排序，一直到maxsize，例如：[_next_idx-1, ..., 0, batch_size-1, ....next_idx]
将上述list打乱
v. sample
给定idxes，从storage中抽取这些数据
vi. collect
return sample(-1)
指的是收集这些数据的阶段

2.3 已测试的实验
2.4 一些Python与tensorflow相关语法要点的记录
Python相关要点
函数形参实参前的*号
单星号（*）用于导入：agrs，将所有参数以元组(tuple)的形式导入
单星号（）也可以用于解压参数列表
双星号（**）：kwargs，双星号（）将参数以字典的形式导入
lambda函数使用方法（匿名函数anonymous functions）
https://www.cnblogs.com/huangbiquan/p/8030298.html
lambda x,y : x+y

lambda之后的变量为该匿名函数的输入，冒号后面为该函数的输出，整个语句等同于def function，属于function
python中的pickle库：
https://docs.python.org/3/library/pickle.html
介绍：
The pickle module implements binary protocols for serializing and de-serializing a Python object structure.
“Pickling” is the process whereby a Python object hierarchy is converted into a byte stream, and “unpickling” is the
inverse operation, whereby a byte stream (from a binary file or bytes-like object) is converted back into an object hierarchy.
python内置all函数
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE，如果是返回 True，否则返回 False
all([0,1,1]) # False
all([1,1,1]) # True

collections库相关
collections.OrderedDict

会按照输入的键值对顺序来排序,而python本身的字典是不考虑顺序的
Python object中的__call__函数:
https://www.cnblogs.com/xinglejun/p/10129823.html
所有的函数都是可调用对象。一个类实例也可以变成一个可调用对象，只需要实现一个特殊方法__call__,该对象(注意是对象, 不是类)可被当成函数调用
类的实例化对象(即object)可以充当函数使用.
示例程序:
class X(object):
def __init__(self,a,b):
self.a = a
self.b = b
print(self.a, self.b, ' this is initialization of class X')

def __call__(self, *args, **kwargs):
self.a = args
self.b = kwargs
print(self.a, self.b, ' this is calling class X')

xInstance = X(1,2)
xInstance(1,2,3,c=1,d=2)

Python中字典中的update方法——Dict.update()
把字典dict2的键/值对更新到dict里:
dict.update(dict2)
例子程序:
a = {'a':1, 'b':1}
b = {'c':2}
a.update(b) # {'a': 1, 'b': 1, 'c': 2}

Tensorflow相关要点
tf.train.Saver相关: (tf 1.13)
https://github.com/tensorflow/docs/blob/r1.13/site/en/api_docs/python/tf/train/Saver.md
介绍：
The Saver class adds ops to save and restore variables to and from checkpoints. It also provides convenience methods
to run these ops.
Checkpoints are binary files in a proprietary format which map variable names to tensor values.
Constructor:
__init__(
var_list=None, # variables that will be saved and restored, can be passed as a dict or a list
reshape=False, # if true, restore a variable from a save file where the variable had a different shape, but the same number of elements and type
sharded=False, # if true, instructs the saver to shard checkpoints, one per device
max_to_keep=5, # maximum number of recent checkpoint files to keep, as new files are created, older files are deleted
keep_checkpoint_every_n_hours=10000.0, # How often to keep checkpoints.
name=None, # Optional name to use as a prefix when adding operations
restore_sequentially=False, # restore different variables
saver_def=None,
builder=None,
defer_build=False, # If True, defer adding the save and restore ops to the build() call.
# In that case build() should be called before finalizing the graph or using the saver.
allow_empty=False, # If False (default) raise an error if there are no variables in the graph
write_version=tf.train.SaverDef.V2,
save_relative_paths=False,
filename=None
)

程序中用到的Methods:
save (tf.train.Saver.save)
e.g.:
saver.save(sess, 'my-model', global_step=0) ==> filename: 'my-model-0'

save(
sess, # A Session to use to save the variables.
save_path, # Prefix of filenames created for the checkpoint.
global_step=None, # If provided the global step number is appended to save_path to create the checkpoint filenames
latest_filename=None,
meta_graph_suffix='meta', # Suffix for MetaGraphDef file. Defaults to 'meta'
write_meta_graph=True, # Boolean indicating whether or not to write the meta graph file.
write_state=True, # indicating whether or not to write the CheckpointStateProto
strip_default_attrs=False
)

restore (tf.train.Saver.restore)
介绍：
Restores previously saved variables. The variables to restore do not have to have been initialized, as restoring is
itself a way to initialize variables.
restore(
sess, # A Session to use to restore the parameters. None in eager mode.
save_path # Path where parameters were previously saved.
)


存储的文件格式：

.data-00000-of-00001
保存了当前参数名和值
.index
保存了辅助索引信息
.meta
保存了当前图结构.
checkpoint
记录了模型文件的路径信息列表

tf.get_default_session:
返回Innermost的session,
tf.group:
函数原型:
tf.group(
*inputs,
**kwargs
)

Create an op that groups multiple operations. 组合多个运算
When this op finishes, all ops in inputs have finished. This op has no output.


展开全文
• 之前接触的强化学习算法都是单个智能体的强化学习算法，但是也有很重要的应用场景牵涉到智能体之间的交互，比如说，个机器人的控制，语言的交流，玩家的游戏等等。本文，就带你简单了解一下Open-AI的...
• ICLR 2020 多智能体强化学习论文总结如有错误，欢迎指正所引用内容链接Multi-Agent RL1.Multi-agent Reinforcement Learning For Networked System Control2.Intrinsic Motivation For Encouraging Synergistic ...
• 关于模糊系统见上一篇。 游戏描述： 以多人领土保卫游戏（guarding territory）为例：进攻者...防卫者作为智能体，输入和输出分别经过模糊化和去模糊化处理。 模糊系统 nnn个输入变量的连续输入空间被离散化为MMM个...
• RL之SARSA：利用强化学习之SARSA实现走迷宫—训练智能体走到迷宫(复杂陷阱迷宫)的宝藏位置 目录 输出结果 设计思路 实现代码 测试记录全过程 输出结果 设计思路 实现代码 后期更新...
• RL之Q Learning：利用强化学习之Q Learning实现走迷宫—训练智能体走到迷宫(简单迷宫)的宝藏位置 目录 输出结果 设计思路 实现代码 测试记录全过程 输出结果 设计思路 实现代码 from ...
• RL之Q Learning：利用强化学习之Q Learning实现走迷宫—训练智能体走到迷宫(复杂迷宫)的宝藏位置 目录 输出结果 设计思路 实现代码 测试记录全过程 输出结果 设计思路 实现代码 ...
• ## 智能体路径规划

千次阅读 2017-11-07 10:23:07
C++实现代码如下： #include #include #include #include #include #include #include using namespace std; ofstream out_explore("d:\\explore.txt"); ofstream out_use("d:\\...
• ## 多智能体系统（Multi-agent system）

万次阅读 多人点赞 2015-03-03 13:30:35
Swarm是美国新墨西哥州的桑塔费研究所（The Santa Fe Institute，SFI）1994年起开发的一个面向对象程序设计（OOP）的多智能体仿真软件工具，是一种基于复杂适应系统（complex adaptive system，CAS）发展起来的支持...
• 多智能体强化学习在城市交通网络信号 控制方法中的应用综述 交通信号控制系统在物理位置和控制逻辑上分散于动态变化的网络交通环境， 将每个路口的交通信号控制器看做一个异质的智能体， 非常适合采用无模型、自...
• MobileNet是针对移动端优化的卷积，所以当需要压缩模型时，可以考虑使用MobileNet替换卷积。下面我们开始学习MobileNet原理，并且先通过Tensorflow函数接口实现MobileNet，再手写python代码实现MobileNet。
• 从本篇文章开始，作者正式开始...本文主要结合作者之前的博客、AI经验和相关视频介绍，后面随着深入会讲解更的Python人工智能案例及应用。基础性文章，希望对您有所帮助，如果文章中存在错误或不足之处，还请海涵~
• 点击上方关注我们!嗨！听说最近有一部大片《全场景智慧》正在热映，去瞧瞧啊？又是些玄之又玄的东西吧？没兴趣！据说是讲述如何借助“智能体”打造智慧城市、智慧行业和智慧企业，赋能千行百业智能升...
• 摘要：在HUAWEI CONNECT 2020上，华为云与计算BG总裁侯金龙发布了智能体，这是业界首次针对政企智能升级提出的系统化参考架构。 近日，在HUAWEI CONNECT 2020上，华为云与计算BG总裁侯金龙发布了智能体，这是业界...
• 近年以来，强化学习在人工智能所充当的角色越来越重要了，很研究机构和大学都将强化学习与深度学习相结合打造高性能的系统。因此，本文注重描述强化学习的基本概念与实现，希望能为读者介绍这一机器学习分支的巨大...
• https://zhuanlan.zhihu.com/p/55003734
• 作为一名软件开发人员，我相信大家都对面向对象技术有个比较深刻的认识。面向对象技术的确为提高软件开发效率做出了巨大的贡献。但是在我们的开发过程中，面向对象也暴露了...本文首先介绍一下智能体的基本概念，然后
• ## UML中常见代码实现

万次阅读 热门讨论 2016-10-02 22:42:44
强烈推荐一个大神的人工智能的...在此之前我对面向对象的一些方法做过一些总结，感兴趣的读者可以参看《面向对象三大特性》《面向对象》，其中对构造函数等等做了一些解释，这在理解代码实现的时候很有帮助。 代...
• 九、基于智能体的模型 原文：Chapter 9 Agent-based models 译者：飞龙 协议：CC BY-NC-SA 4.0 自豪地采用谷歌翻译 我们迄今为止看到的模型可能具有“基于规则”的特征，因为它们涉及受简单规则支配的...
• 上一篇文章介绍，一个随机博弈可以看成是一个多智能体强化学习过程。其实这两个概念不能完全等价，随机博弈中假定每个状态的奖励矩阵是已知的，不需要学习。而多智能体强化学习则是通过与环境的不断交互来学习每个...
• ## 深度 | 人工智能究竟能否实现？

万次阅读 多人点赞 2019-03-31 16:36:34
作者 | 李理，环信人工智能研发中心vp，十多年自然语言处理和...本文讨论人工智能是否可以实现这个哲学问题。本文是《深度学习理论与实战：提高篇》的一章。 更内容请查看：http://fancyerii.github.io/tags/ ...

...