Feed Forward Neural Network
Dependencies
Mix.install([
{:exla, "~> 0.1.0-dev", github: "elixir-nx/nx", sparse: "exla", override: true},
{:nx, "~> 0.1.0-dev", github: "elixir-nx/nx", sparse: "nx", override: true},
{:axon, "~> 0.1.0-dev", github: "elixir-nx/axon"},
{:scholar, "~> 0.1.0", github: "elixir-nx/scholar", branch: "main"},
{:explorer, "~> 0.1.0-dev", github: "elixir-nx/explorer", branch: "main"},
{:vega_lite, "~> 0.1.3"},
{:kino, "~> 0.5.2"}
])
alias Explorer.DataFrame
alias Explorer.Series
alias VegaLite, as: Vl
Data Set
df = DataFrame.read_csv!("KDD.csv")
{n_rows, n_cols} = DataFrame.shape(df)
split = trunc(n_rows * 0.8)
n_train_rows = split
n_test_rows = n_rows - split
train_df = DataFrame.slice(df, 0, n_train_rows)
test_df = DataFrame.slice(df, split, n_test_rows)
train_x = DataFrame.select(train_df, ["anomalous"], :drop)
train_y = DataFrame.select(train_df, ["anomalous"], :keep)
test_x = DataFrame.select(test_df, ["anomalous"], :drop)
test_y = DataFrame.select(test_df, ["anomalous"], :keep)
{_, n_features} = DataFrame.shape(train_x)
{_, n_labels} = DataFrame.shape(train_y)
:ok
to_tensor = fn df ->
df
|> DataFrame.names()
|> Enum.map(fn name ->
df[name]
|> Series.to_tensor()
|> Nx.reshape({:auto, 1})
end)
|> Nx.concatenate(axis: 1)
end
train_x = to_tensor.(train_x)
train_y = to_tensor.(train_y)
test_x = to_tensor.(test_x)
test_y = to_tensor.(test_y)
:ok
batched_train_x = Nx.to_batched_list(train_x, 32)
batched_train_y = Nx.to_batched_list(train_y, 32)
:ok
Model
model =
Axon.input({nil, n_features})
|> Axon.dense(100, activation: :relu)
|> Axon.dropout(rate: 0.2)
|> Axon.dense(50, activation: :relu)
|> Axon.dropout(rate: 0.2)
|> Axon.dense(1, activation: :sigmoid)
Training
params =
model
|> Axon.Loop.trainer(:binary_cross_entropy, :adam)
|> Axon.Loop.metric(:precision, "Precision")
|> Axon.Loop.run(Stream.zip(batched_train_x, batched_train_y), epochs: 25, compiler: EXLA)
Precision
require Axon
preds = Axon.predict(model, params, test_x, compiler: EXLA)
accuracy = Nx.Defn.jit(&Scholar.Metrics.accuracy/2, [test_y, preds], compiler: EXLA)
precision = Nx.Defn.jit(&Scholar.Metrics.precision/2, [test_y, preds], compiler: EXLA)
IO.inspect(accuracy, label: "accuracy")
IO.inspect(precision, label: "precision")
:ok
Saving
binary = :erlang.term_to_binary(params)
File.write!("FFNN.etf", binary)