Skip to content

Commit 032a50a

Browse files
committed
commmits, including the train --> val on the video_info.
1 parent 738f9e2 commit 032a50a

14 files changed

+998
-472
lines changed

data/gymnastics_annotations/video_info.sep052019.fps12.csv

+413-413
Large diffs are not rendered by default.

dataset.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ def _get_video_data(self, data, index):
209209
class ThumosImages(Thumos):
210210

211211
def __init__(self, opt, subset=None, fps=30, image_dir=None, img_loading_func=None):
212+
self.do_augment = opts['do_augment'] and subset == 'train'
212213
super(ThumosImages, self).__init__(opt, subset, feature_dirs=None, fps=fps, image_dir=image_dir, img_loading_func=img_loading_func)
213214

214215
def _get_video_data(self, data, index):
@@ -217,7 +218,8 @@ def _get_video_data(self, data, index):
217218
path = os.path.join(self.image_dir, name)
218219
path = Path(path)
219220
paths = [path / ('%010.4f.npy' % (i / self.fps)) for i in indices]
220-
imgs = [self.img_loading_func(p.absolute()) for p in paths if p.exists()]
221+
imgs = [self.img_loading_func(p.absolute(), do_augment=self.do_augment)
222+
for p in paths if p.exists()]
221223
# if len(imgs) < self.window_size:
222224
# imgs.extend([np.zeros(imgs[-1].shape) for _ in range(self.window_size - len(imgs))])
223225

@@ -275,6 +277,7 @@ class GymnasticsDataSet(data.Dataset):
275277
def __init__(self, opt, subset="train", img_loading_func=None, overlap_windows=False):
276278
self.subset = subset
277279
self.mode = opt["mode"]
280+
self.do_augment = opt['do_augment'] and subset == 'train'
278281
self.img_loading_func = img_loading_func
279282
self.overlap_windows = overlap_windows
280283

@@ -361,7 +364,10 @@ def _get_base_data(self, index, start=None, end=None):
361364
for i in range(start, end, self.skip_videoframes) \
362365
if i < max_frames
363366
]
364-
imgs = [self.img_loading_func(p.absolute()) for p in paths]
367+
368+
imgs = [self.img_loading_func(p.absolute(), do_augment=self.do_augment)
369+
for p in paths if p.exists()]
370+
365371
diff = len(list(range(start, end, self.skip_videoframes))) - len(imgs)
366372
if type(imgs[0]) == np.array:
367373
if diff > 0:
@@ -558,7 +564,7 @@ def _getDatasetDict(self):
558564
pdf = pd.read_csv(pgm_proposals_path)
559565
video_feature = np.load(pgm_features_path)
560566
pre_count = len(pdf)
561-
if self.top_K is not None:
567+
if self.top_K > 0:
562568
try:
563569
pdf = pdf.sort_values(by="score", ascending=False)
564570
except KeyError:
@@ -606,7 +612,7 @@ def __getitem__(self, index):
606612
pdf = pdf.sort_values(by="score", ascending=False)
607613
# ***
608614
video_feature = np.load(pgm_features_path)
609-
if self.top_K is not None:
615+
if self.top_K > 0:
610616
pdf = pdf[:self.top_K]
611617
video_feature = video_feature[:self.top_K, :]
612618

eval2.py

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import numpy as np
2+
import pandas as pd
3+
from scipy.interpolate import interp1d
4+
import os
5+
6+
7+
def segment_tiou(target_segments, test_segments):
8+
"""Compute intersection over union btw segments
9+
Parameters
10+
----------
11+
target_segments : ndarray
12+
2-dim array in format [m x 2:=[init, end]]
13+
test_segments : ndarray
14+
2-dim array in format [n x 2:=[init, end]]
15+
Outputs
16+
-------
17+
tiou : ndarray
18+
2-dim array [m x n] with IOU ratio.
19+
Note: It assumes that target-segments are more scarce that test-segments
20+
"""
21+
if target_segments.ndim != 2 or test_segments.ndim != 2:
22+
raise ValueError('Dimension of arguments is incorrect')
23+
24+
m, n = target_segments.shape[0], test_segments.shape[0]
25+
tiou = np.empty((m, n))
26+
for i in range(m):
27+
tt1 = np.maximum(target_segments[i, 0], test_segments[:, 0])
28+
tt2 = np.minimum(target_segments[i, 1], test_segments[:, 1])
29+
30+
# Non-negative overlap score
31+
intersection = (tt2 - tt1 + 1.0).clip(0)
32+
union = ((test_segments[:, 1] - test_segments[:, 0] + 1) + (
33+
target_segments[i, 1] - target_segments[i, 0] + 1) - intersection)
34+
# Compute overlap as the ratio of the intersection
35+
# over union of two segments at the frame level.
36+
tiou[i, :] = intersection / union
37+
return tiou
38+
39+
40+
def average_recall_vs_nr_proposals(proposals,
41+
ground_truth,
42+
tiou_thresholds=np.linspace(0.5, 1.0, 11)):
43+
""" Computes the average recall given an average number
44+
of proposals per video.
45+
46+
Parameters
47+
----------
48+
proposals : DataFrame
49+
pandas table with the resulting proposals. It must include
50+
the following columns: {'video-name': (str) Video identifier,
51+
'f-init': (int) Starting index Frame,
52+
'f-end': (int) Ending index Frame,
53+
'score': (float) Proposal confidence}
54+
ground_truth : DataFrame
55+
pandas table with annotations of the dataset. It must include
56+
the following columns: {'video-name': (str) Video identifier,
57+
'f-init': (int) Starting index Frame,
58+
'f-end': (int) Ending index Frame}
59+
tiou_thresholds : 1darray, optional
60+
array with tiou threholds.
61+
62+
Outputs
63+
-------
64+
average_recall : 1darray
65+
recall averaged over a list of tiou threshold.
66+
proposals_per_video : 1darray
67+
average number of proposals per video.
68+
"""
69+
# Get list of videos.
70+
video_lst = proposals['video-name'].unique()
71+
72+
# For each video, computes tiou scores among the retrieved proposals.
73+
score_lst = []
74+
for videoid in video_lst:
75+
76+
# Get proposals for this video.
77+
prop_idx = proposals['video-name'] == videoid
78+
this_video_proposals = proposals[prop_idx][['f-init', 'f-end']].values
79+
# Sort proposals by score.
80+
sort_idx = proposals[prop_idx]['score'].argsort()[::-1]
81+
this_video_proposals = this_video_proposals[sort_idx, :]
82+
83+
# Get ground-truth instances associated to this video.
84+
gt_idx = ground_truth['video-name'] == videoid
85+
this_video_ground_truth = ground_truth[gt_idx][['f-init',
86+
'f-end']].values
87+
88+
# Compute tiou scores.
89+
tiou = segment_tiou(this_video_ground_truth, this_video_proposals)
90+
score_lst.append(tiou)
91+
92+
# Given that the length of the videos is really varied, we
93+
# compute the number of proposals in terms of a ratio of the total
94+
# proposals retrieved, i.e. average recall at a percentage of proposals
95+
# retrieved per video.
96+
97+
# Computes average recall.
98+
pcn_lst = np.arange(1, 201) / 200.0
99+
matches = np.empty((video_lst.shape[0], pcn_lst.shape[0]))
100+
positives = np.empty(video_lst.shape[0])
101+
recall = np.empty((tiou_thresholds.shape[0], pcn_lst.shape[0]))
102+
# Iterates over each tiou threshold.
103+
for ridx, tiou in enumerate(tiou_thresholds):
104+
105+
# Inspect positives retrieved per video at different
106+
# number of proposals (percentage of the total retrieved).
107+
for i, score in enumerate(score_lst):
108+
# Total positives per video.
109+
positives[i] = score.shape[0]
110+
111+
for j, pcn in enumerate(pcn_lst):
112+
# Get number of proposals as a percentage of total retrieved.
113+
nr_proposals = int(score.shape[1] * pcn)
114+
# Find proposals that satisfies minimum tiou threhold.
115+
matches[i, j] = ((score[:, :nr_proposals] >= tiou).sum(axis=1) >
116+
0).sum()
117+
118+
# Computes recall given the set of matches per video.
119+
recall[ridx, :] = matches.sum(axis=0) / positives.sum()
120+
121+
# Recall is averaged.
122+
recall = recall.mean(axis=0)
123+
124+
# Get the average number of proposals per video.
125+
proposals_per_video = pcn_lst * (
126+
float(proposals.shape[0]) / video_lst.shape[0])
127+
128+
return recall, proposals_per_video
129+
130+
131+
def recall_vs_tiou_thresholds(proposals,
132+
ground_truth,
133+
nr_proposals=1000,
134+
tiou_thresholds=np.arange(0.05, 1.05, 0.05)):
135+
""" Computes recall at different tiou thresholds given a fixed
136+
average number of proposals per video.
137+
138+
Parameters
139+
----------
140+
proposals : DataFrame
141+
pandas table with the resulting proposals. It must include
142+
the following columns: {'video-name': (str) Video identifier,
143+
'f-init': (int) Starting index Frame,
144+
'f-end': (int) Ending index Frame,
145+
'score': (float) Proposal confidence}
146+
ground_truth : DataFrame
147+
pandas table with annotations of the dataset. It must include
148+
the following columns: {'video-name': (str) Video identifier,
149+
'f-init': (int) Starting index Frame,
150+
'f-end': (int) Ending index Frame}
151+
nr_proposals : int
152+
average number of proposals per video.
153+
tiou_thresholds : 1darray, optional
154+
array with tiou threholds.
155+
156+
Outputs
157+
-------
158+
average_recall : 1darray
159+
recall averaged over a list of tiou threshold.
160+
proposals_per_video : 1darray
161+
average number of proposals per video.
162+
"""
163+
# Get list of videos.
164+
video_lst = proposals['video-name'].unique()
165+
166+
# For each video, computes tiou scores among the retrieved proposals.
167+
score_lst = []
168+
for videoid in video_lst:
169+
170+
# Get proposals for this video.
171+
prop_idx = proposals['video-name'] == videoid
172+
this_video_proposals = proposals[prop_idx][['f-init', 'f-end']].values
173+
# Sort proposals by score.
174+
sort_idx = proposals[prop_idx]['score'].argsort()[::-1]
175+
this_video_proposals = this_video_proposals[sort_idx, :]
176+
177+
# Get ground-truth instances associated to this video.
178+
gt_idx = ground_truth['video-name'] == videoid
179+
this_video_ground_truth = ground_truth[gt_idx][['f-init',
180+
'f-end']].values
181+
182+
# Compute tiou scores.
183+
tiou = segment_tiou(this_video_ground_truth, this_video_proposals)
184+
score_lst.append(tiou)
185+
186+
# To obtain the average number of proposals, we need to define a
187+
# percentage of proposals to get per video.
188+
pcn = (video_lst.shape[0] * float(nr_proposals)) / proposals.shape[0]
189+
190+
# Computes recall at different tiou thresholds.
191+
matches = np.empty((video_lst.shape[0], tiou_thresholds.shape[0]))
192+
positives = np.empty(video_lst.shape[0])
193+
recall = np.empty(tiou_thresholds.shape[0])
194+
# Iterates over each tiou threshold.
195+
for ridx, tiou in enumerate(tiou_thresholds):
196+
197+
for i, score in enumerate(score_lst):
198+
# Total positives per video.
199+
positives[i] = score.shape[0]
200+
201+
# Get number of proposals at the fixed percentage of total retrieved.
202+
nr_proposals = int(score.shape[1] * pcn)
203+
# Find proposals that satisfies minimum tiou threhold.
204+
matches[i, ridx] = ((score[:, :nr_proposals] >= tiou).sum(axis=1) >
205+
0).sum()
206+
207+
# Computes recall given the set of matches per video.
208+
recall[ridx] = matches[:, ridx].sum(axis=0) / positives.sum()
209+
210+
return recall, tiou_thresholds
211+
212+
213+
def evaluation_proposal(opt):
214+
bsn_results = pd.read_csv(os.path.join(opt['postprocessed_results_dir'], 'thumos14_results.csv'))
215+
ground_truth = pd.read_csv(opt['video_info'])
216+
217+
# Computes average recall vs average number of proposals.
218+
average_recall, average_nr_proposals = average_recall_vs_nr_proposals(
219+
bsn_results, ground_truth)
220+
221+
print(average_nr_proposals.shape)
222+
f = interp1d(average_nr_proposals, average_recall, axis=0)
223+
print(f(50), f(100), f(200), f(500), f(1000))

gen_pem_results_jobs.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,33 @@
1212

1313
1414
code_directory = '/private/home/cinjon/Code/BSN-boundary-sensitive-network.pytorch'
15-
anno_directory = '/private/home/cinjon/Code/BSN-boundary-sensitive-network.pytorch/data/gymnastics_annotations'
15+
1616
base_dir = '/checkpoint/cinjon/spaceofmotion/bsn'
1717
pem_dir = os.path.join(base_dir, 'peminf')
1818
pem_results_dir = os.path.join(pem_dir, 'results')
1919
if not os.path.exists(pem_results_dir):
2020
os.makedirs(pem_results_dir)
2121
ckpt_directory = os.path.join(pem_dir, 'do_ckpts')
2222

23-
regex = re.compile('.*(\d{5}).*')
23+
regex = re.compile('.*ckpt.*-(\d{5}).*')
24+
num_gpus = 4
2425

2526
for ckpt_subdir in os.listdir(ckpt_directory):
2627
counter = int(regex.match(ckpt_subdir).groups()[0])
2728
_job = run(find_counter=counter)
28-
_job['num_gpus'] = 8
29-
_job['num_cpus'] = 8 * 10
30-
_job['gb'] = 64 * 8
31-
_job['time'] = 4 # what time should this be?
29+
_job['num_gpus'] = num_gpus
30+
_job['num_cpus'] = num_gpus * 10
31+
_job['gb'] = 64 * num_gpus
32+
_job['time'] = 1.5
3233
_job['pem_inference_results_dir'] = pem_results_dir
33-
_job['pem_results_subset'] = _job['pem_train_subset']
3434
_job['pem_inference_subset'] = 'full'
3535
_job['mode'] = 'inference'
3636
_job['checkpoint_path'] = os.path.join(ckpt_directory, ckpt_subdir)
37-
38-
print(counter, sorted(_job.items()))
39-
fb_run_batch(_job, counter, email, code_directory)
37+
38+
name = _job['name']
39+
for ckpt_epoch in [15, 30]:
40+
_job['checkpoint_epoch'] = ckpt_epoch
41+
_job['name'] = '%s.ckpt%d' % (name, ckpt_epoch)
42+
print(counter, _job['name'])
43+
print(sorted(_job.items()))
44+
fb_run_batch(_job, counter, email, code_directory)

gen_postprocessed_results_jobs.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Run the jobs that generate TEM Results.
2+
3+
Example commands:
4+
python gen_postprocessed_results_jobs.py
5+
"""
6+
from copy import deepcopy
7+
import os
8+
import re
9+
import sys
10+
11+
from run_on_cluster import fb_run_batch as func
12+
from pem_jobs import run as pemrun
13+
14+
15+
code_directory = '/private/home/cinjon/Code/BSN-boundary-sensitive-network.pytorch'
16+
17+
base_dir = '/checkpoint/cinjon/spaceofmotion/bsn'
18+
checkpoint_path = os.path.join(base_dir, 'checkpoint', 'pem')
19+
pem_dir = os.path.join(base_dir, 'peminf')
20+
pem_results_dir = os.path.join(pem_dir, 'results')
21+
postprocessed_results_dir = os.path.join(base_dir, 'postprocessing')
22+
23+
regex = re.compile('.*ckpt.*-(\d{5}).*')
24+
num_gpus = 0
25+
26+
27+
for pem_results_subdir in os.listdir(pem_results_dir):
28+
counter = int(regex.match(pem_results_subdir).groups()[0])
29+
job = pemrun(find_counter=counter)
30+
31+
name = job['name']
32+
for ckpt_subdir in os.listdir(os.path.join(pem_results_dir, pem_results_subdir)):
33+
_job = deepcopy(job)
34+
_job['module'] = 'Post_processing'
35+
dirkey = '%s/%s' % (pem_results_subdir, ckpt_subdir)
36+
_job['postprocessed_results_dir'] = os.path.join(postprocessed_results_dir, dirkey)
37+
_job['pem_inference_results_dir'] = os.path.join(pem_results_dir, dirkey)
38+
if 'thumos' in _job['dataset']:
39+
_job['video_info'] = _job['video_info'].replace('Full_Annotation.csv', 'thumos14_test_groundtruth.csv')
40+
_job['name'] = '2019.09.18.%s.%s' % (pem_results_subdir, ckpt_subdir)
41+
_job['num_gpus'] = num_gpus
42+
_job['num_cpus'] = 48
43+
_job['gb'] = 64
44+
_job['time'] = 4
45+
46+
func(_job, counter, email, code_directory)

gen_tem_results_jobs.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
1515
code_directory = '/private/home/cinjon/Code/BSN-boundary-sensitive-network.pytorch'
16-
# anno_directory = '/private/home/cinjon/Code/BSN-boundary-sensitive-network.pytorch/data/gymnastics_annotations'
16+
1717
base_dir = '/checkpoint/cinjon/spaceofmotion/bsn'
1818
tem_dir = os.path.join(base_dir, 'teminf')
1919
tem_results_dir = os.path.join(tem_dir, 'results')
@@ -23,9 +23,6 @@
2323

2424
regex = re.compile('.*(\d{5}).*')
2525

26-
now = datetime.datetime.now()
27-
print(now)
28-
2926
for ckpt_subdir in os.listdir(ckpt_directory):
3027
counter = int(regex.match(ckpt_subdir).groups()[0])
3128
if counter not in [195]:

0 commit comments

Comments
 (0)