画像の欠損補間
実世界の問題において、データが欠損していることが多々あります。そのような場合にも、スパースであるという仮定をうまく利用することで、データの欠損を補間することができます。
前回、画像の再構成について紹介したとき、自然画像をパッチに区切って辞書学習を行うと、各パッチは得られた辞書を用いてスパースに表現できることがわかりました。実はこの辞書とスパース表現は、学習画像に、ある程度欠損があったとしても、うまく求めることができるのです。
なぜ、そんなことが可能かというと、例えば100変数の連立方程式を考えたときに、式の数は100個あれば全ての変数の値を決定できます。データとして10000個方程式があったとしても、そのうちの1%だけを使って連立方程式を解くことができます。また、方程式の解がほとんど0であるとわかっている場合も少数の方程式から解が得られることが知られています。つまり、10000変数の連立方程式を解くために10000個も方程式を必要としないということであり、これがスパースモデリングは少量データと相性がいいと言われる理由です。
このことから、辞書学習で求める辞書とスパースコードが連立方程式の変数に相当すると考えると、欠損していない部分から得られる方程式だけで、うまく辞書とスパースコードを推定できるというわけです。
では実際に、欠損画像に対して辞書学習を適用してみます。まず、以下のように、画像をランダムに50%欠損させた画像を作ります。
deficit_rate = 0.5 img = np.asarray(Image.open("img/recipe.jpg").convert('L')) mask = (np.random.rand(img.shape[0], img.shape[1]) > deficit_rate) deficit_img = mask * img
この画像に対して、辞書学習を適用します。ただし、欠損箇所には0という値が入っているので、欠損箇所は無視して学習を行うようにアルゴリズムを書き換える必要があります。前回使用したspm-imageというライブラリでは、すでに欠損を想定した辞書学習アルゴリズムが提供されているので、それを使ってみましょう。興味がある方は、内部の実装を読んでみるといいかもしれません。実際は、以下のようにmissing_value=0
と指定するだけで、欠損を考慮した辞書学習を実行することができます。
from sklearn.feature_extraction.image import extract_patches_2d, reconstruct_from_patches_2d from spmimage.decomposition import KSVD from spmimage.decomposition import sparse_encode_with_mask from sklearn.preprocessing import StandardScaler # 辞書学習のパラメータを設定 patch_size = (8, 8) n_nonzero_coefs = 5 n_components = 64 # 画像からパッチを切り出す patches = extract_patches_2d(deficit_img, patch_size).reshape(-1, np.prod(patch_size)).astype(np.float64) # 辞書学習を実行し、辞書DとスパースコードXを求める model = KSVD(n_components=n_components, transform_n_nonzero_coefs=n_nonzero_coefs, max_iter=15, missing_value=0) X = model.fit_transform(patches) D = model.components_
欠損している画像から学習された辞書とスパース表現を用いて、再構成画像を計算した結果が以下の通りです。
このように、欠損している画像からでも、ある程度復元をすることができました。欠損率を変えて、どの程度まで復元できるのか、いろいろ挑戦してみると面白いかもしれません。