⚡️ Speed up method T2IAdapterInvocation.validate_ip_adapter_weight by 103%
#131
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
📄 103% (1.03x) speedup for
T2IAdapterInvocation.validate_ip_adapter_weightininvokeai/app/invocations/t2i_adapter.py⏱️ Runtime :
451 microseconds→223 microseconds(best of250runs)📝 Explanation and details
The optimization replaces an
any()generator expression withmin()andmax()operations for range validation.Key Change: Instead of iterating through each weight value with
any(i < -1 or i > 2 for i in to_validate), the optimized version usesif min(to_validate) < -1 or max(to_validate) > 2:to check bounds.Why This is Faster:
minandmax) regardless of list size.min/maxare implemented in C and are highly optimized for numerical operations.min/maxcan still exit early in many cases.if to_validate:to avoid callingmin/maxon empty lists, which provides a 75% speedup for empty lists.Performance Characteristics:
min/maxoperationsmaxImpact on Workloads: This validation function is used in T2I-Adapter weight validation during model setup, so the optimization will improve initialization performance, especially when using multiple adapters or large weight arrays.
✅ Correctness verification report:
🌀 Generated Regression Tests and Runtime
from typing import Union
imports
import pytest
from invokeai.app.invocations.t2i_adapter import T2IAdapterInvocation
------------------------
Unit Tests for T2IAdapterInvocation.validate_ip_adapter_weight
------------------------
1. Basic Test Cases
def test_single_valid_float_middle_range():
# Test a single float within the valid range
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(1.0) # 1.62μs -> 1.49μs (8.38% faster)
def test_single_valid_float_lower_bound():
# Test a single float at the lower bound
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(-1.0) # 1.54μs -> 1.32μs (16.4% faster)
def test_single_valid_float_upper_bound():
# Test a single float at the upper bound
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(2.0) # 1.43μs -> 1.29μs (11.3% faster)
def test_list_of_valid_floats():
# Test a list of valid floats within the range
weights = [0.0, 1.0, 1.5, -0.5, 2.0, -1.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.94μs -> 1.44μs (34.9% faster)
def test_list_with_one_value():
# Test a list with a single valid value
weights = [1.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.34μs -> 1.22μs (9.75% faster)
2. Edge Test Cases
def test_single_float_below_lower_bound():
# Test a single float just below the lower bound
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(-1.0001) # 2.20μs -> 1.60μs (37.7% faster)
def test_single_float_above_upper_bound():
# Test a single float just above the upper bound
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(2.0001) # 2.13μs -> 1.82μs (17.1% faster)
def test_list_with_value_below_lower_bound():
# Test a list where one value is below the lower bound
weights = [0.0, -1.1, 1.0]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.27μs -> 1.60μs (41.5% faster)
def test_list_with_value_above_upper_bound():
# Test a list where one value is above the upper bound
weights = [1.0, 2.1, 0.0]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.18μs -> 1.96μs (11.2% faster)
def test_list_with_multiple_invalid_values():
# Test a list with multiple invalid values (both below and above)
weights = [-1.5, 2.5, 0.0]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.00μs -> 1.55μs (28.6% faster)
def test_list_with_all_invalid_values():
# Test a list where all values are invalid
weights = [-2.0, 3.0, 2.5]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.90μs -> 1.56μs (22.0% faster)
def test_empty_list():
# Test an empty list (should not raise, as there are no invalid values)
weights = []
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.20μs -> 684ns (74.9% faster)
def test_list_with_nan():
# Test a list containing NaN (should not raise ValueError, but could be a hidden bug)
import math
weights = [0.0, math.nan]
# math.nan is not < -1 or > 2, so should not raise, but let's check behavior
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.67μs -> 1.35μs (23.5% faster)
def test_list_with_inf():
# Test a list containing inf (should raise ValueError)
import math
weights = [0.0, math.inf]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.20μs -> 1.85μs (19.0% faster)
def test_list_with_negative_inf():
# Test a list containing -inf (should raise ValueError)
import math
weights = [0.0, -math.inf]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.24μs -> 1.54μs (45.5% faster)
def test_non_numeric_input():
# Test a string input (should raise TypeError)
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight("not a number") # 2.82μs -> 2.37μs (18.7% faster)
def test_list_with_non_numeric():
# Test a list containing a non-numeric value (should raise TypeError)
weights = [1.0, "bad"]
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.83μs -> 2.32μs (21.8% faster)
def test_list_with_none():
# Test a list containing None (should raise TypeError)
weights = [1.0, None]
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.73μs -> 2.22μs (22.6% faster)
def test_none_input():
# Test None as input (should raise TypeError)
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight(None) # 2.38μs -> 2.16μs (9.94% faster)
3. Large Scale Test Cases
def test_large_list_all_valid():
# Test a large list (1000 elements) all valid
weights = [1.0 for _ in range(1000)]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.5μs -> 13.6μs (205% faster)
def test_large_list_one_invalid_at_start():
# Test a large list (1000 elements) with first element invalid
weights = [-1.1] + [1.0 for _ in range(999)]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.13μs -> 7.76μs (72.5% slower)
def test_large_list_one_invalid_at_end():
# Test a large list (1000 elements) with last element invalid
weights = [1.0 for _ in range(999)] + [2.1]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 42.1μs -> 14.1μs (198% faster)
def test_large_list_one_invalid_in_middle():
# Test a large list (1000 elements) with one invalid value in the middle
weights = [1.0 for _ in range(500)] + [-2.0] + [1.0 for _ in range(499)]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 22.3μs -> 7.82μs (185% faster)
def test_large_list_all_invalid():
# Test a large list (1000 elements) all invalid
weights = [3.0 for _ in range(1000)]
with pytest.raises(ValueError, match="Control weights must be within -1 to 2 range"):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.08μs -> 14.0μs (85.1% slower)
def test_large_list_all_at_lower_bound():
# Test a large list (1000 elements) all at lower bound
weights = [-1.0 for _ in range(1000)]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.5μs -> 13.6μs (205% faster)
def test_large_list_all_at_upper_bound():
# Test a large list (1000 elements) all at upper bound
weights = [2.0 for _ in range(1000)]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.4μs -> 13.5μs (208% faster)
def test_large_list_mixed_valid():
# Test a large list (1000 elements) with values at lower, upper, and mid-range
weights = [-1.0, 0.0, 1.0, 2.0] * 250 # 1000 elements
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.1μs -> 13.6μs (203% faster)
codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from typing import Union
imports
import pytest
from invokeai.app.invocations.t2i_adapter import T2IAdapterInvocation
unit tests
-------------------------
1. Basic Test Cases
-------------------------
def test_single_valid_weight_middle():
# Test with a single valid float in the middle of the range
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(0.5) # 2.06μs -> 1.76μs (17.1% faster)
def test_single_valid_weight_lower_bound():
# Test with a single valid float at the lower bound
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(-1.0) # 1.65μs -> 1.42μs (16.3% faster)
def test_single_valid_weight_upper_bound():
# Test with a single valid float at the upper bound
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(2.0) # 1.56μs -> 1.35μs (15.6% faster)
def test_list_valid_weights_various():
# Test with a list of valid weights within range
weights = [0.0, 1.0, -0.5, 2.0, -1.0, 1.5]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.91μs -> 1.52μs (25.7% faster)
def test_list_valid_weights_all_zeros():
# Test with a list of zeros
weights = [0.0, 0.0, 0.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.56μs -> 1.31μs (19.4% faster)
-------------------------
2. Edge Test Cases
-------------------------
def test_single_weight_below_lower_bound():
# Test with a single weight just below the lower bound
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(-1.00001) # 2.23μs -> 1.67μs (33.6% faster)
def test_single_weight_above_upper_bound():
# Test with a single weight just above the upper bound
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(2.00001) # 2.24μs -> 1.85μs (21.1% faster)
def test_list_weight_contains_invalid_low():
# Test with a list containing one invalid (too low) value
weights = [0.0, -1.1, 1.0]
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.26μs -> 1.65μs (37.0% faster)
def test_list_weight_contains_invalid_high():
# Test with a list containing one invalid (too high) value
weights = [0.0, 2.1, 1.0]
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.19μs -> 1.90μs (15.8% faster)
def test_list_weight_multiple_invalid():
# Test with a list containing multiple invalid values (both low and high)
weights = [-2.0, 2.5, 0.0]
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.92μs -> 1.51μs (27.1% faster)
def test_empty_list():
# Test with an empty list (should be valid, as there are no invalid elements)
weights = []
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.16μs -> 661ns (74.9% faster)
def test_non_float_type_string():
# Test with a string input (should raise TypeError)
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight("not_a_float") # 2.86μs -> 2.40μs (19.3% faster)
def test_non_float_type_dict():
# Test with a dict input (should raise TypeError)
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight({'a': 1}) # 2.73μs -> 2.36μs (15.6% faster)
def test_list_with_non_float_element():
# Test with a list containing a non-float element (should raise TypeError)
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight([0.0, "bad", 1.0]) # 2.67μs -> 2.33μs (14.6% faster)
-------------------------
3. Large Scale Test Cases
-------------------------
def test_large_list_all_valid():
# Test with a large list of valid weights (all 1.0)
weights = [1.0] * 999
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.6μs -> 13.7μs (203% faster)
def test_large_list_one_invalid_low():
# Test with a large list where one value is just below the lower bound
weights = [0.5] * 500 + [-1.0001] + [1.5] * 498
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 22.3μs -> 7.79μs (186% faster)
def test_large_list_one_invalid_high():
# Test with a large list where one value is just above the upper bound
weights = [0.5] * 600 + [2.0001] + [1.5] * 398
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 26.2μs -> 14.2μs (84.8% faster)
def test_large_list_edge_values():
# Test with a large list containing only edge values (-1.0 and 2.0)
weights = [-1.0, 2.0] * 499 + [0.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 41.8μs -> 13.5μs (209% faster)
def test_large_list_all_invalid():
# Test with a large list where all values are invalid
weights = [-2.0] * 999
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.98μs -> 7.63μs (74.1% slower)
-------------------------
4. Additional Robustness Tests
-------------------------
def test_list_with_nan():
# Test with a list containing float('nan')
import math
weights = [0.0, float('nan'), 1.0]
# nan is not less than -1 or greater than 2, so it should pass
# But comparing nan with < or > returns False, so this passes unless you want to explicitly catch nan
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.81μs -> 1.40μs (29.0% faster)
def test_list_with_inf():
# Test with a list containing float('inf')
weights = [0.0, float('inf'), 1.0]
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.24μs -> 1.86μs (20.6% faster)
def test_list_with_negative_inf():
# Test with a list containing float('-inf')
weights = [0.0, float('-inf'), 1.0]
with pytest.raises(ValueError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.25μs -> 1.50μs (49.9% faster)
def test_list_with_bool_values():
# Test with a list containing boolean values (should pass, as bool is a subclass of int)
weights = [True, False, 1.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.74μs -> 1.53μs (13.7% faster)
def test_list_with_int_values():
# Test with a list containing int values (should pass, as ints are valid floats)
weights = [0, 1, -1, 2]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.61μs -> 1.36μs (18.4% faster)
def test_single_int_value():
# Test with a single int value
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(1) # 1.48μs -> 1.22μs (21.1% faster)
def test_list_with_mixed_int_and_float():
# Test with a list containing both int and float values
weights = [0, 1.0, -1, 2.0]
codeflash_output = T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 1.69μs -> 1.61μs (5.09% faster)
def test_list_with_none():
# Test with a list containing None (should raise TypeError)
weights = [0.0, None, 1.0]
with pytest.raises(TypeError):
T2IAdapterInvocation.validate_ip_adapter_weight(weights) # 2.92μs -> 2.41μs (21.6% faster)
codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
To edit these changes
git checkout codeflash/optimize-T2IAdapterInvocation.validate_ip_adapter_weight-mhvf8oyaand push.