りんけーじ - blog

2025/04/27 11:04 : trustmarkで遊ぶ

ステガノグラフィであるTrustMarkをFreeBSD上で遊んだ記録。

FreeBSDでのビルドに興味のない人は、最後へどうぞ。

大雑把な手順:

はじめる前に

以下の手順では、インストールされるonnxとonnxruntimeを変更してしまう。つまり、これらに依存したほかのアプリがあれば、挙動に影響を与える可能性がある。

どちらも大きな変更となるので、なにをしているのか理解したうえで、壊れても泣かないような実験用の環境で実施してほしい。

また、以下は「とにかく動けばいい」という方針で編集している点にも留意してほしい。私自身はports systemやRustに慣れているわけではないし、特に調べているわけでもない。

依存パッケージのインストール

「おれはpkgなんて使わないぜ!」派の人はスルーしてOK。portsが全部面倒を見てくれる。

私は面倒なので pkg install onnx onnxruntime ninja した。

misc/onnxのビルド

pkgでインストールしたonnxには問題がある。

[package] onnxruntime/1.14.1: "Schema error" when creating Session (conan-io / conan-center-index)

ちょっと手直ししてあげないと、trustmarkを使ったときに以下のようなエラーを大量に吐いて死んでしまう。

Schema error: Trying to register schema with name ...

Issueにも書かれている通り、ONNX_DISABLE_STATIC_REGISTRATIONを指定します。これは/usr/ports/misc/onnx/Makefileに書けばOK。

diff --git a/misc/onnx/Makefile b/misc/onnx/Makefile
index 3054dd2df..936d5b1b1 100644
--- a/misc/onnx/Makefile
+++ b/misc/onnx/Makefile
@@ -20,7 +20,7 @@ USES=         cmake:testing compiler:c++17-lang python:build
 
 USE_GITHUB=    yes
 
-CMAKE_ON=      BUILD_SHARED_LIBS
+CMAKE_ON=      BUILD_SHARED_LIBS ONNX_DISABLE_STATIC_REGISTRATION
 CMAKE_OFF=     BUILD_ONNX_PYTHON
 CMAKE_TESTING_ON=      ONNX_BUILD_TESTS
 CMAKE_TESTING_TARGET=

編集したら、make deinstall ; make & make installでインストールしましょう。

misc/onnxruntimeのビルド

次はonnxruntimeをビルドします。こいつも問題があるので手直しします。具体的にはpkg-configではlibonnxruntimeがあるはずなのに、実際には存在しない。(インストールもビルドもされない)

# pkg install -y onnxruntime
(...snip...)
# pkg-config --libs libonnxruntime
-L/usr/local/lib -lonnxruntime
# ls /usr/local/lib/libonnxruntime.*
ls: /usr/local/lib/libonnxruntime.*: No such file or directory

[Build] .pc file asks for -lonnxruntime but onnxruntime.a isn't installed (microsoft / onnxruntime)

これを直すにはonnxruntime_BUILD_SHARED_LIB=ONを指定する。onnxと同様にMakefileを編集するが、成果物も変わるのでpkg-plistも調整が必要。バカ長いけどdiffで載せちゃう。

diff --git a/misc/onnxruntime/Makefile b/misc/onnxruntime/Makefile
index a9f471625..b7df920a5 100644
--- a/misc/onnxruntime/Makefile
+++ b/misc/onnxruntime/Makefile
@@ -29,7 +29,7 @@ GH_TUPLE=     emscripten-core:emsdk:0742117:emsdk/cmake/external/emsdk \
 CMAKE_SOURCE_PATH=     ${WRKSRC}/cmake
 CMAKE_OFF=     FETCHCONTENT_FULLY_DISCONNECTED \
                onnxruntime_BUILD_UNIT_TESTS
-CMAKE_ARGS=    -Donnx_SOURCE_DIR=${WRKSRC}/cmake/external/onnx
+CMAKE_ARGS=    -Donnx_SOURCE_DIR=${WRKSRC}/cmake/external/onnx -Donnxruntime_BUILD_SHARED_LIB=ON
 CMAKE_TESTING_ON=      onnxruntime_BUILD_UNIT_TESTS
 
 CXXFLAGS+=     -Wno-array-bounds # workaround for https://github.com/microsoft/onnxruntime/issues/23410
diff --git a/misc/onnxruntime/pkg-plist b/misc/onnxruntime/pkg-plist
index 0d596eed3..cb78cce1f 100644
--- a/misc/onnxruntime/pkg-plist
+++ b/misc/onnxruntime/pkg-plist
@@ -1,102 +1,16 @@
-include/onnxruntime/core/common/basic_types.h
-include/onnxruntime/core/common/code_location.h
-include/onnxruntime/core/common/common.h
-include/onnxruntime/core/common/const_pointer_container.h
-include/onnxruntime/core/common/denormal.h
-include/onnxruntime/core/common/eigen_common_wrapper.h
-include/onnxruntime/core/common/exceptions.h
-include/onnxruntime/core/common/gpu_profiler_common.h
-include/onnxruntime/core/common/hash_combine.h
-include/onnxruntime/core/common/inlined_containers.h
-include/onnxruntime/core/common/inlined_containers_fwd.h
-include/onnxruntime/core/common/logging/capture.h
-include/onnxruntime/core/common/logging/isink.h
-include/onnxruntime/core/common/logging/logging.h
-include/onnxruntime/core/common/logging/macros.h
-include/onnxruntime/core/common/logging/severity.h
-include/onnxruntime/core/common/logging/sink_types.h
-include/onnxruntime/core/common/make_string.h
-include/onnxruntime/core/common/narrow.h
-include/onnxruntime/core/common/optional.h
-include/onnxruntime/core/common/parse_string.h
-include/onnxruntime/core/common/profiler_common.h
-include/onnxruntime/core/common/span_utils.h
-include/onnxruntime/core/common/spin_pause.h
-include/onnxruntime/core/common/status.h
-include/onnxruntime/core/common/string_helper.h
-include/onnxruntime/core/framework/alloc_kind.h
-include/onnxruntime/core/framework/allocator.h
-include/onnxruntime/core/framework/buffer_deleter.h
-include/onnxruntime/core/framework/customregistry.h
-include/onnxruntime/core/framework/data_types.h
-include/onnxruntime/core/framework/data_types_internal.h
-include/onnxruntime/core/framework/endian.h
-include/onnxruntime/core/framework/execution_provider.h
-include/onnxruntime/core/framework/float16.h
-include/onnxruntime/core/framework/float8.h
-include/onnxruntime/core/framework/framework_common.h
-include/onnxruntime/core/framework/framework_provider_common.h
-include/onnxruntime/core/framework/func_api.h
-include/onnxruntime/core/framework/int4.h
-include/onnxruntime/core/framework/kernel_def_builder.h
-include/onnxruntime/core/framework/kernel_registry.h
-include/onnxruntime/core/framework/op_kernel.h
-include/onnxruntime/core/framework/op_kernel_context.h
-include/onnxruntime/core/framework/op_kernel_info.h
-include/onnxruntime/core/framework/op_node_proto_helper.h
-include/onnxruntime/core/framework/ort_value.h
-include/onnxruntime/core/framework/ortdevice.h
-include/onnxruntime/core/framework/ortmemoryinfo.h
-include/onnxruntime/core/framework/provider_options.h
-include/onnxruntime/core/framework/provider_options_utils.h
-include/onnxruntime/core/framework/provider_shutdown.h
-include/onnxruntime/core/framework/resource_accountant.h
-include/onnxruntime/core/framework/run_options.h
-include/onnxruntime/core/framework/sparse_tensor.h
-include/onnxruntime/core/framework/stream_handles.h
-include/onnxruntime/core/framework/tensor.h
-include/onnxruntime/core/framework/tensor_shape.h
-include/onnxruntime/core/framework/to_tensor_proto_element_type.h
-include/onnxruntime/core/graph/basic_types.h
-include/onnxruntime/core/graph/constants.h
-include/onnxruntime/core/graph/function.h
-include/onnxruntime/core/graph/graph.h
-include/onnxruntime/core/graph/graph_nodes.h
-include/onnxruntime/core/graph/graph_viewer.h
-include/onnxruntime/core/graph/indexed_sub_graph.h
-include/onnxruntime/core/graph/model_saving_options.h
-include/onnxruntime/core/graph/node_arg.h
-include/onnxruntime/core/graph/onnx_protobuf.h
-include/onnxruntime/core/graph/schema_registry.h
-include/onnxruntime/core/optimizer/graph_transformer.h
-include/onnxruntime/core/optimizer/graph_transformer_config.h
-include/onnxruntime/core/optimizer/graph_transformer_level.h
-include/onnxruntime/core/optimizer/graph_transformer_utils.h
-include/onnxruntime/core/optimizer/rewrite_rule.h
-include/onnxruntime/core/optimizer/rule_based_graph_transformer.h
 include/onnxruntime/core/providers/custom_op_context.h
 include/onnxruntime/core/providers/resource.h
-include/onnxruntime/core/session/environment.h
-include/onnxruntime/core/session/experimental_onnxruntime_cxx_api.h
-include/onnxruntime/core/session/experimental_onnxruntime_cxx_inline.h
-include/onnxruntime/core/session/onnxruntime_c_api.h
-include/onnxruntime/core/session/onnxruntime_cxx_api.h
-include/onnxruntime/core/session/onnxruntime_cxx_inline.h
-include/onnxruntime/core/session/onnxruntime_float16.h
-include/onnxruntime/core/session/onnxruntime_lite_custom_op.h
-include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h
-include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h
-include/onnxruntime/core/session/snippets.dox
 include/onnxruntime/cpu_provider_factory.h
-lib/libonnxruntime_common.a
-lib/libonnxruntime_flatbuffers.a
-lib/libonnxruntime_framework.a
-lib/libonnxruntime_graph.a
-lib/libonnxruntime_lora.a
-lib/libonnxruntime_mlas.a
-lib/libonnxruntime_optimizer.a
-lib/libonnxruntime_providers.a
+include/onnxruntime/onnxruntime_c_api.h
+include/onnxruntime/onnxruntime_cxx_api.h
+include/onnxruntime/onnxruntime_cxx_inline.h
+include/onnxruntime/onnxruntime_float16.h
+include/onnxruntime/onnxruntime_lite_custom_op.h
+include/onnxruntime/onnxruntime_run_options_config_keys.h
+include/onnxruntime/onnxruntime_session_options_config_keys.h
+include/onnxruntime/provider_options.h
+lib/libonnxruntime.so
+lib/libonnxruntime.so.1
+lib/libonnxruntime.so.1.21.1
 lib/libonnxruntime_providers_shared.so
-lib/libonnxruntime_session.a
-lib/libonnxruntime_util.a
 libdata/pkgconfig/libonnxruntime.pc

編集したら、こちらもmake deinstall ; make && make installしておく。

trustmarkのビルド

こいつも調整が必要。onnxruntimeのバインディングであるortが、WindowsとLinuxとmacOSしか対応していない部分を持っている。ちくせう。

まずはgitでソースを2つ拾ってくる。trustmark本体と、問題のort。ortのtagは、trustmark/Cargo.tomlで指定されているものを選んでおく。(しかし2.0.0-rc.8タグはなかったのでrc.7にした)

$ git clone https://github.com/adobe/trustmark.git
$ cat trustmark/rust/Cargo.toml | grep ort
ort = "=2.0.0-rc.8"
$ git clone https://github.com/pykeio/ort.git
$ ( cd ort ; git checkout v2.0.0-rc.7 )

まずortをいじる。diffは以下の通り。

diff --git a/ort-sys/src/internal/dirs.rs b/ort-sys/src/internal/dirs.rs
index 098d27f..924b20b 100644
--- a/ort-sys/src/internal/dirs.rs
+++ b/ort-sys/src/internal/dirs.rs
@@ -170,7 +170,7 @@ mod unix {
        }
 }
 
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "freebsd"))]
 #[must_use]
 pub fn cache_dir() -> Option {
        std::env::var_os("XDG_CACHE_HOME")

これだけのために……?と思いながら編集して保存する。この時点でビルドは不要。

次にtrustmarkのCargo.tomlを編集して、いじったortを参照させる。diffは以下の通り。

diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 91d34a7..4d500d6 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -28,7 +28,8 @@ harness = false
 [dependencies]
 image = "0.24"
 ndarray = "0.16"
-ort = "=2.0.0-rc.8"
+#ort = "=2.0.0-rc.8"
+ort = { path = "../../ort" }
 thiserror = "1"

あとはビルドするだけ。デフォルトではライブラリしか生成しないので、--packagetrustmark-cliを明示する。

$ cargo build --release --package trustmark-cli

試す

では、おいしい試食の時間。まずtrustmarkのモデルを拾ってくる。

$ cargo xtask fetch-models

適当な画像を用意する。題材には先日撮影したツツジの写真を使ってみよう。

こいつにwatermarkをencodeしてみる。ちなみに今回は埋め込む情報を指定していないので、ランダムなビット列になる。指定したければ、-w 10110101...のように指定できるはず。

$ target/release/trustmark -m models encode -i work/original.jpg -o work/encoded.jpg
Terminating due to uncaught exception 0x157ad52383c0 of type std::__1::system_error
Abort trap (core dumped)

coreを吐いたけど気にしない。onnxruntime関係、exit時に出るようなので、出力は生成されている。

できあがりがこちら。でかすぎるので、適当にJPEG quality 40で再圧縮した。

見て分かる違いはないし、並べて表示しても差が分かる人はいないだろう。

今度はdecodeしてみる。(相変わらずcoreを吐くが、本質ではないので省略)

$ target/release/trustmark -m models decode -i work/original.jpg
Corrupt or missing watermark
$ target/release/trustmark -m models decode -i work/encoded.jpg
Found watermark: 0000110000110011111001101011111111011110110100101110101111000
$ target/release/trustmark -m models decode -i work/encoded_q40.jpg
Found watermark: 0000110000110011111001101011111111011110110100101110101111000

無事、そして期待通りにdecodeできた。生のものでも、JPEG quality 40で再圧縮したものでもdecodeできている。

切り抜くとどうだろうかと試したが、これはマチマチの結果だった。

失敗 失敗 成功

ちょっとでも切り取るとダメかも、という感じ。

最後に、原画像とwatermark入り画像の差を可視化してみた。適当なツールでabs(a-b)を計算して、目に見えるように増幅すると以下になる。

このうねうねがwatermarkの情報を運んでいるとすると、ビット数の割に大きいパターンになっているので、切り抜きに対しては弱そう。一方で、拡大縮小や、JPEG圧縮のノイズには強そうかな。

興味のある人は arXiv の論文PDF 3ページ目に他手法も含めた比較があるので見てみると面白いと思う。