#実現したいこと
Pytorchを用いたマルウェア検知のためのDeep learningフレームワークに対するFGSMを実装しようとしています.
FGSMのスクリプト実行時に,CUDA out of memoryのRuntimeErrorが発生し,最後まで実行することができません.
以下がFGSMを行なっているスクリプトです.
python
1def fgsm_attack(self, benign_block): 2 #追加するバイト列を読み込み 3 append_bytez = self.benign_bytez[start_pos:end_pos] 4 append_size = len(append_bytez) 5 with torch.no_grad(): 6 #embdされた状態から元のバイト列に直すために,appendするバイト列を保存しておく 7 origin_bytez = \ 8 torch.from_numpy(np.frombuffer(self.malware_bytez + append_bytez,\ 9 dtype=np.uint8)[np.newaxis,:] ).float() 10 origin_bytez = origin_bytez.to(DEVICE) 11 while True:#lossが一定以下か,ループ上限になったらbreak 12 #勾配の初期化 13 self.opt.zero_grad() 14 #bytesの下処理.bytes -> Tensor & to -> GPU 15 inp_bytez = \ 16 torch.from_numpy(np.frombuffer(self.malware_bytez + append_bytez,\ 17 dtype=np.uint8)[np.newaxis,:]).float() 18 inp_bytez = inp_bytez.to(DEVICE) 19 #gradient計算のための処理.入力byte列をembeddding 20 inp_adv = inp_bytez.requires_grad_() 21 inp_adv.requires_grad = True 22 embd_bytez = self.model.embd_bytez(inp_adv.long()) 23 embd_bytez.requires_grad = True 24 #modelに通して結果を出力 25 out = self.model(embd_bytez) 26 result = F.softmax(out, dim=1) 27 #目標は良性なのでlabel=0.またlossを計算してbackprop + opimize 28 label = torch.from_numpy(np.array([0])) 29 label = label.to(DEVICE) 30 loss = self.criterion(result, label) 31 loss.backward() 32 self.opt.step() 33 with torch.no_grad(): 34 #入力バイト列全体のgradientを取得して,append部分のembd行列を取り出す 35 grad = embd_bytez.grad 36 grad_sign = grad.detach().sign()[0][-append_size:] 37 #-> torch.size([512, 8]) 38 if not (grad_sign.to('cpu').numpy() == 0).all(): #all_gradient != 0の場合のみ 39 #appendしているbyte列の変換,bytes -> Tensor -> embedding 40 append_bytez = self.model.embd_bytez(append_bytez) 41 #上のgradientを利用して,appendした部分の変更を行う 42 append_bytez = (append_bytez - self.eps * grad_sign) 43 #全体のembedの方でappendした部分の変更を行う 44 embd_bytez[0][-append_size:] = append_bytez #update perturbation 45 #embdしたバイト列を元に戻す 46 recont_bytez = self.reconstruction_to_byte(origin_bytez, embd_bytez, \ 47 append_size) 48 #recont_bytezの要素をnumpy.float32 -> bytesに直す 49 recont_bytez = (recont_bytez[0]).astype(np.uint8) 50 recont_bytez = recont_bytez.tobytes() 51 #bytes型に直下append_bytesを格納し直す 52 append_bytez = recont_bytez[-append_size:] 53 loop_count -= 1 54 #lossが一定値以上であれば,fgsmを用いて再度更新.以下なら成でbreak 55 if loop_count < 0 or loss.detach() < self.beta: 56 break 57 #返すのは最初のバイト列にfgsmで変更を加えたバイト列を追加したもの 58 return_bytez = self.malware_bytez + append_bytez 59 #メモリ不足対策に変数を消しておく 60 del origin_bytez, inp_bytez, embd_bytez, loss 61 return return_bytez
#試したこと
memory_profilerを用いてメモリ使用量を確認したところ,loss.backward()で大幅に増加することがあるのを確認しました.そこで変数lossに勾配情報がひたすら残り続けているのではないかと考え,最後にdelを行なったのですが,効果はありませんでした.
またbackpropに関係ない場所では,with torch.no_grad()を使用してみたのですが,これも効果がありませんでした.
そしてself.reconttuction_to_bytez()でもメモリ使用量が増えているのを確認しました.
関数の中で以下のコードを実行しているのが原因なのかな,と考えたのですが,正直そこまで問題のあるようには思えません.
python
1 out = original_bytez.to('cpu').detach().clone().numpy() 2 embd = embd_bytez.to('cpu').detach().clone().numpy()
回答1件
あなたの回答
tips
プレビュー