Skip to content
Snippets Groups Projects
Commit 73b0bcd6 authored by Maxence Naud's avatar Maxence Naud
Browse files

Merge branch 'dev' into 'main'

version 0.2.0

See merge request !15
parents 91a067d9 3adf3096
Branches dev main
Tags v0.2.0
No related merge requests found
Pipeline #61803 failed
Showing
with 980 additions and 31 deletions
# common
.cache
# C++ Build # C++ Build
build*/ build*/
install*/ install*/
...@@ -6,10 +9,13 @@ install*/ ...@@ -6,10 +9,13 @@ install*/
.vscode .vscode
# Python # Python
aidge_quantization/_version.py
*.so *.so
__pycache__ __pycache__
*.pyc *.pyc
*.egg-info *.egg-info
aidge_quantization/_version.py
wheelhouse/*
# Mermaid # Mermaid
*.mmd *.mmd
...@@ -18,4 +24,4 @@ __pycache__ ...@@ -18,4 +24,4 @@ __pycache__
xml*/ xml*/
# ONNX # ONNX
*.onnx *.onnx
\ No newline at end of file
###############################################################################
# Aidge Continuous Integration and Deployment #
# #
###############################################################################
stages:
- static_analysis
- build
- test
- coverage
- release
- deploy
include:
- project: 'eclipse/aidge/gitlab_shared_files'
ref: 'main'
file:
# choose which jobs to run by including the corresponding files.
- '.gitlab/ci/ubuntu_cpp.gitlab-ci.yml'
- '.gitlab/ci/ubuntu_python.gitlab-ci.yml'
- '.gitlab/ci/release/cibuildwheel_ubuntu.gitlab-ci.yml'
- '.gitlab/ci/windows_cpp.gitlab-ci.yml'
- '.gitlab/ci/windows_python.gitlab-ci.yml'
- '.gitlab/ci/release/cibuildwheel_windows.gitlab-ci.yml'
test:ubuntu_python:
before_script:
- !reference [.retrieve_deps:apt, script]
- source venv/bin/activate
- python -m pip install numpy unittest-xml-reporting
- python -m pip list
- DEPS_NAMES=("aidge_onnx")
- DEPENDENCY_JOB="build:ubuntu_python"
- !reference [.ubuntu:download:artifacts, script]
coverage:ubuntu_python:
before_script:
- !reference [.retrieve_deps:apt, script]
- source venv/bin/activate
- python -m pip install numpy coverage
- DEPS_NAMES=("aidge_onnx")
- DEPENDENCY_JOB="build:ubuntu_python"
- !reference [.ubuntu:download:artifacts, script]
release:pip:ubuntu:
before_script:
- !reference [.retrieve_deps:apt, script]
- DEPS_NAMES=("aidge_core" "aidge_backend_cpu" "aidge_onnx")
- DEPENDENCY_JOB="build:ubuntu_python"
- !reference [.ubuntu:download:repositories, script] # located in common.gitlab-ci.yml
- curl -sSL https://get.docker.com/ | sh
release:pip:windows:
before_script:
- (Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture
- (Get-WmiObject -Class Win32_OperatingSystem).Caption
- $PSVersionTable.PSVersion
# Install Chocolatey
- Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install dependencies
- choco install cmake.install --installargs '"ADD_CMAKE_TO_PATH=System"' -Y
- choco install git -Y
- choco install python --version=$python_version -Y
# Update PATH
- $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
- python -m pip install cibuildwheel==2.17.0
# Download repositories
- $DEPS_NAMES = "aidge_core","aidge_backend_cpu","aidge_onnx"
- $DEPENDENCY_JOB="build:windows_python"
- !reference [.windows:download:repositories, script]
$ErrorActionPreference = "Stop"
# Retrieve and clean the dependencies string from the environment variable
$AIDGE_DEPENDENCIES = $env:AIDGE_DEPENDENCIES -split ' '
Write-Host "Aidge dependencies : $AIDGE_DEPENDENCIES"
if ( $($AIDGE_DEPENDENCIES.Length) -eq 0) {
Write-Host "- No dependencies provided for current repsitory"
New-Item -ItemType Directory -Force -Path ".\build" | Out-Null
Remove-Item -Path ".\build\*" -Recurse -Force
} else {
Write-Host "Retrieving given dependencies to build current package : $AIDGE_DEPENDENCIES"
foreach ($dep in $($AIDGE_DEPENDENCIES -split " ")) {
Write-Host "Retrieving : $dep"
$curr_loc=$(Get-Location)
Set-Location ../$dep
Get-Location
Get-ChildItem .
New-Item -Path ".\build" -ItemType Directory -Force | Out-Null
Get-ChildItem -Path ".\build" -File | Remove-Item -Force
python -m pip install . -v
Set-Location $curr_loc
}
}
#!/bin/bash
set -e
if [[ "$1" == "" ]]; then
echo "build aidge deps in cibuildwheel container before building wheel."
echo "search path defines where the dependencies will be searched."
echo "Hint : In wheel containers, files are mounted on /host by default."
echo "\nusage : ./cibuildwheel_build_deps_before_build_wheel.sh $search_path"
fi
set -x
if [[ $AIDGE_DEPENDENCIES == "" ]]; then # case for aidge_ core
mkdir -p build # creating build if its not already there to hold the build of cpp files
rm -rf build/* # build from scratch
else
for repo in $AIDGE_DEPENDENCIES ; do # case for other projects
search_path=$1
REPO_PATH=$(find $search_path ! -writable -prune -o -type d \
-name "$repo" \
-not -path "*/install/*" \
-not -path "*/.git/*" \
-not -path "*/miniconda/*" \
-not -path "*/conda/*" \
-not -path "*/.local/*" \
-not -path "*/lib/*" \
-not -path "*/$repo/$repo/*" \
-not -path "*/proc/*" \
-print -quit)
if [[ -z "$REPO_PATH" ]]; then
echo "ERROR : dependency $repo not found in search_path \"$search_path\". ABORTING."
exit -1
fi
cd $REPO_PATH
mkdir -p build # creating build if its not already there to hold the build of cpp files
rm -rf build/* # build from scratch
pip install . -v
cd -
done
fi
set +x
set +e
...@@ -15,11 +15,10 @@ project(${project}) ...@@ -15,11 +15,10 @@ project(${project})
############################################## ##############################################
# Import utils CMakeLists # Import utils CMakeLists
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
include(PybindModuleCreation)
############################################## ##############################################
# Define options # Define options
option(PYBIND "python binding" ON) option(PYBIND "python binding" OFF)
option(WERROR "Warning as error" OFF) option(WERROR "Warning as error" OFF)
option(TEST "Enable tests" ON) option(TEST "Enable tests" ON)
option(COVERAGE "Enable coverage" OFF) option(COVERAGE "Enable coverage" OFF)
...@@ -33,8 +32,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND COVERAGE) ...@@ -33,8 +32,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND COVERAGE)
Include(CodeCoverage) Include(CodeCoverage)
endif() endif()
# XXX HERE !!!
# ############################################## # ##############################################
# Find system dependencies # Find system dependencies
Include(FetchContent) Include(FetchContent)
...@@ -49,8 +46,6 @@ set(FMT_SYSTEM_HEADERS ON) ...@@ -49,8 +46,6 @@ set(FMT_SYSTEM_HEADERS ON)
FetchContent_MakeAvailable(fmt) FetchContent_MakeAvailable(fmt)
set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON)
############################################## ##############################################
# Find system dependencies # Find system dependencies
find_package(aidge_core REQUIRED) find_package(aidge_core REQUIRED)
...@@ -81,14 +76,15 @@ target_include_directories(${module_name} ...@@ -81,14 +76,15 @@ target_include_directories(${module_name}
# PYTHON BINDING # PYTHON BINDING
if (PYBIND) if (PYBIND)
generate_python_binding(${project} ${module_name})
# Handles Python + pybind11 headers dependencies # Handles Python + pybind11 headers dependencies
include(PybindModuleCreation)
generate_python_binding(${CMAKE_PROJECT_NAME} ${module_name})
target_link_libraries(${module_name} target_link_libraries(${module_name}
PUBLIC PUBLIC
pybind11::pybind11 pybind11::pybind11
PRIVATE PRIVATE
Python::Python Python::Module
) )
endif() endif()
...@@ -109,6 +105,10 @@ endif() ...@@ -109,6 +105,10 @@ endif()
############################################## ##############################################
# Installation instructions # Installation instructions
if(NOT $ENV{AIDGE_INSTALL} STREQUAL "")
set(CMAKE_INSTALL_PREFIX $ENV{AIDGE_INSTALL})
message(WARNING "CMAKE_INSTALL_PREFIX set to env variable AIDGE_INSTALL by default = ${CMAKE_INSTALL_PREFIX}")
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${project}) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${project})
...@@ -158,6 +158,9 @@ export(EXPORT ${project}-targets ...@@ -158,6 +158,9 @@ export(EXPORT ${project}-targets
############################################## ##############################################
## Add test ## Add test
if(TEST) if(TEST)
if(PYBIND)
message(FATAL_ERROR "PYBIND and TEST are both enabled. But cannot compile with catch_2.\nChoose between pybind and Catch2 for compilation.")
endif()
enable_testing() enable_testing()
add_subdirectory(unit_tests) add_subdirectory(unit_tests)
endif() endif()
include README.md LICENCE
recursive-include aidge_quantization *.py
recursive-exclude aidge_quantization/unit_tests *.py
recursive-include include *.hpp
recursive-include src *.cpp
recursive-include python_binding *.cpp
include CMakeLists.txt
# Aidge Quantization Module # Aidge Quantization Module
You can find in this folder the library that implements the quantization algorithms. You can find in this folder the library that implements the quantization algorithms.
For the moment only Post Training Quantization (PTQ) is available. For the moment only Post Training Quantization (PTQ) is available.
Its implementation does support multiple branch architectures. Its implementation does support multiple branch architectures.
[TOC]
## Installation
### Dependencies
- `GCC`
- `Make`/`Ninja`
- `CMake`
- `Python` (optional, if you have no intend to use this library in python with pybind)
#### Aidge dependencies
- `aidge_core`
The requirements for installing the library are the followings: The requirements for installing the library are the followings:
- GCC, Make and CMake for the compilation pipeline - GCC, Make and CMake for the compilation pipeline
- The AIDGE modules aidge_core, aidge_onnx and aidge_backend_cpu - The AIDGE modules aidge_core, aidge_onnx and aidge_backend_cpu
- Python (> 3.7) if you intend to use the pybind wrapper - Python (> 3.7) if you intend to use the pybind wrapper
## Pip installation ### Pip installation
In an environment which satisfies the previous requirements, run :
``` bash ``` bash
pip install . -v pip install . -v
``` ```
> **TIPS :** Use environment variables to change compilation options :
> - `AIDGE_INSTALL` : to set the installation folder. Defaults to /usr/local/lib. :warning: This path must be identical to aidge_core install path.
> - `AIDGE_PYTHON_BUILD_TYPE` : to set the compilation mode to **Debug** or **Release**
> - `AIDGE_BUILD_GEN` : to set the build backend with
## User guide ## User guide
......
import unittest import unittest
import gzip import gzip
import numpy as np import numpy as np
from pathlib import Path
import aidge_core import aidge_core
import aidge_backend_cpu import aidge_backend_cpu
import aidge_onnx import aidge_onnx
import aidge_quantization import aidge_quantization
from aidge_core import Log, Level
# -------------------------------------------------------------- # --------------------------------------------------------------
# CONFIGS # CONFIGS
# -------------------------------------------------------------- # --------------------------------------------------------------
...@@ -52,12 +55,13 @@ class test_ptq(unittest.TestCase): ...@@ -52,12 +55,13 @@ class test_ptq(unittest.TestCase):
# load the samples / labels (numpy) # load the samples / labels (numpy)
self.samples = np.load(gzip.GzipFile('assets/mnist_samples.npy.gz', "r")) curr_file_dir = Path(__file__).parent.resolve()
self.labels = np.load(gzip.GzipFile('assets/mnist_labels.npy.gz', "r")) self.samples = np.load(gzip.GzipFile(curr_file_dir / 'assets/mnist_samples.npy.gz', "r"))
self.labels = np.load(gzip.GzipFile(curr_file_dir / 'assets/mnist_labels.npy.gz', "r"))
# load the model in AIDGE # load the model in AIDGE
self.model = aidge_onnx.load_onnx("assets/" + MODEL_NAME, verbose=False) self.model = aidge_onnx.load_onnx(curr_file_dir / "assets/" / MODEL_NAME, verbose=False)
aidge_core.remove_flatten(self.model) aidge_core.remove_flatten(self.model)
self.model.set_datatype(aidge_core.dtype.float32) self.model.set_datatype(aidge_core.dtype.float32)
...@@ -69,15 +73,16 @@ class test_ptq(unittest.TestCase): ...@@ -69,15 +73,16 @@ class test_ptq(unittest.TestCase):
def test_model(self): def test_model(self):
Log.set_console_level(Level.Info)
# compute the base accuracy # compute the base accuracy
accuracy = compute_accuracy(self.model, self.samples[0:NB_SAMPLES], self.labels) accuracy = compute_accuracy(self.model, self.samples[0:NB_SAMPLES], self.labels)
self.assertAlmostEqual(accuracy * 100, ACCURACIES[0], msg='base accuracy does not meet the baseline !', delta=0.1) self.assertAlmostEqual(accuracy * 100, ACCURACIES[0], msg='base accuracy does not meet the baseline !', delta=0.1)
def test_quant_model(self): def test_quant_model(self):
# create the calibration dataset Log.set_console_level(Level.Info)
# create the calibration dataset
tensors = [] tensors = []
for sample in self.samples[0:NB_SAMPLES]: for sample in self.samples[0:NB_SAMPLES]:
sample = prepare_sample(sample) sample = prepare_sample(sample)
...@@ -109,4 +114,4 @@ class test_ptq(unittest.TestCase): ...@@ -109,4 +114,4 @@ class test_ptq(unittest.TestCase):
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
\ No newline at end of file
function(generate_python_binding name target_to_bind) function(generate_python_binding pybind_module_name target_to_bind)
add_definitions(-DPYBIND) add_definitions(-DPYBIND)
Include(FetchContent) Include(FetchContent)
set(PYBIND_VERSION v2.10.4)
set(PYBIND11_FINDPYTHON ON)
message(STATUS "Retrieving pybind ${PYBIND_VERSION} from git")
FetchContent_Declare( FetchContent_Declare(
PyBind11 PyBind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.10.4 # or a later release GIT_TAG ${PYBIND_VERSION} # or a later release
) )
# Use the New FindPython mode, recommanded. Requires CMake 3.15+ # Use the New FindPython mode, recommanded. Requires CMake 3.15+
find_package(Python COMPONENTS Interpreter Development) find_package(Python COMPONENTS Interpreter Development.Module)
FetchContent_MakeAvailable(PyBind11) FetchContent_MakeAvailable(PyBind11)
message(STATUS "Creating binding for module ${name}") message(STATUS "Creating binding for module ${pybind_module_name}")
file(GLOB_RECURSE pybind_src_files "python_binding/*.cpp") file(GLOB_RECURSE pybind_src_files "python_binding/*.cpp")
pybind11_add_module(${name} MODULE ${pybind_src_files} "NO_EXTRAS") # NO EXTRA recquired for pip install pybind11_add_module(${pybind_module_name} MODULE ${pybind_src_files} "NO_EXTRAS") # NO EXTRA recquired for pip install
target_include_directories(${name} PUBLIC "python_binding") target_include_directories(${pybind_module_name} PUBLIC "python_binding")
target_link_libraries(${name} PUBLIC ${target_to_bind}) target_link_libraries(${pybind_module_name} PUBLIC ${target_to_bind})
endfunction() endfunction()
// /********************************************************************************
// * Copyright (c) 2023 CEA-List
// *
// * This program and the accompanying materials are made available under the
// * terms of the Eclipse Public License 2.0 which is available at
// * http://www.eclipse.org/legal/epl-2.0.
// *
// * SPDX-License-Identifier: EPL-2.0
// *
// ********************************************************************************/
#ifndef AIDGE_QUANTIZATION_CPU_IMPORTS_H_
#define AIDGE_QUANTIZATION_CPU_IMPORTS_H_
#include "aidge/backend/cpu/operator/FixedQImpl.hpp"
#include "aidge/backend/cpu/operator/LSQImpl.hpp"
#include "aidge/backend/cpu/operator/SAT/TanhClampImpl.hpp"
#include "aidge/backend/cpu/operator/SAT/DoReFaImpl.hpp"
// ...
#endif /* AIDGE_QUANTIZATION_CPU_IMPORTS_H_ */
\ No newline at end of file
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_FIXEDQIMPL_H_
#define AIDGE_CPU_OPERATOR_FIXEDQIMPL_H_
#include <cstddef> // std::size_t
#include <memory>
#include <tuple> // std::tuple
#include <vector>
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/FixedQ.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// Operator implementation entry point for the backend
using FixedQImpl_cpu = OperatorImpl_cpu<FixedQ_Op,
void(const std::size_t, const float, const bool, const std::size_t, const void*, void*),
void(const std::size_t, const float, const bool, const std::size_t, const void*, const void*, void*)>;
// Implementation entry point registration to Operator
REGISTRAR(FixedQ_Op, "cpu", Aidge::FixedQImpl_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_FIXEDQIMPL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_FIXEDQIMPL_FORWARD_KERNEL_H_
#define AIDGE_CPU_OPERATOR_FIXEDQIMPL_FORWARD_KERNEL_H_
#include "aidge/utils/Registrar.hpp"
#include "aidge/backend/cpu/operator/FixedQImpl.hpp"
//#include <iostream>
namespace Aidge {
template <class I, class O>
void FixedQImpl_cpu_forward_kernel(
std::size_t nbBits,
float span_,
bool isOutputUnsigned,
std::size_t inputLenght,
const void* input_,
void* output_) {
I span = static_cast<I> (span_);
I stepSize = span / static_cast<I> (1 << (nbBits - 1));
if (isOutputUnsigned) {
stepSize /= 2;
}
const I upper = span - stepSize;
const I lower = isOutputUnsigned ? 0 : -span;
const I* input = static_cast<const I*>(input_);
O* output = static_cast<O*>(output_);
for (std::size_t i = 0; i < inputLenght; ++i) {
I clipped = std::max(lower, std::min(input[i], upper));
output[i] = std::round(clipped / stepSize) * stepSize;
}
}
template <class I, class GI, class GO>
void FixedQImpl_cpu_backward_kernel(
std::size_t nbBits,
float span_,
bool isOutputUnsigned,
const std::size_t inputLenght,
const void* input_,
const void* grad_output_,
void* grad_input_) {
I span = static_cast<I> (span_);
I stepSize = span / static_cast<I> (1 << (nbBits - 1));
if (isOutputUnsigned) {
stepSize /= 2;
}
const I upper = span - stepSize;
const I lower = isOutputUnsigned ? 0 : -span;
const I* input = static_cast<const I*>(input_);
const GO* grad_output = static_cast<const GO*>(grad_output_);
GI* grad_input = static_cast<GI*>(grad_input_);
for (std::size_t i = 0; i < inputLenght; ++i) {
// Clipped Straight Through Estimator
grad_input[i] = ((input[i] > lower) && (input[i] < upper)) ? grad_output[i] : 0;
}
}
// Kernels registration to implementation entry point
REGISTRAR(FixedQImpl_cpu,
{{DataType::Int32, DataFormat::NCHW}, {DataType::Int32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::FixedQImpl_cpu_forward_kernel<int, int>, Aidge::FixedQImpl_cpu_backward_kernel<int, int, int>});
REGISTRAR(FixedQImpl_cpu,
{{DataType::Float32, DataFormat::NCHW}, {DataType::Float32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::FixedQImpl_cpu_forward_kernel<float, float>, Aidge::FixedQImpl_cpu_backward_kernel<float, float, float>});
REGISTRAR(FixedQImpl_cpu,
{{DataType::Float64, DataFormat::NCHW}, {DataType::Float64, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::FixedQImpl_cpu_forward_kernel<double, double>, Aidge::FixedQImpl_cpu_backward_kernel<double, double, double>});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_FIXEDQIMPL_FORWARD_KERNEL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_LSQIMPL_H_
#define AIDGE_CPU_OPERATOR_LSQIMPL_H_
#include <cstddef> // std::size_t
#include <memory>
#include <tuple> // std::tuple
#include <vector>
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/LSQ.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// compute kernel registry for forward and backward
using LSQImpl_cpu = OperatorImpl_cpu<LSQ_Op,
void(const std::size_t,
std::pair<int, int>&,
const void*,
const void*,
void*),
void(const std::size_t,
std::pair<int, int>&,
const void*,
const void*,
const void*,
void*,
void*)>;
// Implementation entry point registration to Operator
REGISTRAR(LSQ_Op, "cpu", Aidge::LSQImpl_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_LSQIMPL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_LSQIMPL_FORWARD_KERNEL_H_
#define AIDGE_CPU_OPERATOR_LSQIMPL_FORWARD_KERNEL_H_
#include "aidge/utils/Registrar.hpp"
#include "aidge/backend/cpu/operator/LSQImpl.hpp"
namespace Aidge {
template <class I, class O>
void LSQImpl_cpu_forward_kernel(std::size_t inputLength,
const std::pair<int, int>& range,
const void* input_,
const void* stepSize_,
void* output_)
{
const I* input = static_cast<const I*>(input_);
const I* stepSize = static_cast<const I*>(stepSize_);
O* output = static_cast<O*>(output_);
const O bitRangesLowerBound = static_cast<O>(range.first * stepSize[0]);
const O bitRangesUpperBound = static_cast<O>(range.second * stepSize[0]);
//#pragma omp parallel for if (inputLength > 16)
for (unsigned int i = 0; i < inputLength; i++) {
const O qData = input[i] / stepSize[0];
output[i] =
(qData <= static_cast<O>(range.first)) ? bitRangesLowerBound :
(qData >= static_cast<O>(range.second)) ? bitRangesUpperBound :
std::round(qData) * stepSize[0];
}
}
template <class I, class GI, class GO>
void LSQImpl_cpu_backward_kernel(const std::size_t inputLength,
const std::pair<int, int>& range,
const void* input_,
const void* stepSize_,
const void* grad_output_,
void* grad_input_,
void* grad_stepSize_)
{
const I* input = static_cast<const I*>(input_);
const I* stepSize = static_cast<const I*>(stepSize_);
const GO* grad_output = static_cast<const GO*>(grad_output_);
GI* grad_input = static_cast<GI*>(grad_input_);
GI* grad_stepSize = static_cast<GI*>(grad_stepSize_);
GI diffStepSize = GI(0.0);
#pragma omp parallel for schedule(static, 256) reduction(+:diffStepSize) if(inputLength > 16)
for(unsigned int i=0; i < inputLength / 4; i++) {
const GI fullPrecScale_1 = input[4*i] / stepSize[0];
const GI fullPrecScale_2 = input[4*i+1] / stepSize[0];
const GI fullPrecScale_3 = input[4*i+2] / stepSize[0];
const GI fullPrecScale_4 = input[4*i+3] / stepSize[0];
/*****************Features Gradient Computation********************/
// STE method is simply applied
grad_input[4*i] = grad_output[4*i]*((fullPrecScale_1 <= static_cast<GI>(range.first)) ? GI(0.0) :
(fullPrecScale_1 >= static_cast<GI>(range.second)) ? GI(0.0) :
GI(1.0));
grad_input[4*i+1] = grad_output[4*i+1]*((fullPrecScale_2 <= static_cast<GI>(range.first)) ? GI(0.0) :
(fullPrecScale_2 >= static_cast<GI>(range.second)) ? GI(0.0) :
GI(1.0));
grad_input[4*i+2] = grad_output[4*i+2]*((fullPrecScale_3 <= static_cast<GI>(range.first)) ? GI(0.0) :
(fullPrecScale_3 >= static_cast<GI>(range.second)) ? GI(0.0) :
GI(1.0));
grad_input[4*i+3] = grad_output[4*i+3]*((fullPrecScale_4 <= static_cast<GI>(range.first)) ? GI(0.0) :
(fullPrecScale_4 >= static_cast<GI>(range.second)) ? GI(0.0) :
GI(1.0));
/*****************Step Size Gradient Computation******************/
//1st: clip the gradient in interval [rangeMin, rangeMax] and take account of qError
GI qData_1 = fullPrecScale_1;
qData_1 = ((qData_1 <= static_cast<GI>(range.first)) ? static_cast<GI>(range.first) :
(qData_1 >= static_cast<GI>(range.second)) ? static_cast<GI>(range.second) :
round(qData_1) - qData_1);
GI qData_2 = fullPrecScale_2;
qData_2 = ((qData_2 <= static_cast<GI>(range.first)) ? static_cast<GI>(range.first) :
(qData_2 >= static_cast<GI>(range.second)) ? static_cast<GI>(range.second) :
round(qData_2) - qData_2);
GI qData_3 = fullPrecScale_3;
qData_3 = ((qData_3 <= static_cast<GI>(range.first)) ? static_cast<GI>(range.first) :
(qData_3 >= static_cast<GI>(range.second)) ? static_cast<GI>(range.second) :
round(qData_3) - qData_3);
GI qData_4 = fullPrecScale_4;
qData_4 = ((qData_4 <= static_cast<GI>(range.first)) ? static_cast<GI>(range.first) :
(qData_4 >= static_cast<GI>(range.second)) ? static_cast<GI>(range.second) :
round(qData_4) - qData_4);
//2nd: Multiplie backward data with clipped grad
diffStepSize += ((qData_1*grad_output[4*i] + qData_2*grad_output[4*i+1])+(qData_3*grad_output[4*i+2] + qData_4*grad_output[4*i+3]));
}
// Process remaining
for(unsigned int i=inputLength-inputLength%4; i<inputLength; ++i) {
const GI fullPrecScale = input[i] / stepSize[0];
grad_input[i] = grad_output[i]*((fullPrecScale <= static_cast<GI>(range.first)) ? GI(0.0) :
(fullPrecScale >= static_cast<GI>(range.second)) ? GI(0.0) :
GI(1.0));
GI qData = fullPrecScale;
qData = ((qData <= static_cast<GI>(range.first)) ? static_cast<GI>(range.first) :
(qData >= static_cast<GI>(range.second)) ? static_cast<GI>(range.second) :
round(qData) - qData);
diffStepSize += qData*grad_output[i];
}
const GI gradScaleFactor = static_cast<GI>(1.0f / std::sqrt(inputLength * range.second));
// 3rd: Multiply Step Size gradient with scale factor
grad_stepSize[0] = diffStepSize * gradScaleFactor;
}
// Kernels registration to implementation entry point
REGISTRAR(LSQImpl_cpu,
{{DataType::Float16, DataFormat::NCHW}, {DataType::Float16, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::LSQImpl_cpu_forward_kernel<half_float::half, half_float::half>, Aidge::LSQImpl_cpu_backward_kernel<half_float::half, half_float::half, half_float::half>});
REGISTRAR(LSQImpl_cpu,
{{DataType::Float32, DataFormat::NCHW}, {DataType::Float32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::LSQImpl_cpu_forward_kernel<float, float>, Aidge::LSQImpl_cpu_backward_kernel<float, float, float>});
REGISTRAR(LSQImpl_cpu,
{{DataType::Float64, DataFormat::NCHW}, {DataType::Float64, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::LSQImpl_cpu_forward_kernel<double, double>, Aidge::LSQImpl_cpu_backward_kernel<double, double, double>});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_LSQIMPL_FORWARD_KERNEL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_DOREFAIMPL_H_
#define AIDGE_CPU_OPERATOR_DOREFAIMPL_H_
#include <cstddef> // std::size_t
#include <memory>
#include <tuple> // std::tuple
#include <vector>
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/SAT/DoReFa.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// Operator implementation entry point for the backend
using DoReFaImpl_cpu = OperatorImpl_cpu<DoReFa_Op,
void(const std::size_t, float, DoReFaMode, const void*, void*),
void(const std::size_t, float, DoReFaMode, const void*, const void*, void*)>;
// Implementation entry point registration to Operator
REGISTRAR(DoReFa_Op, "cpu", Aidge::DoReFaImpl_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_DOREFAIMPL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_DOREFAIMPL_FORWARD_KERNEL_H_
#define AIDGE_CPU_OPERATOR_DOREFAIMPL_FORWARD_KERNEL_H_
#include "aidge/utils/Registrar.hpp"
#include "aidge/backend/cpu/operator/SAT/DoReFaImpl.hpp"
namespace Aidge {
template <class I, class O>
void DoReFaImpl_cpu_forward_kernel(std::size_t inputLength,
float range,
DoReFaMode mode,
const void* input_,
void* output_)
{
const I* input = static_cast<const I*>(input_);
O* output = static_cast<O*>(output_);
// Dorefa Quantization
//#pragma omp parallel for if (inputLength > 1024)
for (unsigned int i = 0; i < inputLength; ++i) {
if (mode == DoReFaMode::Default) {
auto q = I(0.5) * (input[i] + I(1.0));
q = O(1.0f / range) * O(std::rintf(q * range));
output[i] = q * O(2.0) - O(1.0);
}
else {
output[i] = O(1.0f / range) * O(std::rintf(input[i] * range));
}
}
}
template <class I, class GI, class GO>
void DoReFaImpl_cpu_backward_kernel(const std::size_t inputLength,
float /*range*/,
DoReFaMode /*mode*/,
const void* /*input_*/,
const void* grad_output_,
void* grad_input_)
{
const GO* grad_output = static_cast<const GO*>(grad_output_);
GI* grad_input = static_cast<GI*>(grad_input_);
//#pragma omp parallel for if (inputLength > 1024)
for (unsigned int i = 0; i < inputLength; ++i) {
grad_input[i] = grad_output[i];
}
}
// Kernels registration to implementation entry point
REGISTRAR(DoReFaImpl_cpu,
{{DataType::Int32, DataFormat::NCHW}, {DataType::Int32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::DoReFaImpl_cpu_forward_kernel<int, int>, Aidge::DoReFaImpl_cpu_backward_kernel<int, int, int>});
REGISTRAR(DoReFaImpl_cpu,
{{DataType::Float32, DataFormat::NCHW}, {DataType::Float32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::DoReFaImpl_cpu_forward_kernel<float, float>, Aidge::DoReFaImpl_cpu_backward_kernel<float, float, float>});
REGISTRAR(DoReFaImpl_cpu,
{{DataType::Float64, DataFormat::NCHW}, {DataType::Float64, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::DoReFaImpl_cpu_forward_kernel<double, double>, Aidge::DoReFaImpl_cpu_backward_kernel<double, double, double>});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_DOREFAIMPL_FORWARD_KERNEL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_H_
#define AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_H_
#include <cstddef> // std::size_t
#include <memory>
#include <tuple> // std::tuple
#include <vector>
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/SAT/TanhClamp.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// Operator implementation entry point for the backend
using TanhClampImpl_cpu = OperatorImpl_cpu<TanhClamp_Op,
void(const std::size_t, const void*, void*, void*),
void(const std::size_t, const void*, const void*, void*, void*)>;
// Implementation entry point registration to Operator
REGISTRAR(TanhClamp_Op, "cpu", Aidge::TanhClampImpl_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_KERNELS_H_
#define AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_KERNELS_H_
#include <cstddef> // std::size_t
#include <memory>
#include <tuple> // std::tuple
#include <vector>
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/backend/cpu/operator/SAT/TanhClampImpl.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// Kernels
template <class I, class O>
void TanhClampImpl_cpu_forward_kernel(std::size_t inputLength,
const void* input_,
void* scaling_,
void* output_)
{
const I* input = static_cast<const I*>(input_);
I scaling = *static_cast<I*>(scaling_);
O* output = static_cast<O*>(output_);
const auto minMax = std::minmax_element(input, input + inputLength);
const auto absMax = std::max(std::abs(*(minMax.first)), std::abs(*(minMax.second)));
scaling = std::tanh(absMax);
//#pragma omp parallel for if (inputLength > 1024)
for (unsigned int i = 0; i < inputLength; ++i) {
output[i] = std::tanh(input[i]) / scaling;
}
// Set the scaling output ...
*(static_cast<I*> (scaling_)) = scaling;
}
template <class I, class GI, class GO>
void TanhClampImpl_cpu_backward_kernel(const std::size_t inputLength,
const void* input_,
const void* scaling_,
const void* grad_output_,
void* grad_input_)
{
const I* input = static_cast<const I*>(input_);
const I scaling = *static_cast<const I*>(scaling_);
const GO* grad_output = static_cast<const GO*>(grad_output_);
GI* grad_input = static_cast<GI*>(grad_input_);
//#pragma omp parallel for if (inputLength > 1024)
for (unsigned int i = 0; i < inputLength; ++i) {
const auto inv_cosh = GO(1 / std::cosh(input[i]));
const auto grad = inv_cosh * inv_cosh * GO(1 / scaling);
grad_input[i] = grad_output[i] * grad;
}
}
// Kernels registration to implementation entry point
REGISTRAR(TanhClampImpl_cpu,
{{DataType::Int32, DataFormat::NCHW}, {DataType::Int32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::TanhClampImpl_cpu_forward_kernel<int, int>, Aidge::TanhClampImpl_cpu_backward_kernel<int, int, int>});
REGISTRAR(TanhClampImpl_cpu,
{{DataType::Float32, DataFormat::NCHW}, {DataType::Float32, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::TanhClampImpl_cpu_forward_kernel<float, float>, Aidge::TanhClampImpl_cpu_backward_kernel<float, float, float>});
REGISTRAR(TanhClampImpl_cpu,
{{DataType::Float64, DataFormat::NCHW}, {DataType::Float64, DataFormat::NCHW}},
{ProdConso::inPlaceModel, Aidge::TanhClampImpl_cpu_forward_kernel<double, double>, Aidge::TanhClampImpl_cpu_backward_kernel<double, double, double>});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_TANHCLAMPIMPL_KERNELS_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CORE_OPERATOR_FIXEDQ_H_
#define AIDGE_CORE_OPERATOR_FIXEDQ_H_
#include <cassert>
#include <memory>
#include <vector>
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/utils/ErrorHandling.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
#include "aidge/utils/StaticAttributes.hpp"
namespace Aidge {
enum class FixedQAttr { NbBits, Span, IsOutputUnsigned };
class FixedQ_Op : public OperatorTensor,
public Registrable<FixedQ_Op, std::string,
std::function<std::shared_ptr<OperatorImpl>(const FixedQ_Op&)>> {
public:
static const std::string Type;
private:
using Attributes_ = StaticAttributes<FixedQAttr, std::size_t, float, bool>;
template <FixedQAttr e> using attr = typename Attributes_::template attr<e>;
const std::shared_ptr<Attributes_> mAttributes;
public:
FixedQ_Op(std::size_t nbBits, float span, bool isOutputUnsigned) :
OperatorTensor(Type, {InputCategory::Data}, 1),
mAttributes(std::make_shared<Attributes_>(attr<FixedQAttr::NbBits>(nbBits), attr<FixedQAttr::Span>(span), attr<FixedQAttr::IsOutputUnsigned>(isOutputUnsigned)))
{}
/**
* @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated).
* @param op Operator to copy.
*/
FixedQ_Op(const FixedQ_Op& op)
: OperatorTensor(op), mAttributes(op.mAttributes)
{
if (op.mImpl){
SET_IMPL_MACRO(FixedQ_Op, *this, op.backend());
}else{
mImpl = nullptr;
}
}
/**
* @brief Clone the operator using its copy-constructor.
* @see Operator::FixedQ_Op
*/
std::shared_ptr<Operator> clone() const override {
return std::make_shared<FixedQ_Op>(*this);
}
std::set<std::string> getAvailableBackends() const override final;
void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
inline std::size_t& nbBits() const noexcept { return mAttributes->getAttr<FixedQAttr::NbBits>(); }
inline float& span() const noexcept { return mAttributes->getAttr<FixedQAttr::Span>(); }
inline bool& isOutputUnsigned() const noexcept { return mAttributes->getAttr<FixedQAttr::IsOutputUnsigned>(); }
static const std::vector<std::string> getInputsName(){
return {"data_input"};
}
static const std::vector<std::string> getOutputsName(){
return {"data_output"};
}
};
inline std::shared_ptr<Node> FixedQ(std::size_t nbBits = 8, float span = 4.0f, bool isOutputUnsigned = false, const std::string& name = "") {
return std::make_shared<Node>(std::make_shared<FixedQ_Op>(nbBits, span, isOutputUnsigned), name);
}
}
namespace {
template <>
const char* const EnumStrings<Aidge::FixedQAttr>::data[] = {"nb_bits", "span", "is_output_unsigned"};
}
#endif /* AIDGE_CORE_OPERATOR_FIXEDQ_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_CORE_OPERATOR_LSQ_H_
#define AIDGE_CORE_OPERATOR_LSQ_H_
#include <cassert>
#include <memory>
#include <vector>
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/operator/Producer.hpp"
#include "aidge/utils/ErrorHandling.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/StaticAttributes.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
enum class LSQAttr { Range };
/**
* LSQ is the weights AND activations quantizer for the LSQ method.
*/
class LSQ_Op : public OperatorTensor,
public Registrable<LSQ_Op, std::string, std::function<std::shared_ptr<OperatorImpl>(const LSQ_Op &)>> {
public:
static const std::string Type;
private:
using Attributes_ = StaticAttributes<LSQAttr, std::pair<int, int>>;
template <LSQAttr e> using attr = typename Attributes_::template attr<e>;
const std::shared_ptr<Attributes_> mAttributes;
public:
LSQ_Op(const std::pair<int, int>& range = {0, 255})
: OperatorTensor(Type, {InputCategory::Data, InputCategory::Param}, 1),
mAttributes(std::make_shared<Attributes_>(
attr<LSQAttr::Range>(range)))
{}
/**
* @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated).
* @param op Operator to copy.
*/
LSQ_Op(const LSQ_Op& op)
: OperatorTensor(op),
mAttributes(op.mAttributes)
{
if (op.mImpl){
SET_IMPL_MACRO(LSQ_Op, *this, op.backend());
}else{
mImpl = nullptr;
}
}
/**
* @brief Clone the operator using its copy-constructor.
* @see Operator::LSQ_Op
*/
std::shared_ptr<Operator> clone() const override {
return std::make_shared<LSQ_Op>(*this);
}
bool forwardDims(bool allowDataDependency = false) override final;
std::set<std::string> getAvailableBackends() const override final;
void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
inline std::pair<int, int>& range() const noexcept { return mAttributes->getAttr<LSQAttr::Range>(); }
static const std::vector<std::string> getInputsName(){
return {"data_input", "step_size"};
}
static const std::vector<std::string> getOutputsName(){
return {"data_output"};
}
};
/**
* Range should be (with N the number of bits):
* - {0, 2^N - 1} in place of ReLU activations
* - {-2^(N-1), 2^(N-1) - 1} in for weights quantization
*/
inline std::shared_ptr<Node> LSQ(const std::pair<int, int>& range = {0, 255}, const std::string& name = "") {
auto lsq = std::make_shared<Node>(std::make_shared<LSQ_Op>(range), name);
addProducer(lsq, 1, {1}, "ss");
return lsq;
}
}
namespace {
template <>
const char *const EnumStrings<Aidge::LSQAttr>::data[] = {"range"};
}
#endif /* AIDGE_CORE_OPERATOR_LSQ_H_ */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment