![深度神经网络 (第七部分)。 神经网络的融合: 堆叠](https://c.mql5.com/i/articles/overlay.png)
深度神经网络 (第七部分)。 神经网络的融合: 堆叠
内容
概述
经全套训练的融合基础等级的模型 (个体分类器)。 然后,基于测试集,在预测期间获得的融合输出上训练元模型。 在这种情况下,融合的基本分类器的输出成为新训练的分类器的输入数据,该分类器本身是合并器。 这种方法称为 "复杂合并" 或 "通过学习泛化",更常见的是 "堆叠"。
该合并器的主要问题之一是为元分类器构建训练集合。
我们来试验堆叠集合的构建和测试。 它们将使用 ELM 神经网络分类器的融合,并使用 早前 获得的最优超参数。 在第一个实验中将使用修剪后的融合输出,而在第二个实验中将使用融合的所有输入。 作为合并器,两种变体都将能完全连接神经网络,但具有不同的结构。 在未来的实验中,我们将考察多模态和多任务处理如何影响神经网络分类的品质。
基础比较模型将用于评估这些变体的预测品质。
图例1. 计算结构规划
如您所见,图中实验由三部分组成。
- 准备融合的输入数据,训练 ELM 融合并依据训练/测试/测试1 集合获取预测。 这些集合将作为可训练合并器的 InputAll 输入。
- 修剪融合: 按信息重要性选择最佳 ELM 预测。 测试基础比较模块以获取参考度量。 在这些数据上训练和测试 DNN,计算模型的度量并将其与基本模型的度量进行比较。
- 创建一个多模式和多任务神经网络,训练它们并在 InputAll 集合上测试它们。 计算所获模型的度量,并将它们与基本模型的度量进行比较。
1. 准备可训练合并器的输入数据
为了实验,将使用 R 版本 3.4.4。 它包含若干我们尚未使用的新软件包。
运行 RStudio。 从 GitHub/Part_I 下载包含终端报价的 Cotir.RData 文件,并从 GitHub/Part_VII 中下载数据准备函数 Importar.R, Libary.R, FunPrepareData_VII.R, FUN_Stacking.R 文件。 请注意: 文件下载顺序很重要! 我略微修改了函数以便加快计算速度并提高脚本的可读性。 此外,增加了实验所需的许多预测因子。
我们将使用相同的报价,并将它们拆分为与本系列前几篇文章相同的样本。 我们来编写一个用于准备初始数据的脚本。 计算细节将不再赘述 — 它们已在早前描述过。 所做的修改与使用 dplyr 软件包有关,并将软件包和函数导入工作环境。 dplyr 是一个非常有用的软件包,便于数据操作。 它有时会在调试过程中出现意外情况,需要花费数小时搜索错误。
我来澄清一下。 当加载 dplyr 函数库时,控制台中会出现以下警告:
> library(dplyr) Attaching package: ‘dplyr’ The following objects are masked from ‘package:stats’: filter, lag The following objects are masked from ‘package:base’: intersect, setdiff, setequal, union
很明显是函数名冲突。 要解决此问题,必须明确指定调用特定函数的软件包。 例如, dplyr::filter(), dplyr::lag。 第二个问题: 通常,只需要软件包中的一、两个函数,但是必须加载整个函数库。 某些软件包 (例如,caret) 很庞大,其后续依赖软件包其实我们并不需要。 从这个意义上说,在 Python 中导入函数和软件包的风格更合乎逻辑。 例如:
从 theano 导入函数,配置,共享,张量 import numpy as np import time
在第一行中,导入了 theano 软件包中的许多函数; 在第二行中,导入 numpy 软件包并起了个昵称 np; 而第三个是 — time 软件包。 R 中的相同功能在 importar 软件包中实现,该包只有两个函数 — import() 和 import_fun()。 第一个允许您导入软件包,第二个允许导入函数。 但是,第一个必须重命名为 import_pack(),因此它不会与 reticulate::import() 冲突。
此外,还引入了新的变量,这些变量对于实验是必要的。 生成两个数据集 合 — data1 和 data2。 按信息重要性排列它们的预测因子。
下面是用于准备实验初始数据的脚本。 它可在 Prepare.R 文件中找到。
#--0--Library------------- # source(file = "importar.R") # source(file = "Library.R") # source(file = "FunPrepareData_VII.R") # source(file = "FUN_Stacking.R") #--1-prepare---- evalq({ # combine quotes OHLCV, Med, Typ, W into data frame # calculate the predictors and the target dt <- PrepareData(Data, Open, High, Low, Close, Volume) # split the initial data into pretrain/train/val/test DT <- SplitData(dt$feature, 4000, 1000, 500, 250, start = 1) # define the parameters of outliers pre.outl <- PreOutlier(DT$pretrain) # impute the outliers in all sets DTcap <- CappingData(DT, impute = T, fill = T, dither = F, pre.outl = pre.outl) # set the method for normalizing the predictors meth <- "spatialSign" #"expoTrans" "range" "spatialSign", # define the normalization parameters preproc <- PreNorm(DTcap$pretrain, meth = meth, rang = c(-0.95, 0.95)) # normalize the predictors in all sets DTcap.n <- NormData(DTcap, preproc = preproc) }, env)
再模块 0 (函数库), 下载必要的函数库和函数。 应按指定的顺序下载四个脚本文件。 在模块 1 (准备) 中,创建预测变量并对它们进行标准化,删除异常值。 标准化方法可以改变。
现在形成两个数据集合 — data1 和 data2。 在第一个集合中,数字滤波器及其一阶差分将用作预测因子,且之字折线 (ZigZag) 一阶差分的变化符号用作目标。 在第二个集合中,预测变量将是最高价/最低价/收盘价的一阶差分,以及 CO/HO/LO/HL 报价的差值,而之字折线的一阶差分将作为目标。 该脚本如下所示,可在 Prepare.R 文件中找到。
#--2-Data X------------- evalq({ foreach(i = 1:length(DTcap)) %do% { DTcap.n[[i]] ->.; dp$select(., Data, ftlm, stlm, rbci, pcci, fars, v.fatl, v.satl, v.rftl, v.rstl,v.ftlm, v.stlm, v.rbci, v.pcci, Class)} -> data1 X1 <- vector(mode = "list", 4) foreach(i = 1:length(X1)) %do% { data1[[i]] %>% dp$select(-c(Data, Class)) %>% as.data.frame() -> x data1[[i]]$Class %>% as.numeric() %>% subtract(1) -> y list(x = x, y = y)} -> X1 list(pretrain = X1[[1]] , train = X1[[2]] , test = X1[[3]] , test1 = X1[[4]] ) -> X1 }, env) #----------------- evalq({ foreach(i = 1:length(DTcap.n)) %do% { DTcap.n[[i]] ->.; dp$select(., Data, CO, HO, LO, HL, dC, dH, dL)} -> data2 X2 <- vector(mode = "list", 4) foreach(i = 1:length(X2)) %do% { data2[[i]] %>% dp$select(-Data) %>% as.data.frame() -> x DT[[i]]$dz -> y list(x = x, y = y)} -> X2 list(pretrain = X2[[1]] , train = X2[[2]] , test = X2[[3]] , test1 = X2[[4]] ) -> X2 }, env)
按照信息重要性的降序排列两个集合中的预测变量。 我们来看看它们是如何排位的。 该脚本如下所示,并可在 Prepare.R 文件中找到。
#---3--bestF----------------------------------- #require(clusterSim) evalq({ orderF(x = X1$pretrain$x %>% as.matrix(), type = "metric", s = 1, 4, distance = NULL, # "d1" - Manhattan, "d2" - Euclidean, #"d3" - Chebychev (max), "d4" - squared Euclidean, #"d5" - GDM1, "d6" - Canberra, "d7" - Bray-Curtis method = "kmeans" ,#"kmeans" (default) , "single", #"ward.D", "ward.D2", "complete", "average", "mcquitty", #"median", "centroid", "pam" Index = "cRAND") %$% stopri[ ,1] -> orderX1 }, env) colnames(env$X1$pretrain$x)[env$orderX1] [1] "v.fatl" "v.rbci" "v.ftlm" "fars" "v.satl" "stlm" [7] "rbci" "ftlm" "v.stlm" "v.rftl" "pcci" "v.rstl" [13] "v.pcci evalq({ orderF(x = X2$pretrain$x %>% as.matrix(), type = "metric", s = 1, 4, distance = NULL, # "d1" - Manhattan, "d2" - Euclidean, #"d3" - Chebychev (max), "d4" - squared Euclidean, #"d5" - GDM1, "d6" - Canberra, "d7" - Bray-Curtis method = "kmeans" ,#"kmeans" (default) , "single", #"ward.D", "ward.D2", "complete", "average", "mcquitty", #"median", "centroid", "pam" Index = "cRAND") %$% stopri[ ,1] -> orderX2 }, env) colnames(env$X2$pretrain$x)[env$orderX2] [1] "dC" "CO" "HO" "LO" "dH" "dL" "HL"
报价预测因子的顺序特别令人感兴趣。
要为合并器准备输入数据,必须:
- 创建一个 ELM 集合,并在 X1$pretrain 训练集合上训练它;
- 使用训练的融合预测 X1$train。 这将是 InputTrain 训练集合。
- 使用训练的融合完成 X1$test 集合的预测。 这将是 InputTest 测试集合;
- 使用训练的融合完成 X1$test1 集合的预测。 这将是 InputTest1 测试集合;
定义变量和常量,编写函数 createEns() 和 GetInputData() — 它将返回融合的所有输出值。 在融合优化之后,createEns() 函数参数的值既已获得。 您可能会有其它数值。 下面提供的脚本可以在 FUN_Stacking() 文件中找到。
#----Library------------- import_fun(rminer, holdout, holdout) #source(file = "FunPrepareData_VII.R") #----Input------------- evalq({ #type of activation function. Fact <- c("sig", #: sigmoid "sin", #: sine "radbas", #: radial basis "hardlim", #: hard-limit "hardlims", #: symmetric hard-limit "satlins", #: satlins "tansig", #: tan-sigmoid "tribas", #: triangular basis "poslin", #: positive linear "purelin") #: linear n <- 500 #---createENS---------------------- createEns <- function(numFeature = 8L, r = 7L, nh = 5L, fact = 7L, order, X){ # determine the indices of the best predictors bestF <<- order %>% head(numFeature) # choose the best predictors for the training set Xtrain <- X$pretrain$x[ , bestF] #setMKLthreads(1) k <- 1 rng <- RNGseq(n, 12345) #---creste Ensemble--- Ens <<- foreach(i = 1:n, .packages = "elmNN") %do% { rngtools::setRNG(rng[[k]]) idx <- rminer::holdout(Ytrain, ratio = r/10, mode = "random")$tr k <- k + 1 elmtrain(x = Xtrain[idx, ], y = Ytrain[idx], nhid = nh, actfun = Fact[fact]) } return(Ens) } #---GetInputData -FUN----------- GetInputData <- function(Ens, X){ #---predict-InputTrain-- Xtest <- X$train$x[ , bestF] foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(Ens[[i]], newdata = Xtest) } -> predEns #[ ,n] #---predict--InputTest---- Xtest1 <- X$test$x[ , bestF] foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(Ens[[i]], newdata = Xtest1) } -> InputTest #[ ,n] #---predict--InputTest1---- Xtest2 <- X$test1$x[ , bestF] foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(Ens[[i]], newdata = Xtest2) } -> InputTest1 #[ ,n] #---res------------------------- return(list(InputTrain = predEns, InputTest = InputTest, InputTest1 = InputTest1)) } }, env)
创建一个融合并计算可训练合并器的输入:
#---4--createEns---------------- evalq({ Ytrain <- X1$pretrain$y Ytest <- X1$train$y Ytest1 <- X1$test$y Ytest2 <- X1$test1$y Ens <- vector(mode = "list", n) createEns(order = orderX1, X = X1) -> Ens GetInputData(Ens, X1) -> res }, env)
Result structure:
> env$res %>% str() List of 3 $ InputTrain: num [1:1001, 1:500] 0.811 0.882 0.924 0.817 0.782 ... $ InputTest : num [1:501, 1:500] 0.5 0.383 0.366 0.488 0.359 ... $ InputTest1: num [1:251, 1:500] 0.32 0.246 0.471 0.563 0.451 ...
2. 基础比较模型
将创建两个可训练的合并器。 一个将取代融合最佳神经网络输出的平均值,第二个将取代修剪和平均。 因此,两种选择都需要分类品质得分。
神经网络的融合
对于第一个选项,具有最佳参数的 ELM 融合将是基础比较模型。
由于第二个选项意味着 500 个输入,因此将使用 varbvs 软件包。 它提供了快速选择贝叶斯模型的算法,用于筛选变量和计算贝叶斯系数,其中结果使用线性或逻辑回归建模。 这些算法基于文章 "回归选择贝叶斯变量的可扩展变分推理及其在遗传关联研究中的准确性" 中描述的变分近似。 该软件用于处理包含超过一百万个变量和数千个样本的大型数据集合。
对于第一种选项,编写附加函数 getBest(),testAver(),testVot() 并计算度量。 函数已在 FUN_Stacking.R 文件中提供。
evalq({ getBest <- function(Ens, x, y, nb){ n <- length(Ens) foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(Ens[[i]], newdata = x)} -> y.pr foreach(i = 1:n, .combine = "c") %do% { median(y.pr[ ,i])} ->> th foreach(i = 1:n, .combine = "c") %do% { ifelse(y.pr[ ,i] > th[i], 1, 0) -> Ypred Evaluate(actual = y, predicted = Ypred)$Metrics$F1 %>% mean() } -> Score Score %>% order(decreasing = TRUE) %>% head(2*nb + 1) -> best y.pr[ ,best] %>% apply(1, sum) %>% divide_by(length(best)) %>% median() -> med return(list(Score = Score, bestNN = best, med = med)) } testAver <- function(Ens, x, y, best, med){ n <- length(Ens) foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %:% when(i %in% best) %do% { predict(Ens[[i]], newdata = x)} %>% apply(1, sum) %>% divide_by(length(best)) -> ensPred ifelse(ensPred > med, 1, 0) -> clAver Evaluate(actual = y, predicted = clAver)$Metrics[ ,2:5] %>% round(3) -> Score return(list(Score = Score, Ypred = ensPred, clAver = clAver)) } testVot <- function(Ens, x, y, best){ n <- length(Ens) foreach(i = 1:n, .packages = "elmNN", .combine = "cbind") %:% when(i %in% best) %do% { predict(Ens[[i]], newdata = x)} %>% apply(2, function(x) ifelse(x > th[i], 1, -1)) %>% apply(1, function(x) sum(x)) -> vot ifelse(vot > 0, 1, 0) -> ClVot Evaluate(actual = y, predicted = ClVot)$Metrics[ ,2:5] %>% round(3) -> Score return(list(Score = Score, Ypred = ClVot)) } }, env)
这些函数均已 研究过。 因此,我们不会再详述它们。 然而,它们的输出值得注意。
- 函数 getBest() 返回度量 (Score),融合的最佳单个分类指数 (bestNN),融合输出的均值中位数 (med),并将在测试模型时使用。 所有融合输出的中值向量 th[500] 被插入到环境中。
- 函数 testAver() 返回度量 (Score),集合的平均连续预测 (Ypred) 和融合的标称预测 (clAver)。
- 函数 testVot() 返回度量 (Score) 和融合的标称预测 (Ypred)。
使用平均和多数表决在两个测试集合上测试所创建的融合,然后查看度量。
#--2---test---- evalq({ Ytrain <- X1$pretrain$y Ytest <- X1$train$y Ytest1 <- X1$test$y Ytest2 <- X1$test1$y Ens <- vector(mode = "list", n) Ens <- createEns(order = orderX1, X = X1) #---3------ resBest <- getBest(Ens, x = X1$train$x[ , bestF], y = Ytest, nb = 3) #---4--averaging--- ScoreAver <- testAver(Ens, x = X1$test$x[ , bestF], y = Ytest1, best = resBest$bestNN, med = resBest$med) ScoreAver1 <- testAver(Ens, x = X1$test1$x[ , bestF], y = Ytest2, best = resBest$bestNN, med = resBest$med) #---5--voting---- ScoreVot <- testVot(Ens, x = X1$test$x[ , bestF], y = Ytest1, best = resBest$bestNN) ScoreVot1 <- testVot(Ens, x = X1$test1$x[ , bestF], y = Ytest2, best = resBest$bestNN) }, env) > env$ScoreAver$Score Accuracy Precision Recall F1 0 0.75 0.708 0.778 0.741 1 0.75 0.794 0.727 0.759 > env$ScoreAver1$Score Accuracy Precision Recall F1 0 0.753 0.750 0.826 0.786 1 0.753 0.758 0.664 0.708 > env$ScoreVot$Score Accuracy Precision Recall F1 0 0.752 0.702 0.800 0.748 1 0.752 0.808 0.712 0.757 > env$ScoreVot1$Score Accuracy Precision Recall F1 0 0.741 0.739 0.819 0.777 1 0.741 0.745 0.646 0.692
在两个测试集合都有良好的表现。 下面,在分析结果时,将分类误差分解为 偏差/方差/噪声,并评估每个分量对总误差的贡献。
对于第二个选项 (500 个输入), 下面提供了训练模型的脚本。 它可在 varb.R 文件中找到。
library(varbvs) evalq({ vr <- varbvs(X = res$InputTrain, Z = NULL, y = Ytest, family = "binomial", optimize.eta = TRUE, logodds = seq(-6,-2, 0.25), nr = 250, initialize.params = TRUE, maxiter = 1e5, verbose = FALSE) summary(vr, cred.int = 0.95, nv = 7, nr = 1e5) %>% print() }, env) 拟合贝叶斯变量选择模型汇总: family: binomial num. hyperparameter settings: 17 samples: 1001 iid variable selection prior: yes variables: 500 fit prior var. of coefs (sa): yes covariates: 1 fit approx. factors (eta): yes maximum log-likelihood lower bound: -579.4602 Hyperparameters: estimate Pr>0.95 candidate values sa 8.09 [7.63,8.54] NA--NA logodds -2.26 [-2.75,-2.00] (-6.00)--(-2.00) Selected variables by probability cutoff: >0.10 >0.25 >0.50 >0.75 >0.90 >0.95 3 3 3 3 3 3 Top 7 variables by inclusion probability: index variable prob PVE coef* Pr(coef.>0.95) X18 18 X18 1.00000 NA 4.529 [+3.861,+5.195] X5 5 X5 1.00000 NA 1.955 [+1.543,+2.370] X255 255 X255 1.00000 NA 2.097 [+1.537,+2.660] X109 109 X109 0.00948 NA -1.033 [-2.008,-0.057] X404 404 X404 0.00467 NA -0.665 [-1.350,+0.024] X275 275 X275 0.00312 NA -0.726 [-1.735,+0.286] X343 343 X343 0.00299 NA -0.604 [-1.353,+0.149] * 请参阅 help(varbvs) 中有关逻辑回归中的解释系数。
使用获得的模型,计算两个测试集合的预测并计算度量。
env$vr$pip %>% order() %>% tail(7) -> bestNN_vr evalq({ predict(vr, res$InputTest) -> pr.vr1 Evaluate(actual = Ytest1, predicted = pr.vr1)$Metrics[ ,2:5] %>% round(3) -> metr.test confus(table(Ytest1, pr.vr1)) -> cm1 predict(vr, res$InputTest1) -> pr.vr2 Evaluate(actual = Ytest2, predicted = pr.vr2)$Metrics[ ,2:5] %>% round(3) -> metr.test1 confus(table(Ytest2, pr.vr2)) -> cm2 }, env) > env$metr.test Accuracy Precision Recall F1 0 0.78 0.750 0.783 0.766 1 0.78 0.808 0.779 0.793 > env$metr.test1 Accuracy Precision Recall F1 0 0.729 0.765 0.732 0.748 1 0.729 0.689 0.726 0.707
结果非常好,比融合的度量要好得多。
所有数据均要继续实验直至完成。
由于将来会使用 <k>keras/tensorflow 函数库,因此下面简要介绍它们。
3. Keras/TensorFlow 函数库。 一般说明和安装
快速扩展的深度神经网络领域已经补充了众多开源函数库。 这些包括 — TensorFlow(Google), CNTK(Microsoft), Apache MXNet 和许多其它种。 由于所有这些,和其它主要软件开发人员都是 R Consortium 的成员,全部这些函数库都提供了 R 的 API。
以上所有函数库都是低层次的。 对于初学者,它们难以学习和掌握。 考虑到这一点,Rstudio 团队为 R 开发了 keras 软件包。
Keras 是一个高等级神经网络 API。 该软件包的设计重点在于能够快速创建原型,并通过实验测试模型的性能。 以下是 Keras 的主要特点:
- 允许在 CPU 或 GPU 上同等工作。
- 友好的 API,可以轻松创建深度学习模型的原型。
- 内置支持卷积网络 (用于计算机视觉) ,循环网络 (用于处理序列) 及其任意组合。
- 支持任意网络架构: 具有多个输入或多个输出的模型,层共享,模型共享,等等。 这意味着 Keras 基本上适用于构建从存储器网络到神经图灵机的任何深度学习模型。
- 它能够在若干后端的顶层工作,包括 TensorFlow,CNTK 或 Theano。
Keras 是为人而不是机器设计的 API。 该软件包降低了认知负担: 它提供了一致且简单的 API,最大限度地减少了用户操作的数量,并提供了有关用户错误的有效反馈。 所有这些令 Keras 易于学习和使用。 但这不是靠降低灵活性造成的: 因为 Keras 与深度学习的低级语言 (特别是 TensorFlow) 集成,它允许您实现在基础语言上可创建的所有东西。
您可以使用若干个深度学习模块开发 Keras 模型。 任何仅在嵌入层使用的 Keras 模型都可以在所有这些后端之间进行转换而无需更改: 您可以使用一个后端训练模型并将其加载到另一个后端。 可用的后端包括:
- TensorFlow 后端 (来自 Google)
- CNTK 后端 (来 Microsoft)
- Theano 后端
您可以在几个不同的硬件平台上训练 Keras 模型,而不仅仅是 CPU:
- NVIDIA GPUs
- Google TPUs, 通过 TensorFlow 后端和 Google 云
- 支持 OpenCL 的 GPU,例如来自 AMD 的 GPU,通过 PlaidML Keras后端
安装 keras 和 tensorflow 后端
Keras 和 TensorFlow 可配置在 CPU 或 GPU 上运行。 CPU 版本更易于安装和设置,因此,它是开始使用该软件包的最佳选择。 以下是 TensorFlow 网站上 CPU 和 GPU 版本的手册:
- TensorFlow 仅支持 CPU. 如果您的系统没有 NVIDIA® GPU,则必须安装此版本。
- TensorFlow 仅支持 GPU. TensorFlow 程序在 GPU 上运行通常比在 CPU 上运行快得多。 因此,如果您的系统具有满足所有先决条件的 NVIDIA® GPU,并且您需要运行性能优先的应用程序,则最终应安装此版本。
Windows 上唯一受支持的安装方法是 "conda"。 这意味着您应该在安装 Keras 之前为 Windows 安装 Anaconda 3.x (Python 3.5.x/3.6.x)。 我安装了 Anaconda3(Python3.6)。
首先,从 CRAN 安装 keras 软件包:
install.packages("keras")
Keras R 接口默认使用 TensorFlow。 若要安装 Keras 主体函数库和 TensorFlow 后端,请使用 install_keras() 函数:
# default installation library(keras) install_keras()
因此,将安装 Keras 和 TensorFlow 的 CPU 版本。 如果您需要自定义设置 — 例如,使用 NVIDIA GPU,请参阅 文档。 要安装特定版本的 TensorFlow 或支持 GPU,请执行以下操作:
# install with GPU version of TensorFlow # (NOTE: only do this if you have an NVIDIA GPU + CUDA!) install_keras(tensorflow = "gpu") # install a specific version of TensorFlow install_keras(tensorflow = "1.5") install_keras(tensorflow = "1.5-gpu")
有关更多详细信息,请参见此处。
tfruns 支持的软件包用于 TensorFlow 的实验。 这是一套用于管理来自 R 的 TensorFlow 训练和实验的工具包。
- 跟踪每次训练运行的超参数,度量,输出数据和源代码。
- 比较运行中的超参数和度量,以便找到性能最佳的模型。
- 自动生成报告以便可视化各单一训练运行或所有运行之间的比较。
- 不需要更改源代码 (为所有 Keras 和 tfestimators 模型自动捕获运行数据)。
DNN 训练过程和结果的最佳可视化品质由 TensorBoard 提供。
深度学习智能系统有机会使用 tensorflow 软件包直接使用低级 TensorFlow 函数库。
所有这些软件包都基于 reticulate 主体软件包,它是 Python 模块,函数和类的 R 接口。 在 Python 中调用时,R 数据类型会自动转换为等效的 Python 类型。 从 Python 返回的值将转换回 R 类型。
所有这些软件包都有详细记录,提供了大量示例,并且还在不断发展。 这便有可能使用最先进的深度学习模型 (DNN,RNN,CNN,LSTM,VAE 等),强化学习 (RL) 以及许多其它 Python 来开发终端智能系统和指标。 唯一的限制是开发人员的知识和经验。
这里有两个值得注意的有趣软件包: kerasR 和 kerasformula。 对第一个进行了测试,确认操作速度高于原始的 "tensorflow-1.5"。 第二个使用公式来提供模型的简化版本。
本文目的仅仅是为新领域的简单开始提供示例。 它的任务不是涵盖所有机会的多样性,而是获得高品质的模型得分。
在开始实验之前,有必要检查是否安装了 Python,以及 R 是否能与之交互。
> library(reticulate)
> py_config()
python: K:\Anaconda3\envs\r-tensorflow\python.exe
libpython: K:/Anaconda3/envs/r-tensorflow/python36.dll
pythonhome: K:\ANACON~1\envs\R-TENS~1
version: 3.6.5 | packaged by conda-forge | (default, Apr 6 2018, 16:13:55)
[MSC v.1900 64 bit (AMD64)]
Architecture: 64bit
numpy: K:\ANACON~1\envs\R-TENS~1\lib\site-packages\numpy
numpy_version: 1.14.2
tensorflow: K:\ANACON~1\envs\R-TENS~1\lib\site-packages\tensorflow
python versions found:
K:\Anaconda3\envs\r-tensorflow\python.exe
K:\ANACON~1\python.exe
K:\Anaconda3\python.exe
我们来看看使用的 tensorflow 版本:
> library(tensorflow) > tf_config() TensorFlow v1.5.1 (K:\ANACON~1\envs\R-TENS~1\lib\site-packages\tensorflow) Python v3.6 (K:\Anaconda3\envs\r-tensorflow\python.exe)
一切均已准备就绪,可继续实验。
4. 袋型融合输出合并器 — 神经网络
我们来进行两个实验。 在第一个中,应用 softmax 函数,而不是对融合的最佳输出求平均值。 在第二个中,用神经网络代替修剪和平均,将融合的所有 500 个输出作为输入。 实验的结构方案如下图所示。
图例2. 用神经网络代替融合输出的平均值
Keras 的主要数据结构是一种模型,一种组织层的方式。 最简单的类型是 顺序模型,表示层的线性堆叠。
首先,创建一个简单的顺序模型,然后使用 pipe(%>%) 运算符开始添加层。 对于第一个实验,创建一个仅由输入和输出层组成的神经网络。 在测试集合上所获的修剪后的融合输出将作为输入馈送。 训练集合得 20% 将作为验证。 在这个软件包中创建,训练和测试神经网络非常容易。
设置模型的常量参数,定义 DNN 的训练和测试集合。
#===========Keras=========================================== library(keras) num_classes <- 2L batch_size <- 32L epochs <- 300L #--------- bestNN <- env$resBest$bestNN x_train <- env$res$InputTrain[ ,bestNN] y_train <- env$Ytest %>% to_categorical() x_test <- env$res$InputTest[ ,bestNN] y_test <- env$Ytest1 %>% to_categorical() x_test1 <- env$res$InputTest1[ ,bestNN] y_test1 <- env$Ytest2 %>% to_categorical()
创建模型。 脚本代码如下所示。 定义并编译具有结构 NN(7,2) 的模型 — 输入有 7 个神经元,输出有 2 个神经元。 优化器 — "rmsprop" 函数,损失函数 — "binary'_crossentropy",测试结果的度量 — "accuracy"。
##----model--keras------------------------- # define model model <- keras_model_sequential() # add layers and compile model %>% layer_dense(units = num_classes, input_shape = dim(x_train)[2]) %>% layer_activation(activation = 'softmax') %>% compile( loss = 'binary_crossentropy', optimizer = optimizer_rmsprop(), metrics = 'accuracy' )
训练和测试模型 (脚本在下面提供)。 保存训练历史。 另外,指定:
- 没有必要将每次迭代的结果输出到终端;
- 没有必要在 Viewer/Rstudio 中显示实时图表;
- 有必要在每个训练期之后对输入数据进行筛洗。
为了验证,请使用 20% 的训练集合。
## Training & Evaluation --------------------------- # Fit model to data model %>% fit( x_train, y_train, batch_size = batch_size, epochs = epochs, verbose = 0, view_metrics = FALSE, shuffle = TRUE, validation_split = 0.2) -> history # Output metrics score <- model %>% evaluate(x_test, y_test, verbose = 0) cat('Test loss:', score[[1]] %>% round(3), '\n') Test loss: 0.518 cat('Test accuracy:', score[[2]] %>% round(3), '\n') Test accuracy: 0.754 #--------------- score1 <- model %>% evaluate(x_test1, y_test1, verbose = 0) cat('Test loss:', score1[[1]] %>% round(3), '\n') Test loss: 0.55 cat('Test accuracy:', score1[[2]] %>% round(3), '\n') Test accuracy: 0.737
定量结果并不差,它们几乎等于融合的平均结果。 我们来看看训练和测试这个模型的历史:
#--plot------------------------
plot(history)
图例3. 模型训练历史 (7, 2)
该图表显示该模型在 30 期后显然过度拟合,并且在 50 期之后,准确度达到稳定水平。
请您记住,神经网络初始化的过程是随机的。 也就是说,每个新创建,训练和测试的模型将产生不同的结果。
即使在神经网络的这种最小配置中,也存在许多影响分类品质和过度拟合的机会。 以下是其中一些: 提前停止; 神经元初始化方法; 激活函数的正规化,等等。 其中,我们将仅检查早期停止,向输入数据添加噪声,激活功能的正规化,并输出训练结果的更详细的图形表示。 为此,在训练期间请使用 keras 提供的callback 函数。
callback_early_stopping(monitor = "val_loss", min_delta = 0, patience = 0, verbose = 0, mode = c("auto", "min", "max")) callback_tensorboard(log_dir = NULL, histogram_freq = 0, batch_size = 32, write_graph = TRUE, write_grads = FALSE, write_images = FALSE, embeddings_freq = 0, embeddings_layer_names = NULL, embeddings_metadata = NULL)
定义回调函数。
early_stopping <- callback_early_stopping(monitor = "val_acc", min_delta = 1e-5, patience = 20, verbose = 0, mode = "auto") log_dir <- paste0(getwd(),"/run_1") tensboard <- callback_tensorboard(log_dir = log_dir, histogram_freq = 1, batch_size = 32, write_graph = TRUE, write_grads = TRUE, write_images = FALSE)
在第一个中,我们指出有必要跟踪 Accuracy (准确度) 数值。 如果此值在 patiente 期内小于 min_delta,则应停止训练。 在第二步中,我们设置了存储训练结果的目录路径以供以后回放,并且还指定了准确存储它们的位置。 我们来使用这些函数编写完整的脚本并查看结果。
##=====Variant earlystopping================================= #--prepare data-------------------------- library(reticulate) library(keras) py_set_seed(12345) num_classes <- 2L batch_size <- 32L learning_rate <- 0.005 epochs <- 100L #--------- bestNN <- env$resBest$bestNN x_train <- env$res$InputTrain[ ,bestNN] y_train <- env$Ytest %>% to_categorical() x_test <- env$res$InputTest[ ,bestNN] y_test <- env$Ytest1 %>% to_categorical() x_test1 <- env$res$InputTest1[ ,bestNN] y_test1 <- env$Ytest2 %>% to_categorical() ##----model--keras------------------------- # define model model <- keras_model_sequential() # add layers and compile model %>% layer_gaussian_noise(stddev = 0.05, input_shape = dim(x_train)[2], name = "GN") %>% layer_dense(units = num_classes, name = "dense1") %>% layer_activation_softmax(name = "soft") %>% layer_activity_regularization(l2 = 1.0, name = "reg") %>% #l1 = 0.01, compile( loss = 'binary_crossentropy', optimizer = optimizer_rmsprop(lr = learning_rate, decay = 0.01), metrics = 'accuracy' ) ## Training & Evaluation --------------------------- # Fit model to data model %>% fit( x_train, y_train, batch_size = batch_size, epochs = epochs, verbose = 0, view_metrics = TRUE , shuffle = TRUE, validation_split = 0.2, callbacks = list(early_stopping, tensboard)) -> history
两个测试集合的度量标准和早期停止的训练历史。
# Output metrics > score <- model %>% evaluate(x_test, y_test, verbose = 0) > cat('Test loss:', score[[1]] %>% round(3), '\n') Test loss: 0.539 > cat('Test accuracy:', score[[2]] %>% round(3), '\n') Test accuracy: 0.756 > #--------------- > score1 <- model %>% evaluate(x_test1, y_test1, verbose = 0) > cat('Test loss:', score1[[1]] %>% round(3), '\n') Test loss: 0.571 > cat('Test accuracy:', score1[[2]] %>% round(3), '\n') Test accuracy: 0.713
图例 4. 早期停止训练的历史
若要显示有关神经网络训练过程的详细图形信息,请使用 tensorboard 函数:
> tensorboard(log_dir = log_dir) TensorBoard 1.7.0 at http://127.0.0.1:7451 (Press CTRL+C to quit) Started TensorBoard at http://127.0.0.1:7451
浏览器将打开一个页面,您可以在其中查看神经网络的所有内部详细信息。 以下是示例截图:
图例 5. 训练集合上训练的损失和准确度图表,基于 val_acc 和 val_loss 的验证数据
图例 6. 神经网络的计算图
图例 7. 层 'dense ('密集)' 直方图
图例 8. softmax 和正则化输出的直方图
这些图型是调整神经网络参数的有力工具,但它们的详细分析超出了本文的范围。
在 tensorboard 的每个新开始处,都需要更改保存路径 log_dir 或删除以前使用的路径。
我们来看看具有相同参数的分类品质如何变化,不过使用测试集合进行验证。 该脚本如下所示,并可在文件中找到:
library(reticulate) library(keras) py_set_seed(12345) num_classes <- 2L batch_size <- 32L learning_rate <- 0.005 epochs <- 100L #--------- bestNN <- env$resBest$bestNN x_train <- env$res$InputTrain[ ,bestNN] y_train <- env$Ytest %>% to_categorical() x_test <- env$res$InputTest[ ,bestNN] y_test <- env$Ytest1 %>% to_categorical() x_test1 <- env$res$InputTest1[ ,bestNN] y_test1 <- env$Ytest2 %>% to_categorical() #---------------------------------------- early_stopping <- callback_early_stopping(monitor = "val_acc", min_delta = 1e-5, patience = 20, verbose = 0, mode = "auto") log_dir <- paste0(getwd(),"/run_2") tensboard <- callback_tensorboard(log_dir = log_dir, histogram_freq = 1, batch_size = 32, write_graph = TRUE, write_grads = TRUE, write_images = FALSE) ##----model--keras------------------------- # define model model <- keras_model_sequential() # add layers and compile model %>% layer_gaussian_noise(stddev = 0.05, input_shape = dim(x_train)[2], name = "GN") %>% layer_dense(units = num_classes, name = "dense1") %>% layer_activation_softmax(name = "soft") %>% layer_activity_regularization(l2 = 1.0, name = "reg") %>% #l1 = 0.01, compile( loss = 'binary_crossentropy', optimizer = optimizer_rmsprop(lr = learning_rate, decay = 0.01), metrics = 'accuracy' ) ## Training & Evaluation --------------------------- # Fit model to data model %>% fit( x_train, y_train, batch_size = batch_size, epochs = epochs, verbose = 0, view_metrics = TRUE , shuffle = TRUE, validation_data = list(x_test, y_test), callbacks = list(early_stopping, tensboard)) -> history
让我们看看第二个测试集合上的度量:
#--model--test1------------------------------------------------- predict(model, x_test1) -> Ypr.test1 Ypr.test1 %>% max.col()-1 -> y_pr_test1 #Ypr.test1 %>% apply(1, function(x) which.max(x)) %>% subtract(1) -> y_pr_test1 evalq(res_mod_test1 <- Eval(Ytest2, y_pr_test1), env) > env$res_mod_test1 $metrics Accuracy Precision Recall F1 0 0.713 0.704 0.826 0.760 1 0.713 0.730 0.575 0.644 $confMatr Confusion Matrix and Statistics predicted actual 0 1 0 114 24 1 48 65 Accuracy : 0.7131 95% CI : (0.6529, 0.7683) No Information Rate : 0.6454 P-Value [Acc > NIR] : 0.013728 Kappa : 0.4092 Mcnemar's Test P-Value : 0.006717 Sensitivity : 0.7037 Specificity : 0.7303 Pos Pred Value : 0.8261 Neg Pred Value : 0.5752 Prevalence : 0.6454 Detection Rate : 0.4542 Detection Prevalence : 0.5498 Balanced Accuracy : 0.7170 'Positive' Class : 0
它们几乎与第一个变体相同。 我们可以使用 tensorboard 直观比较两个变体。
#-----plot------------------ tensorboard(log_dir = c(paste0(getwd(),"/run_1"), paste0(getwd(),"/run_2")))
图例 9. 训练集合上的度量
图例 10. 验证集合上的度量
这是可以看出差别的所在。
我们来进行最后一次实验。 融合的所有 500 个输出将作为输入馈送到多层神经网络。 因此,神经网络同时执行修剪和合并。 该脚本提供如下,也可以在 modelDNN_500.R 文件中找到。
library(reticulate) library(keras) py_set_seed(12345) num_classes <- 2L batch_size <- 32L learning_rate <- 0.0001 epochs <- 100L #--------- x_train <- env$res$InputTrain y_train <- env$Ytest %>% to_categorical() x_test <- env$res$InputTest y_test <- env$Ytest1 %>% to_categorical() x_test1 <- env$res$InputTest1 y_test1 <- env$Ytest2 %>% to_categorical() #---------------------------------------- early_stopping <- callback_early_stopping(monitor = "val_acc", min_delta = 1e-5, patience = 20, verbose = 0, mode = "auto")
我们已经下载了函数库,常量,定义了用于训练和测试的集合,以及早期停止函数。
##----modelDNN--keras------------------------- # define model modDNN <- keras_model_sequential() # add layers and compile modDNN %>% layer_gaussian_noise(stddev = 0.001, input_shape = dim(x_train)[2], name = "GN") %>% layer_batch_normalization() %>% layer_dense(units = 100, activation = "elu", name = "dense1") %>% layer_dropout(rate = 0.5, name = "dp1") %>% layer_batch_normalization() %>% layer_dense(units = 50, activation = "elu", name = "dense2") %>% layer_batch_normalization() %>% layer_dropout(rate = 0.5, name = "dp2") %>% layer_dense(units = 10, activation = "elu", name = "dense3") %>% layer_batch_normalization() %>% layer_dropout(rate = 0.2, name = "dp3") %>% layer_dense(units = num_classes, activation = "softmax", name = "soft") %>% compile( loss = 'binary_crossentropy', optimizer = optimizer_rmsprop(lr = learning_rate, decay = 0.0001), metrics = 'accuracy' )
因此,我们已定义了神经网络,指定了层的顺序和参数。 我们还指导编译器在训练模型时使用哪些损失函数,优化器和度量。 现在训练模型:
## Training & Evaluation --------------------------- # Fit model to data modDNN %>% fit( x_train, y_train, batch_size = batch_size, epochs = epochs, verbose = 0, view_metrics = TRUE , shuffle = TRUE, validation_split = 0.2, #validation_data = list(x_test, y_test), callbacks = list(early_stopping)) -> history
在训练期间,我们将输出度量并随机输入数据,20% 的训练集合将用于验证,并将采用提前停止。 在测试集合上测试模型:
#--model--test------------------------- predict(modDNN, x_test) -> Ypr.test Ypr.test %>% apply(1, function(x) which.max(x)) %>% subtract(1) -> y_pr_test evalq(res_mod_test <- Eval(Ytest1, y_pr_test), env)
可以看出,结果数字与融合的均值相当:
> env$res_mod_test $metrics Accuracy Precision Recall F1 0 0.752 0.702 0.800 0.748 1 0.752 0.808 0.712 0.757 $confMatr Confusion Matrix and Statistics predicted actual 0 1 0 184 46 1 78 193 Accuracy : 0.7525 95% CI : (0.7123, 0.7897) No Information Rate : 0.523 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.5068 Mcnemar's Test P-Value : 0.005371 Sensitivity : 0.7023 Specificity : 0.8075 Pos Pred Value : 0.8000 Neg Pred Value : 0.7122 Prevalence : 0.5230 Detection Rate : 0.3673 Detection Prevalence : 0.4591 Balanced Accuracy : 0.7549 'Positive' Class : 0
我们来绘制训练历史:
plot(history)
图例 11. DNN500 神经网络训练的历史
为了提高分类品质,可以修改许多超参数: 神经元初始化方法,神经元激活的正则化及其权重等。 使用几乎凭直觉选择的参数所获的结果具有良好的品种,但其上限也令人失望。 如果没有优化,就不可能将准确度提高到 0.82 以上。 结论: 有必要优化神经网络的超参数。 在之前的文章中,我们尝试了贝叶斯优化。 在这里也可以采用它,但这是另一个难题。
按顺序定义模型允许测试和配置任何复杂度和深度的模型。 但是使用 keras 的函数 API,可以创建更复杂的神经网络结构: 例如,具有多个输入和输出。 这会在即将发表的文章中讨论。
5. 实验结果分析
因此,我们已有五个模型的训练和测试结果:
- 均值融合 (EnsAver);
- 多数表决融合 (EnsVot);
- 逻辑回归模型变体;
- 神经网络 DNN(7,2);
- 神经网络 DNN500。
我们在一个表格中收集所有这些模型的品质得分,将分类误差分解为分量并估计它们对整体误差的贡献。 我们使用函数 randomUniformForest::biasVarCov() (乖离-方差-协方差分解)。 有关此函数的更多详细信息,请参阅软件包说明。 用于分解 EnsAver 和 EnsVot 集合分类误差的代码如下所示。 这些脚本与其它模型类似。
#---bias--test------------------------------- import_fun(randomUniformForest, biasVarCov, BiasVar) evalq({ target = Ytest1 biasAver <- BiasVar(predictions = ScoreAver$clAver, target = target, regression = FALSE, idx = 1:length(target)) biasVot <- BiasVar(predictions = ScoreVot$ClVot, target = target, regression = FALSE, idx = 1:length(target)) }, env) ----------------------------- Noise: 0.2488224 Squared bias: 0.002107561 Variance of estimator: 0.250475 Covariance of estimator and target: 0.1257046 Assuming binary classification with classes {0,1}, where '0' is the majority class. Misclassification rate = P(Y = 1)P(Y = 0) + {P(Y = 1) - P(Y_hat = 1)}^2 + P(Y_hat = 0)P(Y_hat = 1) - 2*Cov(Y, Y_hat) Misclassification rate = P(Y = 1) + P(Y_hat = 1) - 2*E(Y*Y_hat) = 0.2499958 --------------------- Noise: 0.2488224 Squared bias: 0.004079665 Variance of estimator: 0.2499721 Covariance of estimator and target: 0.1274411 Assuming binary classification with classes {0,1}, where '0' is the majority class. Misclassification rate = P(Y = 1)P(Y = 0) + {P(Y = 1) - P(Y_hat = 1)}^2 + P(Y_hat = 0)P(Y_hat = 1) - 2*Cov(Y, Y_hat) Misclassification rate = P(Y = 1) + P(Y_hat = 1) - 2*E(Y*Y_hat) = 0.2479918
紧凑的输出:
> env$biasAver $predError [1] 0.2499958 $squaredBias [1] 0.002107561 $predictionsVar [1] 0.250475 $predictionsTargetCov [1] 0.1257046
95%CI Acc | Precision | Recall | F1 | PredErr | sqBias | predVar | predTargCov | |
---|---|---|---|---|---|---|---|---|
EnsAver | 0.7102, 0.7880 (0.7500) | 0.708 0.794 |
0.778 0.727 |
0.741 0.759 |
0.2499 | 0.0021 | 0.2505 | 0.1257 |
EnsVot | 0.7123, 0.7897 (0.7525) | 0.702 0.808 |
0.800 0.712 |
0.748 0.757 |
0.248 | 0.0041 | 0.25 | 0.1274 |
varb | 0.7416, 0.8159 (0.7804) | 0.790 0.808 |
0.783 0.779 |
0.766 0.793 |
0.2199 | 0.000398 | 0.25 | 0.13964 |
DNN(7, 2) | 0.7165, 0.7935 (0.7565) | 0.765 0.751 |
0.678 0.823 |
0.719 0.785 |
0.2460 | 0.000195 | 0.2498 | 0.1264 |
DNN500 | 0.7123, 0.7897 (0.7525) | 0.702 0.808 |
0.800 0.712 |
0.748 0.757 |
0.2779 | 0.01294 | 0.2452 | 0.1145 |
汇总表格中的信息:
- 基本模型中的最佳 Accuracy (准确度) 得分由合并了 500 个融合输出的 varb 获得。 根据该得分,可训练合并器中的最佳模型是 DNN(7,2),其合并了融合的 7 个最佳输出。
- 测试样本 (PredErr) 的最小测试误差由 varb 和 DNN(7,2) 得到。
- 相同两个模型的平方乖离 (sqBias) 比其它模型好一个数量级。
- 所有模型的误差方差 (PredVar) 几乎相同。 这看起来很奇怪 融合所提供的方差应该降低,但我们收到了低乖离。
- 评估和响应 (predictionTargetCov) 之间的最佳协方差由 varb 表示。 它作为自变量时并不意味着它本身,它仅用于比较模型。
- DNN500 模型的所有分数都是最低的。 结论: 增加简单任务模型的复杂度并不会带来更好的结果。
结束语
具有平均或简单多数表决的 ELM 神经网络分类器的融合在非常高的计算速度下显示出良好的分类品质。 优化将输出从连续变量转换为标称变量的阈值,并在求平均值之前校正输出,可以提高品质。 没有检测到误差的方差明显减少。
用一个简单的神经网络的 softmax 函数代替融合输出的平均值可以将乖离减小一个数量级,而方差没有任何明显的降低。 使用更复杂的神经网络模型来取代修剪和平均并没有产生良好的结果。
在贝叶斯变量选择 (varbvs 软件包) 的帮助下获得的逻辑回归模型显示了非常好的结果。 您可以将此软件包确定的最佳输出用于神经网络。
自预处理以来似乎无法消除的 24% 的噪声再次提示噪声样本应在某个阶段重新标记为单独的类。
有必要使用 keras 的功能,并在我们的数据序列 (时间序列) 上运作。 这可以提高分类品质。
附件
GitHub/PartVII 包含以下文件:
- Importar.R — 软件包导入函数。
- Library.R — 所需的函数库。
- FunPrepareData_VII.R — 准备初始数据的函数。
- FunStacking.R — 用于创建和测试集合的函数。
- Prepare.R — 用于为可训练合并器准备初始数据的函数和脚本。
- Varb.R — varb 基础模型的脚本。
- model_DNN7_2.R — DNN(7-2) 神经网络的脚本。
- model_DNN_500.R — DNN500 神经网络的脚本。
- SessionInfo_VII.txt — 文章中脚本使用的软件包列表。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/4228
![货币对形态测试: 实际应用和真实交易视角。 第四部分](https://c.mql5.com/2/31/LOGO.png)
![如何创建订购交易机器人的需求规范](https://c.mql5.com/2/32/HowCreateExpertSpecification.png)