强化学习学习模块(learners.py)包含实现各种强化学习方法的类。DQNLearner、PolicyGradientLearner、ActorCriticLearner、A2CLearner 和 A3CLearner 分别是基于深度 Q -learning、策略梯度、Actor-critic、A2C 和 A3C 强化学习技术的类实现。根据股票投资的特点,每种技术在理论上可能略有不同。
reset()以下代码片段显示了一个函数,该函数使用存储在每个 epoch 中的新数据初始化变量。
def reset(self):
self.sample = None
self.training_data_idx = -1
# 初始化环境
self.environment.reset()
# 初始化代理
self.agent.reset()
# 初始化可视化
self.visualizer.clear([0, len(self.chart_data)])
# 初始化内存
self.memory_sample = []
self.memory_action = []
self.memory_reward = []
self.memory_value = []
self.memory_policy = []
self.memory_pv = []
self.memory_num_stocks = []
self.memory_exp_idx = []
self.memory_learning_idx = []
# 初始化epoch相关信息
self.loss = 0.
self.itr_cnt = 0
self.exploration_cnt = 0
self.batch_size = 0
self.learning_cnt = 0
此函数重置为从头开始training_data_idx再次读取训练数据。-1随着训练数据的读取,该值增加 1。读取的数据存储在样本中,但由于初始化阶段没有读取训练数据,因此将其分配为 None。
此外,它初始化所有与环境、代理、可视化、memory和epoch相关的信息。environment,调用 的函数agent和reset()的visualizer函数。clear()并memory_*清空列表。
初始化epoch相关信息。loss 是一个变量,用于存储神经网络的结果与训练数据的差异程度。loss建议值随着训练的进行而减小。
itr_cnt该变量存储执行的时期数。exploration_cnt该变量存储进行随机投资的次数。epsilon如果这是 0.1,并且您有 100 个投资决策,您将进行大约 10 个随机投资。
要训练的 mini-batch 的大小batch_size存储在 中,learning_cnt在一个 epoch 中执行的 mini-batch 训练的数量存储在 中。
build_sample()下面显示了一个函数,该函数生成一个构成训练数据的样本。
def build_sample(self):
self.environment.observe()
if len(self.training_data) > self.training_data_idx + 1:
self.training_data_idx += 1
self.sample = self.training_data.iloc[
self.training_data_idx].tolist()
self.sample.extend(self.agent.get_states())
return self.sample
return None
调用环境对象observe()中的函数从图表数据中的当前索引读取下一个索引数据。并检查训练数据上的下一个索引是否存在。
如果训练数据中存在下一个索引数据,training_data_idx则将变量加1,从training_data数组中获取training_data_idx索引的数据,sample并将其存储为 . 到目前为止,样本数据由 26 个值组成。接下来,sample添加一个代理状态以sample使用 28 个值对其进行配置。
。
例 1 显示了一个生成批量训练数据的get_batch()函数和一个训练神经网络以训练神经网络的函数update_networks()。
示例1 ReinforcementLearner 类中的 get_batch()、
@abc.abstractmethod
def get_batch(self, batch_size, delayed_reward, discount_factor):
pass
def update_networks(self,
batch_size, delayed_reward, discount_factor):
# 生成批量训练数据
x, y_value, y_policy = self.get_batch(
batch_size, delayed_reward, discount_factor)
if len(x) > 0:
loss = 0
if y_value is not None:
# 更新价值神经网络
loss += self.value_network.train_on_batch(x, y_value)
if y_policy is not None:
# 更新策略神经网络
loss += self.policy_network.train_on_batch(x, y_policy)
return loss
return None
get_batch()函数是一个抽象方法,ReinforcementLearner类的子类必须实现这个函数。ReinforcementLearner如果您从一个类继承但没有实现此抽象方法,NotImplemented则会引发异常。
update_networks()函数get_batch()调用函数生成批量训练数据,调用神经网络类的tra函数训练价值神经网络和策略神经网络in_on_batch()。价值神经网络从DQNLearner,ActorCriticLearner中学习,A2CLearner策略神经网络从PolicyGradientLearner, ActorCriticLearner,中学习A2CLearner。
返回训练后发生的损失。如果我们同时训练一个价值神经网络和一个策略神经网络,我们会返回两个训练损失的总和。
以下代码片段fit()显示了 ReinforcementLearner 类中的一个函数。
ReinforcementLearner 类中的 fit() 函数
def fit(self, delayed_reward, discount_factor):
# 批量训练数据生成和神经网络更新
if self.batch_size > 0:
_loss = self.update_networks(
self.batch_size, delayed_reward, discount_factor)
if _loss is not None:
self.loss += abs(_loss)
self.learning_cnt += 1
self.memory_learning_idx.append(self.training_data_idx)
self.batch_size = 0
fit()该函数调整批量训练数据的大小update_networks()并调用该函数。然后,将返回的学习损失值_loss添加loss到 。loss将在 epoch 期间产生总的学习损失。learning_cnt我们将训练的数量存储在其中,然后除以,被认为是 epoch 中的学习损失loss。learning_cnt并将memory_learning_idx学习位置保存在 .
是否使用 epoch 中积累的所有数据进行训练是一个 full 参数,如果 full 为 True,则对整个数据进行训练。这用于在 epoch 结束时进一步训练价值神经网络。
以下代码片段是完成一个 epoch 以可视化 epoch 相关信息的部分
def visualize(self, epoch_str, num_epoches, epsilon):
self.memory_action = [Agent.ACTION_HOLD] \
* (self.num_steps - 1) + self.memory_action
self.memory_num_stocks = [0] * (self.num_steps - 1) \
+ self.memory_num_stocks
if self.value_network is not None:
self.memory_value = [np.array([np.nan] \
* len(Agent.ACTIONS))] * (self.num_steps - 1) \
+ self.memory_value
if self.policy_network is not None:
self.memory_policy = [np.array([np.nan] \
* len(Agent.ACTIONS))] * (self.num_steps - 1) \
+ self.memory_policy
self.memory_pv = [self.agent.initial_balance] \
* (self.num_steps - 1) + self.memory_pv
我们可视化的是代理的行为、持有的股票数量、价值神经网络输出、策略神经网络输出、投资组合价值、探索位置、学习位置等。
使用LSTM神经网络和CNN神经网络时,agent行为、持股数量、价值神经网络输出、策略神经网络输出、投资组合价值在第一部分用无意义的值填写,num_steps – 1因为它们少高于环境的日均值。num_steps – 1
Python 提示:在 Python 中,当您将一个列表相乘时,相同的列表会附加到末尾。例如,[1, 2, 3] * 3将[1, 2, 3, 1, 2, 3, 1, 2, 3]是。
self.visualizer.plot(
epoch_str=epoch_str, num_epoches=num_epoches,
epsilon=epsilon, action_list=Agent.ACTIONS,
actions=self.memory_action,
num_stocks=self.memory_num_stocks,
outvals_value=self.memory_value,
outvals_policy=self.memory_policy,
exps=self.memory_exp_idx,
learning_idxes=self.memory_learning_idx,
initial_balance=self.agent.initial_balance,
pvs=self.memory_pv,
)
self.visualizer.save(os.path.join(
self.epoch_summary_dir,
'epoch_summary_{}.png'.format(epoch_str))
)
调用对象上visualizer的函数。plot()并将生成的epoch结果图片保存为PNG图片文件。
run()函数是ReinforcementLearner一个类的核心函数,它的长度也比较长。所以,让我们把它分解成几个部分。下面run()显示了函数的声明部分。
def run(
self, num_epoches=100, balance=1000000,
discount_factor=0.9, start_epsilon=0.5, learning=True):
info = "[{code}] RL:{rl} Net:{net} LR:{lr} " \
"DF:{discount_factor} TU:[{min_trading_unit}," \
"{max_trading_unit}] DRT:{delayed_reward_threshold}".format(
code=self.stock_code, rl=self.rl_method, net=self.net,
lr=self.lr, discount_factor=discount_factor,
min_trading_unit=self.agent.min_trading_unit,
max_trading_unit=self.agent.max_trading_unit,
delayed_reward_threshold=self.agent.delayed_reward_threshold
)
with self.lock:
logging.info(info)
# 开始时间
time_start = time.time()
num_epoches是要执行的迭代总数。随着价值神经网络和策略神经网络通过迭代学习朝着增加投资组合价值的方向逐渐更新,需要设置足够的迭代次数。但num_epoches设置过大,学习时间会过长,所以要适当设置。这取决于你训练了多少数据,但这里将默认值设置为 100。
balance是决定代理人初始投资资金的因素。
discount_factor是找到状态动作值时应用的贴现率。当奖励发生时,当前奖励会影响在上一次奖励发生和当前奖励发生之间所采取的所有行动。此时,过去越远,应用当前奖励就越弱,因为当你进入过去时,应用当前奖励的基础变得模糊。
start_epsilon是初始探索率。在强化学习的早期,探索率应该很大,以允许更多的探索,即随机投资。通过探索,您可以获得经验来确定在特定情况下什么是好的,什么不是。
learning是一个布尔值,决定是否学习。布尔值是一个二进制值,可以是 True 或 False。训练后,创建训练好的价值神经网络模型和策略神经网络模型。learning如果你想通过这种方式训练来做一个神经网络模型True,learning给False。
run()当它进入函数时,它会记录强化学习设置。并节省学习开始时间。这是记录学习结束后的时间差作为学习时间。
# 准备可视化
# 由于图表数据没有变化,所以提前可视化。
self.visualizer.prepare(self.environment.chart_data, info)
# 准备一个文件夹来保存可视化结果
self.epoch_summary_dir = os.path.join(
self.output_path, 'epoch_summary_{}'.format(
self.stock_code))
if not os.path.isdir(self.epoch_summary_dir):
os.makedirs(self.epoch_summary_dir)
else:
for f in os.listdir(self.epoch_summary_dir):
os.remove(os.path.join(self.epoch_summary_dir, f))
# 设置代理的初始资本
self.agent.set_balance(balance)
# 初始化学习信息
max_portfolio_value = 0
epoch_win_cnt = 0
通过调用可视化对象上visualizer的函数来prepare()准备可视化。prepare()该功能将图表数据提前可视化。
并准备好保存可视化结果的路径。可视化结果保存在output_path路径下的文件夹中epoch_summary_*。如果文件夹中已经epoch_summary_*保存了文件,则所有文件都将被删除。
并设定代理的初始资金。100万RMB作为基本资本。
max_portfolio_value该变量存储执行的时期中最高的投资组合价值。epoch_win_cnt该变量存储执行的时期中获利时期的数量。也就是说,投资组合价值超过初始资本的时期数。
以下是循环的介绍部分,该循环通过重复指定数量的 epoch 的股票投资模拟来学习。
#重复学习
for epoch in range(num_epoches):
time_start_epoch = time.time()
q_sample = collections.deque(maxlen=self.num_steps)
# 环境、代理、神经网络、可视化、内存初始化
self.reset()
# 探索率随着学习的进展而降低
if learning:
epsilon = start_epsilon \
* (1. - float(epoch) / (num_epoches - 1))
self.agent.reset_exploration()
else:
epsilon = start_epsilon
Python 提示:在 Python 中,代码块由缩进分隔。特别是在使用 , class, def, if, elif, else, for, while, try, except,final等with时要注意缩进。
进入循环时,首先记录epoch的开始时间。这是为了查看执行一个 epoch 需要多长时间。
并num_step初始化一个队列以容纳尽可能多的样本。
Python 提示:队列是先进先出 (FIFO) 数据结构。甲板可以被视为一个交互式队列。在 Python 中,您可以将交互式队列数据结构创建为collections模块中的函数。deque这时候,maxlen你可以通过给一个参数来限制这个交互队列的大小。
然后,调用 reset() 函数来初始化每个 epoch 初始化的环境、代理、神经网络、可视化信息和内存。
随着每个时期,epsilon 从 start_epsilon 逐渐减小。 在确定 epsilon 值时,start_epsilon 值,即初始随机投资比率,乘以当前 epoch 数乘以学习进度。 例如,如果 start_epsilon 为 0.5,则第一个 epoch 有 30% 的机会进行随机投资。 假设要执行的 epoch 总数为 100,在第 50 个 epoch,epsilon 变为 0.5×(1-49/99)≈0.49。 然后,通过调用代理对象的 reset_exploration() 函数,exploration_base 被重新设置。 explore_base 是随机设置的,值越大,基于购买的探索越多。
while True:
# 创建训练样本
next_sample = self.build_sample()
if next_sample is None:
break
# 按 num_steps 存储样本
q_sample.append(next_sample)
if len(q_sample) < self.num_steps:
continue
调用 build_sample() 函数从环境对象中读取一个样本。 如果 next_sample 为 None,则数据已读完,因此 while 循环结束。
num_stepscontinue后面的逻辑被跳过,直到样本队列中的样本满了,因为样本的数量必须准备好来确定动作。
下面是用价值神经网络和策略神经网络计算预测动作值和预测动作概率的一部分。
# 价值,策略神经网络预测
pred_value = None
pred_policy = None
if self.value_network is not None:
pred_value = self.value_network.predict(
list(q_sample))
if self.policy_network is not None:
pred_policy = self.policy_network.predict(
list(q_sample))
# 通过神经网络或探索确定行为
action, confidence, exploration = \
self.agent.decide_action(
pred_value, pred_policy, epsilon)
# 执行你决定的行动并获得即时和延迟奖励
immediate_reward, delayed_reward = \
self.agent.act(action, confidence)
调用每个神经网络对象的函数,predict()得到预测动作值和预测动作概率。动作由以这种方式获得的值和概率决定。
投资行为是由这样得到的预测值和概率决定的。在这里,您在买卖之间做出决定。这种行为决策要么以随机投资比率值的概率随机作出,要么epsilon通过神经网络的输出作出。策略神经网络的输出表示在买卖时增加投资组合价值的概率。也就是说,如果买入的策略神经网络输出高于卖出的输出,则选择买入,反之亦然。如果策略神经网络没有输出,则选择价值神经网络输出较高的动作。价值神经网络的输出是动作的预测值(盈亏比)。
decide_action()该函数返回三个值。它是决策行为,决策action的确定性程度,以及confidence是否存在随机投资exploration。
act()调用代理的函数来执行它已经决定的动作。act()函数执行操作并返回即时和延迟奖励。
下一部分将执行的动作和动作的结果存储在内存中并执行学习。
# 记住动作和动作的后果
self.memory_sample.append(list(q_sample))
self.memory_action.append(action)
self.memory_reward.append(immediate_reward)
if self.value_network is not None:
self.memory_value.append(pred_value)
if self.policy_network is not None:
self.memory_policy.append(pred_policy)
self.memory_pv.append(self.agent.portfolio_value)
self.memory_num_stocks.append(self.agent.num_stocks)
if exploration:
self.memory_exp_idx.append(self.training_data_idx)
# 更新迭代信息
self.batch_size += 1
self.itr_cnt += 1
self.exploration_cnt += 1 if exploration else 0
# 发生延迟补偿时的小批量训练
if learning and (delayed_reward != 0):
self.fit(delayed_reward, discount_factor)
# epoch 结束后的学习
if learning:
self.fit(self.agent.profitloss, discount_factor)
我们将动作和动作结果存储在以memory开头的变量中。这些变量是存储训练数据样本、代理行为、即时奖励、价值神经网络输出、策略神经网络输出、投资组合价值、持有的股票数量和探索头寸的数组。内存变量有两个用途(1)作为训练中的批量训练数据和(2)在可视化器中绘制图表时。
增加批大小batch_size、迭代次数itr_cnt、随机投资次数exploration_cnt。 对于exploration_cnt,仅在已探索时增加1,否则添加0 不做任何更改。
当延迟补偿发生时,调用神经网络训练函数 fit()。 当发生超过延迟补偿阈值的损益时,将授予延迟补偿。
在 while 块中,它从环境中接收样本并执行一个 epoch。 当没有更多样本时退出 while 块。 退出 while 块后学习剩余的小批量。 在这种情况下,由于大多数情况下没有发生延迟补偿,因此使用代理对象的盈亏比。
这样while,它从块内的环境中接收样本并执行一个 epoch。当没有更多样本时while退出该块。while退出区块后学习剩余的小批量。在这种情况下,大部分延迟补偿都没有发生,所以使用代理对象的盈亏比。
Python 提示:Python 允许if else将语句写在一行上。例如,让我们编写代码,当x大于0或等于时1递增,0小于时1递减。以通用方式,您可以编写:
if x >= 0:
x += 1
else:
x -= 1
在 Python 中,您可以像这样在一行中编写此代码:x += 1 if x >= 0 else -1
以下是记录和可视化有关一个 epoch 的信息的部分。
#epoch相关的日志信息
num_epoches_digit = len(str(num_epoches))
epoch_str = str(epoch + 1).rjust(num_epoches_digit, '0')
time_end_epoch = time.time()
elapsed_time_epoch = time_end_epoch - time_start_epoch
if self.learning_cnt > 0:
self.loss /= self.learning_cnt
logging.info("[{}][Epoch {}/{}] Epsilon:{:.4f} "
"#Expl.:{}/{} #Buy:{} #Sell:{} #Hold:{} "
"#Stocks:{} PV:{:,.0f} "
"LC:{} Loss:{:.6f} ET:{:.4f}".format(
self.stock_code, epoch_str, num_epoches, epsilon,
self.exploration_cnt, self.itr_cnt,
self.agent.num_buy, self.agent.num_sell,
self.agent.num_hold, self.agent.num_stocks,
self.agent.portfolio_value, self.learning_cnt,
self.loss, elapsed_time_epoch))
# 可视化epoch相关信息
self.visualize(epoch_str, num_epoches, epsilon)
# 更新学习相关信息
max_portfolio_value = max(
max_portfolio_value, self.agent.portfolio_value)
if self.agent.portfolio_value > self.agent.initial_balance:
epoch_win_cnt += 1
一个epoch的日志记录包括股票代码、当前时期编号、该时期的探索率、时期内执行的买入操作数、卖出操作数、等待次数、持有的股票数量、达到的投资组合价值、以及在 epoch 期间执行的小批量学习。包括次数、学习损失和执行 epoch 所用的时间。
检查字符串长度以获取 epoch 总数。 如果 epoch 的总数为 1,000,则长度为 4。 使用当前的 epoch 数创建一个长度为 num_epoches_digit 的字符串,并将其存储在 epoch_str 中。 假设我们正在创建一个 4 位数的字符串,在第一个 epoch 的情况下,由于 epoch 为 0,我们加 1 并在前面填写“0”以形成“0001”。
并且时间 elapsed_time_epoch 是通过从当前时间 time_end_epoch 中减去 time_start_epoch 来保存的。 损失变量是该时期执行的小批量的所有学习损失的总和。 将损失除以训练次数,并将其更新为小批量的平均训练损失。
Python 提示:rjust()函数是通过位数对字符串进行右对齐的函数。例如,如果"1".rjust(5)您' 1'这样做。前面填4个空格,加1组成一个5位数的字符串。您还可以指定要填充的字符而不是空格作为第二个参数。"1".rjust(5, '0')变成'00001'.
一个类似的函数是一个ljust()函数。此函数填充现有字符串前面的空格或特定字符。这种填充在现有字符之前或之后称为填充。
Python 提示:在 Python 字符串format()函数中,您可以通过在关键字名称前加上冒号 (:) 来指定格式选项。{:,.0f}表示千位加逗号(,),不显示小数点。
使用可视化对象,将时代信息可视化为图片并将其保存为文件。 为此,我们调用了可视化()函数。
现在更新学习相关信息。 在执行一个时期时,如果投资组合价值高于该时期的权益,则更新最大投资组合价值并增加 epoch_win_cnt。
这是对应于语句块的 epoch 迭代的部分。 以下代码段显示了在所有 epoch 执行后强化学习执行功能的剩余逻辑。
# 结束时间
time_end = time.time()
elapsed_time = time_end - time_start
# # 记录学习相关信息
with self.lock:
logging.info("[{code}] Elapsed Time:{elapsed_time:.4f} "
"Max PV:{max_pv:,.0f} #Win:{cnt_win}".format(
code=self.stock_code, elapsed_time=elapsed_time,
max_pv=max_portfolio_value, cnt_win=epoch_win_cnt))
执行所有 epoch 并记录执行所有 epoch 所需的时间。然后,它记录总前置时间、最大投资组合价值以及投资组合价值高于股本的时期数。
以下函数保存训练好的神经网络模型。
ReinforcementLearner 类:神经网络模型存储功能
def save_models(self):
if self.value_network is not None and \
self.value_network_path is not None:
self.value_network.save_model(self.value_network_path)
if self.policy_network is not None and \
self.policy_network_path is not None:
self.policy_network.save_model(self.policy_network_path)
如果存在价值神经网络,则检查价值神经网络模型文件路径save_model()并调用神经网络类中的函数。同样,如果存在学习的策略神经网络,则将其保存到文件中。
DQN 是一种仅使用价值神经网络的强化学习方法。下面展示了 DQNLearner 类的构造函数和生成批量训练数据的函数。
示例 DQNLearner 类
class DQNLearner(ReinforcementLearner):
def __init__(self, *args, value_network_path=None, **kwargs):
super().__init__(*args, **kwargs)
self.value_network_path = value_network_path
self.init_value_network()
def get_batch(self, batch_size, delayed_reward, discount_factor):
memory = zip(
reversed(self.memory_sample[-batch_size:]),
reversed(self.memory_action[-batch_size:]),
reversed(self.memory_value[-batch_size:]),
reversed(self.memory_reward[-batch_size:]),
)
x = np.zeros((batch_size, self.num_steps, self.num_features))
y_value = np.zeros((batch_size, self.agent.NUM_ACTIONS))
value_max_next = 0
reward_next = self.memory_reward[-1]
for i, (sample, action, value, reward) in enumerate(memory):
x[i] = sample
y_value[i] = value
r = (delayed_reward + reward_next - reward * 2) * 100
y_value[i, action] = r + discount_factor * value_max_next
value_max_next = value.max()
reward_next = reward
return x, y_value, None
在 DQNLearner 的构造函数中,我们将 value_network_path 保存为一个属性,并调用 init_value_network() 函数来创建值神经网络。 DQNLearner 继承自 ReinforcementLearner 类,因此它具有 ReinforcementLearner 的所有属性和功能。任何扩展 ReinforcementLearner 的类都必须实现 get_batch() 函数,它是 Reinforcement-Learner 类的抽象方法。
在 DQNLearner 的 get_batch() 函数中,我们首先捆绑内存数组。此时,内存阵列是反向绑定的。并准备一个样本数组 x 和一个标签数组 y_value。该数组用全零填充。
Python 提示:您可以在 Python 中反转列表。以下是反转列表的三种方法。列表变量的 reverse() 函数、
reversed() 内置函数和 [::-1] 切片技巧可用于反转列表的元素。当有一个名为 lst 的列表变量时,它可以像
lst.reverse()、reversed(lst)、lst[::-1] 一样使用。请注意, lst.reverse() 反转 lst
变量本身。也就是说, reverse() 函数就地更改值。 reversed() 内置函数返回一个 lst 反转的新列表。
lst[::-1] 切片技巧也返回一个新列表。 Python 提示:NumPy 的 zeros()
函数将数组的形状作为参数。返回填充了零的此形状的数组。例如, zeros(3, 1) 返回 [0, 0, 0], zeros((2, 2))
返回 [ [0, 0], [0, 0] ]。请注意,在多维数组的情况下,类型必须作为元组传递。
现在用 for 语句为样本数组和标签数组填充值。因为python列表是向后取的,所以 for 语句从批量训练数据的最后一部分开始。首先,我们将样本填入 x[i],并将值神经网络的输出放入 y_value[i]。
在变量 r 中,我们得到用于训练的奖励并将其存储。其中delayed_reward 是批处理数据中的延迟奖励,reward 是执行行为获得得奖励。最终奖励和当前奖励相减,执行下一个动作时的盈亏百分比和执行当前动作时的盈亏百分比相加。
然后,将贴现率应用于下一个状态的最大值,并添加 r。应用这个值作为状态动作值来学习。下一个状态的最大值存储在变量 value_max_next 中。并将下一个动作时的盈亏比存储在 next_reward 变量中。
Python 提示:NumPy 数组具有基本的统计函数,如 min()、max()、mean() 等。你可以像
np_array.min()、np_array.max()、np_array.mean() 一样使用它。
get_batch() 函数最终返回一个样本数组、一个值神经网络训练标签数组和一个策略神经网络训练标签数组。在 DQNLearner 的情况下,策略神经网络训练标签数组部分被视为无,因为它不使用策略神经网络。
可以修改 get_batch() 函数,以其他方式生成批量训练数据
策略梯度强化学习是一种仅使用策略神经网络进行强化学习的方法。下面展示了用于策略梯度强化学习的 PolicyGradientLearner 类。
PolicyGradientLearner 类
class PolicyGradientLearner(ReinforcementLearner):
def __init__(self, *args, policy_network_path=None, **kwargs):
super().__init__(*args, **kwargs)
self.policy_network_path = policy_network_path
self.init_policy_network()
def get_batch(self, batch_size, delayed_reward, discount_factor):
memory = zip(
reversed(self.memory_sample[-batch_size:]),
reversed(self.memory_action[-batch_size:]),
reversed(self.memory_policy[-batch_size:]),
reversed(self.memory_reward[-batch_size:]),
)
x = np.zeros((batch_size, self.num_steps, self.num_features))
y_policy = np.full((batch_size, self.agent.NUM_ACTIONS), .5)
reward_next = self.memory_reward[-1]
for i, (sample, action, policy, reward) in enumerate(memory):
x[i] = sample
y_policy[i] = policy
r = (delayed_reward + reward_next - reward * 2) * 100
y_policy[i, action] = sigmoid(r)
reward_next = reward
return x, None, y_policy
x是一组学习数据和Agent状态的示例数组。y_policy是学习策略神经网络的标签。x阵列的形状由布局数据大小和学习数据特征大小的二维组成。y_policy数组的形状由批处理数据大小和策略神经网络确定的代理行为的数量组成。y_policy以0.5的形式进行填充。
Python提示:Numpy的full()函数返回Numpy数组,该数组以第一个参数的形式显示,并以第二个参数的输入值填充。例如,full(3,1)返回[1,1,1,1],full(2,2),0.5)返回[0.5,0.5],[0.5,0.5]。
批处理数据的大小由延迟补偿决定,因此每次都不同,学习数据特征的大小和代理行为的数量固定为28和2。当然,如果改变了学习数据的特征,并增加了预测概率的行为,那么这个数字就会改变。
为x[i]指定特征向量,并将策略神经网络的输出放入y_policy[i]。这里和DQNLearner一样寻求奖励。为此值取sigmoid函数作为策略神经网络学习标签。
由于在策略倾斜强化学习中没有价值神经网络,PolicyGradient Learner的get_batch()函数将第二个返回值为None。
A2C(优势演员-评论家)强化学习与演员-评论家强化学习非常相似。但是,在训练策略神经网络时,我们使用 Advantage 而不是按原样使用价值神经网络的值。示例 5.58 显示了 A2CLearner 类。
A2C学习类
class A2CLearner(ActorCriticLearner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def get_batch(self, batch_size, delayed_reward, discount_factor):
memory = zip(
reversed(self.memory_sample[-batch_size:]),
reversed(self.memory_action[-batch_size:]),
reversed(self.memory_value[-batch_size:]),
reversed(self.memory_policy[-batch_size:]),
reversed(self.memory_reward[-batch_size:]),
)
x = np.zeros((batch_size, self.num_steps, self.num_features))
y_value = np.zeros((batch_size, self.agent.NUM_ACTIONS))
y_policy = np.full((batch_size, self.agent.NUM_ACTIONS), .5)
value_max_next = 0
reward_next = self.memory_reward[-1]
for i, (sample, action, value, policy, reward) \
in enumerate(memory):
x[i] = sample
r = (delayed_reward + reward_next - reward * 2) * 100
y_value[i, action] = r + discount_factor * value_max_next
advantage = value[action] - value.mean()
y_policy[i, action] = sigmoid(advantage)
value_max_next = value.max()
reward_next = reward
return x, y_value, y_policy
A2CLearner 类扩展了 ActorCriticLearner 类。因此,A2CLearner类的构造函数除了调用父类的构造函数外,没有任何作用。
A2CLearner 类中的一个函数get_batch()使用 Advantage 训练一个策略神经网络。优势是状态-动作值减去状态值。优势是在给定状态下一个动作比另一个动作更有价值多少。这里,对价值神经网络的预测状态-动作值进行平均,作为状态值。将获得的优势应用于 sigmoid 函数并用作策略神经网络的训练标签。
A3C(异步优势actor-critic)是一种并行执行A2C强化学习的强化学习方法。A3C 还使用价值神经网络和策略神经网络。下面展示了用于 A3C 强化学习的 A3CLearner 类的构造函数。
A3CLearner 类:构造函数
class A3CLearner(ReinforcementLearner):
def __init__(self, *args, list_stock_code=None,
list_chart_data=None, list_training_data=None,
list_min_trading_unit=None, list_max_trading_unit=None,
value_network_path=None, policy_network_path=None,
**kwargs):
assert len(list_training_data) > 0
super().__init__(*args, **kwargs)
self.num_features += list_training_data[0].shape[1]
#创建共享神经网络
self.shared_network = Network.get_shared_network(
net=self.net, num_steps=self.num_steps,
input_dim=self.num_features)
self.value_network_path = value_network_path
self.policy_network_path = policy_network_path
if self.value_network is None:
self.init_value_network(shared_network=self.shared_network)
if self.policy_network is None:
self.init_policy_network(shared_network=self.shared_network)
#创建A2CLearner
self.learners = []
for (stock_code, chart_data, training_data,
min_trading_unit, max_trading_unit) in zip(
list_stock_code, list_chart_data, list_training_data,
list_min_trading_unit, list_max_trading_unit
):
learner = A2CLearner(*args,
stock_code=stock_code, chart_data=chart_data,
training_data=training_data,
min_trading_unit=min_trading_unit,
max_trading_unit=max_trading_unit,
shared_network=self.shared_network,
value_network=self.value_network,
policy_network=self.policy_network, **kwargs)
self.learners.append(learner)
A3CLearner 类扩展了 ReinforcementLearner 类。构造函数的参数接受股票代码作为列表、图表数据、训练数据以及最小和最大投资单位进行训练,这与我们之前看到的 A2C 不同。创建与这些列表大小相等的 A2CLearner 类的对象。learners将创建的 A2CLearner 类对象保存在列表中。每个 A2CLearner 类对象共享一个价值神经网络和一个策略神经网络。
下面展示了A3CLearner类的强化学习性能函数。
A3CLearner 类:并行强化学习函数
def run(
self, num_epoches=100, balance=10000000,
discount_factor=0.9, start_epsilon=0.9, learning=True):
threads = []
for learner in self.learners:
threads.append(threading.Thread(
target=learner.fit, daemon=True, kwargs={
'num_epoches': num_epoches, 'balance': balance,
'discount_factor': discount_factor,
'start_epsilon': start_epsilon,
'learning': learning
}))
for thread in threads:
thread.start()
time.sleep(1)
for thread in threads: thread.join()
A3C 同时并行执行 A2C。共享价值神经网络和策略神经网络,同时训练它们。一个 A2CLearner 类对象探索单一的股票市场环境,并朝着增加盈亏比的方向训练价值神经网络和策略神经网络。
A3CLearnerrun()类的功能使用线程同时执行run()每个 A2CLearner 类对象的功能。等到所有A2C强化学习完成,最后完成A3C强化学习。
Python 提示:要在 Python 中使用线程,请使用threading模块的 Thread 类。Thread
类接收要执行的函数作为target参数。要传递给此目标函数的参数可以args用
和参数指定。将可变数量的参数作为元组传递。以字典的形式传递关键字参数。kwargsargskwargs Python
提示:daemon您可以指定是否成为守护线程作为 Thread 类的参数。守护线程是在主线程退出时终止的线程
博主创作不易,无论是找资料还是写代码都是需要花费时间和精力的,茫茫人海,如果你看到了我的博客,觉得写的还行的话,希望能赞同、收藏、喜欢支持一下,让我更有创作的动力!有什么建议或者问题,评论区见!