         for (int c = 0; c < colorsPerThread; c++) {
             #pragma unroll
             for (int i = 0; i < imgsPerThread; i++) {
-                targets[c * B_Y * imgSizeY * imgSizeX * numImages + i * B_X] = scaleOutputs * prod[c][i];
+                if (!checkCaseBounds || myCaseIdx + i * B_X < numImages) {
+                    targets[c * B_Y * imgPixels * numImages + i * B_X] = scaleOutputs * prod[c][i];
+                }
             }
         }
     }

//    printf("numImages: %d\n", numImages);
//    cudaStream_t stream = NVMatrix::getDefaultStream();

    checkCudaErrors(cudaDeviceSetSharedMemConfig(cudaSharedMemBankSizeEightByte));
    
    if (conv == true) {
        if (scale == false) {
            if (checkCaseBounds == false) {

//    const float* fLoad = conv ? &filters[pxIdxInFilter * numFilters + 0]
//                              : &filters[moduleIdx * numFilterColors * filterPixels * numFilters + pxIdxInFilter * numFilters + 0];
    int filtersLoadOffset = filtersOffset + (conv ? pxIdxInFilter * numFilters + 0
                                                  : moduleIdx * numFilterColors * filterPixels * numFilters + pxIdxInFilter * numFilters);
    #pragma unroll
    for (int i = 0; i < colorsPerThread*B_Y; i+= B_X*B_Y/filterCacheF) {
        if ((colorsPerThread*B_Y) % (B_X*B_Y/filterCacheF) == 0 || i + filtersLoadY < colorsPerThread*B_Y) {
            wPreload[i * filterCacheF/(B_X*B_Y)] = tex1Dfetch<float>(filters, filtersLoadOffset + i * filterPixels * numFilters);
        }
    }

//    const float* hLoad = &hidActs[(moduleIdx + 0 * numModules) * numImages];
    int hidActsLoadOffset = hidActsOffset + (moduleIdx + 0 * numModules) * numImages;
    #pragma unroll
    for (int j = 0; j < filterCacheH; j += B_Y) {
        if (filterCacheH % B_Y == 0 || threadIdx.y + j < filterCacheH) {
            #pragma unroll
            for (int i = 0; i < imgsPerThread; i++) {
                if (!checkCaseBounds || myCaseIdx + i * B_X < numImages) {
                    hPreload[j/B_Y][i] = tex1Dfetch<float>(hidActs, hidActsLoadOffset + j * numModules * numImages + i * B_X);
                }
            }
        }
    }

    for (int my = startY; my < endY; my++) {
        const int moduleTop = paddingStart + my * moduleStride;
        const int pxInFilterY = blockPixelIdxY - moduleTop;

        for (int mx = startX; mx < endX; mx++) {
            moduleIdx = my * numModulesX + mx;
            const int moduleLeft = paddingStart + mx * moduleStride;
            const int pxInFilterX = blockPixelIdxX - moduleLeft;

            pxIdxInFilter = pxInFilterY * filterSize + pxInFilterX;
            int myNext = my, mxNext = mx, moduleIdxNext, pxIdxInFilterNext;
            const bool lastModule = my == endY - 1 && mx == endX - 1;
            if (!lastModule) {
                mxNext = mx + 1 == endX ? startX : mx + 1;
                myNext = my + (mx + 1 == endX);
            }
            conv_img_acts_manycolor_preload_ty_8_tx_32_c_8_ff_32_fh_16_setCoords(myNext, mxNext, numModulesX, paddingStart, moduleStride, blockPixelIdxY,
                                                                                 blockPixelIdxX, filterSize, moduleIdxNext, pxIdxInFilterNext);
            for (int f = 0; f < numFiltersPerGroup; f += filterCacheF) { // multiply with filterCacheF filters at a time
                #pragma unroll
                for (int i = 0; i < colorsPerThread*B_Y; i+= B_X*B_Y/filterCacheF) {
                    if ((colorsPerThread*B_Y) % (B_X*B_Y/filterCacheF) == 0 || i + filtersLoadY < colorsPerThread*B_Y) {
                        shFilterLoad[i * filterCacheF] = wPreload[i * filterCacheF/(B_X*B_Y)];
                    }
                }

                filtersLoadOffset = filtersOffset + (conv ? pxIdxInFilter * numFilters + f + filterCacheF
                                                          : moduleIdx * numFilterColors * filterPixels * numFilters + pxIdxInFilter * numFilters + f + filterCacheF);
                if (f == numFiltersPerGroup - filterCacheF) {
                    filtersLoadOffset = filtersOffset + (conv ? pxIdxInFilterNext * numFilters
                                                              : moduleIdxNext * numFilterColors * filterPixels * numFilters + pxIdxInFilterNext * numFilters);
                }

                #pragma unroll
                for (int j = 0; j < filterCacheH; j += B_Y) {
                    if (filterCacheH % B_Y == 0 || threadIdx.y + j < filterCacheH) {
                        #pragma unroll
                        for (int i = 0; i < imgsPerThread; i++) {
                            // NOTE: bank conflicts here!
                            if (!checkCaseBounds || myCaseIdx + i * B_X < numImages) {
                                shHidActLoad[j * B_X * imgsPerThread + i] = hPreload[j/B_Y][i];
                            }
                        }
                    }
                }

                __syncthreads();

                hidActsLoadOffset = hidActsOffset + (moduleIdx + (f + filterCacheH) * numModules) * numImages;

                #pragma unroll
                for (int z = 0; z < 4; ++z) {
                    IA_PRELOAD_LOOP(z,0);
                    IA_PRELOAD_W_TX(z);
                }

                #pragma unroll
                for (int z = 4; z < 12; ++z) {
                    IA_PRELOAD_LOOP(z,0);
                    IA_PRELOAD_H_TX((z-4)/4,z%4);
                }

                #pragma unroll
                for (int z = 12; z < 16; ++z) {
                    IA_PRELOAD_LOOP(z,0);
                }

                __syncthreads();

                #pragma unroll
                for (int j = 0; j < filterCacheH; j += B_Y) {
                    if (filterCacheH % B_Y == 0 || threadIdx.y + j < filterCacheH) {
                        #pragma unroll
                        for (int i = 0; i < imgsPerThread; i++) {
                            if (!checkCaseBounds || myCaseIdx + i * B_X < numImages) {
                                shHidActLoad[j * B_X * imgsPerThread + i] = hPreload[j/B_Y][i];
                            }
                        }
                    }
                }

                __syncthreads();

                hidActsLoadOffset = hidActsOffset + (moduleIdx + (f + filterCacheF) * numModules) * numImages;
                if (f == numFiltersPerGroup - filterCacheF) {
                    hidActsLoadOffset = hidActsOffset + moduleIdxNext * numImages;
                }

                #pragma unroll
                for (int z = 0; z < 4; ++z) {
                    IA_PRELOAD_LOOP(z,filterCacheH);
                    IA_PRELOAD_W_TX(z+4);
                }

                #pragma unroll
                for (int z = 4; z < 12; ++z) {
                    IA_PRELOAD_LOOP(z,filterCacheH);
                    IA_PRELOAD_H_TX((z-4)/4, z%4);
                }

                #pragma unroll
                for (int z = 12; z < 16; ++z) {
                    IA_PRELOAD_LOOP(z,filterCacheH);
                }

                __syncthreads();
            }
        }
    }
    if (scale) {
        #pragma unroll
        for (int c = 0; c < colorsPerThread; c++) {
            #pragma unroll
            for (int i = 0; i < imgsPerThread; i++) {
                if (!checkCaseBounds || myCaseIdx + i * B_X < numImages) {
                    targets[c * B_Y * imgPixels * numImages + i * B_X] = scaleTargets * targets[c * B_Y * imgPixels * numImages + i * B_X] + scaleOutputs * prod[c][i];
                }
            }
        }
    } else {
