Deep Learning

SketchGraphs

ju_young 2023. 5. 19. 05:28
728x90

Data

https://github.com/PrincetonLIPS/SketchGraphs

 

GitHub - PrincetonLIPS/SketchGraphs: A dataset of 15 million CAD sketches with geometric constraint graphs.

A dataset of 15 million CAD sketches with geometric constraint graphs. - GitHub - PrincetonLIPS/SketchGraphs: A dataset of 15 million CAD sketches with geometric constraint graphs.

github.com


Demo

seq_data = flat_array.load_dictionary_flat('./data/sg_all.npy')
seq_data['sequences']
# FlatArray(len=15020918, mem=13.3 GB)
seq = seq_data['sequences'][1320]
print(*seq, sep='\n')
"""
NodeOp(label=<EntityType.External: 7>, parameters={})
NodeOp(label=<EntityType.Line: 1>, parameters={'isConstruction': False, 'dirX': 0.0, 'dirY': -1.0, 'pntX': -0.015875, 'pntY': 0.0, 'startParam': -0.038735000000000006, 'endParam': 0.038735000000000006})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(1, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(2, 1), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(2, 0, 0), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(3, 1), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(3, 0, 0), parameters={})
NodeOp(label=<EntityType.Arc: 6>, parameters={'isConstruction': False, 'clockwise': False, 'xCenter': -0.013335, 'yCenter': 0.038735000000000006, 'xDir': 1.0, 'yDir': 0.0, 'radius': 0.0025400000000000006, 'startParam': 1.5707963267948966, 'endParam': 3.141592653589793})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(4, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Center: 103>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(5, 4), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(6, 4), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(6, 0, 0), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(7, 4), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(7, 2), parameters={})
NodeOp(label=<EntityType.Line: 1>, parameters={'isConstruction': False, 'dirX': 1.0, 'dirY': 0.0, 'pntX': 5.204170427930421e-18, 'pntY': 0.041275000000000006, 'startParam': -0.013335000000000005, 'endParam': 0.013335000000000008})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(8, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(9, 8), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(9, 6), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
...
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(28, 26), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(28, 20), parameters={})
NodeOp(label=<EntityType.Stop: 8>, parameters={})
"""

SN_End, Sn_Start는 끝점, 시작점을 의미하고 SN_Center는 중심점을 의미한다. 따라서 Line은 SN_End, Sn_Start을 가지고 Arc는 SN_End, Sn_Start, SN_Center를 가지는 것을 확인할 수 있다.

sketch = datalib.sketch_from_sequence(seq)
datalib.render_sketch(sketch)

datalib.render_sketch(sketch, hand_drawn=True)

G = datalib.pgvgraph_from_sequence(seq)
datalib.render_graph(G, './graph.png')
img = plt.imread('./graph.png')
fig = plt.figure(dpi=500)
plt.imshow(img)
plt.axis('off')


Onshape

https://www.onshape.com/en/

 

Onshape | Product Development Platform

Onshape is a product development platform that brings together all the tools needed to develop a product from conception to production.

www.onshape.com

education으로 가입하여 실습을 진행해보았다.

API methods과 참고는 다음 documentation에서 할 수 있었다.

https://onshape-public.github.io/docs/featureaccess/#api-methods

# 현재 document의 모든 feature들을 가져옴
onshape_call.get_features(url)
"""
{'features': [{'type': 151,
   'typeName': 'BTMSketch',
   'message': {'entities': [{'type': 155,
      'typeName': 'BTMSketchCurveSegment',
      'message': {'startPointId': '1.start',
       'endPointId': '1.end',
       'startParam': -0.038735000000000006,
       'endParam': 0.038735000000000006,
       'geometry': {'type': 117,
        'typeName': 'BTCurveGeometryLine',
        'message': {'pntX': -0.015875,
         'pntY': 0.0,
         'dirX': 0.0,
         'dirY': -1.0}},
       'centerId': '',
       'internalIds': [],
       'isConstruction': False,
       'parameters': [],
       'isFromSplineHandle': False,
       'isFromEndpointSplineHandle': False,
       'isFromSplineControlPolygon': False,
       'entityId': '1',
       'namespace': '',
       'hasUserCode': False,
       'nodeId': 'MhyvymBuSvG+175Eo'}},
...
 'serializationVersion': '1.2.0',
 'sourceMicroversion': 'e62e13cc54bc6bfba667522b',
 'rejectMicroversionSkew': False,
 'microversionSkew': False,
 'libraryVersion': 2022}
"""

onshape의 part studio에서는 위와 같이 Front, Top, Right plane이 있는데 기본적으로 sketch를 api를 사용해서 추가하면 right plane에 추가된다. 따라서 다른 plane을 지정하려면 먼저 다음과 같이 geometryId를 확인해야한다.

def add_featurescript(url, script, logging=False):
    # Get doc ids and create Client
    docid, wid, eid = _parse_url(url)
    client = _create_client(logging)
    # Send to Onshape
    client.add_featurescript(docid, wid, eid, payload=script)

def add_featurescript(self, did, wid, eid, payload):
    return self._api.request('post', '/api/partstudios/d/' + did + '/w/' + wid + '/e/' + eid + '/featurescript', body=payload)
        
script = {
  "script" :
    "function(context is Context, queries){return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\"Top\"), EntityType.FACE)));}",
  "queries" : []
}
onshape_call.add_featurescript(url, script, logging=True)
"""
details: {
  "console" : "",
  "notices" : [ ],
  "result" : {
    "type" : 1499,
    "typeName" : "BTFSValueArray",
    "message" : {
      "value" : [ {
        "type" : 1422,
        "typeName" : "BTFSValueString",
        "message" : {
          "value" : "JDC",
          "typeTag" : ""
        }
      } ],
      "typeTag" : ""
    }
  },
  "serializationVersion" : "1.2.0",
...
  "rejectMicroversionSkew" : false,
  "microversionSkew" : false,
  "libraryVersion" : 2022
}
"""

 message의 가장 안쪽에 value "JDC"를 Top plane의 geometryId로 사용한다. 그리고 add_feature를 할때 parameters 부분을 다음과 같이 수정해주면 된다.

            "parameters": [
                {
                    "type": 148,
                    "typeName": "BTMParameterQueryList",
                    "message": {
                        "queries": [
                            {
                                "type": 138,
                                "typeName": "BTMIndividualQuery",
                                "message": {
                                    "geometryIds": [
                                        "JDC"
                                    ],
                                    "hasUserCode": false
                                }
                            }
                        ],
                        "parameterId": "sketchPlane",
                        "hasUserCode": false
                    }
                }
            ],

constraint를 없애고 sketch를 추가한 것과 없애지않고 추가한 것의 차이를 확인해보겠다.

# remove constraints
no_constraint_sketch = deepcopy(sketch)
no_constraint_sketch.constraints.clear()

# with constraints
with_constraints_sketch = deepcopy(unsolved_sketch)
remove constraints with constraints

추가한 sketch를 다시 불러오기위해서는 다음과 같이 get_info(api endpoint: sketches)로 가져오고 constraint를 다시 적용하기위해서는 간단하게 sketch의 constraints에 넣어주면 된다.

# get info
unsolved_sketch_info = onshape_call.get_info(url, 'No_Constraints_Sketch')
unsolved_sketch = datalib.Sketch.from_info(unsolved_sketch_info['geomEntities'])

# apply constraints
unsolved_sketch.constraints = sketch.constraints

Autoconstrain Model

위 github에 autoconstrain을 위한 model이 있어서 논문을 살펴보았는데 message passing networks(MPNs)를 기반으로한 auto-regressive model이라고 한다.

  1. input representation component: primitives와 constraints의 feature embedding
  2. message-passing component: graph structure를 사용한 feature 변환
  3. readout component: 변환된 feature에 따른 확률값 출력

- Train / Eval

논문에서는 150epoch을 돌렸다고 나와있는데 epoch당 3시간이 걸려서 3epoch까지 돌려보았다. (eval은 약 1시간 30분)

train data는 약 5억5천만개(batch_size: 1248), evaluation에 사용한 test data(batch_size: 512)는 1억 6천만개이다.

epoch recall precision
1 0.54 0.51
3 0.58 0.59

 

728x90