Maned

Convolution and pooling

Generated by tools/gen_example_pages.py from mnd_scripts/examples/example_conv_pool.mnd — the output below is a real run, not a transcription. Regenerating the page reruns it.

spatial operators (conv2d, maxpool2d, avgpool2d) and shape operators (concat) — and the OBJECT-PARAMETER syntax { key: value } that configures them.

The program#

# ============================================================================
# example_conv_pool.mnd
# ----------------------------------------------------------------------------
# FUNCTIONALITY: spatial operators (conv2d, maxpool2d, avgpool2d) and shape
# operators (concat) -- and the OBJECT-PARAMETER syntax `{ key: value }` that
# configures them.
#
# THE ONE RULE THAT TRIPS EVERYONE UP: object params are an ARGUMENT, and in a
# postfix language every argument precedes its operator.
#
#     RIGHT:  img {kernel_size: 2, stride: 2} maxpool2d pooled =
#     WRONG:  img maxpool2d {kernel_size: 2, stride: 2} pooled =
#
# The wrong form still parses -- the block just becomes a dangling term that no
# operator ever consumes -- so the operator silently falls back to its defaults
# (and for pooling, a default kernel_size of 0, which is a run-time error).
# Read the params as "with these settings, do this", left to right.
#
# Named params are resolved to integers at graph-build time and folded into the
# 24-bit IR immediate the worker decodes, which is why they must be compile-time
# constants rather than runtime values.
#
#   conv2d      2 ops  {stride, padding}     input rank-2 [H,W] or rank-3
#                                            [C,H,W]; WEIGHT IS RANK-4
#                                            [Cout, Cin, KH, KW]
#   maxpool2d   1 op   {kernel_size, stride} stride defaults to kernel_size
#   avgpool2d   1 op   {kernel_size, stride} integer mean, truncated
#   concat      2 ops  {axis}
#
# RUN: ../maned-run examples/example_conv_pool.mnd
# ============================================================================
mnd::quantmax=1000;
mnd::quantmin=-1000;
mnd::quantres=0;

in::img = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];   # 4x4 [H,W]

# One output channel, one input channel, 2x2 kernel -> shape [1,1,2,2].
# This is a diagonal-difference detector.
in::kernel = [[[[1,0],[0,-1]]]];

in::a = [[1,2],[3,4]];
in::b = [[5,6],[7,8]];

profile::img;

calc::lambda_flow vision(img, kernel, a, b) {
    # --- convolution, stride 1, no padding: 4x4 -> [1,3,3] ----------------
    img kernel {stride: 1, padding: 0} conv2d features =

    # --- same kernel, stride 2: 4x4 -> [1,2,2] ----------------------------
    img kernel {stride: 2, padding: 0} conv2d strided =

    # --- padding widens the output back out --------------------------------
    img kernel {stride: 1, padding: 1} conv2d padded =

    # --- pooling: 4x4 -> 2x2 ------------------------------------------------
    img {kernel_size: 2, stride: 2} maxpool2d pooled_max =
    img {kernel_size: 2, stride: 2} avgpool2d pooled_avg =

    # stride omitted defaults to kernel_size (non-overlapping windows)
    img {kernel_size: 2} maxpool2d pooled_default_stride =

    # overlapping windows: kernel 2, stride 1 -> 3x3
    img {kernel_size: 2, stride: 1} maxpool2d pooled_overlap =

    # --- concatenation along either axis -----------------------------------
    a b {axis: 0} concat stacked_rows =      # 2x2 + 2x2 -> 4x2
    a b {axis: 1} concat stacked_cols =      # 2x2 + 2x2 -> 2x4

    # --- a small pipeline: convolve, rectify, pool ------------------------
    # `padded` carries both signs (the zero-pad border makes the detector fire
    # asymmetrically), so relu actually has something to clamp.
    padded relu rectified =
    rectified {kernel_size: 2, stride: 1} maxpool2d pipeline_out =
} return features, strided, padded,
         pooled_max, pooled_avg, pooled_default_stride, pooled_overlap,
         stacked_rows, stacked_cols, rectified, pipeline_out;

The run#

$ maned-run mnd_scripts/examples/example_conv_pool.mnd
Matrix Profile: img
------------------------------------------------
[basic_id]
  type                      matrix
  field                     real
  dtype                     int
[dimensions]  exact
  shape                     4 x 4
  order                     4
  is_square                 true
  is_rectangular            false
[structure]  exact
  is_diagonal               false
  is_identity               false
  is_zero_matrix            false
  is_upper_triangular       false
  is_lower_triangular       false
  is_bidiagonal             false
  is_lower_bidiagonal       false
  is_upper_bidiagonal       false
  is_tridiagonal            false
  is_band_matrix            false
  bandwidth_lower           3
  bandwidth_upper           3
  is_sparse                 false
  non_zero_elements         16
  zero_elements             0
  sparsity_ratio            0/16  (0)
[symmetry]  exact
  is_symmetric              false
  is_skew_symmetric         false
  is_hermitian              false
  is_orthogonal             false
  is_normal                 false
[linear_algebra]
  trace                     34
  determinant               0
  rank                      2
  is_full_rank              false
  is_invertible             false
  is_singular               true
[spectral]  approximate (QR iteration)
  eigenvalues               -2.209, 0, 0, 36.21
  multiplicity              -2.209 (alg 1, geo 1), 0 (alg 2, geo 2), 36.21 (alg 1, geo 1)
  spectral_radius           36.21
  all_eigenvalues_positive  false
  is_diagonalizable         true
  is_defective              false
  jordan_blocks             -2.209^1, 0^1, 0^1, 36.21^1
[numerical]  approximate
  condition_number          inf
  condition_status          singular
  is_numerically_stable     false
[positivity]
  (definiteness)            not_applicable (matrix is not symmetric)
  is_positive_definite      false
  is_positive_semidefinite  false
  is_negative_definite      false
  is_negative_semidefinite  false
  is_indefinite             false
[special_properties]
  is_nilpotent              false
  is_idempotent             false
  is_involutory             false
[decompositions]
  supports_lu               true
  supports_qr               true
  supports_svd              true
  supports_cholesky         false
  supports_eigendecomp      true
  supports_jordan           true
[computational]  rule
  storage_format            dense_row_major
  linear_solver             lu, qr
  eigen_solver              qr, schur_decomposition
  fpga_friendly             false
  cache_friendly            true
  gpu_friendly              true
  tensor_core_friendly      false
[geometric_interpretation]  rule
  represents_scaling        true
  represents_shear          true
  represents_rotation       false
  represents_projection     false
[dynamic_interpretation]  rule
  has_coupled_modes         false
  dynamic_modes             all modes independent
[taxonomy]
  inherits                  square_matrix, dense_matrix, singular_matrix, diagonalizable_matrix
  implies                   -
  forbids                   symmetric, diagonal, orthogonal, spd, invertible, defective
------------------------------------------------
flow 'vision' outputs:
features : [1x3x3] = [-5, -5, -5, -5, -5, -5, -5, -5, -5]
strided : [1x2x2] = [-5, -5, -5, -5]
padded : [1x5x5] = [-1, -2, -3, -4, 0, -5, -5, -5, -5, 4, -9, -5, -5, -5, 8, -13, -5, -5, -5, 12, 0, 13, 14, 15, 16]
pooled_max : [2x2] = [6, 8, 14, 16]
pooled_avg : [2x2] = [3, 5, 11, 13]
pooled_default_stride : [2x2] = [6, 8, 14, 16]
pooled_overlap : [3x3] = [6, 7, 8, 10, 11, 12, 14, 15, 16]
stacked_rows : [4x2] = [1, 2, 3, 4, 5, 6, 7, 8]
stacked_cols : [2x4] = [1, 2, 5, 6, 3, 4, 7, 8]
rectified : [1x5x5] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 12, 0, 13, 14, 15, 16]
pipeline_out : [1x4x4] = [0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 12, 13, 14, 15, 16]

Next#

© 2026 Fabiano Dicheti · Found a problem on this page? Open an issue