... @tf.function def train(t_train, s_train, t_phys): # Data loss # predict displacement s_train_hat = net.predict(t_train) # MSE loss between training data and predictions data_loss = tf.math.reduce_mean( tf.math.square(s_train - s_train_hat) ) # Physics loss # predict displacement s_phys_hat = net.predict(t_phys) # split into individual x and y components s_x = s_phys_hat[:, 0] s_y = s_phys_hat[:, 1] # take the gradients to get predicted velocity and acceleration v_x = tf.gradients(s_x, t_phys)[0] v_y = tf.gradients(s_y, t_phys)[0] a_x = tf.gradients(v_x, t_phys)[0] a_y = tf.gradients(v_y, t_phys)[0] # combine individual x and y components into velocity and # acceleration vectors v = tf.concat([v_x, v_y], axis=1) a = tf.concat([a_x, a_y], axis=1) # as acceleration is the known equation, this is what we want to # perform gradient descent on. # therefore, prevent any gradients flowing through the higher # order (velocity) terms v = tf.stop_gradient(v) # define speed (velocity norm, the ||v|| in the equation) and # gravity vector for physics equation speed = tf.norm(v, axis=1, keepdims=True) g = [[0.0, 9.81]] # MSE between known physics equation and network gradients phys_loss = tf.math.reduce_mean( tf.math.square(-mu * speed * v - g - a) ) # Total loss loss = data_weight * data_loss + phys_weight * phys_loss # Gradient step # minimise the combined loss with respect to both the neural # network parameters and the unknown physics variable, mu gradients = tf.gradients(loss, net.train_vars + [mu]) optimiser.apply_gradients(zip(gradients, net.train_vars + [mu])) ...