#TL;DR
オーバーフロー
#はじめに
- 本記事はOpenCVアドベントカレンダー2021の21日目の記事です
- 昨日は@eqsさんによる対戦ゲームの動画記録から特定のイベントを自動的に探してクリップを生成する画像処理作ったでした
- その他の記事は目次を参照ください
- 本日は
cudafilters
モジュールの回帰テストがFAILするのを直したお話 - テストが以下のようにFAILします
テストFAIL時のログ
[ FAILED ] 73 tests, listed below:
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/388, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(9x9), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/393, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(11x11), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/396, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(11x11), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/397, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(11x11), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/413, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(15x15), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/417, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(17x17), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/434, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(21x21), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/446, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(23x23), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/453, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(25x25), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/456, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(27x27), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/458, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(27x27), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/476, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(31x31), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/505, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(9x9), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/511, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(9x9), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/537, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(17x17), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/538, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(17x17), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/566, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(23x23), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/569, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(25x25), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/575, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(25x25), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/591, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(29x29), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/593, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(31x31), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/594, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(3), KSize(31x31), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/639, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(11x11), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/648, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(15x15), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/649, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(15x15), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/652, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(15x15), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/658, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(17x17), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/664, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(19x19), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/667, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(19x19), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/703, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(4), KSize(27x27), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1817, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(7x7), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1819, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(7x7), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1826, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(9x9), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1827, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(9x9), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1837, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(11x11), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1843, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(13x13), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1864, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(19x19), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1872, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(21x21), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1874, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(21x21), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1878, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(21x21), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1884, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(23x23), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1892, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(25x25), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1898, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(27x27), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1902, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(27x27), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1905, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(29x29), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1916, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(1), KSize(31x31), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1945, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(9x9), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1952, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(11x11), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1957, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(11x11), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1960, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(13x13), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1965, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(13x13), BORDER_CONSTANT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1969, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(15x15), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1977, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(17x17), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1978, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(17x17), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/1982, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(17x17), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2008, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(25x25), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2023, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(27x27), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2024, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(29x29), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2032, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(31x31), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2038, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(3), KSize(31x31), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2073, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(11x11), BORDER_REFLECT101, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2086, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(13x13), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2088, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(15x15), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2096, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(17x17), BORDER_REFLECT101, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2108, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(19x19), BORDER_CONSTANT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2111, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(19x19), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2114, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(21x21), BORDER_REPLICATE, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2118, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(21x21), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2123, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(23x23), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2131, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(25x25), BORDER_REPLICATE, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2135, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(25x25), BORDER_REFLECT, sub matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2142, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(27x27), BORDER_REFLECT, whole matrix)
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/2153, where GetParam() = (NVIDIA Tegra X1, 113x113, CV_16U, Channels(4), KSize(31x31), BORDER_REFLECT101, sub matrix)
73 FAILED TESTS
- テストは
opencv_test_cudafilters
でしたが、後述の通り、imgproc
モジュールが引き金です
#再現性
コードに飛び込む前に状況を整理してみましょう
##CV_16Uに限る
- テストのメッセージを見るに、
CV_16U
というパラメータが見えます -
GaussianBlur
関数に渡す画像の要素がCV_8U
かCV_32F
の場合はテストはPASSするのですが、CV_16U
のときだけFAILします
[ FAILED ] CUDA_Filters/GaussianBlur.Accuracy/388, where GetParam() = (NVIDIA Tegra X1, 128x128, CV_16U, Channels(1), KSize(9x9), BORDER_CONSTANT, whole matrix)
テスト名の後ろ、GetParamがついている場合は同じ関数を複数のパラメータでチェックする。ここにCV_16U__________^^^^^^
他のパラメータは変化するが、このCV_16Uだけ変化しない
##deterministicな再現性
- 同じテストを何回実行しても決まって同じテストがコケます
$ for i in `seq 1 3 ` ; do ./bin/opencv_test_cudafilters --gtest_filter=*Gaussian* --gtest_param_filter=*CV_16U* | grep "FAILED TESTS" ; done
67 FAILED TESTS
67 FAILED TESTS
67 FAILED TESTS
- 一方で、
--gtest_repeat=3
オプションを利用すると、テストがFAILする数が変わる
$ ./bin/opencv_test_cudafilters --gtest_filter=*Gaussian* --gtest_param_filter=*CV_16U* --gtest_repeat=3 | grep "FAILED TESTS"
67 FAILED TESTS
64 FAILED TESTS
77 FAILED TESTS
- このコケ方が変化することの意味は
-
bash
のfor
文で複数回実行した場合は固定のシードで実行されるので、deterministicな結果が得られる - 一方で、
gtest_repeat
オプションをつけた場合、シードの初期化が1度だけ行われたあと同じ乱数系列が引き続き使われる - そのため、生成される乱数は微妙に違ってくる
-
- つまり、微妙なパラメータの違いでテストがコケることを意味している
#画像
##入力画像
##出力画像GPU版
##出力画像CPU版
- というわけでテストは
cudafilters
モジュールのテストがコケてるのですが、当該テストは- CUDA版のガウシアンフィルタの結果と
- CPU版のガウシアンフィルタの結果を
- それぞれ比較し、結果が一致しなければFAIL
- という仕組みです
- 今回のFAILは、どうやらCPU版が予期せぬ結果を返したためにFAILとなっている模様です。
- CPU版の実装は
imgproc
モジュール内にあります
#bit-exactなGaussianBlur
- 奇しくも2日目の記事でもGaussianBlur関数に触れてますが、ここではもう少しGaussianBlur関数を掘ってみましょう
##関数の仕組み
.cpp
void GaussianBlur(InputArray _src, OutputArray _dst, Size ksize, double sigma1, double sigma2, int borderType)
- このように、GaussianBlur関数には
- 入力画像
- 出力用バッファ
- 平滑化カーネルの大きさ
- 平滑化具合を示すシグマ (x2)
- 境界線の処理を指定するフラグ
- を指定します
-
sigma1
は横方向への平滑化度合い、sigma2
は縦方向への平滑化度合いを指定します-
sigma
は値が大きい方が平滑化の度合いが強くなり、小さい方が平滑化の効果は小さくなる1 - 現状テストコードからは
sigma2
は無罪で、sigma1
だけが引き金のようです。
-
- 内部では、この
sigma
の値をもとに、カーネル(畳み込み積分される係数)が作られます。テストケースでは7x7のフィルタのようです。- 縦横独立して計算するため、7つのパラメータが指定されます。
- また、OpenCVは3.3ぐらいから2 bit-exactなGaussianBlurが実装されました
- なので、7つのパラメータは
float
ではなく、内部では32bit符号なし整数もしくは16bit符号なし整数として表現されます
- カーネルを作るところを見てみましょう。
.cpp
Mat kx, ky;
createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2);
- ここでは
kx
が横方向への平滑化を行うカーネルです - 出てきた
kx
の中身を見てみましょう
0.00000000
3.38778060e-21
7.62910940e-06
0.999984741
7.62910940e-06
3.38778060e-21
0.00000000
- 指数表示なのでわかりにくいですが、小数点を揃えると、こんな感じです。
0.00000000000000000000000000000
0.00000000000000000000338778060
0.00000762910940
0.999984741
0.00000762910940
0.00000000000000000000338778060
0.00000000000000000000000000000
-
何ということでしょう。人生で一番不毛なグラフを描いてしまった気もします。
-
とは言え、1番目と2番目の係数が100,000倍(10万倍)違います。
- そして内部的には
CV_16U
で、表せる最小の桁数は1/65536
です。 - 実はこのあたりがバグのキモではないかと薄々このあたりで筆者は思い始めました。
- そして内部的には
-
この値は、
CV_16U
のケースなので、内部的には固定小数点として以下の形式で保持されます
0x00000000
0x00000000
0x00000000
0x00010000
0x00000000
0x00000000
0x00000000
- 状況から考えるに、
CV_16U
のbit幅で0x10000
が発生したときにだけエラーになってるのでは?とプンプンにおってきます。
##実際にバグのトリガとなるコード
- そこから更に進むと、SIMD最適化されたコードに到着します
.cpp
v_mul_expand(vx_load(src + pre_shift * cn), vx_setall_u16((uint16_t) *((uint32_t*)(m + pre_shift))), v_res0, v_res1);
- ここの内部で使われている
vx_setall_u16
は前述のパラメータをロードして、ベクトルレジスタの全要素に設定するintrinsic
です - ここで、この行をよく読み解くと
.cpp
vx_setall_u16((uint16_t) *((uint32_t*)(m + pre_shift)))
// ^ ^ ^____メモリアドレス
// | |_______________32bit符号なし整数としてロード
// |____________________________16bit符号なし整数に変換(!)
- という具合に
- メモリアドレスを計算
- 32bit符号なし整数としてロード
- 16bit符号なし整数に変換(←イマココ)
- ベクトルレジスタの全要素に同じ値を設定
- ということをしています。
- ところで32bit符号なし整数、
0x10000
を16bit符号なし整数に変換すると結果はいくつでしょう?
##原因中の原因
- というわけで、バグとしては「オーバーフローが発生していた」のが原因です
##sigma2
が無罪なわけ
.cpp
v_uint32 v_mul = vx_setall_u32(*((uint32_t*)(m + pre_shift)));
- 同様に縦方向にガウシアンフィルタをかける実装ではご覧の通り、符号なし32bit整数として処理されております
#まとめ
- GaussianBlur関数の画像が
CV_16U
型の場合でsigma1
に0.2以下の値3を渡すと、空っぽな画像が生成されます - 原因はオーバーフロー
##再現バージョン
- 3.4系列の一部 (3.4.13-3.4.16まで。次期リリース予定の3.4.17でFIX)
- 4.5系列の一部 (4.5.1-4.5.4まで。次期リリース予定の4.5.5でFIX)