大数据文摘著作

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

作者用了一种别致的办法来练习神经络。更新权重的散布而不是次序更新静态权重,得到了更风趣和牢靠的成果。贝叶斯办法给了咱们一个时机,使得咱们能够不手动增加正则项的状况下对神经络进行正则化,了解模型的不确定性,并尽可能运用更少的数据得到更好的成果。

Hi!又碰头啦。上一年我推出了几篇根据神经络的金融猜测教程,我以为有些成果仍是蛮风趣的,值得运用在实践买卖中。

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

咱们运用不同的正则化办法和弥补数据来处理这个问题,可是这十分耗时间并且有点盲目查找了。

今日我想介绍一种略微不同的办法来用于相同的算法。从概率视点讲,咱们能够从数据自身学习正则化办法,在咱们猜测中估量精确性,运用更少的数据来练习并且在模型中参加概率依靠。

我不会深化到贝叶斯模型或变分推理的技能或许数学细节上,我将给出一些概述,一起也会愈加重视怎么运用。像平常相同,你能够鄙人面的链接内查看代码。

代码链接:

链接

为了更深化了解概率编程、贝叶斯模型及其运用,我引荐以下资源给咱们:

形式识别和机器学习:

链接

为黑客规划的贝叶斯办法:

链接

一起引荐以下pypon库:

PyMC3:

链接

Edward:

spdb(600080股吧)

链接

Pyro:

链接

概率编程

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

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

可是假如咱们以为这些参数和输出都是相互依靠的散布呢?

神经络中的每个权重都是来自某个散布的样本,输出也相同,每个输入来自整个络的样本,一起这个络依靠参数的样本。它给予了咱们什么?

咱们从最根底的开端讲。

假如咱们把络当作一组互相依靠的散布,首要界说联合概率散布为p(y,z|x),输出为y,还有一些依靠输入x的模型“内部”、躲藏参数z(和一般神经络相同)。

而咱们想要找到一种神经络散布,咱们能够对y~p(y|x)采样然后把散布作为输出(该散布的样本期望值一般便是输出,标准差用来评价不确定性,假如散布模型的尾部越大,咱们关于输出越没有决心)。

这个设置或多或少现已很清楚了,咱们只需求记住,现在一切的参数,不管是模型的输入仍是输出,都是散布。咱们需求的练习是找到这些散布的参数以便在实践使命中取得更高的精确率。

必需求说到的是,参数散布的形状是咱们自己设置的(例如,一切的初始权重都是w~Normal(0,1),然后咱们将学习正确的均值和方差)。

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

模型的拟合作用怎么样呢?一般的结构叫做变分推理。咱们不去深化了解细节,在这儿咱们需求寻觅的模型是能够最大化似然函数logp_w(z|x)的,w是模型的参数(散布参数),z是躲藏变量(躲藏神经元输出,从参数为w的散布中取样得到的),x是输入数据样本。这便是咱们的模型。

在Pyro库中咱们引入了一个实例作为这个模型的辅导,辅导中包含一些对一切躲藏变量q_ф(z)的散布,其间ф叫做变分参数。这个散布有必要近似于拟合数据最好的模型参数的“实在”散布。

练习的意图是最小化一个辅导中关于输入数据和样本[log(p_w(z|x))—log(q_ф(z))]的期望。咱们这儿不评论练习进程的细节,由于这儿面包含好几门大学课程,现在咱们就做黑盒优化好了。

哦对了,为什么是编程呢?由于咱们一般将这种概率模型(比方神经络)描绘为从一个变量到另一个变量的有向图,这样咱们就能够直接表明变量的依靠性:

开始这种概率编程言语被用来界说这些模型并对其进行揣度。

为什么用概率编程?

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

考虑到一切权重都是散布,你能够从中进行N次抽样然后得到输出的散布,经过标准差能够预算你的模型关于成果的精确性。

并且还有个不错的赠礼便是咱们只需求用更少的数据来练习模型,并且咱们能够在变量间灵敏的增加不同的依靠联系。

为什么不必概率编程呢?

我关于运用贝叶斯模型没有太多经历,但就我从Pyro和PyMC3学习中能够知道,练习进程耗时很长并且很难界说精确的先验散布。此外,处理散布的多个样本会导致误解和歧义。

数据展现

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

以太坊价格来历:

链接

咱们将运用7天的价格、买卖量和推特数量改动的百分比来猜测下一天改动的百分比。

价格、推特数量和买卖量改动

上图所示是数据的样本——蓝色表明价格改动,黄色表明推特数量改动,绿色表明买卖量改动。这些值(0.1-0.2)之间有一些正相关,所以咱们期望运用一些数据练习模型。

贝叶斯线性回归

首要我想了解简略线性回归在咱们使命中的体现。

Pyro官方教程:

链接

咱们在PyTorch中界说了咱们模型(具体解说请看官方教程):

classRegressionModel(nn.Module):def__init__(self,p):super(RegressionModel,self).__init__()self.linear=nn.Linear(p,1)defforward(self,x):#x*w+breturnself.linear(x)

这仅仅咱们从前用过的一个简略确定性模型,可是这也是在Pyro中界说概率的办法。

defmodel(data):#Createunitnormalpriorsoverpeparametersmu=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()wippyro.iarange("map",N,subsample=data):x_data=data[:,:-1]y_data=data[:,-1]#runperegressorforwardconditionedoninputsprediction_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)中采样。

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

defguide(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)returnlifted_module()

这儿咱们界说了咱们想要“练习”的散布的变分散布。就像你看到的,咱们为W和b界说了相同形状的散布,可是尽量使他们更挨近实践(只需咱们能想到的)。在这个比方里,我挑选让这个散布形状更窄一些。

(~Normal(0,0.1))

咱们以这种办法练习模型:

forjinrange(3000):epoch_loss=0.0perm=torch.randperm(N)#shuffledatadata=data[perm]#getindicesofeachbatchall_batches=get_batch_indices(N,64)forix,batch_startinenumerate(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=[]foriinrange(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个神经元以及线性激活模型。

defget_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_modelpile(optimizer='adam',loss='mse')returnfinal_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中练习的相同的神经络。

classNet(torch.nn.Module):def__init__(self,n_feature,n_hidden):super(Net,self).__init__()self.hidden=torch.nn.Linear(n_feature,n_hidden)#hiddenlayerself.predict=torch.nn.Linear(n_hidden,1)#outputlayerdefforward(self,x):x=self.hidden(x)x=self.predict(x)returnx

与贝叶斯回归模型比较,咱们现在有两组参数(从输入到躲藏层以及从躲藏层到输出),所以咱们略微改动一下模型散布和先验:

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}

不要忘掉为模型中一切的散布设置不同的姓名,由于不能有任何的歧义和重复!能够在源代码中查看更多细节。

源代码:

链接

在拟合模型和采样后,让咱们直接看终究成果:

30天的Pyro神经络猜测

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

考虑下从贝叶斯模型中学到的正则化或许权重的性质,与一般神经络做比较,我还会看一下权重计算。下面是我在Pryo模型中怎么查看参数的:

fornameinpyro.get_param_store().get_all_param_names():printname,pyro.param(name).data.numpy()

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

importtensorflowastfsess=tf.Session()wipsess.as_default():tf.global_variables_initializer().run()dense_weights,out_weights=None,Nonewipsess.as_default():forlayerinmodel.layers:iflen(layer.weights)>0:weights=layer.get_weights()if'dense'inlayer.name:dense_weights=layer.weights[0].eval()if'out'inlayer.name:out_weights=layer.weights[0].eval()

举个比方,关于Keras模型中,终究一层的权重平均值和标准差分别是-0.0025901748,0.30395034,关于Pyro模型分别是0.0005974418和0.0005974418,数值更小,模型功能更好!

就像许多L2或许dropout这种正则化办法做的那样,让参数尽可能挨近0,然后咱们能够用变分推理来完成!关于躲藏层权重的状况就更风趣了。

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

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

风趣的是,事实上不只权重的均值和标准差很小,并且权重变得愈加稀少,所以基本上咱们关于第一组权重用到了稀少表明(相似L1正则),对第二组用到了相似L2正则表明,几乎难以想象!不要忘掉试一下代码哦!

定论

咱们用了一种别致的办法来练习神经络。咱们更新权重的散布而不是次序更新静态权重。所以咱们得到更风趣和牢靠的成果。

我想要着重的是,贝叶斯办法给了咱们一个时机,使得咱们能够不手动增加正则项的状况下对神经络进行正则化,了解模型的不确定性,并尽可能运用更少的数据得到更好的成果。欢迎持续重视!:)

原文链接:

链接