dspy icon indicating copy to clipboard operation
dspy copied to clipboard

Typed predictors initiated with a range make assert_transform_module crash

Open ko0stik opened this issue 4 months ago • 1 comments

Hi there, first, thanks a lot for this very cool library!

Code to reproduce the issue:

import functools
from logging import Logger
from typing import List, Optional
from dspy import Module, Suggest, assert_transform_module, backtrack_handler, Predict
from dspy.functional import TypedChainOfThought

class Sandbox(Module):
    def __init__(self, logger: Logger = Logger("Sandbox")):
        super().__init__()
        self.logger = logger

    def forward(self, context: List[str] = []):
        transformed_module_with_array_nested_predictors = assert_transform_module(
            TransformedModule(),
            functools.partial(backtrack_handler, max_backtracks=2))
        transformed_module_with_array_nested_predictors([])


class TransformedModule(Module):
    def __init__(self, logger: Logger = Logger("TransformedModule")):
        super().__init__()
        self.logger = logger
        self.array_predictor = [TypedChainOfThought("question -> answer") for _ in range(3)]

    def forward(self, context: List[str] = []):
        self.array_predictor[0](question="What is the capital of the world?")

Trace:

module
    module.map_named_predictors(dspy.retry.Retry)
  File "/Users/X/Library/Caches/pypoetry/virtualenvs/rag-jAwKM_yQ-py3.11/lib/python3.11/site-packages/dspy/primitives/program.py", line 47, in map_named_predictors
    set_attribute_by_name(self, name, func(predictor))
  File "/Users/X/Library/Caches/pypoetry/virtualenvs/rag-jAwKM_yQ-py3.11/lib/python3.11/site-packages/dspy/primitives/program.py", line 88, in set_attribute_by_name
    sub_obj = getattr(obj, module_name)
              ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'TransformedModule' object has no attribute 'array_predictor[0]'. Did you mean: 'array_predictor'?

It works as it should with non typed arrays of predictors or typed predictors alone

My dirty workaround:

# __init__
        [setattr(self, f"finalize_sub_section_{i}", TypedChainOfThought(GenerateFinalisedSubsection)) for i in range(max_subsections)]

# forward
for i, sub_section in enumerate(sub_sections[:self.max_subsections]):
            # p = self.finalize_sub_section[i](
            p = getattr(self, f"finalize_sub_section_{i}")(context=...

ko0stik avatar Apr 21 '24 09:04 ko0stik

Hi @ko0stik , thanks for raising this. Assertions at the time were experimental and not adapted for TypedPredictors just yet (as per the note on nested patterns here). Will keep this open for patching. Tagging @Shangyint for any additional comments.

arnavsinghvi11 avatar Apr 27 '24 23:04 arnavsinghvi11