用于投资组合优化的 REINFORCE 算法 - 训练时的问题

人工智能 强化学习 训练 收敛 加强
2021-10-23 14:49:55

我正在尝试实施强化算法(蒙特卡洛政策梯度),以便每天优化 94 只股票的投资组合(我有合适的历史数据来实现这一点)。这个想法如下:每天,神经网络的输入包括以下内容:

  • 94 只股票中每只股票过去 20 天的历史每日回报(每日动量)
  • 当前的投资组合权重向量(94 个权重)

因此状态由 1974 维向量表示。神经网络应该返回一个 94 维的动作向量,该向量也是要投资的(理想)投资组合权重的向量。允许使用负权重(空头头寸),并且投资组合权重的总和应为 1。由于动作空间是连续的,我试图通过 Reinforce 算法来解决它。奖励由投资组合每日回报减去交易成本给出。这是一个代码片段:

class Policy(nn.Module):
    def __init__(self, s_size=1974, h_size=400, a_size=94):
        super().__init__()
        self.fc1 = nn.Linear(s_size, h_size)
        self.fc2 = nn.Linear(h_size, a_size)
        self.state_size = 1974
        self.action_size = 94
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x
    def act(self, state):
        state = torch.from_numpy(state).float().unsqueeze(0).to(device)
        means = self.forward(state).cpu()
        m = MultivariateNormal(means,torch.diag(torch.Tensor(np.repeat(1e-8,94))))
        action = m.sample()
        action[0] = action[0]/sum(action[0])
        return action[0], m.log_prob(action)

请注意,为了确保投资组合权重(动作张量的条目)总和为 1,我将除以它们的总和。另请注意,我正在从对角线项极小的多元正态分布中进行采样,因为我希望网络的行为尽可能具有确定性。(我可能应该使用类似于 DDPG 的东西,但我想尝试更简单的解决方案开始)。

训练部分如下所示:

optimizer = optim.Adam(policy.parameters(), lr=1e-3)

def reinforce(n_episodes=10000, max_t=10000, gamma=1.0, print_every=1):
    scores_deque = deque(maxlen=100)
    scores = []
    for i_episode in range(1, n_episodes+1):
        saved_log_probs = []
        rewards = []
        state = env.reset()
        for t in range(max_t):
            action, log_prob = policy.act(state)
            saved_log_probs.append(log_prob)
            state, reward, done, _ = env.step(action.detach().flatten().numpy())
            rewards.append(reward)
            if done:
                break 
        scores_deque.append(sum(rewards))
        scores.append(sum(rewards))

        discounts = [gamma**i for i in range(len(rewards)+1)]
        R = sum([a*b for a,b in zip(discounts, rewards)])

        policy_loss = []
        for log_prob in saved_log_probs:
            policy_loss.append(-log_prob * R)
        policy_loss = torch.cat(policy_loss).sum()

        optimizer.zero_grad()
        policy_loss.backward()
        optimizer.step()

        if i_episode % print_every == 10:
            print('Episode {}\tAverage Score: {:.2f}'.format(i_episode, np.mean(scores_deque)))
            print(scores[-1])

    return scores, scores_deque

scores, scores_deque = reinforce()

不幸的是,即使在调整学习率之后,训练期间也没有收敛,所以我的问题如下:我的方法有什么明显的错误吗?如果有,我应该如何解决这个问题?

1个回答

您可以尝试简化输出逻辑的一件事是使用 softmax 输出,然后使用您的输出将 var 设置为 = (max_output - min_output)/2 然后将该数字视为您的长/短“阈值”,这样可以确保您的输出总和为 1,同时仍允许网络学习输出短信号。我还会检查以确保您有 1.0 个偏置神经元,因为我有时(尤其是第一个时期)想象您会为投资组合权重传递零。