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

[Model] add Paddle.js web demo #392

Merged
merged 18 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
114 changes: 114 additions & 0 deletions examples/application/web_demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@

LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
# 简介

本项目基于 Paddle.js 实现在浏览器中实现目标检测,人像分割,OCR,物品分类等计算机视觉任务。Paddle.js 是百度 PaddlePaddle 的一个 web 项目,它是一个运行在浏览器中的开源深度学习框架,所有支持 WebGL/WebGPU/WebAssembly 的浏览器中都可以使用 Paddle.js 部署模型。
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved


|Demo名称|WebDemo目录|源码目录|npm包|
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
|-|-|-|-|
|人脸检测|./src/pages/cv/detection/FaceDetection| ./packages/paddlejs-models/detect|[@paddle-js-models/detect](https://www.npmjs.com/package/@paddle-js-models/detect)|
|螺丝检测|src/pages/cv/detection/ScrewDetection| ./packages/paddlejs-models/facedetect|[@paddle-js-models/facedetect](https://www.npmjs.com/package/@paddle-js-models/facedetect)|
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
|人像分割背景替换|./src/pages/cv/segmentation/HumanSeg|./packages/paddlejs-models//humanseg|[@paddle-js-models/humanse](https://www.npmjs.com/package/@paddle-js-models/humanseg)|
|手势识别AI猜丁壳|./src/pages/cv/recognition/GestureRecognition|./packages/paddlejs-models/gesture|[@paddle-js-models/gesture](https://www.npmjs.com/package/@paddle-js-models/gesture)|
|1000种物品识别|./src/pages/cv/recognition/ItemIdentification|./packages/paddlejs-models/mobilenet|[@paddle-js-models/mobilenet](https://www.npmjs.com/package/@paddle-js-models/mobilenet)|
|文本检测|./src/pages/cv/ocr/TextDetection|./packages/paddlejs-models/ocrdetection|[@paddle-js-models/ocrdet](https://www.npmjs.com/package/@paddle-js-models/ocrdet)|
|文本识别|./src/pages/cv/ocr/TextRecognition|./packages/paddlejs-models/ocr|[@paddle-js-models/ocr](https://www.npmjs.com/package/@paddle-js-models/ocr)|



LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
# 1. 快速开始

本节介绍如何在浏览器中运行计算机视觉任务。
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved

**安装Node.js**

从 Node.js官网https://nodejs.org/en/download/ 下载适合自己平台的 Node.js 安装包并安装。

在 ./web_mode/demo 目录下执行如下指令:

```
npm install
npm run dev
```

在浏览器中打开网址 http://localhost:5173/main/index.html 即可快速体验在浏览器中运行计算机视觉任务。

![02f81ab34d6007b54daef9a451240a5c](https://user-images.githubusercontent.com/26592129/196321732-1f089e4a-d053-4d9a-9685-e2eb467e51fb.png)

LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved

# 2. npm包使用方式


本节介绍npm包的使用方式,每个demo均提供简单易用的接口,用户只需初始化上传图片即可获得结果,使用步骤如下:
1. 调用模块
2. 初始化模型
3. 传入输入,执行预测

以 OCR 为例,在前端项目中,ocr包的使用方式如下:

```
// 1. 调用ocr模块
import * as ocr from '@paddle-js-models/ocr';

// 2. 初始化ocr模型
await ocr.init();

// 3. 传入HTMLImageElement类型的图像作为输入并获得结果
const res = await ocr.recognize(img);

// 打印OCR模型得到的文本坐标以及文本内容
console.log(res.text);
console.log(res.points);
```

**更换模型**
LDOUBLEV marked this conversation as resolved.
Show resolved Hide resolved
ocr.init()函数中,包含默认初始化的模型链接,如果要替换模型参考下述步骤。

步骤1:将模型转成js格式:
```
# 安装paddlejsconverter
pip3 install paddlejsconverter
# 转换模型格式,输入模型为inference模型
paddlejsconverter --modelPath=./inference.pdmodel --paramPath=./inference.pdiparams --outputDir=./ --useGPUOpt=True
# 注意:useGPUOpt 选项默认不开启,如果模型用在 gpu backend(webgl/webgpu),则开启 useGPUOpt,如果模型运行在(wasm/plain js)则不要开启。
```

导出成功后,本地目录下会出现 model.json chunk_1.dat文件,分别是js模型的网络结构和模型参数二进制文件。

步骤2:将导出的js模型上传到支持跨域访问的服务器,服务器的CORS配置参考下图:
![image](https://user-images.githubusercontent.com/26592129/196356384-6bd25caf-6cc0-4509-92af-0370149825d8.png)


步骤3:修改代码替换默认的模型。以OCR demo为例,修改OCR web demo中[模型初始化代码](https://github.com/DataVizU/Paddle.js/blob/4b2796c15bcc22f5a99a52fd9a2d9bbf667ee73d/demo/src/pages/cv/ocr/TextRecognition/TextRecognition.vue#L64),即
```
await ocr.init();
修改为:
await ocr.init("https://js-models.bj.bcebos.com/PaddleOCR/PP-OCRv3/ch_PP-OCRv3_det_infer_js_960/model.json"); # 第一个参数传入新的文本检测模型链接
```

重新在demo目录下执行即可体验新的模型效果。
```
npm run dev
```

注:
1. OCR文本识别demo模型部署的源代码链接:
https://github.com/DataVizU/Paddle.js/blob/main/packages/paddlejs-models/ocr/src/index.ts
2. ocr.init()函数有两个参数,分别为检测模型参数的替换和识别模型参数,参考[链接](https://github.com/DataVizU/Paddle.js/blob/4b2796c15bcc22f5a99a52fd9a2d9bbf667ee73d/packages/paddlejs-models/ocr/src/index.ts#L52)


**自定义前后处理参数**

以OCR文本检测 demo为例,修改文本检测后处理的参数实现扩大文本检测框的效果,修改OCR web demo中执行[模型预测代码](https://github.com/DataVizU/Paddle.js/blob/4b2796c15bcc22f5a99a52fd9a2d9bbf667ee73d/demo/src/pages/cv/ocr/TextRecognition/TextRecognition.vue#L99),即:

```
const res = await ocr.recognize(img, { canvas: canvas.value });
修改为:
// 定义超参数,将unclip_ratio参数从1.5 增大为3.5
const detConfig = {shape: 960, thresh: 0.3, box_thresh: 0.6, unclip_ratio:3.5};
const res = await ocr.recognize(img, { canvas: canvas.value }, detConfig);
```

注:OCR文本检测demo模型部署的源代码链接:
https://github.com/DataVizU/Paddle.js/blob/main/packages/paddlejs-models/ocrdetection/src/index.ts

73 changes: 73 additions & 0 deletions examples/application/web_demo/converter/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[中文版](./DEVELOPMENT_cn.md)
# paddlejs-converter

paddlejs-converter is a model transformation tool for Paddle.js. Its role is to convert PaddlePaddle models (also known as fluid models) into a browser-friendly format that Paddle.js can use to load and predict usage in browsers as well as other environments. In addition, paddlejs-converter provides powerful model optimization capabilities to help developers optimize the model structure and improve runtime performance.

## 1. Tutorial

### 1.1. Environment Construction
#### Python Version
Confirm whether the python environment and version of the running platform meet the requirements. If Python 3 is used, you may need to change the `python` in subsequent commands to `python3`:
- Python3: 3.5.1+ / 3.6 / 3.7
- Python2: 2.7.15+

#### Install Virtual Environment
*Since the development environment may have multiple versions of Python installed, there may be different versions of dependent packages. In order to avoid conflicts, it is strongly recommended to use Python virtual environment to execute the commands required by the conversion tool to avoid various problems. If you are not using a virtual environment or if you have a virtual environment installed, you can skip this step.*

Take Anaconda as an example:
Go to [Anaconda](https://www.anaconda.com/) main page,Select the corresponding platform and python version of anaconda and install it according to the official prompts;

After installation, execute the following command on the command line to create a python virtual environment:
``` bash
conda create --name <your_env_name>
```

Execute the following command to switch to the virtual environment
``` bash
# Linux or macOS
source activate <your_env_name>

# Windows
activate <your_env_name>
```

#### Installation Dependency
- If you don't need to optimize model, execute the command:
``` bash
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
```
- Otherwise,execute the command:
``` bash
python -m pip install paddlepaddle paddlelite==2.6.0 -i https://mirror.baidu.com/pypi/simple
```

### 1.2. Get Start
- If the weight file of fluid model to be converted is merged format which means one model corresponds to one weight file, then execute:
``` bash
python convertToPaddleJSModel.py --modelPath=<fluid_model_file_path> --paramPath=<fluid_param_file_path> --outputDir=<paddlejs_model_directory>
```
- Otherwise,execute:
``` bash
# Note that in this way, you need to ensure that the model file name '__ model__ ' in the inputDir
python convertToPaddleJSModel.py --inputDir=<fluid_model_directory> --outputDir=<paddlejs_model_directory>
````
The model converter generates the following two types of files for Paddle.js:

- model.json (Contains the model structure and parameter list)
- chunk_\*.dat (The collection of binary weight files)

## 2. Detailed Documentation

Parameter | description
:-: | :-:
--inputDir | The fluid model directory, If and only if weight files are not merged format, `modelPath` and `paramPath` below will be ignored,and the model file name should be `__model__`.
--modelPath | The model file path, used when the weight file is merged.
--paramPath | The weight file path,used when the weight file is merged.
--outputDir | `Necessary`, the output model directory generated after converting.
--disableOptimize | Whether to disable optimize model, `1`is to disable, `0`is use optimize(need to install PaddleLite), default 0.
--logModelInfo | Whether to print model structure information, `0` means not to print, `1` means to print, default 0.
--sliceDataSize | Shard size (in KB) of each weight file. Default size is 4096.
--useGPUOpt | Whether to use gpu opt, default is False.

## 3. Other information
If the model to be converted is in `tensorflow / Cafe / onnx` format, there is [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) tool in PaddlePaddle program for converting other models with different formats to fluid model, and then you can use paddlejs-converter to get a Paddle.js model.
73 changes: 73 additions & 0 deletions examples/application/web_demo/converter/DEVELOPMENT_cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[English](./README.md)
# paddlejs-converter

paddlejs-converter 是适用于 Paddle.js 的模型转换工具,其作用是将 PaddlePaddle 模型(或称为 fluid 模型)转化为浏览器友好的格式,以供Paddle.js在浏览器等环境中加载预测使用。此外,paddlejs-converter 还提供了强大的模型优化能力,帮助开发者对模型结构进行优化,提高运行时性能。

## 1. 使用教程

### 1.1. 环境搭建
#### Python 版本确认
确认运行平台的 Python 环境与版本是否满足要求,若使用 Python3 ,则可能需要将后续命令中的 `python` 换成 `python3`:
- Python3: 3.5.1+ / 3.6 / 3.7
- Python2: 2.7.15+

#### 安装虚拟环境
*由于开发环境可能安装了多个版本的 Python,相关依赖包可能存在不同的版本,为避免产生冲突,**强烈建议**使用 Python 虚拟环境执行转换工具所需的各项命令,以免产生各种问题。若不使用虚拟环境或已安装虚拟环境,可跳过该步骤。*

以 Anaconda 为例:
前往 [Anaconda](https://www.anaconda.com/) 主页,选择对应平台、Python 版本的 Anaconda 按照官方提示,进行安装;

安装完毕后,在命令行执行以下命令,创建Python 虚拟环境:
``` bash
conda create --name <your_env_name>
```

执行以下命令,切换至虚拟环境
``` bash
# Linux 或 macOS下请执行
source activate <your_env_name>

# Windows 下请执行
activate <your_env_name>
```

#### 安装依赖
- 如果`不需要`使用优化模型的能力,执行命令:
``` bash
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
```
- 如果`需要`使用优化模型的能力,执行命令:
``` bash
python -m pip install paddlepaddle paddlelite==2.6.0 -i https://mirror.baidu.com/pypi/simple
```

### 1.2. 快速上手
- 如果待转换的 fluid 模型为`合并参数文件`,即一个模型对应一个参数文件:
``` bash
python convertToPaddleJSModel.py --modelPath=<fluid_model_file_path> --paramPath=<fluid_param_file_path> --outputDir=<paddlejs_model_directory>
```
- 如果待转换的 fluid 模型为`分片参数文件`,即一个模型文件对应多个参数文件:
``` bash
# 注意,使用这种方式调用转换器,需要保证 inputDir 中,模型文件名为'__model__'
python convertToPaddleJSModel.py --inputDir=<fluid_model_directory> --outputDir=<paddlejs_model_directory>
````
模型转换器将生成以下两种类型的文件以供 Paddle.js 使用:

- model.json (模型结构与参数清单)
- chunk_\*.dat (二进制参数文件集合)

## 2. 详细文档
参数 | 描述
:-: | :-:
--inputDir | fluid 模型所在目录,当且仅当使用分片参数文件时使用该参数,将忽略 `modelPath` 和 `paramPath` 参数,且模型文件名必须为`__model__`
--modelPath | fluid 模型文件所在路径,使用合并参数文件时使用该参数
--paramPath | fluid 参数文件所在路径,使用合并参数文件时使用该参数
--outputDir | `必要参数`, Paddle.js 模型输出路径
--disableOptimize | 是否关闭模型优化, `1` 为关闭优化,`0` 为开启优化(需安装 PaddleLite ),默认执行优化
--logModelInfo | 是否打印模型结构信息, `0` 为不打印, `1` 为打印,默认不打印
--sliceDataSize | 分片输出 Paddle.js 参数文件时,每片文件的大小,单位:KB,默认 4096
--useGPUOpt | 是否开启模型 GPU 优化,默认不开启(当模型准备运行在 webgl/webgpu 计算方案时,可以设置为 True 开启,在 wasm/plainjs 方案,则不用开启)

## 3. 其他信息
若需要转换的模型为 `TensorFlow/Caffe/ONNX` 格式,可使用 PaddlePaddle 项目下的 `X2Paddle`工具,将其他格式的模型转为 fluid 模型后,再使用本工具转化为 Paddle.js 模型。
详细请参考 [X2Paddle 项目](https://github.com/PaddlePaddle/X2Paddle)
29 changes: 29 additions & 0 deletions examples/application/web_demo/converter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# PaddleJsConverter

## Installation

System Requirements:

* paddlepaddle >= 2.0.0
* paddlejslite >= 0.0.2
* Python3: 3.5.1+ / 3.6 / 3.7
* Python2: 2.7.15+

#### Install PaddleJsConverter

<img src="https://img.shields.io/pypi/v/paddlejsconverter" alt="version">

```shell
pip install paddlejsconverter

# or
pip3 install paddlejsconverter
```


## Usage

```shell
paddlejsconverter --modelPath=user_model_path --paramPath=user_model_params_path --outputDir=model_saved_path --useGPUOpt=True
```
注意:useGPUOpt 选项默认不开启,如果模型用在 gpu backend(webgl/webgpu),则开启 useGPUOpt,如果模型运行在(wasm/plain js)则不要开启。
82 changes: 82 additions & 0 deletions examples/application/web_demo/converter/RNN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# RNN算子计算过程

## 一、RNN理解

**RNN** 是循环神经网络,由输入层、隐藏层和输出层组成,擅长对序列数据进行处理。

![RNN](https://user-images.githubusercontent.com/43414102/144739164-d6c4b9ff-d885-4812-8d05-5bf045d3a11b.png)
paddle官网文档:https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/RNN_cn.html#rnn

paddle源码实现:https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/operators/rnn_op.h#L812

##二、RNN计算方式

t 时刻,输入层为 ![图片](https://paddlejs.bj.bcebos.com/doc/xt.svg) ,隐藏层为 ![图片](https://paddlejs.bj.bcebos.com/doc/st.svg) ,输出层为 ![图片](https://paddlejs.bj.bcebos.com/doc/ot.svg) 。由上图可知,![图片](https://paddlejs.bj.bcebos.com/doc/st.svg) 的值不仅仅取决于 ![图片](https://paddlejs.bj.bcebos.com/doc/xt.svg) ,还取决于 ![图片](https://paddlejs.bj.bcebos.com/doc/st1.svg) 。计算公式如下:

![RNN公式](https://user-images.githubusercontent.com/43414102/144739185-92724c8c-25f7-4559-9b1d-f1d76e65d965.jpeg)

## 三、pdjs中RNN算子实现

因为 RNN 有梯度消失问题,不能获取更多上下文信息,所以 CRNN 中使用的是 **LSTM(Long Short Term Memory)**,LSTM 是一种特殊的 RNN,能够保存长期的依赖关系。

基于图像的序列,两个方向的上下文是相互有用且互补的。由于 LSTM 是单向的,所以将两个 LSTM,一个向前和一个向后组合到一个**双向 LSTM** 中。此外,可以堆叠多层双向 LSTM。ch_PP-OCRv2_rec_infer 识别模型就是使用的双层双向 LSTM 结构。计算过程如下图所示:

#### 以ch_ppocr_mobile_v2.0_rec_infer 模型 rnn算子为例:
```javascript
{
Attr: {
mode: 'LSTM'
// 是否双向,为true则正向反向都需要遍历
is_bidirec: true
// 隐藏层层数,代表循环次数
num_layers: 2
}

Input: [
transpose_1.tmp_0[25, 1, 288]
]

PreState: [
fill_constant_batch_size_like_0.tmp_0[4, 1, 48],
fill_constant_batch_size_like_1.tmp_0[4, 1, 48]
]

WeightList: [
lstm_cell_0.w_0[192, 288], lstm_cell_0.w_1[192, 48],
lstm_cell_1.w_0[192, 288], lstm_cell_1.w_1[192, 48],
lstm_cell_2.w_0[192, 96], lstm_cell_2.w_1[192, 48],
lstm_cell_3.w_0[192, 96], lstm_cell_3.w_1[192, 48],
lstm_cell_0.b_0[192], lstm_cell_0.b_1[192],
lstm_cell_1.b_0[192], lstm_cell_1.b_1[192],
lstm_cell_2.b_0[192], lstm_cell_2.b_1[192],
lstm_cell_3.b_0[192], lstm_cell_3.b_1[192]
]

Output: [
lstm_0.tmp_0[25, 1, 96]
]
}
```

#### 整体计算过程
![LSTM计算过程](https://user-images.githubusercontent.com/43414102/144739246-daf839ad-1d96-4e1d-8f34-38ed0bc5f288.png)
#### rnn 计算中新增op:
1)rnn_origin

计算公式: blas.MatMul(Input, WeightList_ih, blas_ih) + blas.MatMul(PreState, WeightList_hh, blas_hh)

2)rnn_matmul

计算公式:rnn_matmul = rnn_origin + Matmul( $ S_{t-1} $, WeightList_hh)

3)rnn_cell

计算方式:将rnn_matmul op输出结果分割成4份,每份执行不同激活函数计算,最后输出lstm_x_y.tmp_c[1, 1, 48]。x∈[0, 3],y∈[0, 24]。
详见算子实现:[rnn_cell](../paddlejs-backend-webgl/src/ops/shader/rnn/rnn_cell.ts)
)

4)rnn_hidden
计算方式:将rnn_matmul op输出结果分割成4份,每份执行不同激活函数计算,最后输出lstm_x_y.tmp_h[1, 1, 48]。x∈[0, 3],y∈[0, 24]。
详见算子实现:[rnn_hidden](../paddlejs-backend-webgl/src/ops/shader/rnn/rnn_hidden.ts)


Loading