arkgpt's picture
Updating app.py
a27f699 verified
Raw
History Blame Contribute Delete
14.7 kB
import torch
import torchvision
import gradio as gr
import pandas as pd
import json
from utils.load_image import load_image
from utils.load_model import load_model
from utils.get_layers import get_layers
from utils.get_image_path import get_image_path
from optimization import ActivationExtractor, optimize_activation_batch
from visualization import comparative_visualization
print("All modules Imported successfully")
sample_images = {
"Pizza": "sample_images/Pizza.jpg",
"Elephant": "sample_images/Elephant.jpg",
"the-leaning-tower": "sample_images/the-leaning-tower.jpg"
}
def update_image(selected_sample):
"""
Update the image input based on the selected sample image.
Args:
selected_sample (str): The name of the selected sample image.
Returns:
dict: A dictionary to update the image input component.
"""
return gr.update(value=sample_images[selected_sample])
def optimize_neural_activation(
image_path:str,
use_real_image=True,
architectures=["resnet50"],
resnet50_layers=None,
vgg16_layers=None,
mobilenet_v2_layers=None,
efficientnet_b0_layers=None,
regularizations = {
'reduction':'mean',
'l2': 0.01,
'tv': 0.02,
'sparsity': 0.01,
'entropy':0.01,
'l1': 0.01,
'linf':0.01,
'feature_map_sparsity':0.01,
'clip': (0.0, 1.0)
},
steps:int=50,
neuron_ids = [2,20,250],
sample_image_select = None,
log_freq: int=10
):
"""
Main optimization loop for gradio interface
Args:
image_path (str): Path to user-uploaded or sample image.
use_real_image (bool): Whether to use a real world image or a random noise.
architectures (str): List of architectures to optimize for from. Can be selected from the list ["resnet50", "vgg16", "mobilenet_v2", "efficientnet_b0".
selected_layers (list): List of specific layers to optimize.
regularizations (dict): regularization weights. Use from the following: 'l2': 0.01,'tv': 0.02,'sparsity': 0.01,'entropy':0.01,'l1': 0.01,'linf':0.01,'feature_map_sparsity':0.01,'clip': (0.0, 1.0)
steps (int): No. of steps of iteration
log_freq (int): Frequency of logging optimization progress.
Returns:
fig: the matplotlib figure object with comparative visualizations.
df: Pandas DataFrame summarizing the results.
"""
selected_layers = {
"resnet50": resnet50_layers or [],
"vgg16": vgg16_layers or [],
"mobilenet_v2": mobilenet_v2_layers or [],
"efficientnet_b0": efficientnet_b0_layers or []
}
layer_dropdowns = {
"resnet50": resnet50_layers or [],
"vgg16": vgg16_layers or [],
"mobilenet_v2": mobilenet_v2_layers or [],
"efficientnet_b0": efficientnet_b0_layers or []
}
if layer_dropdowns:
for arch, layers in layer_dropdowns.items():
print(f"Processing {arch} with selected layers: {layers}")
print(f"Dropdown values for resnet50: {resnet50_layers}")
print(f"Dropdown values for vgg16: {vgg16_layers}")
print(f"Dropdown values for mobilenet_v2: {mobilenet_v2_layers}")
print(f"Dropdown values for efficientnet_b0: {efficientnet_b0_layers}")
results_list = []
summary = []
steps = max(1, int(steps)) # ensuring that steps is a positive integer
try:
if isinstance(neuron_ids,str):
neuron_ids=list(map(int, neuron_ids.split(",")))
except ValueError:
raise ValueError("Invalid ids provided. Please enter a comma-separated list of integers.")
try:
if isinstance(regularizations, str):
regularizations=json.loads(regularizations)
except json.JSONDecodeError:
raise ValueError("Invalid JSON provided for regularizations")
for arch in architectures:
print(f"\n--- Optimizing for Architecture: {arch} ---" )
model = load_model(architecture=arch)
#print(f"Model {arch} loaded successfully: {model}") # for debugging
layers = get_layers(model)
layers_dict = dict(layers)
# Validate user-provided layer names or select the first 3 layers by default
# Filtering ensures that only valid layer names (those present in the model) are processed.
default_layers = {
"resnet50": ["layer1.0.conv1", "layer1.0.conv2", "layer1.0.downsample.1"],
"vgg16": ["features.0", "features.5", "features.10"],
"mobilenet_v2": ["features.0.0", "features.2.0", "features.5.0"],
"efficientnet_b0": ["features.0.0", "features.2.0.block.0.0", "features.4.0.block.0.0"]}
filtered_layers = []
selected_layers = selected_layers or default_layers.get(arch, list(layers_dict.keys())[:3])
for name in selected_layers[arch]:
print(f"name:{name}, selectedLayers:{selected_layers}") #debugging
if name in layers_dict:
filtered_layers.append((name, layers_dict[name]))
else:
raise ValueError(f"Layer {name} not found in the selected architecture. Available layers are {layers_dict.keys()}")
if not filtered_layers:
print(f"No valid layers selected for architecture{arch}. Please select or use default values.")
for layer_name, layer in filtered_layers:
# Initialize a fresh input tensor for each layer by initializing the input inside this for loop
# Problem: If the input tensor is reused across iterations, the optimized input from
# one layer's run affects subsequent runs. This results in:
# - Loss curves starting from a pre-optimized state rather than a random initialization.
# - Incorrect visualizations and inconsistencies across layer-specific optimizations.
# Solution: By reinitializing the input tensor inside the loop, we ensure:
# - Each optimization starts from a fresh, randomly initialized input.
# - Independent and unbiased optimization for each layer.
if use_real_image and image_path:
image_path = get_image_path(image_path, sample_image_select)
input_tensor = load_image(image_path)
#print(f"Image loaded successfully with shape: {input_tensor.shape}") # for debugging
print(f"Using real-world as starting input for {layer_name}")
else:
input_tensor = torch.randn(size=(1,3,224,224), requires_grad=True)
print(f"Using random_noise as starting input for {layer_name}")
print(f"Optimizing for {layer_name} | Checking activation size...")
with ActivationExtractor(model=model, target_layer=layer) as extractor:
_ = model(input_tensor)
activation_shape = extractor.activation.shape
num_channels = extractor.activation.size(1) # or extractor.activation.shape[1] or activation_shape[1]
#num_channels = layer.out_channels if hasattr(layer, "out_channels") else 64
target_neurons = [3, 20, 50]
adjusted_neurons = [min(neuron, num_channels-1) for neuron in neuron_ids]
print(f"Target neuron: {adjusted_neurons} out of {num_channels} neurons (activation_shape: {activation_shape})")
result = optimize_activation_batch(model=model,
target_neurons=adjusted_neurons,
input_data=input_tensor,
target_layer=layer,
lr=0.1,
steps=steps,
regularizations_dict = regularizations,
log_freq=log_freq)
results_list.append({
"architecture":arch,
"layer_name":layer_name,
"adjusted_neurons":adjusted_neurons,
"optimized_input":result["optimized_input"],
"loss_history": result["loss_history"]
})
summary.append({
"Architecture": arch,
"Layer Name": layer_name,
"Input Shape": tuple(result["optimized_input"].shape),
"Neuron Ids": adjusted_neurons,
"Final Loss": result["loss_history"][-1]
})
#visualize_results(
#input_tensor=results["optimized_input"],
#loss_history=results["loss_history"],
#neuron_id=adjusted_neurons,
#layer_name=layer_name)
# comparative plot
fig = comparative_visualization(results_list)
# summary table
df = pd.DataFrame(summary)
plot_file="output_plot.png"
fig.savefig(plot_file)
table_file="summary_table.csv"
df.to_csv(table_file,index=False)
return fig, df, plot_file, table_file
def run_interface():
print("Inside run_interface()")
def get_available_layers(architecture):
""" Fetch layer names for selected architecture. """
model = load_model(architecture=architecture)
layers = get_layers(model)
return [name for name,_ in layers]
with gr.Blocks() as interface:
gr.Markdown("# Neural Activation Optimizer")
gr.Markdown("Optimize neural activations across different architectures and layers using real-world images or random noise")
# Add Markdown instructions
gr.Markdown("""
## Steps to Use the Tool:
1. **Upload an Image or Select a Sample:**
- Upload a custom image or select one of the preloaded sample images (e.g., Pizza, Elephant, or The Leaning Tower).
2. **Toggle Real-World Image Usage:**
- Choose whether to use the real-world image or initialize with random noise by selecting nothing.
3. **Select Architectures and Layers:**
- Choose from supported architectures like ResNet50, VGG16, MobileNetV2, or EfficientNetB0.
- Specify the layers to optimize for each selected architecture.
4. **Customize Neuron IDs:**
- Provide neuron IDs to optimize, separated by commas (e.g., `3,20,50`).
5. **Adjust Regularizations and Parameters:**
- Edit the regularization settings using the JSON field provided.
- Specify the number of optimization steps and logging frequency.
6. **Run the Optimization:**
- Click the "Run Optimization" button to start the process.
- Visualize the optimized input and loss curves in real-time.
7. **Export Results:**
- Download the generated plots and summary table for further analysis.
## Supported Features:
- Pre-trained architectures: ResNet, VGG, MobileNet, EfficientNet.
- Dynamic customization of layers and regularizations.
- Detailed visualizations and quick feedback.
- Downloadable results for reproducibility.
""")
with gr.Row():
image_input=gr.Image(type="filepath", label="Upload image or use sample")
sample_image_select=gr.Dropdown(
choices=list(sample_images.keys()),
label="Select Sample Image",
value="Sample Images in Dropdown"
)
real_image_toggle=gr.Checkbox(value=True, label="Use Real-World Image")
neuron_input = gr.Textbox(
value = "3,20,50",
label="Neuron IDs (comma-separated, e.g., 3, 20, 50)",
lines=1
)
log_freq_input = gr.Number(
value=10,
label = "Log Frequency (Steps)"
)
sample_image_select.change(
fn=update_image,
inputs=[sample_image_select],
outputs=[image_input]
)
architecture_select = gr.CheckboxGroup(
choices=["resnet50", "vgg16", "mobilenet_v2", "efficientnet_b0"],
label="Select Architectures"
)
#layer_dropdowns = {
#"resnet50": gr.Dropdown(choices=[], multiselect=True, label="Select layers for ResNet50"),
#"vgg16": gr.Dropdown(choices=[], multiselect=True, label="Select layers for VGG16"),
#"mobilenet_v2": gr.Dropdown(choices=[], multiselect=True, label="Select layers for MobileNetV2"),
#"efficientnet_b0": gr.Dropdown(choices=[], multiselect=True, label="Select layers for EfficientNetB0")}
resnet50_dropdown = gr.Dropdown(choices=[], multiselect=True, label="Select layers for ResNet50", visible=False)
vgg16_dropdown = gr.Dropdown(choices=[], multiselect=True, label="Select layers for VGG16", visible=False)
mobilenet_v2_dropdown = gr.Dropdown(choices=[], multiselect=True, label="Select layers for MobileNetV2", visible=False)
efficientnet_b0_dropdown = gr.Dropdown(choices=[], multiselect=True, label="Select layers for EfficientNetB0", visible=False)
regularizations_input=gr.Textbox(
label="Regularizations (Editable)",
value=json.dumps({'reduction':'mean','l2': 0.01,'tv': 0.02,'sparsity': 0.01,'entropy':0.01,'l1': 0.01,'linf':0.01,'feature_map_sparsity':0.01,'clip': [0.0, 1.0]}, indent=4),
lines=10
)
step_input=gr.Number(value=50, label="Number of Steps (Default: 50)")
output_plot=gr.Plot(label="Comparative Visualizations")
output_dataframe=gr.DataFrame(label="Summary of Results")
download_plot=gr.File(label='Download Plot')
download_table=gr.File(label="Download Summary Table")
def update_layer_dropdowns(selected_architectures):
dropdowns = {
"resnet50": get_available_layers("resnet50") if "resnet50" in selected_architectures else [],
"vgg16": get_available_layers("vgg16") if "vgg16" in selected_architectures else [],
"mobilenet_v2": get_available_layers("mobilenet_v2") if "mobilenet_v2" in selected_architectures else [],
"efficientnet_b0": get_available_layers("efficientnet_b0") if "efficientnet_b0" in selected_architectures else []
}
return (
gr.update(choices=dropdowns["resnet50"], visible="resnet50" in selected_architectures),
gr.update(choices=dropdowns["vgg16"], visible="vgg16" in selected_architectures),
gr.update(choices=dropdowns["mobilenet_v2"], visible="mobilenet_v2" in selected_architectures),
gr.update(choices=dropdowns["efficientnet_b0"], visible="efficientnet_b0" in selected_architectures)
)
architecture_select.change(
fn=update_layer_dropdowns, inputs=[architecture_select],
outputs=[
resnet50_dropdown,
vgg16_dropdown,
mobilenet_v2_dropdown,
efficientnet_b0_dropdown
]
)
run_button=gr.Button("Run Optimization")
run_button.click(
fn=optimize_neural_activation,
inputs=[image_input,
real_image_toggle,
architecture_select,
resnet50_dropdown,
vgg16_dropdown,
mobilenet_v2_dropdown,
efficientnet_b0_dropdown,
regularizations_input,
step_input,
neuron_input,
sample_image_select,
log_freq_input],
outputs=[output_plot, output_dataframe, download_plot, download_table]
)
interface.launch(share=True)
if __name__=="__main__":
print("Starting the Gradio interface...")
run_interface()