Skip to content

Commit

Permalink
[TIPC] Add js infer test (#1588)
Browse files Browse the repository at this point in the history
  • Loading branch information
JingyuanZhang authored Dec 9, 2021
1 parent b596fc3 commit 4ce007d
Show file tree
Hide file tree
Showing 10 changed files with 353 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,4 @@ venv.bak/
# js
node_modules/
package-lock.json
test_tipc/web/models/
50 changes: 50 additions & 0 deletions test_tipc/docs/test_infer_js.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Web 端基础预测功能测试

Web 端主要基于 Jest-Puppeteer 完成 e2e 测试,其中 Puppeteer 操作 Chrome 完成推理流程,Jest 完成测试流程。
>Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome
>Jest 是一个 JavaScript 测试框架,旨在确保任何 JavaScript 代码的正确性。
#### 环境准备

* 安装 Node(包含 npm ) (https://nodejs.org/zh-cn/download/)
* 确认是否安装成功,在命令行执行
```sh
# 显示所安 node 版本号,即表示成功安装
node -v
```
* 确认 npm 是否安装成成
```sh
# npm 随着 node 一起安装,一般无需额外安装
# 显示所安 npm 版本号,即表示成功安装
npm -v
```

#### 使用
```sh
# web 测试环境准备
bash test_tipc/prepare_js.sh 'js_infer'

# web 推理测试
bash test_tipc/test_infer_js.sh
```


#### 流程设计

###### paddlejs prepare
1. 判断 node, npm 是否安装
2. 下载测试模型,当前为 ppseg_lite_portrait_398x224 ,如果需要替换,把对应模型连接和模型包名字修改即可
- 当前模型:https://paddleseg.bj.bcebos.com/dygraph/ppseg/ppseg_lite_portrait_398x224.tar.gz
- 模型配置:configs/pp_humanseg_lite/pp_humanseg_lite_export_398x224.yml
3. 导出模型为静态图模型(保存地址:test_tipc/web/models/pphumanseg_lite)
4. 转换模型, model.pdmodel model.pdiparams 转换为 model.json chunk.dat
5. 安装最新版本 humanseg sdk @paddlejs-models/humanseg@latest
6. 安装测试环境依赖 puppeteer、jest、jest-puppeteer,如果检查到已经安装,则不会进行二次安装


###### paddlejs infer test
1. Jest 执行 server command:`python3 -m http.server 9811` 开启本地服务
2. 启动 Jest 测试服务,通过 jest-puppeteer 插件完成 chrome 操作,加载 @paddlejs-models/humanseg 脚本完成推理流程
3. 测试用例为分割后的图片与预期图片(expect img)效果进行**逐像素对比**,精度误差不超过 **2%**,则视为测试通过,通过为如下显示:
<img width="594" alt="infoflow 2021-12-02 16-34-05" src="https://user-images.githubusercontent.com/
10822846/144386307-b4e10b07-f105-499f-b953-4dc2707c6242.png">
85 changes: 85 additions & 0 deletions test_tipc/prepare_js.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

set -o errexit
set -o nounset
shopt -s extglob

# paddlejs prepare 主要流程
# 1. 判断 node, npm 是否安装
# 2. 下载测试模型,当前为 ppseg_lite_portrait_398x224 ,如果需要替换,把对应模型连接和模型包名字修改即可
# - 当前模型:https://paddleseg.bj.bcebos.com/dygraph/ppseg/ppseg_lite_portrait_398x224.tar.gz
# - 模型配置:configs/pp_humanseg_lite/pp_humanseg_lite_export_398x224.yml
# 3. 导出模型为静态图模型
# 4. 转换模型, model.pdmodel model.pdiparams 转换为 model.json chunk.dat
# 5. 安装最新版本 humanseg sdk @paddlejs-models/humanseg@latest
# 6. 安装测试环境依赖 puppeteer、jest、jest-puppeteer

# 判断是否安装了node
if ! type node >/dev/null 2>&1; then
echo -e "\033[31m node 未安装 \033[0m"
exit
fi

# 判断是否安装了npm
if ! type npm >/dev/null 2>&1; then
echo -e "\033[31m npm 未安装 \033[0m"
exit
fi

# MODE be 'js_infer'
MODE=$1
# js_infer MODE , load model file and convert model to js_infer
if [ ${MODE} != "js_infer" ];then
echo "Please change mode to 'js_infer'"
exit
fi


# saved_model_name
saved_model_name=pphumanseg_lite
# model_path
model_path=test_tipc/web/models/

rm -rf $model_path
echo ${model_path}${saved_model_name}

# download inference model
wget -nc -P $model_path https://paddleseg.bj.bcebos.com/dygraph/ppseg/ppseg_lite_portrait_398x224.tar.gz
cd $model_path && tar xf ppseg_lite_portrait_398x224.tar.gz && cd ../../../

# export to static shape model
python3 export.py \
--config configs/pp_humanseg_lite/pp_humanseg_lite_export_398x224.yml \
--model_path test_tipc/web/models/ppseg_lite_portrait_398x224/model.pdparams \
--save_dir $model_path$saved_model_name/ \
--input_shape 1 3 224 398 \
--without_argmax --with_softmax


pip3 install paddlejsconverter
# convert inference model to web model: model.json、chunk_1.dat
paddlejsconverter \
--modelPath=$model_path$saved_model_name/model.pdmodel \
--paramPath=$model_path$saved_model_name/model.pdiparams \
--outputDir=$model_path$saved_model_name/ \




# always install latest humanseg sdk
cd test_tipc/web
echo -e "\033[33m Installing the latest humanseg sdk... \033[0m"
npm install @paddlejs-models/humanseg@latest
echo -e "\033[32m The latest humanseg sdk installed completely.!~ \033[0m"

# install dependencies
if [ `npm list --dept 0 | grep puppeteer | wc -l` -ne 0 ] && [ `npm list --dept 0 | grep jest | wc -l` -ne 0 ];then
echo -e "\033[32m Dependencies have installed \033[0m"
else
echo -e "\033[33m Installing dependencies ... \033[0m"
npm install jest jest-puppeteer puppeteer
echo -e "\033[32m Dependencies installed completely.!~ \033[0m"
fi

# del package-lock.json
rm package-lock.json
8 changes: 8 additions & 0 deletions test_tipc/test_infer_js.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

set -o errexit
set -o nounset

cd test_tipc/web
# run humanseg test in chrome
./node_modules/.bin/jest --config ./jest.config.js
Binary file added test_tipc/web/imgs/human.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test_tipc/web/imgs/seg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions test_tipc/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>pphumanseg_lite test</title>
<style>
body img {
width: 300px;
border: 2px black solid;
}
canvas {
border: 2px black solid;
}
.test {
display: flex;
}
.test div.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
</head>
<body >
<div class="test">
<div class="item">
<img id="human" src="./imgs/human.jpg"/>
<div> origin img </div>
</div>
<div class="item">
<img id="seg" src="./imgs/seg.png"/>
<div> expect img </div>
</div>
</div>
<canvas id="back_canvas"></canvas>
</body>
<script src="./node_modules/@paddlejs-models/humanseg/lib/index.js"></script>
</html>
43 changes: 43 additions & 0 deletions test_tipc/web/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
describe('e2e test humanseg model', () => {
beforeAll(async () => {
await page.goto(PATH);
});

it('humanseg infer and diff test', async () => {
page.on('console', msg => console.log('PAGE LOG:', msg.text()));
const mAP = await page.evaluate(async () => {
const human = document.querySelector('#human');
const seg = document.querySelector('#seg');
const back_canvas = document.getElementById('back_canvas');
const back_ctx = back_canvas.getContext('2d');

const seg_canvas = document.createElement('canvas');
const seg_ctx = seg_canvas.getContext('2d');
seg_canvas.width = back_canvas.width = seg.naturalWidth;
seg_canvas.height = back_canvas.height = seg.naturalHeight;
seg_ctx.drawImage(seg, 0, 0, seg_canvas.width, seg_canvas.height);

const humanseg = paddlejs['humanseg'];

await humanseg.load(true, false, './models/pphumanseg_lite/model.json');
const {
data
} = await humanseg.getGrayValue(human);
humanseg.drawHumanSeg(data, back_canvas);

const backImageData = back_ctx.getImageData(0, 0, back_canvas.width, back_canvas.height).data;
const segImageData = seg_ctx.getImageData(0, 0, seg_canvas.width, seg_canvas.height).data;

let diffPixelsNum = 0;
for (let index = 0; index < backImageData.length; index++) {
if (backImageData[index] !== segImageData[index]) {
diffPixelsNum++;
}
}
return diffPixelsNum / backImageData.length;
});

const expectedMAP = 0.02;
await expect(mAP).toBeLessThanOrEqual(expectedMAP);
});
});
14 changes: 14 additions & 0 deletions test_tipc/web/jest-puppeteer.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// jest-puppeteer.config.js
module.exports = {
launch: {
headless: false,
product: 'chrome'
},
browserContext: 'default',
server: {
command: 'python3 -m http.server 9811',
port: 9811,
launchTimeout: 10000,
debug: true
}
};
111 changes: 111 additions & 0 deletions test_tipc/web/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// For a detailed explanation regarding each configuration property and type check, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
preset: 'jest-puppeteer',
// All imported modules in your tests should be mocked automatically
// automock: false,

// Automatically clear mock calls and instances between every test
clearMocks: true,

// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,

// A set of global variables that need to be available in all test environments
globals: {
PATH: 'http://localhost:9811'
},

// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",

// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],

// An array of file extensions your modules use
moduleFileExtensions: [
'js',
'json',
'jsx',
'ts',
'tsx',
'node'
],


// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,

// A list of paths to directories that Jest should use to search for files in
roots: [
'<rootDir>'
],

// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",

// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],

// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],

// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,

// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],

// The test environment that will be used for testing
// testEnvironment: 'jsdom',

// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
testPathIgnorePatterns: [
'/node_modules/'
],

// The regexp pattern or array of patterns that Jest uses to detect test files
testRegex: '.(.+)\\.test\\.(js|ts)$',

// This option allows the use of a custom results processor
// testResultsProcessor: undefined,

// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",

// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
testURL: 'http://localhost:9898/',

// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",

// A map from regular expressions to paths to transformers
transform: {
'^.+\\.js$': 'babel-jest'
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [
'/node_modules/',
'\\.pnp\\.[^\\/]+$'
],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,

// Indicates whether each individual test should be reported during the run
verbose: true,

// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],

// Whether to use watchman for file crawling
// watchman: true,
testTimeout: 50000
};

0 comments on commit 4ce007d

Please sign in to comment.