2 * Copyright (C) 2019 Samsung Electronics Co., Ltd. All Rights Reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
16 * @date 04 December 2019
17 * @brief This is Layers Classes for Neural Network
18 * @see https://github.com/nnstreamer/nntrainer
19 * @author Jijoong Moon <jijoong.moon@samsung.com>
20 * @bug No known bugs except for NYI items
26 #include <layer_internal.h>
27 #include <layer_node.h>
28 #include <nntrainer_error.h>
29 #include <nntrainer_log.h>
30 #include <parse_util.h>
31 #include <util_func.h>
35 void LayerV1::setActivation(ActivationType acti) {
36 if (acti == ActivationType::ACT_UNKNOWN) {
37 throw std::invalid_argument("Error:have to specify activation function");
39 activation_type = acti;
42 int LayerV1::checkValidation() {
43 int status = ML_ERROR_NONE;
45 if (activation_type == ActivationType::ACT_UNKNOWN) {
46 ml_loge("Error: Have to set activation for this layer");
47 return ML_ERROR_INVALID_PARAMETER;
53 void LayerV1::setBatch(unsigned int batch) {
54 for (unsigned int idx = 0; idx < getNumInputs(); ++idx)
55 input_dim[idx].setTensorDim(0, batch);
57 for (unsigned int idx = 0; idx < getNumOutputs(); ++idx)
58 output_dim[idx].setTensorDim(0, batch);
61 std::vector<Tensor> LayerV1::getOutputs() {
62 std::vector<Tensor> ret;
63 for (unsigned int i = 0; i < getNumOutputs(); ++i) {
64 ret.push_back(net_hidden[i]->getVariableRef());
69 std::vector<Tensor> LayerV1::getDerivatives() {
70 std::vector<Tensor> ret;
71 for (unsigned int i = 0; i < getNumInputs(); ++i) {
72 ret.push_back(net_input[i]->getGradientRef());
77 void LayerV1::copy(std::shared_ptr<LayerV1> l) {
78 for (auto const &w : l->weights)
79 weights.push_back(w.clone());
81 this->input_dim = l->input_dim;
82 this->output_dim = l->output_dim;
83 this->activation_type = l->activation_type;
85 this->weight_regularizer = l->weight_regularizer;
86 this->weight_regularizer_constant = l->weight_regularizer_constant;
87 this->weight_initializer = l->weight_initializer;
88 this->trainable = l->trainable;
91 sharedConstTensors LayerV1::forwarding_with_val(sharedConstTensors input,
92 sharedConstTensors label,
95 if (getNumInputs() != input.size()) {
97 ss << "Number of inputs mismatched, given: " << input.size()
98 << " expected: " << getNumInputs();
99 throw std::invalid_argument(ss.str().c_str());
102 for (unsigned int i = 0; i < getNumInputs(); ++i) {
103 net_input[i]->getVariableRef() = input[i]->clone();
106 if (!label.empty()) {
107 for (unsigned int i = 0; i < getNumOutputs(); ++i) {
108 net_hidden[i]->getGradientRef() = label[i]->clone();
112 forwarding(training);
114 nntrainer::sharedConstTensors out;
116 for (unsigned int i = 0; i < getNumOutputs(); ++i) {
117 out.push_back(MAKE_SHARED_TENSOR(net_hidden[i]->getVariable()));
123 sharedConstTensors LayerV1::backwarding_with_val(sharedConstTensors label) {
125 for (unsigned int i = 0; i < getNumOutputs(); ++i) {
126 net_hidden[i]->getGradientRef() = label[i]->clone();
131 nntrainer::sharedConstTensors out;
133 for (unsigned int i = 0; i < getNumInputs(); ++i) {
134 out.push_back(MAKE_SHARED_TENSOR(net_input[i]->getGradient()));
140 void LayerV1::read(std::ifstream &file) {
141 for (auto &weight : weights) {
142 weight.getVariableRef().read(file);
146 void LayerV1::save(std::ofstream &file) {
147 for (auto &weight : weights) {
148 weight.getVariableRef().save(file);
152 int LayerV1::setProperty(std::vector<std::string> values) {
153 int status = ML_ERROR_NONE;
156 values = loadProperties(values, layer_props);
157 } catch (std::invalid_argument &e) {
158 ml_loge("parsing property failed, reason: %s", e.what());
159 return ML_ERROR_INVALID_PARAMETER;
162 /// @todo: deprecate this in favor of loadProperties
163 for (unsigned int i = 0; i < values.size(); ++i) {
167 status = getKeyValue(values[i], key, value);
170 unsigned int type = parseLayerProperty(key);
173 ml_logd("value is empty: key: %s, value: %s", key.c_str(), value.c_str());
174 return ML_ERROR_INVALID_PARAMETER;
178 /// @note this calls derived setProperty if available
179 setProperty(static_cast<PropertyType>(type), value);
181 ml_logd("value or key is not valid, key: %s, value: %s", key.c_str(),
183 return ML_ERROR_INVALID_PARAMETER;
189 void LayerV1::setProperty(const PropertyType type, const std::string &value) {
190 int status = ML_ERROR_NONE;
193 case PropertyType::input_shape: {
194 if (getNumInputs() != 1) {
195 throw std::invalid_argument("input_shape keyword is only for one input");
198 TensorDim &in_dim = input_dim[0];
199 if (!value.empty()) {
200 unsigned int cache_batch_size = 1;
201 /** cache original value of batch size */
202 if (in_dim.batch()) {
203 cache_batch_size = in_dim.batch();
206 status = in_dim.setTensorDim(value.c_str());
207 if (in_dim.batch() > 1) {
208 ml_logw("Batch size set with input dimension %d is ignored."
209 "Set batchsize property for the model to update batchsize.",
212 /** set back to cache value of dimension */
213 in_dim.batch(cache_batch_size);
214 throw_status(status);
217 case PropertyType::activation:
218 if (!value.empty()) {
219 setActivation((ActivationType)parseType(value, TOKEN_ACTI));
222 case PropertyType::weight_regularizer:
223 if (!value.empty()) {
225 (WeightRegularizer)parseType(value, TOKEN_WEIGHT_REGULARIZER);
226 if (weight_regularizer == WeightRegularizer::UNKNOWN) {
227 throw std::invalid_argument("[Layer] Unknown Weight decay");
231 case PropertyType::weight_regularizer_constant:
232 if (!value.empty()) {
233 status = setFloat(weight_regularizer_constant, value);
234 throw_status(status);
237 case PropertyType::weight_initializer:
238 if (!value.empty()) {
240 (WeightInitializer)parseType(value, TOKEN_WEIGHT_INIT);
243 case PropertyType::bias_initializer:
244 if (!value.empty()) {
245 bias_initializer = (WeightInitializer)parseType(value, TOKEN_WEIGHT_INIT);
248 case PropertyType::trainable:
249 if (!value.empty()) {
250 status = setBoolean(trainable, value);
251 throw_status(status);
256 "[Layer] Unknown Layer Property Key for value " + std::string(value);
257 throw exception::not_supported(msg);
261 template <typename T>
262 void LayerV1::printIfValid(std::ostream &out, const PropertyType type,
266 } catch (exception::not_supported &e) {
270 out << propToStr(static_cast<unsigned int>(type)) << ": " << target
274 void LayerV1::printShapeInfo(std::ostream &out) {
275 for (unsigned int idx = 0; idx < getNumInputs(); ++idx) {
276 out << "input " << input_dim[idx];
277 for (unsigned int i = 0; i < weights.size(); i++)
278 out << "inner" << i << " " << weightAt(i).getVariable().getDim();
280 for (unsigned int idx = 0; idx < getNumOutputs(); ++idx) {
281 out << "output " << output_dim[idx];
285 void LayerV1::printPropertiesMeta(std::ostream &out) {
287 out, PropertyType::activation,
288 static_cast<std::underlying_type<ActivationType>::type>(activation_type));
291 void LayerV1::printProperties(std::ostream &out) {
292 out << "Trainable: " << trainable << std::endl;
293 printIfValid(out, PropertyType::weight_regularizer,
294 static_cast<int>(weight_regularizer));
295 printIfValid(out, PropertyType::weight_regularizer_constant,
296 weight_regularizer_constant);
299 void LayerV1::printMetric(std::ostream &out) {
301 out << "Weight regularization loss: " << loss;
305 void LayerV1::printPreset(std::ostream &out, PrintPreset preset) {
306 unsigned int flags = 0;
308 case PrintPreset::PRINT_ALL:
309 flags = PRINT_WEIGHTS | PRINT_METRIC;
310 /// fall through intended
311 case PrintPreset::PRINT_SUMMARY_META:
312 flags |= PRINT_PROP_META;
313 /// fall through intended
314 case PrintPreset::PRINT_SUMMARY:
315 flags |= PRINT_INST_INFO | PRINT_SHAPE_INFO | PRINT_PROP | PRINT_PROP_META;
317 case PrintPreset::PRINT_NONE:
320 throw ::std::invalid_argument("undefined preset given");
325 void LayerV1::print(std::ostream &out, unsigned int flags) {
326 /** @todo properly move print to LayerNode */
327 if (flags & PRINT_INST_INFO) {
328 out << "===================";
329 // if (getName().empty())
330 // printInstance(out, this);
332 // out << "<" << getName() << ">" << std::endl;
334 out << "Layer Type: " << getType() << std::endl;
337 if (flags & PRINT_SHAPE_INFO) {
338 out << "======shape information: " << std::endl;
342 if (flags & PRINT_PROP_META) {
343 out << "======meta properties: " << std::endl;
344 printPropertiesMeta(out);
347 if (flags & PRINT_PROP) {
348 out << "======properties: " << std::endl;
349 printProperties(out);
352 if (flags & PRINT_WEIGHTS) {
353 out << "======weights: " << std::endl;
354 for (auto const &weight : weights) {
355 out << '[' << weight.getName() << ']' << std::endl;
356 out << weight.getVariable();
360 if (flags & PRINT_METRIC) {
361 out << "======metrics: " << std::endl;
366 std::shared_ptr<LayerV1> getLayerV1Devel(std::shared_ptr<ml::train::Layer> l) {
367 return std::static_pointer_cast<LayerNode>(l)->getObject();
370 } /* namespace nntrainer */