代码链接:https://github.com/wzmsltw/BSN-boundary-sensitive-network
下载代码并解压。提取视频特征用的是https://github.com/yjxiong/temporal-segment-networks中的TSN模型,预训练的TSN模型在https://github.com/yjxiong/anet2016-cuhk,作者提取好的ActivityNet的特征在https://pan.baidu.com/s/19GI3_-uZbd_XynUO6g-8YQ#list/path=%2F,下载完毕后,执行:
cat zip_csv_mean_100.z* > csv_mean_100.zip
unzip csv_mean_100.zip
cp -r csv_mean_100 ./data/activitynet_feature_cuhk/
解压时遇到问题
Archive: csv_mean_100.zip
error: End-of-centdir-64 signature not where expected (prepended bytes?)
(attempting to process anyway)
warning [csv_mean_100.zip]: zipfile claims to be last disk of a multi-part archive;
attempting to process anyway, assuming all parts have been concatenated
together in order. Expect "errors" and warnings...true multi-part support
doesn't exist yet (coming soon).
warning [csv_mean_100.zip]: 5242880000 extra bytes at beginning or within zipfile
(attempting to process anyway)
file #1: bad zipfile offset (local header sig): 5242880004
(attempting to re-compensate)
不知道是cat的时候出了问题还是unzip啥的版本环境不对,直接在windows上unzip最小的那个文件zip_csv_mean_100.zip就可以顺利解压了
1、训练时序评估模块
python TEM_train.py
将形状为(16, 100, 400)的输入,经过3层same padding的一维卷积和一层sigmoid层,变为形状为(16, 100, 3)的输出,第三维的三个维度分别为动作概率、起始概率和结束概率。
训练好的时序评估模型在./model/TEM
问题:
(1)第3个一维卷积层的输出乘上了0.1的用意
(2)(16, 100, 400)中,三个维度分别代表什么,16等于batch size,那么是代表16个视频还是16个snippets
(3)划分的测试集用了吗,用在哪里了?
2、测试时序评估模块
sh mkdir.sh #建立output文件夹
python TEM_test.py
TEM_test.py文件中,加载了1中训练好的时序评估模型,输出保存在./output/TEM_results/,对应着19228个视频,这个路径下会生成19228个csv文件,每个文件的数据内容分为5列,action,start,end,xmin,xmax,有100行,其中,action,start,end三列的数据是将视频特征(从作者提供的19228个视频中的的特征中读取的)送入TEM得到的输出,而xmin是0.0,0.01,0.02,……,0.99,xmax是0.01,0.02,0.03,……,,1.0。
问题:
(1)那些anchor_xmin:0.0, 0.01, 0.02, ***, 0.99,anchor_xmax:0.01, 0.02, 0.03, ***, 1.0有啥用,还stack到输出里去了
(2)开始窗口和结束窗口的区间都是加减length/2
(3)生成batch_video_list的过程中,是将全部的19228个视频分为了1202个batch,每个batch包括16个视频,但这样的话之前划分的训练集、验证集和测试集呢,现在测试用的数据不是有四分之三已经在之前见过了吗
3、产生候选片段
sh run_pgm_proposal.sh
实际上运行的是PGM_proposal_generation.py,按照json文件中的视频名字,每次处理2500个视频,分8次处理,输出的是,对于每个视频都生成一个csv文件,里面记录的是xmin(起始位置),xmax(结束位置),xmin_score(起始位置的起始概率),xmax_score(结束位置的结束概率),score(起始位置的起始概率与结束位置的结束概率的乘积),match_iou,match_ioa的值,输出保存在./output/PGM_proposals/,一共有19228个文件。具体步骤:按顺序读取TEM_test.py生成的19228个文件,对于1个文件/视频,先找到符合条件的开始点和结束点,条件就是,要么是个概率峰值,要么大于这个文件/视频的最大开始/结束概率的一半;找到符合条件的开始点和结束点后,只要开始点小于结束点,就可以组成一个proposal;计算proposal和groundtruth的IoU和Ioa。有些视频可能没有annotations(来自./data/activitynet_annotations/anet_anno_action.json),即没有动作的开始和结束时间,所以无法计算IoU和Ioa,这些视频的对应文件就只有xmin(起始位置),xmax(结束位置),xmin_score(起始位置的起始概率),xmax_score(结束位置的结束概率),score(起始位置的起始概率与结束位置的结束概率的乘积)五列。
问题:
(1)start_bins中记录的是可以算作开始的点,为啥第一个和最后一个要先标为1?
(2)star_bins的点的两个判别条件,其中一个与文中不同
(3)最后生成的文件的每一列的意思
4、产生BSP特征
读取./output/PGM_proposals/的文件内容作为pdf,读取./output/TEM_results/的文件内容作为adf,如果是训练,取pdf的前500行,如果不是,则取前1000行。(1)对于adf中的动作得分(???),原本维度为100,在前后分别连接维度为35的一维数组,最后变成维度为170的一维数组,作为插值函数中的y;再建立一个长度同样为170的list,数值为-0.345到1.345,间隔为0.01,作为插值函数中的x。(2)对于pdf中的候选,对于其中每一个候选,都要生成一个bsp特征。具体步骤为:对于起始点,再使用pdf中的起始位置和结束位置,得到新的25个x的坐标,按照前面的插值函数,得到新的25个y坐标,然后对于0~3,3~6,6~9,9~12,12~15,15~18,18~21,21~24位置上的元素分别求平均,得到最后的8个值。对于结束点,按照同样的方法得到8个值。对于动作,是得到新的49个x的坐标,再得到新的49个y坐标,然后对于0~3,3~6,6~9,9~12,……,42~45,45~48位置上的元素分别求平均,得到最后的16个值。最后连接新的动作向量,起始向量和结束向量,得到BSP特征,是一个长度为32的一维数组(3)输出保存在"./output/PGM_feature/",每个视频对应着一个文件,每个文件都保存了一个数组,数组的形状为n*32,n为候选的数量。
sh run_pgm_feature.sh
输出保存在./output/PGM_feature/,有19228个文件
5、训练候选评估模型
python PEM_train.py
输入是5种信息(来自./output/PGM_proposals/的match_iou,match_ioa,xmin和xmax信息,和来自./output/PGM_feature/的特征信息,但只取前500行),再将特征信息、iou和ioa信息,按batch存放,将一个batch的iou信息和特征信息送入模型,得到的loss分为三部分——iou_loss,num_iou,l2,将所有batch的iou_loss和l2的平均值分别存入train_info。模型信息保存在models/PEM/,本轮的模型保存为pem_model_checkpoint,如果本轮验证比之前的验证loss更小的话则保存为最佳模型pem_model_best。
6、测试候选评估模型
python PEM_test.py
在models/PEM/pem_model_best加载最好的候选评估模型,输入验证集数据,数据内容为来自./output/PGM_feature/的bsp_feature和来自./output/PGM_proposals/的xmin_score, match_iou, xmax, xmax_score, xmin, match_ioa,都只取前1000行。再将特征信息、iou和ioa信息,按batch存放,将一个batch的特征信息送入模型,输出为得分,输出的文件保存在./output/PEM_results/,有4728个文件,即分别对应着验证集中的4728个视频。文件格式为5列,xmin,xmax,xmin_score,xmax_score,iou_score,其中,xmin,xmax,xmin_score,xmax_score都是直接从原本./output/PGM_proposals/中的信息赋值来的,而iou_score是模型输出的得分。
7、后处理,产生最终的结果
python Post_processing.py
读取./output/PEM_results/的数据,原本为xmin,xmax,xmin_score,xmax_score,iou_score五列,新增一列score,为iou_score,xmin_score和xmax_score的乘积。如果一个视频对应了多个proposal,则进行soft-NMS,处理过后,形状变为了101*3,3代表3列,分别为score,xmin和xmax。如果经过soft-NMS处理之后,proposal的数量仍然大于100,则只取score得分最大的前100个proposal(所以为什么要刻意处理为101个呢),若小于100,则都保留,然后以这些proposal的xmin和xmax乘上视频长度(单位为s),得到这个proposal的真正的开始和结束时间,存入proposal_list。再将每个视频的proposal_list对应着视频名字存入字典result_dict,最后保存为json文件./output/result_proposal.json。
Soft-NMS的过程:输入是来自./output/PEM_results/的数据,这里的数据原本是五列,又增加了一列score,共六列,行数最多1000(因为第6步中只取了前1000行,但也有不足1000行的)。(1)将这些数据按score分数大小降序排列,即第一行score最大,最后一行score最小,用tstart记录这些数据中的所有xmin信息,用tend记录这些数据中的所有xmax信息,用tscore记录这些数据中的所有score信息。(2)找出tscore中最大值的索引,对于其他所有score值不是最大的候选片段,计算它跟score值最大的候选片段之间的IOU,记为tmp_iou,将score值最大的候选片段的长度记为tmp_width,如果tmp_iou大于0.65+0.25*tmp_width(???什么用意???),则这个候选的score修改为e^(-0.75*tmp_iou*tmp_iou)*原score。(3)处理完所有除score最大值候选片段之外的候选片段后,将当前score最大值的候选片段的tstart、tend、tscore信息分别添加到rstart、rend和rscore中,而从原本的tstart、tend、tscore中移除。(4)重新进行第二步,直到tscore的长度小于等于1或者rscore的长度大于101。(5)循环终止后,将最终的rstart、rend和rscore保存下来
在ActiviNet-1.3上,θ为0.8,而THUMOS14上为0.65,两个数据集上ε都是0.75,但作者代码里的是θ=0.65+0.25*tmp_width,为什么???
8、评估候选片段
python eval.py
max_avg_nr_proposals如果没有指定,则等于候选片段的数量除以groundtruth中视频的数量,ratio等于max_avg_nr_proposals乘以groundtruth中视频的数量再除以proposal的数量(这样计算的话这个ratio当然是约等于1啊,有什么作用呢???)。(1)读取上一步生成的./output/result_proposal.json作为最后的候选片段,格式为'video-id, 't-start', 't-end', 'score'四列,读取./Evaluation/data/activity_net_1_3_new.json作为groundtruth,格式为'video-id', 't-start', 't-end'三列。(2)按video-id将候选片段和groundtruth分别分类,对于某一个video-id,先取出对应着这个video-id的候选片段,再将其按score顺序排列。(3)得到这个video-id的groundtruth,即动作的开始和结束时间。(4)如果这个video-id没有对应的候选片段,则记录这个视频对应着几个groundtruth,并向score_lst添加同样多的0。如果有对应的候选片段,则最后保留的proposals的数量等于候选片段的数量*ratio与候选片段的数量本身之间更小的值(按顺序取前多少个就好了)。(5)计算保留的proposal跟这个视频对应的所有groundtruth的tiou得分,形状为
(候选数量,groundtruth数量),并将其存入score_lst。