0%

ICCAD Proj 总结

离ICCAD还有三星期的时候和老板说想放弃投ICCAD,最后在他的“威逼利诱”下,再加之自己的年轻气盛还是答应了并全力以赴的完成了。想想也是蛮了不起的,不过最后一两个星期实在是太累了点,希望以后还是少点这么肝的时候吧。

这大概一个月,一边做proj一边就有新的感触,每有一个感触,都会自己先记一笔,然后不知不觉的备忘录上就塞满了感触。。。现在一次性都记下来当作以后的吸取教训吧。

Idea & Paper Review

前面两个proj 都分成了c++ 和python/pytorch两个板块,因为比较尊重本科生的意见,所以都让他们先选负责的板块(所以都是选的python)。但是有个严重问题:pytorch部分往往和整个proj的idea相关,所以让本科生看paper 找idea实在是好刚没用在刀刃上。因此 两个proj都耽误了比较长的时间。好在自己看paper 总结idea的水平还是比较高了,后面都很快的调整好了方向。

以后在我看来本科生的帮助应该是:

  • 跑实验这种大家都需要时间成本,而且学习成本较低的work
  • 画图,implementation就取决于本科生的学习能力和是否有过类似经验了。倘若我和ta都没学过,那让ta来学一下画图也可以(学习成本一个人花费就可以了)
  • 整个idea方向,除非是比较厉害的本科生(这么看我当年其实还是蛮厉害的,在南科大work都是我来看paper想idea),否则应该是我来看paper 总结,想idea,同时简单的传达意思给ta。毕竟确实我看paper的经验,水平肯定高过大部分本科生的。

最后再吐槽下吧,好羡慕南科大有那么多本科生帮忙,然后本科生也有各种1/2/3作paper,实在是双赢。CU的本科教育就花在了倾庄、人文教育上了(当然有research,但是比起内地学校有组织的research还是差远了)。

Coding style

这是看了DGCNN的mit学长的code发出的感慨。感觉任何语言,尤其python,必须要有一套自己习惯的coding style,包括但不限于:

  • argments
  • i/o
  • error exception handling
  • model architecture

这样的话,自己implementation的时候会方便很多,同时本科小朋友帮忙跑实验也会简单很多(改参数就可以)。哦对了,还有一个要习惯用git。。

Torch Tensor Operation

这算是implementation时候的一个点吧。之前习惯了for loop,这次用多了pytorch tensor后发现实在是太爽了。不仅是速度提升(1000x),整个code 也elegant很多。说下从for loop 转成tensor operation的大概idea吧:

  • 如果index 不影响operation的话,可以直接用tensor[:]操作
  • 如果影响就需要 生成一个index tensor
    • 灵活利用torch gather(有一串index 和一个index对应的value, 想通过index取出所有对应value)
    • 利用torch where 来代替 if else

晒一下自己生成kbbox(对于每个点,return k个最近的且两点bbox间没有第三个点的所有neighbors)的elegant code吧(对比for loop):

For loop version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
for size in range(SIZE_OF_NET):
num_of_sample = int(size)
data = train_data[size].cpu()
# data = train_data[size]
if(len(data) == 0):
continue
index = torch.zeros([data.size(0),data.size(1),num_of_sample]) #B,N,K
for N in range(data.size(1)):
#initialize all value as current node index N
index[:,N,:] = N
#for each batch B
max_sample = 0
print("PROCESS ",size)
for B in range(len(data)):
#for each node N
if(B % 1000 == 0):
print("PROCESS ",size,B)
for N in range(data.size(1)):
sample = 0
#We then check each point Q: whether the bounding box between Q and K has no other points, if yes, we add Q in index[B,N,:]
for Q in range(data.size(1)):
if(Q == N):
continue
#Coordinate of Q related to N
C_QN = data[B,Q,:] - data[B,N,:]
is_index = True
for J in range(data.size(1)):
if(J == Q or J == N):
continue
C_JN = data[B,J,:] - data[B,N,:]
if ((C_JN*C_QN) > (C_JN * C_JN)).min():
# print("Q cannot be index of N due to J",C_QN,C_JN)
is_index = False
break
if(is_index):
sample += 1
index[B,N,sample] = Q
if(sample > max_sample):
max_sample = sample
print("PROCESS ",size, "max_sample: ",max_sample)
torch.save(index[:,:,:max_sample+1],"../../data/tree/"+str(size))

Tensor operation version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#data : raw distance data (B,N,2)
data = tensor
if(len(data) == 0):
continue
# print(tensor.size())
B,N,_ = data.size()
# data = train_data[size]
# print(tensor[0])
#inner : (B,N,2) * (B,2,N) = (B,N,N )
inner = -2 * torch.matmul(data,data.transpose(2, 1))
xx = torch.sum(data ** 2, dim=2, keepdim=True)
#pairwise_distance: relative distance between N1 & N2 (B,N1,N2)
pairwise_distance = -xx - inner - xx.transpose(2, 1)
# print("pairwise_distance",pairwise_distance[0])

# BNN2 = data.view(B,N,1,2).repeat(1,1,N,1)
# BQQ2 = data.view(B,1,N,2).repeat(1,N,1,1)
# print("BNN2",BNN2[0][0])
# print("BQQ2",BQQ2[0][0])
#BNQ2: value in (b,n,q) is the relative coordinates between node n and node q at b_th batch.
# BNQ2 = BNN2 - BQQ2
BNQ2 = data.view(B,N,1,2) - data.view(B,1,N,2)
# print("BNQ2",BNQ2[0][0])
#CQN: value in (b,n,q,j) is the relative coordinates between node n and node q at b_th batch.
#CJN: value in (b,n,q,j) is the relative coordinates between node n and node j at b_th batch.
#UPDATE: The view step here is not neccesary since pytorch will automatically scale the tensor shape
CQN = BNQ2.view(B,N,N,1,2)
CJN = BNQ2.view(B,N,1,N,2)
# print("CQN",CQN[0][0])
# print("CJN",CJN[0][0])
#BNQJ: value in (b,n,q,j) indicates that when n is the centroid, whether j is in the bounding box of q and n (and such makes q not connected to j)
#True means the j influences q
BNQJ = (CQN*CJN > CJN*CJN).min(-1)[0]
# print("BNQJ",BNQJ[0][0])
#BNQJ: value in (b,n,q) indicates that when n is the centroid, whether q cannot connect to n
#True mans q cannot conncet n
BNQ = BNQJ.max(-1)[0]
# print("BNQ",BNQ[0])
#For those q who cannot connect to n (which is exactly True in BNQ), we assign a large distance value(10000)
_,index = ((pairwise_distance - (BNQ.long() * 10000))).topk(k=4,dim = 2)
# print("index",index[0])
# exit()
torch.save(index,"../../data/tree/kbbox_"+str(i)+'_'+str(j))

总结

这个work应该是自己这么多work里面最满意的一个了?虽然比较仓促,但是整个story是连贯的,对应方法也不是和一般dl-based work一样讲究一个玄学,基本都是有规律有原因能解释的。最后的结果也是比较满意(最后两三天的时候加上了FLUTE的结果实在是不太行,临时把FLUTE remove了,最后一天才算出结果。。也是没谁了)

这个要是结果ICCAD没中可就滑稽了。投paper这个东西就真的可以叫做玄学了。ß