Is it possible that the NODE is not able to learn a simple mathematical function?
I tried one code which uses 4 different time series of a weather forecast which means that the network hast 4 inputs of time and 4 outputs (Temperature, Humidity,Velocity, Pressure) of the meteorological aspects. This code works verry well.
using Random, Dates, Optimization, ComponentArrays, Lux, OptimizationOptimisers, DiffEqFlux,
OrdinaryDiffEq, CSV, DataFrames, Dates, Statistics, Plots, DataDeps
#----------------------------------Datenextraktion--------------------------------------------------
function download_data(data_url = "https://raw.githubusercontent.com/SebastianCallh/neural-ode-weather-forecast/master/data/",
data_local_path = "./delhi")
function load(file_name)
data_dep = DataDep("delhi/train", "", "$data_url/$file_name")
Base.download(data_dep, data_local_path; i_accept_the_terms_of_use = true)
CSV.read(joinpath(data_local_path, file_name), DataFrame)
end
train_df = load("DailyDelhiClimateTrain.csv")
test_df = load("DailyDelhiClimateTest.csv")
return vcat(train_df, test_df)
end
df = download_data()
#----------------------------------Daten ordnen--------------------------------------------------------------
FEATURES = [:meantemp, :humidity, :wind_speed, :meanpressure]
UNITS = ["Celsius", "g/m³ of water", "km/h", "hPa"]
FEATURE_NAMES = ["Mean temperature", "Humidity", "Wind speed", "Mean pressure"]
function plot_data(df)
plots = map(enumerate(zip(FEATURES, FEATURE_NAMES, UNITS))) do (i, (f, n, u))
plot(df[:, :date], df[:, f]; title = n, label = nothing,
ylabel = u, size = (800, 600), color = i)
end
n = length(plots)
plot(plots...; layout = (Int(n / 2), Int(n / 2)))
end
plot_data(df)
#------------------------------Daten standardisieren----------------------------------------
function standardize(x)
μ = mean(x; dims = 2)
σ = std(x; dims = 2)
z = (x .- μ) ./ σ
return z, μ, σ
end
function featurize(raw_df, num_train = 20)
raw_df.year = Float64.(year.(raw_df.date))
raw_df.month = Float64.(month.(raw_df.date))
df = combine(groupby(raw_df, [:year, :month]),
:date => (d -> mean(year.(d)) .+ mean(month.(d)) ./ 12),
:meantemp => mean,
:humidity => mean,
:wind_speed => mean,
:meanpressure => mean;
renamecols = false)
t_and_y(df) = df.date', Matrix(select(df, FEATURES))'
t_train, y_train = t_and_y(df[1:num_train, :])
t_test, y_test = t_and_y(df[(num_train + 1):end, :])
t_train, t_mean, t_scale = standardize(t_train)
y_train, y_mean, y_scale = standardize(y_train)
t_test = (t_test .- t_mean) ./ t_scale
y_test = (y_test .- y_mean) ./ y_scale
return (vec(t_train), y_train,
vec(t_test), y_test,
(t_mean, t_scale),
(y_mean, y_scale))
end
function plot_features(t_train, y_train, t_test, y_test)
plt_split = plot(reshape(t_train, :), y_train';
linewidth = 3, colors = 1:4,
xlabel = "Normalized time",
ylabel = "Normalized values",
label = nothing,
title = "Features")
plot!(plt_split, reshape(t_test, :), y_test';
linewidth = 3, linestyle = :dash,
color = [1 2 3 4], label = nothing)
plot!(plt_split, [0], [0]; linewidth = 0,
label = "Train", color = 1)
plot!(plt_split, [0], [0]; linewidth = 0,
linestyle = :dash, label = "Test",
color = 1,
ylims = (-5, 5))
end
t_train, y_train, t_test, y_test, (t_mean, t_scale), (y_mean, y_scale) = featurize(df)
plot_features(t_train, y_train, t_test, y_test)
#-------------------------------Training des NN------------------------------------------
function neural_ode(t, data_dim)
f = Lux.Chain(Lux.Dense(data_dim => 64, swish), Lux.Dense(64 => 32, swish), Lux.Dense(32 => data_dim))
node = NeuralODE(f, extrema(t), Tsit5(); saveat = t,
abstol = 1e-9, reltol = 1e-9)
rng = Random.default_rng()
p, state = Lux.setup(rng, f)
return node, ComponentArray(p), state
end
function train_one_round(node, p, state, y, opt, maxiters, rng, y0 = y[:, 1]; kwargs...)
predict(p) = Array(node(y0, p, state)[1])
loss(p) = sum(abs2, predict(p) .- y)
adtype = Optimization.AutoZygote()
optf = OptimizationFunction((p, _) -> loss(p), adtype)
optprob = OptimizationProblem(optf, p)
res = solve(optprob, opt; maxiters = maxiters, kwargs...)
res.minimizer, state
end
function train(t, y, obs_grid, maxiters, lr, rng, p = nothing, state = nothing; kwargs...)
log_results(ps, losses) = (p, loss) -> begin
push!(ps, copy(p))
push!(losses, loss)
false
end
ps, losses = ComponentArray[], Float32[]
for k in obs_grid
node, p_new, state_new = neural_ode(t, size(y, 1))
p === nothing && (p = p_new) #Löscht Eintrag von p, nimmt jedoch p für train_one_round
state === nothing && (state = state_new)
p, state = train_one_round(node, p, state, y, ADAM(lr), maxiters, rng;
callback = log_results(ps, losses), kwargs...)
end
ps, state, losses
end
rng = MersenneTwister(123)
obs_grid = 4:4:length(t_train) # we train on an increasing amount of the first k obs
maxiters = 150
lr = 5e-3
ps, state, losses = train(t_train, y_train, obs_grid, maxiters, lr, rng; progress = true)
#------------------------------Prediction Part-------------------------------------------
predict(y0, t, p, state) = begin
node, _, _ = neural_ode(t, length(y0))
Array(node(y0, p, state)[1])
end
node, _, _ = neural_ode(t, length(y_train[:, 1]))
y_pred = Array(node(y_train[:, 1], ps[end], state)[1])
t_grid = collect(range(minimum(t_train), maximum(t_test); length = 500))
y_pred = predict(y_train[:, 1], t_grid, ps[end], state)
plot(t_grid, y_pred[1,:], label = "Prediction")
plot!(t_train, y_train[1,:], label = "Data")

Then I reduced the Inputs and Outputs to 1 (Only Temperature) and trained again. Now it does’nt work anymore.
using Random, Dates, Optimization, ComponentArrays, Lux, OptimizationOptimisers, DiffEqFlux,
OrdinaryDiffEq, CSV, DataFrames, Dates, Statistics, Plots, DataDeps
#----------------------------------Datenextraktion--------------------------------------------------
function download_data(data_url = "https://raw.githubusercontent.com/SebastianCallh/neural-ode-weather-forecast/master/data/",
data_local_path = "./delhi")
function load(file_name)
data_dep = DataDep("delhi/train", "", "$data_url/$file_name")
Base.download(data_dep, data_local_path; i_accept_the_terms_of_use = true)
CSV.read(joinpath(data_local_path, file_name), DataFrame)
end
train_df = load("DailyDelhiClimateTrain.csv")
test_df = load("DailyDelhiClimateTest.csv")
return vcat(train_df, test_df)
end
df = download_data()
#----------------------------------Daten ordnen--------------------------------------------------------------
FEATURES = [:meantemp, :humidity, :wind_speed, :meanpressure]
UNITS = ["Celsius", "g/m³ of water", "km/h", "hPa"]
FEATURE_NAMES = ["Mean temperature", "Humidity", "Wind speed", "Mean pressure"]
function plot_data(df)
plots = map(enumerate(zip(FEATURES, FEATURE_NAMES, UNITS))) do (i, (f, n, u))
plot(df[:, :date], df[:, f]; title = n, label = nothing,
ylabel = u, size = (800, 600), color = i)
end
n = length(plots)
plot(plots...; layout = (Int(n / 2), Int(n / 2)))
end
plot_data(df)
#------------------------------Daten standardisieren----------------------------------------
function standardize(x)
μ = mean(x; dims = 2)
σ = std(x; dims = 2)
z = (x .- μ) ./ σ
return z, μ, σ
end
function featurize(raw_df, num_train = 20)
raw_df.year = Float64.(year.(raw_df.date))
raw_df.month = Float64.(month.(raw_df.date))
df = combine(groupby(raw_df, [:year, :month]),
:date => (d -> mean(year.(d)) .+ mean(month.(d)) ./ 12),
:meantemp => mean,
:humidity => mean,
:wind_speed => mean,
:meanpressure => mean;
renamecols = false)
t_and_y(df) = df.date', Matrix(select(df, FEATURES))'
t_train, y_train = t_and_y(df[1:num_train, :])
t_test, y_test = t_and_y(df[(num_train + 1):end, :])
t_train, t_mean, t_scale = standardize(t_train)
y_train, y_mean, y_scale = standardize(y_train)
t_test = (t_test .- t_mean) ./ t_scale
y_test = (y_test .- y_mean) ./ y_scale
return (vec(t_train), y_train,
vec(t_test), y_test,
(t_mean, t_scale),
(y_mean, y_scale))
end
function plot_features(t_train, y_train, t_test, y_test)
plt_split = plot(reshape(t_train, :), y_train';
linewidth = 3, colors = 1:4,
xlabel = "Normalized time",
ylabel = "Normalized values",
label = nothing,
title = "Features")
plot!(plt_split, reshape(t_test, :), y_test';
linewidth = 3, linestyle = :dash,
color = [1 2 3 4], label = nothing)
plot!(plt_split, [0], [0]; linewidth = 0,
label = "Train", color = 1)
plot!(plt_split, [0], [0]; linewidth = 0,
linestyle = :dash, label = "Test",
color = 1,
ylims = (-5, 5))
end
t_train, y_train, t_test, y_test, (t_mean, t_scale), (y_mean, y_scale) = featurize(df)
plot_features(t_train, y_train, t_test, y_test)
plot(t_train, y_train[1,:])
#-------------------------------Training des NN------------------------------------------
function neural_ode(t, data_dim)
f = Lux.Chain(Lux.Dense(data_dim => 64, swish), Lux.Dense(64 => 32, swish), Lux.Dense(32 => data_dim))
node = NeuralODE(f, extrema(t), Tsit5(); saveat = t,
abstol = 1e-9, reltol = 1e-9)
rng = Random.default_rng()
p, state = Lux.setup(rng, f)
return node, ComponentArray(p), state
end
function train_one_round(node, p, state, y, opt, maxiters, rng, y0 = [y[1, 1]]; kwargs...)
predict(p) = Array(node(y0, p, state)[1])
loss(p) = sum(abs2, predict(p) .- y)
adtype = Optimization.AutoZygote()
optf = OptimizationFunction((p, _) -> loss(p), adtype)
optprob = OptimizationProblem(optf, p)
res = solve(optprob, opt; maxiters = maxiters, kwargs...)
res.minimizer, state
end
function train(t, y, obs_grid, maxiters, lr, rng, p = nothing, state = nothing; kwargs...)
log_results(ps, losses) = (p, loss) -> begin
push!(ps, copy(p))
push!(losses, loss)
false
end
ps, losses = ComponentArray[], Float32[]
for k in obs_grid
node, p_new, state_new = neural_ode(t, size(y[1,1], 1))
p === nothing && (p = p_new) #Löscht Eintrag von p, nimmt jedoch p für train_one_round
state === nothing && (state = state_new)
p, state = train_one_round(node, p, state, y, ADAM(lr), maxiters, rng;
callback = log_results(ps, losses), kwargs...)
end
ps, state, losses
end
rng = MersenneTwister(123)
obs_grid = 4:4:length(t_train) # we train on an increasing amount of the first k obs
maxiters = 150
lr = 5e-3
ps, state, losses = train(t_train, y_train[1,:], obs_grid, maxiters, lr, rng; progress = true)
#--------------------------------Prediction Part------------------------------------------
predict(y0, t, p, state) = begin
node, _, _ = neural_ode(t, length(y0))
Array(node(y0, p, state)[1])
end
t_grid = collect(range(minimum(t_train), maximum(t_train); length = 500))
y_pred = predict([y_train[1, 1]], t_grid, ps[end], state)
plot(t_grid, y_pred[1,:], label = "Prediction")
plot!(t_train, y_train[1,:], label = "Data")

Does the network need the connections between the 4 meteorological aspects in order to learn the course of a single aspect? I know this is a difficult question but maybe someone knows an answer.