<commit_before>/*******************************************************************************
 * Copyright (c) 2015-2018 Skymind, Inc.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License, Version 2.0 which is available at
 * https://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.
 *
 * SPDX-License-Identifier: Apache-2.0
 ******************************************************************************/

//
// @author <NAME> (<EMAIL>), created on 19.04.2018
// @author <EMAIL>
//

#include <ops/declarable/helpers/activations.h>
#include <helpers/ShapeUtils.h>
#include <numeric>
#include <helpers/ConstantTadHelper.h>
#include <execution/Threads.h>

namespace sd {
    namespace ops {
        namespace helpers {

            template <typename T>
            static void softMaxForVector_(void *input, Nd4jLong *inShapeInfo, void *output, Nd4jLong *outShapeInfo) {

                T* inBuff  = reinterpret_cast<T *>(input);
                T* outBuff = reinterpret_cast<T *>(output);

                T max = -DataTypeUtils::max<T>();
                T sum = 0.;
                int inEWS = shape::elementWiseStride(inShapeInfo);
                int outEWS = shape::elementWiseStride(outShapeInfo);
                int length = shape::length(inShapeInfo);

                if (inEWS >= 1 && outEWS >= 1) {

                    if (inEWS == 1 && outEWS == 1) {

                        for (int i = 0; i < length; i++)
                            max = sd::math::nd4j_max<T>(max, inBuff[i]);

                        for (int i = 0; i < length; i++) {
                            outBuff[i] = sd::math::nd4j_exp<T, T>(inBuff[i] - max);
                            sum += outBuff[i];
                        }

                        for (int i = 0; i < length; i++)
                            outBuff[i] /= sum;
                    }
                    else {

                        for (int i = 0; i < length; i++)
                            max = sd::math::nd4j_max<T>(max, inBuff[i * inEWS]);

                        for (int i = 0; i < length; i++) {
                            T r = sd::math::nd4j_exp<T, T>(inBuff[i * inEWS] - max);
                            outBuff[i * outEWS] = r;
                            sum += r;
                        }

                        for (int i = 0; i < length; i++)
                            outBuff[i * outEWS] /= sum;
                    }
                }
            }

            ///////////////////////////////////////////////////////////////////
            void softMaxForVector(sd::LaunchContext * context, const NDArray& input, NDArray& output) {

                if(!input.isVector() || !output.isVector())
                    throw std::runtime_error("ops::helpers::softMaxForVector function: input and output arrays must be vectors !");

                auto xType = input.dataType();
                BUILD_SINGLE_SELECTOR(xType, softMaxForVector_, (input.getBuffer(), input.getShapeInfo(), output.buffer(), output.shapeInfo()), FLOAT_TYPES);
            }

            template <typename T>
            void softmax_loop(T *input, T *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen);

            template <>
            FORCEINLINE void softmax_loop(float *input, float *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen) {
                auto func = PRAGMA_THREADS_FOR {
                    for (auto i = start; i < stop; i++) {
                        auto inBuff = input + offsets[i];
                        auto outBuff = output + offsets[i];

                        float max = -DataTypeUtils::max<float>();
                        float sum = 0.f;

#pragma omp simd reduction(max:max)
                        for (uint j = 0; j < tadLen; ++j)
                            max = sd::math::nd4j_max<float>(max, inBuff[j]);

#pragma omp simd reduction(+:sum)
                        for (uint j = 0; j < tadLen; ++j) {
                            float temp = sd::math::nd4j_exp<float, float>(inBuff[j] - max);
                            outBuff[j] = temp;
                            sum += temp;
                        }

                        for (uint j = 0; j < tadLen; ++j)
                            outBuff[j] /= sum;
                    }
                };

                samediff::Threads::parallel_tad(func,0, numOfSubArrs);
            }


            template <typename T>
            FORCEINLINE void softmax_loop(T *input, T *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen) {
                auto func = PRAGMA_THREADS_FOR {
                    for (auto i = start; i < stop; i++) {
                        auto inBuff = input + offsets[i];
                        auto outBuff = output + offsets[i];

                        T max = -DataTypeUtils::max<T>();
                        T sum(0.f);

#pragma omp simd reduction(maxT:max)
                        for (uint j = 0; j < tadLen; ++j)
                            max = sd::math::nd4j_max<T>(max, inBuff[j]);

#pragma omp simd reduction(sumT:sum)
                        for (uint j = 0; j < tadLen; ++j) {
                            T temp = sd::math::nd4j_exp<T, T>(inBuff[j] - max);
                            outBuff[j] = temp;
                            sum += temp;
                        }
<commit_msg>separate omp impl for softmax (#289)<commit_after>/*******************************************************************************
 * Copyright (c) 2015-2018 Skymind, Inc.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License, Version 2.0 which is available at
 * https://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.
 *
 * SPDX-License-Identifier: Apache-2.0
 ******************************************************************************/

//
// @author <NAME> (<EMAIL>), created on 19.04.2018
// @author <EMAIL>
//

#include <ops/declarable/helpers/activations.h>
#include <helpers/ShapeUtils.h>
#include <numeric>
#include <helpers/ConstantTadHelper.h>
#include <execution/Threads.h>

namespace sd {
    namespace ops {
        namespace helpers {

            template <typename T>
            static void softMaxForVector_(void *input, Nd4jLong *inShapeInfo, void *output, Nd4jLong *outShapeInfo) {

                T* inBuff  = reinterpret_cast<T *>(input);
                T* outBuff = reinterpret_cast<T *>(output);

                T max = -DataTypeUtils::max<T>();
                T sum = 0.;
                int inEWS = shape::elementWiseStride(inShapeInfo);
                int outEWS = shape::elementWiseStride(outShapeInfo);
                int length = shape::length(inShapeInfo);

                if (inEWS >= 1 && outEWS >= 1) {

                    if (inEWS == 1 && outEWS == 1) {

                        for (int i = 0; i < length; i++)
                            max = sd::math::nd4j_max<T>(max, inBuff[i]);

                        for (int i = 0; i < length; i++) {
                            outBuff[i] = sd::math::nd4j_exp<T, T>(inBuff[i] - max);
                            sum += outBuff[i];
                        }

                        for (int i = 0; i < length; i++)
                            outBuff[i] /= sum;
                    }
                    else {

                        for (int i = 0; i < length; i++)
                            max = sd::math::nd4j_max<T>(max, inBuff[i * inEWS]);

                        for (int i = 0; i < length; i++) {
                            T r = sd::math::nd4j_exp<T, T>(inBuff[i * inEWS] - max);
                            outBuff[i * outEWS] = r;
                            sum += r;
                        }

                        for (int i = 0; i < length; i++)
                            outBuff[i * outEWS] /= sum;
                    }
                }
            }

            ///////////////////////////////////////////////////////////////////
            void softMaxForVector(sd::LaunchContext * context, const NDArray& input, NDArray& output) {

                if(!input.isVector() || !output.isVector())
                    throw std::runtime_error("ops::helpers::softMaxForVector function: input and output arrays must be vectors !");

                auto xType = input.dataType();
                BUILD_SINGLE_SELECTOR(xType, softMaxForVector_, (input.getBuffer(), input.getShapeInfo(), output.buffer(), output.shapeInfo()), FLOAT_TYPES);
            }

            template <typename T>
            void softmax_loop(T *input, T *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen);
#ifdef _OPENMP
            template <>
            FORCEINLINE void softmax_loop(float *input, float *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen) {
#pragma omp parallel for
                    for (Nd4jLong i = 0; i < numOfSubArrs; i++) {
                        auto inBuff = input + offsets[i];
                        auto outBuff = output + offsets[i];

                        float max = -DataTypeUtils::max<float>();
                        float sum = 0.f;

#pragma omp simd reduction(max:max)
                        for (uint j = 0; j < tadLen; ++j)
                            max = sd::math::nd4j_max<float>(max, inBuff[j]);

#pragma omp simd reduction(+:sum)
                        for (uint j = 0; j < tadLen; ++j) {
                            float temp = sd::math::nd4j_exp<float, float>(inBuff[j] - max);
                            outBuff[j] = temp;
                            sum += temp;
                        }

                        for (uint j = 0; j < tadLen; ++j)
                            outBuff[j] /= sum;
                    }
            }
#else
            template <>
            FORCEINLINE void softmax_loop(float *input, float *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen) {
                auto func = PRAGMA_THREADS_FOR {
                    for (auto i = start; i < stop; i++) {
                        auto inBuff = input + offsets[i];
                        auto outBuff = output + offsets[i];

                        float max = -DataTypeUtils::max<float>();
                        float sum = 0.f;

                        for (uint j = 0; j < tadLen; ++j)
                            max = sd::math::nd4j_max<float>(max, inBuff[j]);

                        for (uint j = 0; j < tadLen; ++j) {
                            float temp = sd::math::nd4j_exp<float, float>(inBuff[j] - max);
                            outBuff[j] = temp;
                            sum += temp;
                        }

                        for (uint j = 0; j < tadLen; ++j)
                            outBuff[j] /= sum;
                    }
                };

                samediff::Threads::parallel_tad(func,0, numOfSubArrs);
            }

#endif


            template <typename T>
            FORCEINLINE void softmax_loop(T *input, T *output, Nd4jLong *offsets, Nd4jLong numOfSubArrs, uint32_t tadLen) {
                auto func = PRAGMA_THREADS_FOR {
                    for (auto i = start; i < stop; i++) {
                        auto inBuff = input + offsets[i];
                        auto outBuff = output + offsets[i];

                        T max = -DataTypeUtils::max<T>();
                        T sum(0.f);

#pragma omp simd reduction(maxT:max)
                        for (uint j = 0; j < tadLen; ++j)
                            max = sd::math::nd4j_max<T>(max, inBuff[j]);

#pragma omp simd reduction(sumT:sum)
                        for (uint j = 0; j < tadLen; ++j) {
                            T temp = sd::math::nd4j_exp<T, T>(inBuff[j] - max);
                            outBuff[j] = temp;
                            sum += temp;
                        }

{'fraction_non_alphanumeric': 0.14553764734183305, 'fraction_numerical': 0.011306230454654799, 'mean_word_length': 1.3765243902439024, 'pattern_counts': {'":': 0, '<': 87, '<?xml version=': 0, '>': 61, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '368822', 'n_tokens_mistral': 3622, 'n_tokens_neox': 3347, 'n_words': 918}