ShotaArima / demo-lowprofool

0 stars 0 forks source link

bug-KeyError #4

Closed ShotaArima closed 2 months ago

ShotaArima commented 3 months ago

問題とは

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/tmp/ipykernel_1557/3277999088.py in <module>
     83 
     84 # Generate adversarial examples
---> 85 df_adv_lpf = gen_adv(config, 'LowProFool')
     86 df_adv_df = gen_adv(config, 'Deepfool')
     87 config['AdvData'] = {'LowProFool' : df_adv_lpf, 'Deepfool' : df_adv_df}

/tmp/ipykernel_1557/883132095.py in gen_adv(config, method)
     21 
     22         if method == 'LowProFool':
---> 23             orig_pred, adv_pred, x_adv, loop_i = lowProFool(x_tensor, model, weights, bounds, maxiters, alpha, lambda_)
     24         elif method == 'Deepfool':
     25             orig_pred, adv_pred, x_adv, loop_i = deepfool(x_tensor, model, maxiters, alpha, bounds, weights=[])

/src/Adverse.py in lowProFool(x, model, weights, bounds, maxiters, alpha, lambda_)
     96 
     97         # Clip to stay in legitimate bounds
---> 98         xprime = clip(xprime, bounds[0], bounds[1])
     99 
    100         # Classify adversarial example

KeyError: 0

原因解析

この状況を解決するには、一貫性のあるアプローチを取ることが重要です。以下の2つの選択肢があります:

boundsをリスト形式に統一する:

メリット:lowProFool関数の変更が最小限で済む。 デメリット:カテゴリカル変数の扱いが難しくなる可能性がある。

boundsを辞書形式に統一する:

メリット:より柔軟で情報量の多い形式。カテゴリカル変数も扱いやすい。 デメリット:lowProFool関数の修正がより複雑になる。

推奨されるアプローチ: 辞書形式に統一することをお勧めします。理由は以下の通りです:

柔軟性:辞書形式は各特徴量に関するより詳細な情報(型、範囲、カテゴリなど)を保持できます。 可読性:辞書形式は各特徴量の情報が明確に関連付けられるため、コードの可読性が向上します。 拡張性:将来的に新しい情報や制約を追加する場合、辞書形式の方が対応しやすいです。

実装手順:

  1. normalize関数の出力を辞書形式のままにします。
  2. gen_adv関数でboundsをそのままlowProFool関数に渡します。
  3. lowProFool関数を以下のように修正します:
def lowProFool(x, model, weights, bounds, maxiters, alpha, lambda_):
    # boundsから最小値と最大値を抽出
    min_bounds = []
    max_bounds = []
    for feature, info in bounds.items():
        if info['type'] == 'numeric':
            min_bounds.append(info['min'])
            max_bounds.append(info['max'])
        else:  # カテゴリカル変数の場合
            min_bounds.append(0)
            max_bounds.append(len(info['values']) - 1)

    min_bounds = torch.FloatTensor(min_bounds)
    max_bounds = torch.FloatTensor(max_bounds)

    # 以下、既存のコードを使用
    # clipを呼び出す際は min_bounds と max_bounds を使用
    xprime = clip(xprime, min_bounds, max_bounds)

    # ... (残りのコード)

clip関数も必要に応じて修正します(既にTensorを受け取れるようになっている場合は不要)。

このアプローチを採用することで、コード全体の一貫性が保たれ、将来的な拡張も容易になります。ただし、この変更に伴い、他の部分(例えばdeepfool関数など)も同様に修正が必要になる可能性があることに注意してください。