LBANN  0.103.0
LivermoreBigArtificialNeuralNetworkToolkit
tensor.hpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2023, Lawrence Livermore National Security, LLC.
3 // Produced at the Lawrence Livermore National Laboratory.
4 // Written by the LBANN Research Team (B. Van Essen, et al.) listed in
5 // the CONTRIBUTORS file. <lbann-dev@llnl.gov>
6 //
7 // LLNL-CODE-697807.
8 // All rights reserved.
9 //
10 // This file is part of LBANN: Livermore Big Artificial Neural Network
11 // Toolkit. For details, see http://software.llnl.gov/LBANN or
12 // https://github.com/LLNL/LBANN.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "Licensee"); you
15 // may not use this file except in compliance with the License. You may
16 // obtain a copy of the License at:
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
23 // implied. See the License for the specific language governing
24 // permissions and limitations under the license.
26 
27 #ifndef LBANN_UTILS_TENSOR_HPP
28 #define LBANN_UTILS_TENSOR_HPP
29 
30 #include "lbann/base.hpp"
33 #include "lbann/utils/typename.hpp"
34 
35 #include <El/core/DistMatrix/AbstractDistMatrix.hpp>
36 #include <iterator>
37 #include <type_traits>
38 
39 namespace lbann {
40 
45 template <typename TDT>
46 void do_tensor_copy(const BaseDistMat& src, El::AbstractDistMatrix<TDT>& tgt);
47 
51 template <typename TDT>
52 void view_or_copy_tensor(const BaseDistMat& src,
53  El::AbstractDistMatrix<TDT>& tgt,
54  bool locked_view = true);
55 
56 namespace utils {
57 namespace details {
58 
64 template <typename MatrixT>
65 std::vector<size_t> get_tensor_dims(MatrixT const& A)
66 {
67  return {El::To<size_t>(A.Width()), El::To<size_t>(A.Height())};
68 }
69 
77 template <typename T>
78 std::vector<size_t> localize_dims(El::AbstractDistMatrix<T> const& A,
79  std::vector<size_t> const& global_dims)
80 {
81  if (A.ColDist() == El::Dist::STAR) {
82  std::vector<size_t> out = global_dims;
83  out.front() = A.LocalWidth();
84  return out;
85  }
86  else if (global_dims.size() == 2UL) {
87  return get_tensor_dims(A.LockedMatrix());
88  }
89  else {
90  std::ostringstream oss;
91  oss << "{";
92  for (auto const& d : global_dims)
93  oss << " " << d;
94  oss << " }";
95  LBANN_WARNING("Dimension localization is ill-posed. Dims=", oss.str());
96 
97  return global_dims;
98  }
99 }
100 
101 template <typename MatrixOutT, typename MatrixInT>
103 {
104  static MatrixOutT& cast(MatrixInT& in) { return in; }
105  static MatrixOutT const& cast(MatrixInT const& in) { return in; }
106 };
107 
108 template <typename OutDataType, El::Device D, typename InDataType>
109 struct SafeMatrixCaster<El::Matrix<OutDataType, D>,
110  El::AbstractMatrix<InDataType>>
111 {
112  using OutType = El::Matrix<OutDataType, D>;
113  using InType = El::AbstractMatrix<InDataType>;
114  static OutType& cast(InType& in)
115  {
116  LBANN_ASSERT(in.GetDevice() == D);
117  return static_cast<OutType&>(in);
118  }
119  static OutType const& cast(InType const& in)
120  {
121  LBANN_ASSERT(in.GetDevice() == D);
122  return static_cast<OutType const&>(in);
123  }
124 };
125 
126 template <typename MatrixOutT, typename MatrixInT>
127 MatrixOutT& SafeMatrixCast(MatrixInT& in)
128 {
129  using OutType = std::decay_t<MatrixOutT>;
130  using InType = std::decay_t<MatrixInT>;
132 }
133 
135 template <typename MatrixT>
137 {
138 public:
139  using matrix_type = MatrixT;
140 
141 public:
142  template <typename MatT>
144  : m_data{SafeMatrixCast<matrix_type&>(std::forward<MatT>(x))}
145  {}
146  operator matrix_type&() const noexcept { return m_data; }
147  matrix_type& data() const noexcept { return m_data; }
148 
149 private:
150  std::reference_wrapper<matrix_type> m_data;
151 };
152 
154 template <typename MatrixT>
156 {
157 public:
158  template <typename MatT>
159  MatrixAsTensorView(MatT&& mat, std::vector<size_t> const& dims)
160  : MatrixReferenceWrapper<MatrixT>{std::forward<MatT>(mat)}, m_dims{dims}
161  {}
162 
163  std::vector<size_t> const& dims() const noexcept { return m_dims; }
164  size_t rank() const noexcept { return m_dims.size(); };
165 
166 private:
167  std::vector<size_t> m_dims;
168 }; // MatrixAsTensorView
169 
171 template <typename TDT>
173  El::AbstractDistMatrix<TDT>& tgt);
174 
176 template <typename TDT,
177  El::Dist ColDist,
178  El::Dist RowDist,
179  El::DistWrap Wrap,
182  const BaseDistMat& src,
183  El::DistMatrix<TDT, ColDist, RowDist, Wrap, Device>& tgt);
184 
185 } // namespace details
186 
187 template <typename T, El::Device D>
188 class TensorView : public details::MatrixAsTensorView<El::Matrix<T, D>>
189 {
191 
192 public:
193  template <typename MatT>
194  TensorView(MatT&& mat)
195  : TensorView{std::forward<MatT>(mat), details::get_tensor_dims(mat)}
196  {}
197  template <typename MatT>
198  TensorView(MatT&& mat, std::vector<size_t> const& dims)
199  : base_type{std::forward<MatT>(mat), dims}
200  {}
201 };
202 
203 template <typename T, El::Device D>
205  : public details::MatrixAsTensorView<El::Matrix<T, D> const>
206 {
208 
209 public:
210  template <typename MatT>
211  ConstTensorView(MatT&& mat)
212  : ConstTensorView{std::forward<MatT>(mat), details::get_tensor_dims(mat)}
213  {}
214  template <typename MatT>
215  ConstTensorView(MatT&& mat, std::vector<size_t> const& dims)
216  : base_type{std::forward<MatT>(mat), dims}
217  {}
218 };
219 
220 // There's a clever laziness here -- the dist matrix will never be
221 // directly checked for device allocation sanity. However, when the
222 // local tensor view is constructed around the local matrix, _that_
223 // matrix will be checked for device allocation sanity, thereby
224 // guaranteeing the sanity of the whole object.
225 //
226 // FIXME (trb 06/25/21): If we wanted to be VERY rigorous, we'd adjust
227 // the local tensor dimension vector in a distribution-specific
228 // way. But we shouldn't be doing tensor-y things with MC,MR matrices,
229 // just matrix-y things (i.e., we can expect that the samples are 1-D
230 // when we encounter MC,MR matrices).
231 
232 template <typename T, El::Device D>
234  : public details::MatrixAsTensorView<El::AbstractDistMatrix<T>>
235 {
237 
238 public:
239  template <typename MatT>
240  DistTensorView(MatT&& mat)
241  : DistTensorView{std::forward<MatT>(mat), details::get_tensor_dims(mat)}
242  {}
243  template <typename MatT>
244  DistTensorView(MatT&& mat, std::vector<size_t> const& dims)
245  : base_type{std::forward<MatT>(mat), dims},
246  m_local_data{mat.Matrix(), details::localize_dims(mat, this->dims())}
247  {}
248 
250  TensorView<T, D> const& local_data() const noexcept { return m_local_data; }
251 
252 private:
254 
255 }; // DistTensorView<T,D>
256 
257 template <typename T, El::Device D>
259  : public details::MatrixAsTensorView<El::AbstractDistMatrix<T> const>
260 {
261  using base_type =
263 
264 public:
265  template <typename MatT>
267  : ConstDistTensorView{std::forward<MatT>(mat),
269  {}
270  template <typename MatT>
271  ConstDistTensorView(MatT&& mat, std::vector<size_t> const& dims)
272  : base_type{std::forward<MatT>(mat), dims},
273  m_local_data{mat.LockedMatrix(),
274  details::localize_dims(mat, this->dims())}
275  {}
276 
277  ConstTensorView<T, D> const& local_data() const noexcept
278  {
279  return m_local_data;
280  }
281 
282 private:
284 
285 }; // ConstDistTensorView
286 
287 } // namespace utils
288 
289 } // namespace lbann
290 #endif // LBANN_UTILS_TENSOR_HPP
static MatrixOutT const & cast(MatrixInT const &in)
Definition: tensor.hpp:105
ConstTensorView< T, D > const & local_data() const noexcept
Definition: tensor.hpp:277
TensorView(MatT &&mat, std::vector< size_t > const &dims)
Definition: tensor.hpp:198
std::vector< size_t > localize_dims(El::AbstractDistMatrix< T > const &A, std::vector< size_t > const &global_dims)
Attempt to compute the tensor dimensions of the local portion of the matrix, given the global tensor ...
Definition: tensor.hpp:78
ConstTensorView(MatT &&mat, std::vector< size_t > const &dims)
Definition: tensor.hpp:215
ConstDistTensorView(MatT &&mat, std::vector< size_t > const &dims)
Definition: tensor.hpp:271
TensorView(MatT &&mat)
Definition: tensor.hpp:194
std::reference_wrapper< matrix_type > m_data
Definition: tensor.hpp:150
constexpr El::Device Device
#define LBANN_ASSERT(cond)
Definition: exception.hpp:97
Interpret a matrix as a tensor.
Definition: tensor.hpp:155
DistTensorView(MatT &&mat, std::vector< size_t > const &dims)
Definition: tensor.hpp:244
void do_tensor_copy_between_grids(const BaseDistMat &src, El::AbstractDistMatrix< TDT > &tgt)
Copy between two tensors on different process grids.
Definition: tensor_impl.hpp:66
Manage a reference to a (possibly const) matrix.
Definition: tensor.hpp:136
ConstTensorView< T, D > m_local_data
Definition: tensor.hpp:283
MatrixOutT & SafeMatrixCast(MatrixInT &in)
Definition: tensor.hpp:127
void view_or_copy_tensor(const BaseDistMat &src, El::AbstractDistMatrix< TDT > &tgt, bool locked_view=true)
If distributed tensors have the same distribution setup the target to use a view to the source tensor...
TensorView< T, D > const & local_data() const noexcept
Access the local tensor data.
Definition: tensor.hpp:250
matrix_type & data() const noexcept
Definition: tensor.hpp:147
El::BaseDistMatrix BaseDistMat
Definition: base.hpp:121
void do_tensor_copy(const BaseDistMat &src, El::AbstractDistMatrix< TDT > &tgt)
Function to efficiently select the best method for copying between two distributed tensors...
Definition: tensor_impl.hpp:39
#define LBANN_WARNING(...)
Definition: exception.hpp:53
TensorView< T, D > m_local_data
Definition: tensor.hpp:253
std::vector< size_t > get_tensor_dims(MatrixT const &A)
Interpret the matrix as a tensor and return the tensor-ized dimensions.
Definition: tensor.hpp:65
MatrixAsTensorView(MatT &&mat, std::vector< size_t > const &dims)
Definition: tensor.hpp:159
::distconv::tensor::Distribution Dist
static MatrixOutT & cast(MatrixInT &in)
Definition: tensor.hpp:104