# 1st place solution (0.220 public LB)

Hi, the post may be a little late. Thanks to organizers and congratulations to all!
Background
For the record, I want to state that I am really new to Kaggle and actually really new to machine learning. I only started to work on machine learning 9 month ago. My background is in 3D Computer Graphics so I looked into the problems more in the view of 3D than in machine learning. Pardon me if I made any silly mistake with regard to machine learning.
Before this competition, I won 2nd place in CVPR 2019 competition WAD-Beyond Single-Frame Perception hosted by Baidu on a similar topic: 3D detection with Lidar points (
[http://wad.ai/2019/challenge.html](http://wad.ai/2019/challenge.html)
). The tricks we used is actually based on that competition. So we just adopt and modified the tricks and have no idea about the performance without the tricks.
Models
Our method is based on Voxelnet (
[traveller59](https://github.com/traveller59/second.pytorch)
) But our tricks can be applied to any other network. I gave a try with PointRCNN but got no luck.
Basic Setting:
- No external data
- Data Augmentation: flip x and y, random rotation, random scaling and random translation
- No Ground Truth Augmentation
- Detection Range [-100,-100,-5,100,100,3]
- No direction classifier
- No specific post processing but score thresholding (0.1) and NMS
Two types of voxelnet are implemented in second: FHD and PointPillars. We use both. Based on the idea that ensembling models with more difference results in better results, we use different settings to train a set of models. E.g. we use voxel size 0.1, 0.125, 0.2, 0.25 for PointPillar, 0.1 and 0.125 for FHD. Different Voxel Feature Extractors are also used for different models(e.g. PillarFeatureNet, PillarFeatureNetRadius,PillarFeatureNetRadiusHeight). RPN is modified so that the final resolution is 200 X 200 or 250 X 250.
Key Tricks
The key to our method is Test time augmentation (TTA) and model ensemble with a specific 3D box fusion method.
Test Time Augmentation
We transform the point cloud into several copies. Each copy is then feed into the network and get the predicted boxes. Then the predicted boxes are transformed back. For example, we can rotate the point cloud 20 degrees. After we got the predicted boxes (after NMS), we rotate the predicted boxes -20 degrees (both the center position and yaw angle are changed). We do this for many copies and fuse the results. During the competition, we only use 4 copies: original, flip x, flip y, flip x and y. We tried more copies with rotation, scaling and translation. It gives slightly better results but needs more inference time.
Model ensemble
We use TTA to get the predicted boxes for each model and fuse the results.
Best Single Model (No TTA):          >0.175 (I only got the score for a model with TTA score 0.193. But I  got a better model with TTA score 0.197)
Best Single Model (TTA):    0.197
Ensembling 7 best models: 0.220
3D box fusion
After we got several copies of predicted boxes (from TTA or model ensemble), we need to fuse them. We choose boxes with same label and IOU > 0.6 to fuse into one. After the competition,we tried Weighted Boxes Fusion: ensembling boxes for object detection models. It actually gives better results (0.222 Public LB) but is slower. To fuse boxes, the center and size are directly weighted averaged. The key is the yaw angle. If you predict the direction and can trust it. You may use sin and cos interpolation.
![](assets/ba37c9159a0d67dea3ac01cb.png)
However, in our implementation, we did not use direction classifier (it won’t affect the score and it can not be 100% accurate). We need to deal with one ambiguity: yaw angle is the same to yaw angle + 180 degrees. Say for one box, one prediction might give yaw angle 175 degrees or -5 degrees.
It  does not matter since it is of the same IOU to ground truth. However, when we do box fusion, it matters. Say for the same box, another prediction gives yaw angle 5 degrees. If the first prediction is -5 degree. The average is 0 degree. It is okay. However, if the first prediction is 175 degree, the averaged boxes will be with yaw angle 90 degrees.
![](assets/0ce842a8fb486e037240aa28.png)
To deal with this problem, we use an intuitive method: average 2 * yaw instead of yaw. 
The idea is that sin and cos interpolation of yaw angle can remove 360 degrees ambiguity. So sin and cos interpolation of 2 * yaw angle can remove 180 degrees ambiguity. I have no theoretical proof yet but intuitively feel it is correct. Actually the idea came into my head when I was telling bedtime story to my daughter. She asked me to tell the story over and over again so I just repeated it😂 !
I uploaded our code and pretrained models. You may give a try. Have fun!
p.s. 
For sparse convolution, since spconv used in second might be patented, we replace it with
[this one](https://github.com/facebookresearch/SparseConvNet)
. It is much slower.