예제 #1
0
class ForwardSolverFHNDiff:
    def __init__(self, point_cloud, diffusion_model, interpolated_spacing,
                 order_acc, fhn_model):

        self.fhn_model = fhn_model

        self.point_cloud = point_cloud
        self.diffusion_model = diffusion_model

        self.interpolated_spacing = interpolated_spacing
        self.order_acc = order_acc
        self.ut = Utils()

        self.coeff_matrix_first_der = None
        self.coeff_matrix_second_der = None

        self.ut = Utils()

    def solve(self, dt, duration):

        assert self.diffusion_model.nn_u0.shape[
            0] == 1, 'first axis of nn_u must be 1, indicating nn_u0'
        assert self.diffusion_model.u0.shape[
            0] == 1, 'first axis of u must be 1, indicating u0'
        assert self.fhn_model.V0.shape[
            0] == 1, 'first axis of u must be 1, indicating V0'
        assert self.fhn_model.v0.shape[
            0] == 1, 'first axis of u must be 1, indicating v0'

        coeff_matrix_first_der = self.coeff_matrix_first_der.copy()
        coeff_matrix_second_der = self.coeff_matrix_second_der.copy()
        V = np.squeeze(self.fhn_model.V0).copy()
        v = np.squeeze(self.fhn_model.v0).copy()

        time_pt = np.linspace(0,
                              duration,
                              int(duration / dt) + 1,
                              endpoint=True,
                              dtype='float64')

        V_update = []
        v_update = []
        V_update.append(V)
        v_update.append(v)

        for t in range(1, len(time_pt)):
            print('time: {}'.format(t * dt))
            # ==== FHN MODEL ====
            fast_v = self.fhn_model.fast_variable(V, v)
            slow_v = self.fhn_model.slow_variable(V, v)
            applied_current = self.fhn_model.applied_current

            # === DIFFUSION MODEL ===
            deltaD_deltaV = self.diffusion_model.del_D_delV(V, self.interpolated_spacing, self.order_acc, \
                                                            coeff_matrix_first_der, coeff_matrix_second_der)

            dVdt = deltaD_deltaV + fast_v + applied_current
            dvdt = slow_v

            next_time_pt_V = V + dt * dVdt
            next_time_pt_v = v + dt * dvdt

            if next_time_pt_V.size > 1:
                assert sum(np.isnan(next_time_pt_V)
                           ) == 0, 'at time {}, next_time_pt_V has nan'.format(
                               t * dt)
                assert sum(np.isnan(next_time_pt_v)
                           ) == 0, 'at time {}, next_time_pt_v has nan'.format(
                               t * dt)
                assert next_time_pt_V.shape[0] == next_time_pt_v.shape[
                    0], 'V and v has different length'
            elif next_time_pt_V.size == 1:
                assert np.isnan(
                    next_time_pt_V
                ) == False, 'at time {}, next_time_pt_V has nan'.format(t * dt)
                assert np.isnan(
                    next_time_pt_v
                ) == False, 'at time {}, next_time_pt_v has nan'.format(t * dt)

            V = next_time_pt_V.copy()
            v = next_time_pt_v.copy()
            V_update.append(V)
            v_update.append(v)

        V_update = np.array(V_update, dtype='float64')
        v_update = np.array(v_update, dtype='float64')

        return V_update, v_update, time_pt

    def generate_first_der_coeff_matrix(self):
        coeff = self.ut.OA_coeff(self.order_acc)
        input_length = np.shape(self.point_cloud.intp_coord_axis1)[1]
        coeff_matrix_first_der = self.ut.coeff_matrix_first_order(
            input_length, coeff)
        self.coeff_matrix_first_der = coeff_matrix_first_der.copy()
        return

    def generate_second_der_coeff_matrix(self):
        coeff = self.ut.OA_coeff(self.order_acc)
        input_length2 = np.shape(
            self.point_cloud.intp_coord_axis1)[1] - len(coeff) + 1
        coeff_matrix_second_der = self.ut.coeff_matrix_first_order(
            input_length2, coeff)
        self.coeff_matrix_second_der = coeff_matrix_second_der.copy()
        return
예제 #2
0
class InverseSolverFHNDiff:
    def __init__(self, fhn_dl_model, diff_dl_model, order_acc):
        self.fhn_dl_model = fhn_dl_model
        self.diff_dl_model = diff_dl_model

        self.order_acc = order_acc
        self.ut = Utils()

        self.tf_coeff_matrix_first_der = None
        self.tf_coeff_matrix_second_der = None

        return

    def solve(self, num_epochs, batch_size, tf_loss, tf_optimizer):
        duration = self.fhn_dl_model.t[-1]
        dt = self.fhn_dl_model.t[1] - self.fhn_dl_model.t[0]

        tf_V = self.fhn_dl_model.tf_V.__copy__()
        tf_v = self.fhn_dl_model.tf_v.__copy__()
        tf_dVdt = self.fhn_dl_model.tf_dVdt.__copy__()
        tf_dvdt = self.fhn_dl_model.tf_dvdt.__copy__()

        tf_intp_V_axis1 = self.diff_dl_model.tf_intp_u_axis1.__copy__()
        tf_intp_V_axis2 = self.diff_dl_model.tf_intp_u_axis2.__copy__()
        tf_coeff_matrix_first_der = self.tf_coeff_matrix_first_der.__copy__()
        tf_coeff_matrix_second_der = self.tf_coeff_matrix_second_der.__copy__()

        n_training_epoch = []
        training_loss = []
        batch_iteration = int(int(duration / dt) / batch_size)

        lowest_loss_value = 1e9
        for epoch in range(num_epochs):
            loss_value = 0
            # loss_value_dVdt = 0
            # loss_value_dvdt = 0

            for iteration in range(batch_iteration):
                begin = [iteration * batch_size, 0, 0]
                size = [(iteration + 1) * batch_size, tf_intp_V_axis1.shape[1],
                        tf_intp_V_axis1.shape[2]]
                tf_intp_V_axis1_tmp = tf.slice(tf_intp_V_axis1, begin, size)
                tf_intp_V_axis2_tmp = tf.slice(tf_intp_V_axis2, begin, size)

                begin = [iteration * batch_size, 0, 0]
                size = [(iteration + 1) * batch_size, tf_dVdt.shape[1],
                        tf_dVdt.shape[2]]
                tf_V_tmp = tf.slice(tf_V, begin, size)
                tf_v_tmp = tf.slice(tf_v, begin, size)
                tf_dVdt_tmp = tf.slice(tf_dVdt, begin, size)
                tf_dvdt_tmp = tf.slice(tf_dvdt, begin, size)

                with tf.GradientTape(persistent=True) as tape:
                    tf_diffusion_term = self.diff_dl_model.call_dl_model(
                        tf_intp_V_axis1_tmp, tf_intp_V_axis2_tmp,
                        tf_coeff_matrix_first_der, tf_coeff_matrix_second_der,
                        self.order_acc)
                    tf_fast_variable = self.fhn_dl_model.fast_variable(
                        tf_V_tmp, tf_v_tmp)
                    tf_slow_variable = self.fhn_dl_model.slow_variable(
                        tf_V_tmp, tf_v_tmp)

                    tf_dVdt_pred = tf_diffusion_term + tf_fast_variable + self.fhn_dl_model.tf_weight_current
                    tf_dvdt_pred = tf_slow_variable

                    pred = tf_dVdt_pred + tf_dvdt_pred
                    true = tf_dVdt_tmp + tf_dvdt_tmp

                    loss_value += tf_loss(true, pred)

                # == calculate gradient and update variables =====
                grads_diff = tape.gradient(
                    loss_value, self.diff_dl_model.trainable_weights)
                tf_optimizer.apply_gradients(
                    zip(grads_diff, self.diff_dl_model.trainable_weights))
                grads_fhn = tape.gradient(loss_value,
                                          self.fhn_dl_model.trainable_weights)
                tf_optimizer.apply_gradients(
                    zip(grads_fhn, self.fhn_dl_model.trainable_weights))
                del tape

            average_loss = loss_value.numpy() / batch_iteration
            lowest_loss_value = self.check_if_avg_loss_lower_than_lowest_loss_value(
                lowest_loss_value, average_loss)

            n_training_epoch.append(epoch)
            training_loss.append(average_loss)

            if epoch % 1 == 0:
                print('epoch {}/{}: loss{}'.format(epoch, num_epochs,
                                                   average_loss))
                print('avg_weight_D: {0:0.4f}'.format(
                    tf.reduce_mean(self.diff_dl_model.tf_weight_D).numpy()))
                print('avg_weight_a: {0:0.4f}'.format(
                    tf.reduce_mean(self.fhn_dl_model.tf_weight_a).numpy()))
                print('avg_weight_epsilon: {0:0.4f}'.format(
                    tf.reduce_mean(
                        self.fhn_dl_model.tf_weight_epsilon).numpy()))
                print('avg_weight_beta: {0:0.4f}'.format(
                    tf.reduce_mean(self.fhn_dl_model.tf_weight_beta).numpy()))
                print('avg_weight_gamma: {0:0.4f}'.format(
                    tf.reduce_mean(self.fhn_dl_model.tf_weight_gamma).numpy()))
                print('avg_weight_delta: {0:0.4f}'.format(
                    tf.reduce_mean(self.fhn_dl_model.tf_weight_delta).numpy()))
                print('\n')
        n_training_epoch = np.array(n_training_epoch)
        training_loss = np.array(training_loss)

        return n_training_epoch, training_loss

    def check_if_avg_loss_lower_than_lowest_loss_value(
            self, lowest_loss_value, current_epoch_loss_value):
        print('current_loss  = {} lowest_loss = {}'.format(
            current_epoch_loss_value, lowest_loss_value))
        if current_epoch_loss_value < lowest_loss_value:
            print('assign_lowest_weight_D')
            self.diff_dl_model.assign_tf_lowest_weight_D(
                self.diff_dl_model.tf_weight_D)
            self.fhn_dl_model.assign_tf_lowest_weight_a(
                self.fhn_dl_model.tf_weight_a)
            self.fhn_dl_model.assign_tf_lowest_weight_epsilon(
                self.fhn_dl_model.tf_weight_epsilon)
            self.fhn_dl_model.assign_tf_lowest_weight_beta(
                self.fhn_dl_model.tf_weight_beta)
            self.fhn_dl_model.assign_tf_lowest_weight_gamma(
                self.fhn_dl_model.tf_weight_gamma)
            self.fhn_dl_model.assign_tf_lowest_weight_delta(
                self.fhn_dl_model.tf_weight_delta)
            lowest_loss_value = current_epoch_loss_value.copy()
        return lowest_loss_value

    def generate_first_der_coeff_matrix(self):
        coeff = self.ut.OA_coeff(self.order_acc)
        input_length = np.shape(self.diff_dl_model.tf_intp_u_axis1.numpy())[-1]
        coeff_matrix_first_der = self.ut.coeff_matrix_first_order(
            input_length, coeff)
        coeff_matrix_first_der = coeff_matrix_first_der.copy()
        return coeff_matrix_first_der

    def generate_second_der_coeff_matrix(self):
        coeff = self.ut.OA_coeff(self.order_acc)
        input_length2 = np.shape(
            self.diff_dl_model.tf_intp_u_axis2.numpy())[-1] - len(coeff) + 1
        coeff_matrix_second_der = self.ut.coeff_matrix_first_order(
            input_length2, coeff)
        coeff_matrix_second_der = coeff_matrix_second_der.copy()
        return coeff_matrix_second_der

    def convert_coeff_matrix_to_tensor_with_correct_shape(
            self, coeff_matrix_first_der, coeff_matrix_second_der):
        coeff_matrix_first_der = np.expand_dims(coeff_matrix_first_der,
                                                axis=0)  # shape(1, 5, 3)
        coeff_matrix_second_der = np.expand_dims(coeff_matrix_second_der,
                                                 axis=0)  # shape(1, 3, 1)

        # coeff_matrix_first_der = np.expand_dims(coeff_matrix_first_der, axis=0)  # shape(1, 1, 5, 3)
        # coeff_matrix_second_der = np.expand_dims(coeff_matrix_second_der, axis=0)  # shape(1, 1, 3, 1)

        assert np.ndim(
            coeff_matrix_first_der
        ) == 3, 'coeff_matrix_first_der must be 3D array (1, 5nn, 3)'
        assert np.ndim(
            coeff_matrix_first_der
        ) == 3, 'coeff_matrix_first_der must be 3D array (1, 3nn, 1)'

        self.tf_coeff_matrix_first_der = tf.convert_to_tensor(
            coeff_matrix_first_der, dtype=tf.float64)
        self.tf_coeff_matrix_second_der = tf.convert_to_tensor(
            coeff_matrix_second_der, dtype=tf.float64)
        return