Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : /**
3 : * Copyright (C) 2020 Parichay Kapoor <pk.kapoor@samsung.com>
4 : *
5 : * @file var_grad.h
6 : * @date 13 November 2020
7 : * @see https://github.com/nnstreamer/nntrainer
8 : * @author Parichay Kapoor <pk.kapoor@samsung.com>
9 : * @bug No known bugs except for NYI items
10 : * @brief This is Var_Grad Class for Neural Network
11 : *
12 : */
13 :
14 : #ifndef __VAR_GRAD_H__
15 : #define __VAR_GRAD_H__
16 :
17 : #include <tuple>
18 :
19 : #include <tensor.h>
20 : #include <tensor_wrap_specs.h>
21 :
22 : namespace nntrainer {
23 :
24 : /**
25 : * @class Var_Grad
26 : * @brief Variable with Gradient, and its corresponding need_gradient property
27 : */
28 : class Var_Grad {
29 : public:
30 : /**
31 : * @brief Specification of the Var_Grad
32 : *
33 : * @details The tuple values are dimension, need_gradient property, and the
34 : * name of the Var_Grad object.
35 : */
36 : typedef VarGradSpec Spec;
37 :
38 : /**
39 : * @brief Var_Grad default constructor
40 : * @note Default variable is not need_gradient as gradient is 0 dim tensor
41 : */
42 1 : Var_Grad() : Var_Grad(TensorDim()) {}
43 :
44 : /**
45 : * @brief Var_Grad default destructor
46 : */
47 41839 : virtual ~Var_Grad() = default;
48 :
49 : /**
50 : * @brief Construct a new Var_Grad object
51 : *
52 : * @param dim Variable and gradient tensor dimension
53 : * @param ng If the variable is need_gradient
54 : * @param alloc_now The memory for the var_grad tensors be allocated upon init
55 : * @param name Name for this Var_Grad
56 : */
57 : explicit Var_Grad(const TensorDim &dim,
58 : const Initializer init = Initializer::NONE, bool ng = true,
59 : bool alloc_now = false, const std::string &name = "");
60 :
61 : /**
62 : * @brief Construct a new Var_Grad object
63 : *
64 : * @param dim_v Variable tensor dimension
65 : * @param dim_g Gradient tensor dimension
66 : * @param ng If the variable is need_gradient
67 : * @param alloc_now The memory for the var_grad tensors be allocated upon init
68 : * @param name Name for this Var_Grad
69 : */
70 : explicit Var_Grad(const TensorDim &dim_v, const TensorDim &dim_g,
71 : const Initializer init = Initializer::NONE, bool ng = true,
72 : bool alloc_now = false, const std::string &name = "");
73 :
74 : /**
75 : * @brief Construct a new Var_Grad object
76 : *
77 : * @param spec Var_Grad specification
78 : */
79 166 : explicit Var_Grad(const Spec &spec, bool alloc_now = false) :
80 : Var_Grad(std::get<0>(spec), // TensorDim
81 : std::get<1>(spec), // initializer
82 166 : std::get<2>(spec), // need_gradient
83 : alloc_now,
84 : std::get<3>(spec) // Name
85 166 : ) {}
86 :
87 : /**
88 : * @brief Construct a new Var_Grad object
89 : *
90 : * @param v Already created variable object
91 : * @param g Already created gradient object
92 : * @param n Name for this Var_Grad
93 : * @param is_dependent true if the var grad is dependent
94 : *
95 : * @note This API is not recommended for usage and must be used for internal
96 : * uses only, as Var_Grad does not own the tensors v and g, and can go invalid
97 : * if the owner of these tensors free the tensors.
98 : */
99 4184 : explicit Var_Grad(const Tensor &v, const Tensor &g, const std::string &n = "",
100 4184 : bool is_dependent = false) :
101 4184 : is_dependent(is_dependent),
102 4184 : is_first_access_gradient(false),
103 4184 : is_last_access_gradient(false),
104 : var(
105 8368 : std::make_shared<Tensor>(v.getSharedDataTensor(v.getDim(), 0, false, n))),
106 8368 : grad(std::make_shared<Tensor>(n + grad_suffix)) {
107 4184 : if (!g.empty())
108 3992 : grad = std::make_shared<Tensor>(
109 11976 : g.getSharedDataTensor(v.getDim(), 0, false, n + grad_suffix));
110 4184 : }
111 :
112 : /**
113 : * @brief Construct a new Var_Grad object
114 : *
115 : * @param v ptr to already created variable tensor
116 : * @param g ptr to already created gradient tensor
117 : * @param is_dependent true if the given var grad is dependent
118 : */
119 18389 : explicit Var_Grad(Tensor *v, Tensor *g, bool is_dependent = false) :
120 18389 : is_dependent(is_dependent),
121 18389 : is_first_access_gradient(false),
122 18389 : is_last_access_gradient(false),
123 : var(std::shared_ptr<Tensor>(v, [](void *) {})),
124 18389 : grad(std::shared_ptr<Tensor>(g, [](void *) {})) {
125 18389 : if (!v)
126 0 : var = std::make_shared<Tensor>();
127 18389 : if (!g)
128 1718 : grad = std::make_shared<Tensor>();
129 18389 : }
130 :
131 : /**
132 : * @brief Copy constructor for Var_Grad
133 : *
134 : * @param rhs Var_Grad to construct from
135 : */
136 1822 : Var_Grad(const Var_Grad &rhs) = default;
137 :
138 : /**
139 : * @brief Move constructor for Var_Grad
140 : *
141 : * @param rhs Var_Grad to construct from
142 : */
143 3234 : Var_Grad(Var_Grad &&rhs) = default;
144 :
145 : /**
146 : * @brief copy assigment
147 : *
148 : * @param rhs copy from
149 : * @return Var_Grad& Updated Var_Grad
150 : */
151 : Var_Grad &operator=(const Var_Grad &rhs) = default;
152 :
153 : /**
154 : * @brief move assignment
155 : *
156 : * @param rhs move from
157 : * @return Var_Grad& Updated Var_Grad
158 : */
159 0 : Var_Grad &operator=(Var_Grad &&rhs) = default;
160 :
161 : /**
162 : * @brief Initialize the variable
163 : * @param preallocated if initialized, use this tensor for variable memory
164 : */
165 : virtual void initializeVariable(const Tensor &preallocated = Tensor());
166 :
167 : /**
168 : * @brief Initialize the gradient for the variable
169 : * @param preallocated if initialized, use this tensor for gradient memory
170 : */
171 : virtual void initializeGradient(const Tensor &preallocated = Tensor());
172 :
173 : /**
174 : * @brief Get the TensorDim
175 : *
176 : * @return TensorDim Dimension
177 : */
178 10867 : TensorDim getDim() const { return var->getDim(); }
179 :
180 : /**
181 : * @brief Get the name of the variable
182 : *
183 : * @return std::string name of the variable
184 : */
185 14358 : const std::string &getName() const { return var->getName(); }
186 :
187 : /**
188 : * @brief Get the name of the gradient
189 : *
190 : * @return std::string name of the gradient
191 : */
192 994 : const std::string &getGradientName() const { return grad->getName(); }
193 :
194 : /**
195 : * @brief Get the variable tensor
196 : *
197 : * @return Tensor Variable tensor
198 : */
199 6903 : Tensor getVariable() const { return *var.get(); }
200 :
201 : /**
202 : * @brief Get the Gradient tensor
203 : *
204 : * @return Tensor Gradient tensor
205 : */
206 2302 : Tensor getGradient() const { return *grad.get(); }
207 :
208 : /**
209 : * @brief Reset the gradient to 0
210 : */
211 : void resetGradient() {
212 : /** zero the gradient */
213 : grad->initialize();
214 : }
215 :
216 : /**
217 : * @brief Set batch size
218 : *
219 : * @param batch batch size
220 : */
221 9156 : void setBatchSize(unsigned int batch) {
222 9156 : if (!var->empty())
223 9156 : var->updateBatch(batch);
224 9156 : if (grad && !grad->empty())
225 8208 : grad->updateBatch(batch);
226 9156 : }
227 :
228 : /**
229 : * @brief Update the dimension
230 : *
231 : * @param dimension dimension to be updated
232 : */
233 0 : void updateDimension(TensorDim dimension) {
234 0 : if (!var->empty())
235 0 : var->updateDimension(dimension);
236 0 : if (grad && !grad->empty())
237 0 : grad->updateDimension(dimension);
238 0 : }
239 :
240 : /**
241 : * @brief Get the variable tensor (by reference)
242 : *
243 : * @return Tensor Variable tensor
244 : */
245 : Tensor &getVariableRef() { return *var.get(); }
246 :
247 : /**
248 : * @brief Get the Gradient tensor (by reference)
249 : *
250 : * @return Tensor Gradient tensor
251 : */
252 : Tensor &getGradientRef() { return *grad.get(); }
253 :
254 : /**
255 : * @brief Get the variable tensor (by reference)
256 : *
257 : * @return Tensor Variable tensor
258 : */
259 : const Tensor &getVariableRef() const { return *var.get(); }
260 :
261 : /**
262 : * @brief Get the Gradient tensor (by reference)
263 : *
264 : * @return Tensor Gradient tensor
265 : */
266 : const Tensor &getGradientRef() const { return *grad.get(); }
267 :
268 : /**
269 : * @brief If this variable has gradient
270 : *
271 : * @return true if the var_grad as gradient set, else false
272 : * @note this is can return is the var_grad needs gradient but it not
273 : * empty
274 : */
275 129624 : bool hasGradient() const {
276 129624 : if (!grad)
277 : return false;
278 129624 : if (var->isAllocated())
279 103569 : return grad->isAllocated();
280 26055 : return !grad->empty();
281 : }
282 :
283 : /**
284 : * @brief check if given weight is dependent to other weight
285 : *
286 : * @return bool return true if the weight is dependent to others
287 : */
288 0 : bool isDependent() const { return is_dependent; }
289 :
290 : /**
291 : * @brief Set the As First Gradient Access
292 : *
293 : */
294 4036 : void setAsGradientFirstAccess() { is_first_access_gradient = true; }
295 :
296 : /**
297 : * @brief Set the As Gradient Last Access object
298 : *
299 : */
300 4028 : void setAsGradientLastAccess() { is_last_access_gradient = true; }
301 :
302 : /**
303 : * @brief check if given weight at the last execution order
304 : * (first access of gradient)
305 : *
306 : * @return bool true if last access
307 : */
308 16248 : bool isGradientFirstAccess() const { return is_first_access_gradient; }
309 :
310 : /**
311 : * @brief check if given weight at the first execution order (last access of
312 : * gradient)
313 : *
314 : * @return bool true if last access
315 : */
316 28654 : bool isGradientLastAccess() const { return is_last_access_gradient; }
317 :
318 : /**
319 : * @brief Get the norm of the gradient
320 : *
321 : * @return float l2 norm of the gradient
322 : */
323 44 : float getGradientNorm() const { return grad->l2norm(); }
324 :
325 : static constexpr const char *grad_suffix = ":grad";
326 :
327 : protected:
328 : bool is_dependent; /**< check if the weight tensor is burrowed from somewhere
329 : thus it is dependent */
330 : bool is_first_access_gradient; /**< check if current weight tensor is first
331 : access */
332 : bool is_last_access_gradient; /**< check if current weight tensor is last
333 : access */
334 :
335 : std::shared_ptr<Tensor> var; /**< variable to be updated and used */
336 : std::shared_ptr<Tensor> grad; /**< gradient for the variable */
337 : };
338 :
339 : } // namespace nntrainer
340 :
341 : #endif /** __VAR_GRAD_H__ */
|