Skip to content
Permalink
Browse files

Add ML loss.

  • Loading branch information...
bamos committed Apr 12, 2019
1 parent 7b9fb70 commit df0235cd85b7349de1f184f67d542501c087befb
@@ -202,4 +202,5 @@ def setup_parser(self):
parser.add_argument('-lml_topk', type=int)
parser.add_argument('-lml_softmax', action='store_true')
parser.add_argument('-entr_topk', type=int)
parser.add_argument('-ml_loss', action='store_true')
return parser
@@ -330,6 +330,7 @@ def __init__(
pass_in_obj_feats_to_edge=True, rec_dropout=0.0, use_bias=True,
use_tanh=True, limit_vision=True,
lml_topk=False, lml_softmax=False, entr_topk=False,
ml_loss=False,
):

"""
@@ -365,6 +366,8 @@ def __init__(
self.lml_softmax = lml_softmax
self.entr_topk = entr_topk

self.ml_loss = ml_loss

self.require_overlap = require_overlap_det and self.mode == 'sgdet'

self.detector = ObjectDetector(
@@ -656,7 +659,7 @@ def forward(
Variable(torch.zeros(n_rel, 1).type_as(rel_dists_i.data)),
rel_rep,
), 1)
elif self.entr_topk is not None and self.entr_topk:
elif (self.entr_topk is not None and self.entr_topk) or self.ml_loss:
# Hack to ignore the background.
rel_rep = torch.cat((
Variable(-1e10*torch.ones(n_rel,1).type_as(rel_dists_i.data)),
@@ -84,6 +84,7 @@ def main():
lml_topk=conf.lml_topk,
lml_softmax=conf.lml_softmax,
entr_topk=conf.entr_topk,
ml_loss=conf.ml_loss
)

# Freeze the detector
@@ -253,6 +254,32 @@ def train_batch(batch_num, b, detector, train, optimizer, verbose=False):
loss = torch.cat(loss)
loss = torch.sum(loss) / n_pos
losses['rel_loss'] = loss
elif conf.ml_loss:
loss = []

start = 0
for i, rel_reps_i in enumerate(result.rel_reps):
n = rel_reps_i.shape[0]

# Get rid of the background labels here:
reps = result.rel_dists[start:start+n,1:].contiguous().view(-1)
gt = result.rel_labels[start:start+n,-1].data.cpu()
I = gt > 0
gt = gt[I]
gt = gt - 1 # Hacky shift to get rid of background labels.
r = (n_rel-1)*torch.arange(len(I))[I].long()
gt_flat = r + gt
gt_flat_onehot = torch.zeros(len(reps))
gt_flat_onehot.scatter_(0, gt_flat, 1)
loss_i = torch.nn.BCEWithLogitsLoss(size_average=False)(
reps, Variable(gt_flat_onehot.cuda()))
loss.append(loss_i)

start += n

loss = torch.cat(loss)
loss = torch.sum(loss) / len(loss)
losses['rel_loss'] = loss
elif conf.entr_topk is not None and conf.entr_topk:
# Note: This still uses a maximum of 1 relationship per edge
# in the graph. Adding them all requires changing the data loading
@@ -32,12 +32,24 @@ run_entr() {
SEED=$2
# No manual seed is set internally, so just give the
# output directory a different name.
python3 models/train_rels.py -m predcls -model motifnet \
-order leftright -nl_obj 2 -nl_edge 4 -b 6 -clip 5 \
-p 10 -hidden_dim 512 -pooling_dim 4096 -lr 1e-3 \
-ngpu 1 -ckpt checkpoints/vg-faster-rcnn.tar \
-save_dir checkpoints/entr_predcls.$TOPK.$SEED \
-nepoch 30 -use_bias -entr_topk $TOPK &> logs/entr.$TOPK.log &
}

run_ml() {
SEED=$1
# No manual seed is set internally, so just give the
# output directory a different name.
python3 models/train_rels.py -m predcls -model motifnet \
-order leftright -nl_obj 2 -nl_edge 4 -b 6 -clip 5 \
-p 10 -hidden_dim 512 -pooling_dim 4096 -lr 1e-3 \
-ngpu 1 -ckpt checkpoints/vg-faster-rcnn.tar \
-save_dir checkpoints/entr_predcls.$TOPK.$SEED \
-nepoch 30 -use_bias -entr_topk $TOPK &> logs/entr.$TOPK.log &
-save_dir checkpoints/ml_predcls.$SEED \
-nepoch 30 -use_bias -ml_loss &> logs/ml.log &
}

SEED=0
@@ -63,4 +75,7 @@ SEED=0
# export CUDA_VISIBLE_DEVICES=2
# run_entr 100 $SEED

export CUDA_VISIBLE_DEVICES=0
run_ml

wait
@@ -149,7 +149,7 @@ def _add_loss_parser(parser):
l_parser = parser.add_argument_group(title='Loss parameters')

l_parser.add_argument('--loss', type=str, required=True,
choices=['svm', 'ce', 'svm-lapin', 'lml', 'entr'],
choices=['svm', 'ce', 'svm-lapin', 'lml', 'ml', 'entr'],
help="loss ('svm', 'ce', 'lml')")
l_parser.add_argument('--topk', type=int,
help="Top-k error to minimize")
@@ -1,6 +1,7 @@
import torch.nn as nn
from losses.svm import SmoothSVM
from losses.lml_loss import LMLLoss
from losses.ml import MLLoss
from losses.entr import EntrLoss

def get_loss(xp, args):
@@ -14,6 +15,8 @@ def get_loss(xp, args):
elif args.loss == 'lml':
print("Using LML loss")
loss = LMLLoss(n_classes=args.num_classes, k=args.topk, tau=args.tau)
elif args.loss == 'ml':
loss = MLLoss(n_classes=args.num_classes)
elif args.loss == 'entr':
print("Using truncated entr (Lapin) loss")
loss = EntrLoss(n_classes=args.num_classes, k=args.topk, tau=args.tau)
@@ -0,0 +1,15 @@
import torch
from torch import nn

class MLLoss(nn.Module):
def __init__(self, n_classes):
super(MLLoss, self).__init__()
self.n_classes = n_classes
self.tau = 1.0

def forward(self, x, y):
n_batch = x.shape[0]
y_onehot = torch.zeros(n_batch, self.n_classes).type_as(x)
y_onehot.scatter_(1, y.unsqueeze(1), 1)
loss = nn.BCEWithLogitsLoss()(x, y_onehot)
return loss
@@ -0,0 +1,18 @@
#!/bin/bash

# echo "Using device" $device

mkdir -p logs

# for p in 0.0 0.2 0.4 0.6 0.8 1.0; do
# for p in 0.2 0.4 0.6 0.8 1.0; do
for p in 0.2 0.4; do
for seed in 0 3; do
export CUDA_VISIBLE_DEVICES=$seed
python3 main.py --dataset cifar100 --model densenet40-40 \
--out-name ../xp/cifar100/cifar100_${p}_${seed}_ml \
--loss ml --noise $p --seed $seed \
--no-visdom --test-batch-size 64 &> /dev/null &
done
wait
done
@@ -38,6 +38,8 @@
loss = 'ce'
elif 'lml' in xp_file:
loss = 'lml'
elif '_ml' in xp_file:
loss = 'ml'
elif 'entr' in xp_file:
loss = 'entr'
else:

0 comments on commit df0235c

Please sign in to comment.
You can’t perform that action at this time.