-
Notifications
You must be signed in to change notification settings - Fork 56
Add optional custom log_rewards to all GFlowNet losses #503
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
Changes from 9 commits
c5b064a
9630594
2308c24
485dab7
429e790
ee6f787
11caee9
f7f0d40
001ecd3
380f59b
5aaef2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -210,6 +210,8 @@ def get_scores( | |
| env: Env, | ||
| transitions: Transitions, | ||
| recalculate_all_logprobs: bool = True, | ||
| *, | ||
| log_rewards: torch.Tensor | None = None, | ||
| ) -> torch.Tensor: | ||
| r"""Calculates the scores for a batch of transitions. | ||
|
|
||
|
|
@@ -220,11 +222,31 @@ def get_scores( | |
| env: The environment where the transitions are sampled from. | ||
| transitions: The Transitions object to evaluate. | ||
| recalculate_all_logprobs: Whether to re-evaluate all logprobs. | ||
| log_rewards: Optional custom log rewards tensor of shape | ||
| (n_transitions,). When None, uses the environment rewards | ||
| from the transitions. Useful for intrinsic rewards (see | ||
| "Towards Improving Exploration through Sibling Augmented | ||
| GFlowNets", Madan et al., ICLR 2025). | ||
| **Not supported when** ``forward_looking=True``: raises | ||
| ``ValueError`` in that case because the forward-looking | ||
| objective still calls ``env.log_reward()`` for intermediate | ||
| state adjustments, so custom rewards cannot fully replace | ||
| environment rewards. | ||
|
|
||
| Returns: | ||
| A tensor of shape (n_transitions,) representing the scores for each | ||
| transition. | ||
| """ | ||
| # Reject custom log_rewards in forward-looking mode (documented in docstring). | ||
| if log_rewards is not None and self.forward_looking: | ||
| raise ValueError( | ||
| "custom log_rewards are not supported when forward_looking=True: " | ||
| "the forward-looking DB objective calls env.log_reward() for " | ||
| "intermediate-state adjustments, so environment rewards cannot be " | ||
| "fully replaced. Either use forward_looking=False or do not pass " | ||
| "log_rewards." | ||
| ) | ||
|
|
||
| # Guard bad inputs under debug to avoid graph breaks in torch.compile. | ||
| if self.debug and transitions.is_backward: | ||
| raise ValueError("Backward transitions are not supported") | ||
|
|
@@ -261,11 +283,13 @@ def get_scores( | |
| is_terminating = transitions.is_terminating | ||
| is_intermediate = ~is_terminating | ||
|
|
||
| # cast: log_rewards is always populated for valid transitions; | ||
| # assert is behind debug to avoid graph breaks in torch.compile. | ||
| log_rewards = cast(torch.Tensor, transitions.log_rewards) | ||
| # Use custom log_rewards if provided, otherwise fall back to the | ||
| # transition's environment rewards. | ||
| if log_rewards is None: | ||
| log_rewards = cast(torch.Tensor, transitions.log_rewards) | ||
| if self.debug: | ||
|
Comment on lines
+286
to
290
|
||
| assert log_rewards is not None | ||
| assert log_rewards.shape == (transitions.n_transitions,) | ||
| if math.isfinite(self.log_reward_clip_min): | ||
| log_rewards = log_rewards.clamp_min(self.log_reward_clip_min) | ||
| log_F_s_next[is_terminating] = log_rewards[is_terminating] | ||
|
|
@@ -334,6 +358,8 @@ def loss( | |
| transitions: Transitions, | ||
| recalculate_all_logprobs: bool = True, | ||
| reduction: str = "mean", | ||
|
Comment on lines
355
to
360
|
||
| *, | ||
| log_rewards: torch.Tensor | None = None, | ||
| ) -> torch.Tensor: | ||
| """Computes the detailed balance loss. | ||
|
|
||
|
|
@@ -346,6 +372,8 @@ def loss( | |
| recalculate_all_logprobs: Whether to re-evaluate all logprobs. | ||
| reduction: The reduction method to use ('mean', 'sum', or 'none'). | ||
| Run with self.debug=False for improved performance. | ||
| log_rewards: Optional custom log rewards tensor of shape | ||
| (n_transitions,). When None, uses the environment rewards. | ||
|
|
||
| Returns: | ||
| The computed detailed balance loss as a tensor. The shape depends on the | ||
|
|
@@ -356,6 +384,7 @@ def loss( | |
| scores = self.get_scores( | ||
| env, | ||
| transitions, | ||
| log_rewards=log_rewards, | ||
| recalculate_all_logprobs=recalculate_all_logprobs, | ||
| ) | ||
| scores = self.loss_fn(scores) | ||
|
|
||
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.
Adding
log_rewardsbeforerecalculate_all_logprobschanges the positional calling convention forget_scores(). Existing code that previously didget_scores(trajs, False, env)would now passFalseaslog_rewards, breaking backward compatibility. Consider keeping existing positional args intact and makinglog_rewardskeyword-only (e.g., place it afterenv/ behind a*).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.
@copilot apply changes based on this feedback
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.
Fixed in commit
11caee9. Madelog_rewardskeyword-only (using*) in all publicloss()andget_scores()methods acrossbase.py,trajectory_balance.py,detailed_balance.py,flow_matching.py,sub_trajectory_balance.py, and the tutorial subclass. The existing positional parameters (env,trajectories/transitions,recalculate_all_logprobs,reduction) remain in their original positions, so callers using positional args continue to work unchanged.