def set_ip_adapter_scale(self, scale: Union[float, List[float], List[List[float]]]):
        """
        Set IP-Adapter scales per-transformer block. Input `scale` could be a single config or a list of configs for
        granular control over each IP-Adapter behavior. A config can be a float or a list.

        `float` is converted to list and repeated for the number of blocks and the number of IP adapters. `List[float]`
        length match the number of blocks, it is repeated for each IP adapter. `List[List[float]]` must match the
        number of IP adapters and each must match the number of blocks.

        Example:

        ```py
        # To use original IP-Adapter
        scale = 1.0
        pipeline.set_ip_adapter_scale(scale)


        def LinearStrengthModel(start, finish, size):
            return [(start + (finish - start) * (i / (size - 1))) for i in range(size)]


        ip_strengths = LinearStrengthModel(0.3, 0.92, 19)
        pipeline.set_ip_adapter_scale(ip_strengths)
        ```
        """

        scale_type = Union[int, float]
        num_ip_adapters = self.transformer.encoder_hid_proj.num_ip_adapters
        num_layers = self.transformer.config.num_layers

        # Single value for all layers of all IP-Adapters
        if isinstance(scale, scale_type):
            scale = [scale for _ in range(num_ip_adapters)]
        # List of per-layer scales for a single IP-Adapter
        elif _is_valid_type(scale, List[scale_type]) and num_ip_adapters == 1:
            scale = [scale]
        # Invalid scale type
        elif not _is_valid_type(scale, List[Union[scale_type, List[scale_type]]]):
            raise TypeError(f"Unexpected type {_get_detailed_type(scale)} for scale.")

        if len(scale) != num_ip_adapters:
            raise ValueError(f"Cannot assign {len(scale)} scales to {num_ip_adapters} IP-Adapters.")

        if any(len(s) != num_layers for s in scale if isinstance(s, list)):
            invalid_scale_sizes = {len(s) for s in scale if isinstance(s, list)} - {num_layers}
            raise ValueError(
                f"Expected list of {num_layers} scales, got {', '.join(str(x) for x in invalid_scale_sizes)}."
            )

        # Scalars are transformed to lists with length num_layers
        scale_configs = [[s] * num_layers if isinstance(s, scale_type) else s for s in scale]

        # Set scales. zip over scale_configs prevents going into single transformer layers
        for attn_processor, *scale in zip(self.transformer.attn_processors.values(), *scale_configs):
            attn_processor.scale = scale

        Set IP-Adapter scales per-transformer block. Input `scale` could be a single config or a list of configs for
        granular control over each IP-Adapter behavior. A config can be a float or a list.

        `float` is converted to list and repeated for the number of blocks and the number of IP adapters. `List[float]`
        length match the number of blocks, it is repeated for each IP adapter. `List[List[float]]` must match the
        number of IP adapters and each must match the number of blocks.

        Example:

        ```py
        # To use original IP-Adapter
        scale = 1.0
        pipeline.set_ip_adapter_scale(scale)


        def LinearStrengthModel(start, finish, size):
            return [(start + (finish - start) * (i / (size - 1))) for i in range(size)]


        ip_strengths = LinearStrengthModel(0.3, 0.92, 19)
        pipeline.set_ip_adapter_scale(ip_strengths)
        ```
        
src/diffusers/loaders/ip_adapter.py