"""DeepDream Studio -- a Gradio app for Hugging Face Spaces. Wraps the DeepDream algorithm from Chollet's Deep Learning with Python (Ch. 12), adapted to MobileNetV2 for lighter/faster CPU inference, behind a polished interactive UI: upload/example images, style presets, an intensity slider, per-layer advanced controls, live progress, and a before/after view. """ import gradio as gr import spaces from deepdream import LAYER_NAMES, run_deepdream BRAND_BLUE = "#266498" BRAND_ORANGE = "#d34c2c" BRAND_GRAY = "#c9c9cb" CUSTOM_CSS = f""" :root {{ --brand-blue: {BRAND_BLUE}; --brand-orange: {BRAND_ORANGE}; --brand-gray: {BRAND_GRAY}; }} .gradio-container {{ background: linear-gradient(160deg, #f4f6f8 0%, #e9edf1 45%, #f4f6f8 100%) !important; }} #app-header h1 {{ color: var(--brand-blue) !important; font-weight: 800 !important; letter-spacing: -0.02em; }} #app-header p, #app-header li {{ color: #33363a !important; }} .panel-card {{ background: rgba(255, 255, 255, 0.85) !important; border: 1px solid rgba(38, 100, 152, 0.18) !important; border-radius: 16px !important; padding: 12px !important; }} button.preset-btn {{ border: 1px solid var(--brand-orange) !important; color: var(--brand-orange) !important; background: transparent !important; font-weight: 600 !important; }} button.preset-btn:hover {{ background: var(--brand-orange) !important; color: #ffffff !important; }} #dream-button {{ background: var(--brand-orange) !important; border: none !important; color: #ffffff !important; font-weight: 700 !important; font-size: 1.05em !important; }} #dream-button:hover {{ filter: brightness(1.1); }} """ PRESETS = { "Subtle": {"layers": [0.5, 0.7, 1.0, 1.2], "intensity": 0.6}, "Classic": {"layers": [1.0, 1.5, 2.0, 2.5], "intensity": 1.0}, "Psychedelic": {"layers": [1.5, 2.5, 3.5, 4.5], "intensity": 1.6}, } EXAMPLES = [ "examples/coast.jpg", "examples/elephant.jpg", "examples/cat.jpg", ] HEADER_MARKDOWN = """ # 🌌 DeepDream Studio Turn any photo into a hallucinatory dreamscape using a convolutional neural network's own learned visual features. **How it works:** a pretrained image classifier (MobileNetV2) already "knows" what edges, textures, and shapes look like. Instead of using it to recognize an image, we run it *backwards*: we nudge the pixels of your photo to make the network's own internal features fire more strongly, repeating this thousands of times at multiple zoom levels ("octaves"). The network starts hallucinating the patterns it already knows how to see, painted into your image. This technique comes from Chapter 12 of François Chollet's *Deep Learning with Python*. Upload a photo (or pick an example below), choose a style, and hit **Dream**. """ def apply_preset(preset_name): preset = PRESETS[preset_name] layers = preset["layers"] return layers[0], layers[1], layers[2], layers[3], preset["intensity"] @spaces.GPU(duration=90) def generate_dream( image, intensity, layer_1, layer_2, layer_3, layer_4, iterations, num_octave, progress=gr.Progress(), ): if image is None: raise gr.Error("Please upload a photo or pick an example image first.") layer_settings = { name: value * intensity for name, value in zip(LAYER_NAMES, [layer_1, layer_2, layer_3, layer_4]) } def progress_cb(octave_index, num_octaves, iteration, total_iterations, loss): fraction = (octave_index * total_iterations + iteration + 1) / ( num_octaves * total_iterations ) progress( fraction, desc=f"Octave {octave_index + 1}/{num_octaves} · " f"step {iteration + 1}/{total_iterations} · loss {loss:.2f}", ) progress(0, desc="Warming up MobileNetV2...") dreamed = run_deepdream( image, layer_settings=layer_settings, iterations=int(iterations), num_octave=int(num_octave), progress_cb=progress_cb, ) return image, dreamed with gr.Blocks(css=CUSTOM_CSS, title="DeepDream Studio") as demo: with gr.Column(elem_id="app-header"): gr.Markdown(HEADER_MARKDOWN) with gr.Row(): with gr.Column(scale=1, elem_classes=["panel-card"]): input_image = gr.Image(type="pil", label="Your photo", height=320) gr.Examples(examples=EXAMPLES, inputs=input_image, label="Or try an example") with gr.Column(scale=1, elem_classes=["panel-card"]): gr.Markdown("**Style presets**") with gr.Row(): subtle_btn = gr.Button("Subtle", elem_classes=["preset-btn"]) classic_btn = gr.Button("Classic", elem_classes=["preset-btn"]) psychedelic_btn = gr.Button("Psychedelic", elem_classes=["preset-btn"]) intensity_slider = gr.Slider( minimum=0.3, maximum=2.0, value=1.0, step=0.05, label="Intensity", info="Overall strength of the dream effect", ) with gr.Accordion("Advanced: per-layer feature emphasis", open=False): gr.Markdown( "MobileNetV2 has feature layers at increasing depth. Earlier " "layers emphasize edges/textures; deeper layers emphasize " "more complex, object-like shapes." ) layer_1_slider = gr.Slider(0.0, 5.0, value=1.0, step=0.1, label="Layer 1 (shallow, edges/textures)") layer_2_slider = gr.Slider(0.0, 5.0, value=1.5, step=0.1, label="Layer 2") layer_3_slider = gr.Slider(0.0, 5.0, value=2.0, step=0.1, label="Layer 3") layer_4_slider = gr.Slider(0.0, 5.0, value=2.5, step=0.1, label="Layer 4 (deep, complex shapes)") iterations_slider = gr.Slider(5, 20, value=12, step=1, label="Iterations per octave") octave_slider = gr.Slider(1, 4, value=3, step=1, label="Number of octaves") dream_button = gr.Button("Dream ✨", elem_id="dream-button", size="lg") with gr.Row(): original_output = gr.Image(label="Original", show_download_button=False) dreamed_output = gr.Image(label="Dreamed", show_download_button=True) subtle_btn.click( lambda: apply_preset("Subtle"), outputs=[layer_1_slider, layer_2_slider, layer_3_slider, layer_4_slider, intensity_slider], ) classic_btn.click( lambda: apply_preset("Classic"), outputs=[layer_1_slider, layer_2_slider, layer_3_slider, layer_4_slider, intensity_slider], ) psychedelic_btn.click( lambda: apply_preset("Psychedelic"), outputs=[layer_1_slider, layer_2_slider, layer_3_slider, layer_4_slider, intensity_slider], ) dream_button.click( generate_dream, inputs=[ input_image, intensity_slider, layer_1_slider, layer_2_slider, layer_3_slider, layer_4_slider, iterations_slider, octave_slider, ], outputs=[original_output, dreamed_output], ) gr.Markdown( "---\n" "Based on Chapter 12 of *Deep Learning with Python* by François Chollet. " "Runs on free-tier CPU, so a dream may take 30-90 seconds depending on " "settings -- larger intensity/iterations/octaves take longer." ) if __name__ == "__main__": demo.queue().launch()