/
Lrnr_bilstm.R
130 lines (117 loc) 路 4.36 KB
/
Lrnr_bilstm.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#' Bidirectional Long short-term memory Recurrent Neural Network (LSTM)
#'
#' This learner supports bidirectinal long short-term memory recurrent neural
#' network algorithm. In order to use this learner, you will need keras Python
#' module 2.0.0 or higher. Note that all preprocessing, such as differencing and
#' seasonal effects for time series, should be addressed before using this
#' learner.
#'
#' @docType class
#' @importFrom R6 R6Class
#' @export
#' @keywords data
#' @return \code{\link{Lrnr_base}} object with methods for training and prediction
#' @format \code{\link{R6Class}} object.
#'
#' @field units Positive integer, dimensionality of the output space.
#' @field loss Name of a loss function used.
#' @field optimizer name of optimizer, or optimizer object.
#' @field batch_size Number of samples per gradient update.
#' @field epochs Number of epochs to train the model.
#' @field window Size of the sliding window input.
#' @field activation The activation function to use.
#' @field dense regular, densely-connected NN layer. Default is 1.
#' @field dropout float between 0 and 1. Fraction of the input units to drop.
#'
#' @importFrom assertthat assert_that is.count is.flag
#'
#' @family Learners
#'
Lrnr_bilstm <- R6Class(
classname = "Lrnr_bilstm", inherit = Lrnr_base, portable = TRUE, class = TRUE,
public = list(
initialize = function(units = 4,
loss = "mean_squared_error",
optimizer = "adam",
batch_size = 1,
epochs = 500,
window = 5,
activation = "linear",
dense = 1,
dropout = 0,
...) {
params <- list(
units = units, loss = loss, optimizer = optimizer,
batch_size = batch_size, epochs = epochs, window = window,
activation = activation, dense = dense, dropout = dropout, ...
)
super$initialize(params = params, ...)
}
),
private = list(
.properties = c("timeseries", "continuous"),
.train = function(task) {
args <- self$params
# Pad with NA:
data <- c(rep(NA, args$window), task$Y)
# Convert to keras input shape:
args$x <- t(data.frame(lapply(
1:(length(data)[1] - args$window),
function(x) data[x:(x + args$window - 1)]
)))
row.names(args$x) <- NULL
args$y <- as.numeric(sapply(
(args$window + 1):(length(data)[1]),
function(x) data[x]
))
names(args$y) <- NULL
args$x <- kerasR::expand_dims(args$x, axis = 2)
args$y <- kerasR::expand_dims(args$y, axis = 1)
num_samples <- dim(args$x)[1] # based on spliting the time series
num_steps <- dim(args$x)[2] # window
num_features <- dim(args$x)[3] # features = ts
# Build the model
model <- kerasR::Sequential()
# keras::bidirectional(
# object = model, layer = kerasR::LSTM(args$units,
# return_sequences = TRUE
# ),
# input_shape = c(num_steps, num_features)
# )
model$add(kerasR::Bidirectional(kerasR::LSTM(args$units, return_sequences = TRUE)))
model$add(kerasR::Dropout(rate = args$dropout))
model$add(kerasR::Flatten())
model$add(kerasR::Dense(args$dense))
model$add(kerasR::Activation(args$activation))
kerasR::keras_compile(model, loss = args$loss, optimizer = args$optimizer)
# Fit the model
kerasR::keras_fit(
model, args$x, args$y,
batch_size = args$batch_size,
epochs = args$epochs
)
fit_object <- model
return(fit_object)
},
.predict = function(task = NULL) {
args <- self$params
# Pad with NA:
data <- c(rep(NA, args$window), task$Y)
# Convert to keras input shape:
args$x <- t(data.frame(lapply(
1:(length(data)[1] - args$window),
function(x) data[x:(x + args$window - 1)]
)))
row.names(args$x) <- NULL
args$x <- kerasR::expand_dims(args$x, axis = 2)
predictions <- kerasR::keras_predict(private$.fit_object, args$x,
batch_size = args$batch_size
)
# Create output as in glm
predictions <- as.numeric(predictions)
predictions <- structure(predictions, names = seq_along(predictions))
return(predictions)
},
.required_packages = c("kerasR", "tensorflow", "keras")
),
)