blob: bd1dae3dc455ffbae54771a8fbeaa9f1d56441c0 [file]
#-------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#-------------------------------------------------------------
/*
* Local Response Normalization (LRN) layer.
*/
forward = function(matrix[double] X, int C, int Hin, int Win,
int N, double alpha, double beta, double K)
return (matrix[double] Y) {
/*
* Computes the forward pass for a Local Response Normalization
* (LRN) layer. The LRN layer performs a lateral normalization
* over channels at each spatial location.
*
* This is the cross-channel LRN used in AlexNet:
* `y_{x,y}^i = x_{x,y}^i / (K + alpha * sum_{j=max(0,i-n/2)}^{min(C-1,i+n/2)} (x_{x,y}^j)^2)^beta`
*
* Inputs:
* - X: Inputs, of shape (N, C*Hin*Win).
* - C: Number of input channels.
* - Hin: Input height.
* - Win: Input width.
* - N: Number of channels to sum over (i.e. size of local region).
* - alpha: Scaling parameter.
* - beta: Exponent parameter.
* - K: Additive constant to avoid divide-by-zero.
*
* Outputs:
* - Y: Outputs, of shape (N, C*Hin*Win).
*/
N_batch = nrow(X)
# Initialize output
Y = matrix(0, rows=N_batch, cols=C*Hin*Win)
# Reshape for easier manipulation
X_reshaped = matrix(X, rows=N_batch, cols=C*Hin*Win)
# Compute normalization
half_N = as.integer(N / 2)
for (i in 1:N_batch) {
# Get current sample
x = matrix(X_reshaped[i,], rows=C, cols=Hin*Win, byrow=TRUE)
y = matrix(0, rows=C, cols=Hin*Win)
# For each channel
for (c in 1:C) {
# Define the local region
j_start = max(1, c - half_N)
j_end = min(C, c + half_N)
# Compute sum of squares in the local region
scale = matrix(K, rows=1, cols=Hin*Win)
for (j in j_start:j_end) {
scale = scale + alpha * (x[j,])^2
}
# Apply normalization
y[c,] = x[c,] / (scale^beta)
}
# Reshape back and store
Y[i,] = matrix(y, rows=1, cols=C*Hin*Win, byrow=TRUE)
}
}
backward = function(matrix[double] dY, matrix[double] X, int C, int Hin, int Win,
int N, double alpha, double beta, double K)
return (matrix[double] dX) {
/*
* Computes the backward pass for a Local Response Normalization layer.
*
* Inputs:
* - dY: Gradient wrt Y, of shape (N, C*Hin*Win).
* - X: Inputs, of shape (N, C*Hin*Win).
* - C: Number of input channels.
* - Hin: Input height.
* - Win: Input width.
* - N: Number of channels to sum over.
* - alpha: Scaling parameter.
* - beta: Exponent parameter.
* - K: Additive constant.
*
* Outputs:
* - dX: Gradient wrt X, of shape (N, C*Hin*Win).
*/
N_batch = nrow(X)
# Initialize gradient
dX = matrix(0, rows=N_batch, cols=C*Hin*Win)
# Reshape for easier manipulation
X_reshaped = matrix(X, rows=N_batch, cols=C*Hin*Win)
dY_reshaped = matrix(dY, rows=N_batch, cols=C*Hin*Win)
half_N = as.integer(N / 2)
for (i in 1:N_batch) {
# Get current sample
x = matrix(X_reshaped[i,], rows=C, cols=Hin*Win, byrow=TRUE)
dy = matrix(dY_reshaped[i,], rows=C, cols=Hin*Win, byrow=TRUE)
dx = matrix(0, rows=C, cols=Hin*Win)
# First, compute the scale values for all channels
scale = matrix(K, rows=C, cols=Hin*Win)
for (c in 1:C) {
j_start = max(1, c - half_N)
j_end = min(C, c + half_N)
for (j in j_start:j_end) {
scale[c,] = scale[c,] + alpha * (x[j,])^2
}
}
# Compute gradients
for (c in 1:C) {
# Channels that this channel influences
k_start = max(1, c - half_N)
k_end = min(C, c + half_N)
for (k in k_start:k_end) {
if (k == c) {
# Gradient from own normalization
dx[c,] = dx[c,] + dy[k,] * scale[k,]^(-beta)
}
# Gradient from normalizing other channels
dx[c,] = dx[c,] - 2 * alpha * beta * dy[k,] * x[k,] * x[c,] * scale[k,]^(-beta-1)
}
}
# Reshape back and store
dX[i,] = matrix(dx, rows=1, cols=C*Hin*Win, byrow=TRUE)
}
}