LBANN  0.103.0
LivermoreBigArtificialNeuralNetworkToolkit
entrywise_operator.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_ENTRYWISE_OPERATOR_HPP
28 #define LBANN_UTILS_ENTRYWISE_OPERATOR_HPP
29 
30 #include "lbann/base.hpp"
32 
33 namespace lbann {
34 
39 template <template <typename> class Op, typename TensorDataType>
41  const El::AbstractMatrix<TensorDataType>& input,
42  El::AbstractMatrix<TensorDataType>& output)
43 {
44  using UnaryOperator = Op<TensorDataType>;
45  // Check that input and output are valid
46  std::stringstream err;
47  if (input.GetDevice() != El::Device::CPU) {
48  LBANN_ERROR("input is not on CPU");
49  }
50  else if (output.GetDevice() != El::Device::CPU) {
51  LBANN_ERROR("output is not on CPU");
52  }
53  else if (input.Height() != output.Height() ||
54  input.Width() != output.Width()) {
55  err << "input matrix dimensions "
56  << "(" << input.Height() << " x " << input.Width() << ")"
57  << "don't match output matrix dimensions "
58  << "(" << output.Height() << " x " << output.Width() << ")";
59  LBANN_ERROR(err.str());
60  }
61 
62  // Apply unary operator
63  if (input.Contiguous() && output.Contiguous()) {
64  const auto* input_buffer = input.LockedBuffer();
65  auto* output_buffer = output.Buffer();
66  const size_t size = input.Height() * input.Width();
68  for (size_t i = 0; i < size; ++i) {
69  UnaryOperator op;
70  output_buffer[i] = op(input_buffer[i]);
71  }
72  }
73  else {
74  auto const width = input.Width();
75  auto const height = input.Height();
77  for (El::Int col = 0; col < width; ++col) {
78  for (El::Int row = 0; row < height; ++row) {
79  UnaryOperator op;
80  output(row, col) = op(input(row, col));
81  }
82  }
83  }
84 }
85 
90 template <template <typename> class Op, typename TensorDataType>
92  const El::AbstractMatrix<TensorDataType>& input1,
93  const El::AbstractMatrix<TensorDataType>& input2,
94  El::AbstractMatrix<TensorDataType>& output)
95 {
96  using BinaryOperator = Op<TensorDataType>;
97  // Check that input and output are valid
98  if (input1.GetDevice() != El::Device::CPU ||
99  input2.GetDevice() != El::Device::CPU) {
100  LBANN_ERROR("input is not on CPU");
101  }
102  else if (output.GetDevice() != El::Device::CPU) {
103  LBANN_ERROR("output is not on CPU");
104  }
105  else if (input1.Height() != input2.Height() ||
106  input1.Width() != input2.Width() ||
107  input1.Height() != output.Height() ||
108  input1.Width() != output.Width()) {
109  LBANN_ERROR("input matrix dimensions "
110  "(",
111  input1.Height(),
112  " x ",
113  input1.Width(),
114  ", ",
115  input2.Height(),
116  " x ",
117  input2.Width(),
118  ")"
119  "don't match output matrix dimensions "
120  "(",
121  output.Height(),
122  " x ",
123  output.Width(),
124  ")");
125  }
126 
127  // Apply binary operator
128  if (input1.Contiguous() && input2.Contiguous() && output.Contiguous()) {
129  const auto* input1_buffer = input1.LockedBuffer();
130  const auto* input2_buffer = input2.LockedBuffer();
131  auto* output_buffer = output.Buffer();
132  const size_t size = input1.Height() * input1.Width();
134  for (size_t i = 0; i < size; ++i) {
135  BinaryOperator op;
136  output_buffer[i] = op(input1_buffer[i], input2_buffer[i]);
137  }
138  }
139  else {
140  auto const width = input1.Width();
141  auto const height = input1.Height();
143  for (El::Int col = 0; col < width; ++col) {
144  for (El::Int row = 0; row < height; ++row) {
145  BinaryOperator op;
146  output(row, col) = op(input1(row, col), input2(row, col));
147  }
148  }
149  }
150 }
151 
156 template <template <typename> class Op, typename TensorDataType>
158  const El::AbstractDistMatrix<TensorDataType>& input,
159  El::AbstractDistMatrix<TensorDataType>& output)
160 {
161  if (input.Height() != output.Height() || input.Width() != output.Width()) {
162  LBANN_ERROR("input matrix dimensions "
163  "(",
164  input.Height(),
165  " x ",
166  input.Width(),
167  ")"
168  "don't match output matrix dimensions "
169  "(",
170  output.Height(),
171  " x ",
172  output.Width(),
173  ")");
174  }
175  else if (input.DistData() != output.DistData()) {
176  LBANN_ERROR("input and output matrix distributions don't match");
177  }
178  apply_entrywise_unary_operator<Op>(input.LockedMatrix(), output.Matrix());
179 }
180 
185 template <template <typename> class Op, typename TensorDataType>
187  const El::AbstractDistMatrix<TensorDataType>& input1,
188  const El::AbstractDistMatrix<TensorDataType>& input2,
189  El::AbstractDistMatrix<TensorDataType>& output)
190 {
191  if (input1.Height() != input2.Height() || input1.Width() != input2.Width() ||
192  input1.Height() != output.Height() || input1.Width() != output.Width()) {
193  LBANN_ERROR("input matrix dimensions "
194  "(",
195  input1.Height(),
196  " x ",
197  input1.Width(),
198  ", ",
199  input2.Height(),
200  " x ",
201  input2.Width(),
202  ")"
203  "don't match output matrix dimensions "
204  "(",
205  output.Height(),
206  " x ",
207  output.Width(),
208  ")");
209  }
210  else if (input1.DistData() != input2.DistData() ||
211  input1.DistData() != output.DistData()) {
212  LBANN_ERROR("input and output matrix distributions don't match");
213  }
214  apply_entrywise_binary_operator<Op>(input1.LockedMatrix(),
215  input2.LockedMatrix(),
216  output.Matrix());
217 }
218 
219 } // namespace lbann
220 
221 #endif // LBANN_UTILS_ENTRYWISE_OPERATOR_HPP
void apply_entrywise_binary_operator(const El::AbstractMatrix< TensorDataType > &input1, const El::AbstractMatrix< TensorDataType > &input2, El::AbstractMatrix< TensorDataType > &output)
#define LBANN_ERROR(...)
Definition: exception.hpp:37
void apply_entrywise_unary_operator(const El::AbstractMatrix< TensorDataType > &input, El::AbstractMatrix< TensorDataType > &output)
#define LBANN_OMP_PARALLEL_FOR_COLLAPSE2
Definition: omp_pragma.hpp:68
#define LBANN_OMP_PARALLEL_FOR
Definition: omp_pragma.hpp:67