lhallee commited on
Commit
b95d357
·
verified ·
1 Parent(s): a284246

Upload vb_modules_utils.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. vb_modules_utils.py +303 -303
vb_modules_utils.py CHANGED
@@ -1,303 +1,303 @@
1
- # started from code from https://github.com/lucidrains/alphafold3-pytorch, MIT License, Copyright (c) 2024 Phil Wang
2
-
3
- from functools import partial
4
- from typing import Optional
5
-
6
- import torch
7
- import torch.nn.functional as F
8
- from torch.nn import (
9
- Linear,
10
- Module,
11
- )
12
- from torch.types import Device
13
-
14
- LinearNoBias = partial(Linear, bias=False)
15
-
16
-
17
- def exists(v):
18
- return v is not None
19
-
20
-
21
- def default(v, d):
22
- return v if exists(v) else d
23
-
24
-
25
- def log(t, eps=1e-20):
26
- return torch.log(t.clamp(min=eps))
27
-
28
-
29
- class SwiGLU(Module):
30
- def forward(
31
- self,
32
- x, #: Float['... d']
33
- ): # -> Float[' ... (d//2)']:
34
- x, gates = x.chunk(2, dim=-1)
35
- return F.silu(gates) * x
36
-
37
-
38
- def center(atom_coords, atom_mask):
39
- atom_mean = torch.sum(
40
- atom_coords * atom_mask[:, :, None], dim=1, keepdim=True
41
- ) / torch.sum(atom_mask[:, :, None], dim=1, keepdim=True)
42
- atom_coords = atom_coords - atom_mean
43
- return atom_coords
44
-
45
-
46
- def compute_random_augmentation(
47
- multiplicity, s_trans=1.0, device=None, dtype=torch.float32
48
- ):
49
- R = random_rotations(multiplicity, dtype=dtype, device=device)
50
- random_trans = (
51
- torch.randn((multiplicity, 1, 3), dtype=dtype, device=device) * s_trans
52
- )
53
- return R, random_trans
54
-
55
-
56
- def randomly_rotate(coords, return_second_coords=False, second_coords=None):
57
- R = random_rotations(len(coords), coords.dtype, coords.device)
58
-
59
- if return_second_coords:
60
- return torch.einsum("bmd,bds->bms", coords, R), torch.einsum(
61
- "bmd,bds->bms", second_coords, R
62
- ) if second_coords is not None else None
63
-
64
- return torch.einsum("bmd,bds->bms", coords, R)
65
-
66
-
67
- def center_random_augmentation(
68
- atom_coords,
69
- atom_mask,
70
- s_trans=1.0,
71
- augmentation=True,
72
- centering=True,
73
- return_second_coords=False,
74
- second_coords=None,
75
- ):
76
- """Algorithm 19"""
77
- if centering:
78
- atom_mean = torch.sum(
79
- atom_coords * atom_mask[:, :, None], dim=1, keepdim=True
80
- ) / torch.sum(atom_mask[:, :, None], dim=1, keepdim=True)
81
- atom_coords = atom_coords - atom_mean
82
-
83
- if second_coords is not None:
84
- # apply same transformation also to this input
85
- second_coords = second_coords - atom_mean
86
-
87
- if augmentation:
88
- atom_coords, second_coords = randomly_rotate(
89
- atom_coords, return_second_coords=True, second_coords=second_coords
90
- )
91
- random_trans = torch.randn_like(atom_coords[:, 0:1, :]) * s_trans
92
- atom_coords = atom_coords + random_trans
93
-
94
- if second_coords is not None:
95
- second_coords = second_coords + random_trans
96
-
97
- if return_second_coords:
98
- return atom_coords, second_coords
99
-
100
- return atom_coords
101
-
102
-
103
- class ExponentialMovingAverage:
104
- """from https://github.com/yang-song/score_sde_pytorch/blob/main/models/ema.py, Apache-2.0 license
105
- Maintains (exponential) moving average of a set of parameters."""
106
-
107
- def __init__(self, parameters, decay, use_num_updates=True):
108
- """
109
- Args:
110
- parameters: Iterable of `torch.nn.Parameter`; usually the result of
111
- `model.parameters()`.
112
- decay: The exponential decay.
113
- use_num_updates: Whether to use number of updates when computing
114
- averages.
115
- """
116
- if decay < 0.0 or decay > 1.0:
117
- raise ValueError("Decay must be between 0 and 1")
118
- self.decay = decay
119
- self.num_updates = 0 if use_num_updates else None
120
- self.shadow_params = [p.clone().detach() for p in parameters if p.requires_grad]
121
- self.collected_params = []
122
-
123
- def update(self, parameters):
124
- """
125
- Update currently maintained parameters.
126
- Call this every time the parameters are updated, such as the result of
127
- the `optimizer.step()` call.
128
- Args:
129
- parameters: Iterable of `torch.nn.Parameter`; usually the same set of
130
- parameters used to initialize this object.
131
- """
132
- decay = self.decay
133
- if self.num_updates is not None:
134
- self.num_updates += 1
135
- decay = min(decay, (1 + self.num_updates) / (10 + self.num_updates))
136
- one_minus_decay = 1.0 - decay
137
- with torch.no_grad():
138
- parameters = [p for p in parameters if p.requires_grad]
139
- for s_param, param in zip(self.shadow_params, parameters):
140
- s_param.sub_(one_minus_decay * (s_param - param))
141
-
142
- def compatible(self, parameters):
143
- if len(self.shadow_params) != len(parameters):
144
- print(
145
- f"Model has {len(self.shadow_params)} parameter tensors, the incoming ema {len(parameters)}"
146
- )
147
- return False
148
-
149
- for s_param, param in zip(self.shadow_params, parameters):
150
- if param.data.shape != s_param.data.shape:
151
- print(
152
- f"Model has parameter tensor of shape {s_param.data.shape} , the incoming ema {param.data.shape}"
153
- )
154
- return False
155
- return True
156
-
157
- def copy_to(self, parameters):
158
- """
159
- Copy current parameters into given collection of parameters.
160
- Args:
161
- parameters: Iterable of `torch.nn.Parameter`; the parameters to be
162
- updated with the stored moving averages.
163
- """
164
- parameters = [p for p in parameters if p.requires_grad]
165
- for s_param, param in zip(self.shadow_params, parameters):
166
- if param.requires_grad:
167
- param.data.copy_(s_param.data)
168
-
169
- def store(self, parameters):
170
- """
171
- Save the current parameters for restoring later.
172
- Args:
173
- parameters: Iterable of `torch.nn.Parameter`; the parameters to be
174
- temporarily stored.
175
- """
176
- self.collected_params = [param.clone() for param in parameters]
177
-
178
- def restore(self, parameters):
179
- """
180
- Restore the parameters stored with the `store` method.
181
- Useful to validate the model with EMA parameters without affecting the
182
- original optimization process. Store the parameters before the
183
- `copy_to` method. After validation (or model saving), use this to
184
- restore the former parameters.
185
- Args:
186
- parameters: Iterable of `torch.nn.Parameter`; the parameters to be
187
- updated with the stored parameters.
188
- """
189
- for c_param, param in zip(self.collected_params, parameters):
190
- param.data.copy_(c_param.data)
191
-
192
- def state_dict(self):
193
- return dict(
194
- decay=self.decay,
195
- num_updates=self.num_updates,
196
- shadow_params=self.shadow_params,
197
- )
198
-
199
- def load_state_dict(self, state_dict, device):
200
- self.decay = state_dict["decay"]
201
- self.num_updates = state_dict["num_updates"]
202
- self.shadow_params = [
203
- tensor.to(device) for tensor in state_dict["shadow_params"]
204
- ]
205
-
206
- def to(self, device):
207
- self.shadow_params = [tensor.to(device) for tensor in self.shadow_params]
208
-
209
-
210
- # the following is copied from Torch3D, BSD License, Copyright (c) Meta Platforms, Inc. and affiliates.
211
-
212
-
213
- def _copysign(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
214
- """
215
- Return a tensor where each element has the absolute value taken from the,
216
- corresponding element of a, with sign taken from the corresponding
217
- element of b. This is like the standard copysign floating-point operation,
218
- but is not careful about negative 0 and NaN.
219
-
220
- Args:
221
- a: source tensor.
222
- b: tensor whose signs will be used, of the same shape as a.
223
-
224
- Returns:
225
- Tensor of the same shape as a with the signs of b.
226
- """
227
- signs_differ = (a < 0) != (b < 0)
228
- return torch.where(signs_differ, -a, a)
229
-
230
-
231
- def quaternion_to_matrix(quaternions: torch.Tensor) -> torch.Tensor:
232
- """
233
- Convert rotations given as quaternions to rotation matrices.
234
-
235
- Args:
236
- quaternions: quaternions with real part first,
237
- as tensor of shape (..., 4).
238
-
239
- Returns:
240
- Rotation matrices as tensor of shape (..., 3, 3).
241
- """
242
- r, i, j, k = torch.unbind(quaternions, -1)
243
- # pyre-fixme[58]: `/` is not supported for operand types `float` and `Tensor`.
244
- two_s = 2.0 / (quaternions * quaternions).sum(-1)
245
-
246
- o = torch.stack(
247
- (
248
- 1 - two_s * (j * j + k * k),
249
- two_s * (i * j - k * r),
250
- two_s * (i * k + j * r),
251
- two_s * (i * j + k * r),
252
- 1 - two_s * (i * i + k * k),
253
- two_s * (j * k - i * r),
254
- two_s * (i * k - j * r),
255
- two_s * (j * k + i * r),
256
- 1 - two_s * (i * i + j * j),
257
- ),
258
- -1,
259
- )
260
- return o.reshape(quaternions.shape[:-1] + (3, 3))
261
-
262
-
263
- def random_quaternions(
264
- n: int, dtype: Optional[torch.dtype] = None, device: Optional[Device] = None
265
- ) -> torch.Tensor:
266
- """
267
- Generate random quaternions representing rotations,
268
- i.e. versors with nonnegative real part.
269
-
270
- Args:
271
- n: Number of quaternions in a batch to return.
272
- dtype: Type to return.
273
- device: Desired device of returned tensor. Default:
274
- uses the current device for the default tensor type.
275
-
276
- Returns:
277
- Quaternions as tensor of shape (N, 4).
278
- """
279
- if isinstance(device, str):
280
- device = torch.device(device)
281
- o = torch.randn((n, 4), dtype=dtype, device=device)
282
- s = (o * o).sum(1)
283
- o = o / _copysign(torch.sqrt(s), o[:, 0])[:, None]
284
- return o
285
-
286
-
287
- def random_rotations(
288
- n: int, dtype: Optional[torch.dtype] = None, device: Optional[Device] = None
289
- ) -> torch.Tensor:
290
- """
291
- Generate random rotations as 3x3 rotation matrices.
292
-
293
- Args:
294
- n: Number of rotation matrices in a batch to return.
295
- dtype: Type to return.
296
- device: Device of returned tensor. Default: if None,
297
- uses the current device for the default tensor type.
298
-
299
- Returns:
300
- Rotation matrices as tensor of shape (n, 3, 3).
301
- """
302
- quaternions = random_quaternions(n, dtype=dtype, device=device)
303
- return quaternion_to_matrix(quaternions)
 
1
+ # started from code from https://github.com/lucidrains/alphafold3-pytorch, MIT License, Copyright (c) 2024 Phil Wang
2
+
3
+ from functools import partial
4
+ from typing import Optional
5
+
6
+ import torch
7
+ import torch.nn.functional as F
8
+ from torch.nn import (
9
+ Linear,
10
+ Module,
11
+ )
12
+ from torch.types import Device
13
+
14
+ LinearNoBias = partial(Linear, bias=False)
15
+
16
+
17
+ def exists(v):
18
+ return v is not None
19
+
20
+
21
+ def default(v, d):
22
+ return v if exists(v) else d
23
+
24
+
25
+ def log(t, eps=1e-20):
26
+ return torch.log(t.clamp(min=eps))
27
+
28
+
29
+ class SwiGLU(Module):
30
+ def forward(
31
+ self,
32
+ x, #: Float['... d']
33
+ ): # -> Float[' ... (d//2)']:
34
+ x, gates = x.chunk(2, dim=-1)
35
+ return F.silu(gates) * x
36
+
37
+
38
+ def center(atom_coords, atom_mask):
39
+ atom_mean = torch.sum(
40
+ atom_coords * atom_mask[:, :, None], dim=1, keepdim=True
41
+ ) / torch.sum(atom_mask[:, :, None], dim=1, keepdim=True)
42
+ atom_coords = atom_coords - atom_mean
43
+ return atom_coords
44
+
45
+
46
+ def compute_random_augmentation(
47
+ multiplicity, s_trans=1.0, device=None, dtype=torch.float32
48
+ ):
49
+ R = random_rotations(multiplicity, dtype=dtype, device=device)
50
+ random_trans = (
51
+ torch.randn((multiplicity, 1, 3), dtype=dtype, device=device) * s_trans
52
+ )
53
+ return R, random_trans
54
+
55
+
56
+ def randomly_rotate(coords, return_second_coords=False, second_coords=None):
57
+ R = random_rotations(len(coords), coords.dtype, coords.device)
58
+
59
+ if return_second_coords:
60
+ return torch.einsum("bmd,bds->bms", coords, R), torch.einsum(
61
+ "bmd,bds->bms", second_coords, R
62
+ ) if second_coords is not None else None
63
+
64
+ return torch.einsum("bmd,bds->bms", coords, R)
65
+
66
+
67
+ def center_random_augmentation(
68
+ atom_coords,
69
+ atom_mask,
70
+ s_trans=1.0,
71
+ augmentation=True,
72
+ centering=True,
73
+ return_second_coords=False,
74
+ second_coords=None,
75
+ ):
76
+ """Algorithm 19"""
77
+ if centering:
78
+ atom_mean = torch.sum(
79
+ atom_coords * atom_mask[:, :, None], dim=1, keepdim=True
80
+ ) / torch.sum(atom_mask[:, :, None], dim=1, keepdim=True)
81
+ atom_coords = atom_coords - atom_mean
82
+
83
+ if second_coords is not None:
84
+ # apply same transformation also to this input
85
+ second_coords = second_coords - atom_mean
86
+
87
+ if augmentation:
88
+ atom_coords, second_coords = randomly_rotate(
89
+ atom_coords, return_second_coords=True, second_coords=second_coords
90
+ )
91
+ random_trans = torch.randn_like(atom_coords[:, 0:1, :]) * s_trans
92
+ atom_coords = atom_coords + random_trans
93
+
94
+ if second_coords is not None:
95
+ second_coords = second_coords + random_trans
96
+
97
+ if return_second_coords:
98
+ return atom_coords, second_coords
99
+
100
+ return atom_coords
101
+
102
+
103
+ class ExponentialMovingAverage:
104
+ """from https://github.com/yang-song/score_sde_pytorch/blob/main/models/ema.py, Apache-2.0 license
105
+ Maintains (exponential) moving average of a set of parameters."""
106
+
107
+ def __init__(self, parameters, decay, use_num_updates=True):
108
+ """
109
+ Args:
110
+ parameters: Iterable of `torch.nn.Parameter`; usually the result of
111
+ `model.parameters()`.
112
+ decay: The exponential decay.
113
+ use_num_updates: Whether to use number of updates when computing
114
+ averages.
115
+ """
116
+ if decay < 0.0 or decay > 1.0:
117
+ raise ValueError("Decay must be between 0 and 1")
118
+ self.decay = decay
119
+ self.num_updates = 0 if use_num_updates else None
120
+ self.shadow_params = [p.clone().detach() for p in parameters if p.requires_grad]
121
+ self.collected_params = []
122
+
123
+ def update(self, parameters):
124
+ """
125
+ Update currently maintained parameters.
126
+ Call this every time the parameters are updated, such as the result of
127
+ the `optimizer.step()` call.
128
+ Args:
129
+ parameters: Iterable of `torch.nn.Parameter`; usually the same set of
130
+ parameters used to initialize this object.
131
+ """
132
+ decay = self.decay
133
+ if self.num_updates is not None:
134
+ self.num_updates += 1
135
+ decay = min(decay, (1 + self.num_updates) / (10 + self.num_updates))
136
+ one_minus_decay = 1.0 - decay
137
+ with torch.no_grad():
138
+ parameters = [p for p in parameters if p.requires_grad]
139
+ for s_param, param in zip(self.shadow_params, parameters):
140
+ s_param.sub_(one_minus_decay * (s_param - param))
141
+
142
+ def compatible(self, parameters):
143
+ if len(self.shadow_params) != len(parameters):
144
+ print(
145
+ f"Model has {len(self.shadow_params)} parameter tensors, the incoming ema {len(parameters)}"
146
+ )
147
+ return False
148
+
149
+ for s_param, param in zip(self.shadow_params, parameters):
150
+ if param.data.shape != s_param.data.shape:
151
+ print(
152
+ f"Model has parameter tensor of shape {s_param.data.shape} , the incoming ema {param.data.shape}"
153
+ )
154
+ return False
155
+ return True
156
+
157
+ def copy_to(self, parameters):
158
+ """
159
+ Copy current parameters into given collection of parameters.
160
+ Args:
161
+ parameters: Iterable of `torch.nn.Parameter`; the parameters to be
162
+ updated with the stored moving averages.
163
+ """
164
+ parameters = [p for p in parameters if p.requires_grad]
165
+ for s_param, param in zip(self.shadow_params, parameters):
166
+ if param.requires_grad:
167
+ param.data.copy_(s_param.data)
168
+
169
+ def store(self, parameters):
170
+ """
171
+ Save the current parameters for restoring later.
172
+ Args:
173
+ parameters: Iterable of `torch.nn.Parameter`; the parameters to be
174
+ temporarily stored.
175
+ """
176
+ self.collected_params = [param.clone() for param in parameters]
177
+
178
+ def restore(self, parameters):
179
+ """
180
+ Restore the parameters stored with the `store` method.
181
+ Useful to validate the model with EMA parameters without affecting the
182
+ original optimization process. Store the parameters before the
183
+ `copy_to` method. After validation (or model saving), use this to
184
+ restore the former parameters.
185
+ Args:
186
+ parameters: Iterable of `torch.nn.Parameter`; the parameters to be
187
+ updated with the stored parameters.
188
+ """
189
+ for c_param, param in zip(self.collected_params, parameters):
190
+ param.data.copy_(c_param.data)
191
+
192
+ def state_dict(self):
193
+ return dict(
194
+ decay=self.decay,
195
+ num_updates=self.num_updates,
196
+ shadow_params=self.shadow_params,
197
+ )
198
+
199
+ def load_state_dict(self, state_dict, device):
200
+ self.decay = state_dict["decay"]
201
+ self.num_updates = state_dict["num_updates"]
202
+ self.shadow_params = [
203
+ tensor.to(device) for tensor in state_dict["shadow_params"]
204
+ ]
205
+
206
+ def to(self, device):
207
+ self.shadow_params = [tensor.to(device) for tensor in self.shadow_params]
208
+
209
+
210
+ # the following is copied from Torch3D, BSD License, Copyright (c) Meta Platforms, Inc. and affiliates.
211
+
212
+
213
+ def _copysign(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
214
+ """
215
+ Return a tensor where each element has the absolute value taken from the,
216
+ corresponding element of a, with sign taken from the corresponding
217
+ element of b. This is like the standard copysign floating-point operation,
218
+ but is not careful about negative 0 and NaN.
219
+
220
+ Args:
221
+ a: source tensor.
222
+ b: tensor whose signs will be used, of the same shape as a.
223
+
224
+ Returns:
225
+ Tensor of the same shape as a with the signs of b.
226
+ """
227
+ signs_differ = (a < 0) != (b < 0)
228
+ return torch.where(signs_differ, -a, a)
229
+
230
+
231
+ def quaternion_to_matrix(quaternions: torch.Tensor) -> torch.Tensor:
232
+ """
233
+ Convert rotations given as quaternions to rotation matrices.
234
+
235
+ Args:
236
+ quaternions: quaternions with real part first,
237
+ as tensor of shape (..., 4).
238
+
239
+ Returns:
240
+ Rotation matrices as tensor of shape (..., 3, 3).
241
+ """
242
+ r, i, j, k = torch.unbind(quaternions, -1)
243
+ # pyre-fixme[58]: `/` is not supported for operand types `float` and `Tensor`.
244
+ two_s = 2.0 / (quaternions * quaternions).sum(-1)
245
+
246
+ o = torch.stack(
247
+ (
248
+ 1 - two_s * (j * j + k * k),
249
+ two_s * (i * j - k * r),
250
+ two_s * (i * k + j * r),
251
+ two_s * (i * j + k * r),
252
+ 1 - two_s * (i * i + k * k),
253
+ two_s * (j * k - i * r),
254
+ two_s * (i * k - j * r),
255
+ two_s * (j * k + i * r),
256
+ 1 - two_s * (i * i + j * j),
257
+ ),
258
+ -1,
259
+ )
260
+ return o.reshape(quaternions.shape[:-1] + (3, 3))
261
+
262
+
263
+ def random_quaternions(
264
+ n: int, dtype: Optional[torch.dtype] = None, device: Optional[Device] = None
265
+ ) -> torch.Tensor:
266
+ """
267
+ Generate random quaternions representing rotations,
268
+ i.e. versors with nonnegative real part.
269
+
270
+ Args:
271
+ n: Number of quaternions in a batch to return.
272
+ dtype: Type to return.
273
+ device: Desired device of returned tensor. Default:
274
+ uses the current device for the default tensor type.
275
+
276
+ Returns:
277
+ Quaternions as tensor of shape (N, 4).
278
+ """
279
+ if isinstance(device, str):
280
+ device = torch.device(device)
281
+ o = torch.randn((n, 4), dtype=dtype, device=device)
282
+ s = (o * o).sum(1)
283
+ o = o / _copysign(torch.sqrt(s), o[:, 0])[:, None]
284
+ return o
285
+
286
+
287
+ def random_rotations(
288
+ n: int, dtype: Optional[torch.dtype] = None, device: Optional[Device] = None
289
+ ) -> torch.Tensor:
290
+ """
291
+ Generate random rotations as 3x3 rotation matrices.
292
+
293
+ Args:
294
+ n: Number of rotation matrices in a batch to return.
295
+ dtype: Type to return.
296
+ device: Device of returned tensor. Default: if None,
297
+ uses the current device for the default tensor type.
298
+
299
+ Returns:
300
+ Rotation matrices as tensor of shape (n, 3, 3).
301
+ """
302
+ quaternions = random_quaternions(n, dtype=dtype, device=device)
303
+ return quaternion_to_matrix(quaternions)