Skip to content

Commit 0439354

Browse files
committed
fixed the sorting bug in the gradients and skipped the good examples in the gradients
1 parent 4c8f6ba commit 0439354

File tree

8 files changed

+122
-99
lines changed

8 files changed

+122
-99
lines changed

adalflow/adalflow/core/generator.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ def _backward_through_one_predecessor(
642642
prompt_str: str,
643643
is_intermediate_node: bool = False,
644644
):
645+
"""Creating gradient/textual feedback for prompt type parameters."""
645646
if not pred.requires_opt:
646647
log.debug(
647648
f"Generator: Skipping {pred} as it does not require optimization."
@@ -704,7 +705,9 @@ def _backward_through_one_predecessor(
704705
template=obj_ins_template,
705706
prompt_kwargs={
706707
"response_desc": response.role_desc,
707-
"response_gradient": response.get_gradient_and_context_text(),
708+
"response_gradient": response.get_gradient_and_context_text(
709+
skip_correct_sample=True
710+
),
708711
"instruction_to_backward_engine": pred.instruction_to_backward_engine,
709712
},
710713
)()
@@ -716,11 +719,16 @@ def _backward_through_one_predecessor(
716719
gradient_output: GeneratorOutput = None
717720
if response._score is not None and float(response._score) > 0.9:
718721
log.debug(f"EvalFnToTextLoss: Skipping {pred} as the score is high enough.")
719-
manual_response = f"You get a high score: {response._score}."
722+
# TODO: plus score descriptions
723+
manual_response = f"You get score: {response._score}."
720724
gradient_output = GeneratorOutput(
721725
data=manual_response, raw_response=manual_response
722726
)
723727
else:
728+
# manual_response = f"You get score: {response._score}."
729+
# gradient_output = GeneratorOutput(
730+
# data=manual_response, raw_response=manual_response
731+
# )
724732

725733
gradient_output: GeneratorOutput = backward_engine(
726734
prompt_kwargs=backward_engine_prompt_kwargs

adalflow/adalflow/optim/parameter.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,12 @@ def __init__(
212212

213213
# here are used for demo parameter, filled by generator.forward
214214
self._traces: Dict[str, DataClass] = {} # id to data items (DynamicDataClass)
215+
self._student_traces: Dict[str, DataClass] = {} # id
216+
215217
self._score: float = (
216-
score # end to end evaluation score, TODO: might have multiple scores if using multiple eval fns
218+
score # end to end evaluation score, TODO: might have multiple scores if using multiple eval fns # score is set in the gradients in the backward pass
217219
)
218220

219-
self._student_traces: Dict[str, DataClass] = {} # id
220221
self._demos: List[DataClass] = (
221222
[]
222223
) # used for the optimizer to save the proposed demos
@@ -431,10 +432,13 @@ def get_gradients_names(self) -> str:
431432
names = ", ".join(names)
432433
return names
433434

434-
def get_gradient_and_context_text(self) -> str:
435+
def get_gradient_and_context_text(self, skip_correct_sample: bool = False) -> str:
435436
"""Aggregates and returns:
436437
1. the gradients
437438
2. the context text for which the gradients are computed
439+
440+
Sort the gradients from the lowest score to the highest score.
441+
Highlight the gradients with the lowest score to the optimizer.
438442
"""
439443
from adalflow.core.prompt_builder import Prompt
440444

@@ -444,18 +448,26 @@ def get_gradient_and_context_text(self) -> str:
444448

445449
# sore gradients by the _score from low to high
446450
self.gradients = sorted(
447-
self.gradients, key=lambda x: x._score if x._score else 1
451+
self.gradients, key=lambda x: x._score if x._score is not None else 1
448452
)
453+
# print the score for the sorted gradients
454+
lowest_score_gradients = []
455+
for i, g in enumerate(self.gradients):
456+
if skip_correct_sample:
457+
if g._score > 0.5:
458+
continue
459+
lowest_score_gradients.append(g)
460+
print(f"{i} Score: {g._score} for {g.name}, {type(g._score)}")
449461

450462
gradient_context_combined = list(
451463
zip(
452-
self.gradients,
453-
[self.gradients_context[g] for g in self.gradients],
464+
lowest_score_gradients,
465+
[self.gradients_context[g] for g in lowest_score_gradients],
454466
)
455467
)
456468
# set all gradients value to None
457-
for g in self.gradients:
458-
g.data = None
469+
# for g in self.gradients:
470+
# g.data = None
459471

460472
gradient_context_combined_str = Prompt(
461473
template=COMBINED_GRADIENTS_TEMPLATE,
@@ -520,7 +532,11 @@ def report_cycle(cycle_nodes: List["Parameter"]):
520532

521533
def backward(
522534
self,
523-
): # engine should be the llm or customized backwards function to pass feedback
535+
):
536+
"""
537+
Apply backward pass for for all nodes in the graph by reversing the topological order.
538+
"""
539+
# engine should be the llm or customized backwards function to pass feedback
524540

525541
# topological sort of all the predecessors of the current parameter in the graph
526542
log.debug(f"Backward pass for {self.data}, backward function: {self.grad_fn}")
@@ -543,7 +559,6 @@ def build_topo(node: Parameter):
543559
if not node.requires_opt:
544560
log.debug(f"Skipping {node.name} as it does not require optimization")
545561
continue
546-
node.gradients = _check_and_reduce_gradients(node)
547562
log.debug(f"v: {node.data}, grad_fn: {node.grad_fn}, {node.get_grad_fn()}")
548563
if node.get_grad_fn() is not None: # gradient function takes in the engine
549564
log.debug(f"Calling gradient function for {node.name}")
@@ -949,20 +964,3 @@ def from_dict(cls, data: dict):
949964
def __repr__(self):
950965
return f"Parameter(name={self.name}, requires_opt={self.requires_opt}, param_type={self.param_type}, role_desc={self.role_desc}, data={self.data}, predecessors={self.predecessors}, gradients={self.gradients},\
951966
raw_response={self.raw_response}, input_args={self.input_args}, traces={self._traces})"
952-
953-
954-
def _check_and_reduce_gradients(variable: Parameter) -> Set[Parameter]:
955-
956-
if variable.get_gradient_and_context_text() == "":
957-
log.debug(f"No gradients detected for {variable.data}")
958-
return variable.gradients
959-
if len(variable.gradients) == 1:
960-
log.debug(f"Only one gradient, no need to reduce: {variable.gradients}")
961-
return variable.gradients
962-
else:
963-
log.debug(
964-
f"Multiple gradients detected for {variable.data}. But we are not reducting them."
965-
)
966-
return variable.gradients
967-
968-
# TODO: Implement the reduction logic later

adalflow/adalflow/optim/text_grad/text_loss_with_eval_fn.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ def _backward_through_one_predecessor(
322322
)
323323

324324
# backward the end to end score
325+
# TODO: not really useful
325326
pred.set_score(response.data)
326327
print(f"setting pred name {pred.name} score to {response.data}")
327328

adalflow/adalflow/optim/text_grad/tgd_optimizer.py

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ class HistoryPrompt(DataClass):
3737
####################################################################################################
3838
# Textual Gradient Descent Optimizer
3939
####################################################################################################
40-
40+
# {% if failed_proposals %}
41+
# Here are the past failed proposals:
42+
# {% for failed_proposal in failed_proposals %}
43+
# {{loop.index}}. {{failed_proposal}}
44+
# {% endfor %}
45+
# {% endif %}
4146
TEXT_GRAD_DESC_TEMPLATE = r"""<START_OF_SYSTEM_PROMPT>
4247
{{optimizer_system_prompt}}
4348
<END_OF_SYSTEM_PROMPT>
@@ -51,13 +56,6 @@ class HistoryPrompt(DataClass):
5156
{{loop.index}}. {{history}}
5257
{% endfor %}
5358
IMPORTANT: Your goal is to generate new variable values that score higher than all previous iterations.
54-
55-
{% if failed_proposals %}
56-
Here are the past failed proposals:
57-
{% for failed_proposal in failed_proposals %}
58-
{{loop.index}}. {{failed_proposal}}
59-
{% endfor %}
60-
{% endif %}
6159
<END_OF_HISTORY_PERFORMANCE>
6260
{% endif %}
6361
Here are the context and feedback for the variable:
@@ -176,7 +174,7 @@ class TGDOptimizer(TextOptimizer):
176174
params: ParamsT
177175
constraints: List[str]
178176
params_history: Dict[str, List[HistoryPrompt]] = {} # id to history
179-
failed_proposals: Dict[str, List[HistoryPrompt]] = {} # only need the value
177+
# failed_proposals: Dict[str, List[HistoryPrompt]] = {} # only need the value
180178

181179
def __init__(
182180
self,
@@ -189,7 +187,7 @@ def __init__(
189187
in_context_examples: List[str] = None, # TODO: in-context examples
190188
num_gradient_memory: int = 0, # TODO: gradient memory and momentum, for now it is not useful
191189
max_past_history: int = 3,
192-
max_failed_proposals: int = 3,
190+
# max_failed_proposals: int = 3,
193191
):
194192
from adalflow.core.generator import Generator
195193
from adalflow.core import Prompt
@@ -229,12 +227,12 @@ def __init__(
229227
)
230228

231229
self.max_past_history = max_past_history
232-
self.max_failed_proposals = max_failed_proposals
230+
# self.max_failed_proposals = max_failed_proposals
233231

234232
# initate the past history for each parameter
235233
for param in self.params:
236234
self.params_history[param.id] = []
237-
self.failed_proposals[param.id] = []
235+
# self.failed_proposals[param.id] = []
238236

239237
@property
240238
def constraint_text(self):
@@ -289,39 +287,39 @@ def render_history(self, param_id: str) -> List[str]:
289287
history.to_yaml(exclude=["id"]) for history in self.params_history[param_id]
290288
]
291289

292-
def add_failed_proposal(self):
293-
"""Save a copy of the current value of the parameter in the failed proposals."""
294-
for param in self.params:
295-
failed_proposal = HistoryPrompt(
296-
id=param.id,
297-
value=param.data,
298-
eval_score=None,
299-
)
300-
self.failed_proposals[param.id].append(failed_proposal)
301-
if len(self.failed_proposals[param.id]) > self.max_failed_proposals:
302-
for _ in range(
303-
len(self.failed_proposals[param.id]) - self.max_failed_proposals
304-
):
305-
self.failed_proposals[param.id].pop()
306-
# if param_id not in self.failed_proposals:
307-
# self.failed_proposals[param_id] = []
308-
# failed_proposal = HistoryPrompt(
309-
# id=param_id,
310-
# value=value,
311-
# eval_score=None,
312-
# )
313-
# self.failed_proposals[param_id].append(failed_proposal)
314-
# if len(self.failed_proposals[param_id]) > self.max_failed_proposals:
315-
# for _ in range(len(self.failed_proposals[param_id]) - self.max_failed_proposals):
316-
# self.failed_proposals[param_id].pop()
317-
318-
def render_failed_proposals(self, param_id: str) -> List[str]:
319-
if param_id not in self.failed_proposals:
320-
return []
321-
return [
322-
history.to_yaml(exclude=["id", "eval_score"])
323-
for history in self.failed_proposals[param_id]
324-
]
290+
# def add_failed_proposal(self):
291+
# """Save a copy of the current value of the parameter in the failed proposals."""
292+
# for param in self.params:
293+
# failed_proposal = HistoryPrompt(
294+
# id=param.id,
295+
# value=param.data,
296+
# eval_score=None,
297+
# )
298+
# self.failed_proposals[param.id].append(failed_proposal)
299+
# if len(self.failed_proposals[param.id]) > self.max_failed_proposals:
300+
# for _ in range(
301+
# len(self.failed_proposals[param.id]) - self.max_failed_proposals
302+
# ):
303+
# self.failed_proposals[param.id].pop()
304+
# # if param_id not in self.failed_proposals:
305+
# # self.failed_proposals[param_id] = []
306+
# # failed_proposal = HistoryPrompt(
307+
# # id=param_id,
308+
# # value=value,
309+
# # eval_score=None,
310+
# # )
311+
# # self.failed_proposals[param_id].append(failed_proposal)
312+
# # if len(self.failed_proposals[param_id]) > self.max_failed_proposals:
313+
# # for _ in range(len(self.failed_proposals[param_id]) - self.max_failed_proposals):
314+
# # self.failed_proposals[param_id].pop()
315+
316+
# def render_failed_proposals(self, param_id: str) -> List[str]:
317+
# if param_id not in self.failed_proposals:
318+
# return []
319+
# return [
320+
# history.to_yaml(exclude=["id", "eval_score"])
321+
# for history in self.failed_proposals[param_id]
322+
# ]
325323

326324
# TODO: optimize with adalflow template for better readability
327325
def get_gradient_memory_text(self, param: Parameter) -> str:
@@ -341,7 +339,9 @@ def _get_user_prompt_kwargs(self, param: Parameter) -> Dict[str, str]:
341339

342340
user_prompt_kwargs = {
343341
"variable_and_peers_info": variable_and_peer_info,
344-
"variable_grad": param.get_gradient_and_context_text(),
342+
"variable_grad": param.get_gradient_and_context_text(
343+
skip_correct_sample=True
344+
),
345345
# constraints
346346
"constraint_text": self.constraint_text if self.do_constrained else None,
347347
# in-context examples
@@ -361,19 +361,19 @@ def _get_user_prompt_kwargs(self, param: Parameter) -> Dict[str, str]:
361361
self.render_history(param.id) if self.max_past_history else None
362362
),
363363
# failed proposals
364-
"failed_proposals": (
365-
self.render_failed_proposals(param.id)
366-
if self.max_failed_proposals
367-
else None
368-
),
364+
# "failed_proposals": (
365+
# self.render_failed_proposals(param.id)
366+
# if self.max_failed_proposals
367+
# else None
368+
# ),
369369
}
370370

371371
return user_prompt_kwargs
372372

373373
# TODO: better way to update the gradient memory
374374
def update_gradient_memory(self, param: Parameter):
375375
self.gradient_memory_dict[param.id].append(
376-
{"value": param.get_gradient_and_context_text()}
376+
{"value": param.get_gradient_and_context_text(skip_correct_sample=True)}
377377
)
378378

379379
def zero_grad(self):

0 commit comments

Comments
 (0)