molcraft 0.1.0a16__py3-none-any.whl → 0.1.0a18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of molcraft might be problematic. Click here for more details.
- molcraft/__init__.py +4 -3
- molcraft/applications/chromatography.py +0 -0
- molcraft/applications/proteomics.py +141 -106
- molcraft/chem.py +17 -22
- molcraft/datasets.py +6 -6
- molcraft/descriptors.py +14 -0
- molcraft/features.py +50 -58
- molcraft/featurizers.py +257 -487
- molcraft/layers.py +95 -40
- molcraft/models.py +2 -0
- molcraft/records.py +24 -15
- {molcraft-0.1.0a16.dist-info → molcraft-0.1.0a18.dist-info}/METADATA +13 -12
- molcraft-0.1.0a18.dist-info/RECORD +21 -0
- molcraft/conformers.py +0 -151
- molcraft-0.1.0a16.dist-info/RECORD +0 -21
- {molcraft-0.1.0a16.dist-info → molcraft-0.1.0a18.dist-info}/WHEEL +0 -0
- {molcraft-0.1.0a16.dist-info → molcraft-0.1.0a18.dist-info}/licenses/LICENSE +0 -0
- {molcraft-0.1.0a16.dist-info → molcraft-0.1.0a18.dist-info}/top_level.txt +0 -0
molcraft/layers.py
CHANGED
|
@@ -380,11 +380,14 @@ class GraphConv(GraphLayer):
|
|
|
380
380
|
self._update_final_dense = self.get_dense(self.units)
|
|
381
381
|
|
|
382
382
|
if not self._normalize:
|
|
383
|
-
self.
|
|
383
|
+
self._message_norm = keras.layers.Identity()
|
|
384
|
+
self._update_norm = keras.layers.Identity()
|
|
384
385
|
elif str(self._normalize).lower().startswith('layer'):
|
|
385
|
-
self.
|
|
386
|
+
self._message_norm = keras.layers.LayerNormalization()
|
|
387
|
+
self._update_norm = keras.layers.LayerNormalization()
|
|
386
388
|
else:
|
|
387
|
-
self.
|
|
389
|
+
self._message_norm = keras.layers.BatchNormalization()
|
|
390
|
+
self._update_norm = keras.layers.BatchNormalization()
|
|
388
391
|
|
|
389
392
|
def propagate(self, tensor: tensors.GraphTensor) -> tensors.GraphTensor:
|
|
390
393
|
"""Forward pass.
|
|
@@ -430,7 +433,7 @@ class GraphConv(GraphLayer):
|
|
|
430
433
|
elif add_aggregate:
|
|
431
434
|
update = update.update({'node': {'aggregate': None}})
|
|
432
435
|
|
|
433
|
-
if not self._skip_connect
|
|
436
|
+
if not self._skip_connect:
|
|
434
437
|
return update
|
|
435
438
|
|
|
436
439
|
feature = update.node['feature']
|
|
@@ -438,8 +441,6 @@ class GraphConv(GraphLayer):
|
|
|
438
441
|
if self._skip_connect:
|
|
439
442
|
feature += residual
|
|
440
443
|
|
|
441
|
-
feature = self._normalization(feature)
|
|
442
|
-
|
|
443
444
|
return update.update({'node': {'feature': feature}})
|
|
444
445
|
|
|
445
446
|
def message(self, tensor: tensors.GraphTensor) -> tensors.GraphTensor:
|
|
@@ -480,6 +481,7 @@ class GraphConv(GraphLayer):
|
|
|
480
481
|
axis=-1
|
|
481
482
|
)
|
|
482
483
|
message = self._message_intermediate_dense(message)
|
|
484
|
+
message = self._message_norm(message)
|
|
483
485
|
message = self._message_intermediate_activation(message)
|
|
484
486
|
message = self._message_final_dense(message)
|
|
485
487
|
return tensor.update({'edge': {'message': message}})
|
|
@@ -519,6 +521,7 @@ class GraphConv(GraphLayer):
|
|
|
519
521
|
"""
|
|
520
522
|
aggregate = tensor.node['aggregate']
|
|
521
523
|
node_feature = self._update_intermediate_dense(aggregate)
|
|
524
|
+
node_feature = self._update_norm(node_feature)
|
|
522
525
|
node_feature = self._update_intermediate_activation(node_feature)
|
|
523
526
|
node_feature = self._update_final_dense(node_feature)
|
|
524
527
|
return tensor.update(
|
|
@@ -1312,13 +1315,19 @@ class NodeEmbedding(GraphLayer):
|
|
|
1312
1315
|
|
|
1313
1316
|
def __init__(
|
|
1314
1317
|
self,
|
|
1315
|
-
dim: int = None,
|
|
1318
|
+
dim: int | None = None,
|
|
1319
|
+
intermediate_dim: int | None = None,
|
|
1320
|
+
intermediate_activation: str | keras.layers.Activation | None = 'relu',
|
|
1316
1321
|
normalize: bool = False,
|
|
1317
1322
|
embed_context: bool = False,
|
|
1318
1323
|
**kwargs
|
|
1319
1324
|
) -> None:
|
|
1320
1325
|
super().__init__(**kwargs)
|
|
1321
1326
|
self.dim = dim
|
|
1327
|
+
self._intermediate_dim = intermediate_dim
|
|
1328
|
+
self._intermediate_activation = keras.activations.get(
|
|
1329
|
+
intermediate_activation
|
|
1330
|
+
)
|
|
1322
1331
|
self._normalize = normalize
|
|
1323
1332
|
self._embed_context = embed_context
|
|
1324
1333
|
|
|
@@ -1326,30 +1335,38 @@ class NodeEmbedding(GraphLayer):
|
|
|
1326
1335
|
feature_dim = spec.node['feature'].shape[-1]
|
|
1327
1336
|
if not self.dim:
|
|
1328
1337
|
self.dim = feature_dim
|
|
1329
|
-
|
|
1330
|
-
|
|
1338
|
+
if not self._intermediate_dim:
|
|
1339
|
+
self._intermediate_dim = self.dim * 2
|
|
1340
|
+
self._node_dense = self.get_dense(
|
|
1341
|
+
self._intermediate_dim, activation=self._intermediate_activation
|
|
1342
|
+
)
|
|
1331
1343
|
self._has_super = 'super' in spec.node
|
|
1332
1344
|
has_context_feature = 'feature' in spec.context
|
|
1333
1345
|
if not has_context_feature:
|
|
1334
1346
|
self._embed_context = False
|
|
1335
1347
|
if self._has_super and not self._embed_context:
|
|
1336
|
-
self._super_feature = self.get_weight(
|
|
1348
|
+
self._super_feature = self.get_weight(
|
|
1349
|
+
shape=[self._intermediate_dim], name='super_node_feature'
|
|
1350
|
+
)
|
|
1337
1351
|
if self._embed_context:
|
|
1338
|
-
self._context_dense = self.get_dense(
|
|
1339
|
-
|
|
1352
|
+
self._context_dense = self.get_dense(
|
|
1353
|
+
self._intermediate_dim, activation=self._intermediate_activation
|
|
1354
|
+
)
|
|
1340
1355
|
if not self._normalize:
|
|
1341
1356
|
self._norm = keras.layers.Identity()
|
|
1342
1357
|
elif str(self._normalize).lower().startswith('layer'):
|
|
1343
1358
|
self._norm = keras.layers.LayerNormalization()
|
|
1344
1359
|
else:
|
|
1345
1360
|
self._norm = keras.layers.BatchNormalization()
|
|
1361
|
+
self._dense = self.get_dense(self.dim)
|
|
1346
1362
|
|
|
1347
1363
|
def propagate(self, tensor: tensors.GraphTensor) -> tensors.GraphTensor:
|
|
1348
1364
|
feature = self._node_dense(tensor.node['feature'])
|
|
1349
1365
|
|
|
1350
1366
|
if self._has_super and not self._embed_context:
|
|
1351
1367
|
super_mask = keras.ops.expand_dims(tensor.node['super'], 1)
|
|
1352
|
-
|
|
1368
|
+
super_feature = self._intermediate_activation(self._super_feature)
|
|
1369
|
+
feature = keras.ops.where(super_mask, super_feature, feature)
|
|
1353
1370
|
|
|
1354
1371
|
if self._embed_context:
|
|
1355
1372
|
context_feature = self._context_dense(tensor.context['feature'])
|
|
@@ -1357,6 +1374,7 @@ class NodeEmbedding(GraphLayer):
|
|
|
1357
1374
|
tensor = tensor.update({'context': {'feature': None}})
|
|
1358
1375
|
|
|
1359
1376
|
feature = self._norm(feature)
|
|
1377
|
+
feature = self._dense(feature)
|
|
1360
1378
|
|
|
1361
1379
|
return tensor.update({'node': {'feature': feature}})
|
|
1362
1380
|
|
|
@@ -1364,6 +1382,10 @@ class NodeEmbedding(GraphLayer):
|
|
|
1364
1382
|
config = super().get_config()
|
|
1365
1383
|
config.update({
|
|
1366
1384
|
'dim': self.dim,
|
|
1385
|
+
'intermediate_dim': self._intermediate_dim,
|
|
1386
|
+
'intermediate_activation': keras.activations.serialize(
|
|
1387
|
+
self._intermediate_activation
|
|
1388
|
+
),
|
|
1367
1389
|
'normalize': self._normalize,
|
|
1368
1390
|
'embed_context': self._embed_context,
|
|
1369
1391
|
})
|
|
@@ -1381,50 +1403,67 @@ class EdgeEmbedding(GraphLayer):
|
|
|
1381
1403
|
def __init__(
|
|
1382
1404
|
self,
|
|
1383
1405
|
dim: int = None,
|
|
1406
|
+
intermediate_dim: int | None = None,
|
|
1407
|
+
intermediate_activation: str | keras.layers.Activation | None = 'relu',
|
|
1384
1408
|
normalize: bool = False,
|
|
1385
1409
|
**kwargs
|
|
1386
1410
|
) -> None:
|
|
1387
1411
|
super().__init__(**kwargs)
|
|
1388
1412
|
self.dim = dim
|
|
1413
|
+
self._intermediate_dim = intermediate_dim
|
|
1414
|
+
self._intermediate_activation = keras.activations.get(
|
|
1415
|
+
intermediate_activation
|
|
1416
|
+
)
|
|
1389
1417
|
self._normalize = normalize
|
|
1390
1418
|
|
|
1391
1419
|
def build(self, spec: tensors.GraphTensor.Spec) -> None:
|
|
1392
1420
|
feature_dim = spec.edge['feature'].shape[-1]
|
|
1393
1421
|
if not self.dim:
|
|
1394
1422
|
self.dim = feature_dim
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
self.
|
|
1398
|
-
|
|
1423
|
+
if not self._intermediate_dim:
|
|
1424
|
+
self._intermediate_dim = self.dim * 2
|
|
1425
|
+
self._edge_dense = self.get_dense(
|
|
1426
|
+
self._intermediate_dim, activation=self._intermediate_activation
|
|
1427
|
+
)
|
|
1428
|
+
self._self_loop_feature = self.get_weight(
|
|
1429
|
+
shape=[self._intermediate_dim], name='self_loop_edge_feature'
|
|
1430
|
+
)
|
|
1399
1431
|
self._has_super = 'super' in spec.edge
|
|
1400
1432
|
if self._has_super:
|
|
1401
|
-
self._super_feature = self.get_weight(
|
|
1402
|
-
|
|
1433
|
+
self._super_feature = self.get_weight(
|
|
1434
|
+
shape=[self._intermediate_dim], name='super_edge_feature'
|
|
1435
|
+
)
|
|
1403
1436
|
if not self._normalize:
|
|
1404
1437
|
self._norm = keras.layers.Identity()
|
|
1405
1438
|
elif str(self._normalize).lower().startswith('layer'):
|
|
1406
1439
|
self._norm = keras.layers.LayerNormalization()
|
|
1407
1440
|
else:
|
|
1408
1441
|
self._norm = keras.layers.BatchNormalization()
|
|
1442
|
+
self._dense = self.get_dense(self.dim)
|
|
1409
1443
|
|
|
1410
1444
|
def propagate(self, tensor: tensors.GraphTensor) -> tensors.GraphTensor:
|
|
1411
1445
|
feature = self._edge_dense(tensor.edge['feature'])
|
|
1412
1446
|
|
|
1413
1447
|
if self._has_super:
|
|
1414
1448
|
super_mask = keras.ops.expand_dims(tensor.edge['super'], 1)
|
|
1415
|
-
|
|
1449
|
+
super_feature = self._intermediate_activation(self._super_feature)
|
|
1450
|
+
feature = keras.ops.where(super_mask, super_feature, feature)
|
|
1416
1451
|
|
|
1417
1452
|
self_loop_mask = keras.ops.expand_dims(tensor.edge['source'] == tensor.edge['target'], 1)
|
|
1418
|
-
|
|
1419
|
-
|
|
1453
|
+
self_loop_feature = self._intermediate_activation(self._self_loop_feature)
|
|
1454
|
+
feature = keras.ops.where(self_loop_mask, self_loop_feature, feature)
|
|
1420
1455
|
feature = self._norm(feature)
|
|
1421
|
-
|
|
1456
|
+
feature = self._dense(feature)
|
|
1422
1457
|
return tensor.update({'edge': {'feature': feature}})
|
|
1423
1458
|
|
|
1424
1459
|
def get_config(self) -> dict:
|
|
1425
1460
|
config = super().get_config()
|
|
1426
1461
|
config.update({
|
|
1427
1462
|
'dim': self.dim,
|
|
1463
|
+
'intermediate_dim': self._intermediate_dim,
|
|
1464
|
+
'intermediate_activation': keras.activations.serialize(
|
|
1465
|
+
self._intermediate_activation
|
|
1466
|
+
),
|
|
1428
1467
|
'normalize': self._normalize,
|
|
1429
1468
|
})
|
|
1430
1469
|
return config
|
|
@@ -1441,42 +1480,60 @@ class AddContext(GraphLayer):
|
|
|
1441
1480
|
def __init__(
|
|
1442
1481
|
self,
|
|
1443
1482
|
field: str = 'feature',
|
|
1444
|
-
|
|
1483
|
+
intermediate_dim: int | None = None,
|
|
1484
|
+
intermediate_activation: str | keras.layers.Activation | None = 'relu',
|
|
1485
|
+
drop: bool = False,
|
|
1445
1486
|
normalize: bool = False,
|
|
1446
1487
|
**kwargs
|
|
1447
1488
|
) -> None:
|
|
1448
1489
|
super().__init__(**kwargs)
|
|
1449
|
-
self.
|
|
1450
|
-
self.
|
|
1490
|
+
self._field = field
|
|
1491
|
+
self._drop = drop
|
|
1492
|
+
self._intermediate_dim = intermediate_dim
|
|
1493
|
+
self._intermediate_activation = keras.activations.get(
|
|
1494
|
+
intermediate_activation
|
|
1495
|
+
)
|
|
1451
1496
|
self._normalize = normalize
|
|
1452
1497
|
|
|
1453
1498
|
def build(self, spec: tensors.GraphTensor.Spec) -> None:
|
|
1454
1499
|
feature_dim = spec.node['feature'].shape[-1]
|
|
1455
|
-
self.
|
|
1500
|
+
if self._intermediate_dim is None:
|
|
1501
|
+
self._intermediate_dim = feature_dim * 2
|
|
1502
|
+
self._intermediate_dense = self.get_dense(
|
|
1503
|
+
self._intermediate_dim, activation=self._intermediate_activation
|
|
1504
|
+
)
|
|
1505
|
+
self._final_dense = self.get_dense(feature_dim)
|
|
1456
1506
|
if not self._normalize:
|
|
1457
|
-
self.
|
|
1507
|
+
self._intermediate_norm = keras.layers.Identity()
|
|
1458
1508
|
elif str(self._normalize).lower().startswith('layer'):
|
|
1459
|
-
self.
|
|
1509
|
+
self._intermediate_norm = keras.layers.LayerNormalization()
|
|
1460
1510
|
else:
|
|
1461
|
-
self.
|
|
1511
|
+
self._intermediate_norm = keras.layers.BatchNormalization()
|
|
1462
1512
|
|
|
1463
1513
|
def propagate(self, tensor: tensors.GraphTensor) -> tensors.GraphTensor:
|
|
1464
|
-
context = tensor.context[self.
|
|
1465
|
-
context = self.
|
|
1466
|
-
context = self.
|
|
1514
|
+
context = tensor.context[self._field]
|
|
1515
|
+
context = self._intermediate_dense(context)
|
|
1516
|
+
context = self._intermediate_norm(context)
|
|
1517
|
+
context = self._final_dense(context)
|
|
1467
1518
|
node_feature = ops.scatter_add(
|
|
1468
1519
|
tensor.node['feature'], tensor.node['super'], context
|
|
1469
1520
|
)
|
|
1470
1521
|
data = {'node': {'feature': node_feature}}
|
|
1471
|
-
if self.
|
|
1472
|
-
data['context'] = {self.
|
|
1522
|
+
if self._drop:
|
|
1523
|
+
data['context'] = {self._field: None}
|
|
1473
1524
|
return tensor.update(data)
|
|
1474
1525
|
|
|
1475
1526
|
def get_config(self) -> dict:
|
|
1476
1527
|
config = super().get_config()
|
|
1477
|
-
config
|
|
1478
|
-
|
|
1479
|
-
|
|
1528
|
+
config.update({
|
|
1529
|
+
'field': self._field,
|
|
1530
|
+
'intermediate_dim': self._intermediate_dim,
|
|
1531
|
+
'intermediate_activation': keras.activations.serialize(
|
|
1532
|
+
self._intermediate_activation
|
|
1533
|
+
),
|
|
1534
|
+
'drop': self._drop,
|
|
1535
|
+
'normalize': self._normalize,
|
|
1536
|
+
})
|
|
1480
1537
|
return config
|
|
1481
1538
|
|
|
1482
1539
|
|
|
@@ -1738,5 +1795,3 @@ def _spec_from_inputs(inputs):
|
|
|
1738
1795
|
return spec
|
|
1739
1796
|
return tensors.GraphTensor.Spec(**nested_specs)
|
|
1740
1797
|
|
|
1741
|
-
|
|
1742
|
-
GraphTransformer = GTConv
|
molcraft/models.py
CHANGED
|
@@ -154,6 +154,7 @@ class GraphModel(layers.GraphLayer, keras.models.Model):
|
|
|
154
154
|
return graph
|
|
155
155
|
|
|
156
156
|
def get_config(self):
|
|
157
|
+
"""Obtain model config."""
|
|
157
158
|
config = super().get_config()
|
|
158
159
|
if hasattr(self, '_model_layers') and self._model_layers is not None:
|
|
159
160
|
config['model_layers'] = [
|
|
@@ -164,6 +165,7 @@ class GraphModel(layers.GraphLayer, keras.models.Model):
|
|
|
164
165
|
|
|
165
166
|
@classmethod
|
|
166
167
|
def from_config(cls, config: dict):
|
|
168
|
+
"""Obtain model from model config."""
|
|
167
169
|
if 'model_layers' in config:
|
|
168
170
|
config['model_layers'] = [
|
|
169
171
|
keras.saving.deserialize_keras_object(l)
|
molcraft/records.py
CHANGED
|
@@ -14,7 +14,7 @@ from molcraft import featurizers
|
|
|
14
14
|
|
|
15
15
|
def write(
|
|
16
16
|
inputs: list[str | tuple],
|
|
17
|
-
featurizer: featurizers.
|
|
17
|
+
featurizer: featurizers.GraphFeaturizer,
|
|
18
18
|
path: str,
|
|
19
19
|
overwrite: bool = True,
|
|
20
20
|
num_files: typing.Optional[int] = None,
|
|
@@ -23,10 +23,13 @@ def write(
|
|
|
23
23
|
device: str = '/cpu:0'
|
|
24
24
|
) -> None:
|
|
25
25
|
|
|
26
|
-
if os.path.isdir(path)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if os.path.isdir(path):
|
|
27
|
+
if not overwrite:
|
|
28
|
+
return
|
|
29
|
+
else:
|
|
30
|
+
_remove_files(path)
|
|
31
|
+
else:
|
|
32
|
+
os.makedirs(path)
|
|
30
33
|
|
|
31
34
|
with tf.device(device):
|
|
32
35
|
|
|
@@ -133,7 +136,7 @@ def load_spec(path: str) -> tensors.GraphTensor.Spec:
|
|
|
133
136
|
def _write_tfrecord(
|
|
134
137
|
inputs,
|
|
135
138
|
path: str,
|
|
136
|
-
featurizer: featurizers.
|
|
139
|
+
featurizer: featurizers.GraphFeaturizer,
|
|
137
140
|
) -> None:
|
|
138
141
|
|
|
139
142
|
def _write_example(tensor):
|
|
@@ -149,11 +152,7 @@ def _write_tfrecord(
|
|
|
149
152
|
x = tuple(x)
|
|
150
153
|
tensor = featurizer(x)
|
|
151
154
|
if tensor is not None:
|
|
152
|
-
|
|
153
|
-
_write_example(tensor)
|
|
154
|
-
else:
|
|
155
|
-
for t in tensor:
|
|
156
|
-
_write_example(t)
|
|
155
|
+
_write_example(tensor)
|
|
157
156
|
|
|
158
157
|
def _serialize_example(
|
|
159
158
|
feature: dict[str, tf.train.Feature]
|
|
@@ -168,8 +167,18 @@ def _parse_example(
|
|
|
168
167
|
) -> tf.Tensor:
|
|
169
168
|
out = tf.io.parse_single_example(
|
|
170
169
|
x, features={'feature': tf.io.RaggedFeature(tf.string)})['feature']
|
|
171
|
-
out = [
|
|
172
|
-
tf.
|
|
173
|
-
|
|
170
|
+
out = [
|
|
171
|
+
tf.ensure_shape(tf.io.parse_tensor(x[0], s.dtype), s.shape)
|
|
172
|
+
for (x, s) in zip(
|
|
173
|
+
tf.split(out, len(tf.nest.flatten(spec, expand_composites=True))),
|
|
174
|
+
tf.nest.flatten(spec, expand_composites=True)
|
|
175
|
+
)
|
|
176
|
+
]
|
|
174
177
|
out = tf.nest.pack_sequence_as(spec, tf.nest.flatten(out), expand_composites=True)
|
|
175
|
-
return out
|
|
178
|
+
return out
|
|
179
|
+
|
|
180
|
+
def _remove_files(path):
|
|
181
|
+
for filename in os.listdir(path):
|
|
182
|
+
if filename.endswith('tfrecord') or filename == 'spec.pb':
|
|
183
|
+
filepath = os.path.join(path, filename)
|
|
184
|
+
os.remove(filepath)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: molcraft
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a18
|
|
4
4
|
Summary: Graph Neural Networks for Molecular Machine Learning
|
|
5
5
|
Author-email: Alexander Kensert <alexander.kensert@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -43,9 +43,9 @@ Provides-Extra: gpu
|
|
|
43
43
|
Requires-Dist: tensorflow[and-cuda]>=2.16; extra == "gpu"
|
|
44
44
|
Dynamic: license-file
|
|
45
45
|
|
|
46
|
-
<img src="https://github.com/akensert/molcraft/blob/main/docs/_static/molcraft-logo.png" alt="molcraft-logo">
|
|
46
|
+
<img src="https://github.com/akensert/molcraft/blob/main/docs/_static/molcraft-logo.png" alt="molcraft-logo", width="90%">
|
|
47
47
|
|
|
48
|
-
**Deep Learning on Molecules**: A Minimalistic GNN package for Molecular ML.
|
|
48
|
+
**Deep Learning on Molecules**: A Minimalistic GNN package for Molecular ML.
|
|
49
49
|
|
|
50
50
|
> [!NOTE]
|
|
51
51
|
> In progress.
|
|
@@ -83,11 +83,12 @@ featurizer = featurizers.MolGraphFeaturizer(
|
|
|
83
83
|
features.BondType(),
|
|
84
84
|
features.IsRotatable(),
|
|
85
85
|
],
|
|
86
|
-
|
|
86
|
+
super_node=True,
|
|
87
87
|
self_loops=True,
|
|
88
|
+
include_hydrogens=False,
|
|
88
89
|
)
|
|
89
90
|
|
|
90
|
-
graph = featurizer([('N[C@@H](C)C(=O)O', 2.
|
|
91
|
+
graph = featurizer([('N[C@@H](C)C(=O)O', 2.5), ('N[C@@H](CS)C(=O)O', 1.5)])
|
|
91
92
|
print(graph)
|
|
92
93
|
|
|
93
94
|
model = models.GraphModel.from_layers(
|
|
@@ -95,13 +96,13 @@ model = models.GraphModel.from_layers(
|
|
|
95
96
|
layers.Input(graph.spec),
|
|
96
97
|
layers.NodeEmbedding(dim=128),
|
|
97
98
|
layers.EdgeEmbedding(dim=128),
|
|
98
|
-
layers.
|
|
99
|
-
layers.
|
|
100
|
-
layers.
|
|
101
|
-
layers.
|
|
102
|
-
layers.Readout(
|
|
103
|
-
keras.layers.Dense(units=1024, activation='
|
|
104
|
-
keras.layers.Dense(units=1024, activation='
|
|
99
|
+
layers.GraphConv(units=128),
|
|
100
|
+
layers.GraphConv(units=128),
|
|
101
|
+
layers.GraphConv(units=128),
|
|
102
|
+
layers.GraphConv(units=128),
|
|
103
|
+
layers.Readout(),
|
|
104
|
+
keras.layers.Dense(units=1024, activation='elu'),
|
|
105
|
+
keras.layers.Dense(units=1024, activation='elu'),
|
|
105
106
|
keras.layers.Dense(1)
|
|
106
107
|
]
|
|
107
108
|
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
molcraft/__init__.py,sha256=nK5aO2tHHpVmGxS0I5gz7gDmmf3yyyggcGCAKBAjdyU,477
|
|
2
|
+
molcraft/callbacks.py,sha256=x5HnkZhqcFRrW6xdApt_jZ4X08A-0fxcnFKfdmRKa0c,3571
|
|
3
|
+
molcraft/chem.py,sha256=e56qBDuqh8rq_4-UMyp6LCQNxxSx8hZ7gzuz-87DHgw,21652
|
|
4
|
+
molcraft/datasets.py,sha256=Nd2lw5USUZE52vvAiNr-q-n03Y3--NlZlK0NzqHgp-E,4145
|
|
5
|
+
molcraft/descriptors.py,sha256=Cl3KnBPsTST7XLgRLktkX5LwY9MV0P_lUlrt8iPV5no,3508
|
|
6
|
+
molcraft/features.py,sha256=s0WeV8eZcDEypPgC1m37f4s9QkvWIlVgn-L43Cdsa14,13525
|
|
7
|
+
molcraft/featurizers.py,sha256=bD3RFY9eg89-O-Nxgy6gote1zS4cyjOgzdSiSJZJdJE,17664
|
|
8
|
+
molcraft/layers.py,sha256=FanfJGsB4FxHe_uzNw-0RRJMLtgkf_eH5WMIEm3JwfM,64616
|
|
9
|
+
molcraft/losses.py,sha256=qnS2yC5g-O3n_zVea9MR6TNiFraW2yqRgePOisoUP4A,1065
|
|
10
|
+
molcraft/models.py,sha256=2Pc1htT9fCukGd8ZxrvE0rzEHsPBm0pluHw4FZXaUE4,21963
|
|
11
|
+
molcraft/ops.py,sha256=bQbdFDt9waxVCzF5-dkTB6vlpj9eoSt8I4Qg7ZGXbsU,6178
|
|
12
|
+
molcraft/records.py,sha256=0j4EWP55sfnkoQIH5trdaAIevPfVbAtPLrygTRmLyFw,5686
|
|
13
|
+
molcraft/tensors.py,sha256=EOUKx496KUZsjA1zA2ABc7tU_TW3Jv7AXDsug_QsLbA,22407
|
|
14
|
+
molcraft/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
molcraft/applications/chromatography.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
molcraft/applications/proteomics.py,sha256=qy6KTUrpu0MGOgAsbh0mw4ibtZbYQZa1GLlGA6g1ivg,8991
|
|
17
|
+
molcraft-0.1.0a18.dist-info/licenses/LICENSE,sha256=sbVeqlrtZ0V63uYhZGL5dCxUm8rBAOqe2avyA1zIQNk,1074
|
|
18
|
+
molcraft-0.1.0a18.dist-info/METADATA,sha256=glSAlKMG_kYkWKy4slJ7srY9-CVnc4VPcw-J_lh4osM,3930
|
|
19
|
+
molcraft-0.1.0a18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
molcraft-0.1.0a18.dist-info/top_level.txt,sha256=dENV6MfOceshM6MQCgJlcN1ojZkiCL9B4F7XyUge3QM,9
|
|
21
|
+
molcraft-0.1.0a18.dist-info/RECORD,,
|
molcraft/conformers.py
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import keras
|
|
2
|
-
|
|
3
|
-
from molcraft import chem
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@keras.saving.register_keras_serializable(package="molcraft")
|
|
7
|
-
class ConformerProcessor:
|
|
8
|
-
|
|
9
|
-
def get_config(self) -> dict:
|
|
10
|
-
return {}
|
|
11
|
-
|
|
12
|
-
@classmethod
|
|
13
|
-
def from_config(cls, config: dict):
|
|
14
|
-
return cls(**config)
|
|
15
|
-
|
|
16
|
-
def __call__(self, mol: chem.Mol) -> chem.Mol:
|
|
17
|
-
raise NotImplementedError
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@keras.saving.register_keras_serializable(package="molcraft")
|
|
21
|
-
class ConformerEmbedder(ConformerProcessor):
|
|
22
|
-
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
method: str = 'ETKDGv3',
|
|
26
|
-
num_conformers: int = 5,
|
|
27
|
-
**kwargs,
|
|
28
|
-
) -> None:
|
|
29
|
-
self.method = method
|
|
30
|
-
self.num_conformers = num_conformers
|
|
31
|
-
self.kwargs = kwargs
|
|
32
|
-
|
|
33
|
-
def get_config(self) -> dict:
|
|
34
|
-
config = {
|
|
35
|
-
'method': self.method,
|
|
36
|
-
'num_conformers': self.num_conformers,
|
|
37
|
-
}
|
|
38
|
-
config.update({
|
|
39
|
-
k: v for (k, v) in self.kwargs.items()
|
|
40
|
-
})
|
|
41
|
-
return config
|
|
42
|
-
|
|
43
|
-
def __call__(self, mol: chem.Mol) -> chem.Mol:
|
|
44
|
-
return chem.embed_conformers(
|
|
45
|
-
mol,
|
|
46
|
-
method=self.method,
|
|
47
|
-
num_conformers=self.num_conformers,
|
|
48
|
-
**self.kwargs,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@keras.saving.register_keras_serializable(package="molcraft")
|
|
53
|
-
class ConformerOptimizer(ConformerProcessor):
|
|
54
|
-
|
|
55
|
-
def __init__(
|
|
56
|
-
self,
|
|
57
|
-
method: str = 'UFF',
|
|
58
|
-
max_iter: int = 200,
|
|
59
|
-
ignore_interfragment_interactions: bool = True,
|
|
60
|
-
vdw_threshold: float = 10.0,
|
|
61
|
-
**kwargs,
|
|
62
|
-
) -> None:
|
|
63
|
-
self.method = method
|
|
64
|
-
self.max_iter = max_iter
|
|
65
|
-
self.ignore_interfragment_interactions = ignore_interfragment_interactions
|
|
66
|
-
self.vdw_threshold = vdw_threshold
|
|
67
|
-
self.kwargs = kwargs
|
|
68
|
-
|
|
69
|
-
def get_config(self) -> dict:
|
|
70
|
-
config = {
|
|
71
|
-
'method': self.method,
|
|
72
|
-
'max_iter': self.max_iter,
|
|
73
|
-
'ignore_interfragment_interactions': self.ignore_interfragment_interactions,
|
|
74
|
-
'vdw_threshold': self.vdw_threshold,
|
|
75
|
-
}
|
|
76
|
-
config.update({
|
|
77
|
-
k: v for (k, v) in self.kwargs.items()
|
|
78
|
-
})
|
|
79
|
-
return config
|
|
80
|
-
|
|
81
|
-
def __call__(self, mol: chem.Mol) -> chem.Mol:
|
|
82
|
-
return chem.optimize_conformers(
|
|
83
|
-
mol,
|
|
84
|
-
method=self.method,
|
|
85
|
-
max_iter=self.max_iter,
|
|
86
|
-
ignore_interfragment_interactions=self.ignore_interfragment_interactions,
|
|
87
|
-
vdw_threshold=self.vdw_threshold,
|
|
88
|
-
**self.kwargs,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
@keras.saving.register_keras_serializable(package="molcraft")
|
|
93
|
-
class ConformerPruner(ConformerProcessor):
|
|
94
|
-
def __init__(
|
|
95
|
-
self,
|
|
96
|
-
keep: int = 1,
|
|
97
|
-
threshold: float = 0.0,
|
|
98
|
-
energy_force_field: str = 'UFF',
|
|
99
|
-
**kwargs,
|
|
100
|
-
) -> None:
|
|
101
|
-
self.keep = keep
|
|
102
|
-
self.threshold = threshold
|
|
103
|
-
self.energy_force_field = energy_force_field
|
|
104
|
-
self.kwargs = kwargs
|
|
105
|
-
|
|
106
|
-
def get_config(self) -> dict:
|
|
107
|
-
config = {
|
|
108
|
-
'keep': self.keep,
|
|
109
|
-
'threshold': self.threshold,
|
|
110
|
-
'energy_force_field': self.energy_force_field,
|
|
111
|
-
}
|
|
112
|
-
config.update({
|
|
113
|
-
k: v for (k, v) in self.kwargs.items()
|
|
114
|
-
})
|
|
115
|
-
return config
|
|
116
|
-
|
|
117
|
-
def __call__(self, mol: chem.Mol) -> chem.Mol:
|
|
118
|
-
return chem.prune_conformers(
|
|
119
|
-
mol,
|
|
120
|
-
keep=self.keep,
|
|
121
|
-
threshold=self.threshold,
|
|
122
|
-
energy_force_field=self.energy_force_field,
|
|
123
|
-
**self.kwargs,
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@keras.saving.register_keras_serializable(package='molcraft')
|
|
128
|
-
class ConformerGenerator(ConformerProcessor):
|
|
129
|
-
|
|
130
|
-
def __init__(self, steps: list[ConformerProcessor]) -> None:
|
|
131
|
-
self.steps = steps
|
|
132
|
-
|
|
133
|
-
def get_config(self) -> dict:
|
|
134
|
-
return {
|
|
135
|
-
"steps": [
|
|
136
|
-
keras.saving.serialize_keras_object(step) for step in self.steps
|
|
137
|
-
]
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
@classmethod
|
|
141
|
-
def from_config(cls, config: dict) -> 'ConformerGenerator':
|
|
142
|
-
steps = [
|
|
143
|
-
keras.saving.deserialize_keras_object(obj)
|
|
144
|
-
for obj in config["steps"]
|
|
145
|
-
]
|
|
146
|
-
return cls(steps)
|
|
147
|
-
|
|
148
|
-
def __call__(self, mol: chem.Mol) -> chem.Mol:
|
|
149
|
-
for step in self.steps:
|
|
150
|
-
mol = step(mol)
|
|
151
|
-
return mol
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
molcraft/__init__.py,sha256=uo2ze7WMv3VhP0JcJedXDS9UkeEFydlXgSw4l7Xi8E0,464
|
|
2
|
-
molcraft/callbacks.py,sha256=x5HnkZhqcFRrW6xdApt_jZ4X08A-0fxcnFKfdmRKa0c,3571
|
|
3
|
-
molcraft/chem.py,sha256=--4AdZV0TCj_cf5i-TRidNJGSFyab1ksUEMjmDi7zaM,21837
|
|
4
|
-
molcraft/conformers.py,sha256=K6ZtiSUNDN_fwqGP9JrPcwALLFFvlMlF_XejEJH3Sr4,4205
|
|
5
|
-
molcraft/datasets.py,sha256=QKHi9SUBKvJvdkRFmRQNowhrnu35pQqtujuLatOK8bE,4151
|
|
6
|
-
molcraft/descriptors.py,sha256=jJpT0XWu3Tx_bxnwk1rENySRkaM8cMDMaDIjG8KKvtg,3097
|
|
7
|
-
molcraft/features.py,sha256=GwOecLCNUIuGfbIVzsAJH4LikkzWMKj5IT7zSgGTttU,13846
|
|
8
|
-
molcraft/featurizers.py,sha256=8Jmd2yguYmVRyh5wkn6sRzzEENkJ0TqHSlR8qgC4zNY,27131
|
|
9
|
-
molcraft/layers.py,sha256=200Y4QLOXDyHw1bnjoSQ6hZ-zD0vpforv-KQGESAZi8,61733
|
|
10
|
-
molcraft/losses.py,sha256=qnS2yC5g-O3n_zVea9MR6TNiFraW2yqRgePOisoUP4A,1065
|
|
11
|
-
molcraft/models.py,sha256=hKYSV8z65ohRKfPyjjzxZeVjipm064BWeUBGZE0tpyU,21882
|
|
12
|
-
molcraft/ops.py,sha256=bQbdFDt9waxVCzF5-dkTB6vlpj9eoSt8I4Qg7ZGXbsU,6178
|
|
13
|
-
molcraft/records.py,sha256=MbvYkcCunbAmpy_MWXmQ9WBGi2WvwxFUlwQSPKPvSSk,5534
|
|
14
|
-
molcraft/tensors.py,sha256=EOUKx496KUZsjA1zA2ABc7tU_TW3Jv7AXDsug_QsLbA,22407
|
|
15
|
-
molcraft/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
molcraft/applications/proteomics.py,sha256=usZkoYtmTi1BtoP8SigyBNPjxR-nLH1yEsuAdpjvF2M,9009
|
|
17
|
-
molcraft-0.1.0a16.dist-info/licenses/LICENSE,sha256=sbVeqlrtZ0V63uYhZGL5dCxUm8rBAOqe2avyA1zIQNk,1074
|
|
18
|
-
molcraft-0.1.0a16.dist-info/METADATA,sha256=JL32RxGZY92s39EnhonY4mZbvgGvXjcybtV9nXukn4s,3930
|
|
19
|
-
molcraft-0.1.0a16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
-
molcraft-0.1.0a16.dist-info/top_level.txt,sha256=dENV6MfOceshM6MQCgJlcN1ojZkiCL9B4F7XyUge3QM,9
|
|
21
|
-
molcraft-0.1.0a16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|