TorchLean API

NN.Spec.Layers.Pooling.Spatial

Spatial Pooling #

Dimension-polymorphic pooling specs for spatial tensors and channels-first tensors.

Arbitrary-rank pooling (channels-first, no batch) #

These operators define pooling over an arbitrary spatial rank d.

Conventions:

PyTorch comparisons (conceptual, without batch axis):

Layer configs + output shapes #

structure Spec.MaxPoolSpec (d : ) (kernel stride padding : TorchLean.Tensor [d]) (hKernel : ∀ (i : Fin d), kernel.getScalar i 0) (hStride : ∀ (i : Fin d), stride.getScalar i 0) :

Witness that an arbitrary-rank max-pooling configuration has nonzero kernel and stride on every axis.

The structure has no fields: it is a phantom type whose indices force every construction site to supply the nonzero-kernel and nonzero-stride proofs, and it is the value threaded through the runtime, lowering, and verification code paths. The pooling specs themselves do not eliminate these proofs. A zero kernel or stride is instead excluded at the shape level: poolOutDim returns an empty output axis for a zero kernel, so no window is ever evaluated, and the getD 0 fallback inside Pooling.Internal.maxPoolValue is unreachable for the shapes this witness admits.

The tensors are indices of the type rather than duplicate structure fields, so a value cannot advertise one configuration while its type describes another.

    Instances For
      structure Spec.AvgPoolSpec (d : ) (kernel stride padding : TorchLean.Tensor [d]) (hKernel : ∀ (i : Fin d), kernel.getScalar i 0) (hStride : ∀ (i : Fin d), stride.getScalar i 0) :

      Witness that an arbitrary-rank average-pooling configuration has nonzero kernel and stride. Like MaxPoolSpec, it is a field-free phantom type; see that docstring for what the proofs do.

        Instances For
          def Spec.poolOutDim (input kernel stride padding : ) :

          Output spatial sizes with symmetric padding.

          Pooling follows the usual floor-mode sliding-window formula, but an empty input axis, empty kernel, or padding larger than half the kernel gives an empty output axis. The last condition is part of the pooling contract used by PyTorch and by TorchLean's native implementations; it is not a restriction on convolution.

          Instances For
            def Spec.poolOutSpatial {d : } (inSpatial kernel stride : TorchLean.Tensor [d]) :

            Output spatial sizes without padding.

            An invalid axis (empty input, zero kernel, zero stride, or a kernel larger than the input) has size zero.

            Instances For
              def Spec.poolOutSpatialPad {d : } (inSpatial kernel stride padding : TorchLean.Tensor [d]) :

              Apply poolOutDim independently to each spatial axis.

              Instances For
                theorem Spec.poolOutSpatialPad_global {d : } (spatial : TorchLean.Tensor [d]) (hSpatial : ∀ (i : Fin d), spatial.getScalar i 0) :

                Pooling over the complete spatial extent produces one value on every spatial axis.

                def Spec.poolOutShape {d : } (inSpatial kernel stride : TorchLean.Tensor [d]) :

                Output shape for single-channel arbitrary-rank pooling (no padding).

                Instances For
                  def Spec.poolMultiOutShape {d : } (inC : ) (inSpatial kernel stride : TorchLean.Tensor [d]) :

                  Output shape for channels-first arbitrary-rank pooling (no padding; channels preserved).

                  Instances For
                    def Spec.poolOutShapePad {d : } (inSpatial kernel stride padding : TorchLean.Tensor [d]) :

                    Output shape for single-channel arbitrary-rank pooling with symmetric padding.

                    Instances For
                      def Spec.poolMultiOutShapePad {d : } (inC : ) (inSpatial kernel stride padding : TorchLean.Tensor [d]) :

                      Output shape for channels-first arbitrary-rank pooling with symmetric padding (channels preserved).

                      Instances For
                        def Spec.Pooling.Internal.smoothMaxPivotStep {α : Type} [Context α] (beta current candidate : α) :
                        α

                        Choose the input-space pivot whose scaled value is maximal.

                        Instances For
                          def Spec.Pooling.Internal.foldlIndices' {β : Type} (dims : List ) (init : β) (f : βList β) :
                          β

                          Fold over every coordinate of a rectangular index box given by dims.

                          Pooling walks a window whose rank is only known at runtime, so the walk is a fold over a list of extents rather than nested Fin loops. The accumulator sees each coordinate list once, in row-major order.

                          Instances For
                            def Spec.Pooling.Internal.paddedCoords? (outIdxs winIdxs stride : List ) :

                            Coordinate of a window cell in the padded input, or none on a rank mismatch.

                            Per axis this is output * stride + window, the position the cell occupies before padding is removed.

                            Instances For

                              Turn a padded-input coordinate back into a real input coordinate.

                              Returns none when the coordinate lands inside the padding, which is how the callers tell a genuine input cell from a fabricated one; average and max pooling then treat that answer differently.

                              Instances For

                                Whether a runtime coordinate list is in range for dims, and of the right length.

                                Instances For
                                  def Spec.Pooling.Internal.getPaddedAverageInputVal {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs winIdxs stride padding : List ) :
                                  α

                                  Input lookup for average/smooth pooling.

                                  For average-style pooling, padded cells contribute numeric zero and are still counted by the denominator chosen by the surrounding pooling spec. We keep this separate from getPaddedMaxInputVal?, where padded cells must be ignored rather than treated as zero.

                                  Instances For
                                    def Spec.Pooling.Internal.getPaddedMaxInputVal? {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs winIdxs stride padding : List ) :

                                    Input lookup for hard max-pooling.

                                    Unlike average pooling, max pooling does not insert numeric zero for an individual padded cell: PyTorch's valid max-pool configurations behave as though those cells were -∞. TorchLean keeps the spec scalar-polymorphic by returning none for padded coordinates and ignoring them in the max fold. poolOutSpatialPad rejects empty input axes, empty kernels, and padding beyond PyTorch's half-kernel restriction, so every emitted output window contains at least one input coordinate.

                                    Instances For

                                      Number of cells in a pooling window, the denominator average pooling counts with.

                                      Instances For

                                        Start of adaptive-pooling bin i: floor(i * input / output).

                                        Instances For
                                          def Spec.Pooling.Internal.adaptiveEnd (input output i : ) :

                                          End of adaptive-pooling bin i: ceil((i + 1) * input / output).

                                          Instances For
                                            theorem Spec.Pooling.Internal.adaptiveStart_lt_adaptiveEnd (input output i : ) (hInput : input 0) (hOutput : output 0) :
                                            adaptiveStart input output i < adaptiveEnd input output i

                                            Every adaptive-pooling bin is nonempty when the input and output extents are positive.

                                            Both hypotheses are needed: an empty input axis gives start = end = 0, and output = 0 makes both quotients zero under Lean's total division. This is the fact that justifies the hInput and hOutput arguments of adaptiveAvgPoolSpec and adaptiveMaxPoolSpec: the average never divides by zero and the max fold always sees at least one element.

                                            Per-axis bin starts for one adaptive-pooling output coordinate.

                                            Instances For

                                              Per-axis bin extents for one adaptive-pooling output coordinate.

                                              Adaptive pooling is the case where the window is not fixed: bin widths vary with the coordinate when the input extent is not a multiple of the output extent, which is exactly why the walk is over a computed extent list.

                                              Instances For

                                                Add two coordinate lists axiswise, dropping any tail the shorter list does not cover.

                                                Instances For

                                                  Average of one adaptive-pooling bin.

                                                  adaptiveStart_lt_adaptiveEnd is what keeps this honest: with positive input and output extents the bin is nonempty, so the division below is never a division by zero.

                                                  Instances For

                                                    Maximum over one adaptive-pooling bin.

                                                    The getD 0 fallback would only be reached on an empty bin, which adaptiveStart_lt_adaptiveEnd rules out for the shapes the public specs accept.

                                                    Instances For
                                                      def Spec.Pooling.Internal.maxPoolValue {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                      α

                                                      Maximum over one fixed pooling window, ignoring padded cells.

                                                      Padded cells are skipped rather than treated as zero, since a zero would win the max over an all-negative window. poolOutSpatialPad guarantees at least one real cell per window.

                                                      Instances For
                                                        def Spec.Pooling.Internal.maxPoolSelectedTangentValue {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (input tangent : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                        α

                                                        Selected-branch tangent for one hard max-pooling window.

                                                        The tangent follows the same winner selected by maxPoolValue. At a tie this is a deterministic generalized-derivative convention, not the mathematical directional derivative of max.

                                                        Instances For
                                                          def Spec.Pooling.Internal.avgPoolValue {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                          α

                                                          Average over one fixed pooling window, counting padded cells as zero.

                                                          This is PyTorch's count_include_pad = True behaviour: the denominator is the whole window, so a padded edge pulls the average toward zero rather than being renormalized away.

                                                          Instances For
                                                            def Spec.Pooling.Internal.smoothMaxPoolPivot {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (beta : α) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                            α

                                                            Input-space pivot whose scaled value is maximal over a nonempty arbitrary-rank pooling window.

                                                            Instances For
                                                              def Spec.Pooling.Internal.smoothMaxPoolValue {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (beta : α) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                              α

                                                              Evaluate one arbitrary-rank smooth-max window with the sign-aware input-space pivot.

                                                              Instances For
                                                                def Spec.Pooling.Internal.smoothMaxPoolJvpValue {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial : TorchLean.Tensor [d]} (beta : α) (input tangent : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (outIdxs kernel stride padding : List ) :
                                                                α

                                                                Directional derivative of the smooth log-sum-exp pooling value.

                                                                For y = beta⁻¹ log Σ exp(beta*xᵢ), the directional derivative is Σ softmax(beta*xᵢ) * dxᵢ, using the same zero-padding and stable input-pivot convention as smoothMaxPoolValue.

                                                                Instances For

                                                                  Forward (single-channel spatial tensor) #

                                                                  def Spec.maxPoolSpatialSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) :

                                                                  arbitrary-rank max pooling on a spatial tensor (no explicit channel axis).

                                                                  Instances For
                                                                    def Spec.maxPoolSpatialLinearizationSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input tangent : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) :

                                                                    Selected-branch linearization for arbitrary-rank hard max-pooling on a spatial tensor.

                                                                    Away from ties this is the ordinary JVP. At ties it follows the first row-major primal maximizer, matching the VJP convention but not claiming an analytic directional derivative.

                                                                    Instances For
                                                                      def Spec.avgPoolSpatialSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : AvgPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) :

                                                                      arbitrary-rank average pooling on a spatial tensor (no explicit channel axis).

                                                                      Instances For

                                                                        Backward (single-channel spatial tensor) #

                                                                        These are the VJPs of the forward pooling specs above.

                                                                        Conventions:

                                                                        def Spec.maxPoolSpatialBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (gradOutput : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList)) :

                                                                        Backward/VJP for maxPoolSpatialSpec.

                                                                        Each output gradient is propagated to the argmax location in the corresponding input window. Ties keep the first position in row-major order.

                                                                        Instances For
                                                                          def Spec.avgPoolSpatialBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : AvgPoolSpec d kernel stride padding hKernel hStride) (gradOutput : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList)) :

                                                                          Backward/VJP for avgPoolSpatialSpec (single-channel).

                                                                          Each output gradient is evenly distributed across its kernel window.

                                                                          Instances For

                                                                            Forward (channels-first: C × spatial...) #

                                                                            def Spec.maxPoolSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) :

                                                                            arbitrary-rank max pooling on a channels-first tensor: shape [C] ++ spatial.

                                                                            Instances For
                                                                              def Spec.maxPoolLinearizationSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input tangent : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) :

                                                                              arbitrary-rank hard max-pool selected-branch linearization, applied channel-wise.

                                                                              Instances For
                                                                                def Spec.avgPoolSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : AvgPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) :

                                                                                arbitrary-rank average pooling on a channels-first tensor: shape [C] ++ spatial.

                                                                                Instances For

                                                                                  Adaptive pooling #

                                                                                  Adaptive pooling partitions every input axis into a requested number of bins. Unlike fixed-window pooling, its window sizes depend on the output index. The same definition handles sequence, image, volume, and higher-rank tensors.

                                                                                  def Spec.adaptiveAvgPoolSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial outSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) (_hInput : ∀ (i : Fin d), inSpatial.getScalar i 0) (_hOutput : ∀ (i : Fin d), outSpatial.getScalar i 0) :

                                                                                  Adaptive average pooling on a channels-first tensor of arbitrary spatial rank.

                                                                                  The two hypotheses make every bin nonempty (Pooling.Internal.adaptiveStart_lt_adaptiveEnd), so the per-bin average never divides by zero. They are not eliminated inside the definition.

                                                                                  Instances For
                                                                                    def Spec.adaptiveMaxPoolSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial outSpatial : TorchLean.Tensor [d]} (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) (_hInput : ∀ (i : Fin d), inSpatial.getScalar i 0) (_hOutput : ∀ (i : Fin d), outSpatial.getScalar i 0) :

                                                                                    Adaptive max pooling on a channels-first tensor of arbitrary spatial rank.

                                                                                    The two hypotheses make every bin nonempty (Pooling.Internal.adaptiveStart_lt_adaptiveEnd), so the getD 0 fallback in Pooling.Internal.adaptiveMaxPoolValue is never taken.

                                                                                    Instances For

                                                                                      Backward (channels-first: C × spatial...) #

                                                                                      def Spec.maxPoolBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) (gradOutput : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList))) :

                                                                                      Multi-channel VJP for maxPoolSpec (apply spatial backward per channel).

                                                                                      Instances For
                                                                                        def Spec.avgPoolBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : AvgPoolSpec d kernel stride padding hKernel hStride) (gradOutput : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList))) :

                                                                                        Multi-channel VJP for avgPoolSpec (apply spatial backward per channel).

                                                                                        Instances For

                                                                                          Smooth max pooling (log-sum-exp surrogate) #

                                                                                          def Spec.smoothMaxPoolSpatialSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) :

                                                                                          Smooth log-sum-exp max pooling on a spatial tensor (no explicit channel axis).

                                                                                          The temperature parameter must be nonzero because the forward expression contains 1 / beta.

                                                                                          Instances For
                                                                                            def Spec.smoothMaxPoolSpatialJvpSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input tangent : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) :

                                                                                            Forward-mode JVP for arbitrary-rank smooth max-pooling on a spatial tensor.

                                                                                            For the log-sum-exp surrogate this is the softmax-weighted sum of the input tangent over each window. It is the forward-mode counterpart of smoothMaxPoolSpatialBackwardSpec.

                                                                                            Instances For
                                                                                              def Spec.smoothMaxPoolSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) :

                                                                                              Smooth log-sum-exp max pooling on a channels-first tensor (channel-wise application).

                                                                                              The temperature parameter must be nonzero because the forward expression contains 1 / beta.

                                                                                              Instances For
                                                                                                def Spec.smoothMaxPoolJvpSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input tangent : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) :

                                                                                                arbitrary-rank smooth max-pool JVP on a channels-first tensor (channel-wise application).

                                                                                                Instances For

                                                                                                  Smooth max pooling backward #

                                                                                                  def Spec.smoothMaxPoolSpatialBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (_layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data inSpatial).toList)) (gradOutput : TorchLean.Tensor α (Shape.ofList (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList)) :

                                                                                                  Backward/VJP for smoothMaxPoolSpatialSpec (log-sum-exp surrogate).

                                                                                                  For a window x₁,…,xₙ, the surrogate is:

                                                                                                  y = (1/beta) * log(∑ exp(beta*xᵢ))

                                                                                                  and the VJP distributes upstream gradient proportionally to exp(beta*xᵢ). The implementation evaluates the equivalent max/min-shifted weights so large finite inputs do not overflow before normalization.

                                                                                                  Instances For
                                                                                                    def Spec.smoothMaxPoolBackwardSpec {α : Type} [TorchLean.Storage α] [Context α] {d C : } {inSpatial kernel stride padding : TorchLean.Tensor [d]} {hKernel : ∀ (i : Fin d), kernel.getScalar i 0} {hStride : ∀ (i : Fin d), stride.getScalar i 0} (layer : MaxPoolSpec d kernel stride padding hKernel hStride) (beta : α) (hBeta : beta 0) (input : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data inSpatial).toList))) (gradOutput : TorchLean.Tensor α (Shape.ofList (C :: (TorchLean.Tensor.Internal.Rep.data (poolOutSpatialPad inSpatial kernel stride padding)).toList))) :

                                                                                                    Multi-channel VJP for smoothMaxPoolSpec (apply spatial backward per channel).

                                                                                                    Instances For