From e3fd92ec4f4ebfafe13e4c94495f9d555e33b2f8 Mon Sep 17 00:00:00 2001 From: Eric Hanson <5846501+ericphanson@users.noreply.github.com> Date: Fri, 18 Nov 2022 21:27:06 +0100 Subject: [PATCH] Add serialization reference test & bump Legolas compat (#22) * add serialization test, bump compat * format example * Update examples/digits.jl * Update examples/digits.jl Co-authored-by: Dave Kleinschmidt * Bump to Legolas v0.4 Co-authored-by: Dave Kleinschmidt --- .JuliaFormatter.toml | 1 + .github/workflows/CI.yml | 13 +++-------- Project.toml | 6 ++--- examples/digits.jl | 39 +++++++++++++++++++++++-------- examples/test.digits-model.arrow | Bin 0 -> 33738 bytes 5 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 .JuliaFormatter.toml create mode 100644 examples/test.digits-model.arrow diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..857c3ae --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1 @@ +style = "yas" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 07a2eec..f655384 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -23,18 +23,12 @@ jobs: strategy: fail-fast: false matrix: - legolas-version: - - '0.2' - - '0.3' flux-version: - '0.12' - '0.13' version: - '1' # current release - include: - - version: '1.5' # earliest supported version - legolas-version: '0.2' - flux-version: '0.12' + - '1.6' # earliest supported version steps: - uses: actions/checkout@v2 with: @@ -43,12 +37,11 @@ jobs: with: version: ${{ matrix.version }} arch: x64 - - name: "Install Legolas and Flux" + - name: "Install Flux" shell: julia --color=yes --project=. {0} run: | using Pkg - Pkg.add([Pkg.PackageSpec(; name="Legolas", version="${{ matrix.legolas-version }}"), - Pkg.PackageSpec(; name="Flux", version="${{ matrix.flux-version }}")]) + Pkg.add([Pkg.PackageSpec(; name="Flux", version="${{ matrix.flux-version }}")]) - uses: actions/cache@v2 with: path: ~/.julia/artifacts diff --git a/Project.toml b/Project.toml index 7291ace..ee58684 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LegolasFlux" uuid = "eb5f792d-d1b1-4535-bae3-d5649ec7daa4" authors = ["Beacon Biosignals, Inc."] -version = "0.1.7" +version = "0.1.8" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -13,9 +13,9 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Arrow = "1, 2" Flux = "0.12, 0.13" Functors = "0.2.6, 0.3" -Legolas = "0.1, 0.2, 0.3" +Legolas = "0.4" Tables = "1" -julia = "1.5" +julia = "1.6" [extras] Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" diff --git a/examples/digits.jl b/examples/digits.jl index 0bbc08d..5387a81 100644 --- a/examples/digits.jl +++ b/examples/digits.jl @@ -8,13 +8,13 @@ using StableRNGs using Flux: onehotbatch, onecold, crossentropy, throttle using Base.Iterators: repeated, partition using Legolas, LegolasFlux +using Tables # This should store all the information needed # to construct the model. -Base.@kwdef struct DigitsConfig - seed::Int = 5 - dropout_rate::Float32 = 0f1 -end +const DigitsConfig = Legolas.@row("digits-config@1", + seed::Int = 5, + dropout_rate::Float32 = 0.0f1,) # Here's our model object itself, just a `DigitsConfig` and # a `chain`. We keep the config around so it's easy to save out @@ -57,9 +57,9 @@ end # Here, we define a schema extension of the `legolas-flux.model` schema. # We add our `DigitsConfig` object, as well as the epoch and accuracy. const DigitsRow = Legolas.@row("digits.model@1" > "legolas-flux.model@1", - config::DigitsConfig, - epoch::Union{Missing, Int}, - accuracy::Union{Missing, Float32}) + config::DigitsConfig = DigitsConfig(config), + epoch::Union{Missing,Int}, + accuracy::Union{Missing,Float32}) # Construct a `DigitsRow` from a model by collecting the weights. # This can then be saved with e.g. `LegolasFlux.write_model_row`. @@ -76,7 +76,6 @@ function DigitsModel(row) return m end - # Increase to get more training/test data N_train = 1_000 N_test = 50 @@ -109,11 +108,12 @@ function accuracy(m, x, y) return val end -function train_model!(m; N = N_train) +function train_model!(m; N=N_train) loss = (x, y) -> crossentropy(m(x), y) opt = ADAM() evalcb = throttle(() -> @show(accuracy(m, tX, tY)), 5) - Flux.@epochs 1 Flux.train!(loss, Flux.params(m), Iterators.take(train, N), opt; cb=evalcb) + Flux.@epochs 1 Flux.train!(loss, Flux.params(m), Iterators.take(train, N), opt; + cb=evalcb) return accuracy(m, tX, tY) end @@ -138,3 +138,22 @@ testmode!(m2) output2 = m2(input) @test output ≈ output2 + +path = joinpath(pkgdir(LegolasFlux), "examples", "test.digits-model.arrow") +# The saved weights in this repo were generated by running the command: +# Legolas.write(path, [row], Legolas.Schema("digits.model@1")) +# We don't run this every time, since we want to test that we can continue to deserialize previously saved out weights. +table = Legolas.read(path) +roundtripped = DigitsRow(only(Tables.rows(table))) +@test roundtripped isa DigitsRow +@test roundtripped.config isa DigitsConfig + +roundtripped_model = DigitsModel(roundtripped) +output3 = roundtripped_model(input) +@test output3 isa Matrix{Float32} + +# Here, we've hardcoded the results at the time of serialization. +# This lets us check that the model we've saved gives the same answers now as it did then. +# It is OK to update this test w/ a new reference if the answers are *supposed* to change for some reason. Just make sure that is the case. +@test output3 ≈ + Float32[0.09915658; 0.100575574; 0.101189725; 0.10078623; 0.09939819; 0.099650174; 0.1013182; 0.09952383; 0.0991391; 0.09926238;;] diff --git a/examples/test.digits-model.arrow b/examples/test.digits-model.arrow new file mode 100644 index 0000000000000000000000000000000000000000..43cc445e6faf7c148c0b63f285be6dbd7d0762b1 GIT binary patch literal 33738 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 r|2H>&uEUZo8!|H{rmhi*nf99KibK}qQ