网易首页 > 网易号 > 正文 申请入驻

手把手:基于概率编程Pyro的金融预测,让正则化结果更有趣!

0
分享至

大数据文摘作品

编译:修竹、笪洁琼、夏雅薇

作者用了一种新奇的方法来训练神经网络。更新权重的分布而不是顺序更新静态权重,得到了更有趣和可靠的结果。贝叶斯方法给了我们一个机会,使得我们可以不手动添加正则项的情况下对神经网络进行正则化,理解模型的不确定性,并尽可能使用更少的数据得到更好的结果。

Hi!又见面啦。去年我推出了几篇基于神经网络的金融预测教程,我认为有些结果还是蛮有趣的,值得应用在实际交易中。

如果你读过那些教程,你一定会注意到,当你试图在“随机”数据上用一些机器学习模型并且希望找到隐藏模式时,你其实正逐渐对训练集进行过拟合。

我们使用不同的正则化方法和补充数据来解决这个问题,但是这非常耗时间并且有点盲目搜索了。

今天我想介绍一种稍微不同的方法来用于相同的算法。从概率角度讲,我们可以从数据本身学习正则化方法,在我们预测中估计准确性,使用更少的数据来训练并且在模型中加入概率依赖。

我不会深入到贝叶斯模型或变分推理的技术或者数学细节上,我将给出一些概述,同时也会更加关注如何应用。像往常一样,你可以在下面的链接内查看代码。

代码链接:

https://github.com/Rachnog/Deep-Trading/tree/master/bayesian

为了更深入了解概率编程、贝叶斯模型及其应用,我推荐以下资源给大家:

  • 模式识别和机器学习:

    http://www.springer.com/us/book/9780387310732

  • 为黑客设计的贝叶斯方法:

    https://www.amazon.com/Bayesian-Methods-Hackers-Probabilistic-Addison-Wesley/dp/0133902838

同时推荐以下python库:

  • PyMC3:

    https://github.com/pymc-devs/pymc3

  • Edward:

    http://edwardlib.org/

  • Pyro:

    http://pyro.ai/

概率编程

这个概率性的东西是什么,而且我们为什么要称之为编程呢?首先,我们先回忆一下“正常”的神经网络以及我们能从中获得什么。

我们有参数(权重),这些参数以矩阵表示,输出通常是一些标量值或者向量(例如用于分类时)。比如说,在用SGD训练模型之后,我们有了这些固定矩阵和网络在相同的输入样本上输出相同的向量。完全正确!

但是如果我们认为这些参数和输出都是互相依赖的分布呢?

神经网络中的每个权重都是来自某个分布的样本,输出也一样,每个输入来自整个网络的样本,同时这个网络依赖参数的样本。它给予了我们什么?

我们从最基础的开始讲。

如果我们把网络看成一组彼此依赖的分布,首先定义联合概率分布为p(y, z|x),输出为y,还有一些依赖输入x 的模型“内部”、隐藏参数z(和普通神经网络一样)。

而我们想要找到一种神经网络分布,我们可以对y ~ p(y|x)采样然后把分布作为输出(该分布的样本期望值通常就是输出,标准差用来评估不确定性,如果分布模型的尾部越大,我们对于输出越没有信心)。

这个设置或多或少已经很清楚了,我们只需要记住,现在所有的参数,不管是模型的输入还是输出,都是分布。我们需要的训练是找到这些分布的参数以便在实际任务中获得更高的准确率。

必须要提到的是,参数分布的形状是我们自己设置的(例如,所有的初始权重都是w ~ Normal(0, 1),然后我们将学习正确的均值和方差)。

初始分布称之为先验分布,使用过训练数据拟合参数的分布叫做后验分布。后者用于取样和获得输出数据。

模型的拟合效果怎么样呢?一般的框架叫做变分推理。我们不去深入了解细节,在这里我们需要寻找的模型是可以最大化似然函数log p_w(z|x)的, w 是模型的参数(分布参数),z是隐藏变量(隐藏神经元输出,从参数为 w 的分布中取样得到的),x是输入数据样本。这就是我们的模型。

在Pyro库中我们引入了一个实例作为这个模型的指导,指导中包括一些对所有隐藏变量q_ф(z)的分布,其中 ф叫做变分参数。这个分布必须近似于拟合数据最好的模型参数的“真实”分布。

训练的目的是最小化一个指导中关于输入数据和样本[log(p_w(z|x))—log(q_ф(z))] 的期望。我们这里不讨论训练过程的细节,因为这里面包含好几门大学课程,现在我们就做黑盒优化好了。

哦对了,为什么是编程呢?因为我们通常将这种概率模型(比如神经网络)描述为从一个变量到另一个变量的有向图,这样我们就可以直接表示变量的依赖性:

最初这种概率编程语言被用来定义这些模型并对其进行推断。

为什么用概率编程?

你可以将它认为是一种附加的隐藏变量,从数据中学习模型,而不是采用在模型中注入dropout或L1正则化的方法。

考虑到所有权重都是分布,你可以从中进行N次抽样然后得到输出的分布,通过标准差可以估算你的模型对于结果的准确性。

而且还有个不错的赠礼就是我们只需要用更少的数据来训练模型,并且我们可以在变量间灵活的增加不同的依赖关系。

为什么不用概率编程呢?

我对于使用贝叶斯模型没有太多经验,但就我从Pyro和PyMC3学习中可以知道,训练过程耗时很长而且很难定义准确的先验分布。此外,处理分布的多个样本会导致误解和歧义。

数据展示

我获取了以太坊每日价格。这里面包括典型OHLCV(高开低走)元组以及每天关于以太坊推特的数量。

以太坊价格来源:

https://bitinfocharts.com/

我们将使用7天的价格、交易量和推特数量变化的百分比来预测下一天变化的百分比。

价格、推特数量和交易量变化

上图所示是数据的样本——蓝色表示价格变化,黄色表示推特数量变化,绿色表示交易量变化。这些值(0.1-0.2)之间有一些正相关,所以我们希望利用一些数据训练模型。

贝叶斯线性回归

首先我想了解简单线性回归在我们任务中的表现。

Pyro官方教程:

http://pyro.ai/examples/bayesian_regression.html

我们在PyTorch中定义了我们模型(详细解释请看官方教程):

class RegressionModel(nn.Module):
def __init__(self, p):
super(RegressionModel, self).__init__()
self.linear = nn.Linear(p, 1)
def forward(self, x):
# x * w + b
return self.linear(x)

这只是我们曾经用过的一个简单确定性模型,但是这也是在Pyro中定义概率的方法。

def model(data):
# Create unit normal priors over the parameters
mu = Variable(torch.zeros(1, p)).type_as(data)
sigma = Variable(torch.ones(1, p)).type_as(data)
bias_mu = Variable(torch.zeros(1)).type_as(data)
bias_sigma = Variable(torch.ones(1)).type_as(data)
w_prior, b_prior = Normal(mu, sigma), Normal(bias_mu, bias_sigma)
priors = {'linear.weight': w_prior, 'linear.bias': b_prior}
lifted_module = pyro.random_module("module", regression_model, priors)
lifted_reg_model = lifted_module()
with pyro.iarange("map", N, subsample=data):
x_data = data[:, :-1]
y_data = data[:, -1]
# run the regressor forward conditioned on inputs
prediction_mean = lifted_reg_model(x_data).squeeze()
pyro.sample("obs",
Normal(prediction_mean, Variable(torch.ones(data.size(0))).type_as(data)),
obs=y_data.squeeze())

上述代码中我们为参数W和b设置了一般线性回归模型分布,均为 ~Normal(0, 1)。我们称之为先验,创建了Pyro的随机函数(在我们例子中,是PyTorch的回归模型),将先验概率加到({‘linear.weight’: w_prior, ‘linear.bias’: b_prior})并且基于输入数据x从模型p(y|x)中采样。

这个模型的指导如下所示:

def guide(data):
w_mu = Variable(torch.randn(1, p).type_as(data.data), requires_grad=True)
w_log_sig = Variable(0.1 * torch.ones(1, p).type_as(data.data), requires_grad=True)
b_mu = Variable(torch.randn(1).type_as(data.data), requires_grad=True)
b_log_sig = Variable(0.1 * torch.ones(1).type_as(data.data), requires_grad=True)
mw_param = pyro.param("guide_mean_weight", w_mu)
sw_param = softplus(pyro.param("guide_log_sigma_weight", w_log_sig))
mb_param = pyro.param("guide_mean_bias", b_mu)
sb_param = softplus(pyro.param("guide_log_sigma_bias", b_log_sig))
w_dist = Normal(mw_param, sw_param)
b_dist = Normal(mb_param, sb_param)
dists = {'linear.weight': w_dist, 'linear.bias': b_dist}
lifted_module = pyro.random_module("module", regression_model, dists)
return lifted_module()

这里我们定义了我们想要“训练”的分布的变分分布。就像你看到的,我们为W和b定义了相同形状的分布,但是尽量使他们更接近实际(只要我们能想到的)。在这个例子里,我选择让这个分布形状更窄一些。

(~Normal(0, 0.1))

我们以这种方式训练模型:

for j in range(3000):
epoch_loss = 0.0
perm = torch.randperm(N)
# shuffle data
data = data[perm]
# get indices of each batch
all_batches = get_batch_indices(N, 64)
for ix, batch_start in enumerate(all_batches[:-1]):
batch_end = all_batches[ix + 1]
batch_data = data[batch_start: batch_end]
epoch_loss += svi.step(batch_data)

之后我们想从模型中取样y。重复取样100次然后计算每一次取样预测的均值和标准差(标准差越大,我们对预测准确的信心越低)。

preds = []
for i in range(100):
sampled_reg_model = guide(X_test)
pred = sampled_reg_model(X_test).data.numpy().flatten()
preds.append(pred)

我们应该记得,金融预测中MSE,MAE或者MAPE等经典指标可能会让人很困惑——相对较小的错误率并不意味着你的模型运行良好,所以在样本外的数据上查看性能是非常重要的,这也是我们要做的:

30天的贝叶斯模型预测

如上图所示,结果并不是很好,但是最后一条的预测形状很好,这给了我们一点信心。让我们继续吧!

普通神经网络

在这个非常简单的模型之后,我们想试着尝试些更有趣的东西,比如神经网络。首先让我们先了解一个简单的MLP,只有一个隐藏层,包括含有25个神经元以及线性激活模型。

def get_model(input_size):
main_input = Input(shape=(input_size, ), name='main_input')
x = Dense(25, activation='linear')(main_input)
output = Dense(1, activation = "linear", name = "out")(x)
final_model = Model(inputs=[main_input], outputs=[output])
final_model.compile(optimizer='adam', loss='mse')
return final_model

然后训练100次。

model = get_model(len(X_train[0]))
history = model.fit(X_train, Y_train,
epochs = 100,
batch_size = 64,
verbose=1,
validation_data=(X_test, Y_test),
callbacks=[reduce_lr, checkpointer],
shuffle=True)

得到以下结果:

30天的Keras神经网络预测

这个结果甚至比简单贝叶斯回归还糟糕,而且这个模型不能得到确定性估计,更重要的是,这个模型甚至不能正则化。

贝叶斯神经网络

现在我想在PyTorch中定义一个和我们在Keras中训练的相同的神经网络。

class Net(torch.nn.Module):
def __init__(self, n_feature, n_hidden):
super(Net, self).__init__()
self.hidden = torch.nn.Linear(n_feature, n_hidden) # hidden layer
self.predict = torch.nn.Linear(n_hidden, 1) # output layer
def forward(self, x):
x = self.hidden(x)
x = self.predict(x)
return x

与贝叶斯回归模型相比,我们现在有两组参数(从输入到隐藏层以及从隐藏层到输出),所以我们稍微改变一下模型分布和先验:

priors = {'hidden.weight': w_prior,
'hidden.bias': b_prior,
'predict.weight': w_prior2,
'predict.bias': b_prior2}

以及这个指导:

dists = {'hidden.weight': w_dist,
'hidden.bias': b_dist,
'predict.weight': w_dist2,
'predict.bias': b_dist2}

不要忘记为模型中所有的分布设置不同的名字,因为不能有任何的歧义和重复!可以在源代码中查看更多细节。

源代码:

https://github.com/Rachnog/Deep-Trading/tree/master/bayesian

在拟合模型和采样后,让我们直接看最终结果:

30天的Pyro神经网络预测

这个结果看上去比之前的结果都要好!

考虑下从贝叶斯模型中学到的正则化或者权重的性质,与普通神经网络做比较,我还会看一下权重统计。下面是我在Pryo模型中如何检查参数的:

for name in pyro.get_param_store().get_all_param_names():
print name, pyro.param(name).data.numpy()

在Keras模型中我是这么做的:

import tensorflow as tf
sess = tf.Session()
with sess.as_default():
tf.global_variables_initializer().run()
dense_weights, out_weights = None, None
with sess.as_default():
for layer in model.layers:
if len(layer.weights) > 0:
weights = layer.get_weights()
if 'dense' in layer.name:
dense_weights = layer.weights[0].eval()
if 'out' in layer.name:
out_weights = layer.weights[0].eval()

举个例子,对于Keras模型中,最后一层的权重平均值和标准差分别是-0.0025901748,0.30395034,对于Pyro模型分别是0.0005974418和0.0005974418,数值更小,模型性能更好!

就像许多L2或者dropout这种正则化方法做的那样,让参数尽可能接近0,然后我们可以用变分推理来实现!对于隐藏层权重的情况就更有趣了。

我们把一些权重向量画出来,蓝色代表Keras的权重,橙色代表Pyro的权重:

输入和隐藏层间的一些权重

有趣的是,事实上不仅权重的均值和标准差很小,而且权重变得更加稀疏,所以基本上我们对于第一组权重用到了稀疏表示(类似L1正则),对第二组用到了类似L2正则表示,简直不可思议!不要忘记试一下代码哦!

结论

我们用了一种新奇的方法来训练神经网络。我们更新权重的分布而不是顺序更新静态权重。所以我们得到更有趣和可靠的结果。

我想要强调的是,贝叶斯方法给了我们一个机会,使得我们可以不手动添加正则项的情况下对神经网络进行正则化,理解模型的不确定性,并尽可能使用更少的数据得到更好的结果。欢迎继续关注!:)

原文链接:

https://medium.com/@alexrachnog/financial-forecasting-with-probabilistic-programming-and-pyro-db68ab1a1dba

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
哇塞!欧文+杜兰特!火箭4换1交易方案曝光

哇塞!欧文+杜兰特!火箭4换1交易方案曝光

篮球实战宝典
2026-05-22 21:48:32
40岁童星街头被拍:眉毛镶满水钻,手里夹着烟

40岁童星街头被拍:眉毛镶满水钻,手里夹着烟

赴一场山海啊
2026-05-22 01:48:16
存款大局已定?不出意外,6月以后,银行存款利率或迎来4大变化

存款大局已定?不出意外,6月以后,银行存款利率或迎来4大变化

巢客HOME
2026-05-23 07:45:03
广东39岁男子每天不吃主食只喝两三瓶可乐,从160斤减到130斤,右眼视力仅剩0.03差点失明

广东39岁男子每天不吃主食只喝两三瓶可乐,从160斤减到130斤,右眼视力仅剩0.03差点失明

鲁中晨报
2026-05-23 07:18:03
100亿化为泡影,35名顶尖电子战专家牺牲!中国空中预警机血泪史

100亿化为泡影,35名顶尖电子战专家牺牲!中国空中预警机血泪史

基斯默默
2026-05-23 07:45:23
哪个瞬间你突然觉得读书很有用?网友的一树梨花压海棠让人破防了

哪个瞬间你突然觉得读书很有用?网友的一树梨花压海棠让人破防了

夜深爱杂谈
2026-05-22 20:48:07
白天作陪晚上同宿?明码标价8000一回!高端伴游沦为色情交易窝点

白天作陪晚上同宿?明码标价8000一回!高端伴游沦为色情交易窝点

网络易不易
2026-01-20 10:17:46
太突然!俄方传出消息,普京和特朗普或将会面,地点选在中国深圳

太突然!俄方传出消息,普京和特朗普或将会面,地点选在中国深圳

无情有思ss
2026-05-22 12:22:55
要打奉陪到底,中方启用仲裁,不准收回港口租约,澳防长咬死二字

要打奉陪到底,中方启用仲裁,不准收回港口租约,澳防长咬死二字

观史搜寻着
2026-05-23 02:58:15
福克斯回归双枪哑火,文班空砍26+4+3,马刺命门被打爆遭雷霆逆转

福克斯回归双枪哑火,文班空砍26+4+3,马刺命门被打爆遭雷霆逆转

钉钉陌上花开
2026-05-23 11:24:28
暴雨过后广东人的谨慎,地铁清一色的拖鞋,网友_也只有广东见着

暴雨过后广东人的谨慎,地铁清一色的拖鞋,网友_也只有广东见着

画夕
2026-05-23 10:44:08
山西沁源煤矿事故已致8人死亡 井下38人正在全力搜救

山西沁源煤矿事故已致8人死亡 井下38人正在全力搜救

新京报
2026-05-23 07:13:31
能不能发生关系,第一次见面就差不多定了。

能不能发生关系,第一次见面就差不多定了。

聪明小石头
2026-04-20 18:12:52
最新!全国人口140545万人,其中男性人口为71722万人,女性人口为68823万人,大学文化程度人口为27233万人

最新!全国人口140545万人,其中男性人口为71722万人,女性人口为68823万人,大学文化程度人口为27233万人

每日经济新闻
2026-05-22 20:30:19
暴跌90%!重庆首富改了六年财报,坑惨11万股民

暴跌90%!重庆首富改了六年财报,坑惨11万股民

新浪财经
2026-05-22 17:56:03
国家发改委:对外开放是中国基本国策,从未要求中国科技企业不得接受外商投资

国家发改委:对外开放是中国基本国策,从未要求中国科技企业不得接受外商投资

澎湃新闻
2026-05-22 10:38:30
板桥水库溃坝:24万人一夜消逝,尘封28年,真相远比天灾残酷

板桥水库溃坝:24万人一夜消逝,尘封28年,真相远比天灾残酷

小玡说故事
2026-05-15 20:07:35
刚刚,马斯克SpaceX发射人类史上最大最强火箭!NASA局长点赞星舰V3

刚刚,马斯克SpaceX发射人类史上最大最强火箭!NASA局长点赞星舰V3

智东西
2026-05-23 09:51:05
心理学发现:99%喜欢抬杠、凡事都要争对错的人,不是本性偏执,也不是爱较真,而是没正视过自己的这两个价值感缺失

心理学发现:99%喜欢抬杠、凡事都要争对错的人,不是本性偏执,也不是爱较真,而是没正视过自己的这两个价值感缺失

心理观察局
2026-05-13 09:40:07
国务院这一纸令,把退休人员身上拴了几十年的绳子,一刀剪开了

国务院这一纸令,把退休人员身上拴了几十年的绳子,一刀剪开了

宝哥精彩赛事
2026-05-23 09:32:16
2026-05-23 12:48:49
大数据文摘 incentive-icons
大数据文摘
专注大数据,每日有分享!
6865文章数 94545关注度
往期回顾 全部

科技要闻

爆炸声中又迈一步!拆解马斯克“十二飞”

头条要闻

牛弹琴:印度的麻烦来了 "老对手"中国处境要好得多

头条要闻

牛弹琴:印度的麻烦来了 "老对手"中国处境要好得多

体育要闻

嘲讽许利民的发言,可许指导说错了吗?

娱乐要闻

歌手2026首播:胡彦斌破音 张碧晨跑调

财经要闻

股价暴跌!富途老虎是什么来头?

汽车要闻

11万级直接上四驱 银河星耀7限时权益价9.88万起

态度原创

家居
旅游
艺术
公开课
军事航空

家居要闻

低调传承 温润沉静

旅游要闻

集中爆发!宁波多地惊现罕见景观!有人半夜11点刷到立马起床出发,连夜奔赴

艺术要闻

15幅 2026年国家艺术基金优秀油画作品选

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

特朗普再酝酿对伊打击 美伊谈判连放信号

无障碍浏览 进入关怀版