Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
185ada5
Validator Proxy Response Update (#103)
dylanuys Nov 20, 2024
132dc62
Two new image models: SDXL finetuned on Midjourney, and SD finetuned …
aliang322 Nov 20, 2024
7f8a26a
Added required StableDiffusionPipeline import
aliang322 Nov 20, 2024
ec35faf
Merge pull request #105 from BitMind-AI/expand-models/image-finetuned
aliang322 Nov 21, 2024
c98c08f
Updated transformers version to fix tokenizer initialization error
benliang99 Nov 22, 2024
b3d0a57
Merge pull request #107 from BitMind-AI/transformers-version-update
aliang322 Nov 22, 2024
f2cefdd
GPU Specification (#108)
dylanuys Nov 24, 2024
3097718
Update __init__.py
dylanuys Nov 24, 2024
686fbf7
pulling in latest from main
dylanuys Nov 24, 2024
6060c65
removing logging
benliang99 Nov 24, 2024
5c00f9e
old logging removed
benliang99 Nov 25, 2024
fe9fa6d
adding check for state file in case it is deleted somehow
dylanuys Nov 25, 2024
343b1d6
Merge branch 'testnet' of github.com:BitMind-AI/bitmind-subnet into t…
dylanuys Nov 25, 2024
14a32c3
removing remaining random prompt generation code
benliang99 Nov 25, 2024
a4032dc
Merge branch 'main' into testnet
dylanuys Nov 27, 2024
3866df2
Merge branch 'main' into testnet
dylanuys Dec 2, 2024
4678efa
[Testnet] Video Challenges V1 (#111)
dylanuys Dec 3, 2024
d35af29
fixing image_size for augmentations
dylanuys Dec 3, 2024
3e23a4a
Updated validator gpu requirements (#113)
benliang99 Dec 3, 2024
912c8ab
splitting rewards over image and video (#112)
dylanuys Dec 3, 2024
d22a250
Update README.md (#110)
kenobijon Dec 3, 2024
92dafa4
combining requirements files
dylanuys Dec 3, 2024
fe84b1a
Merge branch 'testnet' of github.com:BitMind-AI/bitmind-subnet into t…
dylanuys Dec 3, 2024
d46694c
Combined requirements installation
benliang99 Dec 3, 2024
3e5c2e2
Improved formatting, added checks to prevent overwriting existing .en…
benliang99 Dec 3, 2024
485f095
Merge pull request #115 from BitMind-AI/combined-requirements
aliang322 Dec 3, 2024
f3edacc
Re-added endpoint options
benliang99 Dec 3, 2024
80a0773
Fixed incorrect diffusers install
benliang99 Dec 4, 2024
f907031
Fixed missing initialization of miner performance trackers
benliang99 Dec 4, 2024
e115a52
Merge pull request #117 from BitMind-AI/video-uat-fixes
aliang322 Dec 4, 2024
0feab36
[Testnet] Docs Updates (#114)
dylanuys Dec 4, 2024
d7c4a1f
Removed deprecated requirements files from github tests (#118)
benliang99 Dec 4, 2024
00a591d
[Testnet] Async Cache Updates (#119)
dylanuys Dec 4, 2024
ae2904f
Increased minimum and recommended storage (#120)
benliang99 Dec 4, 2024
235c483
[Testnet] Data download cleanup (#121)
dylanuys Dec 4, 2024
43f8b71
pep8
dylanuys Dec 4, 2024
9c7e6b3
use png codec, sample by framerate + num frames
dylanuys Dec 4, 2024
979bc86
fps, min_fps, max_fps parameterization of sample
dylanuys Dec 4, 2024
9d5fbb2
return fps and num frames
dylanuys Dec 4, 2024
3add4a8
Merge pull request #122 from BitMind-AI/variable-framerate-sampling
aliang322 Dec 4, 2024
7870207
Fix registry module imports (#123)
dylanuys Dec 5, 2024
571c4c6
Update README.md
dylanuys Dec 5, 2024
0b455a3
README title
dylanuys Dec 5, 2024
ac9f495
removing samples from cache
dylanuys Dec 5, 2024
391b3af
README
dylanuys Dec 5, 2024
e9f47ce
fixing cache removal (#125)
dylanuys Dec 5, 2024
c5c7cde
Fixed tensor not being set to device for video challenges, causing er…
aliang322 Dec 5, 2024
fd5b640
Mainnet Prep (#127)
dylanuys Dec 5, 2024
36b3721
removign old reqs from autoupdate
dylanuys Dec 5, 2024
b772db0
Re-added bitmind HF org prefix to dataset path
benliang99 Dec 5, 2024
dbf1114
Merge pull request #128 from BitMind-AI/open-images-path-fix
aliang322 Dec 5, 2024
93fb6aa
shortening self heal timer
dylanuys Dec 5, 2024
5f849c6
autoupdate
dylanuys Dec 5, 2024
94d2eeb
autoupdate
dylanuys Dec 5, 2024
ec3a8f7
sample size
dylanuys Dec 5, 2024
1a07c68
pulling in hotfix from main
dylanuys Dec 6, 2024
5acb1af
Merge branch 'main' into testnet
dylanuys Dec 10, 2024
2416dbd
Validator Improvements: VRAM usage, logging (#131)
dylanuys Dec 11, 2024
c2cb1c5
version bump
dylanuys Dec 11, 2024
7e527ea
moved info log setting to config.py
dylanuys Dec 11, 2024
649e29a
Merge branch 'main' into testnet
dylanuys Dec 17, 2024
e47c49d
Bittensor 8.5.1 (#133)
dylanuys Dec 18, 2024
ef8e129
Prompt Generation Pipeline Improvements (#135)
dylanuys Jan 5, 2025
3507bad
[testnet] I2i/in painting (#137)
dylanuys Jan 7, 2025
eb73189
Updated image_annotation_generator to prompt_generator (#138)
aliang322 Jan 8, 2025
93e7fc9
bump version 2.0.3 -> 2.1.0
dylanuys Jan 8, 2025
ab0aac8
testing cache clearing via autoupdate
dylanuys Jan 8, 2025
49261cf
Merge branch 'testnet' of github.com:BitMind-AI/bitmind-subnet into t…
dylanuys Jan 8, 2025
7fda1bc
cranking up video rewards to .2
dylanuys Jan 8, 2025
47cfe4e
Merge branch 'main' into testnet
dylanuys Jan 8, 2025
dd30c8a
Add DeepFloyd/IF model and multi-stage pipeline support
aliang322 Jan 10, 2025
941b3ec
Moved multistage pipeline generator to SyntheticDataGenerator
aliang322 Jan 10, 2025
927e932
Args for testing specific model
aliang322 Jan 10, 2025
15e5ffe
[TESTNET] HunyuanVideo (#140)
dylanuys Jan 23, 2025
19850af
merging main
dylanuys Jan 23, 2025
aa88c87
Update __init__.py
dylanuys Jan 23, 2025
304f8f4
updated subnet arch diagram
dylanuys Jan 25, 2025
d9cec1e
README wip
dylanuys Jan 25, 2025
dc2ba6a
docs udpates
dylanuys Jan 25, 2025
10c6c55
README updates
dylanuys Jan 25, 2025
25bb436
README updates
dylanuys Jan 25, 2025
f6d6e0e
more README udpates
dylanuys Jan 25, 2025
da32df2
README updates
dylanuys Jan 25, 2025
3f94567
README udpates
dylanuys Jan 25, 2025
b7a9427
README cleanup
dylanuys Jan 25, 2025
c59e36b
more README updates
dylanuys Jan 25, 2025
bc82324
Fixing table border removal html for github
dylanuys Jan 25, 2025
6815dba
fixing table html
dylanuys Jan 25, 2025
a136012
one last attempt at a prettier table
dylanuys Jan 25, 2025
2c683e8
one last last attempt at a prettier table
dylanuys Jan 25, 2025
7a5d94c
bumping video rewards
dylanuys Jan 25, 2025
79cf10d
removing decay for unsampled miners
dylanuys Jan 26, 2025
6a03333
README cleanup
dylanuys Jan 26, 2025
a6e0ee9
increasing suggested and min compute for validators
dylanuys Jan 27, 2025
655bc2b
README update, markdown fix in Incentive.md
dylanuys Jan 27, 2025
4cb3bd6
README tweak
dylanuys Jan 27, 2025
d84b4cc
removing redundant dereg check from update_scores
dylanuys Jan 27, 2025
4550958
Deepfloyed specific configs, args for better cache/data gen testing, …
aliang322 Jan 28, 2025
ae11857
Merge testnet into t2i/deepfloyed-if
aliang322 Jan 28, 2025
4f24e5b
use largest deepfloyed-if I and II models, ensure no watermarker
aliang322 Jan 30, 2025
b930fbf
Fixed FLUX resolution format, added back model_id and scheduler loadi…
aliang322 Jan 30, 2025
5f7d139
Add Janus-Pro-7B t2i model with custom diffuser pipeline class
aliang322 Jan 30, 2025
7dbc0c7
Janus repo install
aliang322 Jan 30, 2025
bbceeca
Removed custom wrapper files, added Janus DiffusionPipeline wrapper t…
aliang322 Jan 30, 2025
4ac1a4e
Removed DiffusionPipeline import
aliang322 Jan 30, 2025
655e1f5
Uncomment wandb inits
aliang322 Jan 30, 2025
098a4b1
Move create_pipeline_generator() to model utils
aliang322 Feb 3, 2025
4dd1c79
Moved model optimizations to model utils
aliang322 Feb 3, 2025
1e0bbc3
Merge pull request #147 from BitMind-AI/t2i/deepfloyed-if-and-janus-pro
aliang322 Feb 3, 2025
c7a23dd
[Testnet] Mutli-Video Challenges (#148)
dylanuys Feb 6, 2025
5a64f22
merging main
dylanuys Feb 6, 2025
cbce647
Update config.py
dylanuys Feb 6, 2025
a7561fa
explicit requirements install
dylanuys Feb 6, 2025
f172cbb
moving pm2 process stopping prior to model verification
dylanuys Feb 7, 2025
6eb5352
fix for no available vidoes in multi-video challenge generation
dylanuys Feb 7, 2025
1ea4f7c
Update forward.py
dylanuys Feb 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bitmind/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# DEALINGS IN THE SOFTWARE.


__version__ = "2.1.3"
__version__ = "2.1.4"
version_split = __version__.split(".")
__spec_version__ = (
(1000 * int(version_split[0]))
Expand Down
18 changes: 9 additions & 9 deletions bitmind/synthetic_data_generation/image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,35 +75,35 @@ def create_random_mask(size: Tuple[int, int]) -> Image.Image:
height = np.random.randint(h//4, h//2)

# Center the rectangle with some random offset
x1 = (w - width) // 2 + np.random.randint(-width//4, width//4)
y1 = (h - height) // 2 + np.random.randint(-height//4, height//4)
x = (w - width) // 2 + np.random.randint(-width//4, width//4)
y = (h - height) // 2 + np.random.randint(-height//4, height//4)

# Create mask with PIL draw for smoother edges
draw = ImageDraw.Draw(mask)
draw.rounded_rectangle(
[x1, y1, x1 + width, y1 + height],
[x, y, x + width, y + height],
radius=min(width, height) // 10, # Smooth corners
fill='white'
)
else:
# Circular mask with feathered edges
draw = ImageDraw.Draw(mask)
center_x = w//2
center_y = h//2
x = w//2
y = h//2

# Make radius proportional to image size
radius = min(w, h) // 4

# Add small random offset to center
center_x += np.random.randint(-radius//4, radius//4)
center_y += np.random.randint(-radius//4, radius//4)
x += np.random.randint(-radius//4, radius//4)
y += np.random.randint(-radius//4, radius//4)

# Draw multiple circles with decreasing opacity for feathered edge
for r in range(radius, radius-10, -1):
opacity = int(255 * (r - (radius-10)) / 10)
draw.ellipse(
[center_x-r, center_y-r, center_x+r, center_y+r],
[x-r, y-r, x+r, y+r],
fill=(255, 255, 255, opacity)
)

return mask
return mask, (x, y)
3 changes: 1 addition & 2 deletions bitmind/synthetic_data_generation/prompt_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,7 @@ def generate(
description += '.'

moderated_description = self.moderate(description)
enhanced_description = self.enhance(description)
return enhanced_description
return self.enhance(moderated_description)

def moderate(self, description: str, max_new_tokens: int = 80) -> str:
"""
Expand Down
27 changes: 15 additions & 12 deletions bitmind/synthetic_data_generation/prompt_utils.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@


def get_tokenizer_with_min_len(model):
"""
Returns the tokenizer with the smallest maximum token length from the 't2vis_model` object.

If a second tokenizer exists, it compares both and returns the one with the smaller
maximum token length. Otherwise, it returns the available tokenizer.
Returns the tokenizer with the smallest maximum token length.

Args:
model: Single pipeline or dict of pipeline stages.

Returns:
tuple: A tuple containing the tokenizer and its maximum token length.
tuple: (tokenizer, max_token_length)
"""
# Check if a second tokenizer is available in the t2vis_model
if hasattr(model, 'tokenizer_2'):
if model.tokenizer.model_max_length > model.tokenizer_2.model_max_length:
return model.tokenizer_2, model.tokenizer_2.model_max_length
return model.tokenizer, model.tokenizer.model_max_length
# Get the model to check for tokenizers
pipeline = model['stage1'] if isinstance(model, dict) else model

# If model has two tokenizers, return the one with smaller max length
if hasattr(pipeline, 'tokenizer_2'):
len_1 = pipeline.tokenizer.model_max_length
len_2 = pipeline.tokenizer_2.model_max_length
return (pipeline.tokenizer_2, len_2) if len_2 < len_1 else (pipeline.tokenizer, len_1)

return pipeline.tokenizer, pipeline.tokenizer.model_max_length


def truncate_prompt_if_too_long(prompt: str, model):
Expand Down
181 changes: 101 additions & 80 deletions bitmind/synthetic_data_generation/synthetic_data_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
from bitmind.synthetic_data_generation.prompt_utils import truncate_prompt_if_too_long
from bitmind.synthetic_data_generation.prompt_generator import PromptGenerator
from bitmind.validator.cache import ImageCache
from bitmind.validator.model_utils import (
load_hunyuanvideo_transformer,
load_annimatediff_motion_adapter,
JanusWrapper,
create_pipeline_generator,
enable_model_optimizations
)


future_warning_modules_to_ignore = [
Expand Down Expand Up @@ -135,24 +142,30 @@ def batch_generate(self, batch_size: int = 5) -> None:
prompts = []
images = []
bt.logging.info(f"Generating {batch_size} prompts")

# Generate all prompts first
for i in range(batch_size):
image_sample = self.image_cache.sample()
images.append(image_sample['image'])
bt.logging.info(f"Sampled image {i+1}/{batch_size} for captioning: {image_sample['path']}")
prompts.append(self.generate_prompt(image=image_sample['image'], clear_gpu=i==batch_size-1))
bt.logging.info(f"Caption {i+1}/{batch_size} generated: {prompts[-1]}")

# shuffle and interleave models to add stochasticity to initial validator challenges
i2i_model_names = random.sample(I2I_MODEL_NAMES, len(I2I_MODEL_NAMES))
t2i_model_names = random.sample(T2I_MODEL_NAMES, len(T2I_MODEL_NAMES))
t2v_model_names = random.sample(T2V_MODEL_NAMES, len(T2V_MODEL_NAMES))
model_names_interleaved = [
m for triple in zip_longest(t2v_model_names, t2i_model_names, i2i_model_names)
for m in triple if m is not None
]

# for each model, generate an image/video from the prompt generated for its specific tokenizer max len
for model_name in model_names_interleaved:

# If specific model is set, use only that model
if not self.use_random_model and self.model_name:
model_names = [self.model_name]
else:
# shuffle and interleave models to add stochasticity
i2i_model_names = random.sample(I2I_MODEL_NAMES, len(I2I_MODEL_NAMES))
t2i_model_names = random.sample(T2I_MODEL_NAMES, len(T2I_MODEL_NAMES))
t2v_model_names = random.sample(T2V_MODEL_NAMES, len(T2V_MODEL_NAMES))
model_names = [
m for triple in zip_longest(t2v_model_names, t2i_model_names, i2i_model_names)
for m in triple if m is not None
]

# Generate for each model/prompt combination
for model_name in model_names:
modality = get_modality(model_name)
task = get_task(model_name)
for i, prompt in enumerate(prompts):
Expand Down Expand Up @@ -232,7 +245,6 @@ def _run_generation(
model_name: Optional[str] = None,
image: Optional[Image.Image] = None,
generate_at_target_size: bool = False,

) -> Dict[str, Any]:
"""
Generate synthetic data based on a text prompt.
Expand All @@ -256,6 +268,7 @@ def _run_generation(

bt.logging.info("Preparing generation arguments")
gen_args = model_config.get('generate_args', {}).copy()
mask_center = None

# prep inpainting-specific generation args
if task == 'i2i':
Expand All @@ -264,7 +277,7 @@ def _run_generation(
if image.size[0] > target_size[0] or image.size[1] > target_size[1]:
image = image.resize(target_size, Image.Resampling.LANCZOS)

gen_args['mask_image'] = create_random_mask(image.size)
gen_args['mask_image'], mask_center = create_random_mask(image.size)
gen_args['image'] = image

# Prepare generation arguments
Expand All @@ -284,28 +297,24 @@ def _run_generation(
gen_args['width'] = gen_args['resolution'][1]
del gen_args['resolution']

truncated_prompt = truncate_prompt_if_too_long(
prompt,
self.model
)

truncated_prompt = truncate_prompt_if_too_long(prompt, self.model)
bt.logging.info(f"Generating media from prompt: {truncated_prompt}")
bt.logging.info(f"Generation args: {gen_args}")

start_time = time.time()

# Create pipeline-specific generator
generate = create_pipeline_generator(model_config, self.model)

# Handle autocast if needed
if model_config.get('use_autocast', True):
pretrained_args = model_config.get('from_pretrained_args', {})
torch_dtype = pretrained_args.get('torch_dtype', torch.bfloat16)
with torch.autocast(self.device, torch_dtype, cache_enabled=False):
gen_output = self.model(
prompt=truncated_prompt,
**gen_args
)
with torch.autocast(self.device, torch_dtype, cache_enabled=False):
gen_output = generate(truncated_prompt, **gen_args)
else:
gen_output = self.model(
prompt=truncated_prompt,
**gen_args
)
gen_output = generate(truncated_prompt, **gen_args)

gen_time = time.time() - start_time

except Exception as e:
Expand Down Expand Up @@ -338,78 +347,90 @@ def _run_generation(
'model_name': self.model_name,
'gen_time': gen_time,
'mask_image': gen_args.get('mask_image', None),
'mask_center': mask_center,
'image': gen_args.get('image', None)
}

def load_model(self, model_name: Optional[str] = None, modality: Optional[str] = None) -> None:
"""Load a Hugging Face text-to-image or text-to-video model to a specific GPU."""
"""Load a Hugging Face text-to-image or text-to-video model."""
if model_name is not None:
self.model_name = model_name
elif self.use_random_model or model_name == 'random':
model_name = select_random_model(modality)
self.model_name = model_name
self.model_name = select_random_model(modality)

bt.logging.info(f"Loading {self.model_name}")

model_config = MODELS[self.model_name]
pipeline_cls = model_config['pipeline_cls']
pipeline_args = model_config['from_pretrained_args'].copy()

pipeline_cls = MODELS[model_name]['pipeline_cls']
pipeline_args = MODELS[model_name]['from_pretrained_args']
# Handle custom loading functions passed as tuples
for k, v in pipeline_args.items():
if isinstance(v, tuple) and callable(v[0]):
pipeline_args[k] = v[0](**v[1])

if 'model_id' in pipeline_args:
model_id = pipeline_args['model_id']
del pipeline_args['model_id']
else:
model_id = model_name
# Get model_id if specified, otherwise use model_name
model_id = pipeline_args.pop('model_id', self.model_name)

# Handle multi-stage pipeline
if isinstance(pipeline_cls, dict):
self.model = {}
for stage_name, stage_cls in pipeline_cls.items():
stage_args = pipeline_args.get(stage_name, {})
base_model = stage_args.get('base', model_id)
stage_args_filtered = {k:v for k,v in stage_args.items() if k != 'base'}

bt.logging.info(f"Loading {stage_name} from {base_model}")
self.model[stage_name] = stage_cls.from_pretrained(
base_model,
cache_dir=HUGGINGFACE_CACHE_DIR,
**stage_args_filtered,
add_watermarker=False
)

enable_model_optimizations(
model=self.model[stage_name],
device=self.device,
enable_cpu_offload=model_config.get('enable_model_cpu_offload', False),
enable_sequential_cpu_offload=model_config.get('enable_sequential_cpu_offload', False),
enable_vae_slicing=model_config.get('vae_enable_slicing', False),
enable_vae_tiling=model_config.get('vae_enable_tiling', False),
stage_name=stage_name
)

self.model = pipeline_cls.from_pretrained(
model_id,
cache_dir=HUGGINGFACE_CACHE_DIR,
**pipeline_args,
add_watermarker=False
)
# Disable watermarker
self.model[stage_name].watermarker = None
else:
# Single-stage pipeline
self.model = pipeline_cls.from_pretrained(
model_id,
cache_dir=HUGGINGFACE_CACHE_DIR,
**pipeline_args,
add_watermarker=False
)

self.model.set_progress_bar_config(disable=True)
# Load scheduler if specified
if 'scheduler' in model_config:
sched_cls = model_config['scheduler']['cls']
sched_args = model_config['scheduler']['from_config_args']
self.model.scheduler = sched_cls.from_config(
self.model.scheduler.config,
**sched_args
)

# Load scheduler if specified
if 'scheduler' in MODELS[model_name]:
sched_cls = MODELS[model_name]['scheduler']['cls']
sched_args = MODELS[model_name]['scheduler']['from_config_args']
self.model.scheduler = sched_cls.from_config(
self.model.scheduler.config,
**sched_args
enable_model_optimizations(
model=self.model,
device=self.device,
enable_cpu_offload=model_config.get('enable_model_cpu_offload', False),
enable_sequential_cpu_offload=model_config.get('enable_sequential_cpu_offload', False),
enable_vae_slicing=model_config.get('vae_enable_slicing', False),
enable_vae_tiling=model_config.get('vae_enable_tiling', False)
)

# Configure model optimizations
model_config = MODELS[model_name]
if model_config.get('enable_model_cpu_offload', False):
bt.logging.info(f"Enabling cpu offload for {model_name}")
self.model.enable_model_cpu_offload()
if model_config.get('enable_sequential_cpu_offload', False):
bt.logging.info(f"Enabling sequential cpu offload for {model_name}")
self.model.enable_sequential_cpu_offload()
if model_config.get('vae_enable_slicing', False):
bt.logging.info(f"Enabling vae slicing for {model_name}")
try:
self.model.vae.enable_slicing()
except Exception:
try:
self.model.enable_vae_slicing()
except Exception:
bt.logging.warning(f"Could not enable vae slicing for {self.model}")
if model_config.get('vae_enable_tiling', False):
bt.logging.info(f"Enabling vae tiling for {model_name}")
try:
self.model.vae.enable_tiling()
except Exception:
try:
self.model.enable_vae_tiling()
except Exception:
bt.logging.warning(f"Could not enable vae tiling for {self.model}")
# Disable watermarker
self.model.watermarker = None

self.model.to(self.device)
bt.logging.info(f"Loaded {model_name} using {pipeline_cls.__name__}.")
bt.logging.info(f"Loaded {self.model_name}")

def clear_gpu(self) -> None:
"""Clear GPU memory by deleting models and running garbage collection."""
Expand Down
Loading