TorchvisionでIoUの計算
はじめに
物体検出の評価指標で使われたりしているIoUを求めてみた。
IoUとは
Intersection over Unionの略である。Jaccard indexとも言われている。
物体検出の評価指標などで使われている。 物体検出では、物体を矩形で囲むことで、物体の位置を予測する。 正解もまた、矩形で囲まれたものが与えられる。この予測した矩形と正解の矩形を 評価する手法の1つとして、IoUが使われる。
2つの矩形があり、重なった部分の面積を面積の和で割ったものがIoUである。
2つの矩形が、まったく重ならなかったらIoU=0
となり、完全に重なるとIoU=1
となる。
IoUを求めてみる
IoUを求めてみる。
バージョン
- PyTorch : 1.4.0
- Torchvision : 0.5.0
使った関数
torchvision.ops.boxes.box_iou(boxes1,boxes2)
torchvisionにはtorchvision.ops.boxes
にbox_iou(boxes1, boxes2)
という関数がある。ドキュメントには載っていないが使えるので使う。
引数が矩形のboxes1とboxes2でそれぞれサイズがTensor[N, 4]、Tensor[M, 4]である。 この4の所は矩形の座標で(x1,y1,x2,y2)である。 返り値はiouでサイズがTensor[N, M]のテンソルである。
Google Colabで試した
矩形を2つ用意する。 最も左上の座標を(0,0)として右方向、下方向が+となる方向。 それぞれ左上の座標と左下の座標で矩形を表している。
一方の矩形にもう一方の矩形が含まれている例
box1は(0,0),(3,3)の矩形(黄色)、box2は(0,0),(5,5)の矩形(青)。
import torchvision.ops.boxes as bops box1=torch.tensor([[0,0,3,3]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) area1,area2=bops.box_area(box1),bops.box_area(box2) print("area1:",area1) print("area2:",area2) iou=bops.box_iou(box1,box2) print(iou)
実行してみる。
box1: tensor([[0., 0., 3., 3.]]) box2: tensor([[0., 0., 5., 5.]]) area1: tensor([9.]) area2: tensor([25.]) tensor([[0.3600]])
重なり部分の面積=(3-0)(3-0)=9、和の部分の面積=(5-0)(5-0)=25となる。
その結果、 となる
2つの矩形が重ならない例
box1:(5,0),(8,3)で、box:(0,0),(5,5)の場合
box1=torch.tensor([[5,0,8,3]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) iou=bops.box_iou(box1,box2) print(iou)
実行してみる。
box1: tensor([[5., 0., 8., 3.]]) box2: tensor([[0., 0., 5., 5.]]) tensor([[0.]])
重なっている部分がないので、IoU=0となる。
一部が重なる例
box1:(3,1),(6,4)で、box:(0,0),(5,5)の場合
box1=torch.tensor([[3,1,6,4]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) iou=bops.box_iou(box1,box2) print(iou[0][0].item()) print(iou)
実行してみる。
box1: tensor([[3., 1., 6., 4.]]) box2: tensor([[0., 0., 5., 5.]]) 0.2142857164144516 tensor([[0.2143]])
重なり部分の面積は6、和の部分の面積は28なので、 となる。
入力のboxesが複数ある例
boxes1:(3,1),(6,4)の黄色の矩形と(1,3),(4,5)の紫の矩形 で、boxes2:(0,3),(2,6)の赤の矩形と(0,0),(5,5)の青の矩形の場合
boxes1=torch.tensor([[3,1,6,4],[1,3,4,5]],dtype=torch.float) #黄, 紫 boxes2=torch.tensor([[0,3,2,6],[0,0,5,5]],dtype=torch.float) #赤, 青 print("boxes1:",boxes1) print("boxes2:",boxes2) iou=bops.box_iou(boxes1,boxes2) print(iou)
出力は、
boxes1: tensor([[3., 1., 6., 4.], [1., 3., 4., 5.]]) boxes2: tensor([[0., 3., 2., 6.], [0., 0., 5., 5.]]) tensor([[0.0000, 0.2143],[0.2000, 0.2400]])
返り値のIoUは入力サイズのboxes1が2、boxes2が2より、2x2のtensorが返ってくる。
得られたIoUのtensorは下の表のようになる。縦がboxes1で横がboxes2の並びとなる。
(0,3),(2,6) 赤 | (0,0),(5,5) 青 | |
---|---|---|
(3,1),(6,4) 黄色 | 0.0 | 0.2143 |
(1,3),(4,5) 紫 | 0.2000 | 0.2400 |
つまり、iou[index1][index2]でboxes1[index1]とboxes2[index2]の2つの矩形のIoUを得られる。
つまった点
box_iouの入力のbox1,box2をdtype=torch.intのtensorで計算すると、結果が0になってしまう。 そのため、dtypeはfloatにする必要がある。
まとめ
IoUについて調べ、torchvisionのbox_iou関数を使ってIoUを求めてみた。 複数の矩形のIoUを一括で求められて便利。 今後は、物体検出の評価指標は他にも色々あるので調べてみたい。