diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 67be167..07a2eec 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -18,21 +18,23 @@ on: - 'Project.toml' jobs: test: - name: Julia ${{ matrix.version }} - Legolas ${{ matrix.legolas-version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} - runs-on: ${{ matrix.os }} + name: Julia ${{ matrix.version }} - Legolas ${{ matrix.legolas-version }} - Flux ${{ matrix.flux-version }} - ${{ github.event_name }} + runs-on: ubuntu-latest strategy: fail-fast: false matrix: legolas-version: - '0.2' - '0.3' + flux-version: + - '0.12' + - '0.13' version: - - '1.5' # earliest supported version - '1' # current release - os: - - ubuntu-latest - arch: - - x64 + include: + - version: '1.5' # earliest supported version + legolas-version: '0.2' + flux-version: '0.12' steps: - uses: actions/checkout@v2 with: @@ -40,12 +42,13 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - name: "Install Legolas version" + arch: x64 + - name: "Install Legolas and Flux" shell: julia --color=yes --project=. {0} run: | using Pkg - Pkg.add(Pkg.PackageSpec(; name="Legolas", version="${{ matrix.legolas-version }}")) + Pkg.add([Pkg.PackageSpec(; name="Legolas", version="${{ matrix.legolas-version }}"), + Pkg.PackageSpec(; name="Flux", version="${{ matrix.flux-version }}")]) - uses: actions/cache@v2 with: path: ~/.julia/artifacts diff --git a/.gitignore b/.gitignore index d02f795..c8cc4d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ Manifest.toml -test/my_model.model.arrow +my_model.model.arrow diff --git a/Project.toml b/Project.toml index 8e04117..c4ac6ca 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.5" +version = "0.1.6" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -11,7 +11,7 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" [compat] Arrow = "1, 2" -Flux = "0.12" +Flux = "0.12, 0.13" Functors = "0.2.6" Legolas = "0.1, 0.2, 0.3" Tables = "1" diff --git a/examples/digits.jl b/examples/digits.jl index 611813f..0bbc08d 100644 --- a/examples/digits.jl +++ b/examples/digits.jl @@ -113,7 +113,7 @@ 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, 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 diff --git a/test/runtests.jl b/test/runtests.jl index 67995c5..b73db2d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,7 @@ using LegolasFlux using Test using Flux, LegolasFlux using LegolasFlux: Weights, FlatArray, ModelRow +using Flux: params using Arrow using Random using StableRNGs @@ -15,34 +16,32 @@ function test_weights() return [reshape(Float32.(1:prod(s)), s) for s in shapes] end -# This simple model should work with both Flux's `params/loadparams!` and -# our `weights/load_weights!`. The only difference is in layers with `!isempty(other_weights(layer))`. -@testset "using ($get_weights, $load_weights)" for (get_weights, load_weights) in [(fetch_weights, load_weights!, params, Flux.loadparams!)] +@testset "Roundtripping simple model" begin + try + # quick test with `missing` weights. + model_row = ModelRow(; weights=missing) + write_model_row("my_model.model.arrow", model_row) + rt = read_model_row("my_model.model.arrow") + @test isequal(model_row, rt) - # quick test with `missing` weights. - model_row = ModelRow(; weights=missing) - write_model_row("my_model.model.arrow", model_row) - rt = read_model_row("my_model.model.arrow") - @test isequal(model_row, rt) - - my_model = make_my_model() - load_weights(my_model, test_weights()) - - model_row = ModelRow(; weights=collect(get_weights(my_model))) - write_model_row("my_model.model.arrow", model_row) + my_model = make_my_model() + load_weights!(my_model, test_weights()) + model_row = ModelRow(; weights=collect(fetch_weights(my_model))) + write_model_row("my_model.model.arrow", model_row) - fresh_model = make_my_model() + fresh_model = make_my_model() - model_row = read_model_row("my_model.model.arrow") - weights = collect(model_row.weights) - load_weights(fresh_model, weights) + model_row = read_model_row("my_model.model.arrow") + weights = collect(model_row.weights) + load_weights!(fresh_model, weights) - @test collect(params(fresh_model)) == weights == test_weights() + @test collect(params(fresh_model)) == weights == test_weights() - @test all(x -> eltype(x) == Float32, weights) - - rm("my_model.model.arrow") + @test all(x -> eltype(x) == Float32, weights) + finally + rm("my_model.model.arrow") + end end struct MyArrayModel @@ -51,16 +50,20 @@ end Flux.@functor MyArrayModel @testset "Non-numeric arrays ignored" begin - m = MyArrayModel([Dense(1, 10), Dense(10, 10), Dense(10, 1)]) - weights = fetch_weights(m) - @test length(weights) == 6 - - model_row = ModelRow(; weights=collect(weights)) - write_model_row("my_model.model.arrow", model_row) - - new_model_row = read_model_row("my_model.model.arrow") - new_weights = collect(new_model_row.weights) - @test new_weights == weights + try + m = MyArrayModel([Dense(1, 10), Dense(10, 10), Dense(10, 1)]) + weights = fetch_weights(m) + @test length(weights) == 6 + + model_row = ModelRow(; weights=collect(weights)) + write_model_row("my_model.model.arrow", model_row) + + new_model_row = read_model_row("my_model.model.arrow") + new_weights = collect(new_model_row.weights) + @test new_weights == weights + finally + rm("my_model.model.arrow") + end end @testset "Errors" begin @@ -97,6 +100,7 @@ end end testmode!(model) w = fetch_weights(model) + p = collect(params(model)) output = model(x)