9.4 KiB
9.4 KiB
tags
| tags | ||
|---|---|---|
|
IPAdapter Weights
Documentation
- Class name:
IPAdapterWeights - Category:
ipadapter/weights - Output node:
False
The IPAdapterWeights node is designed to manage and manipulate weights within the IPAdapter framework, providing a foundational structure for weight strategy implementation and optional image-based adjustments.
Input types
Required
weights- A string of comma or newline-separated values representing the weights to be applied, which can be adjusted based on the strategy.
- Comfy dtype:
STRING - Python dtype:
str
timing- Defines the timing strategy for applying weights, offering various options such as custom, linear, ease_in_out, etc.
- Comfy dtype:
COMBO[STRING] - Python dtype:
str
frames- Specifies the number of frames to which the weights will be applied, influencing the animation or transition effect.
- Comfy dtype:
INT - Python dtype:
int
start_frame- The starting frame from which weight application begins, allowing for precise control over the animation.
- Comfy dtype:
INT - Python dtype:
int
end_frame- The ending frame at which weight application stops, defining the scope of the animation.
- Comfy dtype:
INT - Python dtype:
int
add_starting_frames- Additional frames added at the beginning of the animation, extending the initial state.
- Comfy dtype:
INT - Python dtype:
int
add_ending_frames- Additional frames added at the end of the animation, extending the final state.
- Comfy dtype:
INT - Python dtype:
int
method- The method of applying weights across frames, such as full batch, shift batches, or alternate batches, affecting the animation's flow.
- Comfy dtype:
COMBO[STRING] - Python dtype:
str
Optional
image- An optional parameter that allows for image-based adjustments to weights, enhancing the flexibility and applicability of the weight strategy.
- Comfy dtype:
IMAGE - Python dtype:
torch.Tensor
Output types
weights- Comfy dtype:
FLOAT - The adjusted weights after applying the specified strategy and adjustments.
- Python dtype:
list[float]
- Comfy dtype:
weights_invert- Comfy dtype:
FLOAT - The inverted weights calculated from the original weights, providing an alternative perspective.
- Python dtype:
list[float]
- Comfy dtype:
total_frames- Comfy dtype:
INT - The total number of frames resulting from the applied weights and additional frame adjustments.
- Python dtype:
int
- Comfy dtype:
image_1- Comfy dtype:
IMAGE - The first image in a pair used for certain weight application methods, particularly in batch shifting or alternation.
- Python dtype:
torch.Tensor
- Comfy dtype:
image_2- Comfy dtype:
IMAGE - The second image in a pair used alongside image_1 for specific weight application methods.
- Python dtype:
torch.Tensor
- Comfy dtype:
weights_strategy- Comfy dtype:
WEIGHTS_STRATEGY - The comprehensive strategy used for weight application, including all specified parameters and their effects.
- Python dtype:
dict
- Comfy dtype:
Usage tips
- Infra type:
CPU - Common nodes: unknown
Source code
class IPAdapterWeights:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"weights": ("STRING", {"default": '1.0, 0.0', "multiline": True }),
"timing": (["custom", "linear", "ease_in_out", "ease_in", "ease_out", "random"], { "default": "linear" } ),
"frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"start_frame": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"end_frame": ("INT", {"default": 9999, "min": 0, "max": 9999, "step": 1 }),
"add_starting_frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"add_ending_frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"method": (["full batch", "shift batches", "alternate batches"], { "default": "full batch" }),
}, "optional": {
"image": ("IMAGE",),
}
}
RETURN_TYPES = ("FLOAT", "FLOAT", "INT", "IMAGE", "IMAGE", "WEIGHTS_STRATEGY")
RETURN_NAMES = ("weights", "weights_invert", "total_frames", "image_1", "image_2", "weights_strategy")
FUNCTION = "weights"
CATEGORY = "ipadapter/weights"
def weights(self, weights='', timing='custom', frames=0, start_frame=0, end_frame=9999, add_starting_frames=0, add_ending_frames=0, method='full batch', weights_strategy=None, image=None):
import random
frame_count = image.shape[0] if image is not None else 0
if weights_strategy is not None:
weights = weights_strategy["weights"]
timing = weights_strategy["timing"]
frames = weights_strategy["frames"]
start_frame = weights_strategy["start_frame"]
end_frame = weights_strategy["end_frame"]
add_starting_frames = weights_strategy["add_starting_frames"]
add_ending_frames = weights_strategy["add_ending_frames"]
method = weights_strategy["method"]
frame_count = weights_strategy["frame_count"]
else:
weights_strategy = {
"weights": weights,
"timing": timing,
"frames": frames,
"start_frame": start_frame,
"end_frame": end_frame,
"add_starting_frames": add_starting_frames,
"add_ending_frames": add_ending_frames,
"method": method,
"frame_count": frame_count,
}
# convert the string to a list of floats separated by commas or newlines
weights = weights.replace("\n", ",")
weights = [float(weight) for weight in weights.split(",") if weight.strip() != ""]
if timing != "custom":
frames = max(frames, 2)
start = 0.0
end = 1.0
if len(weights) > 0:
start = weights[0]
end = weights[-1]
weights = []
end_frame = min(end_frame, frames)
duration = end_frame - start_frame
if start_frame > 0:
weights.extend([start] * start_frame)
for i in range(duration):
n = duration - 1
if timing == "linear":
weights.append(start + (end - start) * i / n)
elif timing == "ease_in_out":
weights.append(start + (end - start) * (1 - math.cos(i / n * math.pi)) / 2)
elif timing == "ease_in":
weights.append(start + (end - start) * math.sin(i / n * math.pi / 2))
elif timing == "ease_out":
weights.append(start + (end - start) * (1 - math.cos(i / n * math.pi / 2)))
elif timing == "random":
weights.append(random.uniform(start, end))
weights[-1] = end if timing != "random" else weights[-1]
if end_frame < frames:
weights.extend([end] * (frames - end_frame))
if len(weights) == 0:
weights = [0.0]
frames = len(weights)
# repeat the images for cross fade
image_1 = None
image_2 = None
if image is not None:
if "shift" in method:
image_1 = image[:-1]
image_2 = image[1:]
weights = weights * image_1.shape[0]
image_1 = image_1.repeat_interleave(frames, 0)
image_2 = image_2.repeat_interleave(frames, 0)
elif "alternate" in method:
image_1 = image[::2].repeat_interleave(2, 0)
image_1 = image_1[1:]
image_2 = image[1::2].repeat_interleave(2, 0)
mew_weights = weights + [1.0 - w for w in weights]
mew_weights = mew_weights * (image_1.shape[0] // 2)
if image.shape[0] % 2:
image_1 = image_1[:-1]
else:
image_2 = image_2[:-1]
mew_weights = mew_weights + weights
weights = mew_weights
image_1 = image_1.repeat_interleave(frames, 0)
image_2 = image_2.repeat_interleave(frames, 0)
else:
weights = weights * image.shape[0]
image_1 = image.repeat_interleave(frames, 0)
# add starting and ending frames
if add_starting_frames > 0:
weights = [weights[0]] * add_starting_frames + weights
image_1 = torch.cat([image[:1].repeat(add_starting_frames, 1, 1, 1), image_1], dim=0)
if image_2 is not None:
image_2 = torch.cat([image[:1].repeat(add_starting_frames, 1, 1, 1), image_2], dim=0)
if add_ending_frames > 0:
weights = weights + [weights[-1]] * add_ending_frames
image_1 = torch.cat([image_1, image[-1:].repeat(add_ending_frames, 1, 1, 1)], dim=0)
if image_2 is not None:
image_2 = torch.cat([image_2, image[-1:].repeat(add_ending_frames, 1, 1, 1)], dim=0)
weights_invert = [1.0 - w for w in weights]
return (weights, weights_invert, len(weights), image_1, image_2, weights_strategy,)