Skip to content

Commit 1219f3d

Browse files
Dobiasdclaude
andcommitted
Add regression test for flat input_layers/output_layers format
Newer Keras versions serialize a single input/output as a flat triple ["layer", node_idx, tensor_idx] instead of a list containing one such triple. The existing readme_example_main test exercises a single-input model, but only catches this when CI runs against a Keras version that already emits the flat form. Post-process the readme example JSON into flat form and load it from a new test so this code path is covered on any Keras version. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9390c3a commit 1219f3d

3 files changed

Lines changed: 62 additions & 0 deletions

File tree

test/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ add_custom_command ( OUTPUT readme_example_model.json
5858
COMMAND bash -c "${Python3_EXECUTABLE} ${FDEEP_TOP_DIR}/keras_export/convert_model.py readme_example_model.keras readme_example_model.json"
5959
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/)
6060

61+
add_custom_command ( OUTPUT readme_example_flat_format_model.json
62+
DEPENDS readme_example_model.json
63+
COMMAND bash -c "${Python3_EXECUTABLE} ${FDEEP_TOP_DIR}/test/readme_example_flat_format_generate.py readme_example_model.json readme_example_flat_format_model.json"
64+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/)
65+
6166
hunter_add_package(doctest)
6267
find_package(doctest CONFIG REQUIRED)
6368

@@ -75,6 +80,7 @@ _add_test(test_model_variable_test test_model_variable.json)
7580
_add_test(test_model_autoencoder_test test_model_autoencoder.json)
7681
_add_test(test_model_sequential_test test_model_sequential.json)
7782
_add_test(readme_example_main readme_example_model.json)
83+
_add_test(readme_example_flat_format_test readme_example_flat_format_model.json)
7884

7985
add_custom_target(unittest
8086
COMMAND test_model_exhaustive_test
@@ -83,6 +89,7 @@ add_custom_target(unittest
8389
COMMAND test_model_autoencoder_test
8490
COMMAND test_model_sequential_test
8591
COMMAND readme_example_main
92+
COMMAND readme_example_flat_format_test
8693

8794
COMMENT "Running unittests\n\n"
8895
VERBATIM
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python3
2+
"""Force the single-input fdeep model JSON into Keras' newer flat
3+
input_layers/output_layers format so we can regression-test loading it
4+
on any Keras version. See https://github.com/Dobiasd/frugally-deep/issues/461.
5+
"""
6+
7+
import json
8+
import sys
9+
10+
11+
def flatten(node_connections):
12+
if (
13+
isinstance(node_connections, list)
14+
and len(node_connections) == 1
15+
and isinstance(node_connections[0], list)
16+
):
17+
return node_connections[0]
18+
return node_connections
19+
20+
21+
def main(src, dst):
22+
with open(src, 'r') as f:
23+
data = json.load(f)
24+
config = data['architecture']['config']
25+
config['input_layers'] = flatten(config['input_layers'])
26+
config['output_layers'] = flatten(config['output_layers'])
27+
with open(dst, 'w') as f:
28+
json.dump(data, f)
29+
30+
31+
if __name__ == '__main__':
32+
main(sys.argv[1], sys.argv[2])
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2016, Tobias Hermann.
2+
// https://github.com/Dobiasd/frugally-deep
3+
// Distributed under the MIT License.
4+
// (See accompanying LICENSE file or at
5+
// https://opensource.org/licenses/MIT)
6+
7+
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
8+
#include "doctest/doctest.h"
9+
#include <fdeep/fdeep.hpp>
10+
11+
// Regression test for https://github.com/Dobiasd/frugally-deep/issues/461.
12+
// Newer Keras versions serialize a single input/output as a flat triple
13+
// ["layer", node_idx, tensor_idx] instead of a list containing one such
14+
// triple. The test JSON is post-processed into that flat form so this
15+
// path is exercised regardless of the Keras version used by CI.
16+
TEST_CASE("readme_example_flat_format_test, main")
17+
{
18+
const auto model = fdeep::load_model("../readme_example_flat_format_model.json");
19+
const auto result = model.predict(
20+
{ fdeep::tensor(fdeep::tensor_shape(static_cast<std::size_t>(4)),
21+
fdeep::float_vec { 1, 2, 3, 4 }) });
22+
std::cout << fdeep::show_tensors(result) << std::endl;
23+
}

0 commit comments

Comments
 (0)