2

iチャンネルの画像がありますimage。チャンネルに適用できるfフィルターもあります。画像のチャンネルにフィルターを選択的に適用して、チャンネル画像filtersを生成したいと考えています。私は現在これを2つのリストで定義しているので、処理は次のように行われますooutputimage_idxfilter_idx

for j in xrange(o) :
    output[j] = filter[filter_idx[j]](image[image_idx[j]])

画像はかなり大きくなる可能性があるため、この処理をインプレースで行いたいと思うかもしれません。これには、後で必要になるデータの上書きを避けるために、特定の順序でチャネルを処理する必要がある場合があります。現在、次の関数を使用して、そのような注文が存在するかどうかを確認し、計算しています。

def in_place_sequence(indices) :
    """
    Figure out a processing sequence for in-place computation.
    """
    indices = [j for j in indices]
    positions = set(range(len(indices)))
    processing_order = []
    change = True
    while change and len(positions) :
        change = False
        for j in list(positions) :
            val = indices[j]
            if (j not in indices) or (indices.count(val) == 1 and val == j) :
                indices[j] = None
                positions.remove(j)
                processing_order.append(j)
                change = True
    if len(positions) :
        return None
    return processing_order

例えば:

In [21]: in_place_sequence([4, 0, 3, 0, 4])
Out[21]: [1, 2, 3, 0, 4]

また、上書きを避けるために可能な処理順序は次のとおりです。

img[0] -> img[1]
img[3] -> img[2]
img[0] -> img[3]
img[4] -> img[0]
img[4] -> img[4]

これは次のように実装されています。

for j in in_place_sequence(image_idx) :
    image[j] = filter[filter_idx[j]](image[image_idx[j]])

image_idxシーケンスが見つからないのは、閉ループ順列を定義しているためだとほのめかし始めています。例えば:

In [29]: in_place_sequence([2, 0, 3, 1])

を返しますがNone、1 チャネルの最小限のストレージでインプレースで実行できます。

img[0] -> temp
img[2] -> img[0]
img[3] -> img[2]
img[1] -> img[3]
temp   -> img[1]

これを自動的に実装する方法を見つけるのに苦労しています。私は、現在のアルゴリズムを維持し、それが使い果たされない場合はpositions、閉じたループを見つけ出し、それぞれに対して上記のようなことを行うことだと思います。ただし、ここで車輪を再発明している可能性があるという印象があります。コーディングに入る前に、中間ストレージを最小限に抑えるための処理順序を決定する最良の方法は何ですか?


編集Sam Mussmann の励ましで、私は先に進み、残りのサイクルを把握しました。私のコードは次のようになります。

def in_place_sequence(indices) :
    """
    Figures out a processing sequence for in-place computation.

    Parameters
    ----------
     indices : array-like
         The positions that the inputs will take in the output after
         processing.

    Returns
    -------
     processing_order : list
         The order in which output should be computed to avoid overwriting
         data needed for a later computation.

     cycles : list of lists
         A list of cycles present in `indices`, that will require a one
         element intermediate storage to compute in place.

    Notes
    -----
    If not doing the opearation in-place, if `in_` is a sequence of elements
    to process with a function `f`, then `indices` would be used as follows to
    create the output `out`:

        >>> out = []
        >>> for idx in indices :
        ...     out.append(f(in_[idx]))

    so that `out[j] = f(in_[indices[j]])`.

    If the operation is to be done in-place, `in_place_sequence` could be used
    as follows:

        >>> sequence, cycles = in_place_sequence(indices)
        >>> for j, idx in enumerate(sequence) :
        ...     in_[j] = f(in_[idx])
        >>> for cycle in cycles :
        ...     temp = in_[cycle[0]]            
        ...     for to, from_ in zip(cycle, cycle[1:]) :
        ...         in_[to] = f(in_[from_])
        ...     in_[cycle[-1]] = f(temp)
    """
    indices = [j for j in indices]
    print indices
    positions = set(range(len(indices)))
    processing_order = []
    change = True
    while change and positions :
        change = False
        for j in list(positions) :
            val = indices[j]
            if (j not in indices) or (indices.count(val) == 1 and val == j) :
                indices[j] = None
                positions.remove(j)
                processing_order.append(j)
                change = True
    cycles = []
    while positions :
        idx = positions.pop()
        start = indices.index(idx)
        cycle = [start]
        while idx != start :
            cycle.append(idx)
            idx = indices[idx]
            positions.remove(idx)
        cycles.append(cycle)
    return processing_order, cycles
4

1 に答える 1

1

あなたの方法はあなたが得るのと同じくらい良いと思います。

indicesリストの表現を、各チャネルがノードである有向グラフと考えてください。エッジ ( uv) は、出力チャネルvが入力チャネルに依存することを表しますu

書かれているように、ソリューションはアウトバウンド エッジのないノードを見つけ、このノードとそのインカミング エッジを削除し、それ以上ノードを削除できなくなるまで繰り返します。ノードが残っていない場合は完了です。ノードが残っている場合は、スタックしています。

私たちのグラフ表現では、行き詰まっているということは循環があることを意味します。一時的なチャネルを追加すると、ノードを「分割」してサイクルを断ち切ることができます。

ただし、この時点で、賢くなりたいと思うかもしれません。複数のサイクルを中断する、分割できるノードはありますか? 残念ながら、答えはノーです。各出力チャネルvは 1 つの入力チャネルにしか依存できないため、各ノードには 1 つのインバウンド エッジしかありません。ノードが複数のサイクルの一部になるためには、そのノード (または他のノード) に 2 つのインバウンド エッジが必要です。

したがって、一時チャネルを追加することで各サイクルを中断でき、一時チャネルを追加しても 1 つのサイクルしか中断できません。

さらに、サイクルしか残っていない場合、ノードを分割するとサイクルの 1 つが壊れます。したがって、派手なヒューリスティックは必要ありません。完了するまで今のコードを実行してください。まだpositions残っている場合は、一時チャネルを追加してコードを再度実行してください。

于 2013-02-16T02:56:07.660 に答える