Unexpected behavior using BSON: @load in Julia

Viewed 507

So, I am training a neural network model using Flux package in Julia. During training, each iteration that acquires an improvement in the model, the latter is saved in my computer. For this, I use the line:

if acc_te[epoch_i] >= best_acc
     @info(" -> New best accuracy! Saving model out to mymodel.bson")
     @save "mymodel.bson" m
     best_acc = acc_te[epoch_i];
     last_improvement = epoch_i;
end

Which I assume is pretty standard (I extracted it from model-Zoo).

At the end of the training, it is fair to assume that the saved model "mymodel.bson" is the best I got. So far so good!. Now, the problem:

Next morning, I open a terminal and this is what happens (every time is the same):

julia>using Flux;
julia>using BSON: @save
julia>using BSON: @load
julia> @load "mymodel.bson" model
ERROR: KeyError: key :model not found
Stacktrace:
 [1] getindex(::Dict{Symbol,Any}, ::Symbol) at ./dict.jl:477
 [2] top-level scope at /home/gbrunini/.julia/packages/BSON/XAts7/src/BSON.jl:53
julia>
julia> #maybe try another name
julia> @load "mymodel.bson" someothername
ERROR: KeyError: key :someothername not found
Stacktrace:
 [1] getindex(::Dict{Symbol,Any}, ::Symbol) at ./dict.jl:477
 [2] top-level scope at /home/gbrunini/.julia/packages/BSON/XAts7/src/BSON.jl:53
julia> #maybe try another name
.....same error...
julia> #maybe try another name
.... same error....
julia> #maybe try another name
.... same error....
julia> #maybe try another name
julia>@load "mymodel.bson" m     # eureca! this name works!

Why is this happening? Are there some forbidden names? Sometimes it works with other names, but I always have to try at least 5-6 different names until I find someone that works! t's getting annoying

What am I doing wrong?

Thanks in advance and stay safe!

2 Answers

The macros BSON.@save and BSON.@load store the variable with the exact given name. You cannot restore it under a different name.

using BSON
x=5
BSON.@save "mydoc.bson" x

This has stored the value 5 together with the name x.

If you try to recover it using wrong name it will not be found:

julia> BSON.@load "mydoc.bson" y
ERROR: KeyError: key :y not found

Rather than that - you need to recover with the original name - looks how the value gets overwritten:

julia> x=999
999

julia> BSON.@load "mydoc.bson" x

julia> x
5

So what to do when you need more flexibility? Use the BSON.parse function that returns a Dict and you can do with it whatever you need:

julia> BSON.parse("mydoc.bson")
Dict{Symbol,Any} with 1 entry:
  :x => 5

BSON uses Dicts to save and load

BSON does saving and loading based on a top-level Dict, which usually stores the variables by their name as their key (m in your case).

If you do the loading of your .bson you retrieve that dictionary and again instantiate the respective variables giving them their dict key as their name and their dict value as their value.

Taking a look at the README.md of BSON.jl showcases that already.

So in case you would want more flexibility you could directly save a Dict via BSON (check out the mentioned README.md) and do something like:

if acc_te[epoch_i] >= best_acc
     @info(" -> New best accuracy! Saving model out to mymodel.bson")
     bson("mymodel.bson", Dict(:model => m, <...other key-value stuff you want to save...>)
     best_acc = acc_te[epoch_i];
     last_improvement = epoch_i;
end

Bonus / Opinion

BSON offers better interoperability between the languages, but when it comes to saving/loading performance and file size, I found Serialization doing a better job. So just in case you want to check out alternatives depending on your use case.

[edit: fixed typo]

Related