chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:05 +08:00
commit 4f3b7da785
7394 changed files with 2005594 additions and 0 deletions
@@ -0,0 +1,40 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 24.01.18.
//
#include <graph/ArgumentsList.h>
namespace sd {
namespace graph {
ArgumentsList::ArgumentsList(std::initializer_list<Pair> arguments) { _arguments = arguments; }
ArgumentsList::ArgumentsList(std::initializer_list<int> arguments) {
std::vector<int> args(arguments);
for (size_t e = 0; e < args.size(); e++) {
Pair pair(args[e]);
_arguments.emplace_back(pair);
}
}
int ArgumentsList::size() { return (int)_arguments.size(); }
Pair& ArgumentsList::at(int index) { return _arguments.at(index); }
} // namespace graph
} // namespace sd
+878
View File
@@ -0,0 +1,878 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <array/InteropDataBuffer.h>
#include <graph/Context.h>
#include <helpers/ShapeUtils.h>
#if defined(SD_GCC_FUNCTRACE)
#include <graph/OpContextLifecycleTracker.h>
#endif
namespace sd {
namespace graph {
Context::Context(ContextPrototype *prototype, VariableSpace *variableSpace) {
_variableSpace = variableSpace;
_dataType = prototype->dataType();
if (prototype != nullptr) {
for (const auto &v : *(prototype->inputs())) {
this->_inputs.push_back(v);
}
for (const auto &v : *(prototype->getTArguments())) {
this->_tArgs.push_back(v);
}
for (const auto &v : *(prototype->getIArguments())) {
this->_iArgs.push_back(v);
}
for (const auto &v : *(prototype->getBArguments())) {
this->_bArgs.push_back(v);
}
for (const auto &v : *(prototype->getAxis())) {
this->_axis.push_back(v);
}
for(auto v : *(prototype->getDArguments())) {
this->_dataTypes.push_back(v);
}
this->_opNum = prototype->opNum();
this->_isInplace = prototype->isInplace();
this->_nodeId = prototype->nodeId();
this->_useONEDNN = prototype->isUseONEDNN();
}
if (variableSpace != nullptr && variableSpace->launchContext()->getWorkspace() != nullptr)
this->_workspace = variableSpace->launchContext()->getWorkspace();
#if defined(SD_GCC_FUNCTRACE)
// Track OpContext allocation
OpContextLifecycleTracker::getInstance().recordAllocation(
this, _nodeId,
_fastpath_in.size(), _fastpath_out.size(),
_intermediateResults.size(), _handles.size(),
_workspace != nullptr, isFastPath());
#endif
}
DataType Context::dataType(int index) {
if(numD() < 1) {
if(width() > 0) {
return this->array(index)->dataType();
} else {
std::string errorMessage;
errorMessage += std::string("Context::dataType: Unable to determine data type. Both d args and inputs are empty.");
errorMessage += std::string(" Index: ");
errorMessage += std::to_string(index);
errorMessage += std::string(" Width: ");
errorMessage += std::to_string(width());
THROW_EXCEPTION(errorMessage.c_str());
};
}
return getDArguments()->at(index);
}
DataType Context::dataType() { return dataType(0); }
void Context::setDataType(int index, DataType type) {
if (this->_dataTypes.size() > (size_t)index) _dataTypes[index] = type;
_dataType = type;
}
Context::Context(int nodeId, VariableSpace *variableSpace) {
this->_nodeId = nodeId;
this->_variableSpace = variableSpace;
this->_isInplace = false;
this->_workspace = nullptr;
this->_executionTime.first = 0;
this->_executionTime.second = 0;
if (variableSpace != nullptr && variableSpace->launchContext()->getWorkspace() != nullptr)
this->_workspace = variableSpace->launchContext()->getWorkspace();
#if defined(SD_GCC_FUNCTRACE)
// Track OpContext allocation
OpContextLifecycleTracker::getInstance().recordAllocation(
this, _nodeId,
_fastpath_in.size(), _fastpath_out.size(),
_intermediateResults.size(), _handles.size(),
_workspace != nullptr, isFastPath());
#endif
}
Context::Context(int nodeId, VariableSpace *variableSpace, bool isInplace) : Context(nodeId, variableSpace) {
this->_isInplace = isInplace;
}
Context::~Context() {
#if defined(SD_GCC_FUNCTRACE)
// Track OpContext deallocation before cleanup
OpContextLifecycleTracker::getInstance().recordDeallocation(this);
#endif
this->_iArgs.clear();
this->_tArgs.clear();
this->_inputs.clear();
// IMPORTANT: Do NOT delete arrays in _fastpath_in and _fastpath_out!
// These are BORROWED pointers - the Context does not own them.
// The caller (e.g., DeclarableOp::execute) owns these arrays and is
// responsible for their lifecycle. Deleting them here causes use-after-free
// bugs when operations call sub-operations (e.g., layer_norm calling standardize).
// Only _handles contains arrays explicitly marked as owned by this Context.
this->_fastpath_in.clear();
this->_fastpath_out.clear();
// Clean up intermediate results - these ARE owned by the Context
for (auto v : _intermediateResults) {
if (v != nullptr) delete v;
}
_intermediateResults.clear();
// Clean up handles - these are arrays explicitly marked as removable/owned
for (auto v : _handles) delete v;
if (_context != nullptr) delete _context;
}
void Context::setTargetEngine(samediff::Engine engine) { _engine = engine; }
bool Context::hasWorkspaceProvided() { return this->_workspace != nullptr; }
void Context::attachWorkspace(sd::memory::Workspace *workspace) { this->_workspace = workspace; }
void Context::setVariableSpace(VariableSpace *variableSpace) { this->_variableSpace = variableSpace; }
void Context::forgetWorkspace() { _workspace = nullptr; }
std::vector<NDArray *> &Context::fastpath_in() { return _fastpath_in; }
std::vector<NDArray *> &Context::fastpath_out() { return _fastpath_out; }
bool Context::isFastPath() {
auto ie = _fastpath_in.empty();
auto io = _fastpath_out.empty();
// two options here.
// either both IN/OUT are filled
auto b1 = (!ie && !io) || (!ie && _isInplace);
// or at least something is filled, and FastPath is NOT forbidden
auto b2 = (!ie || !io) && !_forbidFastPath;
return b1 || b2;
}
void Context::forbidFastPath(bool reallyForbid) { _forbidFastPath = reallyForbid; }
VariableSpace *Context::getVariableSpace() { return _variableSpace; }
memory::Workspace *Context::getWorkspace() { return _workspace; }
memory::Workspace *Context::workspace() { return _workspace; }
random::RandomBuffer *Context::getRNG() { return _rng; }
void Context::setRNG(random::RandomBuffer *rng) { _rng = rng; }
Stash *Context::getStash() {
if (_variableSpace == nullptr) {
THROW_EXCEPTION("Context::getStash: VariableSpace is null. Context was not properly initialized.");
}
return _variableSpace->getStash();
}
void Context::trackList(NDArrayList *list) {
if (_variableSpace == nullptr) {
THROW_EXCEPTION("Context::trackList: VariableSpace is null. Context was not properly initialized.");
}
_variableSpace->trackList(list);
}
int Context::getBranch() {
if (_variableSpace == nullptr) {
THROW_EXCEPTION("Context::getBranch: VariableSpace is null. Context was not properly initialized.");
}
if (_variableSpace->flowPath() == nullptr) {
return 0; // Default branch when no flow path is set
}
return _variableSpace->flowPath()->branch(this->nodeId());
}
void Context::setBranch(int branch) {
//_branch = branch;
if (_variableSpace != nullptr && _variableSpace->flowPath() != nullptr) {
_variableSpace->flowPath()->markBranch(this->nodeId(), branch);
}
}
LongType Context::getOuterTime() { return this->_executionTime.first; }
LongType Context::getInnerTime() { return this->_executionTime.second; }
void Context::setOuterTime(LongType time) { this->_executionTime.first = time; }
void Context::setInnerTime(LongType time) { this->_executionTime.second = time; }
Variable *Context::getVariable(int idx) {
if (static_cast<size_t>(idx) >= this->_inputs.size()) {
std::string errorMessage;
errorMessage += "Node ";
errorMessage += std::to_string(this->_nodeId);
errorMessage += "; Variable [";
errorMessage += std::to_string(idx);
errorMessage += " requested, but only ";
errorMessage += std::to_string(this->_inputs.size());
errorMessage += " available";
THROW_EXCEPTION(errorMessage.c_str());
}
auto p = this->_inputs[idx];
auto v = variable(p);
// preconditioned with v->variableType()==VariableType::NDARRAY as for other cases getNDArray() can throw exception
if (Environment::getInstance().isDebugAndVerbose() && v != nullptr && v->variableType() == NDARRAY &&
v->getNDArray() != nullptr) {
auto array = v->getNDArray();
std::string shape_ = ShapeUtils::shapeAsString(array);
auto type = DataTypeUtils::asString(array->dataType());
float m = std::numeric_limits<float>::quiet_NaN();
if (!array->isEmpty()) {
LongType maxLen = sd::math::sd_min<LongType>(16, array->lengthOf() - 1);
sd_printf("Debug info for node_%i input[%i]; shape: %s; ews: [%i]; order: [%c]; dtype: [%s];\n",
this->_nodeId, idx, shape_.c_str(),array->ews(), array->ordering(), type.c_str());
std::vector<sd::LongType> shapeLen = {array->lengthOf()};
NDArray *raveled = array->reshape(array->ordering(), shapeLen);
sd_printf("Values: [ ",0);
for (LongType i = 0; i < maxLen; i++) {
auto v2 = raveled->e<float>(i);
sd_printf("%f, ", v2);
}
delete raveled;
sd_printf("]\n",0);
} else {
sd_printf("Debug info for node_%i input[%i]; shape: %s; ews: [%i]; order: [%c]; dtype: [%s]; mean value: [%f]\n",
this->_nodeId, idx, shape_.c_str(), (int)array->ews(), array->ordering(), type.c_str(), m);
}
}
return v;
}
Variable *Context::variable(int idx) { return getVariable(idx); }
Variable *Context::variable(std::initializer_list<int> p) {
if (p.size() != 2) THROW_EXCEPTION("Variable address should have size of 2");
std::vector<int> vec(p);
std::pair<int, int> pair(vec[0], vec[1]);
return variable(pair);
}
Variable *Context::variable(int node, int idx) {
std::pair<int, int> pair(node, idx);
return variable(pair);
}
Variable *Context::variable(std::pair<int, int> &p) {
if (_variableSpace == nullptr) {
std::string errorMessage;
errorMessage += "Node ";
errorMessage += std::to_string(this->_nodeId);
errorMessage += "; VariableSpace is null when trying to get variable: [";
errorMessage += std::to_string(p.first);
errorMessage += ":";
errorMessage += std::to_string(p.second);
errorMessage += "]. This usually means the Context was not properly initialized or fastpath was expected but failed.";
THROW_EXCEPTION(errorMessage.c_str());
}
#ifdef __cpp_exceptions
try {
return _variableSpace->getVariable(p);
} catch (std::exception &e) {
std::string errorMessage;
errorMessage += "Node ";
errorMessage += std::to_string(this->_nodeId);
errorMessage += "; Non-existent variable requested: [";
errorMessage += std::to_string(p.first);
errorMessage += ":";
errorMessage += std::to_string(p.second);
errorMessage += "]";
errorMessage += "\n";
THROW_EXCEPTION(errorMessage.c_str());
}
#else
return _variableSpace->getVariable(p);
#endif
return nullptr;
}
void Context::pushNDArrayToVariableSpace(int nodeId, int index, NDArray *array, bool removable) {
std::pair<int, int> pair(nodeId, index);
pushNDArrayToVariableSpace(pair, array, removable);
}
void Context::pushNDArrayToVariableSpace(std::pair<int, int> &pair, NDArray *array, bool removable) {
if (_variableSpace != nullptr) {
if (!_variableSpace->hasVariable(pair)) {
auto var = new Variable(array, nullptr, pair.first, pair.second);
_variableSpace->putVariable(pair, var);
var->markRemovable(removable);
} else {
sd_debug("Context: Getting variable in push ndarray\n",0);
auto var = _variableSpace->getVariable(pair);
sd_debug("Context: After getting variable in push ndarray to variable space\n",0);
if (var->hasNDArray()) {
if (var->getNDArray() != array) {
if (var->isRemovable() && var->hasNDArray() && !var->getNDArray()->isView()) {
delete var->getNDArray();
}
var->setNDArray(array);
var->markRemovable(removable);
}
} else {
var->setNDArray(array);
var->markRemovable(removable);
}
}
}
}
void Context::pushNDArrayListToVariableSpace(int nodeId, int index, NDArrayList *list, bool track) {
std::pair<int, int> pair(nodeId, index);
pushNDArrayListToVariableSpace(pair, list, track);
}
void Context::pushNDArrayListToVariableSpace(std::pair<int, int> &pair, NDArrayList *list, bool track) {
sd_debug("Pre push variable list\n",0);
if (_variableSpace == nullptr) {
THROW_EXCEPTION("Context::pushNDArrayListToVariableSpace: VariableSpace is null. Context was not properly initialized.");
}
if (!_variableSpace->hasVariable(pair)) {
sd_debug("Context::pushNDArrayListToVariableSpace: Pre create variable when none exists\n",0);
auto var = new Variable(nullptr, nullptr, pair.first, pair.second);
sd_debug("Context::pushNDArrayListToVariableSpace: Created when none exists\n",0);
var->setNDArrayList(list);
_variableSpace->putVariable(pair, var);
sd_debug("Context::pushNDArrayListToVariableSpace: Put variable\n",0);
} else {
sd_debug("Context::pushNDArrayListToVariableSpace: In else: Getting variable\n",0);
auto var = _variableSpace->getVariable(pair);
sd_debug("Context::pushNDArrayListToVariableSpace: Got variable setting list\n",0);
var->setNDArrayList(list);
}
sd_debug("Context::pushNDArrayListToVariableSpace: pre tracking\n",0);
if (track) _variableSpace->trackList(list);
}
Variable *Context::ensureVariable(int idx) {
std::pair<int, int> pair(this->nodeId(), idx);
if (_variableSpace == nullptr) THROW_EXCEPTION("Context::ensureVariable VariableSpace is NULL!");
if (!_variableSpace->hasVariable(pair)) {
auto var = new Variable(nullptr, nullptr, this->nodeId(), idx);
_variableSpace->putVariable(pair, var);
return var;
} else {
sd_debug("Before ensure variable",0);
return _variableSpace->getVariable(pair);
}
}
bool Context::isValueAvailable(int idx) {
auto var = ensureVariable(idx);
if (var->variableType() == NDARRAY) {
return var->hasNDArray();
} else if (var->variableType() == ARRAY_LIST) {
return var->hasNDArrayList();
}
return false;
}
NDArray *Context::getNDArray(int idx) { return array(idx); }
NDArray *Context::outputArray(int idx) {
// we check for fastpath first
if (!_fastpath_out.empty() && _fastpath_out.size() > static_cast<size_t>(idx)) {
NDArray* result = _fastpath_out[idx];
// Validate the output NDArray to catch memory corruption early
if (result != nullptr) {
const sd::LongType* shInfo = result->shapeInfo();
if (shInfo == nullptr) {
std::string errorMessage;
errorMessage += "Context::outputArray(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray has null shapeInfo. This indicates severe memory corruption or use-after-free.";
THROW_EXCEPTION(errorMessage.c_str());
}
sd::LongType rank = shInfo[0];
if (rank < 0 || rank > 32) {
std::string errorMessage;
errorMessage += "Context::outputArray(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray has corrupted rank: ";
errorMessage += std::to_string(rank);
errorMessage += " (expected 0-32). This likely indicates:\n";
errorMessage += " 1. Memory corruption in the output NDArray\n";
errorMessage += " 2. Use-after-free (accessing deallocated memory)\n";
errorMessage += " 3. Uninitialized output buffer allocation failure\n";
errorMessage += " 4. JNI marshalling error from Java layer";
THROW_EXCEPTION(errorMessage.c_str());
}
}
return result;
}
std::string errorMessage;
errorMessage += std::string("Context::outputArray: Fastpath is empty");
errorMessage += std::string(" Index: ");
errorMessage += std::to_string(idx);
errorMessage += std::string(" Fastpath size: ");
errorMessage += std::to_string(_fastpath_out.size());
THROW_EXCEPTION(errorMessage.c_str());
return nullptr;
}
NDArray *Context::array(int idx) {
// we check for fastpath first
if (!_fastpath_in.empty() && _fastpath_in.size() > static_cast<size_t>(idx)) {
NDArray* result = _fastpath_in[idx];
// Validate the NDArray to catch memory corruption early
if (result != nullptr) {
const sd::LongType* shInfo = result->shapeInfo();
if (shInfo == nullptr) {
std::string errorMessage;
errorMessage += "Context::array(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray has null shapeInfo. This indicates severe memory corruption or use-after-free.";
THROW_EXCEPTION(errorMessage.c_str());
}
// Check if rank is valid (should be 0-32, not a memory address)
sd::LongType rank = shInfo[0];
if (rank < 0 || rank > 32) {
std::string errorMessage;
errorMessage += "Context::array(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray has corrupted rank: ";
errorMessage += std::to_string(rank);
errorMessage += " (expected 0-32). This likely indicates:\n";
errorMessage += " 1. Memory corruption in the NDArray\n";
errorMessage += " 2. Use-after-free (accessing deallocated memory)\n";
errorMessage += " 3. Uninitialized NDArray from failed operation\n";
errorMessage += " 4. JNI marshalling error from Java layer";
THROW_EXCEPTION(errorMessage.c_str());
}
}
return result;
}
// When using fastpath (from OpContext/Java), _variableSpace is null by design.
// If the operation expects more inputs than were provided via setInputArrays(),
// throw an informative error instead of crashing in getVariable().
if (!_fastpath_in.empty() && _variableSpace == nullptr) {
// Fastpath has some inputs but not enough for the requested index
std::string errorMessage;
errorMessage += "Context::array(";
errorMessage += std::to_string(idx);
errorMessage += "): Input index out of bounds. Fastpath has ";
errorMessage += std::to_string(_fastpath_in.size());
errorMessage += " input array(s), but input at index ";
errorMessage += std::to_string(idx);
errorMessage += " was requested.\n";
errorMessage += "This typically means the operation expects more inputs than were provided.\n";
errorMessage += "For variable-input operations (like concat), ensure all input arrays are set via setInputArrays().";
THROW_EXCEPTION(errorMessage.c_str());
}
// if no luck for fastpath - return whatever is available
NDArray* result = getVariable(idx)->getNDArray();
// Validate the NDArray from variable path as well
if (result != nullptr) {
const sd::LongType* shInfo = result->shapeInfo();
if (shInfo == nullptr) {
std::string errorMessage;
errorMessage += "Context::array(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray from variable has null shapeInfo. This indicates severe memory corruption or use-after-free.";
THROW_EXCEPTION(errorMessage.c_str());
}
sd::LongType rank = shInfo[0];
if (rank < 0 || rank > 32) {
std::string errorMessage;
errorMessage += "Context::array(";
errorMessage += std::to_string(idx);
errorMessage += "): NDArray from variable has corrupted rank: ";
errorMessage += std::to_string(rank);
errorMessage += " (expected 0-32). This likely indicates:\n";
errorMessage += " 1. Memory corruption in the NDArray\n";
errorMessage += " 2. Use-after-free (accessing deallocated memory)\n";
errorMessage += " 3. Uninitialized NDArray from failed operation\n";
errorMessage += " 4. JNI marshalling error from Java layer";
THROW_EXCEPTION(errorMessage.c_str());
}
}
return result;
}
memory::Workspace *Context::fWorkspace() { return workspace(); }
memory::Workspace *Context::tWorkspace() { return nullptr; }
memory::Workspace *Context::oWorkspace() { return nullptr; }
LaunchContext *Context::launchContext() {
// FIXME: we need proper context to be shared here
if (_context == nullptr) {
return LaunchContext::defaultContext();
} else {
return _context;
}
}
unsigned long Context::outputWidth() {
return _fastpath_out.size();
}
unsigned long Context::width() {
if (!_fastpath_in.empty())
return _fastpath_in.size();
else
return _inputs.size();
}
void Context::setInputArray(int index, NDArray *array, bool removable) {
// Check for null array FIRST before any dereference
if (array == nullptr) {
std::string errorMessage;
errorMessage += std::string("Context::setInputArray: Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" is null!");
THROW_EXCEPTION(errorMessage.c_str());
}
if(array->shapeInfo() == nullptr) {
std::string errorMessage;
errorMessage += std::string("Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" has a null shape buffer!");
THROW_EXCEPTION(errorMessage.c_str());
}
if(array->dataType() != ArrayOptions::dataType(array->shapeInfo())) {
std::string errorMessage;
errorMessage += std::string("Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" has a different data type than the shape buffer!");
//add the shape info as a string to the error message
errorMessage += std::string(" Shape info: ");
errorMessage += ShapeUtils::shapeAsString(array->shapeInfo());
errorMessage += std::string(" Data type: ");
errorMessage += DataTypeUtils::asString(ArrayOptions::dataType(array->shapeInfo()));
THROW_EXCEPTION(errorMessage.c_str());
}
if (_fastpath_in.size() < static_cast<size_t>(index + 1)) _fastpath_in.resize(index + 1);
_fastpath_in[index] = array;
if (removable) _handles.emplace_back(array);
}
void Context::setOutputArray(int index, NDArray *array, bool removable) {
// Check for null array FIRST before any dereference
if (array == nullptr) {
std::string errorMessage;
errorMessage += std::string("Context::setOutputArray: Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" is null!");
THROW_EXCEPTION(errorMessage.c_str());
}
if (_fastpath_out.size() < static_cast<size_t>(index + 1)) _fastpath_out.resize(index + 1);
// Check for null shapeInfo before accessing it
if (array->shapeInfo() == nullptr) {
std::string errorMessage;
errorMessage += std::string("Context::setOutputArray: Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" has a null shape buffer!");
THROW_EXCEPTION(errorMessage.c_str());
}
if(array->dataType() != ArrayOptions::dataType(array->shapeInfo())) {
std::string errorMessage;
errorMessage += std::string("Array at index ");
errorMessage += std::to_string(index);
errorMessage += std::string(" has a different data type than the shape buffer!");
//add the shape info as a string to the error message
errorMessage += std::string(" Shape info: ");
errorMessage += ShapeUtils::shapeAsString(array->shapeInfo());
errorMessage += std::string(" Data type: ");
errorMessage += DataTypeUtils::asString(ArrayOptions::dataType(array->shapeInfo()));
THROW_EXCEPTION(errorMessage.c_str());
}
_fastpath_out[index] = array;
if (removable) _handles.emplace_back(array);
}
void validateBufferAndShape(InteropDataBuffer* dataBuffer, LongType * newShapeInfoCast, int index) {
bool errorFound = false;
std::string errorMessage;
//opaque/interop data buffers are created with int8 on purpose and therefore will be excluded from validation here.
//see more here: https://github.com/deeplearning4j/deeplearning4j/blob/8aa0ef12794ca40a2d00c5c80206a24a3bd6529c/nd4j/nd4j-backends/nd4j-backend-impls/nd4j-cpu-backend-common/src/main/java/org/nd4j/linalg/cpu/nativecpu/buffer/BaseCpuDataBuffer.java#L386
bool isString = ArrayOptions::dataType(newShapeInfoCast) == UTF8 || ArrayOptions::dataType(newShapeInfoCast) == UTF16 ||
ArrayOptions::dataType(newShapeInfoCast) == UTF32;
if(isString || shape::isEmptyConst(newShapeInfoCast) || dataBuffer->getDataBuffer()->getDataType() == INT8) return;
if (dataBuffer != nullptr) {
if (!shape::isEmptyConst(newShapeInfoCast)) {
if (dataBuffer->dataBuffer() != nullptr) {
//opaque/interop data buffers are created with int8 on purpose and therefore will be excluded from validation here.
//see more here: https://github.com/deeplearning4j/deeplearning4j/blob/8aa0ef12794ca40a2d00c5c80206a24a3bd6529c/nd4j/nd4j-backends/nd4j-backend-impls/nd4j-cpu-backend-common/src/main/java/org/nd4j/linalg/cpu/nativecpu/buffer/BaseCpuDataBuffer.java#L386
if (!isString && dataBuffer->getDataBuffer()->getDataType() != ArrayOptions::dataType(newShapeInfoCast)) {
errorMessage += "Data type mismatch between data buffer and shape buffer. ";
errorMessage += "Data buffer data type: " + DataTypeUtils::asString(dataBuffer->dataBuffer()->getDataType()) + ". ";
errorMessage += "Shape buffer data type: " + DataTypeUtils::asString(ArrayOptions::dataType(newShapeInfoCast)) + ". ";
errorFound = true;
}
if (!DataTypeUtils::validDataType(dataBuffer->dataBuffer()->getDataType())) {
errorMessage += "Invalid data type in data buffer. ";
errorFound = true;
}
} else {
errorMessage += "Data buffer is null. ";
errorFound = true;
}
if (!DataTypeUtils::validDataType(ArrayOptions::dataType(newShapeInfoCast))) {
errorMessage += "Invalid data type in shape buffer. ";
errorFound = true;
}
} else if (dataBuffer->dataBuffer() != nullptr && (dataBuffer->dataBuffer()->primary() != nullptr || dataBuffer->dataBuffer()->special() != nullptr)) {
errorMessage += "Shape Buffer at index " + std::to_string(index) + " is marked as empty but data buffer is not null! ";
errorFound = true;
}
}
if (errorFound) {
errorMessage += "Shape info: " + ShapeUtils::shapeAsString(newShapeInfoCast) + ". ";
errorMessage += "Data type: " + DataTypeUtils::asString(ArrayOptions::dataType(newShapeInfoCast)) + ". ";
if (dataBuffer->dataBuffer() != nullptr) {
errorMessage += "Data buffer: " + std::string(dataBuffer->dataBuffer()->primary() != nullptr ? "not null" : "null") + ". ";
errorMessage += "Special buffer: " + std::string(dataBuffer->dataBuffer()->special() != nullptr ? "not null" : "null") + ". ";
}
errorMessage += "Elements: ";
for(int i = 0; i < shape::shapeInfoLength(newShapeInfoCast); i++) {
errorMessage += std::to_string(newShapeInfoCast[i]) + ", ";
}
errorMessage += "\n";
THROW_EXCEPTION(errorMessage.c_str());
}
}
void Context::setTArguments(double *arguments, int numberOfArguments) {
_tArgs.clear();
_tArgs.reserve(numberOfArguments);
for (int e = 0; e < numberOfArguments; e++) _tArgs.push_back(arguments[e]);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("float values set in context: ");
for (auto d : _bArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setIArguments(LongType *arguments, int numberOfArguments) {
_iArgs.clear();
_iArgs.reserve(numberOfArguments);
for (int e = 0; e < numberOfArguments; e++) _iArgs.push_back(arguments[e]);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("int arguments set in context: ");
for (auto d : _bArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setBArguments(bool *arguments, int numberOfArguments) {
_bArgs.clear();
_bArgs.reserve(numberOfArguments);
for (int e = 0; e < numberOfArguments; e++) _bArgs.push_back(arguments[e]);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("boolean types set in context: ");
for (auto d : _bArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setCudaContext(Pointer cudaStream, Pointer reductionPointer, Pointer allocationPointer) {
#ifdef SD_CUDA
_context = new LaunchContext(cudaStream, reductionPointer, allocationPointer);
// FIXME: either pass handle from outside, or make sure outside we use the same handle
_context->setCublasHandle(LaunchContext::defaultContext()->getCublasHandle());
for (auto v : _fastpath_out) v->setContext(_context);
for (auto v : _fastpath_in) v->setContext(_context);
#endif
}
void Context::allowHelpers(bool reallyAllow) { _helpersAllowed = reallyAllow; }
bool Context::helpersAllowed() { return _helpersAllowed; }
void Context::setTArguments(const std::vector<double> &tArgs) {
for (auto t : tArgs) _tArgs.emplace_back(t);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("t argument types set in context: ");
for (auto d : _bArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setIArguments(const std::vector<LongType> &iArgs) {
for (auto i : iArgs) _iArgs.emplace_back(i);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("int argument types set in context: ");
for (auto d : iArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setBArguments(const std::vector<bool> &bArgs) {
for (auto b : bArgs) _bArgs.push_back(b);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("boolean types set in context: ");
for (auto d : _bArgs) {
printf("%s\n, ", std::to_string(d).c_str());
}
fflush(stdout);
}
}
void Context::setShapeFunctionOverride(bool reallyOverride) { _shapeFunctionOverride = reallyOverride; }
bool Context::shapeFunctionOverride() { return _shapeFunctionOverride; }
samediff::ExecutionMode Context::executionMode() { return _execMode; }
void Context::setExecutionMode(samediff::ExecutionMode executionMode) { _execMode = executionMode; }
bool Context::isTraining() { return _execMode == samediff::ExecutionMode::MODE_TRAINING; }
bool Context::isInference() { return _execMode == samediff::ExecutionMode::MODE_INFERENCE; }
void Context::setDArguments(DataType *arguments, int numberOfArguments) {
_dArgs.clear();
for (int e = 0; e < numberOfArguments; e++) _dArgs.emplace_back(arguments[e]);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("data types set in context: ");
for (auto d : _dArgs) {
printf("%s\n, ", DataTypeUtils::asString(d).c_str());
}
fflush(stdout);
}
}
void Context::setDArguments(const std::vector<DataType> &dArgs) {
_dArgs.clear();
for (auto d : dArgs) _dArgs.emplace_back(d);
if(Environment::getInstance().isDebug() || Environment::getInstance().isVerbose()) {
printf("data types set in context: ");
for (auto d : dArgs) {
printf("%s\n, ", DataTypeUtils::asString(d).c_str());
}
fflush(stdout);
}
}
void Context::clearFastPath() {
_fastpath_in.clear();
_fastpath_out.clear();
// Delete arrays in _handles before clearing (fixes memory leak)
for (auto v : _handles) {
if (v != nullptr) delete v;
}
_handles.clear();
}
void Context::setInputArrays(int numArrays,NDArray** array, bool removable) {
for(int i = 0; i < numArrays; i++) {
setInputArray(i,array[i],removable);
}
}
void Context::setOutputArrays(int numArrays,NDArray** array, bool removable) {
for(int i = 0; i < numArrays; i++) {
setOutputArray(i,array[i],removable);
}
}
} // namespace graph
} // namespace sd
@@ -0,0 +1,146 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/ContextPrototype.h>
#include <types/float16.h>
namespace sd {
namespace graph {
ContextPrototype::ContextPrototype(ops::OpDescriptor* opDescriptor, int nodeId, bool inPlace) {
_nodeId = nodeId;
_isInplace = inPlace;
_opDescriptor = opDescriptor;
}
void ContextPrototype::pickInput(std::pair<int, int>& p) { this->_inputs.emplace_back(p); }
void ContextPrototype::pickInput(int input, int index) {
std::pair<int, int> pair(input, index);
pickInput(pair);
}
int ContextPrototype::opNum() { return this->_opNum; }
void ContextPrototype::setOpNum(int opNum) { this->_opNum = opNum; }
std::vector<std::pair<int, int>>* ContextPrototype::inputs() { return &_inputs; }
void ContextPrototype::fillInputs(std::vector<int>& inputs) {
for (size_t e = 0; e < inputs.size(); e++) {
auto v = inputs.at(e);
pickInput(v);
}
}
samediff::Engine ContextPrototype::engine() { return _engine; }
bool ContextPrototype::hasVariablesFilled() { return this->_inputs.size() > 0; }
bool ContextPrototype::isInplace() { return this->_isInplace; }
std::vector<double>* ContextPrototype::getTArguments() { return &(this->_tArgs); }
std::vector<LongType>* ContextPrototype::getIArguments() { return &(this->_iArgs); }
std::vector<bool>* ContextPrototype::getBArguments() { return &(this->_bArgs); }
std::vector<LongType>* ContextPrototype::getAxis() { return &(this->_axis); }
std::vector<std::string> * ContextPrototype::getSArguments() {return &(this->_sArgs);}
void ContextPrototype::pickInput(int input) {
std::pair<int, int> pair(input, 0);
this->_inputs.emplace_back(pair);
}
std::pair<int, int>* ContextPrototype::input(int idx) { return &(this->_inputs.at(idx)); }
void ContextPrototype::fillInputs(std::initializer_list<int> inputs) {
for (auto v : inputs) {
pickInput(v);
}
}
int ContextPrototype::nodeId() { return getNodeId(); }
DataType ContextPrototype::dataType() { return dataType(0); }
DataType ContextPrototype::dataType(int index) {
if(numD() < 1) {
THROW_EXCEPTION("No data types were set for this ContextPrototype");
} else {
return _dArgs.at(index);
}
return DataType::UNKNOWN;
}
void ContextPrototype::setDataType(int index, DataType type) {
_dArgs[index] = type;
}
size_t ContextPrototype::numT() { return (int)_tArgs.size(); }
size_t ContextPrototype::numI() { return (int)_iArgs.size(); }
size_t ContextPrototype::numB() { return (int)_bArgs.size(); }
int ContextPrototype::getNodeId() { return this->_nodeId; }
/**
* This method returns number of inputs available in this block
* @return
*/
unsigned long ContextPrototype::width() { return this->_inputs.size(); };
void ContextPrototype::markInplace(bool reallyInplace) { this->_isInplace = reallyInplace; }
template <typename N>
ContextPrototype* ContextPrototype::asT() {
auto clone = new ContextPrototype(_opDescriptor, _nodeId, _isInplace);
return clone;
}
void ContextPrototype::setOpDescriptor(ops::OpDescriptor* opDescriptor) { _opDescriptor = opDescriptor; }
ContextPrototype* ContextPrototype::clone() {
auto clone = new ContextPrototype(_opDescriptor, _nodeId, _isInplace);
clone->_opNum = _opNum;
for (auto v : _inputs) clone->_inputs.emplace_back(v);
for (auto v : _tArgs) clone->_tArgs.emplace_back(v);
for (auto v : _iArgs) clone->_iArgs.emplace_back(v);
for(auto v : _bArgs) clone->_bArgs.emplace_back(v);
for(auto v : _dArgs) clone->_dArgs.emplace_back(v);
return clone;
}
std::vector<DataType>* ContextPrototype::getDArguments() { return &_dArgs; }
size_t ContextPrototype::numD() { return _dArgs.size(); }
} // namespace graph
} // namespace sd
@@ -0,0 +1,100 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/ExecutionResult.h>
#include <system/common.h>
#include <system/op_boilerplate.h>
namespace sd {
namespace graph {
ExecutionResult::ExecutionResult(const ::graph::FlatResult* flatResult) {
if (flatResult->variables() != nullptr) {
for (size_t e = 0; e < flatResult->variables()->size(); e++) {
auto fv = flatResult->variables()->Get(e);
auto v = new Variable(fv);
this->emplace_back(v);
}
_releasable = true;
}
}
ExecutionResult::~ExecutionResult() {
if (_releasable)
for (auto v : _variables) delete v;
}
LongType ExecutionResult::size() { return _variables.size(); }
ExecutionResult::ExecutionResult(std::initializer_list<Variable*> variables) {
for (auto v : variables) this->emplace_back(v);
}
void ExecutionResult::emplace_back(Variable* variable) {
_variables.emplace_back(variable);
if (variable->getName() != nullptr) _stringIdMap[*variable->getName()] = variable;
std::pair<int, int> p(variable->id(), variable->index());
_pairIdMap[p] = variable;
}
Variable* ExecutionResult::at(int position) {
if (static_cast<size_t>(position) >= _variables.size())
THROW_EXCEPTION("Position index is higher then number of variables stored");
return _variables.at(position);
}
Variable* ExecutionResult::byId(std::string& id) {
if (_stringIdMap.count(id) == 0) THROW_EXCEPTION("Can't find specified ID");
return _stringIdMap.at(id);
}
Variable* ExecutionResult::byId(std::pair<int, int>& id) {
if (_pairIdMap.count(id) == 0) THROW_EXCEPTION("Can't find specified ID");
return _pairIdMap.at(id);
}
Variable* ExecutionResult::byId(int id) {
std::pair<int, int> p(id, 0);
return byId(p);
}
Variable* ExecutionResult::byId(const char* str) {
std::string p(str);
return byId(p);
}
flatbuffers::Offset<::graph::FlatResult> ExecutionResult::asFlatResult(flatbuffers::FlatBufferBuilder& builder) {
std::vector<flatbuffers::Offset<::graph::FlatVariable>> vec;
for (Variable* v : _variables) {
vec.emplace_back(v->asFlatVariable(builder));
}
auto vecOffset = builder.CreateVector(vec);
return CreateFlatResult(builder, 0, vecOffset);
}
} // namespace graph
} // namespace sd
@@ -0,0 +1,62 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/ExecutorConfiguration.h>
namespace sd {
namespace graph {
ExecutorConfiguration::ExecutorConfiguration(const ::graph::FlatConfiguration *conf) {
if (conf != nullptr) {
_profilingMode = conf->profilingMode();
_executionMode = conf->executionMode();
_outputMode = conf->outputMode();
_timestats = conf->timestats();
_footprintForward = conf->footprintForward();
_footprintBackward = conf->footprintBackward();
_direction = conf->direction();
} else {
_profilingMode = ::graph::ProfilingMode_NONE;
_executionMode = ::graph::ExecutionMode_SEQUENTIAL;
_outputMode = ::graph::OutputMode_IMPLICIT;
_timestats = false;
}
};
ExecutorConfiguration *ExecutorConfiguration::clone() {
auto clone = new ExecutorConfiguration();
clone->_profilingMode = _profilingMode;
clone->_executionMode = _executionMode;
clone->_outputMode = _outputMode;
clone->_timestats = _timestats;
clone->_direction = _direction;
clone->_footprintForward = _footprintForward;
clone->_footprintBackward = _footprintBackward;
return clone;
};
flatbuffers::Offset<::graph::FlatConfiguration> ExecutorConfiguration::asFlatConfiguration(
flatbuffers::FlatBufferBuilder &builder) {
return CreateFlatConfiguration(builder, 0, _executionMode, _profilingMode, _outputMode, _timestats,
_footprintBackward, _footprintBackward);
}
} // namespace graph
} // namespace sd
+114
View File
@@ -0,0 +1,114 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 22.11.2017.
//
#include <array/ByteOrder.h>
#include <array/ByteOrderUtils.h>
#include <array/DataTypeConversions.h>
#include <array/DataTypeUtils.h>
#include <array/NDArrayFactory.h>
#include <graph/FlatUtils.h>
namespace sd {
namespace graph {
std::pair<int, int> FlatUtils::fromIntPair(::graph::IntPair *pair) { return std::pair<int, int>(pair->first(), pair->second()); }
std::pair<LongType, LongType> FlatUtils::fromLongPair(::graph::LongPair *pair) {
return std::pair<LongType, LongType>(pair->first(), pair->second());
}
NDArray *FlatUtils::fromFlatArray(const ::graph::FlatArray *flatArray) {
auto rank = static_cast<int>(flatArray->shape()->Get(0));
auto newShape = new LongType[shape::shapeInfoLength(rank)];
memcpy(newShape, flatArray->shape()->data(), shape::shapeInfoByteLength(rank));
auto length = shape::length(newShape);
auto dtype = DataTypeUtils::fromFlatDataType(flatArray->dtype());
// empty arrays is special case, nothing to restore here
if (shape::isEmptyConst(newShape)) {
delete[] newShape;
return NDArrayFactory::empty_(dtype, nullptr);
}
// TODO fix UTF16 and UTF32
if (dtype == UTF8) {
std::vector<std::string> substrings(length);
std::vector<LongType> shapeVector(rank);
for (int e = 0; e < rank; e++) shapeVector[e] = newShape[e + 1];
auto rawPtr = (void *)flatArray->buffer()->data();
auto longPtr = reinterpret_cast<LongType *>(rawPtr);
auto charPtr = reinterpret_cast<char *>(longPtr + length + 1);
auto offsets = new LongType[length + 1];
for (LongType e = 0; e <= length; e++) {
auto o = longPtr[e];
// FIXME: BE vs LE on partials
// auto v = canKeep ? o : BitwiseUtils::swap_bytes<sd::LongType>(o);
offsets[e] = o;
}
for (LongType e = 0; e < length; e++) {
auto start = offsets[e];
auto end = offsets[e + 1];
auto len = end - start;
auto c = (char *)malloc(len + 1);
CHECK_ALLOC(c, "Failed temp allocation", len + 1);
memset(c, '\0', len + 1);
memcpy(c, charPtr + start, len);
std::string val(c);
substrings[e] = val;
free(c);
}
delete[] offsets;
delete[] newShape;
// string order always 'c'
return NDArrayFactory::string_(shapeVector, substrings);
}
auto newBuffer = new int8_t[length * DataTypeUtils::sizeOf(dtype)];
BUILD_SINGLE_SELECTOR(dtype, DataTypeConversions,
::convertType(newBuffer, (void *)flatArray->buffer()->data(), dtype,
ByteOrderUtils::fromFlatByteOrder(flatArray->byteOrder()), length),
SD_COMMON_TYPES);
auto array = new NDArray(newBuffer, newShape, LaunchContext::defaultContext(), true, 0);
delete[] newShape;
return array;
}
flatbuffers::Offset<::graph::FlatArray> FlatUtils::toFlatArray(flatbuffers::FlatBufferBuilder &builder, NDArray &array) {
auto byteVector = array.asByteVector();
auto fBuffer = builder.CreateVector(byteVector);
auto fShape = builder.CreateVector(array.getShapeInfoAsFlatVector());
auto bo = static_cast<::graph::ByteOrder>(BitwiseUtils::asByteOrder());
return CreateFlatArray(builder, fShape, fBuffer, static_cast<::graph::DType>(array.dataType()), bo);
}
} // namespace graph
} // namespace sd
+131
View File
@@ -0,0 +1,131 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 16/11/17.
//
#include <graph/FlowPath.h>
namespace sd {
namespace graph {
void FlowPath::ensureNode(int nodeId) {
if (_states.count(nodeId) == 0) {
NodeState state(nodeId);
_states[nodeId] = state;
}
}
void FlowPath::ensureFrame(int frameId) {
if (_frames.count(frameId) == 0) {
FrameState state(frameId);
_frames[frameId] = state;
}
}
void FlowPath::setInnerTime(int nodeId, LongType time) {
ensureNode(nodeId);
_states[nodeId].setInnerTime(time);
}
void FlowPath::setOuterTime(int nodeId, LongType time) {
ensureNode(nodeId);
_states[nodeId].setOuterTime(time);
}
LongType FlowPath::innerTime(int nodeId) {
ensureNode(nodeId);
return _states[nodeId].innerTime();
}
LongType FlowPath::outerTime(int nodeId) {
ensureNode(nodeId);
return _states[nodeId].outerTime();
}
bool FlowPath::isNodeActive(int nodeId) {
ensureNode(nodeId);
return _states[nodeId].isActive();
}
void FlowPath::markNodeActive(int nodeId, bool isActive) {
ensureNode(nodeId);
_states[nodeId].markActive(isActive);
}
int FlowPath::branch(int nodeId) {
ensureNode(nodeId);
return _states[nodeId].branch();
}
void FlowPath::markBranch(int nodeId, int index) {
ensureNode(nodeId);
_states[nodeId].markBranch(index);
}
bool FlowPath::isFrameActive(LongType frameId) {
ensureFrame(frameId);
return _frames[frameId].wasActivated();
}
void FlowPath::markFrameActive(LongType frameId, bool isActive) {
ensureFrame(frameId);
_frames[frameId].markActivated(isActive);
}
bool FlowPath::isRewindPlanned(LongType frameId) { return _frames[frameId].isRewindPlanned(); }
void FlowPath::planRewind(LongType frameId, bool reallyRewind) { _frames[frameId].planRewind(reallyRewind); }
int FlowPath::getRewindPosition(LongType frameId) { return _frames[frameId].getRewindPosition(); }
void FlowPath::setRewindPosition(LongType frameId, int position) { _frames[frameId].setRewindPosition(position); }
void FlowPath::setRewindPositionOnce(LongType frameId, int position) {
_frames[frameId].setRewindPositionOnce(position);
}
void FlowPath::registerFrame(LongType frameId) {
if (_frames.count(frameId) == 0) ensureFrame(frameId);
}
void FlowPath::forgetFrame(LongType frameId) {
if (_frames.count(frameId) > 0) _frames.erase(frameId);
}
void FlowPath::incrementNumberOfCycles(LongType frameId) { _frames[frameId].incrementNumberOfCycles(); }
LongType FlowPath::getNumberOfCycles(LongType frameId) { return _frames[frameId].getNumberOfCycles(); }
bool FlowPath::wasExecuted(int nodeId) { return _states[nodeId].wasExecuted(); }
void FlowPath::markExecuted(int nodeId, bool wasExecuted) { _states[nodeId].markExecuted(wasExecuted); }
GraphProfile* FlowPath::profile() { return &_profile; }
} // namespace graph
} // namespace sd
+50
View File
@@ -0,0 +1,50 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 06.02.2018.
//
#include <graph/FrameState.h>
namespace sd {
namespace graph {
FrameState::FrameState(sd::LongType id) { this->_id = id; }
int FrameState::getNumberOfCycles() { return _numberOfCycles; }
void FrameState::incrementNumberOfCycles() { ++_numberOfCycles; }
bool FrameState::wasActivated() { return _activated; }
void FrameState::markActivated(bool reallyActivated) { _activated = reallyActivated; }
std::string &FrameState::getFrameName() { return _name; }
bool FrameState::isRewindPlanned() { return _rewindPlanned; }
int FrameState::getRewindPosition() { return _rewindPosition; }
void FrameState::setRewindPosition(int pos) { _rewindPosition = pos; }
void FrameState::setRewindPositionOnce(int pos) {
if (_rewindPosition < 0) _rewindPosition = pos;
}
void FrameState::planRewind(bool reallyPlanning) { _rewindPlanned = reallyPlanning; }
} // namespace graph
} // namespace sd
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,665 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/generated/graph_generated.h>
#include <graph/generated/node_generated.h>
#include <graph/generated/result_generated.h>
#include <graph/GraphExecutioner.h>
#include <graph/Node.h>
#include <graph/Scope.h>
#include <graph/TimeHolder.h>
#include <graph/Variable.h>
#include <graph/VariableSpace.h>
#include <loops/pairwise_transform.h>
#include <loops/scalar.h>
#include <loops/transform_same.h>
#include <memory/MemoryRegistrator.h>
#include <ops/declarable/DeclarableOp.h>
#include <array/DataTypeUtils.h>
#include <exceptions/graph_execution_exception.h>
#include <exceptions/no_results_exception.h>
#include <fcntl.h>
#include <graph/ExecutionResult.h>
#include <graph/FlatUtils.h>
#include <graph/ResultWrapper.h>
#include <graph/execution/LogicExecutor.h>
#include <graph/generated/array_generated.h>
#include <helpers/BitwiseUtils.h>
#include <helpers/ShapeUtils.h>
#include <chrono>
#include <ctime>
#include <deque>
namespace sd {
namespace graph {
/**
* This method executes given Node (as in Op within Node)
*
* Basically it just does DeclarableOp::execute(Block), and ops to their job. However, there are some additional
* functionality.
*
* @param graph - Graph instance pointer
* @param node - Node instance pointer, which will be executed
* @param variableSpace - VariableSpace instance pointer - varspace specific to current Thread/Session
* @return
*/
Status GraphExecutioner::executeFlatNode(Graph *graph, Node *node, VariableSpace *variableSpace) {
::graph::OpType opType = node->opType();
int opNum = node->opNum();
// std::string opName = *(node->getCustomOp()->getOpName());
if (opType == ::graph::OpType_BOOLEAN) {
sd_debug("Executing boolean graph node_%i", node->id());
} else if (opType == ::graph::OpType_LOGIC) {
sd_debug("Executing logic graph node_%i", node->id());
} else if (opType == ::graph::OpType_GRAPH) {
sd_debug("Executing embedded graph node_%i", node->id());
} else if (opType != ::graph::OpType_CUSTOM) {
sd_debug("Executing node_%i{%i}\n", node->id(), opNum);
} else {
sd_debug("Executing node_%i{%s}\n", node->id(), node->getCustomOp()->getOpName()->c_str());
}
Context context(node->getContextPrototype(), variableSpace);
if (Environment::getInstance().isDebugAndVerbose()) {
// sd_debug("Input variables: %i\n", node->input()->size());
printf(" Inputs: {");
for (size_t e = 0; e < node->input()->size(); e++) {
printf("[%i:%i]", node->input()->at(e).first, node->input()->at(e).second);
if (e < node->input()->size() - 1) printf(", ");
}
printf("}\n");
fflush(stdout);
}
if (node->id() == 13) sd_debug("", "");
// if true - this is special case: Graph-in-Graph.
if (node->hasGraphEmbedded()) {
auto embedded = node->getGraph();
/**
* basically, we should do following things here:
* 1) fill embedded graph with input variables from this graph, if anything should be filled in
* 2) invoke embedded graph
* 3) announce its results as corresponding output variables in current VariableSpace
*/
// enforcing IMPLICIT mode. or not... should we try to be smarter then user?
// embedded->getExecutorConfiguration()->_outputMode = OutputMode_IMPLICIT;
if (node->input()->size() != static_cast<size_t>(embedded->numberOfPlaceholders())) {
sd_debug("Placeholders amount mismatch: %i expected, and %i available\n", node->input()->size(),
embedded->numberOfPlaceholders());
return Status::BAD_INPUT;
}
// we need to propagate required variables to the embedded graph
ResultSet deletables;
int cnt = 0;
for (Variable *v : *embedded->getPlaceholders()) {
if (v->getName() != nullptr && v->getName()->size() > 0) {
// trying symbolic lookup first
if (variableSpace->hasVariable(v->getName())) {
// symbolic feeder
auto array = variableSpace->getVariable(v->getName())->getNDArray();
auto vr = array->dup(array->ordering());
v->setNDArray(vr);
} else {
sd_debug("Can't find variable [%s] in parent graph...", v->getName()->c_str());
return Status::BAD_INPUT;
}
} else {
// if we're not using symbolic lookup - we'll use sequential approach then
auto p = node->input()->at(cnt);
auto array = variableSpace->getVariable(p)->getNDArray();
auto vr = array->dup(array->ordering()); // dup() already returns NDArray*
v->setNDArray(vr);
}
cnt++;
}
// executing embedded graph as independent one
Status status = execute(embedded);
if (status != Status::OK) return status;
// now we should migrate its results to this node, as its own outputs
cnt = 0;
auto outputs = embedded->fetchOutputs();
for (auto v : *outputs) {
NDArray *array = v->getNDArray();
v->setNDArray(nullptr);
std::pair<int, int> pair(node->id(), cnt++);
auto var = variableSpace->getVariable(pair);
var->setNDArray(array);
var->markRemovable(true);
}
deletables.size();
delete outputs;
sd_debug("Embedded graph execution finished. %i variable(s) migrated\n", cnt);
} else if (node->hasCustomOp()) {
// now, if we have something to execute - lets just execute it.
auto status = node->getCustomOp()->execute(&context);
if (status != Status::OK) return status;
// propagate variables
if (node->hasExternalOutputs()) {
for (auto v : *node->output()) {
if (variableSpace->hasExternalVariable(v.first)) {
variableSpace->getVariable(v.first)->getNDArray()->assign(
variableSpace->getVariable(node->id())->getNDArray());
}
}
}
return status;
}
return Status::OK;
}
/**
* This method executes given Graph instance, and returns error code.
*
* @param graph
* @return one of error codes defined in pointercast.h
*/
Status GraphExecutioner::execute(Graph *graph, VariableSpace *variableSpace) {
auto __variableSpace = variableSpace == nullptr ? graph->getVariableSpace() : variableSpace;
bool tempFlow = false;
if (__variableSpace->flowPath() == nullptr) {
tempFlow = true;
__variableSpace->setFlowPath(new FlowPath());
}
auto flowPath = __variableSpace->flowPath();
LongType tb0 = Environment::getInstance().isProfiling() ? GraphProfile::currentTime() : 0L;
graph->buildGraph();
auto footprintForward = memory::MemoryRegistrator::getInstance().getGraphMemoryFootprint(graph->hashCode());
if (footprintForward > 0) {
if (__variableSpace->launchContext()->getWorkspace() != nullptr) {
// this method will work only if current workspace size is smaller then proposed value
sd_debug("Setting workspace to %lld bytes\n", footprintForward);
__variableSpace->launchContext()->getWorkspace()->expandTo(footprintForward);
}
}
// optionally saving graph build time
if (Environment::getInstance().isProfiling()) flowPath->profile()->setBuildTime(GraphProfile::relativeTime(tb0));
LongType timeStart = Environment::getInstance().isProfiling() ? GraphProfile::currentTime() : 0L;
bool pe = graph->getExecutorConfiguration()->_executionMode == ::graph::ExecutionMode_AUTO;
// basically if at some point code diverges, code branch might be _DISABLED_, and all nodes within that branch will be
// disabled as well
std::deque<LongType> frames;
bool leftFrame = false;
auto nodeTime = GraphProfile::currentTime();
int lastId = -10000000;
LongType exec_counter = 0;
// we loop through op layers here
for (int l = 0; l < (int)graph->getOnion()->size(); l++) {
int layerSize = graph->getOnion()->count(l) == 1 ? graph->getOnion()->at(l)->size() : 0;
int n = 0;
// this omp block will probably never be the case
for (; n < layerSize; n++) {
if (++exec_counter > 10000) {
l = graph->getOnion()->size();
return Logger::logKernelFailureMsg("Early termination hit");
}
Node *node = graph->getOnion()->at(l)->at(n);
if (Environment::getInstance().isProfiling()) flowPath->profile()->nodeById(node->id(), node->name()->c_str());
if (lastId != node->id() && Environment::getInstance().isProfiling()) {
if (lastId != -10000000)
flowPath->profile()->nodeById(lastId)->setTotalTime(GraphProfile::relativeTime(nodeTime));
lastId = node->id();
nodeTime = GraphProfile::currentTime();
}
sd_debug("Step: %lld; Node: %i <%s>\n", exec_counter, node->id(), node->name()->c_str());
// on first non-Exit node after loop we can rewind (if planned)
if (!(node->opType() == ::graph::OpType_LOGIC && node->opNum() == logic::Exit)) {
// VALIDATED
// if we're out of frame - let's remove it from queue
if (leftFrame) {
auto frame_id = frames.back();
frames.pop_back();
flowPath->markFrameActive(frame_id, false);
flowPath->forgetFrame(frame_id);
leftFrame = false;
}
// TODO: move inactivity check right here
bool shouldSkip = false;
if (node->opType() == ::graph::OpType_LOGIC && node->opNum() == logic::Merge) {
// Merge node has own checkout logic
auto inputId0 = node->input()->at(0);
auto inputId1 = node->input()->at(1);
// Merge node can be skipped only both inputs are inactive
if (!flowPath->isNodeActive(inputId0.first) && !flowPath->isNodeActive(inputId1.first)) shouldSkip = true;
} else {
// let's check for input nodes, if they are disabled or contain divergents
for (size_t e = 0; e < node->input()->size(); e++) {
auto inputId = node->input()->at(e);
// not a node. skipping checks
if (graph->getMapped()->count(inputId.first) == 0) continue;
/**
* We can skip current node, in two cases:
* 1) If previous node was disabled
* 2) If previous node was divergent node (i.e. IF op) and code went other way
*/
Node *prevNode = graph->getMapped()->at(inputId.first);
if (!flowPath->isNodeActive(inputId.first)) {
shouldSkip = true;
flowPath->markNodeActive(node->id(), false);
sd_debug("Skipping Node_%i due to inactive input [%i]\n", node->id(), inputId.first);
break;
} else if (prevNode->isDivergencePoint()) { // literally checking for switch here
if (flowPath->branch(inputId.first) != inputId.second) {
shouldSkip = true;
flowPath->markNodeActive(node->id(), false);
sd_debug("Skipping Node_%i due to divergent branch [%i]\n", node->id(), inputId.first);
break;
}
}
}
}
if (shouldSkip) continue;
}
// we're propagating frameId here (but only if wasn't set earlier)
if (frames.size() > 0 && node->getFrameId() < 0) node->setFrameId(frames.back());
flowPath->markNodeActive(node->id(), true);
if (node->opType() == ::graph::OpType_LOGIC && node->opNum() == logic::Enter) {
// Enter operation
// VALIDATED
// we expect this node to have frameId set
auto frame_id = node->getFrameId();
// new frame starts here
if (frames.size() == 0 || (frames.size() > 0 && frames.back() != frame_id)) {
flowPath->registerFrame(frame_id);
frames.emplace_back(frame_id);
}
auto status = LogicExecutor::processNode(graph, node);
if (status != Status::OK) return status;
} else if (node->opType() == ::graph::OpType_LOGIC && node->opNum() == logic::NextIteration) {
/**
* NextIteration is special case: after successful execution of this op - we're changing execution position
*/
// VALIDATED
auto status = LogicExecutor::processNode(graph, node);
if (status != Status::OK) return status;
auto frame_id = frames.back();
flowPath->markNodeActive(node->id(), true);
flowPath->markExecuted(node->id(), true);
if (!flowPath->isRewindPlanned(frame_id)) {
auto nextLayer = node->getRewindLayer();
sd_debug("Node_%i planned rewind to Node_%i at [%i:%i]\n", node->id(), node->getRewindNode(), nextLayer.first,
nextLayer.second);
flowPath->planRewind(frame_id, true);
flowPath->setRewindPositionOnce(frame_id, nextLayer.first - 1);
continue;
}
} else if (node->opType() == ::graph::OpType_LOGIC && node->opNum() == logic::Exit) {
// Exit node is another special case: it can rewind executioner to specific point in graph
// VALIDATED
auto frame_id = frames.back();
// if this loop frame wasn't activated - just skip it
if (!flowPath->isFrameActive(frame_id)) {
flowPath->markNodeActive(node->id(), false);
leftFrame = true;
continue;
}
if (flowPath->isRewindPlanned(frame_id)) {
// just break loop here
l = flowPath->getRewindPosition(frame_id);
flowPath->setRewindPosition(frame_id, -1);
flowPath->planRewind(frame_id, false);
break;
} else {
// execute Exit node otherwise
auto status = LogicExecutor::processNode(graph, node);
if (status != Status::OK) return status;
leftFrame = true;
}
} else if (node->opType() == ::graph::OpType_LOGIC) {
/**
* If this LOGIC op, we'll use another execution model here
*/
auto status = LogicExecutor::processNode(graph, node);
if (status != Status::OK) return status;
} else {
auto timeStart2 = std::chrono::system_clock::now();
// actual node execution happens right here
Status status = executeFlatNode(graph, node, __variableSpace);
auto timeEnd = std::chrono::system_clock::now();
auto outerTime = std::chrono::duration_cast<std::chrono::nanoseconds>(timeEnd - timeStart2).count();
flowPath->setOuterTime(node->id(), outerTime);
if (status != Status::OK) return status;
// here we should handle divergent ops, and disable nodes accordingly
if (node->isDivergencePoint()) {
auto activeBranch = flowPath->branch(node->id());
sd_debug("Active branch at node [%i]: %i\n", node->id(), activeBranch);
// now we skip all branches except of this active one
}
if (Environment::getInstance().isDebugAndVerbose()) {
if (__variableSpace->getVariable(node->id())->hasNDArray()) {
auto array = __variableSpace->getVariable(node->id())->getNDArray();
auto shape = ShapeUtils::shapeAsString(array);
auto values = array->asIndexedString(16);
auto type = DataTypeUtils::asString(array->dataType());
sd_debug("node_%i finished. result shape: %s; data type: %s; first values: %s\n", node->id(), shape.c_str(),
type.c_str(), values->c_str());
} else if (__variableSpace->getVariable(node->id())->hasNDArrayList()) {
auto list = __variableSpace->getVariable(node->id())->hasNDArrayList()
? __variableSpace->getVariable(node->id())->getNDArrayList()
: nullptr;
sd_debug("node_% is ListOp, skipping evaluation", node->id());
} else {
sd_debug("node_% is Unknown: has no NDArray or NDArrayList", node->id());
}
}
}
// if node was executed - tag it as active
flowPath->markExecuted(node->id(), true);
}
}
// optionally saving execution time
if (Environment::getInstance().isProfiling()) {
flowPath->profile()->nodeById(lastId)->setTotalTime(GraphProfile::relativeTime(nodeTime));
flowPath->profile()->setExecutionTime(GraphProfile::relativeTime(timeStart));
}
// saving memory footprint for current run
if (__variableSpace->launchContext()->getWorkspace() != nullptr) {
auto m = __variableSpace->launchContext()->getWorkspace()->getAllocatedSize();
auto h = graph->hashCode();
memory::MemoryRegistrator::getInstance().setGraphMemoryFootprintIfGreater(h, m);
}
if (tempFlow) {
delete flowPath;
__variableSpace->setFlowPath(nullptr);
}
return Status::OK;
}
/**
* This method is provided for IPC:
* 1) it accepts pointer to FlatBuffers buffer
* 2) restores Graph from it
* 3) Executes this Graph
* 4) Packs execution results into FlatBuffers (FlatResults instance)
* 5) Returns pointer to FlatBuffer results buffer
*
*/
ResultWrapper *GraphExecutioner::executeFlatBuffer(Pointer pointer) {
uint8_t *buffer = reinterpret_cast<uint8_t *>(pointer);
auto restoredGraph = ::graph::GetFlatGraph(buffer);
// converting FlatGraph to internal representation
auto nativeGraph = new Graph(restoredGraph);
if (Environment::getInstance().isDebugAndVerbose()) {
nativeGraph->printOut();
}
FlowPath flowPath;
nativeGraph->getVariableSpace()->setFlowPath(&flowPath);
// sd_debug("Going to execute graph\n", 0);
// executing internal representation
auto status = execute(nativeGraph);
if (status != Status::OK) {
sd_printf("Graph execution failed with status: [%i]\n", status) return nullptr;
}
flatbuffers::FlatBufferBuilder builder(1024);
// fetching time reports
std::vector<flatbuffers::Offset<::graph::FlatTiming>> timings_vector;
for (int e = 0; e < (int)nativeGraph->getAllNodes()->size(); e++) {
Node *node = nativeGraph->getAllNodes()->at(e);
if (node->getContextPrototype() == nullptr) continue;
auto pair = ::graph::CreateLongPair(builder, flowPath.outerTime(node->id()), flowPath.innerTime(node->id()));
if (node->getName() != nullptr) {
auto name = builder.CreateString(node->getName()->c_str());
auto fr = CreateFlatTiming(builder, node->id(), name, pair);
timings_vector.push_back(fr);
} else {
auto fr = CreateFlatTiming(builder, node->id(), 0, pair);
timings_vector.push_back(fr);
}
}
// now, we'll prepare output, depending on given outputmode
auto outputs = nativeGraph->fetchOutputs();
auto size = static_cast<int>(outputs->size());
int arrays = 0;
std::vector<flatbuffers::Offset<::graph::FlatVariable>> variables_vector;
for (int e = 0; e < size; e++) {
auto var = outputs->at(e);
// FIXME: we want to export multi-output nodes as well
// FIXME: we want to export NDArrayList and skip nodes without outputs
if (!var->hasNDArray()) continue;
auto array = var->getNDArray();
auto fArray = FlatUtils::toFlatArray(builder, *array);
auto fName = builder.CreateString(*(var->getName()));
auto id = ::graph::CreateIntPair(builder, var->id(), var->index());
auto fv = CreateFlatVariable(builder, id, fName, static_cast<::graph::DType>(array->dataType()), 0, fArray);
variables_vector.push_back(fv);
arrays++;
}
sd_debug("Returning %i variables back\n", arrays);
auto varTimings = builder.CreateVector(timings_vector);
auto varVectors = builder.CreateVector(variables_vector);
auto result = CreateFlatResult(builder, restoredGraph->id(), varVectors, varTimings);
builder.Finish(result);
// we might want to keep this graph for future
delete outputs;
delete nativeGraph;
char *res = new char[builder.GetSize()];
memcpy(res, builder.GetBufferPointer(), builder.GetSize());
sd_debug("Buffer size: %lld\n", static_cast<sd::LongType>(builder.GetSize()));
return new ResultWrapper(builder.GetSize(), reinterpret_cast<Pointer>(res));
}
Graph *GraphExecutioner::importFromTensorFlow(const char *fileName) {
return nullptr;
}
/**
* This function returns file size for the given file name, or -1 if something went wrong
*/
long getFileSize(const char *filename) {
struct stat stat_buf;
int rc = stat(filename, &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
/**
* Helper function, that loads given filename into uint8_t array
*
*/
uint8_t *readFlatBuffers(const char *filename) {
long fileLen = getFileSize(filename);
if (fileLen < 0) {
sd_printf("File [%s] wasn't found. Please check path and permissions\n", filename);
THROW_EXCEPTION("File not found");
}
sd_debug("File length: %i\n", fileLen);
uint8_t *data = new uint8_t[fileLen];
FILE *in = fopen(filename, "rb");
int cnt = 0;
int b = 0;
while (cnt < fileLen) {
b = fread(data + cnt, 1, 1, in);
cnt += b;
}
fclose(in);
return data;
}
flatbuffers::Offset<::graph::FlatResult> GraphExecutioner::execute(Graph *graph, flatbuffers::FlatBufferBuilder &builder,
const ::graph::FlatInferenceRequest *request) {
ExecutionResult result;
auto varSpace = graph->getVariableSpace();
if (request != nullptr && request->variables() != nullptr) {
auto vars = request->variables();
for (size_t e = 0; e < vars->size(); e++) {
auto fv = vars->Get(e);
auto v = new Variable(fv);
varSpace->replaceVariable(v);
}
}
if (Environment::getInstance().isDebugAndVerbose()) graph->printOut();
auto status = execute(graph);
if (status != Status::OK) THROW_EXCEPTION(graph_execution_exception(request->id()).what());
auto outputs = graph->fetchOutputs();
if (outputs->size() == 0) THROW_EXCEPTION(no_results_exception(request->id()).what());
for (auto v : *outputs) {
result.emplace_back(v);
}
auto t = result.asFlatResult(builder);
delete outputs;
return t;
}
/**
* This method reads given FlatBuffers file, and returns Graph instance
*
* PLEASE NOTE: This method is mostly suited for tests and debugging/profiling
*/
Graph *GraphExecutioner::importFromFlatBuffers(const char *filename) {
auto data = readFlatBuffers(filename);
auto restoredGraph = importFromFlatPointer(reinterpret_cast<Pointer>(data));
delete[] data;
return restoredGraph;
}
Graph *GraphExecutioner::importFromFlatPointer(Pointer ptr) {
auto fg = ::graph::GetFlatGraph(reinterpret_cast<uint8_t *>(ptr));
auto restoredGraph = new Graph(fg);
return restoredGraph;
}
} // namespace graph
} // namespace sd
+119
View File
@@ -0,0 +1,119 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <exceptions/graph_execution_exception.h>
#include <exceptions/graph_exists_exception.h>
#include <graph/GraphExecutioner.h>
#include <graph/GraphHolder.h>
namespace sd {
namespace graph {
GraphHolder& GraphHolder::getInstance() {
static GraphHolder instance;
return instance;
};
void GraphHolder::registerGraph(sd::LongType graphId, Graph* graph) {
if (hasGraphAny(graphId)) THROW_EXCEPTION(graph_exists_exception(graphId).what());
_graphF[graphId] = graph;
sd::SimpleReadWriteLock lock;
_locks[graphId] = lock;
}
Graph* GraphHolder::cloneGraph(sd::LongType graphId) {
if (!this->hasGraph(graphId)) {
sd_printf("GraphHolder doesn't have graph stored for [%lld]\n", graphId);
THROW_EXCEPTION("Bad argument");
}
auto graph = _graphF[graphId]->cloneWithProxy();
return graph;
}
Graph* GraphHolder::pullGraph(sd::LongType graphId) {
if (!this->hasGraph(graphId)) {
sd_printf("GraphHolder doesn't have graph stored for [%lld]\n", graphId);
THROW_EXCEPTION("Bad argument");
}
auto graph = _graphF[graphId];
return graph;
}
void GraphHolder::forgetGraph(sd::LongType graphId) {
if (this->hasGraph(graphId)) _graphF.erase(graphId);
}
void GraphHolder::dropGraph(sd::LongType graphId) {
if (this->hasGraph(graphId)) {
auto g = _graphF[graphId];
forgetGraph(graphId);
delete g;
}
}
void GraphHolder::dropGraphAny(sd::LongType graphId) {
if (!hasGraphAny(graphId)) return;
this->lockWrite(graphId);
this->dropGraph(graphId);
this->unlockWrite(graphId);
}
bool GraphHolder::hasGraphAny(sd::LongType graphId) { return this->hasGraph(graphId); }
bool GraphHolder::hasGraph(sd::LongType graphId) { return _graphF.count(graphId) > 0; }
void GraphHolder::replaceGraph(sd::LongType graphId, Graph* graph) {
if (!hasGraph(graphId)) {
registerGraph(graphId, graph);
return;
}
this->lockWrite(graphId);
_graphF[graphId] = graph;
this->unlockWrite(graphId);
}
flatbuffers::Offset<::graph::FlatResult> GraphHolder::execute(sd::LongType graphId, flatbuffers::FlatBufferBuilder& builder,
const ::graph::FlatInferenceRequest* request) {
if (!hasGraph(graphId)) THROW_EXCEPTION(unknown_graph_exception(graphId).what());
lockRead(graphId);
auto graph = cloneGraph(graphId);
auto res = GraphExecutioner::execute(graph, builder, request);
delete graph;
unlockRead(graphId);
return res;
}
} // namespace graph
} // namespace sd
+152
View File
@@ -0,0 +1,152 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 23.01.18.
//
#include <graph/GraphState.h>
#include <graph/Node.h>
namespace sd {
namespace graph {
GraphState::GraphState(sd::LongType id) {
_id = id;
_graph = new Graph(nullptr, &_variableSpace);
};
GraphState::~GraphState() {
// stupid. we should get rid of pointers here i think. no need to bother
for (const auto& v : _scopes) {
v.second->forgetNodes();
delete v.second;
}
// we must remove reference to VariableSpace
_graph->forgetVariableSpace();
delete _graph;
};
sd::Status GraphState::registerScope(int scopeId) {
auto scope = new Scope(scopeId);
_scopes[scopeId] = scope;
auto scopeWrapper = new Node(::graph::OpType_LOGIC, 10, scopeId);
_graph->addNode(scopeWrapper);
return sd::Status::OK;
};
sd::Status GraphState::forgetScope(int scopeId) {
if (_scopes.count(scopeId) > 0)
_scopes.erase(scopeId);
else
return Logger::logKernelFailureMsg("Non-existent scope requested");
return sd::Status::OK;
};
#ifndef __JAVACPP_HACK__
sd::Status GraphState::attachOpToScope(int scopeId, int nodeId, ops::DeclarableOp* op, ArgumentsList inputs) {
if (_scopes.count(scopeId) == 0) return Logger::logKernelFailureMsg("GraphState: can't attach op to unknown scope");
auto scope = _scopes[scopeId];
// creating new Node
auto node = new Node(op, nodeId);
node->setScopeInfo(scopeId);
// mapping inputs here
for (int e = 0; e < inputs.size(); e++) {
auto p = inputs.at(e);
// each expected input is Variable in current VariableSpace
// it should have it's numerical and symbolic ID
if (!_variableSpace.hasVariable(p.first(), p.second())) {
auto var = new Variable();
var->setId(p.first(), p.second());
_variableSpace.putVariable(p.first(), p.second(), var);
}
node->pickInput(p.first(), p.second());
}
scope->push_back(node);
_graph->addNode(node);
return sd::Status::OK;
};
Graph* GraphState::graph() { return _graph; }
Scope* GraphState::getScope(int scopeId) {
if (_scopes.count(scopeId) == 0) {
sd_printf("GraphState: Unknown scope requested %i\n", scopeId);
return nullptr;
}
return _scopes[scopeId];
}
#endif
sd::Status GraphState::defineReturn(int scopeId, int nodeId, ArgumentsList args) {
if (_scopes.count(scopeId) == 0) return Logger::logKernelFailureMsg("GraphState: can't attach op to unknown scope");
auto scope = _scopes[scopeId];
// creating new Node for RETURN
auto node = new Node(::graph::OpType_LOGIC, 40, nodeId);
node->setScopeInfo(scopeId);
// mapping inputs here
for (int e = 0; e < args.size(); e++) {
auto p = args.at(e);
// each expected input is Variable in current VariableSpace
// it should have it's numerical and symbolic ID
if (!_variableSpace.hasVariable(p.first(), p.second())) {
auto var = new Variable();
var->setId(p.first(), p.second());
_variableSpace.putVariable(p.first(), p.second(), var);
}
node->pickInput(p.first(), p.second());
node->pickOutput(0, e);
}
scope->push_back(node);
_graph->addNode(node);
return sd::Status::OK;
}
bool GraphState::hasScope(int scopeId) { return _scopes.count(scopeId) > 0; }
VariableSpace* GraphState::variableSpace() { return &_variableSpace; };
sd::LongType GraphState::id() { return _id; }
sd::Status GraphState::attachOpToScope(int scopeId, sd::LongType opNum, int type, ArgumentsList inputs) {
// we should use OpRegistrator here, to create Node and push it to specific scope
return sd::Status::OK;
}
} // namespace graph
} // namespace sd
@@ -0,0 +1,75 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/InferenceRequest.h>
namespace sd {
namespace graph {
InferenceRequest::InferenceRequest(LongType graphId, ExecutorConfiguration *configuration) {
this->_id = graphId;
this->_configuration = configuration;
}
InferenceRequest::~InferenceRequest() {
for (auto v : _deletables) delete v;
}
void InferenceRequest::appendVariable(int id, NDArray *array) { appendVariable(id, 0, array); }
void InferenceRequest::appendVariable(int id, int index, NDArray *array) {
auto v = new Variable(array, nullptr, id, index);
insertVariable(v);
}
void InferenceRequest::appendVariable(std::string &id, NDArray *array) {
auto v = new Variable(array, id.c_str());
insertVariable(v);
}
void InferenceRequest::appendVariable(std::string &name, int id, int index, NDArray *array) {
auto v = new Variable(array, name.c_str(), id, index);
insertVariable(v);
}
void InferenceRequest::insertVariable(Variable *variable) {
variable->markRemovable(false);
variable->markReadOnly(true);
_variables.emplace_back(variable);
_deletables.emplace_back(variable);
}
void InferenceRequest::appendVariable(Variable *variable) { _variables.emplace_back(variable); }
flatbuffers::Offset<::graph::FlatInferenceRequest> InferenceRequest::asFlatInferenceRequest(
flatbuffers::FlatBufferBuilder &builder) {
std::vector<flatbuffers::Offset<::graph::FlatVariable>> vec;
for (Variable *v : _variables) {
vec.emplace_back(v->asFlatVariable(builder));
}
auto confOffset = _configuration != nullptr ? _configuration->asFlatConfiguration(builder) : 0;
auto vecOffset = builder.CreateVector(vec);
return CreateFlatInferenceRequest(builder, _id, vecOffset, confOffset);
}
} // namespace graph
} // namespace sd
+44
View File
@@ -0,0 +1,44 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 yurii@skymind.io
//
#include <graph/Intervals.h>
namespace sd {
// default constructor
Intervals::Intervals() : _content({{}}) {}
// constructor
Intervals::Intervals(const std::initializer_list<std::vector<LongType>>& content) : _content(content) {}
Intervals::Intervals(const std::vector<std::vector<LongType>>& content) : _content(content) {}
//////////////////////////////////////////////////////////////////////////
// accessing operator
std::vector<LongType> Intervals::operator[](const LongType i) const { return *(_content.begin() + i); }
//////////////////////////////////////////////////////////////////////////
// returns size of _content
int Intervals::size() const { return _content.size(); }
//////////////////////////////////////////////////////////////////////////
} // namespace sd
+720
View File
@@ -0,0 +1,720 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <array/NDArrayFactory.h>
#include <graph/FlatUtils.h>
#include <graph/Node.h>
#include <ops/declarable/LegacyBroadcastBoolOp.h>
#include <ops/declarable/LegacyBroadcastOp.h>
#include <ops/declarable/LegacyIndexReduceOp.h>
#include <ops/declarable/LegacyOp.h>
#include <ops/declarable/LegacyPairwiseTransformBoolOp.h>
#include <ops/declarable/LegacyPairwiseTransformOp.h>
#include <ops/declarable/LegacyRandomOp.h>
#include <ops/declarable/LegacyReduce3Op.h>
#include <ops/declarable/LegacyReduceBoolOp.h>
#include <ops/declarable/LegacyReduceFloatOp.h>
#include <ops/declarable/LegacyReduceLongOp.h>
#include <ops/declarable/LegacyReduceSameOp.h>
#include <ops/declarable/LegacyScalarBoolOp.h>
#include <ops/declarable/LegacyScalarOp.h>
#include <ops/declarable/LegacyStatsOp.h>
#include <ops/declarable/LegacyTransformBoolOp.h>
#include <ops/declarable/LegacyTransformFloatOp.h>
#include <ops/declarable/LegacyTransformSameOp.h>
#include <ops/declarable/LegacyTransformStrictOp.h>
#include <ops/declarable/OpRegistrator.h>
namespace sd {
namespace graph {
void sd::graph::Node::setOuterTime(sd::LongType time) {
}
void sd::graph::Node::setInnerTime(sd::LongType time) {
}
void sd::graph::Node::setGraph(sd::graph::Graph* graph) { _graph = graph; }
sd::graph::Graph* sd::graph::Node::getGraph() { return _graph; }
bool sd::graph::Node::hasGraphEmbedded() { return _graph != nullptr; }
void sd::graph::Node::markInplace(bool reallyInplace) {
_isInplace = reallyInplace;
if (_protoContext != nullptr) {
_protoContext->markInplace(reallyInplace);
}
}
::graph::OpClass sd::graph::Node::getOpClass() { return _opClass; }
bool sd::graph::Node::hasBlockAttached() { return _protoContext != nullptr; }
bool sd::graph::Node::isInplace() { return _isInplace; }
bool sd::graph::Node::isDivergencePoint() {
if (hasCustomOp()) {
return _customOp->getOpDescriptor()->isDivergent();
} else if (opType() == ::graph::OpType_LOGIC && opNum() == 30)
return true;
else
return false;
}
void sd::graph::Node::setActive(bool reallyActive) { _active = reallyActive; }
bool sd::graph::Node::isActive() { return _active; }
sd::LongType Node::getFrameId() { return _frameId; }
void Node::setFrameId(sd::LongType frameId) { _frameId = frameId; }
ContextPrototype* sd::graph::Node::getContextPrototype() {
if (_protoContext == nullptr)
_protoContext = new ContextPrototype(
this->getCustomOp() != nullptr ? this->getCustomOp()->getOpDescriptor() : nullptr, this->id());
if (_protoContext->inputs()->empty()) {
for (size_t e = 0; e < this->input()->size(); e++) {
_protoContext->inputs()->emplace_back(this->input()->at(e));
}
}
return _protoContext;
}
void sd::graph::Node::setContextPrototype(ContextPrototype* block) {
if (_protoContext != nullptr) THROW_EXCEPTION("Block already exists");
_protoContext = block;
}
void sd::graph::Node::setId(int id) { _id = id; }
sd::ops::DeclarableOp* sd::graph::Node::getCustomOp() { return _customOp; }
void sd::graph::Node::setCustomOp(sd::ops::DeclarableOp* customOp) {
_customOp = customOp;
// divergent ops (Switch etc) are always inplace, they don't allocate anything
if (_customOp != nullptr && customOp->getOpDescriptor()->isDivergent()) _isInplace = true;
}
bool sd::graph::Node::hasCustomOp() { return _customOp != nullptr; }
std::string* sd::graph::Node::name() { return this->getName(); }
std::string* sd::graph::Node::getName() { return &_name; }
void sd::graph::Node::setName(const std::string& name) { _name = name.c_str(); }
void sd::graph::Node::setName(std::string* name) { _name = *name; }
;
void sd::graph::Node::pickInput(std::pair<int, int>& pair) { _input.push_back(pair); }
void sd::graph::Node::pickInput(int inputId, int outputId) {
std::pair<int, int> p(inputId, outputId);
pickInput(p);
}
void sd::graph::Node::pickInput(int inputId) {
pickInput(inputId, 0);
if (inputId < 0)
_hasExternalInputs = true;
else
_hasInternalInputs = true;
}
void sd::graph::Node::pickExternalOutput(int outputId) {
std::pair<int, int> pair(outputId, 0);
_output.push_back(pair);
_hasExternalOutputs = true;
}
void sd::graph::Node::pickOutputOnce(int outputId) {
std::pair<int, int> pair(outputId, 0);
if (std::find(_output.begin(), _output.end(), pair) == _output.end()) pickOutput(outputId);
}
void sd::graph::Node::pickOutput(int nodeId, int outputId) {
std::pair<int, int> pair(nodeId, outputId);
_output.emplace_back(pair);
}
void sd::graph::Node::pickOutput(int outputId) {
std::pair<int, int> pair(outputId, 0);
_output.emplace_back(pair);
if (outputId < 0)
_hasExternalOutputs = true;
else
_hasInternalOutputs = true;
}
sd::LongType* sd::graph::Node::getDimensionsPtr() { return _dim; }
std::vector<sd::LongType>* sd::graph::Node::getDimensions() { return &_dimensions; }
int sd::graph::Node::getLayer() { return _layer; }
void sd::graph::Node::setLayer(int layer) { _layer = layer; }
bool sd::graph::Node::hasExternalOutputs() { return _hasExternalOutputs; }
bool sd::graph::Node::hasExternalInputs() { return _hasExternalInputs; }
bool sd::graph::Node::hasInternalOutputs() { return _hasInternalOutputs; }
bool sd::graph::Node::hasInternalInputs() { return _hasInternalInputs; }
bool sd::graph::Node::isMultiInput() { return _input.size() > 1; }
bool sd::graph::Node::isMultiOutput() { return _output.size() > 1; }
double* sd::graph::Node::extraParams() { return _extraParams; }
int Node::totalReferences() { return _referencedBy.size(); }
void Node::addReference(int nodeId) { _referencedBy.emplace_back(nodeId); }
::graph::OpType sd::graph::Node::opType() { return _opType; }
int sd::graph::Node::id() { return _id; }
sd::LongType sd::graph::Node::opNum() { return _opNum; }
std::vector<std::pair<int, int>>* sd::graph::Node::input() { return &_input; }
std::vector<std::pair<int, int>>* sd::graph::Node::output() { return &_output; }
bool Node::isScoped() { return _scope_id != 0; }
void Node::setScopeInfo(int id, const char* name) {
_scope_id = id;
if (name != nullptr) _scope_name = name;
}
int Node::scopeId() { return _scope_id; }
std::string* Node::scopeName() { return &_scope_name; }
template <typename T>
Node* Node::asT() {
auto node = this->clone();
node->_dataType = DataTypeUtils::fromT<T>();
return node;
}
BUILD_SINGLE_TEMPLATE( SD_LIB_EXPORT Node* Node::asT, (), SD_COMMON_TYPES);
sd::graph::Node::Node(sd::ops::DeclarableOp* customOp, int id, std::initializer_list<int> input,
std::initializer_list<int> output, std::initializer_list<int> dimensions, float scalar,
std::initializer_list<double> tArgs, std::initializer_list<int> iArgs) {
this->_opType = ::graph::OpType_CUSTOM;
this->_id = id;
this->_opNum = customOp->getOpHash();
this->_extraParams = nullptr;
this->_dataType = sd::DataType::FLOAT32; // float as default
this->_dim = nullptr;
this->_customOp = customOp;
_hasExternalInputs = false;
_hasExternalOutputs = false;
_hasInternalInputs = false;
_hasInternalOutputs = false;
for (auto i : input) pickInput(i);
for (auto o : output) pickOutput(o);
if (dimensions.size() > 0) {
_dim = new sd::LongType[dimensions.size()];
int cnt = 0;
for (auto d : dimensions) {
_dimensions.push_back(d);
_dim[cnt++] = d;
}
}
auto block = new ContextPrototype(this->getCustomOp()->getOpDescriptor(), this->id(), false);
for (auto v : dimensions) block->getAxis()->emplace_back(v);
for (auto v : iArgs) block->getIArguments()->emplace_back(v);
for (auto v : tArgs) block->getTArguments()->emplace_back(v);
this->setContextPrototype(block);
}
void sd::graph::Node::setOpType(::graph::OpType opType) { this->_opType = opType; }
sd::graph::Node::Node(::graph::OpType opType, int opNum, int id, std::initializer_list<int> input,
std::initializer_list<int> output, std::initializer_list<int> dimensions, float scalar,
std::initializer_list<double> tArgs, std::initializer_list<int> iArgs) {
this->_opType = opType;
this->_id = id;
this->_opNum = opNum;
this->_extraParams = nullptr;
this->_dataType = sd::DataType::FLOAT32; // float as default
this->_dim = nullptr;
_hasExternalInputs = false;
_hasExternalOutputs = false;
_hasInternalInputs = false;
_hasInternalOutputs = false;
for (auto i : input) pickInput(i);
for (auto o : output) pickOutput(o);
if (dimensions.size() > 0) {
_dim = new sd::LongType[dimensions.size()];
int cnt = 0;
for (auto d : dimensions) {
_dimensions.push_back(d);
_dim[cnt++] = d;
}
}
// these ops allow in-place execution by design
if (opType == ::graph::OpType_TRANSFORM_SAME || opType == ::graph::OpType_TRANSFORM_FLOAT || opType == ::graph::OpType_TRANSFORM_STRICT ||
opType == ::graph::OpType_TRANSFORM_BOOL || opType == ::graph::OpType_SCALAR || opType == ::graph::OpType_BROADCAST) {
if (_output.size() <= 1) {
_isInplace = true;
}
_opClass = ::graph::OpClass_TRANSFORM;
} else if (opType == ::graph::OpType_REDUCE_SAME || opType == ::graph::OpType_REDUCE_FLOAT || opType == ::graph::OpType_REDUCE_BOOL ||
opType == ::graph::OpType_REDUCE_LONG || opType == ::graph::OpType_SUMMARYSTATS) {
_opClass = ::graph::OpClass_REDUCTION;
}
if (opType == ::graph::OpType_BROADCAST || opType == ::graph::OpType_BROADCAST_BOOL || opType == ::graph::OpType_INDEX_REDUCE ||
opType == ::graph::OpType_SUMMARYSTATS || opType == ::graph::OpType_REDUCE_BOOL || opType == ::graph::OpType_REDUCE_SAME ||
opType == ::graph::OpType_REDUCE_FLOAT || opType == ::graph::OpType_REDUCE_3 || opType == ::graph::OpType_TRANSFORM_STRICT ||
opType == ::graph::OpType_TRANSFORM_SAME || opType == ::graph::OpType_TRANSFORM_FLOAT || opType == ::graph::OpType_TRANSFORM_BOOL ||
opType == ::graph::OpType_RANDOM || opType == ::graph::OpType_PAIRWISE || opType == ::graph::OpType_PAIRWISE_BOOL ||
opType == ::graph::OpType_SCALAR_BOOL || opType == ::graph::OpType_SCALAR) {
this->_isDeductable = true;
auto block = new ContextPrototype(nullptr, this->id(), false);
for (auto v : dimensions) block->getAxis()->emplace_back(v);
for (auto v : iArgs) block->getIArguments()->emplace_back(v);
for (auto v : tArgs) block->getTArguments()->emplace_back(v);
NDArray *_scalar = NDArrayFactory::create(0.0f);
this->setContextPrototype(block);
this->setCustomOp(Node::buildOpByType(opType, (int)input.size(), (int)block->getIArguments()->size(),
(int)block->getTArguments()->size(), opNum, _scalar));
block->setOpDescriptor(this->getCustomOp()->getOpDescriptor());
delete _scalar;
} else if (opType == ::graph::OpType_CUSTOM) {
if (this->getCustomOp()) {
auto block = new ContextPrototype(this->getCustomOp()->getOpDescriptor(), this->id(), false);
for (auto v : dimensions) block->getAxis()->emplace_back(v);
for (auto v : iArgs) block->getIArguments()->emplace_back(v);
for (auto v : tArgs) block->getTArguments()->emplace_back(v);
this->setContextPrototype(block);
} else
THROW_EXCEPTION("wrong custom operation given");
}
};
sd::graph::Node::Node(const ::graph::FlatNode* node) {
_hasExternalInputs = false;
_hasExternalOutputs = false;
_hasInternalInputs = false;
_hasInternalOutputs = false;
_extraParams = nullptr;
_dim = nullptr;
_dataType = sd::DataType::FLOAT32; // float as default
if (node->scope_id() != 0) this->_scope_id = node->scope_id();
if (node->scope_name() != nullptr && node->scope_name()->size() > 0) this->_scope_name = node->scope_name()->str();
if (node != nullptr) {
this->_id = node->id();
// this->_dataType = DataTypeUtils::fromFlatDataType(node->dataType());
this->_opNum = node->opNum();
this->_opType = node->opType();
if (node->name() != nullptr && node->name()->c_str() != nullptr) {
this->_name = node->name()->str();
}
if (node->inputPaired() != nullptr && node->inputPaired()->size() > 0) {
for (int e = 0; e < (int)node->inputPaired()->size(); e++) {
auto pair = node->inputPaired()->Get(e);
pickInput(pair->first(), pair->second());
}
} else if (node->input() != nullptr && node->input()->size() > 0) {
for (int e = 0; e < (int)node->input()->size(); e++) pickInput(node->input()->Get(e));
} else {
if (this->opType() != ::graph::OpType_LOGIC) {
if (this->_name.size() > 0) {
sd_debug("Node [%i:<%s>] has no inputs defined\n", this->_id, this->_name.c_str());
} else {
sd_debug("Node [%i:<noname>] has no inputs defined\n", this->_id);
}
}
}
if (node->extraParams() != nullptr && node->extraParams()->size() > 0) {
_extraParams = new double[node->extraParams()->size()];
for (int e = 0; e < (int)node->extraParams()->size(); e++) {
_extraParams[e] = static_cast<double>(node->extraParams()->Get(e));
}
}
if (node->dimensions() != nullptr && node->dimensions()->size() > 0) {
_dim = new sd::LongType [node->dimensions()->size()];
for (int e = 0; e < (int)node->dimensions()->size(); e++) {
_dimensions.emplace_back(node->dimensions()->Get(e));
_dim[e] = node->dimensions()->Get(e);
}
}
if (this->opType() == ::graph::OpType_LOGIC && this->opNum() == 100L) {
if (node->extraInteger()->size() < 1) {
sd_printf("Node_%i is type of Enter, but has no FrameID defined\n", this->id());
THROW_EXCEPTION("Enter node must have FrameID specified");
}
this->setFrameId(node->extraInteger()->Get(0));
}
// these ops allow in-place execution by design
if (_opType == ::graph::OpType_BROADCAST || _opType == ::graph::OpType_BROADCAST_BOOL || _opType == ::graph::OpType_INDEX_REDUCE ||
_opType == ::graph::OpType_SUMMARYSTATS || _opType == ::graph::OpType_REDUCE_BOOL || _opType == ::graph::OpType_REDUCE_SAME ||
_opType == ::graph::OpType_REDUCE_FLOAT || _opType == ::graph::OpType_REDUCE_3 || _opType == ::graph::OpType_TRANSFORM_STRICT ||
_opType == ::graph::OpType_TRANSFORM_SAME || _opType == ::graph::OpType_TRANSFORM_FLOAT || _opType == ::graph::OpType_TRANSFORM_BOOL ||
_opType == ::graph::OpType_RANDOM || _opType == ::graph::OpType_PAIRWISE || _opType == ::graph::OpType_PAIRWISE_BOOL ||
_opType == ::graph::OpType_SCALAR_BOOL || _opType == ::graph::OpType_SCALAR) {
if (_output.size() <= 1) {
_isInplace = true;
}
if (node->input() != nullptr && node->input()->size() > 0) {
this->_isDeductable = true;
auto block = new ContextPrototype(nullptr, this->id(), false);
for (auto v : _dimensions) block->getAxis()->emplace_back(v);
if (node->extraParams() != nullptr && node->extraParams()->size() > 0)
for (int e = 0; e < (int)node->extraParams()->size(); e++) {
block->getTArguments()->emplace_back(static_cast<double>(node->extraParams()->Get(e)));
}
if (node->extraBools() != nullptr && node->extraBools()->size() > 0)
for (int e = 0; e < (int)node->extraBools()->size(); e++) {
block->getBArguments()->push_back(node->extraBools()->Get(e));
}
if (node->extraInteger() != nullptr && node->extraInteger()->size() > 0)
for (int e = 0; e < (int)node->extraInteger()->size(); e++) {
block->getIArguments()->emplace_back(node->extraInteger()->Get(e));
}
if (node->extraTypes() != nullptr && node->extraTypes()->size() > 0) {
for (int e = 0; e < (int)node->extraTypes()->size(); e++) {
block->getDArguments()->emplace_back((sd::DataType)node->extraTypes()->Get(e));
}
}
NDArray *_scalar = NDArrayFactory::create(0.0f);
this->setContextPrototype(block);
this->setCustomOp(Node::buildOpByType(_opType, (int)node->input()->size(), (int)block->getIArguments()->size(),
(int)block->getTArguments()->size(), (int)_opNum, _scalar));
block->setOpDescriptor(this->getCustomOp()->getOpDescriptor());
delete _scalar;
} else if (node->inputPaired() != nullptr && node->inputPaired()->size() > 0) {
this->_isDeductable = true;
auto block = new ContextPrototype(nullptr, this->id(), false);
for (size_t e = 0; e < this->input()->size(); e++) {
block->inputs()->emplace_back(this->input()->at(e));
}
// there's no other IArgs in legacy options, actually
for (auto v : _dimensions) block->getAxis()->emplace_back(v);
if (node->extraParams() != nullptr && node->extraParams()->size() > 0)
for (int e = 0; e < (int)node->extraParams()->size(); e++) {
block->getTArguments()->emplace_back(static_cast<double>(node->extraParams()->Get(e)));
}
if (node->extraBools() != nullptr && node->extraBools()->size() > 0)
for (int e = 0; e < (int)node->extraBools()->size(); e++) {
block->getBArguments()->push_back(node->extraBools()->Get(e));
}
if (node->extraInteger() != nullptr && node->extraInteger()->size() > 0)
for (int e = 0; e < (int)node->extraInteger()->size(); e++) {
block->getIArguments()->emplace_back(node->extraInteger()->Get(e));
}
if (node->extraTypes() != nullptr && node->extraTypes()->size() > 0) {
for (int e = 0; e < (int)node->extraTypes()->size(); e++) {
block->getDArguments()->emplace_back((sd::DataType)node->extraTypes()->Get(e));
}
}
this->setContextPrototype(block);
NDArray *_scalar = NDArrayFactory::create(0.0f);
this->setCustomOp(Node::buildOpByType(_opType, (int)node->inputPaired()->size(),
(int)block->getIArguments()->size(), (int)block->getTArguments()->size(),
(int)_opNum, _scalar));
block->setOpDescriptor(this->getCustomOp()->getOpDescriptor());
delete _scalar;
}
} else if (this->_opType == ::graph::OpType_CUSTOM) {
auto op = sd::ops::OpRegistrator::getInstance().getOperation(this->opNum());
if (op == nullptr) {
sd_verbose("Can't find operation: %lld\n", this->opNum());
THROW_EXCEPTION("Can't find requested operation");
}
auto block = new ContextPrototype(nullptr, this->id());
for (size_t e = 0; e < this->input()->size(); e++) {
block->inputs()->emplace_back(this->input()->at(e));
}
if (node->extraInteger() != nullptr)
for (uint32_t e = 0; e < node->extraInteger()->size(); e++) {
auto v = node->extraInteger()->Get(e);
// FIXME: remove this static_cast, iArgs should be sd::LongType
block->getIArguments()->emplace_back(static_cast<int>(v));
}
if (node->extraParams() != nullptr)
for (uint32_t e = 0; e < node->extraParams()->size(); e++)
block->getTArguments()->emplace_back(static_cast<double>(node->extraParams()->Get(e)));
if (node->extraBools() != nullptr && node->extraBools()->size() > 0)
for (int e = 0; e < (int)node->extraBools()->size(); e++) {
block->getBArguments()->push_back(node->extraBools()->Get(e));
}
if (node->extraTypes() != nullptr && node->extraTypes()->size() > 0) {
for (int e = 0; e < (int)node->extraTypes()->size(); e++) {
block->getDArguments()->emplace_back((sd::DataType)node->extraTypes()->Get(e));
}
}
for (auto v : _dimensions) block->getAxis()->emplace_back(v);
this->setContextPrototype(block);
this->setCustomOp(op);
block->setOpDescriptor(this->getCustomOp()->getOpDescriptor());
}
} else {
// empty dynamic node, tests probably
}
}
sd::DataType Node::dataType() { return _dataType; }
ContextPrototype* Node::protoContext() { return _protoContext; }
sd::graph::Node::~Node() {
if (_extraParams != nullptr) delete[] _extraParams;
if (_dim != nullptr) delete[] _dim;
if (_isDeductable && _customOp != nullptr) {
Node::deleteOpByType(_opType, _customOp);
}
}
int sd::graph::Node::getRewindNode() { return _rewindNode; }
void sd::graph::Node::setRewindNode(int nodeId) { _rewindNode = nodeId; }
std::pair<int, int>& sd::graph::Node::getRewindLayer() { return _rewindLayer; };
void sd::graph::Node::setRewindLayer(int layerId, int stepId) {
_rewindLayer.first = layerId;
_rewindLayer.second = stepId;
}
bool sd::graph::Node::equals(Node* other) {
if (_opType == other->_opType && _dataType == other->_dataType && _opNum == other->_opNum) return true;
return false;
}
void sd::graph::Node::deleteOpByType(::graph::OpType opType, void* op) {
switch (opType) {
case ::graph::OpType_PAIRWISE:
delete reinterpret_cast<sd::ops::LegacyPairwiseTransformOp*>(op);
break;
case ::graph::OpType_PAIRWISE_BOOL:
delete reinterpret_cast<sd::ops::LegacyPairwiseTransformBoolOp*>(op);
break;
case ::graph::OpType_TRANSFORM_STRICT:
delete reinterpret_cast<sd::ops::LegacyTransformStrictOp*>(op);
break;
case ::graph::OpType_TRANSFORM_SAME:
delete reinterpret_cast<sd::ops::LegacyTransformSameOp*>(op);
break;
case ::graph::OpType_TRANSFORM_FLOAT:
delete reinterpret_cast<sd::ops::LegacyTransformFloatOp*>(op);
break;
case ::graph::OpType_TRANSFORM_BOOL:
delete reinterpret_cast<sd::ops::LegacyTransformBoolOp*>(op);
break;
case ::graph::OpType_SCALAR:
delete reinterpret_cast<sd::ops::LegacyScalarOp*>(op);
break;
case ::graph::OpType_SCALAR_BOOL:
delete reinterpret_cast<sd::ops::LegacyScalarBoolOp*>(op);
break;
case ::graph::OpType_REDUCE_3:
delete reinterpret_cast<sd::ops::LegacyReduce3Op*>(op);
break;
case ::graph::OpType_REDUCE_SAME:
delete reinterpret_cast<sd::ops::LegacyReduceSameOp*>(op);
break;
case ::graph::OpType_REDUCE_FLOAT:
delete reinterpret_cast<sd::ops::LegacyReduceFloatOp*>(op);
break;
case ::graph::OpType_REDUCE_LONG:
delete reinterpret_cast<sd::ops::LegacyReduceLongOp*>(op);
break;
case ::graph::OpType_REDUCE_BOOL:
delete reinterpret_cast<sd::ops::LegacyReduceBoolOp*>(op);
break;
case ::graph::OpType_INDEX_REDUCE:
delete reinterpret_cast<sd::ops::LegacyIndexReduceOp*>(op);
break;
case ::graph::OpType_SUMMARYSTATS:
delete reinterpret_cast<sd::ops::LegacyStatsOp*>(op);
break;
case ::graph::OpType_RANDOM:
delete reinterpret_cast<sd::ops::LegacyRandomOp*>(op);
break;
case ::graph::OpType_BROADCAST:
delete reinterpret_cast<sd::ops::LegacyBroadcastOp*>(op);
break;
case ::graph::OpType_BROADCAST_BOOL:
delete reinterpret_cast<sd::ops::LegacyBroadcastBoolOp*>(op);
break;
case ::graph::OpType_CUSTOM:
delete reinterpret_cast<sd::ops::DeclarableOp*>(op);
break;
default:
THROW_EXCEPTION("Bad opType passed in");
}
}
sd::ops::DeclarableOp* sd::graph::Node::buildOpByType(::graph::OpType opType, int numInputs, int numIArgs, int numTArgs,
int opNum, NDArray* scalar) {
switch (opType) {
case ::graph::OpType_PAIRWISE:
return new sd::ops::LegacyPairwiseTransformOp(opNum);
case ::graph::OpType_PAIRWISE_BOOL:
return new sd::ops::LegacyPairwiseTransformBoolOp(opNum);
case ::graph::OpType_TRANSFORM_STRICT:
return new sd::ops::LegacyTransformStrictOp(opNum);
case ::graph::OpType_TRANSFORM_SAME:
return new sd::ops::LegacyTransformSameOp(opNum);
case ::graph::OpType_TRANSFORM_FLOAT:
return new sd::ops::LegacyTransformFloatOp(opNum);
case ::graph::OpType_TRANSFORM_BOOL:
return new sd::ops::LegacyTransformBoolOp(opNum);
case ::graph::OpType_SCALAR:
return scalar == nullptr ? new sd::ops::LegacyScalarOp(opNum) : new sd::ops::LegacyScalarOp(opNum, *scalar);
case ::graph::OpType_SCALAR_BOOL:
return scalar == nullptr ? new sd::ops::LegacyScalarBoolOp(opNum)
: new sd::ops::LegacyScalarBoolOp(opNum, *scalar);
case ::graph::OpType_REDUCE_3:
return new sd::ops::LegacyReduce3Op(opNum);
case ::graph::OpType_REDUCE_SAME:
return new sd::ops::LegacyReduceSameOp(opNum);
case ::graph::OpType_REDUCE_FLOAT:
return new sd::ops::LegacyReduceFloatOp(opNum);
case ::graph::OpType_REDUCE_LONG:
return new sd::ops::LegacyReduceLongOp(opNum);
case ::graph::OpType_REDUCE_BOOL:
return new sd::ops::LegacyReduceBoolOp(opNum);
case ::graph::OpType_INDEX_REDUCE:
return new sd::ops::LegacyIndexReduceOp(opNum);
case ::graph::OpType_SUMMARYSTATS:
return new sd::ops::LegacyStatsOp(opNum);
case ::graph::OpType_RANDOM:
return new sd::ops::LegacyRandomOp(opNum);
case ::graph::OpType_BROADCAST:
return new sd::ops::LegacyBroadcastOp(opNum);
case ::graph::OpType_BROADCAST_BOOL:
return new sd::ops::LegacyBroadcastBoolOp(opNum);
default:
THROW_EXCEPTION("Bad opType passed in");
}
return nullptr;
}
bool Node::isDeductable() { return _isDeductable; }
void Node::setDeductable(bool reallyDeductable) { _isDeductable = reallyDeductable; }
Node* Node::clone() {
if (this->_customOp && this->_opType == ::graph::OpType_CUSTOM) {
auto clone = new Node(this->_customOp, _id);
clone->pullValues(this);
return clone;
} else {
auto clone = new Node(_opType, _opNum, _id);
clone->pullValues(this);
// op time
if (!_isDeductable)
clone->_customOp = _customOp;
else {
auto c = static_cast<sd::ops::LegacyOp*>(_customOp);
clone->_customOp = c->clone();
}
return clone;
}
}
} // namespace graph
} // namespace sd
+48
View File
@@ -0,0 +1,48 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 16/11/17.
//
#include <graph/NodeState.h>
namespace sd {
namespace graph {
NodeState::NodeState(int id) { _id = id; }
void NodeState::setInnerTime(LongType time) { _inner = time; }
void NodeState::setOuterTime(LongType time) { _outer = time; }
LongType NodeState::innerTime() { return _inner; }
LongType NodeState::outerTime() { return _outer; }
void NodeState::markActive(bool isActive) { _active = isActive; }
bool NodeState::isActive() { return _active; }
int NodeState::branch() { return _branch; }
void NodeState::markBranch(int index) { _branch = index; }
bool NodeState::wasExecuted() { return _executed; }
void NodeState::markExecuted(bool wasExecuted) { _executed = wasExecuted; }
} // namespace graph
} // namespace sd
@@ -0,0 +1,46 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 11/06/18.
//
#include <graph/ResultWrapper.h>
#include <stdexcept>
namespace sd {
namespace graph {
ResultWrapper::ResultWrapper(LongType size, Pointer ptr) {
if (size <= 0) THROW_EXCEPTION("FlatResult size should be > 0");
_size = size;
_pointer = ptr;
}
ResultWrapper::~ResultWrapper() {
if (_pointer != nullptr && _size > 0) {
auto ptr = reinterpret_cast<char *>(_pointer);
delete[] ptr;
}
}
LongType ResultWrapper::size() { return _size; }
Pointer ResultWrapper::pointer() { return _pointer; }
} // namespace graph
} // namespace sd
+59
View File
@@ -0,0 +1,59 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 14.10.2017.
//
#include <graph/Scope.h>
namespace sd {
namespace graph {
Scope::Scope(int id, const char* name) {
_id = id;
if (name != nullptr)
_name = name;
else
name = "";
}
Scope::~Scope() {
for (auto v : _nodes) delete v;
}
void Scope::push_back(Node* node) { _nodes.emplace_back(node); }
std::vector<Node*>* Scope::nodes() { return &_nodes; }
int Scope::size() { return (int)_nodes.size(); }
int Scope::id() { return _id; }
std::string* Scope::name() { return &_name; }
void Scope::forgetNodes() { _nodes.clear(); }
Scope* Scope::clone() {
auto clone = new Scope(_id, _name.c_str());
for (auto v : _nodes) clone->_nodes.emplace_back(v->clone());
return clone;
}
} // namespace graph
} // namespace sd
@@ -0,0 +1,120 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/SessionLocalStorage.h>
#include <graph/Stash.h>
#include <graph/VariableSpace.h>
namespace sd {
namespace graph {
SessionLocalStorage::SessionLocalStorage(VariableSpace* variableSpace, Stash* stash) {
// we start from 1, since key 0 holds original VariableSpace
_sessionCounter.store(1);
_variableSpace = variableSpace;
_stash = stash;
}
VariableSpace* SessionLocalStorage::localVariableSpace(LongType sessionId) {
_mutex.lock();
auto varSpace = _threadVariableSpace.at(sessionId);
_mutex.unlock();
return varSpace;
}
VariableSpace* SessionLocalStorage::localVariableSpace() { return localVariableSpace(getSessionId()); }
SessionLocalStorage::~SessionLocalStorage() {
for (const auto& v : _threadVariableSpace) {
delete v.second;
}
}
LongType SessionLocalStorage::getThreadId() {
#ifdef __APPLE__
// syscall?
#elif _WIN32
// some win32api
#else
// syscall!
#endif
auto id = std::this_thread::get_id();
uint64_t* ptr = (uint64_t*)&id;
return (*ptr);
}
int SessionLocalStorage::numberOfSessions() {
_mutex.lock();
int size = (int)_threadSession.size();
_mutex.unlock();
return size;
}
void SessionLocalStorage::endSession(LongType sessionId) {
// we should delete specific holders here
_mutex.lock();
auto vs = _threadVariableSpace[sessionId];
_threadVariableSpace.erase(sessionId);
delete vs;
_mutex.unlock();
}
void SessionLocalStorage::endSession() {
auto tid = getThreadId();
_mutex.lock();
auto ntid = _threadSession[tid];
_threadSession.erase(tid);
_mutex.unlock();
endSession(ntid);
}
LongType SessionLocalStorage::getSessionId() {
auto tid = getThreadId();
_mutex.lock();
auto ntid = _threadSession[tid];
_mutex.unlock();
return ntid;
}
LongType SessionLocalStorage::startSession() {
auto tid = getThreadId();
sd_debug("Adding ThreadId: %i;\n", (int)tid);
LongType ntid = _sessionCounter++;
_mutex.lock();
_threadSession[tid] = ntid;
_threadVariableSpace[ntid] = _variableSpace->clone();
_mutex.unlock();
return ntid;
}
} // namespace graph
} // namespace sd
+98
View File
@@ -0,0 +1,98 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/Stash.h>
namespace std {
size_t hash<sd::graph::KeyPair>::operator()(const sd::graph::KeyPair &k) const {
using std::hash;
auto res = std::hash<std::string>()(k.name());
res ^= std::hash<int>()(k.key()) + 0x9e3779b9 + (res << 6) + (res >> 2);
return res;
}
} // namespace std
namespace sd {
namespace graph {
KeyPair::KeyPair(int node, const char *name) {
_node = node;
_name = std::string(name);
}
bool KeyPair::operator<(const KeyPair &other) const {
if (_node < other._node)
return true;
else if (_node > other._node)
return false;
else
return _name < other._name;
}
Stash::Stash() {
//
}
Stash::~Stash() {
if (_handles.size() > 0) this->clear();
}
/*
bool sd::graph::Stash::checkStash(sd::graph::Block& block, const char *name) {
return checkStash(block.getNodeId(), name);
}
*/
bool Stash::checkStash(int nodeId, const char *name) {
KeyPair kp(nodeId, name);
return _stash.count(kp) > 0;
}
/*
sd::NDArray* sd::graph::Stash::extractArray(sd::graph::Block& block, const char *name) {
return extractArray(block.getNodeId(), name);
}
*/
NDArray *Stash::extractArray(int nodeId, const char *name) {
KeyPair kp(nodeId, name);
return _stash[kp];
}
/*
void sd::graph::Stash::storeArray(sd::graph::Block& block, const char *name, sd::NDArray *array) {
storeArray(block.getNodeId(), name, array);
}
*/
void Stash::storeArray(int nodeId, const char *name, NDArray *array) {
KeyPair kp(nodeId, name);
_stash[kp] = array;
// storing reference to delete it once it's not needed anymore
_handles.push_back(array);
}
void Stash::clear() {
for (auto v : _handles) delete v;
_handles.clear();
_stash.clear();
}
} // namespace graph
} // namespace sd
+43
View File
@@ -0,0 +1,43 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 16/11/17.
//
#include <graph/TimeHolder.h>
namespace sd {
namespace graph {
void TimeHolder::setOuterTime(int nodeId, LongType time) { _outer[nodeId] = time; }
void TimeHolder::setInnerTime(int nodeId, LongType time) { _inner[nodeId] = time; }
LongType TimeHolder::outerTime(int nodeId) {
if (_outer.count(nodeId) == 0) return 0;
return _outer[nodeId];
}
LongType TimeHolder::innerTime(int nodeId) {
if (_inner.count(nodeId) == 0) return 0;
return _inner[nodeId];
}
} // namespace graph
} // namespace sd
+298
View File
@@ -0,0 +1,298 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <array/ByteOrderUtils.h>
#include <array/DataTypeConversions.h>
#include <array/DataTypeUtils.h>
#include <graph/FlatUtils.h>
#include <graph/Variable.h>
#include <helpers/EnumUtils.h>
#include <helpers/StringUtils.h>
namespace sd {
namespace graph {
template <typename N>
Variable *Variable::asT() {
auto result = new Variable(this->isPlaceholder());
result->markExternal(this->_external);
result->setId(this->_id);
result->markReadOnly(this->_readOnly);
result->setName(&this->_name);
result->setIndex(this->_index);
if (this->_ndarray != nullptr) result->setNDArray(new NDArray(this->_ndarray->template asT<N>()));
// FIXME: add support for ArrayList
if (this->_list != nullptr) {
sd_printf("ArrayList not supported yet\n", "");
THROW_EXCEPTION("ArrayList not supported yet for asT");
}
return result;
}
BUILD_SINGLE_TEMPLATE( SD_LIB_EXPORT Variable *Variable::asT, (), SD_COMMON_TYPES);
Variable *Variable::clone() {
auto result = new Variable(this->isPlaceholder());
result->_external = this->_external;
result->_id = this->_id;
result->_readOnly = this->_readOnly;
result->_name = this->_name;
result->_index = this->_index;
if (this->_ndarray != nullptr) {
result->_ndarray = new NDArray(this->_ndarray->dup(this->_ndarray->ordering(), false));
result->_readOnly = false;
result->_removable = true;
}
if (this->_list != nullptr) result->_list = this->_list->clone();
return result;
}
void Variable::setIndex(int index) { _index = index; }
bool Variable::hasNDArray() { return _ndarray != nullptr; }
void Variable::setVariableType(VariableType variableType) { _variableType = variableType; }
bool Variable::hasNDArrayList() { return _list != nullptr; }
bool Variable::isPlaceholder() { return _placeholder; }
std::string *Variable::getName() { return &_name; }
void Variable::setName(std::string *name) { _name = *name; }
int Variable::id() { return _id; }
int Variable::index() { return _index; }
void Variable::setId(int id) { _id = id; }
bool Variable::isEmpty() {
if (_variableType == NDARRAY)
return _ndarray == nullptr || !_ndarray->nonNull();
else if (_variableType == ARRAY_LIST)
return _list == nullptr;
return false;
}
bool Variable::isExternal() { return _external; }
bool Variable::isReadOnly() { return _readOnly; }
void Variable::markExternal(bool reallyExternal) { this->_external = reallyExternal; }
void Variable::markRemovable(bool reallyRemovable) {
if (!reallyRemovable) sd_debug("", "");
this->_removable = reallyRemovable;
}
void Variable::markReadOnly(bool reallyReadOnly) { this->_readOnly = reallyReadOnly; }
NDArray *Variable::getNDArray() {
if (_variableType != NDARRAY) {
sd_printf("Variable[%i:%i/<%s>] is has [%s] type, but NDArray was requested\n", this->_id, this->_index,
this->_name.c_str(), EnumUtils::_VariableTypeToString(_variableType));
}
if (this->_ndarray == nullptr) {
if (_name.empty()) {
auto nodeId = StringUtils::valueToString<int>(this->id());
auto outputIndex = StringUtils::valueToString<int>(this->index());
auto msg = "Array doesn't exist for Variable <" + nodeId + ":" + outputIndex + ">";
THROW_EXCEPTION(msg.c_str());
} else {
auto outputIndex = StringUtils::valueToString<int>(this->index());
auto msg = "Array doesn't exist for Variable <" + this->_name + ":" + outputIndex + ">";
THROW_EXCEPTION(msg.c_str());
}
}
return this->_ndarray;
}
NDArrayList *Variable::getNDArrayList() {
if (_variableType != ARRAY_LIST) {
sd_debug("Variable[%i:%i/<%s>] is has [%s] type, but NDArrayList was requested\n", this->_id, this->_index,
this->_name.c_str(), EnumUtils::_VariableTypeToString(_variableType));
}
return this->_list;
}
bool Variable::isRemovable() { return _removable; }
void Variable::setNDArrayList(NDArrayList *list) {
this->_variableType = ARRAY_LIST;
this->_list = list;
}
void Variable::setNDArray(NDArray *array) {
this->_variableType = NDARRAY;
this->_ndarray = array;
}
VariableType Variable::variableType() { return _variableType; }
Variable::Variable(const ::graph::FlatVariable *flatVariable) {
auto vid = flatVariable->id();
this->_id = vid->first();
this->_index = vid->second();
if (flatVariable->name() != nullptr && flatVariable->name()->size() != 0) this->_name = flatVariable->name()->str();
_external = true;
_readOnly = false;
int8_t *buffer = nullptr;
switch (flatVariable->variabletype()) {
case ::graph::VarType_VARIABLE: {
// ?????
if (flatVariable->ndarray() != nullptr) {
auto ar = flatVariable->ndarray();
_ndarray = FlatUtils::fromFlatArray(ar);
}
_variableType = NDARRAY;
} break;
case ::graph::VarType_CONSTANT: {
if (flatVariable->ndarray() == nullptr) THROW_EXCEPTION("CONSTANT variable must have NDArray bundled");
auto ar = flatVariable->ndarray();
if (ar->dtype() == ::graph::DType_UTF8) {
_ndarray = FlatUtils::fromFlatArray(ar);
} else {
_ndarray = FlatUtils::fromFlatArray(ar);
}
_variableType = NDARRAY;
} break;
case ::graph::VarType_ARRAY: {
// ?????
if (flatVariable->ndarray() != nullptr) {
auto ar = flatVariable->ndarray();
_ndarray = FlatUtils::fromFlatArray(ar);
// _ndarray->triggerAllocationFlag(true);
}
_variableType = NDARRAY;
} break;
case ::graph::VarType_PLACEHOLDER: {
if (flatVariable->shape() == nullptr && flatVariable->ndarray() == nullptr)
THROW_EXCEPTION("PLACEHOLDER variable must have shape defined");
if (flatVariable->ndarray() != nullptr) {
auto ar = flatVariable->ndarray();
_ndarray = FlatUtils::fromFlatArray(ar);
_variableType = NDARRAY;
}
if (flatVariable->shape() != nullptr) {
int shapeLen = flatVariable->shape()->size();
for (size_t i = 0; i < flatVariable->shape()->size(); i++) _shape.emplace_back(flatVariable->shape()->Get(i));
if (_ndarray == nullptr) _variableType = PLACEHOLDER;
}
} break;
default:
THROW_EXCEPTION("Unknown variable type used");
}
}
std::vector<LongType> &Variable::shape() { return _shape; }
Variable::Variable(bool placeholder) { _placeholder = placeholder; }
Variable::Variable(NDArray *array, const char *name) {
_ndarray = array;
_external = false;
_readOnly = false;
if (name != nullptr) _name = std::string(name);
if (_ndarray != nullptr) _variableType = NDARRAY;
}
Variable::Variable(NDArray *array, const char *name, int id, int idx) : Variable(array, name) {
_id = id;
_index = idx;
}
Variable::~Variable() {
if (_variableType == NDARRAY) {
sd_debug("Removing variable <%i:%i>\n", _id, _index);
if (_ndarray != nullptr && _removable && !_readOnly) delete _ndarray;
}
}
void Variable::setId(int id, int idx) {
_id = id;
_index = idx;
}
flatbuffers::Offset<::graph::FlatVariable> Variable::asFlatVariable(flatbuffers::FlatBufferBuilder &builder) {
if (this->hasNDArray()) {
auto array = this->getNDArray();
auto fShape = builder.CreateVector(array->getShapeInfoAsFlatVector());
auto fBuffer = builder.CreateVector(array->asByteVector());
// packing array
auto fArray = CreateFlatArray(builder, fShape, fBuffer, (::graph::DType)array->dataType());
// packing id/index of this var
auto fVid = ::graph::CreateIntPair(builder, this->_id, this->_index);
// name is still optional
flatbuffers::Offset<flatbuffers::String> stringId = 0;
if (!this->_name.empty()) stringId = builder.CreateString(this->_name);
// returning array
return CreateFlatVariable(builder, fVid, stringId, static_cast<::graph::DType>(array->dataType()), 0, fArray);
} else {
THROW_EXCEPTION("Variable::asFlatVariable isn't possible for NDArrayList");
}
return CreateFlatVariable(builder, 0, 0, static_cast<::graph::DType>(0), 0, 0);
}
} // namespace graph
} // namespace sd
namespace std {
size_t hash<std::pair<int, int>>::operator()(const std::pair<int, int> &k) const {
auto v = std::hash<int>()(k.first);
v ^= std::hash<int>()(k.second) + 0x9e3779b9 + (v << 6) + (v >> 2);
return v;
}
size_t hash<bfloat16>::operator()(const bfloat16 &k) const { return std::hash<float>()((float)k); }
size_t hash<float16>::operator()(const float16 &k) const { return std::hash<float>()((float)k); }
} // namespace std
@@ -0,0 +1,196 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/VariableProxy.h>
namespace sd {
namespace graph {
VariableProxy::VariableProxy(VariableSpace *ref) {
if (ref == nullptr) _backed = new VariableSpace();
_backed = ref;
_current = new VariableSpace();
}
VariableProxy::~VariableProxy() {
delete _current;
}
int VariableProxy::numberOfPlaceholders() { return _backed->numberOfPlaceholders(); }
std::vector<Variable *> *VariableProxy::getPlaceholders() { return _backed->getPlaceholders(); }
bool VariableProxy::hasExternalVariable(int it) { return _backed->hasExternalVariable(it); }
bool VariableProxy::hasExternalVariable(std::pair<int, int> &pair) { return _backed->hasExternalVariable(pair); }
bool VariableProxy::hasExternalVariable(std::string *symbol) { return _backed->hasExternalVariable(symbol); }
bool VariableProxy::hasVariable(int id) { return _current->hasVariable(id) || _backed->hasVariable(id); }
bool VariableProxy::hasVariable(int id, int idx) {
return _current->hasVariable(id, idx) || _backed->hasVariable(id, idx);
}
bool VariableProxy::hasVariable(std::pair<int, int> &pair) {
return _current->hasVariable(pair) || _backed->hasVariable(pair);
}
void VariableProxy::dropVariable(std::pair<int, int> &pair) { dropVariable(pair.first, pair.second); }
void VariableProxy::dropVariable(int id, int idx) {
assert(_current->hasVariable(id, idx));
_current->dropVariable(id, idx);
}
std::vector<Variable *> VariableProxy::getVariables() {
std::vector<Variable *> result;
auto b = _backed->getVariables();
auto c = _current->getVariables();
for (auto v : b) result.emplace_back(v);
for (auto v : c) result.emplace_back(v);
return result;
}
bool VariableProxy::hasVariable(std::string *symbol) {
return _current->hasVariable(symbol) || _backed->hasVariable(symbol);
}
Variable *VariableProxy::getVariable(int id) {
if (_current->hasVariable(id)) return _current->getVariable(id);
if (_backed->hasVariable(id)) return _backed->getVariable(id);
sd_printf("Unable to get Variable to proxy: [%i]\n", id);
THROW_EXCEPTION("Bad arguments");
return nullptr;
}
Variable *VariableProxy::getVariable(int id, int idx) {
if (_current->hasVariable(id, idx)) return _current->getVariable(id, idx);
if (_backed->hasVariable(id, idx)) return _backed->getVariable(id, idx);
sd_printf("Unable to get Variable to proxy: [%i:%i]\n", id, idx);
THROW_EXCEPTION("Bad arguments");
return nullptr;
}
Variable *VariableProxy::getVariable(std::pair<int, int> &pair) {
if (_current->hasVariable(pair)) return _current->getVariable(pair);
if (_backed->hasVariable(pair)) return _backed->getVariable(pair);
sd_printf("Unable to get Variable to proxy: [%i:%i]\n", pair.first, pair.second);
THROW_EXCEPTION("Bad arguments");
return nullptr;
}
Variable *VariableProxy::getVariable(std::string *symbol) {
if (_current->hasVariable(symbol)) return _current->getVariable(symbol);
if (_backed->hasVariable(symbol)) return _backed->getVariable(symbol);
sd_printf("Unable to get Variable to proxy: [%s]\n", symbol->c_str());
THROW_EXCEPTION("Bad arguments");
return nullptr;
}
void VariableProxy::replaceVariable(Variable *variable) {
if (variable->getName() != nullptr && !variable->getName()->empty()) {
// if variable has name defined - we should resolve it via backing var space
if (_backed->hasVariable(variable->getName())) {
auto origVar = _backed->getVariable(variable->getName());
variable->setId(origVar->id(), origVar->index());
_current->replaceVariable(variable);
} else
_current->replaceVariable(variable);
} else // if proxy has variable - that's one story
_current->replaceVariable(variable);
}
Variable *VariableProxy::putVariable(std::pair<int, int> &pair, NDArray *array) {
return _current->putVariable(pair, array);
}
void VariableProxy::putVariable(std::pair<int, int> &pair, Variable *variable) {
_current->putVariable(pair, variable);
}
void VariableProxy::putVariable(int id, Variable *variable) { _current->putVariable(id, variable); }
void VariableProxy::putVariable(int id, NDArray *array) { _current->putVariable(id, array); }
void VariableProxy::putVariable(int id, int idx, NDArray &array) { _current->putVariable(id, idx, array); }
Variable *VariableProxy::putVariable(int id, int idx, NDArray *array) { return _current->putVariable(id, idx, array); }
void VariableProxy::putVariable(int id, int idx, Variable *array) { _current->putVariable(id, idx, array); }
void VariableProxy::trackList(NDArrayList *list) { _current->trackList(list); }
Stash *VariableProxy::getStash() { return _current->getStash(); }
void VariableProxy::setFlowPath(FlowPath *timers) { _current->setFlowPath(timers); }
FlowPath *VariableProxy::flowPath() { return _current->flowPath(); }
void VariableProxy::putOutputVariable(Variable *variable) { _current->putOutputVariable(variable); }
LongType VariableProxy::externalMemory() { return _backed->externalMemory() + _current->externalMemory(); }
LongType VariableProxy::internalMemory() { return _backed->internalMemory() + _current->internalMemory(); }
LongType VariableProxy::totalMemory() { return _backed->totalMemory() + _current->totalMemory(); }
int VariableProxy::externalEntries() { return _backed->externalEntries() + _current->externalEntries(); }
int VariableProxy::internalEntries() { return _backed->internalEntries() + _current->internalEntries(); }
int VariableProxy::totalEntries() { return _backed->totalEntries() + _current->totalEntries(); }
VariableSpace *VariableProxy::clone() {
auto clone = new VariableProxy(_backed);
delete clone->_current;
clone->_current = _current->clone();
return clone;
}
VariableSpace &VariableProxy::operator=(const VariableSpace &other) {
if (this == &other) return *this;
sd_printf("VariableProxy = not implemented\n", "");
return *this;
}
memory::Workspace *VariableProxy::workspace() { return _workspace; }
} // namespace graph
} // namespace sd
@@ -0,0 +1,382 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 raver119@gmail.com
//
#include <graph/VariableSpace.h>
#include <legacy/NativeOps.h>
namespace sd {
namespace graph {
std::vector<sd::graph::Variable*>* sd::graph::VariableSpace::getExternalVariables() { return &_external; }
sd::graph::Stash* sd::graph::VariableSpace::getStash() { return &_stash; }
sd::graph::VariableSpace* sd::graph::VariableSpace::clone() {
auto result = new VariableSpace();
for (auto const& x : _paired) {
std::pair<int, int> pair(x.first.first, x.first.second);
Variable* clonedVar = x.second->clone();
result->injectVariable(pair, clonedVar);
}
return result;
}
void VariableSpace::setWorkspace(sd::memory::Workspace* workspace) {
_workspace = workspace;
}
sd::graph::VariableSpace* sd::graph::VariableSpace::asT() {
auto result = new VariableSpace();
for (auto const& x : _paired) {
std::pair<int, int> pair(x.first.first, x.first.second);
}
return result;
}
void sd::graph::VariableSpace::injectVariable(std::pair<int, int>& pair, Variable* variable) {
if (pair.second == 0) {
if (pair.first < 0)
this->_variables[pair.first] = variable;
else
this->_temporary[pair.first] = variable;
}
if (variable->getName() != nullptr && variable->getName()->length() > 0)
this->_symbolic[*(variable->getName())] = variable;
this->_paired[pair] = variable;
this->_handles->push_back(variable);
}
std::vector<sd::graph::Variable*>* sd::graph::VariableSpace::getPlaceholders() { return &_placeholders; }
int sd::graph::VariableSpace ::numberOfPlaceholders() { return _placeholders.size(); }
bool sd::graph::VariableSpace::hasVariable(std::string* symbol) { return _symbolic.count(*symbol) == 1; }
sd::graph::Variable* sd::graph::VariableSpace::getVariable(std::string* symbol) { return _symbolic.at(*symbol); }
bool sd::graph::VariableSpace::hasVariable(int id, int index) {
std::pair<int, int> pair(id, index);
return hasVariable(pair);
}
bool VariableSpace::hasExternalVariable(int id) {
if (!hasVariable(id)) return false;
auto var = getVariable(id);
return var->isExternal();
}
bool VariableSpace::hasExternalVariable(std::pair<int, int>& pair) {
if (!hasVariable(pair)) return false;
auto var = getVariable(pair);
return var->isExternal();
}
bool VariableSpace::hasExternalVariable(std::string* symbol) {
if (!hasVariable(symbol)) return false;
auto var = getVariable(symbol);
return var->isExternal();
}
sd::graph::Variable* sd::graph::VariableSpace::getVariable(int id, int index) {
std::pair<int, int> pair(id, index);
return getVariable(pair);
}
sd::graph::Variable* sd::graph::VariableSpace::getVariable(std::pair<int, int>& pair) {
if (pair.first < 0) {
return getVariable(pair.first);
} else {
return _paired.at(pair);
}
sd_printf("Unknown variable requested: [%i,%i]\n", pair.first, pair.second);
THROW_EXCEPTION("Unknown variable requested");
return nullptr;
}
bool sd::graph::VariableSpace::hasVariable(int id) { return _variables.count(id) == 1 || _temporary.count(id) == 1; }
bool sd::graph::VariableSpace::hasVariable(std::pair<int, int>& id) { return _paired.count(id) > 0; }
void sd::graph::VariableSpace::putOutputVariable(Variable* variable) {
putVariable(variable->id(), variable);
}
int sd::graph::VariableSpace::externalEntries() { return _external.size(); }
int sd::graph::VariableSpace::internalEntries() { return _internal.size(); }
int sd::graph::VariableSpace::totalEntries() { return externalEntries() + internalEntries(); }
sd::LongType sd::graph::VariableSpace::externalMemory() {
sd::LongType size = 0;
for (auto n : _external) {
size += n->getNDArray()->memoryFootprint();
}
return size;
}
std::vector<Variable*> VariableSpace::getVariables() {
std::vector<Variable*> result;
for (auto v : _internal) result.emplace_back(v);
for (auto v : _external) result.emplace_back(v);
return result;
}
sd::LongType sd::graph::VariableSpace::internalMemory() {
sd::LongType size = 0;
for (auto n : _internal) {
size += n->getNDArray()->memoryFootprint();
}
return size;
}
sd::LongType sd::graph::VariableSpace::totalMemory() { return externalMemory() + internalMemory(); }
Variable* sd::graph::VariableSpace::putVariable(std::pair<int, int>& pair, NDArray* array) {
auto variable = new Variable(array, nullptr, pair.first, pair.second);
this->putVariable(pair, variable);
return variable;
}
Variable* sd::graph::VariableSpace::putVariable(int node, int idx, NDArray* array) {
std::pair<int, int> pair(node, idx);
return this->putVariable(pair, array);
}
void sd::graph::VariableSpace::putVariable(int node, int idx, Variable* variable) {
std::pair<int, int> pair(node, idx);
this->putVariable(pair, variable);
}
void sd::graph::VariableSpace::silentPutVariable(std::pair<int, int>& pair, Variable* variable) {
_varmap.lock();
_paired[pair] = variable;
_varmap.unlock();
}
void sd::graph::VariableSpace::putVariable(std::pair<int, int>& pair, Variable* variable) {
silentPutVariable(pair, variable);
if (variable->isPlaceholder()) _placeholders.push_back(variable);
// copying duplicate for compatibility
if (pair.second == 0 && !this->hasVariable(pair.first)) {
this->putVariable(pair.first, variable);
} else {
if (variable->getName() != nullptr && variable->getName()->length() != 0) {
_symbolic[*(variable->getName())] = variable;
}
_varmap.lock();
_handles->push_back(variable);
_varmap.unlock();
}
}
void VariableSpace::trackList(sd::NDArrayList* list) { _lists.emplace_back(list); }
void sd::graph::VariableSpace::putVariable(int id, Variable* variable) {
// we don't want to add variables more then once
if (_variables.count(id) > 0 || _temporary.count(id) > 0) {
auto local = id < 0 ? _variables.at(id) : _temporary.at(id);
if (!local->hasNDArray() && variable->hasNDArray()) {
local->setNDArray(variable->getNDArray());
// we're inheriting this from Variable
local->markReadOnly(variable->isReadOnly());
local->markRemovable(variable->isRemovable());
}
return;
}
_varmap.lock();
_handles->emplace_back(variable);
if (_auto_counter >= id) _auto_counter = id - 1;
variable->setId(id);
if (variable->getName() != nullptr && variable->getName()->length() != 0) {
_symbolic[*(variable->getName())] = variable;
}
// we have special list for external variables to ensure graph completeness
if (id < 0) {
_external.push_back(variable);
_variables[id] = variable;
} else {
_internal.push_back(variable);
_temporary[id] = variable;
}
_varmap.unlock();
std::pair<int, int> pair(id, 0);
if (!hasVariable(pair)) {
this->silentPutVariable(pair, variable);
if (variable->isPlaceholder()) _placeholders.push_back(variable);
}
}
void sd::graph::VariableSpace::putVariable(int id, int idx, NDArray& array) {
auto* var = new sd::graph::Variable(&array, "", id, idx);
var->markRemovable(false);
var->markReadOnly(true);
// let's see if this op needs
bool d = this->hasVariable(id, idx);
this->putVariable(id, var);
// if var for this nodeid already exists - we'll just delete variable
if (d) delete var;
}
void sd::graph::VariableSpace::putVariable(int id, NDArray* array) {
auto* var = new sd::graph::Variable(array);
this->putVariable(id, var);
}
sd::graph::Variable* sd::graph::VariableSpace::getVariable(int id) {
if (id < 0) {
return _variables.at(id);
} else {
return _temporary.at(id);
}
}
LaunchContext* sd::graph::VariableSpace::launchContext() { return LaunchContext::defaultContext(); }
std::vector<Variable*>* sd::graph::VariableSpace::handles() { return _handles; }
/*
* FIXME: this thing have nice chances to become backend-specific!
*/
sd::graph::VariableSpace::~VariableSpace() {
// loop through variables and release them
for (auto p : *_handles) {
delete p;
}
delete _handles;
for (auto p : _lists) delete p;
_lists.clear();
}
VariableSpace& VariableSpace::operator=(const VariableSpace& other) {
if (this == &other) return *this;
for (auto const& x : other._paired) {
std::pair<int, int> pair(x.first.first, x.first.second);
Variable* clonedVar = x.second->clone();
if (pair.second == 0) {
if (pair.first < 0)
this->_variables[pair.first] = clonedVar;
else
this->_temporary[pair.first] = clonedVar;
}
if (clonedVar->getName() != nullptr && clonedVar->getName()->length() > 0)
this->_symbolic[*(clonedVar->getName())] = clonedVar;
this->_paired[pair] = clonedVar;
this->_handles->push_back(clonedVar);
}
return *this;
}
void VariableSpace::replaceVariable(Variable* variable) {
bool replaced = false;
// trying name first
if (variable->getName() != nullptr && !variable->getName()->empty()) {
sd_printf("Trying to replace variable by name: [%s]\n", variable->getName()->c_str());
if (hasVariable(variable->getName())) {
sd_printf("Replacing by name: [%s]\n", variable->getName()->c_str());
auto vs = getVariable(variable->getName());
dropVariable(vs->id(), vs->index());
putVariable(vs->id(), vs->index(), variable);
delete vs;
replaced = true;
}
} else {
sd_printf("Trying to replace variable by id: [%i:%i]\n", variable->id(), variable->index());
if (hasVariable(variable->id(), variable->index())) {
sd_printf("Replacing by id: [%i:%i]\n", variable->id(), variable->index());
auto vs = getVariable(variable->id(), variable->index());
dropVariable(variable->id(), variable->index());
putVariable(vs->id(), vs->index(), variable);
delete vs;
replaced = true;
}
}
if (!replaced) {
sd_printf("wasn't able to replace variable, putting\n", "");
putVariable(variable->id(), variable->index(), variable);
}
}
void VariableSpace::dropVariable(std::pair<int, int>& pair) { dropVariable(pair.first, pair.second); }
void VariableSpace::dropVariable(int id, int idx) {}
void VariableSpace::setFlowPath(FlowPath* flow) { _flow = flow; }
FlowPath* VariableSpace::flowPath() { return _flow; }
VariableSpace::VariableSpace() { _handles = new std::vector<Variable*>; }
} // namespace graph
} // namespace sd
@@ -0,0 +1,40 @@
/* ******************************************************************************
*
*
* 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.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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
******************************************************************************/
//
// Created by raver119 on 15/11/17.
//
#include <graph/VariablesSet.h>
namespace sd {
namespace graph {
Status VariablesSet::status() { return _status; }
int VariablesSet::size() { return _holder.size(); }
void VariablesSet::push_back(Variable *variable) { _holder.push_back(variable); }
Variable *VariablesSet::at(int index) { return _holder.at(index); }
VariablesSet::VariablesSet(Status status) { _status = status; }
VariablesSet::~VariablesSet() {
for (auto v : _holder) delete v;
}
} // namespace graph
} // namespace sd