Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hawkes cumulants - Tensorflow v1 #505

Merged

Conversation

claudio-ICL
Copy link
Collaborator

This PR proposes to break the class HawkesCumulantMatching in a base class with the general interface, and a derived class that implements the methods of the interface using tensorflow. A second derived class that will implement the same methods with pytorch is also prototyped.
Moreover, this PR tries to migrate HawkesCumulantMatching to tensorflow v2 minimising the required changes: I used tf.compat.v1. Tests of the inference methodology are re-activated (no longer skipped by default).

@claudio-ICL
Copy link
Collaborator Author

Hi @Mbompr

I am trying to adapt the code of HawkesCumulantMatching to tensorflow v2. There are some tests that fail however, because the numerical precision is not achieved. I was wondering whether you can explain how the expected values were produced?

@Mbompr
Copy link
Contributor

Mbompr commented Dec 14, 2022

If I remember correctly, these values have been obtained by making the algorithm run.
I think that if the new values are close enough, we can simply replace them. Maybe the optimization loop has changed with TF2.

@claudio-ICL
Copy link
Collaborator Author

If I remember correctly, these values have been obtained by making the algorithm run. I think that if the new values are close enough, we can simply replace them. Maybe the optimization loop has changed with TF2.

Understood. So, they are not ground truth. From a first run with v2 I get somewhat similar values, but the precision of 6 decimal places is certainly lost.

image (1)

@Mbompr
Copy link
Contributor

Mbompr commented Dec 14, 2022

I think it makes sense to change the values in the test within the PR then

@claudio-ICL
Copy link
Collaborator Author

If I remember correctly, these values have been obtained by making the algorithm run. I think that if the new values are close enough, we can simply replace them. Maybe the optimization loop has changed with TF2.

Understood. So, they are not ground truth. From a first run with v2 I get somewhat similar values, but the precision of 6 decimal places is certainly lost.

I am thinking whether it would be more appropriate to design a test as follows:

  1. Instantiate a parametric class (e.g. exponential) with given coefficients, and compute exact L1 norms of kernels.
  2. Generate timestamps from simulation.
  3. Calibrate HawkesCumulantMatching on the simulated timestamps.
  4. Compare calibrated adjacency with exact L1 norms.

@Mbompr
Copy link
Contributor

Mbompr commented Dec 14, 2022

I agree that makes more sense. But I find it hard to suggest something big when I had been lazy before 😬

np.random.seed(320982)

@staticmethod
def get_simulated_model():
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mbompr This is the idea that I was suggesting in the conversation of this PR. I simulate a hawkes process with exponential kernels and I train HawkesCumulantMatching on five samples. Loading pickled data would be replaced by this, if you agree.
More importantly, the assertion of almost equality now are between the exact theoretical values from the simulated hawkes process and the calibrated coefficients of HawkesCumulantMatching. When these assertion succeed, they should guarantee approximate exactness of algorithm.

np.allclose(
learner.solution,
expected_R_pred,
atol=0.1, # TODO: explain why estimation is not so accurate
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mbompr Unfortunately, accuracy is not so good here. Are you familiar with the tuning of hyperparameters of HawkesCumulantMatching? If yes, can you please see if a better choice of step, max_iter etc... gives more accurate estimations? I can see from the paper that the accuracy was really good.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Mbompr

Could you look into this please?

@@ -35,4 +33,29 @@ class DLL_PUBLIC HawkesCumulant : public ModelHawkesList {
}
};

class DLL_PUBLIC HawkesTheoreticalCumulant {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mbompr @PhilipDeegan

This is a new c++ class that implements the theoretical formulae for mean intensity, covariance and skewness of hawkes processes. These are the formulae (7), (8), and (9) in the paper.
Currently, the class is only used to test the accuracy of the estimation of HawkesCumulantMatching. However, the formulae have intrinsic values beside such testing, and we might include these calculations in a more general Hawkes class in the future.


np.testing.assert_array_almost_equal(
learner.objective(R=learner.solution), 149232.94041039888)
@unittest.skipIf(SKIP_TF, "Tensorflow not available")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PhilipDeegan I have defined a global boolean variable SKIP_TF and used it with unitest.skipIf

np.allclose(
learner.solution,
expected_R_pred,
atol=0.1, # TODO: explain why estimation is not so accurate
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Mbompr

Could you look into this please?

@claudio-ICL
Copy link
Collaborator Author

Hi @PhilipDeegan , Do you think we can merge this?

@@ -126,3 +124,66 @@ double HawkesCumulant::compute_E_ijk(ulong r, ulong i, ulong j, ulong k,
res /= (*end_times)[r];
return res;
}

HawkesTheoreticalCumulant::HawkesTheoreticalCumulant(int dim) : d(dim) {
Lambda = SArrayDouble::new_ptr(dim);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can these be part of the constuctor setup arguments like : d(dim) ?

@@ -126,3 +124,66 @@ double HawkesCumulant::compute_E_ijk(ulong r, ulong i, ulong j, ulong k,
res /= (*end_times)[r];
return res;
}

HawkesTheoreticalCumulant::HawkesTheoreticalCumulant(int dim) : d(dim) {
Lambda = SArrayDouble::new_ptr(dim);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. is Lambda the best name?
  2. variables names don't typically start with upper case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variables Lambda, C, Kc, and R represent first integrated cumulant, second integrated cumulant, (reduced) third integrated cumulant, and inverse of $I - G$ (where $G$ is the matrix of $L^1$-norms of kernel functions), respectively. Their names are directly taken from the math symbols used in the paper: $\Lambda$, $C$, $K$, and $R$, respectively.

I agree that the upper case is uncommon. I can change the name as follows:
Lambda -> first_cumulant
C -> second_cumulant
Kc -> third_cumulant
R -> g_geometric

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done here: 11353f4

@@ -56,15 +53,13 @@ bool Hawkes::update_time_shift_(double delay, ArrayDouble &intensity,
void Hawkes::reset() {
for (unsigned int i = 0; i < n_nodes; i++) {
for (unsigned int j = 0; j < n_nodes; j++) {
if (kernels[i * n_nodes + j] != nullptr)
kernels[i * n_nodes + j]->rewind();
if (kernels[i * n_nodes + j] != nullptr) kernels[i * n_nodes + j]->rewind();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it was unsigned int before, I would generally prefer std::uint32_t or similar

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood...
I will open a new PR about that because it is not related to HawkesCumulant or tensorflow

public:
HawkesTheoreticalCumulant(int);
int get_dimension() { return d; }
void set_baseline(const SArrayDoublePtr mu) { this->mu = mu; }
Copy link
Member

@PhilipDeegan PhilipDeegan Jan 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might not have it everywhere, but T const[&] n is the preferred order

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed: fa43f6d

claudio-tw and others added 5 commits February 2, 2023 11:13
 On branch tensorflow-v1-hawkes-cumulants
 Your branch is up-to-date with 'origin/tensorflow-v1-hawkes-cumulants'.

 Changes to be committed:
	modified:   lib/cpp/hawkes/inference/hawkes_cumulant.cpp
	modified:   lib/include/tick/hawkes/inference/hawkes_cumulant.h
	modified:   lib/swig/tick/hawkes/inference/hawkes_cumulant.i
	modified:   tick/hawkes/inference/hawkes_cumulant_matching.py
Conflicts:
	.github/workflows/build_nix.yml
	tick/hawkes/inference/hawkes_cumulant_matching.py
@claudio-ICL
Copy link
Collaborator Author

@PhilipDeegan
I believe that this PR is ready to merge. Would it be possible to do it today?

claudio-ICL added a commit to claudio-ICL/tick that referenced this pull request Feb 14, 2023
'tensorflow-v1-hawkes-cumulants' into 'pytorch-hawkes-cumulant'
@PhilipDeegan PhilipDeegan merged commit 4187902 into X-DataInitiative:master Feb 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants