Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tests] add pytorch.mobilenet #750

Merged
merged 6 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/cases/blastoise/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"pytorch.demo": -1,
"pytorch.lenet": -1,
"pytorch.matmul": -1,
"pytorch.mobilenet": -1,
"mlir.rvv_vp_intrinsic_add": 436,
"mlir.rvv_vp_intrinsic_add_scalable": 584,
"mlir.hello": 146,
Expand Down
1 change: 1 addition & 0 deletions nix/pkgs/buddy-mlir.nix
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ let
pyenv = python3.withPackages (ps: [
self
ps.torch
ps.torchvision
]);
};
};
Expand Down
2 changes: 1 addition & 1 deletion tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ let
findAndBuild = dir: build:
lib.recurseIntoAttrs (lib.pipe (builtins.readDir dir) [
# filter out all non-directory entrires and underscore-prefixed directories
(lib.filterAttrs (name: type: type == "directory" && ! lib.hasPrefix "_" name))
(lib.filterAttrs (name: type: type == "directory" && ! (lib.hasPrefix "_" name) && ! (lib.elem name [ "lib" "include" ])))
# prepend path with base directory
(lib.mapAttrs (subDirName: _: (lib.path.append dir subDirName)))
# build. If {sourcePath}/default.nix exists, call it. Otherwise call the generic builder
Expand Down
5 changes: 1 addition & 4 deletions tests/pytorch/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,7 @@ let
fi

echo "Building final binary"
mkdir -p _include
cp ${./memref.hpp} _include/memref.hpp

$CXX -nostdlib -I _include -c ${caseName}.cc -o host.o
$CXX -nostdlib -I${./include} -c ${caseName}.cc -o host.o
$CC -T${linkerScript} \
host.o ''${llcArtifacts[@]} ${t1main} \
-o $pname.elf
Expand Down
234 changes: 234 additions & 0 deletions tests/pytorch/include/img.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
//===- ImgContainer.h -----------------------------------------------------===//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//===----------------------------------------------------------------------===//
//
// original source from https://github.com/buddy-compiler/buddy-mlir
// Modified for embedded environment.
//
//===----------------------------------------------------------------------===//

#ifndef IMG_H
#define IMG_H

#include "memref.hpp"

enum ImageModes {
DIP_GRAYSCALE = 0,
DIP_RGB = 1,
};

template <typename T, size_t N> class Image : public MemRef<T, N> {
public:
// Constructor initializes the image by loading from a file.
// Params:
// file: Raw data to image file memory
// filesize: size of the file memory
// buffer: pre-allocated space for image modification
// mode: Specifies the image mode (e.g., DIP_GRAYSCALE, DIP_RGB).
// norm: Indicates whether to normalize pixel values (default is false).
constexpr Image(const char *file, int32_t filesize, T *buffer,
ImageModes mode, bool norm = false);

// Overload
constexpr Image(T *data, const int32_t sizes[N]);
constexpr Image(T *data, T init, const int32_t sizes[N]);

// Retrieves the name of the current image format as a string.
inline const char *getFormatName() const {
switch (this->imageFormat) {
case ImageFormat::BMP:
return "BMP";
default:
return "Unsupported format";
}
}
// Returns the width of the image in pixels.
inline size_t getWidth() const { return this->width; }
// Returns the height of the image in pixels.
inline size_t getHeight() const { return this->height; }
// Returns the bit depth of the image.
inline int getBitDepth() const { return this->bitDepth; }

private:
// Enum to represent supported image formats.
enum class ImageFormat {
BMPDecodeError, // Represents an error or unsupported format.
BMP, // BMP file format.
Unsupported,
} imageFormat;
// Mode of the image (e.g., DIP_GRAYSCALE, DIP_RGB).
ImageModes imageMode;
// Width of the image in pixels.
int32_t width;
// Height of the image in pixels.
int32_t height;
// Bit depth of the image.
int32_t bitDepth;
// Normalization flag.
bool isNorm;
// Determines the image format from raw file data.
inline void determineFormat(const uint8_t *fileData, uint32_t filesize);
// Decodes a BMP image from raw file data.
inline bool decodeBMP(const uint8_t *fileData, uint32_t filesize);
};

template <typename T, std::size_t N>
constexpr Image<T, N>::Image(T *data, const int32_t sizes[N])
: MemRef<T, N>(data, sizes){};

template <typename T, std::size_t N>
constexpr Image<T, N>::Image(T *data, T init, const int32_t sizes[N])
: MemRef<T, N>(data, init, sizes){};

// Image Container Constructor
// Constructs an image container object from the image file path.
template <typename T, std::size_t N>
constexpr Image<T, N>::Image(const char *file, int32_t filesize, T *buffer,
ImageModes mode, bool norm)
: imageMode(mode), isNorm(norm) {

this->allocated = buffer;
this->aligned = this->allocated;

determineFormat(file, filesize);
if (this->imageFormat == ImageFormat::BMP) {
bool success = decodeBMP(file, filesize);
if (!success) {
this->imageFormat = ImageFormat::BMPDecodeError;
};
} else {
this->imageFormat = ImageFormat::Unsupported;
}
}

// Determines the image format by inspecting the header of the file data.
template <typename T, std::size_t N>
inline void Image<T, N>::determineFormat(const uint8_t *fileData,
uint32_t filesize) {
if (filesize > 2 && fileData[0] == 'B' && fileData[1] == 'M') {
this->imageFormat = ImageFormat::BMP;
} else {
this->imageFormat = ImageFormat::BMPDecodeError;
}
}

// BMP Image File Decoder
template <typename T, std::size_t N>
inline bool Image<T, N>::decodeBMP(const uint8_t *fileData, uint32_t filesize) {
// Check if the provided data is large enough to contain a minimal BMP header
// (54 bytes).
if (filesize < 54) {
return false;
}

// Extract image information from BMP header
this->width = *reinterpret_cast<const int32_t *>(&fileData[18]);
this->height = *reinterpret_cast<const int32_t *>(&fileData[22]);
this->bitDepth = *reinterpret_cast<const uint16_t *>(&fileData[28]);
uint32_t compression = *reinterpret_cast<const uint32_t *>(&fileData[30]);
size_t pixelDataOffset = *reinterpret_cast<const uint32_t *>(&fileData[10]);

// Currently, only the BI_RGB (value 0) compression method is supported.
if (compression != 0) {
return false;
}

// Currently, only the NCHW format with 4 dimensions is supported.
if (N == 4) {
if (this->imageMode == ImageModes::DIP_GRAYSCALE) {
// TODO: Add batch setting.
this->sizes[0] = 1;
this->sizes[1] = 1;
this->sizes[2] = this->height;
this->sizes[3] = this->width;
this->setStrides();
size_t size = this->product(this->sizes);
// Fullfill data to memref container.
size_t memrefIndex = 0;
if (this->bitDepth == 32) {
// BMP file is upside-down storage.
for (size_t i = this->height; i > 0; i--) {
for (size_t j = 0; j < this->width; j++) {
// Locate the current pixel.
size_t pixelIndex =
pixelDataOffset + (((i - 1) * this->width) + j) * 4;
// Extract the blue, green, and red value from the current pixel.
int bluePixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex]);
int greenPixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex + 1]);
int redPixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex + 2]);
// Calculate the gray scale value.
int grayScaleValue = static_cast<int>(
0.299 * redPixel + 0.587 * greenPixel + 0.114 * bluePixel);
// Store the gray scale value into memref container.
this->aligned[memrefIndex] =
this->isNorm ? static_cast<T>(grayScaleValue) / 255
: static_cast<T>(grayScaleValue);
memrefIndex++;
}
}
} else {
return false;
}
} else if (this->imageMode == ImageModes::DIP_RGB) {
// TODO: Add batch setting.
this->sizes[0] = 1;
this->sizes[1] = 3;
this->sizes[2] = this->height;
this->sizes[3] = this->width;
this->setStrides();
size_t size = this->product(this->sizes);
// Fullfill data to memref container.
size_t memrefIndex = 0;
size_t colorStride = this->height * this->width;
if (this->bitDepth == 32) {
// BMP file is upside-down storage.
for (size_t i = height; i > 0; i--) {
for (size_t j = 0; j < width; j++) {
// Locate the current pixel.
size_t pixelIndex = pixelDataOffset + (((i - 1) * width) + j) * 4;
// Extract the blue, green, and red value from the current pixel.
int bluePixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex]);
int greenPixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex + 1]);
int redPixel =
*reinterpret_cast<const uint8_t *>(&fileData[pixelIndex + 2]);
// Store the values into memref container as RGB order. (BGR -> RGB)
this->aligned[memrefIndex] = this->isNorm
? static_cast<T>(redPixel) / 255
: static_cast<T>(redPixel);
this->aligned[memrefIndex + colorStride] =
this->isNorm ? static_cast<T>(greenPixel) / 255
: static_cast<T>(greenPixel);
this->aligned[memrefIndex + 2 * colorStride] =
this->isNorm ? static_cast<T>(bluePixel) / 255
: static_cast<T>(bluePixel);
memrefIndex++;
}
}
} else {
return false;
}
}
} else {
return false;
}
return true;
}

#endif // IMG_H
23 changes: 22 additions & 1 deletion tests/pytorch/memref.hpp → tests/pytorch/include/memref.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
//===- ImgContainer.h -----------------------------------------------------===//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//===----------------------------------------------------------------------===//
//
// Original source from https://github.com/buddy-compiler/buddy-mlir.
// Modified for embedded environment.
//
//===----------------------------------------------------------------------===//

#ifndef MEMREF_H
#define MEMREF_H

Expand Down Expand Up @@ -56,4 +77,4 @@ template <typename T, std::size_t N> inline void MemRef<T, N>::setStrides() {
}
}

#endif
#endif // MEMREF_H
44 changes: 23 additions & 21 deletions tests/pytorch/lenet/build.nix
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,29 @@ buildBuddyE2ETest {
buddy-opt subgraphs0.mlir -pass-pipeline \
"builtin.module(func.func(tosa-to-linalg-named, tosa-to-arith, tosa-to-linalg, tosa-to-tensor))" \
| buddy-opt \
-convert-elementwise-to-linalg \
-func-bufferize-dynamic-offset \
-arith-bufferize \
-func-bufferize \
-tensor-bufferize \
-linalg-bufferize \
-finalizing-bufferize \
-batchmatmul-optimize \
-convert-linalg-to-affine-loops \
-lower-affine \
-convert-vector-to-scf \
-convert-scf-to-cf \
-llvm-request-c-wrappers \
-convert-vector-to-llvm \
-convert-math-to-llvm \
-convert-math-to-libm \
-convert-arith-to-llvm \
-convert-func-to-llvm \
-expand-strided-metadata \
-finalize-memref-to-llvm \
-reconcile-unrealized-casts \
--convert-elementwise-to-linalg \
--func-bufferize-dynamic-offset \
--arith-bufferize \
--func-bufferize \
--tensor-bufferize \
--linalg-bufferize \
--finalizing-bufferize \
--batchmatmul-optimize \
--convert-linalg-to-affine-loops \
--lower-affine \
--convert-vector-to-scf \
--convert-scf-to-cf \
--llvm-request-c-wrappers \
--lower-vector-exp \
--lower-rvv=rv32 \
--convert-vector-to-llvm \
--convert-math-to-llvm \
--convert-math-to-libm \
--convert-arith-to-llvm \
--convert-func-to-llvm \
--expand-strided-metadata \
--finalize-memref-to-llvm \
--reconcile-unrealized-casts \
> subgraphs0-lowered.mlir

optArtifacts+=(
Expand Down
Loading