LeNet View#

The LeNet style visualization renders models using classic “feature map stack” diagrams, where each layer is shown as a 2D representation of its output channels. This style is inspired by the original LeNet paper and produces distinctive, publication-quality architectural diagrams.

Best For#

LeNet view excels for:

  • Academic papers: Classic feature-map diagrams expected in computer vision research

  • Technical documentation: Showing detailed channel-level architecture

  • Educational materials: Clear visualization of how channels flow through layers

  • Presentations: Distinctive, professional-looking architecture diagrams

  • Detailed architecture analysis: Understanding how many channels each layer outputs

LeNet view is particularly effective for CNNs because it shows the actual channel count progression visually, making the architecture’s growth/reduction patterns immediately obvious.

When to Use LeNet vs. Other Modes#

Choose mode='lenet' over other modes when:

DO use LeNet for:
  • CNN architectures you’re publishing in papers/presentations

  • Models where channel progression is important to understand

  • Creating distinctive architecture diagrams

  • Detailed architectural analysis

  • Models with interesting channel dynamics (e.g., bottlenecks)

DON’T use LeNet for:
  • Models highlighting computational graph structure: use graph mode

  • Models with complex branching or skip connections: use functional mode

  • Simple sequential models for learning: use layered mode

  • Very deep models (>100 layers): becomes impractical unless heavily customized

Basic Example#

import tensorflow as tf
from tensorflow import keras
import visualkeras

model = keras.Sequential([
    keras.layers.Input(shape=(28, 28, 1)),
    keras.layers.Conv2D(32, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Flatten(),
    keras.layers.Dense(10)
])

# Default LeNet view
image = visualkeras.show(model, mode='lenet')
image.show()

The visualization shows each layer as stacked feature maps, with the height/color/size representing the channel count changing through the network.

Layout Customization#

Control spacing and sizing:

from visualkeras.options import LenetOptions, LENET_PRESETS

# Custom layout
options = LenetOptions(
    layer_spacing=50,      # Space between layers (larger = more spread out)
    map_spacing=5,         # Space between individual channels
    scale_xy=5.0,          # Scale width/height of feature maps
    max_visual_channels=16 # Limit channels shown (default 12)
)

image = visualkeras.show(model, mode='lenet', options=options)
image.show()

Using Presets#

LeNet view includes three curated presets:

from visualkeras.options import LENET_PRESETS

# Compact: minimal spacing, tight layout
compact = visualkeras.show(
    model,
    mode='lenet',
    preset='compact'
)

# Presentation: large, detailed, publication-ready
presentation = visualkeras.show(
    model,
    mode='lenet',
    preset='presentation'
)

# Default: balanced for general use
default = visualkeras.show(
    model,
    mode='lenet',
    preset='default'
)

Color and Style Customization#

Visual appearance options:

from visualkeras.options import LenetOptions

options = LenetOptions(
    background_fill='white',      # Background color
    connector_fill='#333333',      # Connection line color
    connector_width=2,             # Line thickness
    font_color='black',            # Label color
    draw_connections=True,         # Show layer connections
    draw_patches=True,             # Show patch visualizations
)

image = visualkeras.show(model, mode='lenet', options=options)
image.show()

Layer-Type Color Styling#

Customize colors per layer type:

from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense

color_map = {
    Conv2D: {'fill': '#1f77b4', 'outline': '#0d47a1'},
    MaxPooling2D: {'fill': '#ff7f0e', 'outline': '#d84315'},
    Dense: {'fill': '#2ca02c', 'outline': '#1b5e20'},
}

image = visualkeras.show(
    model,
    mode='lenet',
    color_map=color_map
)
image.show()

Advanced: Text Labels and Callables#

Control what text appears above and below each layer.

Built-in Text Options#

By default, LeNet shows layer names below and shapes above. You can customize this with label callables:

from visualkeras.options import LenetOptions

# Define custom top label (above each layer)
def top_label(layer, shape):
    """Show shape info above each layer"""
    return f"{shape.dH}×{shape.dW}×{shape.dZ}"  # height x width x channels

# Define custom bottom label (below each layer)
def bottom_label(layer, shape):
    """Show layer name below each layer"""
    return layer.__class__.__name__

options = LenetOptions(
    top_label_callable=top_label,
    bottom_label_callable=bottom_label,
)

image = visualkeras.show(model, mode='lenet', options=options)
image.show()
The RenderShape object provides:
  • dH, dW: Height and width of feature maps

  • dZ: Number of channels (depth)

Practical Label Example#

Show parameter counts and activation info:

def info_label(layer, shape):
    """Show layer type and parameters"""
    layer_type = layer.__class__.__name__
    activation = getattr(layer, 'activation', None)
    if activation:
        return f"{layer_type} ({activation.__name__})"
    return layer_type

options = LenetOptions(
    bottom_label_callable=info_label
)

image = visualkeras.show(model, mode='lenet', options=options)
image.show()

Advanced: Embedding Images in Feature Maps#

Display custom images or textures within feature map visualizations using the styles parameter.

Basic Face Image#

Embed an image in a specific layer’s visualization:

from visualkeras.options import LenetOptions

# Style: embed image in specific layer
styles = {
    'layer_2': {  # Apply to layer at index 2
        'face_image': '/path/to/your/texture.png',
        'face_image_fit': 'cover',      # How to fit image in frame
        'face_image_alpha': 200,        # Transparency (0-255)
        'face_image_inset': 2,          # Border inset in pixels
    }
}

options = LenetOptions(styles=styles)
image = visualkeras.show(model, mode='lenet', options=options)
image.show()
face_image_fit options:
  • 'cover': Fill entire feature map (may crop image)

  • 'contain': Fit entire image (may have letterboxing)

  • 'fill': Stretch to fill (may distort image)

  • 'stretch': Same as fill

  • 'scale-down': Largest fit that doesn’t upscale

Complex Styling with Images#

Combine image embedding with other style parameters:

styles = {
    'conv_1': {
        'face_image': 'kernel_viz.png',
        'face_image_fit': 'contain',
        'face_image_alpha': 180,
    },
    'conv_2': {
        'face_image': 'activation_viz.png',
        'face_image_fit': 'cover',
        'face_image_alpha': 200,
    }
}

options = LenetOptions(
    styles=styles,
    padding=30,
    layer_spacing=60,
    preset='presentation'
)

image = visualkeras.show(model, mode='lenet', options=options)
image.save('detailed_architecture.png')

Filtering Layers#

Control which layers appear:

from tensorflow.keras.layers import BatchNormalization, Dropout
from visualkeras.options import LenetOptions

# Skip layers by type
options = LenetOptions(
    type_ignore=[BatchNormalization, Dropout]
)

# Or skip by index (layer position)
options = LenetOptions(
    index_ignore=[3, 5, 8]  # Skip layers 3, 5, and 8
)

image = visualkeras.show(model, mode='lenet', options=options)
image.show()

Practical Examples#

Classic CNN for Publication

model = keras.Sequential([
    keras.layers.Input(shape=(32, 32, 3)),
    keras.layers.Conv2D(32, (3, 3), activation='relu'),
    keras.layers.Conv2D(32, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(128, (3, 3), activation='relu'),
    keras.layers.Conv2D(128, (3, 3), activation='relu'),
    keras.layers.GlobalAveragePooling2D(),
    keras.layers.Dense(256, activation='relu'),
    keras.layers.Dense(10, activation='softmax'),
])

# High-quality publication figure
image = visualkeras.show(
    model,
    mode='lenet',
    preset='presentation',
    color_map={
        keras.layers.Conv2D: {'fill': '#1f77b4'},
        keras.layers.MaxPooling2D: {'fill': '#ff7f0e'},
        keras.layers.Dense: {'fill': '#2ca02c'},
    }
)
image.save('architecture.png', dpi=300)

Compact Diagram for Slides

# Space-efficient, still readable
image = visualkeras.show(
    model,
    mode='lenet',
    preset='compact',
    max_visual_channels=8  # Limit channels shown
)
image.show()

Reproducible Randomization#

Control randomness in patch visualization:

from visualkeras.options import LenetOptions

options = LenetOptions(
    seed=42  # Fixed seed = reproducible randomization
)

# Same seed produces identical visualization every time
image = visualkeras.show(model, mode='lenet', options=options)
image.show()

See Also#