Skip to content
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
83 changes: 37 additions & 46 deletions examples/LeNet/LeNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
const size_t WEIGHTS_LENGTH = 1724336;

LeNet::LeNet() {
mContext = CreateCppNeuralNetworkContext();
mContext = CreateCppContext();
mContext.SetUncapturedErrorCallback(
[](WebnnErrorType type, char const* message, void* userData) {
if (type != WebnnErrorType_NoError) {
[](MLErrorType type, char const* message, void* userData) {
if (type != MLErrorType_NoError) {
dawn::ErrorLog() << "Error type is " << type << ", message is " << message;
}
},
Expand All @@ -48,112 +48,103 @@ bool LeNet::Load(const std::string& weigthsPath) {
return false;
}

const webnn::ModelBuilder builder = mContext.CreateModelBuilder();
const ml::GraphBuilder builder = ml::CreateGraphBuilder(mContext);

uint32_t byteOffset = 0;
const webnn::Operand input = utils::BuildInput(builder, "input", {1, 1, 28, 28});
const ml::Operand input = utils::BuildInput(builder, "input", {1, 1, 28, 28});

const std::vector<int32_t> conv2d1FilterShape = {20, 1, 5, 5};
const float* conv2d1FilterData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t conv2d1FilterDataLength = product(conv2d1FilterShape) * sizeof(float);
byteOffset += conv2d1FilterDataLength;
const webnn::Operand conv2d1FilterConstant = utils::BuildConstant(
const ml::Operand conv2d1FilterConstant = utils::BuildConstant(
builder, conv2d1FilterShape, conv2d1FilterData, conv2d1FilterDataLength);
const webnn::Operand conv1 = builder.Conv2d(input, conv2d1FilterConstant);
const ml::Operand conv1 = builder.Conv2d(input, conv2d1FilterConstant);

const std::vector<int32_t> add1BiasShape = {1, 20, 1, 1};
const float* add1BiasData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t add1BiasDataLength = product(add1BiasShape) * sizeof(float);
byteOffset += add1BiasDataLength;
const webnn::Operand add1BiasConstant =
const ml::Operand add1BiasConstant =
utils::BuildConstant(builder, add1BiasShape, add1BiasData, add1BiasDataLength);
const webnn::Operand add1 = builder.Add(conv1, add1BiasConstant);
const ml::Operand add1 = builder.Add(conv1, add1BiasConstant);

utils::Pool2dOptions pool1Options;
pool1Options.windowDimensions = {2, 2};
pool1Options.strides = {2, 2};
const webnn::Operand pool1 = builder.MaxPool2d(add1, pool1Options.AsPtr());
const ml::Operand pool1 = builder.MaxPool2d(add1, pool1Options.AsPtr());

const std::vector<int32_t> conv2d2FilterShape = {50, 20, 5, 5};
const float* conv2d2FilterData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t conv2d2FilterDataLength = product(conv2d2FilterShape) * sizeof(float);
byteOffset += conv2d2FilterDataLength;
const webnn::Operand conv2d2FilterConstant = utils::BuildConstant(
const ml::Operand conv2d2FilterConstant = utils::BuildConstant(
builder, conv2d2FilterShape, conv2d2FilterData, conv2d2FilterDataLength);
const webnn::Operand conv2 = builder.Conv2d(pool1, conv2d2FilterConstant);
const ml::Operand conv2 = builder.Conv2d(pool1, conv2d2FilterConstant);

const std::vector<int32_t> add2BiasShape = {1, 50, 1, 1};
const float* add2BiasData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t add2BiasDataLength = product(add2BiasShape) * sizeof(float);
byteOffset += add2BiasDataLength;
const webnn::Operand add2BiasConstant =
const ml::Operand add2BiasConstant =
utils::BuildConstant(builder, add2BiasShape, add2BiasData, add2BiasDataLength);
const webnn::Operand add2 = builder.Add(conv2, add2BiasConstant);
const ml::Operand add2 = builder.Add(conv2, add2BiasConstant);

utils::Pool2dOptions pool2Options;
pool2Options.windowDimensions = {2, 2};
pool2Options.strides = {2, 2};
const webnn::Operand pool2 = builder.MaxPool2d(add2, pool2Options.AsPtr());
const ml::Operand pool2 = builder.MaxPool2d(add2, pool2Options.AsPtr());

const std::vector<int32_t> newShape = {1, -1};
const webnn::Operand reshape1 = builder.Reshape(pool2, newShape.data(), newShape.size());
const ml::Operand reshape1 = builder.Reshape(pool2, newShape.data(), newShape.size());
// skip the new shape, 2 int64 values
byteOffset += 2 * 8;

const std::vector<int32_t> matmul1Shape = {500, 800};
const float* matmul1Data = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t matmul1DataLength = product(matmul1Shape) * sizeof(float);
byteOffset += matmul1DataLength;
const webnn::Operand matmul1Weights =
const ml::Operand matmul1Weights =
utils::BuildConstant(builder, matmul1Shape, matmul1Data, matmul1DataLength);
const webnn::Operand matmul1WeightsTransposed = builder.Transpose(matmul1Weights);
const webnn::Operand matmul1 = builder.Matmul(reshape1, matmul1WeightsTransposed);
const ml::Operand matmul1WeightsTransposed = builder.Transpose(matmul1Weights);
const ml::Operand matmul1 = builder.Matmul(reshape1, matmul1WeightsTransposed);

const std::vector<int32_t> add3BiasShape = {1, 500};
const float* add3BiasData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t add3BiasDataLength = product(add3BiasShape) * sizeof(float);
byteOffset += add3BiasDataLength;
const webnn::Operand add3BiasConstant =
const ml::Operand add3BiasConstant =
utils::BuildConstant(builder, add3BiasShape, add3BiasData, add3BiasDataLength);
const webnn::Operand add3 = builder.Add(matmul1, add3BiasConstant);
const ml::Operand add3 = builder.Add(matmul1, add3BiasConstant);

const webnn::Operand relu = builder.Relu(add3);
const ml::Operand relu = builder.Relu(add3);

const std::vector<int32_t> newShape2 = {1, -1};
const webnn::Operand reshape2 = builder.Reshape(relu, newShape2.data(), newShape2.size());
const ml::Operand reshape2 = builder.Reshape(relu, newShape2.data(), newShape2.size());

const std::vector<int32_t> matmul2Shape = {10, 500};
const float* matmul2Data = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t matmul2DataLength = product(matmul2Shape) * sizeof(float);
byteOffset += matmul2DataLength;
const webnn::Operand matmul2Weights =
const ml::Operand matmul2Weights =
utils::BuildConstant(builder, matmul2Shape, matmul2Data, matmul2DataLength);
const webnn::Operand matmul2WeightsTransposed = builder.Transpose(matmul2Weights);
const webnn::Operand matmul2 = builder.Matmul(reshape2, matmul2WeightsTransposed);
const ml::Operand matmul2WeightsTransposed = builder.Transpose(matmul2Weights);
const ml::Operand matmul2 = builder.Matmul(reshape2, matmul2WeightsTransposed);

const std::vector<int32_t> add4BiasShape = {1, 10};
const float* add4BiasData = reinterpret_cast<float*>(weightsData.get() + byteOffset);
const uint32_t add4BiasDataLength = product(add4BiasShape) * sizeof(float);
byteOffset += add4BiasDataLength;
const webnn::Operand add4BiasConstant =
const ml::Operand add4BiasConstant =
utils::BuildConstant(builder, add4BiasShape, add4BiasData, add4BiasDataLength);
const webnn::Operand add4 = builder.Add(matmul2, add4BiasConstant);
const ml::Operand add4 = builder.Add(matmul2, add4BiasConstant);

const webnn::Operand softmax = builder.Softmax(add4);
const ml::Operand softmax = builder.Softmax(add4);

mModel = utils::CreateModel(builder, {{"output", softmax}});
return true;
}

bool LeNet::Compile(webnn::CompilationOptions const* options) {
if (!mModel) {
dawn::ErrorLog() << "Model is not ready.";
return false;
}
const std::chrono::time_point<std::chrono::high_resolution_clock> startTime =
std::chrono::high_resolution_clock::now();
mCompilation = utils::AwaitCompile(mModel, options);
if (!mCompilation) {
mGraph = utils::AwaitBuild(builder, {{"output", softmax}});
if (!mGraph) {
return false;
}
const std::chrono::duration<double, std::milli> elapsedTime =
Expand All @@ -162,16 +153,16 @@ bool LeNet::Compile(webnn::CompilationOptions const* options) {
return true;
}

webnn::Result LeNet::Compute(const void* inputData, size_t inputLength) {
if (!mCompilation) {
dawn::ErrorLog() << "Compilation is not ready.";
return webnn::Result();
ml::Result LeNet::Compute(const void* inputData, size_t inputLength) {
if (!mGraph) {
dawn::ErrorLog() << "Graph is not ready.";
return ml::Result();
}
const std::chrono::time_point<std::chrono::high_resolution_clock> startTime =
std::chrono::high_resolution_clock::now();
mResults = utils::AwaitCompute(mCompilation, {{"input", {inputData, inputLength}}});
mResults = utils::AwaitCompute(mGraph, {{"input", {inputData, inputLength}}});
if (!mResults) {
return webnn::Result();
return ml::Result();
}
const std::chrono::duration<double, std::milli> elapsedTime =
std::chrono::high_resolution_clock::now() - startTime;
Expand Down
10 changes: 4 additions & 6 deletions examples/LeNet/LeNet.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ class LeNet {
~LeNet() = default;

bool Load(const std::string& weigthsPath);
bool Compile(webnn::CompilationOptions const* options = nullptr);
webnn::Result Compute(const void* inputData, size_t inputLength);
ml::Result Compute(const void* inputData, size_t inputLength);

private:
webnn::NeuralNetworkContext mContext;
webnn::Model mModel;
webnn::Compilation mCompilation;
webnn::NamedResults mResults;
ml::Context mContext;
ml::Graph mGraph;
ml::NamedResults mResults;
};
8 changes: 2 additions & 6 deletions examples/LeNet/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void SelectTopKData(std::vector<float> outputData,
}
}

void PrintResult(webnn::Result output) {
void PrintResult(ml::Result output) {
const float* outputBuffer = static_cast<const float*>(output.Buffer());
std::vector<float> outputData(outputBuffer, outputBuffer + output.BufferSize() / sizeof(float));
std::vector<size_t> topKIndex(TOP_NUMBER);
Expand Down Expand Up @@ -116,12 +116,8 @@ int main(int argc, const char* argv[]) {
dawn::ErrorLog() << "Failed to load LeNet.";
return -1;
}
if (!lenet.Compile()) {
dawn::ErrorLog() << "Failed to compile LeNet.";
return -1;
}
std::vector<float> input(reader.GetData().get(), reader.GetData().get() + reader.Size());
webnn::Result result = lenet.Compute(input.data(), input.size() * sizeof(float));
ml::Result result = lenet.Compute(input.data(), input.size() * sizeof(float));
if (!result) {
dawn::ErrorLog() << "Failed to compute LeNet.";
return -1;
Expand Down
77 changes: 36 additions & 41 deletions examples/SampleUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ uint32_t product(const std::vector<int32_t>& dims) {
return prod;
}

webnn::NeuralNetworkContext CreateCppNeuralNetworkContext() {
ml::Context CreateCppContext() {
WebnnProcTable backendProcs = webnn_native::GetProcs();
webnnProcSetProcs(&backendProcs);
WebnnNeuralNetworkContext context = webnn_native::CreateNeuralNetworkContext();
MLContext context = webnn_native::CreateContext();
if (context) {
return webnn::NeuralNetworkContext::Acquire(context);
return ml::Context::Acquire(context);
}
return webnn::NeuralNetworkContext();
return ml::Context();
}

void DumpMemoryLeaks() {
Expand All @@ -63,77 +63,72 @@ bool Expected(float output, float expected) {

namespace utils {

webnn::Operand BuildInput(const webnn::ModelBuilder& builder,
ml::Operand BuildInput(const ml::GraphBuilder& builder,
std::string name,
const std::vector<int32_t>& dimensions,
webnn::OperandType type) {
webnn::OperandDescriptor desc = {type, dimensions.data(), (uint32_t)dimensions.size()};
ml::OperandType type) {
ml::OperandDescriptor desc = {type, dimensions.data(), (uint32_t)dimensions.size()};
return builder.Input(name.c_str(), &desc);
}

webnn::Operand BuildConstant(const webnn::ModelBuilder& builder,
ml::Operand BuildConstant(const ml::GraphBuilder& builder,
const std::vector<int32_t>& dimensions,
const void* value,
size_t size,
webnn::OperandType type) {
webnn::OperandDescriptor desc = {type, dimensions.data(), (uint32_t)dimensions.size()};
ml::OperandType type) {
ml::OperandDescriptor desc = {type, dimensions.data(), (uint32_t)dimensions.size()};
return builder.Constant(&desc, value, size);
}

webnn::Model CreateModel(const webnn::ModelBuilder& builder,
ml::Graph AwaitBuild(const ml::GraphBuilder& builder,
const std::vector<NamedOutput>& outputs) {
webnn::NamedOperands namedOperands = webnn::CreateNamedOperands();
for (auto& output : outputs) {
namedOperands.Set(output.name.c_str(), output.operand);
}
return builder.CreateModel(namedOperands);
}

webnn::Compilation AwaitCompile(const webnn::Model& model,
webnn::CompilationOptions const* options) {
typedef struct {
Async async;
webnn::Compilation compilation;
} CompilationData;
ml::Graph graph;
} BuildData;

CompilationData compilationData;
model.Compile(
[](WebnnCompileStatus status, WebnnCompilation impl, char const* message,
BuildData buildData;
ml::NamedOperands namedOperands = ml::CreateNamedOperands();
for (auto& output : outputs) {
namedOperands.Set(output.name.c_str(), output.operand);
}
builder.Build(namedOperands,
[](MLBuildGraphStatus status, MLGraph impl, char const* message,
void* userData) {
CompilationData* compilationDataPtr = reinterpret_cast<CompilationData*>(userData);
DAWN_ASSERT(compilationDataPtr);
if (status != WebnnCompileStatus_Success) {
dawn::ErrorLog() << "Compile failed: " << message;
BuildData* buildDataPtr = reinterpret_cast<BuildData*>(userData);
DAWN_ASSERT(buildDataPtr);
if (status != MLBuildGraphStatus_Success) {
dawn::ErrorLog() << "Compute failed: " << message;
} else {
compilationDataPtr->compilation = compilationDataPtr->compilation.Acquire(impl);
buildDataPtr->graph = buildDataPtr->graph.Acquire(impl);
}
compilationDataPtr->async.Finish();
buildDataPtr->async.Finish();
return;
},
&compilationData, options);
compilationData.async.Wait();
return compilationData.compilation;
&buildData);
buildData.async.Wait();
return buildData.graph;
}

webnn::NamedResults AwaitCompute(const webnn::Compilation& compilation,
ml::NamedResults AwaitCompute(const ml::Graph& graph,
const std::vector<NamedInput>& inputs) {
typedef struct {
Async async;
webnn::NamedResults results;
ml::NamedResults results;
} ComputeData;

ComputeData computeData;
webnn::NamedInputs namedInputs = webnn::CreateNamedInputs();
ml::NamedInputs namedInputs = ml::CreateNamedInputs();
for (auto& input : inputs) {
namedInputs.Set(input.name.c_str(), &input.input);
}
compilation.Compute(
graph.Compute(
namedInputs,
[](WebnnComputeStatus status, WebnnNamedResults impl, char const* message,
[](MLComputeGraphStatus status, MLNamedResults impl, char const* message,
void* userData) {
ComputeData* computeDataPtr = reinterpret_cast<ComputeData*>(userData);
DAWN_ASSERT(computeDataPtr);
if (status != WebnnComputeStatus_Success) {
if (status != MLComputeGraphStatus_Success) {
dawn::ErrorLog() << "Compute failed: " << message;
} else {
computeDataPtr->results = computeDataPtr->results.Acquire(impl);
Expand All @@ -146,7 +141,7 @@ namespace utils {
return computeData.results;
}

bool CheckShape(const webnn::Result& result, const std::vector<int32_t>& expectedShape) {
bool CheckShape(const ml::Result& result, const std::vector<int32_t>& expectedShape) {
if (expectedShape.size() != result.DimensionsSize()) {
dawn::ErrorLog() << "The output rank is expected as " << expectedShape.size()
<< ", but got " << result.DimensionsSize();
Expand Down
Loading