Coverage for encodermap/encodermap_tf1/misc.py: 43%
134 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-07 11:05 +0000
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-07 11:05 +0000
1import os
2from math import pi
4import numpy as np
5import tensorflow.compat.v1 as tf
6from tensorboard.backend.event_processing.event_accumulator import EventAccumulator
9def add_layer_summaries(layer, debug=False):
10 """
12 :param layer:
13 :return:
14 """
15 weights = layer.variables[0]
16 biases = layer.variables[1]
17 variable_summaries(layer.name + "_weights", weights, debug)
18 variable_summaries(layer.name + "_biases", biases, debug)
21def periodic_distance(a, b, periodicity=2 * pi):
22 """
24 :param a:
25 :param b:
26 :param periodicity:
27 :return:
28 """
29 d = tf.abs(b - a)
30 return tf.minimum(d, periodicity - d)
33def periodic_distance_np(a, b, periodicity=2 * pi):
34 """
36 :param a:
37 :param b:
38 :param periodicity:
39 :return:
40 """
41 d = np.abs(b - a)
42 return np.minimum(d, periodicity - d)
45def variable_summaries(name, variables, debug=False):
46 """
47 Attach several summaries to a Tensor for TensorBoard visualization.
49 :param name:
50 :param variables:
51 :return:
52 """
53 if not isinstance(variables, list):
54 variables = [variables]
56 for i, var in enumerate(variables):
57 try:
58 add_index = len(variables) > 1
59 except TypeError:
60 add_index = True
61 if add_index:
62 name = name + str(i)
63 with tf.name_scope(name):
64 mean = tf.reduce_mean(var)
65 tf.summary.scalar("mean", mean)
66 with tf.name_scope("stddev"):
67 stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
68 tf.summary.scalar("stddev", stddev)
69 tf.summary.scalar("max", tf.reduce_max(var))
70 tf.summary.scalar("min", tf.reduce_min(var))
71 tf.summary.histogram("histogram", var)
72 tf.summary.tensor_summary("values", var)
75def create_dir(path):
76 """
78 :param path:
79 :return:
80 """
81 if not os.path.isdir(path):
82 os.makedirs(path)
83 return path
86def distance_cost(r_h, r_l, sig_h, a_h, b_h, sig_l, a_l, b_l, periodicity):
87 """
89 :param r_h:
90 :param r_l:
91 :param sig_h:
92 :param a_h:
93 :param b_h:
94 :param sig_l:
95 :param a_l:
96 :param b_l:
97 :param periodicity:
98 :return:
99 """
100 if periodicity == float("inf"):
101 dist_h = pairwise_dist(r_h)
102 else:
103 dist_h = pairwise_dist_periodic(r_h, periodicity)
104 dist_l = pairwise_dist(r_l)
106 sig_h = sigmoid(dist_h, sig_h, a_h, b_h)
107 sig_l = sigmoid(dist_l, sig_l, a_l, b_l)
109 cost = tf.reduce_mean(tf.square(sig_h - sig_l))
110 return cost
113def sigmoid(r, sig, a, b):
114 """
116 :param r:
117 :param sig:
118 :param a:
119 :param b:
120 :return:
121 """
122 return 1 - (1 + (2 ** (a / b) - 1) * (r / sig) ** a) ** (-b / a)
125def pairwise_dist_periodic(positions, periodicity):
126 assert len(positions.shape) == 2
127 with tf.name_scope("pairwise_dist_periodic"):
128 vecs = periodic_distance(
129 tf.expand_dims(positions, axis=1),
130 tf.expand_dims(positions, axis=0),
131 periodicity,
132 )
133 mask = tf.to_float(tf.equal(vecs, 0.0))
134 vecs = vecs + mask * 1e-16 # gradient infinite for 0
135 dists = tf.norm(vecs, axis=2)
136 return dists
139def pairwise_dist(positions, squared=False, flat=False):
140 # thanks to https://omoindrot.github.io/triplet-loss
142 with tf.name_scope("pairwise_dist"):
143 if not tf.is_numeric_tensor(positions):
144 positions = tf.convert_to_tensor(positions)
145 if len(positions.get_shape()) == 2: 145 ↛ 150line 145 didn't jump to line 150, because the condition on line 145 was never false
146 positions = tf.expand_dims(positions, 0)
148 # Get the dot product between all embeddings
149 # shape (batch_size, batch_size)
150 dot_product = tf.matmul(positions, tf.transpose(positions, [0, 2, 1]))
152 # Get squared L2 norm for each embedding. We can just take the diagonal of `dot_product`.
153 # This also provides more numerical stability (the diagonal of the result will be exactly 0).
154 # shape (batch_size,)
155 square_norm = tf.linalg.diag_part(dot_product)
157 # Compute the pairwise distance matrix as we have:
158 # ||a - b||^2 = ||a||^2 - 2 <a, b> + ||b||^2
159 # shape (batch_size, batch_size)
160 distances = (
161 tf.expand_dims(square_norm, 1)
162 - 2.0 * dot_product
163 + tf.expand_dims(square_norm, 2)
164 )
166 # Because of computation errors, some distances might be negative so we put everything >= 0.0
167 distances = tf.maximum(distances, 0.0)
169 if flat: 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true
170 n = int(positions.shape[1])
171 mask = np.ones((n, n), dtype=bool)
172 mask[np.tril_indices(n)] = False
173 distances = tf.boolean_mask(distances, mask, axis=1)
175 if not squared: 175 ↛ 186line 175 didn't jump to line 186, because the condition on line 175 was never false
176 # Because the gradient of sqrt is infinite when distances == 0.0 (ex: on the diagonal)
177 # we need to add a small epsilon where distances == 0.0
178 mask = tf.to_float(tf.equal(distances, 0.0))
179 distances = distances + mask * 1e-16
181 distances = tf.sqrt(distances)
183 # Correct the epsilon added: set the distances on the mask to be exactly 0.0
184 distances = distances * (1.0 - mask)
186 return distances
189def search_and_replace(
190 file_path, search_pattern, replacement, out_path=None, backup=True
191):
192 """
193 Searches for a pattern in a text file and replaces it with the replacement
195 :param file_path: (str)
196 path to the file to search
197 :param search_pattern: (str)
198 pattern to search for
199 :param replacement: (str)
200 string that replaces the search_pattern in the output file
201 :param out_path: (str)
202 path where to write the output file. If no path is given the original file will be replaced.
203 :param backup: (bool)
204 if backup is true the original file is renamed to filename.bak before it is overwritten
206 :return:
208 """
209 with open(file_path, "r") as f:
210 file_data = f.read()
212 file_data = file_data.replace(search_pattern, replacement)
214 if not out_path:
215 out_path = file_path
216 if backup:
217 os.rename(file_path, file_path + ".bak")
219 with open(out_path, "w") as file:
220 file.write(file_data)
223def run_path(path):
224 """
225 Creates a directory at "path/run{i}" where the i is corresponding to the smallest not yet existing path
227 :param path: (str)
228 :return: (str)
229 path of the created folder
231 """
232 i = 0
233 while True:
234 current_path = os.path.join(path, "run{}".format(i))
235 if not os.path.exists(current_path):
236 os.makedirs(current_path)
237 output_path = current_path
238 break
239 else:
240 i += 1
241 return output_path
244def random_on_cube_edges(n_points, sigma=0):
245 x = y = z = 1
246 r = np.random.uniform(size=n_points)
248 coordinates = np.zeros((n_points, 3))
250 ids = np.zeros(n_points)
252 a = np.array([[0, 0, 0]] * 3 + [[x, y, 0]] * 3 + [[0, y, z]] * 3 + [[x, 0, z]] * 3)
254 b = np.array(
255 [
256 [x, 0, 0],
257 [0, y, 0],
258 [0, 0, z],
259 [-x, 0, 0],
260 [0, -y, 0],
261 [0, 0, z],
262 [x, 0, 0],
263 [0, -y, 0],
264 [0, 0, -z],
265 [-x, 0, 0],
266 [0, y, 0],
267 [0, 0, -z],
268 ]
269 )
271 for i in range(12):
272 mask = (i / 12 < r) & (r < (i + 1) / 12)
273 coordinates[mask] += (
274 a[i] + (np.expand_dims(r[mask], axis=1) - i / 12) * 12 * b[i]
275 )
276 ids[mask] = i
278 if sigma:
279 coordinates += np.random.normal(scale=sigma, size=(n_points, 3))
281 return coordinates, ids
284def rotation_matrix(axis_unit_vec, angle):
285 angle = tf.expand_dims(tf.expand_dims(angle, axis=-1), axis=-1)
286 i = tf.expand_dims(tf.eye(3), 0)
287 zeros = tf.zeros(tf.shape(axis_unit_vec)[0])
288 cross_prod_matrix = tf.convert_to_tensor(
289 [
290 [zeros, -axis_unit_vec[:, 2], axis_unit_vec[:, 1]],
291 [axis_unit_vec[:, 2], zeros, -axis_unit_vec[:, 0]],
292 [-axis_unit_vec[:, 1], axis_unit_vec[:, 0], zeros],
293 ]
294 )
295 cross_prod_matrix = tf.transpose(cross_prod_matrix, [2, 0, 1])
296 r = tf.cos(angle) * i
297 r += tf.sin(angle) * cross_prod_matrix
298 axis_unit_vec = tf.expand_dims(axis_unit_vec, 2)
299 r += (1 - tf.cos(angle)) * tf.matmul(
300 axis_unit_vec, tf.transpose(axis_unit_vec, [0, 2, 1])
301 )
302 return r
305def potential_energy(angles, dihedrals, distances):
306 energy = 0
307 energies = tf.where(
308 distances < 2,
309 tf.minimum(10 - distances, (1 / distances) ** 12),
310 tf.zeros(tf.shape(distances)),
311 )
312 energy += tf.reduce_mean(tf.reduce_sum(energies, axis=1))
313 return energy
316def read_from_log(run_path, names):
317 ea = EventAccumulator(run_path)
318 ea.Reload()
319 results = [np.array(ea.Scalars(name)) for name in names]
320 return results