-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 103 KB
/
content.json
1
{"meta":{"title":"LJK' Notes","subtitle":null,"description":"正值年少,撸铁,撸串,撸代码!","author":"LJK","url":"http://yoursite.com","root":"/"},"pages":[{"title":"categories","date":"2019-05-06T12:00:21.000Z","updated":"2019-05-06T12:00:53.967Z","comments":true,"path":"categories/index.html","permalink":"http://yoursite.com/categories/index.html","excerpt":"","text":""},{"title":"About","date":"2019-05-06T12:09:25.000Z","updated":"2019-08-01T02:27:19.071Z","comments":true,"path":"about/index.html","permalink":"http://yoursite.com/about/index.html","excerpt":"","text":"The blogs is the index of brain!"},{"title":"tags","date":"2019-05-06T12:08:33.000Z","updated":"2019-05-06T12:09:05.071Z","comments":true,"path":"tags/index.html","permalink":"http://yoursite.com/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"Memory-Guided-Video-Detection-CVPR19","slug":"Memory-Guided-Video-Detection-CVPR19","date":"2019-08-01T03:51:20.000Z","updated":"2019-08-13T03:52:48.439Z","comments":true,"path":"2019/08/01/Memory-Guided-Video-Detection-CVPR19/","link":"","permalink":"http://yoursite.com/2019/08/01/Memory-Guided-Video-Detection-CVPR19/","excerpt":"Memory-Guided-Video-Detection-CVPR19 Looking Fast and Slow: Memory-Guided Mobile Video Object Detection Paper: https://arxiv.org/abs/1903.10172 Code: https://github.com/tensorflow/models/tree/master/research Overview 提出了memory-guided的多特征网络提取的网络结构,使用快/慢特征提取网络分别提取不同帧特征,可以减少冗余计算。 使用Double Q-learning强化学习策略来执行memory更新,进行特征提取网络的选择。 在移动设备上可以实现高精度,高速度(70fps)。","text":"Memory-Guided-Video-Detection-CVPR19 Looking Fast and Slow: Memory-Guided Mobile Video Object Detection Paper: https://arxiv.org/abs/1903.10172 Code: https://github.com/tensorflow/models/tree/master/research Overview 提出了memory-guided的多特征网络提取的网络结构,使用快/慢特征提取网络分别提取不同帧特征,可以减少冗余计算。 使用Double Q-learning强化学习策略来执行memory更新,进行特征提取网络的选择。 在移动设备上可以实现高精度,高速度(70fps)。 why 作者将video object detection大致分为三类。 后处理方法。使用单帧检测的方式,然后与前帧中的track进行数据关联。seq-nms通过动态编程和提高弱检测的置信度来进行跟踪。TCNN使用光流法来传播检测,同时使用跟踪算法寻找tubelets来重评分。缺点是仍然是在每帧上做检测。(看描述感觉是多目标跟踪) 特征流方法。将网络的中间特征通过光流方式传播。DFF在稀疏关键帧上进行检测,然后再其他所有帧上按照计算光流的方式进行传播。FGFA通过相邻帧与当前帧特征进行加权平均。 多帧方式。即同时对多帧做处理。D&T做了检测和跟踪的结合,使用了ROI tracking和相邻帧loss的方法。STSN使用DCN来采样相邻帧特征。缺点是仍然需要高精度检测而不是直接使用之前帧的检测结果。 稀疏处理视频帧有很多方式,从固定间隔,到启发式策略。文中使用强化学习方式来构建关键帧选择策略。 what 交叉模型。使用memory guided策略,结合多个特征(大/小)提取网络,大/小网络在视频检测过程中交替使用。 使用DDQN强化学习策略来选取网络使用策略来进行memory更新。 how 交叉模型结构。多个特征提取器顺序或同时执行,提取的feature通过memory机制进行增强/调整。 memory模型。在LSTMs的基础上,对LSTM cell进行了三点改进,融合不同特征提取器的feature。 在bottleneck和output之间添加了skip connection。 使用channel-wise的方式,将LSTM state等分为G组,然后使用组卷积。 使用state skip update方法。相当于跳过f1的状态更新,直接使用之前f0的状态。这是因为LSTM中sigmoid的缺点,在多次更新之后几乎会完全遗忘之前的状态。 DDQN寻找自适应交叉策略 动作空间。包含m个动作。 状态空间。S = (ct,ht,ct − ct−1,ht − ht−1,ηt) ,当前LSTM的状态,状态的相对之前改变,动作的历史参数(长度为20的向量,运行的前k步是1,其余是0) 奖励函数。速度奖励 + 精度奖励,给出γ奖励。其中,L(Di)为使用feature_i做检测的loss。 DDQN的网络结构如下。 result","categories":[{"name":"Video Detection","slug":"Video-Detection","permalink":"http://yoursite.com/categories/Video-Detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Bottleneck-LSTM-Video-Object-CVPR18","slug":"Bottleneck-LSTM-Video-Object-CVPR18","date":"2019-07-31T06:20:33.000Z","updated":"2019-08-13T03:51:24.481Z","comments":true,"path":"2019/07/31/Bottleneck-LSTM-Video-Object-CVPR18/","link":"","permalink":"http://yoursite.com/2019/07/31/Bottleneck-LSTM-Video-Object-CVPR18/","excerpt":"Bottleneck-LSTM-Video-Object-Detection-CVPR18 Bottleneck-LSTM:Mobile Video Object Detection with Temporally-Aware Feature Paper: https://arxiv.org/abs/1711.06368 Code: https://github.com/tensorflow/models/tree/master/research Overview 构建Conv Bottleneck-LSTM,并将Bottleneck-LSTM与one stage检测相结合。其中,Bottleneck-LSTM借鉴了深度可分离卷积和bottleneck。 在video detection中的速度,相比现存检测算快,FPS为15(个人感觉比较慢)。","text":"Bottleneck-LSTM-Video-Object-Detection-CVPR18 Bottleneck-LSTM:Mobile Video Object Detection with Temporally-Aware Feature Paper: https://arxiv.org/abs/1711.06368 Code: https://github.com/tensorflow/models/tree/master/research Overview 构建Conv Bottleneck-LSTM,并将Bottleneck-LSTM与one stage检测相结合。其中,Bottleneck-LSTM借鉴了深度可分离卷积和bottleneck。 在video detection中的速度,相比现存检测算快,FPS为15(个人感觉比较慢)。 why 现存常规的检测器,针对视频检测速度较慢,无法达到实时。 有一部分没有考虑视频检测中的时序信息。 同时部分使用光流的方法存在速度较慢的劣势。 使用LSTM的方法并没有将LSTM和卷积网络完全融合。 LRCNs将每帧的feature序列输入LSTM ROLO使用YOLO做检测,然后将检测的BBox和feature送入到LSTM what 使用CNN提取图像特征,然后将特征送入convolutional LSTM进行历史帧特征融合(记忆重要信息,特征结合),输出。 how 大体思路。使用前t帧的图像,前t-1帧的feature,来获取当前帧的bboxes和分类置信度。F(I_t,S_t-1) = (D_t , S_t)其中,I_t表示第t帧的视频序列,S_t-1表示前t-1帧的feature,D_t表示相对于I_t帧的bboxes和confidences集合 LSTM-SSD中SSD的网络结构更换为MobileNet,并使用深度可分离卷积代替了所有的常规卷积。 Bottleneck-LSTM。借鉴了深度可分离卷积,bottleneck。 Conv LSTM的定义。其中,M,N分别为LSTM输入/输出的通道数。LSTM将x_t和h_t-1(featue map)进行channel-wise操作,输出h_t和c_t,W(j,k)⭐X代表深度可分离卷积操作,j表示输入通道,k表示输出通道,o表示矩阵对应元素相乘,∮表示ReLU激活函数。 使用如下的b_t代替所有门的输入。 添加通道调整超参数a_base = a,a_lstm = 0.5a,a_ssd = 0.25a来分别控制不同网络模块通道维度,从而来控制网络的计算量。 优势:减少了标准LSTM中的计算;BottleNeck-LSTM的网络结构更深,效果更好。 具体实现 单个LSTM模块的网络结构。 首先finetune 无LSTM的SSD网络,freeze基准网络(到conv13),然后在train的时候添加LSTM模块。最终在conv13之后的所有feature map后都添加了LSTM模块作为最终模型。 result 单个LSTM模块,mAP相对提升3.2% 单个LSTM模块,在参数量,和计算量方面的对比,大约可以减少10-20倍的参数量,减少20倍左右的计算量。其中MAC代表multi-adds。 多个LSTM模块,LSTM模块的重复堆叠没有提升,多层放置LSTM的效果会比单个放置提高0.9%,计算量不会有太大变化。","categories":[{"name":"Video Detection","slug":"Video-Detection","permalink":"http://yoursite.com/categories/Video-Detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Object Detection Summary","slug":"object-detection-summary","date":"2019-07-10T10:07:38.000Z","updated":"2019-08-01T01:56:38.351Z","comments":true,"path":"2019/07/10/object-detection-summary/","link":"","permalink":"http://yoursite.com/2019/07/10/object-detection-summary/","excerpt":"目标检测(待完善)简述 one-stage 主要思想:均匀地在图片的不同位置进行密集抽样,抽样时可以采用不同尺度和长宽比,然后利用CNN提取特征后直接进行分类与回归,整个过程只需要一步 代表:Yolo,SSD 特点:速度快,准确率一般没有two-stage高 two-stage 主要思想:一阶段生成proposals,二阶段对这些proposals进行分类和回归 代表:R-CNN,Fast R-CNN, Faster R-CNN","text":"目标检测(待完善)简述 one-stage 主要思想:均匀地在图片的不同位置进行密集抽样,抽样时可以采用不同尺度和长宽比,然后利用CNN提取特征后直接进行分类与回归,整个过程只需要一步 代表:Yolo,SSD 特点:速度快,准确率一般没有two-stage高 two-stage 主要思想:一阶段生成proposals,二阶段对这些proposals进行分类和回归 代表:R-CNN,Fast R-CNN, Faster R-CNN R-CNN - 2013.11 - mAP:58.5网络结构 步骤 找出候选框; 利用CNN提取特征向量; 利用SVM进行特征向量分类(N个SVM分类器)。 selective search 首先通过基于图的图像分割方法初始化原始区域,就是将图像分割成很多很多的小块。 然后我们使用贪心策略,计算每两个相邻的区域的相似度(纹理/颜色/大小),然后每次合并最相似的两块,直到最终只剩下一块完整的图片。 然后这其中每次产生的图像块包括合并的图像块我们都保存下来,这样就得到图像的分层表示。特点/改进点 使用selective search提取预测框。 使用CNN进行特征提取。优/缺点 优点 是CNN在目标检测领域得开篇之作,变检测问题为分类问题。 缺点 需要训练三个模型(proposal,CNN,Regression) selective search仍然十分耗时 存在大量得重复计算 Fast RCNN - 2015.04 - mAP:70,fps:0.5网络结构特点/改进点优/缺点YOLO v1 - 2015.06 - mAP:63.4,fps:45网络结构 步骤 对输入图像进行网格划分。 使用CNN网络生成对应大小的feature map,最后使用两个FC层来进行预测。特点/改进点 抛弃了滑动窗口和RCNN中selective search的方法,而是将image切分为7x7的网格,利用卷积生成相同大小的feature map来进行预测。优/缺点 优点 速度很快,155fps 不容易对背景误判 缺点 每个cell预测2个bbox,但共享一个类别,对密集物体表现不好。 定位不精准 对小物体不友好 Faster RCNN - 2015.06 - mAP:73.2,fps:7网络结构 步骤 阶段一,特征提取。 阶段二,使用RPN提取ROIs,并对其中部分样本(256)进行二分类和回归,NMS过滤。 阶段三,使用ROI Pooling,对ROIs中的部分ROI进行Pooling操作统一到相同尺度,在做分类和回归,NMS过滤。 特点/改进点 使用RPN网络代替selective search,极大减少了生成proposals的时间。 两阶段(粗分类/回归+细分类/回归),可以获得更高的精度。优/缺点 优点 检测精度极大提升 缺点 速度比Yolo慢 SSD - 2015.12 - mAP:72.1,fps:58网络结构 步骤 输入图像可以为300x300/512x512 使用CNN(VGG16改装版)进行特征提取。 结合5层不同尺度的feature map进行不同尺度(anchors)物体的预测。特点/改进点 改Yolo的FC层预测为卷积预测,每个预测框输出一套对应的检测值。 使用了FPN(5层)。 借鉴了Faster RCNN的anchor。优/缺点 优点 准确度比Yolo好 对小物体的检测也比Yolo好 YOLO v2 - 2016网络结构特点/改进点 高分辨率输入 BN层 卷积预测 + anchors 边界框聚类分析 DarkNet-19 位置预测限定(沿用Yolo v1思想) pass through层(信息融合) 多尺度输入训练优/缺点 优点 引入了其他文章的点,性能提升很多 缺点 对小物体的检测仍然不友好 YOLO v3 - 2017网络结构特点/改进点 使用了FPN结构 DarkNet-53 Loss Function: softmax -> logistic loss优/缺点 优点 对小物体的检测有很好的改善 性能提升","categories":[{"name":"objection","slug":"objection","permalink":"http://yoursite.com/categories/objection/"}],"tags":[{"name":"objection","slug":"objection","permalink":"http://yoursite.com/tags/objection/"}]},{"title":"Faster-rcnn-NIPS2015-detection","slug":"faster-rcnn-detection","date":"2019-07-10T03:16:30.000Z","updated":"2019-08-01T15:07:49.259Z","comments":true,"path":"2019/07/10/faster-rcnn-detection/","link":"","permalink":"http://yoursite.com/2019/07/10/faster-rcnn-detection/","excerpt":"Faster-rcnn-NIPS2015 Faster RCNN:Towards Real-Time Object Detection with Region Proposal Networks Paper:https://arxiv.org/abs/1506.01497 Code :https://github.com/chenyuntc/simple-faster-rcnn-pytorch 参考:https://zhuanlan.zhihu.com/p/32404424 Overview 使用RPN代替了耗时的selective search操作。 大致过程如下图。特征提取,RPN提取ROI(二分类+回归),ROI Head(多分类+回归)","text":"Faster-rcnn-NIPS2015 Faster RCNN:Towards Real-Time Object Detection with Region Proposal Networks Paper:https://arxiv.org/abs/1506.01497 Code :https://github.com/chenyuntc/simple-faster-rcnn-pytorch 参考:https://zhuanlan.zhihu.com/p/32404424 Overview 使用RPN代替了耗时的selective search操作。 大致过程如下图。特征提取,RPN提取ROI(二分类+回归),ROI Head(多分类+回归) why 基于selective search的方法速度太慢。 二阶段(粗细粒度的筛选),可以使得检测的精度极大提升。 what 主要贡献在于,使用RPN替代了selective search方法。 Faster RCNN可主要分为三个阶段。 阶段一,特征提取。 阶段二,使用RPN提取ROIs,并对其中部分样本(256)进行二分类和回归,NMS过滤。 阶段三,使用ROI Pooling,对ROIs中的部分ROI进行Pooling操作统一到相同尺度,在做分类和回归,NMS过滤。 how Faster RCNN主要分三步:特征提取,RPN提取ROIs(二分类+回归),ROI Head/Pooling(多分类+回归)Feature Extractor 一般使用与训练好的VGG16,前4层的卷积的学习率设为0(为节省显存),Conv5_3的feature作为输出;VGG最后的三层全连接层的前两层,一般用来初始化RoIHead的部分参数。RPN 每个位置使用的anchor个数为9个,所以整张图大概会生成20000个anchors。 RPN结构3x3的卷积不太清楚什么用意?后接两个1x1的卷积分别用于二分类(9x2)和位置回归(9x4)。 AnchorTargetCreatorRPN利用AnchorTargetCreator从20000个anchor中选取256个做分类和回归。 计算所有anchors与GT的iou,每个GT对应IOU最高的anchor作为正样本。 其余样本随机选择与GT的iou大于阈值0.7的样本作为正样本。 随机选择与GT的iou小于阈值0.1的样本作为负样本。正负样本的比例大概为1:1,总数为256。 ProposalCreatorRPN利用ProposalCreator生成ROIs。 计算20000个anchors属于前景的概率,对应的位置参数 选取概率较大的12000个anchors,利用回归的位置参数修正这些anchors 使用NMS,选择出anchors最大的2000个ROIs inference时候,12000,2000分别对应6000,300 损失计算 分类损失,使用交叉熵。 回归损失,使用Smooth L1 lossROI Head/pooling ProposalTargetCreator ROIs和GT的iou大于0.5的选择32个。 ROIs和GT的iou小于0/1的选择96个。 ROI Pooling在RPN提供的2000个ROIs上,首先使用ProposalTargetCreator挑选128个ROIs,然后使用ROI Pooling将其pooling到统一的尺寸(128x512x7x7,ROI pooling是为了共享权重),继续进行分类和回归。FC21用来分类,20+1背景;F84用来回归,21x4。 损失计算 分类,交叉熵;回归,Smooth L1 loss 回归,只对ROI中的正样本计算loss 小结 RPN阶段是前/背景的二分类,ROIHead是21分类 RPN阶段,ROIHead阶段都做了NMS RPN阶段,ROIHead阶段都进行了回归Loss 4种损失加权求和 RPN分类/回归损失,ROI分类/回归损失 result mAP为0.699,fps为5","categories":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/categories/detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Yolo-v3-CVPR2018-detection","slug":"Yolo-v3-detection","date":"2019-07-09T08:54:47.000Z","updated":"2019-07-09T10:53:07.513Z","comments":true,"path":"2019/07/09/Yolo-v3-detection/","link":"","permalink":"http://yoursite.com/2019/07/09/Yolo-v3-detection/","excerpt":"Yolo v3-2018 YOLOv3: An Incremental Improvement Paper:https://pjreddie.com/media/files/papers/YOLOv3.pdf Code:https://github.com/marvis/pytorch-yolo3 why 针对Yolo v1/2中对小物体不友好的问题。 深层网络DarkNet-53替换。","text":"Yolo v3-2018 YOLOv3: An Incremental Improvement Paper:https://pjreddie.com/media/files/papers/YOLOv3.pdf Code:https://github.com/marvis/pytorch-yolo3 why 针对Yolo v1/2中对小物体不友好的问题。 深层网络DarkNet-53替换。 what 使用FPN解决小物体检测问题。 DarkNet-19 + 残差结构实现深层网络结构替换。 loss更换。 how FPN Yolo v3在输入为416x416时,使用了3个尺度的特征图,52,26,13,feature map上每个点使用3个先验框,则先使用k-means获取9个box,再将这些box按照尺度大框小,尺度小框大的原则分别分配给3个特征图。 Darknet-53 loss 损失函数由v2的softmax loss替换为logistic loss softmax的归一化操作则意味着每个候选框只对应着一个类别,当预测的目标类别很复杂(多个相似类别)的时候,采用logistic regression进行分类,但是可以输出多个分类,比如说,男人,人。","categories":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/categories/detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Yolo-v2-CVPR17-detection","slug":"Yolo-v2-detection","date":"2019-07-09T01:59:23.000Z","updated":"2019-07-10T08:43:21.233Z","comments":true,"path":"2019/07/09/Yolo-v2-detection/","link":"","permalink":"http://yoursite.com/2019/07/09/Yolo-v2-detection/","excerpt":"Yolo v2 2017 Yolo-v2(YOLO9000): Better, Faster, Stronger Paper:https://arxiv.org/abs/1612.08242 Code: https://github.com/marvis/pytorch-yolo2 Overview 基于Yolo v1做了诸多改进。针对Yolo v1定位不精准,召回率低,对小物体不友好的问题,提出了位置限定预测,Anchor+卷积预测,pass-through操作等。 同时,引入了BN,高分辨率输入,边界框聚类分析,darnet-19,多尺度训练等,提高了检测性能。 最终在输入为544x544时,VOC07上mAP可达到78.6,相对应的fps为40(不同输入对应不同结果)","text":"Yolo v2 2017 Yolo-v2(YOLO9000): Better, Faster, Stronger Paper:https://arxiv.org/abs/1612.08242 Code: https://github.com/marvis/pytorch-yolo2 Overview 基于Yolo v1做了诸多改进。针对Yolo v1定位不精准,召回率低,对小物体不友好的问题,提出了位置限定预测,Anchor+卷积预测,pass-through操作等。 同时,引入了BN,高分辨率输入,边界框聚类分析,darnet-19,多尺度训练等,提高了检测性能。 最终在输入为544x544时,VOC07上mAP可达到78.6,相对应的fps为40(不同输入对应不同结果) why Yolo v1虽然检测速度很快,但是定位精度不准,物体定位不准确,召回率低,对小物体不友好,精度效果不如RCNN好。 what Batch Normalization 在Yolo v2中每一个卷积层之后,都添加BN层,抛弃Dropout。 BN可以提高模型的收敛速度,起到一定的正则化效果,防止模型过拟合。 使用BN后,mAP提高了2.4% 高分辨率输入 在Yolo v2中,使用448x448高分辨率输入,抛弃224x224低分辨率输入。 低分辨率不利于检测模型。因为在ImageNet上的预训练模型使用的为224x224的输入,在检测数据上使用448x448进行finetune效果不好;Yolo v2增加了在ImageNet上使用448x448输入来finetune的步骤,使模型可以适应检测数据上的高分辨率输入。 使用高分辨率后,mAP提高了4% 卷积预测+Anchors 更换FC层预测为Conv预测,同时使用anchor box。 Yolo v2采用416x416的输入,stride为32,是为了保证最后feature map的大小为奇数(13x13),其包含一个中心点,对于一些大物体,中心点通常落到图片的中心位置,使用feature map中心点去预测这些物体会相对容易。 Yolo v2对于每一个anchor box都独立预测一套分类概率 使用anchor之后,召回率提高了7% 边界框聚类分析 Yolo v2使用K-means,对训练集中的边界框使用box与中心box的IOU值作为指标进行聚类分析,改善在Faster RCNN和SSD中人工设定先验框的主观性。Yolo v2最终选取5个聚类中心作为先验框。 对于不同的数据集可以分析出更合适的先验框尺度,可以更贴近数据集中gt的尺度。 使用聚类分析后,mAP提高了0.4% DarkNet-19 使用特征提取网络,抛弃GoogLeNet结构。 DarkNet-19使用19个卷积层和5个max pool层,使用7个1x1卷积来减少参数/计算量。最后一层使用global avgpooling(滑窗大小=feature map大小)。 计算量减少33% 位置预测限定 沿用Yolo v1的思想,预测边界框中心点相对于对应cell左上角的偏移量,相当于把中心点约束在当前的cell内。抛弃无约束的位置预测。 其中,bx,by,bw,bh分别为feature map上预测框的中心点坐标和宽高;cx,cy为cell左上角的坐标(每个cell的大小都为1x1);tx,ty,tw,th分别为预测的坐标偏移量;pw,ph为先验框的宽高;W,H为特征图的大小。img_w,img_h为原始图的宽高。 边界框的最终位置为:bx / W img_w,by / H img_h,bw / W img_w,bh / H img_h 使用该约束预测 + 聚类分析,mAP提升5% pass through层 pass through层将DarkNet-19中最后一个max pooling层的输入(26x26x256)进行pass through变换操作得到(13x13x2048),与输出(13x13x1024)进行连接得到(13x13x3072),然后卷积在该特征图上进行预测。 该操作使mAP提高了1% 多尺度输入训练 采用不同大小的图片作为输入,使其可以适应多种大小的图片输入。 每个10个迭代周期,随机选择一种输入大小(必须为32的倍数,如320,352…608),同时对最后检测层进行修改后训练。 how 训练过程 阶段一,使用输入大小为224x224,在ImageNet分类数据集上对DarkNet-19进行预训练。 阶段二,调整输入大小为448x448,继续在ImageNet分类数据集上对DarkNet-19进行fine-tune。 阶段三,修改分类模型为检测模型,在检测数据集上进行fine-tune。网络修改包括(网路结构可视化):移除最后一个卷积层、global avgpooling层以及softmax层,并且新增了三个 3x3卷积层,同时增加了一个passthrough层,最后使用1x1卷积层输出预测结果。 损失函数 第一部分为,背景(iou小于设定阈值)的置信度误差。 第二部分为,先验框与预测框的坐标误差,只在前12800次迭代中计算。 第三部分为,计算与gt匹配的预测框的各部分的loss,坐标误差,置信度误差,分类误差。一个gt只匹配一个预测框,其余的大于iou阈值的预测框的loss不计算。而且Yolo v1中使用平方根降低box大小对loss的影响,Yolo v2使用权重稀系数来控制loss,尺度小一些的box的权重高一些。 总结 加了很多其他文章的点,性能提升很多,但是对小物体不友好的情况仍然没有改善。 Yolo9000 提出了一种分类和检测联合训练策略。对于检测数据集,可以用来学习预测物体的边界框、置信度以及为物体分类,而对于分类数据集可以仅用来学习分类,但是其可以大大扩充模型所能检测的物体种类。 因为检测和分类两者类别并不完全互斥,所以作者提出了一种层级分类方法。即根据各个类别之间的从属关系立一种树结构WordTree。 WordTree中的根节点为”physical object”,每个节点的子节点都属于同一子类,可以对它们进行softmax处理。在给出某个类别的预测概率时,需要找到其所在的位置,遍历这个path,然后计算path上各个节点的概率之积。 在训练时,如果是检测样本,按照YOLOv2的loss计算误差,而对于分类样本,只计算分类误差。在预测时,YOLOv2给出的置信度,边界框位置,一个树状概率图。在这个概率图中找到概率最高的路径,当达到某一个阈值时停止,就用当前节点表示预测的类别。","categories":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/categories/detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"SSD-CVPR15-detection","slug":"SSD-detection","date":"2019-07-08T08:39:15.000Z","updated":"2019-07-09T08:34:06.481Z","comments":true,"path":"2019/07/08/SSD-detection/","link":"","permalink":"http://yoursite.com/2019/07/08/SSD-detection/","excerpt":"SSD - 2015 SSD: Single Shot MultiBox Detector Paper:https://arxiv.org/pdf/1611.10012.pdf Code:https://github.com/amdegroot/ssd.pytorch Overview SSD与Yolo v1的对比 卷积检测。抛弃FC层采用卷积做检测。SSD每个检测框都对应输出一套独立的检测值。 多尺度特征图。采用多尺度特征图,大尺度检测小物体,小尺度检测大物体。 先验框。采用不同尺度/长宽比的先验框。 速度:58fps。mAP为72.1","text":"SSD - 2015 SSD: Single Shot MultiBox Detector Paper:https://arxiv.org/pdf/1611.10012.pdf Code:https://github.com/amdegroot/ssd.pytorch Overview SSD与Yolo v1的对比 卷积检测。抛弃FC层采用卷积做检测。SSD每个检测框都对应输出一套独立的检测值。 多尺度特征图。采用多尺度特征图,大尺度检测小物体,小尺度检测大物体。 先验框。采用不同尺度/长宽比的先验框。 速度:58fps。mAP为72.1 why 针对Yolo v1存在的定位不精准,对小物体不友好等缺点的改进。 what one-stage检测。均匀地在图像上的不同位置,使用不同的尺度/长宽比进行采样,然后使用CNN提取特征后直接进行分类和回归。 SSD结合了卷积预测,多尺度特征,先验框来改进Yolo v1中存在的缺点。 how 网络结构 输入:300x300/512x512 网络结构①主干网络使用VGG16,分别将VGG16的全连接层fc6和fc7转换成conv6和conv7,移除dropout和fc8层,并增加了卷积层来获得更多的feature map。②Conv6使用扩展卷积,来扩大卷积的感受野。Conv6采用3x3大小但dilation rate=6的扩展卷积。③使用feature map大小分别为38,19,10,5,3,1。不同feature map上设定的先验框数目不同,分别为4,6,6,4,4。④随着特征图大小降低,先验框尺度线性增加。长宽比一般选取{1,2,3,1/2,1/3} 输出①检测值包含两个部分:类别置信度和边界框位置,各采用一次3x3卷积来进行完成。令nk为该特征图所采用的先验框数目,那么类别置信度需要的卷积核数量为nk x C ,而边界框位置需要的卷积核数量为nk x 4。②各个feature map对应:w x h x nk x (C+4) GT 损失函数 位置损失 + 置信度损失。其中N为正样本数, 位置损失 置信度损失 - softmax loss 训练细节 先验框匹配①Yolo是gt所在单元格中与其IOU最大的那个作匹配。②第一步,SSD是找到每个gt与其最大的IOU作匹配,保证每一个gt都一定有一个先验框与之匹配。将匹配的bbox作为正样本,其余为负样本。第二步,将剩余先验框中与gts的iou大于阈值的进行匹配。匹配成功的都是正样本。③再采用hard negative mining,对负样本按照背景置信度误差进行抽样,选取误差最大的topk个,保证正负样本的比例为1:3。 使用了数据增强。裁剪,旋转,扭曲,随机采样等等。 result 数据增强,可以提高9个百分点(65.6 - 74.3)。 多尺度检测,可以提高12个百分点(62.4 - 74.6)。","categories":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/categories/detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Yolo-v1-CVPR2015-detection","slug":"Yolo-v1-detection","date":"2019-07-08T07:26:29.000Z","updated":"2019-07-10T12:42:02.799Z","comments":true,"path":"2019/07/08/Yolo-v1-detection/","link":"","permalink":"http://yoursite.com/2019/07/08/Yolo-v1-detection/","excerpt":"Yolo v1 - 2015 Yolo-v1:You Only Look Once, Unified, Real-Time Object Detection. Paper:https://arxiv.org/abs/1506.02640 Code: https://github.com/gliese581gg/YOLO_tensorflow Overview 经典的one-stage。直接对原图进行网格划分,将原图分为nxn的小块,然后通过卷积产生nxn的特征图,其一一对应,feature map上每个元素预测对应单元格内的分类/置信度/bbox偏移。 速度:155fps,mAP:63.4","text":"Yolo v1 - 2015 Yolo-v1:You Only Look Once, Unified, Real-Time Object Detection. Paper:https://arxiv.org/abs/1506.02640 Code: https://github.com/gliese581gg/YOLO_tensorflow Overview 经典的one-stage。直接对原图进行网格划分,将原图分为nxn的小块,然后通过卷积产生nxn的特征图,其一一对应,feature map上每个元素预测对应单元格内的分类/置信度/bbox偏移。 速度:155fps,mAP:63.4 why DPM采用不同大小和比例(宽高比)的窗口在整张图片上以一定的步长进行滑动,然后对这些窗口对应的区域做图像分类,来实现对整张图片的检测。DPM的缺点,目标大小未知,需要使用不同的大小/比例,步长,计算量很大。 RCNN使用selective search的方法仍然耗时。 what Yolo直接将image分成nxn的网格,然后根据卷积生成相同大小的feature map,feature map上每个元素预测对应单元格内的分类/置信度/bbox偏移。 how 网络结构 输入:448x448的image 划分为7x7的网格。 网络结构backbone:使用了24个卷积层,2个fc层训练过程中的网络结构。在googLenet之后添加了4个随机初始化权重的Conv层和2个fc层。 输出:7x7x30 其中30为20个类别概率,2个置信度,2个bbox的(x,y,w,h),其中,预测的x,y是中心坐标相对于左上角坐标的偏移量,单位是相对于单元格大小的;w,h是相对于整个图片的宽和高的比例;所以xy在[0,1]范围内。 预测tensor示意图。网络计算量:SxSx(Bx5+C) 损失函数 采用MSE损失函数,对于定位损失,分类损失分别采用不同的权重。定位损失使用较大的权重(5),然后分类损失权重分别为(0.5无object,1有object)。 其中,要各个大小bbox要同等对待,但是较小的边界框的误差更敏感,所以将网络bbox的w,h的预测改为了对其平方根的预测。 result 优点 简洁,速度较快,可以达到155fps,mAP为63.4 对整个image做conv,不容易对背景误判 缺点 每个单元格仅预测两个bbox,且共享一个类别,所以对密集物体判别不好。 定位不精准。 对小物体不友好,且无法定位比例不同寻常的物体。","categories":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/categories/detection/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Python内存管理","slug":"python内存管理","date":"2019-07-07T07:36:25.000Z","updated":"2019-08-01T14:52:34.271Z","comments":true,"path":"2019/07/07/python内存管理/","link":"","permalink":"http://yoursite.com/2019/07/07/python内存管理/","excerpt":"Python内存管理 今天在刷复杂链表复制的时候,碰到了这个点,总结一下 python内存管理机制:引用计数,垃圾回收,内存池机制","text":"Python内存管理 今天在刷复杂链表复制的时候,碰到了这个点,总结一下 python内存管理机制:引用计数,垃圾回收,内存池机制 引用计数 python中,对象和引用分离,对于整数int和短小的字符str,python都会缓 存这些对象,用以重复使用,当创建多个相同的对象时,实际上只是让所有这些引用指向同一个对象。 int:-5~256 str:只包含数字和字母的元素有小数据池 + 单个字母*int(21)存在小数据池12345a = 1 b = 1id(a) == id(b) # True 即a,b为1对象的两个引用。a is b # True 用于判断两个引用指向的对象是否相同getrefcount(a) # 判断对象的引用总数,getrefcount会创建一个临时引用,这样会比期望结果多1 长字符串和其他对象可以有多个相同的对象,可以使用赋值语句创造出新的对象. 对象引用对象。例如list,dict等可以包含多个对象,实际上,其中包含的是各个元素对象的引用。 引用减少。可以使用del关键字来删除某个引用,或者引用重定向时,原对象的引用数会减少。 可能会出现引用环问题。python通过对每个对象i引用计数,并会遍历所有对象i,对于每个对象i引用的对象j,将j相应的引用计数减1。然后python会将引用计数为0的回收。 垃圾回收 在python中,当某一对象的引用计数为0时,将会被回收。但是python不会频繁地进行垃圾回收,因为会大大影响python的工作效率,python只会在特定的条件下,自动启动垃圾回收(python运行时,会自动记录其中分配对象和取消分配对象的次数,当两者的差值大于某阈值时,垃圾回收便会启动)。 gc.getthreshold(),可以查看垃圾回收启动的阈值。 分代回收 理解:存活时间越久的对象,越不可能成为垃圾,python会减少这些对象的使用频率。 分代:0,1,2 0代为新建的对象,0代对象每次都会扫描。在0代对象扫描一定次数后,开始扫描1代对象。在1代对象扫描一定次数后,开始扫描2代对象。 内存池机制 python中有大内存和小内存。大内存使用malloc分配,小内存使用内存池分配。 python内存池机制 最上层(3),用户对python对象直接操作 中间层(1,2),内存池,分配256k及以下的内存。malloc分配内存,free不会释放内存,以方便下次使用。 在下层(0),分配大于256k的内存,malloc分配内存,free释放内存 最小层(-1,-2),有操作系统调用","categories":[{"name":"python","slug":"python","permalink":"http://yoursite.com/categories/python/"}],"tags":[{"name":"python","slug":"python","permalink":"http://yoursite.com/tags/python/"}]},{"title":"SPM-CVPR19-Tracking","slug":"SPM-CVPR2019","date":"2019-06-28T10:36:36.000Z","updated":"2019-08-13T02:52:01.590Z","comments":true,"path":"2019/06/28/SPM-CVPR2019/","link":"","permalink":"http://yoursite.com/2019/06/28/SPM-CVPR2019/","excerpt":"SPM SPM-Tracker: Series-Parallel Matching for Real-Time Visual Object Tracking Paper: Code: Overview 将Tracking中的两个需求(Robustness,deiscrimination)分别放在两个阶段(two-stage:CM->FM)实现。 感觉效果惊人!OTB-100上的AUC为0.687,VOT-16上的EAO竟然达到了0.434,GPU上的fps为120,牛! 抓住了siamese网络的缺点(相似物体容易drift),解决方式就是在一阶段CM提取目标物体和其相似物体作为正样本,在二阶段FM在仔细区分object和其相似物体,也算是在image中尽可能多的提炼信息。","text":"SPM SPM-Tracker: Series-Parallel Matching for Real-Time Visual Object Tracking Paper: Code: Overview 将Tracking中的两个需求(Robustness,deiscrimination)分别放在两个阶段(two-stage:CM->FM)实现。 感觉效果惊人!OTB-100上的AUC为0.687,VOT-16上的EAO竟然达到了0.434,GPU上的fps为120,牛! 抓住了siamese网络的缺点(相似物体容易drift),解决方式就是在一阶段CM提取目标物体和其相似物体作为正样本,在二阶段FM在仔细区分object和其相似物体,也算是在image中尽可能多的提炼信息。 why 在tracking的过程中,既要求tracker有足够的判别力(针对相似物体或者相似背景等),又需要足够的鲁棒性(对于物体的形变,光照等)。但是用一阶段的方法学习两种能力,其间会相互影响。 现存的tracker速度太慢。 what 将Tracking分为两阶段来做,分别是CM,FM。CM负责鲁棒性,FM负责判别力。两阶段的融合省去了做多尺度测试。 在CM阶段同一类物体都被作为同一物体,来提高CM的鲁棒性。在FM阶段通过距离学习子网络替代了cross corrrelation来提高网络的判别力。CM的输出作为FM的输入,最终的输出是两阶段的融合。 SPM的优势 two-stage,容易train CM的输出作为FM的输入,正负样本的比例和难样本得到了平衡 两个阶段输出的融合可以有更高的精度 FM阶段有较少的proposals,省去了cross-correlation操作,改为使用trainable distance measure how 网络结构 特征提取:Siamese Alexnet(在ImageNet上预训练) CM Stage使用SiamRPN的网络结构,最小化类内特性,专注于robust ROI Align用来为每个proposal生成固定长度的区域特征 FM Stage为距离学习网络,最大化不同物体间的特性,专注于discrimination 最终输出为两阶段decision的融合(score + bbox deltas) CM阶段 将image中同类物体的中心区域(红,绿)都作为正样本,蓝色区域为忽略区域 FM阶段 该阶段的重点在于将CM阶段过滤后的object与背景/相似物体区分开 经CM过滤后剩余较少的proposal,所以丢弃了cross correlation操作,使用了新的关系网络来进行距离计算。 对于每一个proposal,直接从feature map上crop然后使用ROI pooling生成固定大小的feature,同时将高低层的信息concatenation。 关系网络的输入是图像对concatenate的feature信息,后接1x1卷积,再接2个全连接层(256个neurons),用来cls和box regression 融合 最终CM,FM阶段的scores和bbox deltas进行加权融合 other points CF-based执行必不可少的是在线更新策略,但是结合deep learning是特别慢的,所以researcher使用static discriminative trackers,像siamFC等。 SiamRPN使用RPN在提高bbox regression方面做了改进,DaSiamRPN使用样本策略(相似的同类物体作为正样本提高robust,语义信息接近的不同类物体作为负样本提高distrimination)在discrimination方面做了提升。 网络细节 在使用的AlexNet中保留了padding,因为ROI align需要feature和source image的像素对齐。 CM阶段使用no padding的中心feature(应该是从padding后的feature上crop下来) 每个ROI pooling后的feature大小为6x6x640 train细节 IOU 大于0.6,小于0.3的样本被保留。 loss :两个阶段,四个loss的加权和, cls : cross entropy , reg : smooth l1 loss","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"Deepsort-CVPR2017-Tracking","slug":"DeepSort-CVPR2017","date":"2019-06-25T02:36:46.000Z","updated":"2019-07-22T06:27:51.995Z","comments":true,"path":"2019/06/25/DeepSort-CVPR2017/","link":"","permalink":"http://yoursite.com/2019/06/25/DeepSort-CVPR2017/","excerpt":"Deep Sort(待完善)Overview 在Sort的基础上整合了appearance信息,引入了深度信息 将计算复杂度较高放在了离线预训练阶段,在大规模reid的数据集上学习一个关联矩阵,在online阶段,在visual appearance阶段建立了一个mearsure to track的最近邻查询。 减少了ID switch","text":"Deep Sort(待完善)Overview 在Sort的基础上整合了appearance信息,引入了深度信息 将计算复杂度较高放在了离线预训练阶段,在大规模reid的数据集上学习一个关联矩阵,在online阶段,在visual appearance阶段建立了一个mearsure to track的最近邻查询。 减少了ID switch Sort with Deep Association Metric跟踪处理 + 状态估计 使用八个维度值(cx,cy,r,h,vcx,vcy,vr,vh)来估计tracking的状态,同时假设kalman filter是恒定速度和线性观测模型。 对于每一个track,都要计算上次匹配成功后的帧数a。当再次关联的时候置为0,目的是通过计数找出目标消失的情况。当a > 设定Aage时,我们认为该track在image中消失。对于未关联的detection,我们认为其为新出现的目标。这些目标在前3帧中被认为暂定状态,当这些新出现的track在他们出现的前三帧中未成功关联就被删除。 匹配问题 在kalman filter预测和detection状态之间的分配问题一般使用Hungarian算法。文章中在这里整合了运动信息,外观特征信息。 运动信息,通过计算kalman states和detection之间的马氏距离。这里有公式d(1)(i,j) = (dj −yi)T^Si−1(dj −yi)。马氏距离通过测量检测远离平均轨道位置的标准偏差的多少来考虑状态估计不确定性。之后通过x2分布来过滤一些不可能存在的关联,这里有公式b(1) i,j = 1[d(1)(i,j) ≤ t(1)]。其中的Mahalanobis的阈值t(1)设定为9.4877。 [注]以上的马氏距离可以无相机运动的时有较好的预测效果。但是在相机快速运动,遮挡的情况下,Mahalanobis距离相当不准确。 外观特征,对于每一个detection dj提取外观特征,表示为rj,且||rj|| = 1,我们为每一个track维护它的最近Lk = 100个特征。第二个度量是计算track_i和detection_j在外观特征上的cosine distance。之后再通过x2分布进行过滤。 [注]同一物体在不同image中生成的feature向量的余弦距离是很小的。 lamda*运动信息 + (1-lamda)外观特征。运动信息适合短期预测,外观特征适合长期预测。在paper中,将lamda设为0,但是mahalanobis gate仍然被用来判断不可行的预测结果。 级联匹配 原因:在物体长时间遮挡的情况下,kalman预测会增加物体位置预测的不确定性。概率会在状态空间发散,可能无法观察。且当两个track被关联为同一个detection,mahalanobis distance偏向于不确定性更大的track,因为它有效地减少了任何检测的标准偏差与投影轨道平均值之间的距离。因此,采用级联的方式设定优先级。 级联匹配,优先考虑最小age的track。 在最终的match阶段,统计未确认,和age为1的未匹配的track。这个操作有助于对突然的外观变化等增加一定的鲁棒性。 深度外观描述子 使用最近邻查询,所以要提取较好的具有判别力的特征。文章中使用CNN在大规模的reid数据集上进行训练。 CNN网络结构使用resnet,两个conv layer加六个res blocks。最后在dense layer计算出来128维的特征映射。","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"C-RPN-CVPR19-tracking","slug":"C-RPN-CVPR2019","date":"2019-06-23T02:36:46.000Z","updated":"2019-07-02T00:36:25.575Z","comments":true,"path":"2019/06/23/C-RPN-CVPR2019/","link":"","permalink":"http://yoursite.com/2019/06/23/C-RPN-CVPR2019/","excerpt":"C-RPN Siamese Cascaded Region Proposal Networks for Real-Time Visual Tracking Paper: Code: Overview 通过级联RPN(多stages)筛选,解决了样本不平衡问题。(多阶段筛选) 构建FTB block用于高/低特征融合,结果更加精确。(多层融合) 其实跟SPM Tracker的出发点相同,都是针对Siamese网络中相似物体的drift问题,解决思想也相同,都是使用多stages过滤以获得更好的效果,但是整体来说效果离SPM差很多,首先多RPN肯定很耗时,FPS在36左右,同时精度提升也不是特别明显,VOT16上EAO为0.363。","text":"C-RPN Siamese Cascaded Region Proposal Networks for Real-Time Visual Tracking Paper: Code: Overview 通过级联RPN(多stages)筛选,解决了样本不平衡问题。(多阶段筛选) 构建FTB block用于高/低特征融合,结果更加精确。(多层融合) 其实跟SPM Tracker的出发点相同,都是针对Siamese网络中相似物体的drift问题,解决思想也相同,都是使用多stages过滤以获得更好的效果,但是整体来说效果离SPM差很多,首先多RPN肯定很耗时,FPS在36左右,同时精度提升也不是特别明显,VOT16上EAO为0.363。 why 针对Siamese自身存在的问题 – 相似物体的drift 样本不平衡问题 大多数样本为简单负样本 在现有的siamese网络中,低层的feature信息没有合理利用 高层的信息可能包含更多的语义信息,造成相似物体的drift what 提出级联RPN的网络结构,分为3个stages,每个stage都做分类和回归对上一阶筛选的proposals在进行refine,每个阶段都会逐渐过滤简单负样本,保留为下一个阶段保留难例负样本。 用FTB做高低特征融合。 how 网络结构如图。仍然使用AlexNet结构提取特征。 FTB结构如图。高层feature经过反卷积恢复尺度,然后与底层feature通过element-wise结合,最后对融合后的feature进行插值操作,为了确保最终所有的RPN都能对应相同的GT。 GT和各阶段RPN的计算。","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"CIR-CVPR19-tracking","slug":"CIR-CVPR2019","date":"2019-06-23T02:20:46.000Z","updated":"2019-07-02T01:57:19.176Z","comments":true,"path":"2019/06/23/CIR-CVPR2019/","link":"","permalink":"http://yoursite.com/2019/06/23/CIR-CVPR2019/","excerpt":"CIR Deeper and Wider Siamese Networks for Real-Time Visual Tracking Code:https://gitlab.com/MSRA_NLPR/ deeper_wider_siamese_trackers Overview 针对深度网络(如Resnet)无法在siamese网络取得很好的效果。SiamRPN++也是从这个点出发去做,两者的都找出了其影响最大的原因–padding,不过解决方式不同。 paper效果 siamFC/siamRPN在VOT16上的EAO提升了23.3%和8.8%","text":"CIR Deeper and Wider Siamese Networks for Real-Time Visual Tracking Code:https://gitlab.com/MSRA_NLPR/ deeper_wider_siamese_trackers Overview 针对深度网络(如Resnet)无法在siamese网络取得很好的效果。SiamRPN++也是从这个点出发去做,两者的都找出了其影响最大的原因–padding,不过解决方式不同。 paper效果 siamFC/siamRPN在VOT16上的EAO提升了23.3%和8.8% why 深度网络无法在siamese网络中取得很好的效果,对网络的各部分进行了分析,大体原因如下几点: 神经元感受野的增大会减小特征分辨和定位的精度 网络的padding会导致网络学习的位置偏见(主要因素) 网络stride what 基于残差bottleneck block进行了改进–cropping-inside residual ,用来crop(消除)padding的影响,同时可以控制感受野大小,网络的stride 几点说法 感受野:大的感受野能够把握target的结构信息,感受野太小不利于特征提取 Stride:影响定位精度,控制着输出feature的大小;输出feature的大小影响分辨和检测精度。 Padding:当物体移动到padding边缘,会产生一定的位置偏见 几点分析 网络越深,感受野就越大,理论上最后一层得感受野最大 Stride为4-8-16对应得变化为0.59-0.60-0.55(Alexnet),说明siamese更适合中等strdie(4,8),随着网络深度的增加,stride不应该增加。 最优的感受野大概为image z的60%-80% 输出的feature大小较小的话,会降低track精度,因为小的feature没有组后的空间结构信息。 siamese训练的数据中object都在image的中心,所以当test数据中的object出现在image边缘时效果不好,且会受到边缘padding的影响。 how 基于resnet bottleneck改进–CIR Unit 在resnet block之后添加了crop operation,将block之后padding的最外层元素给crop掉。这样feature map岂不是会越来越小? 下采样CIR-D 将stride由2设为1,并在block之后也加入了crop operation操作,之后又加了max pooling用于降采样 CIR多分枝结构 - CIR-Inception/CIR-NeXt CIR-Inception : 在short-connection部分加入了1x1卷积,并且通过concatenation来将两个分支的feature融合 CIR-ResNeXt : 将bottleneck分为了32个分支,最终通过addition融合 这两种结构后也接crop操作,去除padding影响。这两种复杂结构可以学习更加复杂的feature 最终,提到了crop之后feature map变小的解决方案–增大input image的大小,减小网络stride,surprise!?感觉应该有其他的方式来做padding比如说feature的均值填充之类的,没有试过不知道会不会有效果。 result 最好结果相对SiamRPN而言,提升了4个百分点,为0.301,如图。result other points siamese网络的输入就是图像对,之前DaSiam就是在图像对这里使用的数据增强 如果我将z的信息提取hog或者就是feature特征,然后作为网络的input,在之后帧中判断其与之前的cosine distance,这种方案感觉也可行","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"ATOM-CVPR19-tracking","slug":"ATOM-CVPR2019","date":"2019-06-20T02:36:44.000Z","updated":"2019-07-01T14:45:34.924Z","comments":true,"path":"2019/06/20/ATOM-CVPR2019/","link":"","permalink":"http://yoursite.com/2019/06/20/ATOM-CVPR2019/","excerpt":"ATOM Accurate Tracking by Overlap Maximization Paper : Code : https://github.com/visionml/pytracking Overview 大佬决定在跟踪精度上做改进,抛弃anchor,使用GT添加高斯噪声的方式。 受到IOUNet的启发,将class-special的IOU-Net改为target-special的IOU-Net使其适用于tracking的情境。 SGD算法收敛太慢,所以提出了新的收敛算法(共轭梯度+牛顿高斯)。","text":"ATOM Accurate Tracking by Overlap Maximization Paper : Code : https://github.com/visionml/pytracking Overview 大佬决定在跟踪精度上做改进,抛弃anchor,使用GT添加高斯噪声的方式。 受到IOUNet的启发,将class-special的IOU-Net改为target-special的IOU-Net使其适用于tracking的情境。 SGD算法收敛太慢,所以提出了新的收敛算法(共轭梯度+牛顿高斯)。 why 近年来,大家的目光都聚焦在tracking的鲁棒性上,而忽略了tracking的准确性。 在IOUNet的启发下作的一些改进。 what网络结构 target分类(online) 区分前/背景提供一个粗略的定位,online提高分类的鲁棒性 使用2层全连接层 抛弃SGD,使用共轭梯度+牛顿高斯方法优化 target估计(offline) 用于寻找overlap最大化的bbox,offline学习一个更通用的IoU预测表示 使用IOU-predictor网络来进行target估计 input是image object的feature和bbox_delta,然后使用PrROI pooling得到一个预定义大小的feature。 how 网络结构 backbone :Resnet-18(在ImageNet上预训练) IOU Modulation 对reference帧和search帧进行了特征提取,之后通过channel-wise multiplication做特征融合。 IOU predictor 由3层FC层组成 IOU predictor input : 当前帧的feature,当前帧的bbox估计,reference帧的feature,reference帧中的target bbox IOU predictor output : 当前帧中预测的每一个bbox的iou值 Classifier 2个全卷积网络 第一层由1x1卷积构成,将通道减小至64,减少计算量。 第二层使用4x4的单输出通道kernel 使用PELU作为输出的激活函数,可以忽略掉简单的负样本 第一帧,使用了数据增强(旋转,模糊,dropout等) 在分类过程中使用了自定义的优化策略(共轭梯度+牛顿高斯) 实现细节 使用了LaSOT和TrackingNet数据集,同时使用了COCO数据集来进行数据增强操作 图像对采样间隔为50 每个图像对,对应生成16个候选的bbox(GT+高斯噪声,同时确保最小iou为0.1) 权重初始化 - Delving deep into rectifiers: Surpassing human-level performance on imagenet classification. In ICCV, 2015. 5 loss使用MSE loss,训练40个epoch,每个epoch使用64个图像对 学习率初始为10e-3,weight decay factor为0.2(15epoch) 在训练过程中,backbone的weight被freezed 硬负样本挖掘,当distractor在分类score中取到峰值,会将该样本使用2倍的lr在优化训练一轮。同时,在score低于0.25时判断为丢失。 最后的输出使用IOU最高的3个bbox的平均值。 results Nvidia GT-1080 GPU上运行30FPS other points 低层包含更多的表面信息,那为什么不用底层feature做reg,用高层语义信息去做分类。","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"IOU-Net-ECCV18-detection","slug":"IOU-Net-ECCV2018","date":"2019-06-18T06:36:44.000Z","updated":"2019-07-01T14:47:29.403Z","comments":true,"path":"2019/06/18/IOU-Net-ECCV2018/","link":"","permalink":"http://yoursite.com/2019/06/18/IOU-Net-ECCV2018/","excerpt":"IOU-Net Acquisition of Localization Confidence for Accurate Object Detection Paper : Code : Overview 目前大多数的tracker都是通过cls score来确定物体的位置,但是分类得分高并不意味着定位的准确度高,所以用cls score去做NMS并不是特别合理,因为会把定位精准但分类得分低的卡掉。所以作者提出了使用iou score作为排序指标。 Paper提出了IOU-guided NMS,PrROI(使用积分的方式计算ROI特征)。 很有分量的文章,受益匪浅。","text":"IOU-Net Acquisition of Localization Confidence for Accurate Object Detection Paper : Code : Overview 目前大多数的tracker都是通过cls score来确定物体的位置,但是分类得分高并不意味着定位的准确度高,所以用cls score去做NMS并不是特别合理,因为会把定位精准但分类得分低的卡掉。所以作者提出了使用iou score作为排序指标。 Paper提出了IOU-guided NMS,PrROI(使用积分的方式计算ROI特征)。 很有分量的文章,受益匪浅。 why 使用预测box的cls score去做NMS并不合理,如图所示。 根据皮尔逊相关系数,分类score和iou并不成正相关,而定位score和iou是成正相关。 并且,分类得分高的并不一定定位得分高,使用cls score做NMS会把这些定位得分高的box卡掉。 通过下图也可以看出,NMS很容易把IOU较高的bbox过滤掉(当然其中肯定存在大量的冗余bbox)。 传统的基于regression的bbox refine的问题。 regression-based和optimization-based的直观效果差距。 regression-based是通过回归[cx,cy,w,h]使其与gt尽可能接近。理论上不断refine会得到很精确的结果,但是cascad RCNN相关实验表示在随着refine次数的增加效果会下降,(为什么会这样还需要做点工作)。但是使用IOU的方式在不断refine后不会出现该情况。 what 提出了IOU-Net来预测bbox和gt的IOU值。 将ROI pooling/Align更换为prROI。 howIOU-Net IOU predictor的input是image通过FPN后的feature。output是每个bbox的iou score。这里使用的proposal并不是来自RPN,而是通过对GT进行随机变换(添加随机噪声等)得到的一系列proposals,然后对bbox进行过滤。对于每一个bbox会使用prROI-pooling在FPN上提取的feature,这些feature被送入2层fc层做IOU预测。 IOU-guided NMS 将NMS算法中的排序指标改为IOU score。 通过对iou进行聚类的方式对cls score进行更新(重点在第5,8行)。在根据iou过滤的过程中,将过滤掉的bboxes中的最高的cls score分配给当前的bbox,所以保留下的是其iou簇中最高的分类得分。感觉这样做的好处是消除iou一致情况下cls score的差别。 Optimization-based bbox refinement。IOU支路的梯度计算和参数更新 prROI pooling 上图是ROI pooling,ROI align,prROI pooling的对比,这是三种都是基于ROI坐标根据feature map提取feature的方法。 ROI pooling。 先将预测得到的ROI除以stride,并量化取整得到整数值的ROI 将ROI分为k*K个grid,每个grid的坐标为(x1,y1,x2,y2),其坐标值不一定为整数,所以要量化取整,左上角向下取整,右下角向上取整,得到整数的坐标值。然后可以采用均值/最大值操作得到该grid的特征值。 优点:解决了不同大小ROI的尺寸不统一的问题 缺点:量化操作会引入一定的误差 ROI Align 对ROI pooling进行改进,直接使用浮点坐标值将ROI划分,消除了量化操作引入的误差。 对ROI的每个grid的坐标也不再进行量化,而是在grid中均匀取4个点,通过公式2(插值)计算得到该点的特征值(该公式根据距离对周围的4个点进行加权计算,距离越近权重越大),然后对其求平均 优点:消除了量化操作带来的误差 缺点:没有考虑grid的大小差异 PrROI pooling 使用积分的方式计算每个grid的特征值 ROI Align仅考虑该grid中4个插值点的均值,PrROI pooling是将grid中的值看做是连续的,通过对该grid中所有点求积分得到该grid所包围点的总和,最后除以面积。 优点:结果会更加精准 result IOU-guided NMS 当IOU threshold设定较高时,iou nms的效果会更加明显,因为threshold较高的时候需要bbox的坐标更加准确才会能更好的AP值。 optimization-based bbox refinement refinement在各个模块上都有不错的提升。 other pointsNMS 将所有的bbox按cls score降排序生成一个list 从top 1 bbox开始,计算该bbox与其他bbox的iou,若iou大于设定阈值则剔除。 再从top 2 bbox开始,计算该bbox与其他bbox的iou… 重复操作,直到list中所有元素都筛选完毕 soft NMS 并不是真正的抑制,而是对要过滤掉的bbox乘以一个衰减系数。 将所有的bbox按cls score降排序生成一个list 从top 1 bbox开始,计算该bbox与其他bbox的iou,若iou大于设定阈值则将其乘以一个系数,使其缩小,之后在重新比较。 再从top 2 bbox开始,计算该bbox与其他bbox的iou… 重复操作,直到list中所有元素都筛选完毕。 对于遮挡,目标密集的情况效果很好,但是对于稀疏的场景,召回率可能会低于NMS。 想法 对GT做随机调整这种方法,感觉可以用","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Canny边缘检测","slug":"canny边缘检测","date":"2019-05-22T02:31:46.000Z","updated":"2019-08-25T07:30:47.255Z","comments":true,"path":"2019/05/22/canny边缘检测/","link":"","permalink":"http://yoursite.com/2019/05/22/canny边缘检测/","excerpt":"Canny边缘检测Overview 去噪声,算梯度,NMS,定边缘 使用滤波器平滑图像,过滤噪声。 计算图像中每个像素点的梯度强度和方向。 使NMS消除边缘检测带来的杂乱影响。 使用双阈值法来确定边缘。","text":"Canny边缘检测Overview 去噪声,算梯度,NMS,定边缘 使用滤波器平滑图像,过滤噪声。 计算图像中每个像素点的梯度强度和方向。 使NMS消除边缘检测带来的杂乱影响。 使用双阈值法来确定边缘。 原理滤波 边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。 常见的滤波算法有:高斯滤波(采用离散化的高斯函数产生一组归一化的高斯核),然后基于高斯核函数 对图像灰度矩阵的每一点进行加权求和。高斯核函数:$k(x, x’) = e^{-\\frac{||x - x’||^2}{2\\sigma^2}}$sigma决定了高斯函数的宽度。高斯函数的性质:①旋转对称性;②每一个邻域像素值权值是随着该点到中心点的距离单调递减的。 增强 确定图像各点邻域强度的变化值,增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。 编程中,可以通过梯度幅值来确定。 检测 经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是我们要找的边缘点,所以应该采用某种方法来对这些点进行取舍。 实际工程中,常用的方法是通过阈值化方法来检测。 步骤对原始图像灰度化 灰度化就是对图像各个通道的采样值进行加权平均。 Gray = (R+G+B)/3 或者 Gray = 0.299R+0.587G+0.114B 对图像进行高斯滤波 两个一维高斯核进行两次加权实现,或者一个二维高斯核进行一次卷积实现。 $k(x, x’) = 1/{sqrt(2pi)sigma^2}*e^{-\\frac{x^2+y^2}{2\\sigma^2}}$ 图像的高斯滤波,根据待滤波的像素点及其邻域点的灰度值按照一定的参数规则进行加权平均。这样可以有效滤去理想图像中叠加的高频噪声。 用一阶偏导的有限差分来计算梯度的幅值和方向 Roberts算子,Sobel算子,Prewitt算子 canny用到的算子是sx = [-1,1,-1,1],sy = [1,-1,1,-1] 对梯度幅值进行非极大值抑制 图像梯度幅值矩阵的元素值越大,说明该点的梯度值越大,但不能说明该店就是边缘。 寻找像素点局部最大值,将非极大值所对应的灰度值置为0。已知该点周围领点的梯度,使用线性插值的方式计算该店梯度方向上的两个端点,判断其是否为极大值,若是,则将其灰度值置为128,否则,将其灰度值置为0. 这样一个检测结果还是包含了很多由噪声及其他原因造成的假边缘。因此还需要进一步的处理。 用双阈值算法检测和连接边缘 设定阈值maxval和minval,梯度大于maxval的判定为边界,小于minval则舍弃,介于两者之间有边界相连则保留,否则舍弃。 注:minval/maxval越小,检测出来的边缘信息越多","categories":[{"name":"image-processing","slug":"image-processing","permalink":"http://yoursite.com/categories/image-processing/"}],"tags":[{"name":"Canny","slug":"Canny","permalink":"http://yoursite.com/tags/Canny/"}]},{"title":"Tracking-Summary","slug":"Tracking-Summary","date":"2019-05-19T13:56:21.000Z","updated":"2019-07-01T15:03:13.705Z","comments":true,"path":"2019/05/19/Tracking-Summary/","link":"","permalink":"http://yoursite.com/2019/05/19/Tracking-Summary/","excerpt":"Tracking-Summary 总结一下近年来比较经典的tracker,未完待续","text":"Tracking-Summary 总结一下近年来比较经典的tracker,未完待续 综述难点 外观的形变,光照变换,快速运动,运动模糊,背景相似干扰,遮挡,旋转,尺度变换,出视野数据集 OTBOTB包含0.25的灰度序列 VOTvot是彩色序列,且分辨率较高,精细标注,评价指标更好 差别 OTB有随机帧开始,或者矩形框随机干扰初始化去跑 VOT是用第一帧初始化,每次跟踪失败,5帧之后重新初始化类别生成式模型 对第一帧的目标区域建模,下一帧寻找与模型最相似的区域作为预测区域。 方法:卡尔曼滤波,粒子滤波,mean-shift 代表:ASMS,DAT(ASMS仅使用颜色特征,切且速度较快,125fps,在mean-shift框架下加入了尺度估计,加入了尺度不剧变,可能偏最大的两个先验的正则项,再加反向尺度一致性检查)。判别式模型 将当前帧的目标区域作为正样本,背景区域作为负样本来训练分类器。(相比较生成式模型使用了背景信息,效果会更好一些) 方法:传统的机器学习算法,相关滤波,深度学习 代表:传统--Struck,TLD(struck使用了haar+structured output SVM,跟踪中进行多尺度便利搜索来完成尺度自适应)相关滤波--KCF,CSK,DAT深度学习--MDNet,TCNN,SiamFC 传统机器学习方法Struck - 2012 - 20fps相关滤波-CF推荐:大佬维护的CF资源 MOSSE - - 615fps 单通道灰度特征的相关滤波 CSK - - 362fps 岭回归,循环移位的近似密集采样,多通道HOG特征 CSK在MOSSE的基础上扩展了密集采样和kernel-trick KCF - 2014 - 172fps(hog) 在CSK基础上扩展了多通道梯度的HOG特征(梯度特征) DCF - 2014 - 292fps(hog)CN - 2014 - 152fps 在CSK基础上扩展了多通道CN特征(颜色特征)相关知识点 HOG特征 主要思想:梯度的统计信息,梯度主要存在于边缘的地方。 实现过程 灰度化(将图像看做一个x,y,z(灰度)的三维图像); 采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰; 计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。计算图像梯度。计算图像横/纵坐标方向的梯度(就是该像素在横纵方向上的相邻像素去做差,常用的方法是用[-1,0,1]梯度算子对原图像做卷积运算得到x方向的梯度分量,同理,使用[-1,0,1]运算得到y方向上的梯度分量),并计算每个像素位置的梯度方向值。 将图像划分成小cells(例如6*6像素/cell); 统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor; 将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。 将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了。 深度学习-DL","categories":[{"name":"summary","slug":"summary","permalink":"http://yoursite.com/categories/summary/"}],"tags":[{"name":"Tracking","slug":"Tracking","permalink":"http://yoursite.com/tags/Tracking/"}]},{"title":"GIOU-CVPR19-detection","slug":"GIOU-CVPR19-detection","date":"2019-05-09T13:56:21.000Z","updated":"2019-05-10T16:15:30.486Z","comments":true,"path":"2019/05/09/GIOU-CVPR19-detection/","link":"","permalink":"http://yoursite.com/2019/05/09/GIOU-CVPR19-detection/","excerpt":"Overview主要思想 提出新的loss指标GIOU,使用评价标准作为loss,同时避免了IOU作为loss的缺点,有较好的提升。 效果 在anchor较少的detection中有较为明显的提升(3-6个点) paper https://arxiv.org/pdf/1902.09630.pdf","text":"Overview主要思想 提出新的loss指标GIOU,使用评价标准作为loss,同时避免了IOU作为loss的缺点,有较好的提升。 效果 在anchor较少的detection中有较为明显的提升(3-6个点) paper https://arxiv.org/pdf/1902.09630.pdf Motivation 大家都在模型,trick上下功夫,忽略了在L1/L2上的改进(L_n范数对物体的scale比较敏感)。 直接使用iou作为loss存在的问题。 两个框没有相交,IOU=0,loss = 0,无法进行梯度的反向传播,无法学习训练。 IOU无法精确衡量重叠程度,且IOU的变化无法反馈定位框的重合度和方向。如下图。 Method 设定gt为A,pred为B,先求包含A,B的最小闭包C。 计算C中去除A∪B后剩下的面积D,即D = C\\(A∪B)。 计算IoU GIoU = IoU - D/C IOU ∈ [0,1],GIOU ∈ [-1,1] Othersobtains 起初自己也想过使用iou作为loss,但是看到网上说iou作为loss可能存在梯度无法回传问题时,没有多思考去寻找解决办法。所以,遇到问题深究原因,考虑有没有可替代的近似方案。 IOU既然对于尺度不敏感,L_n对尺度敏感,那两者就可以做loss的结合。","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"GARPN-CVPR19-detection","slug":"GARPN-CVPR19-detection","date":"2019-05-08T02:36:24.000Z","updated":"2019-05-10T06:49:36.014Z","comments":true,"path":"2019/05/08/GARPN-CVPR19-detection/","link":"","permalink":"http://yoursite.com/2019/05/08/GARPN-CVPR19-detection/","excerpt":"Overview 主要思想 先前的anchor是在feature map上的每个点都设定(均匀分布),本文的思想是先预测最有可能出现object中心的区域,然后在该区域进行anchor w h的预测,从而确定了anchors,减少了计算量。 anchor和feature map的匹配问题,根据anchor shape计算deformable conv的offset,从而对feature map进行变换,以生成新的feature map。 在新的feature map上进行分类和回归。 效果 在resnet50-fpn作为backbone,其recall(AR)提高了9.1个点,mAP提高了1.2-2.7个点。 paper: https://arxiv.org/pdf/1901.03278.pdf","text":"Overview 主要思想 先前的anchor是在feature map上的每个点都设定(均匀分布),本文的思想是先预测最有可能出现object中心的区域,然后在该区域进行anchor w h的预测,从而确定了anchors,减少了计算量。 anchor和feature map的匹配问题,根据anchor shape计算deformable conv的offset,从而对feature map进行变换,以生成新的feature map。 在新的feature map上进行分类和回归。 效果 在resnet50-fpn作为backbone,其recall(AR)提高了9.1个点,mAP提高了1.2-2.7个点。 paper: https://arxiv.org/pdf/1901.03278.pdf Motivation 之前的anchor尺度/比例(超参)需要人为设定,设定不好对性能影响较大。 前anchor方法中的大多数anchor都分布在背景区域,对于proposal没有作用,徒增计算量。 数据集中的object形变较大,预定义的anchor不一定能满足其object尺寸。 所有。出现了本文稀疏,形状可变的anchor。 Formulation p(x,y,w,h|I) = p(x,y|I)p(w,h|x,y,I)将anchor的坐标概率分布分为两个条件概率,即先进行anchor的位置预测,再进行形状预测。 Methodnetwork architecture network detailed 主要为两部分:anchor生成+feature调整 anchor生成部分:F1(feature map)通过N_L分支预测anchor location,通过N_s预测anchor shape。 feature adaption:使用anchor信息生成可变形卷积的offset,在使用可变形卷积对feature map进行调整,以生成新的feature map。 anchor location predict 二分类问题 在feature map上预测可能出现object中心点的位置(对应原图的一区域),该中心区域为正样本,超出gt的区域作为负样本,gt和中心区域的部分忽略。 N_L子网络,在feature map上使用1x1卷积计算出一个score map,再使用sigmoid将score转换为概率。 anchor shape predict 回归问题 该部分使用IOU loss。设定了几组常见的w,h,然后计算anchors与所有gt的IOU,然后将该anchor分配给IOU最大的gt。 w = σ·s·e_dw, h = σ·s·e_dhN_s子网络预测输出dw,dh;dw,dh通过上式进行变换得到w,h。其中,s为stride,σ为经验比例因子(文中设定为8)。 This nonlinear transformation projects the output space from approximate [0,1000] to [−1,1], leading to an easier and stable learning target. 这句没太懂,是原来直接预测w,h(范围在[0,1000]),现在通过预测dw,dh(范围在[-1,1])经e后可达到原先效果?这里不太理解 feature adaption 为什么呢?文章说是每个anchor都有自己的大小,与feature不是很好的匹配;而且原本的feature map并不知道预测的anchor的形状,但是分类和回归确是基于anchor做的?所以把anchor的形状信息融入到了feature map中?这里不太理解 N_t子网络(使用3x3的可变卷积),根据anchor shape预测deformable conv的offset(offset是通过anchor的w和h经过一个1x1conv得到的),去做一个feature map的变换,以得到新的feature map。offset计算要看代码 在新的feature map上进行分类和回归。 FA提升了近5个点。 Tricks  问题:proposal质量提升很多,但是detector上的性能提升有限。 减少proposal的数量 增大训练时正样本IOU阈值(重要,提升了2.7个点) Others缺点 论文假设图像中的目标是稀疏的。如果是稠密图像,比如车站或广场的拥挤人群,检测效果有待检验。 每一个点只产生一个anchor,那么对于那些目标中心重合,即一个点需要负责检测两个目标,似乎无法处理。 采用deformable卷积会相对地降低速度,同时根据DCN v2的分析,在deformable卷积中加入可调节的机制可能会更好。 Deformable conv Deformable conv简介-CVPR2017 评价标准 R(recall): 查全率,R = 预测出的正样本/原数据集中的所有正样本 AR : 平均查全率 P(precision):查准率,P = 预测中的正样本/预测出的所有样本 AP : 平均查准率","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"FocaLoss-CVPR18-detection","slug":"FocaLoss-CVPR18-detection","date":"2019-04-10T11:36:44.000Z","updated":"2019-05-19T05:06:27.618Z","comments":true,"path":"2019/04/10/FocaLoss-CVPR18-detection/","link":"","permalink":"http://yoursite.com/2019/04/10/FocaLoss-CVPR18-detection/","excerpt":"Overview主要思想 本文认为single stage detection结果不够好的原因是 太多的anchor会导致正负样本极度不平衡 虽然简单样本的loss很低,但是由于简单样本过多,所以对loss仍有较大的影响导致收敛不够好 本文做法:直接loss decay那些简单样本的权重,使训练更加关注有意义的样本效果","text":"Overview主要思想 本文认为single stage detection结果不够好的原因是 太多的anchor会导致正负样本极度不平衡 虽然简单样本的loss很低,但是由于简单样本过多,所以对loss仍有较大的影响导致收敛不够好 本文做法:直接loss decay那些简单样本的权重,使训练更加关注有意义的样本效果 OthersCross Entropy相关概念 信息量 一个事件发生的概率(P(x))越大,那么它所携带的信息量(I(x) = -log(P(x)))就越小。可以说,一件事发生的概率很小,一旦发生了会带来很大的信息量。 熵 熵就是信息量的期望值(E(I(x))),是一个随机变量确定性的度量。熵越大,变量的取值越不确定,反之就越确定。 相对熵(KL散度 / KL距离 / 信息增益) 两个随机分布间距离的度量OHEM(Online Hard Example Mining)-CVPR16","categories":[{"name":"papers","slug":"papers","permalink":"http://yoursite.com/categories/papers/"}],"tags":[{"name":"detection","slug":"detection","permalink":"http://yoursite.com/tags/detection/"}]},{"title":"Algo-BinaryTree","slug":"Algo-BinaryTree","date":"2019-03-23T02:53:51.000Z","updated":"2019-08-01T01:57:46.719Z","comments":true,"path":"2019/03/23/Algo-BinaryTree/","link":"","permalink":"http://yoursite.com/2019/03/23/Algo-BinaryTree/","excerpt":"Algo-BinaryTree基础算法 前/中/后 + 层次遍历 深度优先遍历 + 广度优先遍历 常见算法 重建二叉树 二叉树的下一个节点 树的子结构 二叉树的镜像 对称的二叉树 从上到下打印二叉树 之字形打印二叉树 二叉搜索树的后序遍历序列 二叉树中和为某一值的路径 二叉搜索树与双向链表 序列化二叉树 二叉搜索树的第K大节点 二叉树的深度 已知前/中序,构建二叉树 树中两个节点的最低公共祖先","text":"Algo-BinaryTree基础算法 前/中/后 + 层次遍历 深度优先遍历 + 广度优先遍历 常见算法 重建二叉树 二叉树的下一个节点 树的子结构 二叉树的镜像 对称的二叉树 从上到下打印二叉树 之字形打印二叉树 二叉搜索树的后序遍历序列 二叉树中和为某一值的路径 二叉搜索树与双向链表 序列化二叉树 二叉搜索树的第K大节点 二叉树的深度 已知前/中序,构建二叉树 树中两个节点的最低公共祖先 基础算法遍历 递归 123456789101112131415161718192021222324252627282930313233class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = Noneclass Recursive: def preOrderTraversal(self,root): # recursive if root == None: return root p = root print(p.val) self.preOrderTraversal(p.left) self.preOrderTraversal(p.right) def inOrderTraversal(self,root): # recursive if root == None: return root p = root self.inOrderTraversal(p.left) print(p.val) self.inOrderTraversal(p.right) def postOrderTraversal(self,root): # recursive if root == None: return root p = root self.postOrderTraversal(p.left) self.postOrderTraversal(p.right) print(p.val) 非递归 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677class NotRecursive: def preOrderTraversal(self,root): # not recursive by using the stack if root == None: return root p = root res = list() stack = list() while p or len(stack)>0: if p == None: p = stack.pop(-1) else: res.append(p.val) stack.append(p.right) p = p.left return res def inOrderTraversal(self,root): # not recursive by using the stack if root == None: return root p = root res = list() stack = list() while p or len(stack) > 0: if p: # find the leftest node stack.append(p) p = p.left else: # output the root,then point the right node p = stack.pop(-1) res.append(p.val) p = p.right return res def postOrderTraversal(self,root): # not recursive by using the stack if root == None: return root p = root res = list() stack = list() flag = None while p or len(stack) > 0: if p: # find the leftest node stack.append(p) p = p.left else: # check the top node of stack p = stack[-1] if p.right == flag or p.right == None: p = stack.pop(-1) res.append(p.val) flag = p p = None else: p = p.right return res def levelOrderTraversal(self,root): # not recursive by using the queue if root == None: return root p = root res = list() queue = list() queue.append(p) while len(queue) > 0: p = queue.pop(0) res.append(p.val) if p.left: queue.append(p.left) if p.right: queue.append(p.right) return res 常考算法重建二叉树(前+中->树) 题目 已知二叉树的前序和中序遍历,构建二叉树。 思路 前序遍历的第一个节点为根节点,根节点在中序遍历中将序列分成两个部分。需要注意的是下标的计算。 代码123456789101112131415161718class Soultion: def createTree(self,preOrder,inOrder): ''' recursive: preOrder: root left right inOrder: left root right ''' if len(preOrder) != len(inOrder) or len(preOrder) < 1 or len(inOrder) < 1: return None root = TreeNode(preOrder[0]) count = 0 for i in inOrder: if i == preOrder[0]: break count += 1 root.left = self.createTree(preOrder[1:count+1],inOrder[0:count]) root.right = self.createTree(preOrder[count+1:],inOrder[count+1:]) return root 二叉树的下一个节点(⭐) 题目 带父节点指针的二叉树,求给定节点中序遍历的下一个节点 思路 左叶子节点,直接返回父节点 右叶子节点/右子树为空的非叶节点,找到其最近的祖先节点,该祖先节点作为左子树的根节点。(重要) 右子树非空的节点,返回右子树最左侧节点。 代码123456789101112131415161718192021222324class Solution: def getNext(self,pNode): ''' some stations: 1. left node 2. rightest node of left tree ''' if pNode == None: return pNode # right node exist if pNode.right != None: q = pNode.right while q.left: q = q.left return q # right node not exist else: # find the nearest parent node that is the root of left tree while pNode.next != None: q = pNode.next if q.left == pNode: return q pNode = pNode.next return None 树的子结构 题目 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:约定空树不是任意一个树的子结构) 思路: 思路一 先通过遍历找出B的根节点在A中的位置 比对B与A相应部分的元素 思路二 在遍历的过程中直接进行判断,可以起到类似剪枝的作用,不需要完整遍历 代码123456789101112131415161718192021222324252627282930313233class Solution: def HasSubtree(self,A,B): if A == None or B == None: return False res = list() self.preOrderTraversal(A,B,res) q = B # compare the two trees ans = False for i in res: ans = ans or self.isEquals(i,q) return ans def isEquals(self,p,q): # compare the trees , the most important thing is the rule if q == None: return True elif p == None: return False elif p.val == q.val: return self.isEquals(p.left, q.left) and self.isEquals(p.right, q.right) else: return False def preOrderTraversal(self,root,t,res): if root == None: return root p = root if p.val == t.val: res.append(p) self.preOrderTraversal(p.left,t,res) self.preOrderTraversal(p.right,t,res) return res 二叉树的镜像 题目 操作给定的二叉树,将其变换为源二叉树的镜像。 思路 借助遍历,遍历过程中交换左右节点 代码123456789101112131415class Solution: def mirror(self,root): if not root: return root self.swapNode(root) self.mirror(root.left) self.mirror(root.right) return root def swapNode(self,root): if not root: return root tmp = root.left root.left = root.right root.right = tmp 对称的二叉树 题目 请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 思路 层次遍历,判断每一层是否对称(90%,没有考虑全部为相同数的情况) 左右子树递归调用(⭐) 代码123456789101112131415161718class Solution(): def isSymmetrical(self,root): if not root or (not root.left and not root.right): return True left = root.left right = root.right if left and right: return self.isSame(left,right) else: return False def isSame(self,left,right): if not left and not right: return True if left and right and left.val == right.val: return self.isSame(left.left, right.right) and self.isSame(left.right, right.left) else: return False 从上到下打印二叉树 题目 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 思路 层次遍历 代码 见上。层次遍历之字形打印二叉树 题目 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推 思路 使用双队列 + 标志位 代码123456789101112131415161718192021222324252627import copyclass Solution: def Print(self, root): # write code here if not root: return [] res_list = [[root.val]] queue1 = list() queue1.append(root) queue2 = list() flag = True while len(queue1): p = queue1.pop(0) if p.left: queue2.append(p.left) if p.right: queue2.append(p.right) if len(queue1) == 0: queue1 = copy.deepcopy(queue2) if len(queue2): if flag: queue2.reverse() res_list.append([x.val for x in queue2]) flag = not flag queue2 = list() return res_list 二叉搜索树的后序遍历序列 题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同 思路 二叉搜索树的特点,左子树 < 根节点 < 右子树 递归 代码1234567891011121314151617181920212223242526class Solution: \"\"\" 需要注意的点 1.下标 2.初始为空,左右子树为空的情况分开判断 \"\"\" def VerifySquenceOfBST(self, s): if not s: return False return self.process(s) def process(self,s): if len(s) <= 1: return True root = s[-1] left = -1 right = len(s)-2 for i in range(len(s)-2,-1,-1): if s[i] < root: left = i break s_left = s[:left+1] s_right = s[left+1:right+1] if (len(s_left) and max(s_left) >= root) or (len(s_right) and min(s[left+1:right+1]) <= root): return False return self.process(s[:left+1]) and self.process(s[left+1:right+1]) 二叉树中和为某一值的路径(⭐) 题目 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前) 思路 先序遍历 + 路径保存 + 叶节点路径和判断 注意:非递归遍历,注意栈弹出操作的条件限制 代码12345678910111213141516171819202122232425262728293031323334353637383940import copyclass TreeNode: def __init__(self, x): self.val = x self.left = None self.right = Nonedef FindPath(root,target): \"\"\" 非递归 1.叶节点的左右空节点会pop两次 2.重要的是在栈弹出操作的判断,当栈顶元素存在且栈顶元素的右子树未访问时,访问右子树,否则弹出 \"\"\" if not root: return [] res_list = [] stack = list() tmp = list() cur = root last = None while cur or len(stack): if not cur: # 这里是非递归遍历解决问题的关键 top = stack[-1] if top.right and top.right != last: cur = top.right else: last = stack.pop(-1) tmp.pop(-1) else: stack.append(cur) tmp.append(cur.val) if not cur.left and not cur.right and sum(tmp) == target: res_list.append(copy.deepcopy(tmp)) cur = cur.left res_list.sort(key=takeLen,reverse=True) return res_listdef takeLen(elem): return len(elem) 二叉搜索树与双向链表 题目 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 思路 中序遍历(递归) + left代替last,right代替next 代码12345678910111213141516171819202122232425262728class Solution: def Convert(self, root): # write code here if not root: return root res = self.process(root,0) while res.left: res = res.left return res def process(self,root,flag): \"\"\" flag 是为了判断左右子树 0代表左子树,返回左子树的最右节点,1代表右子树,返回右子树的最左节点 \"\"\" if not root.left and not root.right: return root p = root l,r = root,root if p.left: l = self.process(p.left,0) l.right,p.left = p,l if p.right: r = self.process(p.right,1) p.right,r.left = r,p if flag == 0: return r return l 二叉树的深度 题目 输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 思路 深度优先遍历 or 层次遍历 层次遍历,可以使用每层节点计数的方式,也可以使用双队列的方式 递归方式,很简洁 代码123456789101112131415161718192021222324252627class Solution(): def TreeDepth(self,root): if not root: return 0 queue = list() p = root queue.append(p) depth = 0 count = 1 # 记录每一层节点数 while len(queue): p = queue.pop(0) count -= 1 if p.left: queue.append(p.left) if p.right: queue.append(p.right) if count == 0: # 节点数为0时,depth+1,并重新赋值 depth += 1 count = len(queue) return depth def treeDepth(self,root): if not root: return 0 left = self.treeDepth(root.left) right = self.treeDepth(root.right) return left+1 if left > right else right +1 平衡二叉树(⭐) 题目 输入一棵二叉树,判断该二叉树是否是平衡二叉树。 思路 平衡二叉树的特点就是空数,或者所有左右子树的深度相差不超过1 遍历,判断二叉树的深度 这里差一种使用后序遍历,时间复杂度为O(n)的代码 代码12345678910111213141516171819class Solution: def IsBalanced_Solution(self, root): \"\"\" 在计算深度的时候重复遍历了很多节点,时间复杂度为O(n2) \"\"\" if not root: return True left = self.treeDepth(root.left) right = self.treeDepth(root.right) if abs(left-right) > 1: return False return self.IsBalanced_Solution(root.left) and self.IsBalanced_Solution(root.right) def treeDepth(self,root): if not root: return 0 left = self.treeDepth(root.left) right = self.treeDepth(root.right) return left+1 if left > right else right +1 序列化二叉树 题目 思路 代码二叉搜索树的第K大节点已知前/中序,构建二叉树树中两个节点的最低公共祖先 题目 寻找树中两个节点的最低公共父节点 思路 思路一 找到到达两个节点的路径,然后从头比较,最后一个相同元素即为公共父节点 思路二 利用先序遍历的特点,找寻包含两个节点的最近父节点 代码1234567891011121314151617181920212223242526272829303132333435363738394041424344class Solution: def method1(self,root,p,q): if not root: return root cur = root q1 = list() q2 = list() q1 = self.preOrderTraversal(cur,p,q1) q2 = self.preOrderTraversal(cur,q,q2) res = None while len(q1) > 0 and len(q2) > 0: print(q1,q2) if q1[0] == q2[0]: res = q1.pop(0) q2.pop(0) else: break return res def preOrderTraversal(self,root,p,res): if not root or not p: return None if root.val == p.val: return res res.append(root.val) # one of the branch find the target ,then return if self.preOrderTraversal(root.left,p,res) or self.preOrderTraversal(root.right,p,res): return res def method2(self,root,p,q): if root == None or p == None or q == None: return None if p.val == root.val or q.val == root.val: return root left = self.method2(root.left, p, q) right = self.method2(root.right,p,q) if left and right: return root if left: return left if right: return right","categories":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/categories/Algorithm/"}],"tags":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/tags/Algorithm/"}]},{"title":"Algo-Sort","slug":"Algo-Sort","date":"2019-03-18T09:17:29.000Z","updated":"2019-07-26T14:49:34.152Z","comments":true,"path":"2019/03/18/Algo-Sort/","link":"","permalink":"http://yoursite.com/2019/03/18/Algo-Sort/","excerpt":"排序 八大内部排序:直接插入排序,冒泡排序,简单选择排序,快速排序,堆排序,归并排序,基数排序 排序的时间/空间复杂度/稳定性","text":"排序 八大内部排序:直接插入排序,冒泡排序,简单选择排序,快速排序,堆排序,归并排序,基数排序 排序的时间/空间复杂度/稳定性 直接插入排序12345678910111213141516class Solution: def insertSort(self,L): if len(L) < 2: return L for i in range(1,len(L)): flag = -1 tmp = L[i] for j in range(1,i+1): if L[i-j] > tmp: L[i-j+1] = L[i-j] flag = i-j else: break if flag != -1: L[flag] = tmp return L 冒泡排序12345678910class Solution: def bubbleSort(self,L): if len(L) < 2: return L length = len(L) for i in range(0,length): for j in range(0,length-i-1): if L[j] > L[j+1]: L[j],L[j+1] = L[j+1],L[j] return L 简单选择排序123456789101112class Solution: def selectSort(self,l): if len(l) < 2: return l length = len(l) for i in range(0,length): min_id = i for j in range(i,length): if l[min_id] > l[j]: min_id = j l[i],l[min_id] = l[min_id],l[i] return l 快速排序1234567891011121314151617181920212223242526class Solution: def quickSort(self,m_list,left,right): if left < right: pivot = self.partition(m_list,left,right) self.quickSort(m_list,left,pivot-1) self.quickSort(m_list,pivot+1,right) return m_list def partition(self,m_list,left,right): tmp = m_list[left] while left < right: while left < right and m_list[right] > tmp: right -=1 m_list[left] = m_list[right] while left <right and m_list[left] < tmp: left +=1 m_list[right] = m_list[left] m_list[left] = tmp return leftif __name__==\"__main__\": list_tmp = list(map(int,input().split(\" \"))) solution = Solution() res = solution.quickSort(list_tmp,0,len(list_tmp)-1) print(res) 堆排序 步骤:①构建大顶堆②交换堆顶和堆底元素,向下调整堆③重复②操作,直到List剩余一个元素则完成排序1234567891011121314151617181920212223242526272829303132333435363738class Solution: def heapSort(self,ls): \"\"\" 要点:为了下标操作的方便,需要为出入的list头插入0 步骤: 1.建立大顶堆,从len/2开始调整 2.交换堆顶和堆底元素,然后向下调整 3.重复2操作,直到剩余一个元素 \"\"\" length = len(ls) - 1 self.buildMaxHeap(ls,length) for i in range(length - 1): tmp = ls[length-i] ls[length-i] = ls[1] ls[1] = tmp self.adjustDown(ls,1,length-i-1) return ls[1:] def buildMaxHeap(self,ls,len): length = len//2 for i in range(0,length): self.adjustDown(ls,length - i,len) def adjustDown(self,ls,low,high): tmp = ls[low] i = low k = 2*i while k <= high: if k < high and ls[k] <ls[k + 1]: k +=1 if ls[k] > tmp: ls[i] = ls[k] i = k k = 2*k else: break ls[i] = tmp","categories":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/categories/Algorithm/"}],"tags":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/tags/Algorithm/"}]},{"title":"Algo-List","slug":"Algo-List","date":"2019-03-16T09:17:03.000Z","updated":"2019-07-26T14:49:29.200Z","comments":true,"path":"2019/03/16/Algo-List/","link":"","permalink":"http://yoursite.com/2019/03/16/Algo-List/","excerpt":"链表技巧 借助双指针,三指针 使用list,dict - hash table,set,stack来辅助 常见算法 从尾到头打印链表 链表中倒数第K个结点 反转链表 合并两个排序的链表 复杂链表的复制 两个链表的第一个公共结点 循环链表的入口节点 删除链表中的重复节点","text":"链表技巧 借助双指针,三指针 使用list,dict - hash table,set,stack来辅助 常见算法 从尾到头打印链表 链表中倒数第K个结点 反转链表 合并两个排序的链表 复杂链表的复制 两个链表的第一个公共结点 循环链表的入口节点 删除链表中的重复节点 常见算法 从尾到头打印链表 思路一,将链表反转,然后打印。 思路二,逆向就想到栈,借助栈打印。123456789101112131415161718192021# -*- coding:utf-8 -*-class ListNode: def __init__(self, x): self.val = x self.next = None class Solution: # 返回从尾部到头部的列表值序列,例如[1,2,3] def printListFromTailToHead(self, listNode): # write code here if listNode == None: return list() stack = list() p = listNode while p: stack.append(p.val) p = p.next res = list() while len(stack) >0: res.append(stack.pop(-1)) return res 链表中倒数第K个结点 思路一,双指针,让p指针先走k步,然后p,q再同时走。 需要特别注意的点:head == None,k==0,len(list)<k,而且特别注意循环判断的条件(0,1)12345678910111213141516171819class Solution: def FindKthToTail(self, head, k): # write code here if head == None: return stack = list() p = head length = 0 res = None while p: length +=1 stack.append(p) p = p.next print(length,k) if length >= k: while k>0: res = stack.pop(-1) k -=1 return res 反转链表 思路一,用三个相邻指针分别操作,重要的是头结点的next要为none,结束的时候尾节点要跟之前的连接起来。 思路二,用栈作为索引,重新连接。1234567891011121314151617class Solution: # 返回ListNode def ReverseList(self, pHead): # write code here if pHead == None or pHead.next == None: return pHead p = pHead q = pHead.next k = pHead.next.next p.next = None while k: q.next = p p = q q = k k = k.next q.next = p return q 合并两个排序的链表 其实不要考虑的太复杂。 思路一,首先判空,然后选头节点小的作为新的头节点,然后循环移位,最后将剩余的拼接就好了123456789101112131415161718192021222324252627282930313233# -*- coding:utf-8 -*-# class ListNode:# def __init__(self, x):# self.val = x# self.next = Noneclass Solution: # 返回合并后列表 def Merge(self, pHead1, pHead2): # write code here if pHead1 == None: return pHead2 if pHead2 == None: return pHead1 if pHead1.val < pHead2.val: head = pHead1 pHead1 = pHead1.next else: head = pHead2 pHead2 = pHead2.next p = head while pHead1 and pHead2: if pHead1.val < pHead2.val: p.next = pHead1 pHead1 = pHead1.next else: p.next = pHead2 pHead2 = pHead2.next p = p.next if pHead1 == None: p.next = pHead2 else: p.next = pHead1 return head 复杂链表的复制 思路一,先按照next建立新的链表,然后再对应原始列表逐个查找random节点,时间复杂度为O(n2) 思路二,先按照next建立新的链表,然后使用哈希表进行查找,O(n)+辅助空间 思路三,新建各个节点在原节点之后,方便连接random,然后再进行奇偶链表差分。12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788# encoding: utf-8'''@author: KK@file: copylsit.py@time: 2019/7/7 14:49'''class RandomListNode: def __init__(self, x): self.label = x self.next = None self.random = Noneclass Solution: # 返回 RandomListNode def Clone(self, pHead): # write code here if pHead == None: return None head = RandomListNode(pHead.label) if pHead.next == None: return head p1 = head p2 = pHead.next # 按next复制链表 while p2: q = RandomListNode(p2.label) p1.next = q p1 = p1.next p2 = p2.next # 暴力搜索random节点位置 p1 = head p2 = pHead while p1: p = head stride = 0 if p2.random==None else self.find(pHead,p2.random) # 这些细节要考虑 if stride > 0: while stride > 0: p = p.next stride -= 1 else: p = None p1.random = p p1 = p1.next p2 = p2.next return head def find(self, head,target): count = 0 p = head while p != target: count += 1 p = p.next return count def CloneEnum(self, pHead): # 这种递归方式可行,但是存在问题,python中是引用计数,head.random相当于引用原始链表上的节点,本质上没有达到复制的效果。 if pHead == None: return newNode = RandomListNode(pHead.label) newNode.next = self.CloneEnum(pHead.next) newNode.random = pHead.random return newNode def CloneHash(self,pHead): # 使用hash表的方式进行快速查询操作 if pHead == None: return hash_dict = {} head = RandomListNode(pHead.label) hash_dict[pHead] = head p = pHead.next q = head while p: node = RandomListNode(p.label) hash_dict[p] = node q.next = node p = p.next q = q.next p = pHead q = head while p: if p.random != None: q.random = hash_dict[p.random] p = p.next q = q.next return head 两个链表的第一个公共结点(懂得变通) 思路一,计算两个链表长度差值,让长链表先走差值步,然后一起走,第一个相同结点便可找到。 思路二,因为两个链表的尾部肯定相同,所以可以从后往前比较,这时候考虑使用栈结构。使用两个辅助栈,从后往前找,最后一个相同元素节点。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465# encoding: utf-8'''@author: KK@file: firstCommonNode.py@time: 2019/7/7 19:01'''class ListNode: def __init__(self, x): self.val = x self.next = Noneclass Solution: def FindFirstCommonNode(self, pHead1, pHead2): # write code here if pHead1 == None or pHead2 == None: return p1 = pHead1 p2 = pHead2 len1 = self.get_len(p1) len2 = self.get_len(p2) stride = len1 - len2 if len1 > len2 else len2 - len1 if len1 > len2: while stride > 0: p1 = p1.next stride -=1 else: while stride > 0: p2 = p2.next stride -=1 while p1 != p2: p1 = p1.next p2 = p2.next return p1 def get_len(self,p): count = 0 head = p while head: head = head.next count += 1 return count def FindFirstCommonNodeWithStack(self, pHead1, pHead2): # 使用辅助栈 if pHead1 == None or pHead2 == None: return stack1 = list() stack2 = list() p1 = pHead1 p2 = pHead2 while p1: stack1.append(p1) p1 = p1.next while p2: stack2.append(p2) p2 = p2.next res = None while len(stack1)>0 and len(stack2)>0: tmp1 = stack1.pop(-1) tmp2 = stack2.pop(-1) if tmp1 == tmp2: res = tmp1 else: break return res 循环链表的入口节点 思路一,使用set集合的特性,当碰到在set中存在的元素时即为入口节点 思路二,双指针,比较经典的解法。但是相对来说麻烦一些,先使用双指针判断是否存在环以及环中节点的个数n,然后让指针1先走n步,再让指针2走,当两指针相遇就可以得到入口节点。 思路三,可以将其中一个链表的首尾相连,然后按照循环节点求入口节点去做。12345678910111213141516171819202122232425# encoding: utf-8'''@author: KK@file: EntryNodeOfLoop.py@time: 2019/7/7 20:19'''class ListNode: def __init__(self, x): self.val = x self.next = Noneclass Solution: def EntryNodeOfLoop(self, pHead): # write code here if pHead == None: return tmp = set() p = pHead while p: if p not in tmp: tmp.add(p) else: return p p = p.next return 删除链表中的重复节点 1.重复节点不保留 思路一,使用字典去计数,最后将count大于1的全部去掉。 思路二,使用双指针。先初始化一个新的头节点head,两个前后指针p1,p2,判断指针所在元素是否相同,若不同则连接后,同时后移,若相同,则p2移动到下一个不同元素,然后赋值给p1,p2 = p2.next(这里要注意判断p2是否为None)。如此往复,不要忘记最后一个节点的连接。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263# encoding: utf-8'''@author: KK@file: deleteDuplication.py@time: 2019/7/7 20:32'''class ListNode: def __init__(self, x): self.val = x self.next = Noneclass Solution: def deleteDuplication(self, pHead): # 使用双指针 if pHead == None: return head = ListNode(0) p = head p1 = pHead p2 = pHead.next while p1 and p2: if p1.val == p2.val: # 注意元素全相同的情况,判断条件要把握好 while p2 and p1.val == p2.val: p2 = p2.next p1 = p2 if p2: p2 = p2.next else: # 连接操作,只会在元素值不同的情况下进行 p.next = p1 p = p.next p1 = p1.next p2 = p2.next # 最后一个节点的连接操作, p.next = p1 return head.next def deleteDuplicationWithDict(self, pHead): if pHead == None: return tmp = dict() p = pHead while p: if p.val not in tmp.keys(): tmp[p.val] = 1 else: tmp[p.val] += 1 p = p.next head = ListNode(-1) head.next = pHead q = head p = pHead while p: if tmp[p.val] >1: p = p.next else: q.next = p q = q.next p = p.next # 同样的,最后一个节点不要忘记 q.next = p return head.next","categories":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/categories/Algorithm/"}],"tags":[{"name":"Algorithm","slug":"Algorithm","permalink":"http://yoursite.com/tags/Algorithm/"}]},{"title":"Related-works","slug":"Related-works","date":"2018-08-03T12:54:18.000Z","updated":"2019-08-22T16:15:33.787Z","comments":true,"path":"2018/08/03/Related-works/","link":"","permalink":"http://yoursite.com/2018/08/03/Related-works/","excerpt":"相关Demo 国际目标跟踪竞赛VOT19(单目标跟踪) 基于Deep sort的车辆跟踪(多目标跟踪) 舰船目标检测(目标检测)","text":"相关Demo 国际目标跟踪竞赛VOT19(单目标跟踪) 基于Deep sort的车辆跟踪(多目标跟踪) 舰船目标检测(目标检测) 国际目标跟踪竞赛VOT19(单目标跟踪) 收录截图。Tracker后更名为SiamGIOU。 SiamGIOUIt is an end-to-end tracker based on SiamRPN[], but aims to improve the accuracy of object localization beyond 50%. Furthermore, it can simultaneously suppress the background clutters and distractors.The proposed tracker brings the Generalized Intersection over Union(GIOU)[] constraint into the tracking network, which guides the network with more accurate bounding box predictions. 基于Deep sort的车辆跟踪(多目标跟踪) Demo展示-B站 舰船目标检测(目标检测) 检测结果图示","categories":[],"tags":[]}]}