container#

Container component for composing multiple components, such as Sequential.

Classes

Sequential()

A sequential container.

class Sequential(*args: Component)[source]#
class Sequential(arg: OrderedDict[str, Component])

Bases: Component

A sequential container.

Adapted from PyTorch’s nn.Sequential.

Components will be added to it in the order they are passed to the constructor. Alternatively, an OrderedDict of components can be passed in. It “chains” outputs of the previous component to the input of the next component sequentially. Output of the previous component is input to the next component as positional argument.

Benefits of using Sequential: 1. Convenient for data pipeline that often consists of multiple components. This allow users to encapsulate the pipeline in a single component. Examples:

Without Sequential:

class AddAB(Component):
    def call(self, a: int, b: int) -> int:
        return a + b


class MultiplyByTwo(Component):
    def call(self, input: int) -> int:
        return input * 2

class DivideByThree(Component):
    def call(self, input: int) -> int:
        return input / 3

# Manually chaining the components
add_a_b = AddAB()
multiply_by_two = MultiplyByTwo()
divide_by_three = DivideByThree()

result = divide_by_three(multiply_by_two(add_a_b(2, 3)))

With Sequential:

seq = Sequential(AddAB(), MultiplyByTwo(), DivideByThree())
result = seq(2, 3)

Note

Only the first component can receive arbitrary positional and keyword arguments. The rest of the components should have a single positional argument as input and have it to be exactly the same type as the output of the previous component.

2. Apply a transformation or operation (like training, evaluation, or serialization) to the Sequential object, it automatically applies that operation to each component it contains. This can be useful for In-context learning training.

Examples:

  1. Use positional arguments:
    >>> seq = Sequential(component1, component2)
    
  2. Add components:
    >>> seq.append(component4)
    
  3. Get a component:
    >>> seq[0]
    
  4. Delete a component:
    >>> del seq[0]
    
  5. Iterate over components:
    >>> for component in seq:
    >>>     print(component)
    
  6. Add two Sequentials:
    >>> seq1 = Sequential(component1, component2)
    >>> seq2 = Sequential(component3, component4)
    >>> seq3 = seq1 + seq2
    
  7. Use OrderedDict:
    >>> seq = Sequential(OrderedDict({"component1": component1, "component2": component2}))
    
  8. Index OrderDict:
    >>> seq = Sequential(OrderedDict({"component1": component1, "component2": component2}))
    >>> seq["component1"]
    # or
    >>> seq[0]
    
  9. Call with a single argument as input:
    >>> seq = Sequential(component1, component2)
    >>> result = seq.call(2)
    
  10. Call with multiple arguments as input: >>> seq = Sequential(component1, component2) >>> result = seq.call(2, 3)

call(input: Any) object[source]#
call(*args: Any, **kwargs: Any) object
async acall(input: Any) object[source]#
async acall(*args: Any, **kwargs: Any) object

When you for loop or multiple await calls inside each component, use acall method can potentially speed up the execution.

append(component: Component) Sequential[source]#

Appends a component to the end of the Sequential.

insert(idx: int, component: Component) None[source]#

Inserts a component at a given index in the Sequential.

extend(components: Iterable[Component]) Sequential[source]#

Extends the Sequential with components from an iterable.