Home | History | Annotate | Download | only in xla
      1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #ifndef TENSORFLOW_COMPILER_XLA_ARRAY4D_H_
     17 #define TENSORFLOW_COMPILER_XLA_ARRAY4D_H_
     18 
     19 #include <algorithm>
     20 #include <functional>
     21 #include <initializer_list>
     22 #include <iterator>
     23 #include <memory>
     24 #include <numeric>
     25 #include <random>
     26 #include <string>
     27 #include <vector>
     28 
     29 #include "absl/strings/str_cat.h"
     30 #include "absl/types/span.h"
     31 #include "tensorflow/compiler/xla/array.h"
     32 #include "tensorflow/compiler/xla/array2d.h"
     33 #include "tensorflow/compiler/xla/types.h"
     34 #include "tensorflow/core/platform/logging.h"
     35 #include "tensorflow/core/platform/macros.h"
     36 #include "tensorflow/core/platform/types.h"
     37 
     38 namespace xla {
     39 
     40 // Simple 4D array structure, similar in form to Array2D, for use primarily in
     41 // testing and describing to XLA APIs values in the 4D array structures used
     42 // in convolutions.
     43 //
     44 // The data layout is, in order from major to minor:
     45 //
     46 //    First dimension: plane, batch, n1
     47 //   Second dimension: depth, feature, z, n2
     48 //    Third dimension: height, y, n3
     49 //   Fourth dimension: width, x, n4
     50 //
     51 // These dimensions are referred to by various names, so that is why
     52 // more than one name is given above. See operator() for the exact
     53 // calculation of 1d indices from 4d indices.
     54 template <typename T>
     55 class Array4D : public Array<T> {
     56  public:
     57   // Creates a 4D array, uninitialized values.
     58   Array4D(int64 planes, int64 depth, int64 height, int64 width)
     59       : Array<T>(std::vector<int64>{planes, depth, height, width}) {}
     60 
     61   // Creates a 4D array, initialized to value.
     62   Array4D(int64 planes, int64 depth, int64 height, int64 width, T value)
     63       : Array<T>(std::vector<int64>{planes, depth, height, width}, value) {}
     64 
     65   // Creates a 4D array, filled with values.
     66   //
     67   // We need to set a default type for Container so that code like
     68   // Array4D(1, 1, 1, 1, {1}) will work. The template cannot infer the
     69   // initializer_list type in that case without this default.
     70   template <typename Container = std::initializer_list<T>>
     71   Array4D(int64 planes, int64 depth, int64 height, int64 width,
     72           const Container& values)
     73       : Array4D(planes, depth, height, width) {
     74     this->SetValues(values);
     75   }
     76 
     77   // Construct an Array4D with the given nested initializer list.
     78   Array4D(std::initializer_list<std::initializer_list<
     79               std::initializer_list<std::initializer_list<T>>>>
     80               values)
     81       : Array<T>(values) {}
     82 
     83   // Creates an array of a floating-point type (half, bfloat16, float,
     84   // or double) from the given nested initializer list of float values.
     85   template <typename T2, typename = typename std::enable_if<
     86                              (std::is_same<T, Eigen::half>::value ||
     87                               std::is_same<T, bfloat16>::value ||
     88                               std::is_same<T, float>::value ||
     89                               std::is_same<T, double>::value) &&
     90                              std::is_same<T2, float>::value>::type>
     91   Array4D(std::initializer_list<std::initializer_list<
     92               std::initializer_list<std::initializer_list<T2>>>>
     93               values)
     94       : Array<T>(values) {}
     95 
     96   // Numerically-named aliases for the various dimensions. This matches the
     97   // dimension names used in array3d.
     98   int64 n4() const { return this->dim(3); }
     99   int64 n3() const { return this->dim(2); }
    100   int64 n2() const { return this->dim(1); }
    101   int64 n1() const { return this->dim(0); }
    102 
    103   int64 width() const { return this->dim(3); }
    104   int64 height() const { return this->dim(2); }
    105   int64 depth() const { return this->dim(1); }
    106   int64 planes() const { return this->dim(0); }
    107 
    108   // Fills all of the {p,z} with the array provided, which specifies {y,x}.
    109   void FillWithYX(const Array2D<T>& value) {
    110     CHECK_EQ(value.height(), height());
    111     CHECK_EQ(value.width(), width());
    112     for (int64 plane = 0; plane < planes(); ++plane) {
    113       for (int64 depth = 0; depth < this->depth(); ++depth) {
    114         for (int64 height = 0; height < this->height(); ++height) {
    115           for (int64 width = 0; width < this->width(); ++width) {
    116             (*this)(plane, depth, height, width) = value(height, width);
    117           }
    118         }
    119       }
    120     }
    121   }
    122 
    123   // Fills all of the {x,y} with the array provided, which specifies {p,z}.
    124   void FillWithPZ(const Array2D<T>& value) {
    125     CHECK_EQ(value.height(), planes());
    126     CHECK_EQ(value.width(), depth());
    127     for (int64 height = 0; height < this->height(); ++height) {
    128       for (int64 width = 0; width < this->width(); ++width) {
    129         for (int64 plane = 0; plane < planes(); ++plane) {
    130           for (int64 depth = 0; depth < this->depth(); ++depth) {
    131             (*this)(plane, depth, height, width) = value(plane, depth);
    132           }
    133         }
    134       }
    135     }
    136   }
    137 
    138   // Fills each of the minor-dim matrices with a number designating which minor
    139   // dim matrix is enclosed by the shape.
    140   void FillWithMinorDimNum() {
    141     LOG(INFO) << "width: " << this->width();
    142     LOG(INFO) << "height: " << this->height();
    143     LOG(INFO) << "depth: " << this->depth();
    144     LOG(INFO) << "planes: " << this->planes();
    145     for (int64 height = 0; height < this->height(); ++height) {
    146       for (int64 width = 0; width < this->width(); ++width) {
    147         for (int64 plane = 0; plane < planes(); ++plane) {
    148           for (int64 depth = 0; depth < this->depth(); ++depth) {
    149             float this_val = plane * this->depth() + depth;
    150             (*this)(plane, depth, height, width) = this_val;
    151           }
    152         }
    153       }
    154     }
    155   }
    156 };
    157 
    158 }  // namespace xla
    159 
    160 #endif  // TENSORFLOW_COMPILER_XLA_ARRAY4D_H_
    161