Deep Learning

[Paper] Discovering Design Concepts for CAD Sketches (2)

ju_young 2023. 4. 30. 13:11
728x90

Implicit concept detection

Sketch encoding

sketch S는 $\mathbb L^0$ primitives와 constraint의 sequence로 나열될 수 있다. 각 $\mathbb L^0$인 instance $t^0$는 type, parameter, reference의 list로 나누어진다. 그리고 각 token category는 특정 embedding module이 사용된다.

 

예를들어 paramter가 scalar 값인 경우 vector로 embedding되기 전에 finite bin으로 quantization 된다. (angle: 30 bins, length: 20 bins, coordinate: 80 bins)

# https://github.com/yyuezhi/SketchConcept/blob/main/data.py
self.length_quantization = 20
self.angle_quantization = 30
self.coordinate_quantization = 80

def length_quantitize(self,num): #length range [0,2]
    return int((num%2)/2.00001 * self.length_quantization)

def angle_quantitize(self,num):
    return int((num%(2*math.pi))/((2*math.pi)+1e-6) * self.angle_quantization)

def coordinate_quantitize(self,num): #coordinate range [-1,1]
    return int(((num+1)%2)/2.00001 * self.coordinate_quantization)

그리고 각 primitive는 최대 5개의 paramter(아마도 construction, length, angle, ref, coord를 말하는 것 같음)를 가지며 모든 parameter embedding을 하나로 packing한다.

 # https://github.com/yyuezhi/SketchConcept/blob/main/data.py
 for entity_idx, entity_key in enumerate(GT_sketch.entities): 
    entity = GT_sketch.entities[entity_key]
    if type(entity) == Line:
        primitive_parameter = [entity.isConstruction, self.coordinate_quantitize(entity.start_point[0]), self.coordinate_quantitize(entity.start_point[1]),self.coordinate_quantitize(entity.end_point[0]),self.coordinate_quantitize(entity.end_point[1])]
    elif type(entity) == Circle:
        primitive_parameter = [entity.isConstruction, self.coordinate_quantitize(entity.xCenter), self.coordinate_quantitize(entity.yCenter),self.length_quantitize(entity.radius)]
    elif type(entity) == Point:
        primitive_parameter = [entity.isConstruction, self.coordinate_quantitize(entity.x), self.coordinate_quantitize(entity.y)]
    elif type(entity) == Arc:
        primitive_parameter = [entity.isConstruction, self.coordinate_quantitize(entity.xCenter), self.coordinate_quantitize(entity.yCenter), self.length_quantitize(entity.radius),self.angle_quantitize(entity.startParam),self.angle_quantitize(entity.endParam)]
    batch_primitive_parameter_GT_list.append(torch.tensor(primitive_parameter,dtype=torch.int64))

batch_primitive_parameter_GT = torch.nn.utils.rnn.pad_sequence(batch_primitive_parameter_GT_list,padding_value= - 1)
batch_prim_param_GT = torch.cat([batch_primitive_parameter_GT,torch.ones(6- batch_primitive_parameter_GT.shape[0],batch_primitive_parameter_GT.shape[1],dtype = torch.int64) * -1 ],dim=0).transpose(0,1)

반면에 primitive index로된 각 constraint reference는 바로 embedding 된다.

 

따라서 $\mathbb L^0$ instance의  각 토큰은 다음과 같이 인코딩된다.

  • $t^0.x$는 나누어진 token들(type, parameter, ref)의 iteration
  • type embedding은 instance의 모든 token들에 공유
  • position embedding는 tokenize된 전체 index를 count
  • parameter, reference는 해당하는 곳에 적용
#below embedding are hardcode embedding parameter group for encoder input! 
#leave it there first 
self.type_embedding = nn.Embedding(self.schema_length+3, self.detection_embedding_dim).to(self.device)  #4 primitive + 15 constraint + 3(start, new, end) token
self.posi_embedding = nn.Embedding(self.global_posi_max_length * self.local_posi_max_length+1, self.detection_embedding_dim).to(self.device)   #max 10 attributes
self.reference_embedding = nn.Embedding(51 , self.detection_embedding_dim).to(self.device)

[reference]

https://github.com/yyuezhi/SketchConcept/blob/main/model_embedding.py

https://github.com/yyuezhi/SketchConcept/blob/44b1cc76069f00f1f04e584deab2654578f8170b/data.py#L176-L287

Sketch encoding format

  • sketch S는 $\mathbb L^0$ primitive token과 constraint token의 sequence로 인코딩
    각 token은 각 indice에 따라 position encoding이 학습됨
  • sequence의 앞, sequence의 끝, 인코딩된 primitive/constraint 각각의 사이사이에 학습 가능한 START, END, NEW 토큰을 추가 (19 = start, 20 = new, 21 = end)

  • 각 primitive는 $\mathbb L^0$와 parameter token으로 표현
  • $\mathbb L^0$의 primitive는 $enc_{type}$으로 표현된 embedding layer에 통과하여 256-dim embedding을 얻음
  • primitive의 parameter는 18 tokens로 concatenation되어있며 각 token은 14-dim이고 256-dim의 zero-padding된 형태이다. 특정 primitive type에 대해서는 해당하는 type의 token들만 사용하고 나머지는 0으로 reset한다. constraint paramter를 위한 slot은 할당하지 않았다고 한다.

* dataset의 __getitem__ 에서는 -1 padding을 주었다.

 

  • 각 constraint는 type token과 여러 reference token으로 표현
  • constraint type token은 primitive에서 사용했던 embedding layer $enc_{type}$을 통해 얻음
  • reference를 encoding하기 위해서는 $enc_{ref}$로 얻은 256-dim embedding을 사용

[reference]

https://github.com/yyuezhi/SketchConcept/blob/44b1cc76069f00f1f04e584deab2654578f8170b/TrainingHarness.py#L156-L187

 

Concept detection

encoder-decoder transformer 구조를 사용하여 detection network를 만듬

  • encoder는 encoding된 sketch sequence($e_{e_i^0}$)를 통과시켜 $e_{e_i^0}^{\prime}$을 얻음
  • decoder는 concept query $\bar{q}_i$ + $\bar{q}_R$을 받고 $e_{e_i^0}^{\prime}$을 self-attention, cross-attention을 통과시고 마지막으로 feed-forward layer를 통과시켜 implicit concept code $q_i$와 $q_R$을 얻음
  • concept code들은 explicit 형태로 확장하기 전에 library $L^1$에서 concept prototype을 선정하여 $q_i^{\prime}$으로 quantization
# https://github.com/yyuezhi/SketchConcept/blob/main/model.py
detection_encoder_layer = TransformerEncoderLayer(self.detection_dim, self.nhead, specs_arch["feedforward_dim"],
                                                specs_arch["dropout"], specs_arch["activation"], self.normalize_before)
detection_encoder_norm = nn.LayerNorm(self.detection_dim) if self.normalize_before else None
self.detection_encoder = TransformerEncoder(detection_encoder_layer, specs_arch["num_encoder_layers"], detection_encoder_norm)


# forward
def code_split(self,code):
    """ p_i, p_R """
    return [code[:,:self.max_detection_query],code[:,-1:]]
        
memory = self.detection_encoder(batch_tensor, src_key_padding_mask=pad_mask, pos=batch_posi) #memory [S0,B,E]
detection_output = self.detection_decoder(tgt, memory, memory_key_padding_mask=pad_mask, query_pos=detection_query,pos=batch_posi)  #detection_output [S1,B,E]

#Process FC accordingly and 
detection_output = detection_output.transpose(0,1)  #batch first [B,S1,E]
structual_input = self.structual_FC(detection_output) #[B,S1,E] S1: number of token detection decoder output E: embedding dimension output by FC
parameter_input = self.parameter_FC(detection_output) #[B,S1,E]
structual_input = self.code_split(structual_input)
parameter_input = self.code_split(parameter_input)

structual_one_hot, structual_selection_code, commitment_loss, step_code, selection_count = self.quantitize(structual_input[0], cad_embedding, mode_flag)

Network details

detection network의 encoder/decoder는 12 layers, 8 attention heads, latent dimension 256을 가진다.

728x90