Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

learn nx on mac

learn_nx_on_mac.livemd

learn nx on mac

Mix.install([
  {:nx, "~> 0.10"},
  {:exla, "~> 0.10"},
  {:benchee, "1.4.0"},

  {:kino, "~> 0.16.0"},
  {:stb_image, "~> 0.6.10"},
  {:vega_lite, "~> 0.1.11"},
  {:kino_vega_lite, "~> 0.1.13"},
  {:explorer, "~> 0.10.0"},
  {:axon, "~> 0.7.0"}
],
config: [
    nx: [
      default_defn_options: [compiler: EXLA],
      some_other_key: "...",
    ]
  ]

)

Application.get_all_env :nx

Section

26 lug 2025

Nx.tensor([1, 2, 3])
defmodule F do
  import Nx.Defn
  
  defn(softmax(n), do: Nx.exp(n) / Nx.sum(Nx.exp(n)))
end
key = Nx.Random.key(42)
{tensor, _key} = Nx.Random.uniform(key, shape: {1_000_000})
Benchee.run(
  %{
    "JIT exla"  => fn ->
      apply(EXLA.jit(&F.softmax/1), [tensor])
    end,
    "Ex exla" => fn ->
      F.softmax(tensor)
    end
  },
  time: 10,
  #save: %{path: "./benchee/nx_no_exla.benchee", tag: "v1.0"}
  load: "./benchee/nx_no_exla.benchee"
)

Ho trovato che consigliavano di mettere: default_defn_options: [compiler: EXLA]

Risultati

Name                 ips        average  deviation         median         99th %
Ex exla           1.36 K        0.74 ms    ±42.02%        0.59 ms        1.82 ms
JIT exla          1.24 K        0.81 ms    ±40.07%        0.62 ms        1.87 ms
JIT (v1.0)        0.80 K        1.24 ms    ±38.58%        1.01 ms        3.05 ms
Ex (v1.0)      0.00301 K      332.25 ms     ±0.49%      331.85 ms      336.86 ms

Comparison: 
Ex exla           1.36 K
JIT exla          1.24 K - 1.09x slower +0.0697 ms
JIT (v1.0)        0.80 K - 1.68x slower +0.50 ms
Ex (v1.0)      0.00301 K - 450.22x slower +331.52 ms

Praticamente le versione Ex che prima era 250x più lenta della JIT, è ora 10% più veloce!

Fiori

Usa Axon. Ho dovuto fare alcune piccole modifiche rispetto al libro:

  • principalmente trasformare le serie come :f32 perchè fallisce qlco se sono :f64. L’errore era cmq molto chiaro.
  • Inizializzare lo stato del modello con un oggetto
require Explorer.DataFrame, as: DF
iris = Explorer.Datasets.iris()
# normalize
feature_cols = ~w(sepal_length sepal_width petal_length petal_width)
normalized_iris = DF.mutate(
  iris,
  for col <- across(^feature_cols) do
    {col.name, (col-mean(col)) / standard_deviation(col) }
  end
)

normalized_iris = DF.mutate( normalized_iris,
[species: Explorer.Series.cast(species, :category)])

# devo convertirli a :f32 se no fallisce il modello.
normalized_iris = DF.mutate(
  normalized_iris,
  for col <- across(^feature_cols) do
    {col.name, Explorer.Series.cast(col, :f32) }
  end
)
shuffled_norm_iris = DF.shuffle(normalized_iris)
train_df = DF.slice(shuffled_norm_iris, 0..119)
test_df = DF.slice(shuffled_norm_iris, 120..149)

x_train = Nx.stack(train_df[feature_cols], axis: -1)
y_train = train_df["species"]
  # trasforma in 0, 1, 2
|> Nx.stack(axis: -1)
  # one-hot encoding
|>Nx.equal(Nx.iota({1, 3}, axis: -1))


x_test = Nx.stack(test_df[feature_cols], axis: -1)
y_test = test_df["species"]
|> Nx.stack(axis: -1)
|>Nx.equal(Nx.iota({1, 3}, axis: -1))



model = Axon.input("iris_features", shape: {nil, 4})
|> Axon.dense(3, activation: :softmax)
Axon.Display.as_graph(model, Nx.template({1, 4}, :f32))
data_stream = Stream.repeatedly(fn ->
  {x_train, y_train}
end)


trained_model_state = model
|> Axon.Loop.trainer(:categorical_cross_entropy, :sgd)
|> Axon.Loop.metric(:accuracy)
|> Axon.Loop.run(data_stream, Axon.ModelState.empty(), iterations: 500, epochs: 20)

# senza CUDA: 30 sec
# con CUDA: 0.5 sec


# più epochs ho, più impara : con 200 epochs ho una loss di 0.08

Più epochs ho, più impara esattamante i dati:

Epoch:  10, Batch: 450, accuracy: 0.9416718 loss: 0.2788212
Epoch: 100, Batch: 450, accuracy: 0.9833357 loss: 0.1109093  **
Epoch: 200, Batch: 450, accuracy: 0.9833357 loss: 0.0850167
Epoch: 300, Batch: 450, accuracy: 0.9833357 loss: 0.0737911
Epoch: 399, Batch: 450, accuracy: 0.9833357 loss: 0.0673194

Più è grosso il batch, pure:

Epoch:  10, Batch: 4950, accuracy: 0.9833598 loss: 0.1081216  **
Epoch: 100, Batch: 4950, accuracy: 0.9833598 loss: 0.0526718
Epoch: 199, Batch: 4950, accuracy: 0.9833598 loss: 0.0464315

Al batch 10 con 5000 ha valori tipo il batch 100 con 500.

#Valutazione modello

test_data= [{x_test, y_test}]

model
|> Axon.Loop.evaluator()
|> Axon.Loop.metric(:accuracy)
|> Axon.Loop.run( test_data, trained_model_state)