# パッケージのインストール
if (!require(keras3))
{
install.packages("keras3")
library(keras3)
install_keras() # r-kerasという仮想環境にKerasがインストールされる。
# install_keras(tensorflow = "gpu") # GPU演算用(NVIDIA GPUとcuDNNが必要)
}
if (!require(plotly)) install.packages("plotly")
set.seed(5) # 乱数シード
n <- 24*7*2 # 時間数(全14日)
x <- 1:n # 時刻
x2 <- x^2
x3 <- 100*sin(2*pi*x/24)
f <- function(x) 100 + 0.1*x + 0.02*x2 + x3
y <- f(x) + rnorm(n, sd = 5)
d <- data.frame(y, x, x2, x3)
d
ii <- 1:(24*11) # 11日分のインデックス
d.tr <- d[ ii, ] # 訓練データを抽出(前11日)
d.te <- d[-ii, ] # 試験データを抽出(後3日)
vline <- list(type = "line",
line = list(color = "blue", dash = "dash"),
x0 = ii[length(ii)], x1 = ii[length(ii)],
y0 = 0, y1 = max(d$y))
plot_ly(type = "scatter", mode = "markers") |>
add_trace(x = d$x, y = d$y, mode = 'markers', name = "観測値") |>
add_trace(x = x, y = f(x), mode = 'lines', name = "真値") |>
layout(title = "青破線の左側:訓練領域,右側:予測領域", shapes = list(vline))
# モデル候補
FML <- vector("list", 4)
FML[[1]] <- formula("y ~ x")
FML[[2]] <- formula("y ~ x + x2")
FML[[3]] <- formula("y ~ x + x2 + x3")
FML[[4]] <- formula("y ~ poly(x, 4)")
# 選択モデル番号
ID.MODEL <- 3
# 回帰モデルから計画行列を作成
x.tr <- model.matrix(FML[[ID.MODEL]], d.tr)
x.te <- model.matrix(FML[[ID.MODEL]], d.te)
nc <- ncol(x.tr) # カラム数
me.tr <- apply(x.tr, 2, mean) # 訓練データの説明変数ごとの平均
sd.tr <- apply(x.tr, 2, sd) # 訓練データの説明変数ごとの標準偏差
x.tr <- scale(x.tr, center = me.tr, scale = sd.tr) # 標準化訓練データ
x.te <- scale(x.te, center = me.tr, scale = sd.tr) # 標準化試験データ
x.tr[, 1] <- 1 # 切片は標準化できない(NaNなる)ので1で置換
x.te[, 1] <- 1 # 切片は標準化できない(NaNなる)ので1で置換
# 深層学習モデル
model <-
keras_model_sequential(input_shape = c(nc)) |> # 入力層
layer_dense(units = nc*2, activation = "relu") |> # 中間層(ReLU)
layer_dense(units = nc*4, activation = "relu") |> # 中間層(ReLU)
layer_dense(units = nc*2, activation = "relu") |> # 中間層(ReLU)
layer_dense(units = 1, activation = "linear") # 出力層(線形)
# モデル概要
summary(model)
## Model: "sequential"
## ┌───────────────────────────────────┬──────────────────────────┬───────────────
## │ Layer (type) │ Output Shape │ Param #
## ├───────────────────────────────────┼──────────────────────────┼───────────────
## │ dense (Dense) │ (None, 8) │ 40
## ├───────────────────────────────────┼──────────────────────────┼───────────────
## │ dense_1 (Dense) │ (None, 16) │ 144
## ├───────────────────────────────────┼──────────────────────────┼───────────────
## │ dense_2 (Dense) │ (None, 8) │ 136
## ├───────────────────────────────────┼──────────────────────────┼───────────────
## │ dense_3 (Dense) │ (None, 1) │ 9
## └───────────────────────────────────┴──────────────────────────┴───────────────
## Total params: 329 (1.29 KB)
## Trainable params: 329 (1.29 KB)
## Non-trainable params: 0 (0.00 B)
# 高速演算のためのコンパイル(PCが素早く理解できる機械語に翻訳)
compile(model,
loss = "mse", # mean-squared-erros(2乗誤差平均)
optimizer = optimizer_adam(learning_rate = 0.1), # 最適化アルゴリズム
metrics = c("mean_absolute_error")) # 評価指標:絶対値誤差平均
# コールバック設定
callbacks <- list(
# 早期停止(検証データでの損失値の改善が20エポック以上なかったら停止)
callback_early_stopping(patience = 20, monitor = "val_loss"),
# 検証データでの損失が改善されない限りモデルを上書きしない設定
# (early_stoppingとセットで使用する)
callback_model_checkpoint(filepath = "bestmodel.keras",
monitor = "val_loss", save_best_only = T),
# 検証データでの損失が改善せず停滞した時(判定:5エポック)
# に局所解を抜け出すため学習率を0.1倍に下げる設定。
callback_reduce_lr_on_plateau(monitor = "val_loss",
factor = 0.1, patience = 5)
)
# フィッティング
fit.dp <- fit(model, # 深層学習モデル
x.tr, # 計画行列
d.tr$y, # 目的変数
verbose = 0, # 1:出力表示(低速),0:出力表示抑制
batch_size = 2^6, # バッチサイズ(要調整)
epochs = 100, # エポック数(早期停止設定時設定不要)
validation_split = 0.2, # 検証用データ割合(訓練には不使用)
callbacks = callbacks) # コールバック設定
plot(fit.dp)

# 予測
yhat <- predict(model, x.te)
## 3/3 - 0s - 27ms/step
# 重回帰モデルとの比較
fit <- lm(FML[[ID.MODEL]], data = d.tr)
yhat.lm <- predict(fit, newdata = d.te)
# 予測結果のグラフ
plot_ly(type = "scatter", mode = "markers") |>
add_trace(x = d$x, y = d$y, mode = "markers", name = "観測値") |>
add_trace(x = d.te$x, y = yhat, mode = "markers", name = "予測値(DNN)") |>
add_trace(x = d.te$x, y = yhat.lm, mode = "lines", name = "予測値(重回帰)") |>
layout(shapes = list(vline))
# 精度評価関数
get.accuracy <- function(yhat, y)
{
data.frame(MBE = mean(yhat - y),
MAE = mean(abs(yhat - y)),
MAPE = mean(abs((yhat - y) / y)) * 100,
RMSE = sqrt(mean((yhat - y)^2))
)
}
get.accuracy(yhat = yhat, y = d.te$y)
# Kerasパッケージでの精度指標
evaluate(model, x.te, d.te$y)
## 3/3 - 0s - 5ms/step - loss: 40941.9922 - mean_absolute_error: 194.8728
## $loss
## [1] 40941.99
##
## $mean_absolute_error
## [1] 194.8728
get.accuracy(yhat = yhat.lm, y = d.te$y)