-
Notifications
You must be signed in to change notification settings - Fork 329
Temporal sampling implementation #4994
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
base: branch-25.08
Are you sure you want to change the base?
Temporal sampling implementation #4994
Conversation
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about efficient implementation of temporal sampling especially considering that some seed vertices can be reached from multiple different paths and we need to apply multiple different temporal windows for the same seed vertex.
This can lead to many vertex partitions especially for power-law graphs.
And applying & creating graph-wise temporal mask can be pretty expensive if we need to do this many times.
We can apply a graph-wise temporal mask to set temporal window including the lower and upper bound of the start/end times for the entire set of seeds in multiple batches.
For a seed specific time window, I think adjusting bias values will lead to more efficient implementation.
We can tag a seed vertex with a time-stamp (https://github.com/rapidsai/cugraph/blob/branch-25.04/cpp/src/prims/per_v_random_select_transform_outgoing_e.cuh#L1092C28-L1092C72).
And when we set the bias value (https://github.com/rapidsai/cugraph/blob/branch-25.04/cpp/src/prims/per_v_random_select_transform_outgoing_e.cuh#L1096), we can set the bias value to 0 if the edge is outside the seed specific time window.
I think this can lead to more efficient implementation than the current approach.
What do you think about this?
And for uniform sampling, we may use a uniform sampling primitive for seeds that appear no more than once and use a biased sampling primitive for seeds that appear two or more times. |
So something akin to what node2vec does... return a bias of 0 if the edge time is invalid, return a bias of 1 if the edge time is valid. Because we're operating on the tagged vertex, each vertex would have its own timestamp... therefore its own computed bias. If my interpretation is correct, I think that would be a much simpler implementation and would probably result in significantly better performance in the cases where we end up with a high degree vertex that appears multiple times in the frontier. |
Yes, your interpretation is correct. I agree that this will be simpler & faster. For uniform sampling and to avoid the overhead of evaluating bias for every edge, we can use just a default uniform sampling for seeds that appear only once, and use bias values & tagging for seeds that appear more than once. |
@ChuckHastings what is the status of this PR? Will this be completed in release 25.06? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (besides few comments about minor cosmetic issues)
template <typename vertex_t, typename value_t> | ||
std::tuple<rmm::device_uvector<vertex_t>, rmm::device_uvector<value_t>> | ||
template <typename vertex_t, typename value_vector_t> | ||
std::tuple<rmm::device_uvector<vertex_t>, value_vector_t> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just use dataframe_buffer_type_t (https://github.com/rapidsai/cugraph/blob/branch-25.06/cpp/include/cugraph/utilities/dataframe_buffer.hpp#L91) here.
Just replacing rmm::device_uvector<value_t> with dataframe_buffer_type_t<value_t>
will work.
template <typename... Ts, std::size_t... Is> | ||
auto view_concat_impl(std::tuple<Ts...> const& tuple, std::index_sequence<Is...>) | ||
{ | ||
return view_concat(std::get<Is>(tuple)...); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A convention is to place the detail namespace code at the beginning of the file.
{ | ||
static_assert(is_std_tuple_of_arithmetic_spans<std::remove_cv_t<BufferType>>::value); | ||
if constexpr (is_std_tuple_of_arithmetic_spans<std::remove_cv_t<BufferType>>::value) { | ||
return std::get<0>(buffer).size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this function? Can't the function above cover std::tuple of std::span as well?
std::conditional_t<std::is_same_v<edge_properties_t, cuda::std::nullopt_t>, | ||
thrust::tuple<>, | ||
std::conditional_t<std::is_arithmetic_v<edge_properties_t>, | ||
thrust::tuple<edge_properties_t>, | ||
edge_properties_t>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this edge_properties_tup_type
defined above? We can just use it here.
} | ||
} | ||
|
||
// FIXME: Duplicated across files... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we move this to detail/sampling_utils.hpp to avoid duplication?
@@ -16,9 +16,11 @@ | |||
|
|||
#pragma once | |||
|
|||
#include "cugraph/utilities/shuffle_comm.cuh" | |||
#include "prims/update_edge_src_dst_property.cuh" // ?? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be from a previous PR but why ?? If we are not using this, can't we delete?
|
||
edge_src_property_t<edge_t, edge_time_t, false> edge_src_times(handle, graph_view); | ||
|
||
#if 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better delete the dead code.
|
||
#if 0 | ||
// FIXME: This call to update_edge_src_property seems like what I want, but it | ||
// doesn't work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know why? What happened with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variation of the call is only used in a few places. MG SSSP, and Random Walks are the only places I see it.
Not sure if it's broken there and we haven't noticed, or if I'm doing something wrong here. But I printed the relevant contents of the arrays and they were incorrect. Since I use them as indices into device arrays, I could clearly see that the wrong values affected the output.
I spent a little time trying to diagnose, but didn't have time to really dig in. It's possible I've done something incorrect in the setup, but setting do_expensive_check didn't reveal anything wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can I reproduce this? I can dig in to see what's going awry here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try and create a reproducer for you.
template <typename vertex_t, typename value_t> | ||
std::tuple<rmm::device_uvector<vertex_t>, rmm::device_uvector<value_t>> | ||
template <typename vertex_t, typename value_vector_t> | ||
std::tuple<rmm::device_uvector<vertex_t>, value_vector_t> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use dataframe_buffer_type_t<value_t>
… performance until we have a good solution
…s other cuh files
… and get things to build in CI
Temporal sampling implementation. Sampling considers the time stamp of edges, if we arrive at a vertex
v
with timestampt1
, then when we depart from that vertex to continue sampling we only consider edges that occur after timet1
.PR includes C++ implementation and tests.
This significantly increases C++ compile time. We'll address this during 25.08.