未验证 提交 6c40834f 编写于 作者: W wangqun 提交者: GitHub

Merge pull request #6 from wangqunbaidu/master

[d][change] 支持paddle op融合pass
...@@ -33,52 +33,52 @@ If the original model was a SavedModel, use paddle.load(). ...@@ -33,52 +33,52 @@ If the original model was a SavedModel, use paddle.load().
```bash ```bash
import Paddle from 'paddlejs'; import Paddle from 'paddlejs';
let feed = io.process({ let feed = io.process({
input: document.getElementById('image'), input: document.getElementById('image'),
params: { params: {
gapFillWith: '#000', // What to use to fill the square part after zooming gapFillWith: '#000', // What to use to fill the square part after zooming
targetSize: { targetSize: {
height: fw, height: fw,
width: fh width: fh
}, },
targetShape: [1, 3, fh, fw], // Target shape changed its name to be compatible with previous logic targetShape: [1, 3, fh, fw], // Target shape changed its name to be compatible with previous logic
// shape: [3, 608, 608], // Preset sensor shape // shape: [3, 608, 608], // Preset sensor shape
mean: [117.001, 114.697, 97.404], // Preset mean mean: [117.001, 114.697, 97.404], // Preset mean
// std: [0.229, 0.224, 0.225] // Preset std // std: [0.229, 0.224, 0.225] // Preset std
} }
}); });
const MODEL_CONFIG = { const MODEL_CONFIG = {
dir: `/${path}/`, // model URL dir: `/${path}/`, // model URL
main: 'model.json', // main graph main: 'model.json', // main graph
}; };
const paddle = new Paddle({ const paddle = new Paddle({
urlConf: MODEL_CONFIG, urlConf: MODEL_CONFIG,
options: {
multipart: true,
dataType: 'binary',
options: { options: {
multipart: true, fileCount: 1, // How many model have been cut
dataType: 'binary', getFileName(i) {
options: { return 'chunk_' + i + '.dat';
fileCount: 1, // How many model have been cut
getFileName(i) {
return 'chunk_' + i + '.dat';
}
} }
} }
}); }
});
model = await paddle.load(); model = await paddle.load();
// //
let inst = model.execute({ let inst = model.execute({
input: feed input: feed
}); });
// There should be a fetch execution call or a fetch output // There should be a fetch execution call or a fetch output
let result = await inst.read(); let result = await inst.read();
``` ```
......
...@@ -4,6 +4,9 @@ import IO from '../../src/feed/imageFeed'; ...@@ -4,6 +4,9 @@ import IO from '../../src/feed/imageFeed';
import Utils from '../../src/utils/utils'; import Utils from '../../src/utils/utils';
// 获取map表 // 获取map表
import Map from '../../test/data/map'; import Map from '../../test/data/map';
const fileDownload = require('js-file-download');
/** /**
* @file model demo 入口文件 * @file model demo 入口文件
* @author wangqun@baidu.com * @author wangqun@baidu.com
...@@ -11,25 +14,21 @@ import Map from '../../test/data/map'; ...@@ -11,25 +14,21 @@ import Map from '../../test/data/map';
*/ */
// 模型feed数据 // 模型feed数据
const feedShape = { const feedShape = {
'608': { 'mobilenetv2': {
fw: 608, fw: 224,
fh: 608 fh: 224
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'separate': {
fw: 244,
fh: 244
} }
}; };
const modelType = 'separate';
// 模型fetch数据
const fetchShape = {
'mobilenetv2': [1, 1000, 1, 1]
};
const modelType = 'mobilenetv2';
const {fw, fh} = feedShape[modelType]; const {fw, fh} = feedShape[modelType];
const outputShape = fetchShape[modelType];
// 统计参数 // 统计参数
let loaded = false; let loaded = false;
let model = {}; let model = {};
...@@ -37,19 +36,21 @@ window.statistic = []; ...@@ -37,19 +36,21 @@ window.statistic = [];
async function run(input) { async function run(input) {
// const input = document.getElementById('mobilenet'); // const input = document.getElementById('mobilenet');
const io = new IO(); const io = new IO();
let feed = io.process({ let feed = io.process({
input: input, input: input,
params: { params: {
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名 gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fh,
width: fw
},
scale: 256, // 缩放尺寸 scale: 256, // 缩放尺寸
width: 224, height: 224, // 压缩宽高 targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
shape: [3, 224, 224], // 预设tensor形状 mean: [0.485, 0.456, 0.406],
mean: [0.485, 0.456, 0.406], // 预设期望 std: [0.229, 0.224, 0.225]
std: [0.229, 0.224, 0.225] // 预设方差 }
}}); });
console.log('feed', feed);
const path = 'model/mobileNet'; const path = 'model/mobileNet';
if (!loaded) { if (!loaded) {
...@@ -62,31 +63,45 @@ async function run(input) { ...@@ -62,31 +63,45 @@ async function run(input) {
urlConf: MODEL_CONFIG, urlConf: MODEL_CONFIG,
options: { options: {
multipart: true, multipart: true,
dataType: 'json' dataType: 'binary',
options: {
fileCount: 4, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_' + i + '.dat';
}
},
feed
} }
}); });
model = await paddle.load(); model = await paddle.load();
} }
let inst = model.execute({ let inst = model.execute({
input: feed input: feed
}); });
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read(); let result = await inst.read();
console.dir(['result', result]); let N = outputShape[0];
// let maxItem = Utils.getMaxItem(result); let C = outputShape[1];
// document.getElementById('txt').innerHTML = Map['' + maxItem.index]; let H = outputShape[2];
// console.log('识别出的结果是' + Map['' + maxItem.index]); let W = outputShape[3];
// console.dir(['每个op耗时', window.statistic]); console.log(outputShape);
// let total = statistic.reduce((all, cur) => { let nhwcShape = [N, H, W, C];
// return all + cur.runTime; console.log(nhwcShape);
// }, 0); console.log(result.length);
// console.log('op total = ' + total);
let nchwData = Utils.nhwc2nchw(result, nhwcShape);
Utils.stridePrint(nchwData);
Utils.continuousPrint(nchwData);
// for test
// fileDownload(nchwData, "paddlejs-0.txt");
let maxItem = Utils.getMaxItem(nchwData);
console.log(maxItem);
document.getElementById('txt').innerHTML = Map['' + maxItem.index];
console.log('识别出的结果是' + Map['' + maxItem.index]);
}; };
var image = ''; var image = '';
function selectImage(file) { function selectImage(file) {
......
...@@ -3,64 +3,12 @@ ...@@ -3,64 +3,12 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>paddle web demo</title> <title>paddle web demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,initial-scale=1,viewport-fit=cover"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<style>
p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
}
#uploadImg {
border: solid 1px #808080;
width: 100%;
padding: 10px;
background-color: #cabfbf;
color: #FFF;
font-size: 16px;
}
p.section-head {
font-variant: small-caps;
text-transform: uppercase;
letter-spacing: .17em;
line-height: 1.2em;
font-weight: 500;
margin-top: 2em;
margin-bottom: 1em;
border-left: 1px solid #EF6C00;
padding-left: 24px;
color: #818181;
}
.image-wrap {
position: relative;
}
#image {
width: 100%;
}
#myDiv {
position: absolute;
border: 1px solid #F00;
box-sizing: border-box;
}
</style>
</head> </head>
<body> <body>
<section class="title-area"> <img id="image" src="https://m.baidu.com/se/static/img/iphone/logo.png" style="max-width: 100%;">
<h1>Paddle.js: Using a pretrained mobileNet V2</h1> <input type="file" id="uploadImg">
</section> <div id="txt"></div>
<section>
<p class="section-head">Description</p>
<p>
Please upload a picture to experience online classification.
</p>
</section>
<section>
<img id="image" src="https://m.baidu.com/se/static/img/iphone/logo.png" style="max-width: 100%;">
<input type="file" id="uploadImg">
<div id="txt"></div>
</section>
<script src="index.es6"></script> <script src="index.es6"></script>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -74,12 +74,12 @@ async function run(input) { ...@@ -74,12 +74,12 @@ async function run(input) {
params: { params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分 gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: { targetSize: {
height: fw, height: fh,
width: fh width: fw
}, },
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名 targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状 // shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404], // 预设期望 mean: [117.001 / 255, 114.697 / 255, 97.404 / 255], // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差 // std: [0.229, 0.224, 0.225] // 预设方差
} }
}); });
......
...@@ -5,45 +5,44 @@ ...@@ -5,45 +5,44 @@
<title>paddleJS demo</title> <title>paddleJS demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,initial-scale=1,viewport-fit=cover"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,initial-scale=1,viewport-fit=cover">
<style> <style>
p { p {
display: block; display: block;
margin-block-start: 1em; margin-block-start: 1em;
margin-block-end: 1em; margin-block-end: 1em;
margin-inline-start: 0px; margin-inline-start: 0;
margin-inline-end: 0px; margin-inline-end: 0;
} }
#uploadImg { #uploadImg {
border: solid 1px gray; border: solid 1px #808080;
width: 100%; width: 100%;
padding: 10px; padding: 10px;
background-color: #cabfbf; background-color: #cabfbf;
color: white; color: #FFF;
font-size: 16px; font-size: 16px;
} }
p.section-head { p.section-head {
font-variant: small-caps; font-variant: small-caps;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.17em; letter-spacing: .17em;
line-height: 1.2em; line-height: 1.2em;
font-weight: 500; font-weight: 500;
margin-top: 2em; margin-top: 2em;
margin-bottom: 1em; margin-bottom: 1em;
border-left: 1px solid #EF6C00; border-left: 1px solid #EF6C00;
padding-left: 24px; padding-left: 24px;
color: #818181;
color: #818181; }
} .image-wrap {
.image-wrap { position: relative;
position: relative; }
} #image {
#image { width: 100%;
width: 100%; }
} #myDiv {
#myDiv { position: absolute;
position: absolute; border: 1px solid #F00;
border: 1px solid red; box-sizing: border-box;
box-sizing: border-box; }
}
</style> </style>
</head> </head>
<body> <body>
...@@ -62,17 +61,17 @@ ...@@ -62,17 +61,17 @@
<section> <section>
<p class="section-head">Model Output</p> <p class="section-head">Model Output</p>
<div class="image-wrap"> <div class="image-wrap">
<img id="mobilenet" /> <img id="mobilenet">
</div> </div>
<p>原图片</p> <p>原图片</p>
<div class="image-wrap"> <div class="image-wrap">
<img id="image" src=""/> <img id="image" src="data:image/jpeg;base64,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">
<div id="myDiv"></div> <div id="myDiv"></div>
</div> </div>
<p>画布</p> <p>画布</p>
<canvas id="myCanvas"></canvas> <canvas id="myCanvas"></canvas>
<br/> <br>
<input type="file" id="uploadImg"/> <input type="file" id="uploadImg">
<div id="txt"></div> <div id="txt"></div>
</section> </section>
......
import 'babel-polyfill'; import 'babel-polyfill';
import Runner from '../src/executor/runner'; import Runner from '../../src/executor/runner';
import Camera from '../src/executor/camera'; import Camera from '../../src/executor/camera';
// 调试工具 // 调试工具
// import vConsole from 'vconsole'; // import vConsole from 'vconsole';
// const theConsole = new vConsole(); // const theConsole = new vConsole();
let startBtn = document.getElementById('start'); let startBtn = document.getElementById('start');
let stopBtn = document.getElementById('stop') let stopBtn = document.getElementById('stop')
// 模型输出shape
const outputShapes = {
'608': {
from: [19, 19, 25, 1],
to: [19, 19, 5, 5]
},
'320': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'320fused': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'tinyYolo': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
}
};
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'tinyYolo': {
fw: 320,
fh: 320
}
};
const modelPath = {
'tinyYolo': 'model/tinyYolo'
};
const modelType = 'tinyYolo';
const path = modelPath[modelType];
const runner = new Runner({ const runner = new Runner({
// 用哪个模型 // 用哪个模型
modelName: 'separate' // '608' | '320' | '320fused' | 'separate' modelName: modelType, // '608' | '320' | '320fused' | 'separate'
modelPath: path,
feedShape: feedShape[modelType],
outputShapes: outputShapes[modelType]
}); });
startBtn.disabled = true; startBtn.disabled = true;
runner.preheat() runner.preheat()
.then(() =>{ .then(() =>{
startBtn.disabled = false startBtn.disabled = false;
}); });
const domElement = document.getElementById('video'); const domElement = document.getElementById('video');
const myCanvas = document.getElementById('myDiv'); const myCanvas = document.getElementById('myDiv');
......
...@@ -5,32 +5,59 @@ ...@@ -5,32 +5,59 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>识别摄像头里的脸</title> <title>识别摄像头里的脸</title>
<style> <style>
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#myDiv { #myDiv {
position: fixed; position: fixed;
border: 1px solid red; border: 1px solid #F00;
box-sizing: border-box; box-sizing: border-box;
} }
#video { #video {
background: red; background: #F00;
} }
</style> p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
}
p.section-head {
font-variant: small-caps;
text-transform: uppercase;
letter-spacing: .17em;
line-height: 1.2em;
font-weight: 500;
margin-top: 2em;
margin-bottom: 1em;
border-left: 1px solid #EF6C00;
padding-left: 24px;
color: #818181;
}
</style>
</head> </head>
<body> <body>
<video id="video"> <section class="title-area">
</video> <h1>Paddle.js: Using a pretrained tinyYolo with WebRTC</h1>
<p> </section>
<button id="start">开始识别</button>
<button id="stop">结束</button>
</p>
<select id="videoSelect"></select>
<p id="tips">tips</p>
<div id="myDiv"></div>
<script src="./videoDemo.es6"></script> <section>
<p class="section-head">Description</p>
<p>Please start the face trace.</p>
</section>
<video id="video">
</video>
<p>
<button type="button" id="start">开始识别</button>
<button type="button" id="stop">结束</button>
</p>
<select id="videoSelect"></select>
<p id="tips">tips</p>
<div id="myDiv"></div>
<script src="./videoDemo.es6"></script>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -4,14 +4,19 @@ ...@@ -4,14 +4,19 @@
"description": "paddle", "description": "paddle",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"server": "parcel ./src/index.html",
"mnistdemo": "parcel ./examples/mnist/index.html", "mnistdemo": "parcel ./examples/mnist/index.html",
"mobilenet": "parcel ./examples/mobileNet/index.html", "mobilenet": "parcel ./examples/mobileNet/index.html",
"tinyYolo": "parcel ./examples/tinyYolo/index.html", "tinyYolo": "parcel ./examples/tinyYolo/index.html",
"huangfan": "parcel ./examples/huangfan/index.html", "huangfan": "parcel ./examples/huangfan/index.html",
"terrorModel": "parcel ./examples/terrorModel/index.html",
"humanseg": "parcel ./examples/humanseg/index.html",
"humanStream": "parcel ./examples/humanStream/index.html --port 1234 --https",
"yolo": "parcel ./examples/yolo/index.html", "yolo": "parcel ./examples/yolo/index.html",
"videoDemo": "parcel ./examples/videoDemo.html --port 8123 --https", "videoDemo": "parcel ./examples/videoDemo.html --port 8123 --https",
"unitTest": "parcel ./test/unitTest.html", "unitTest": "parcel ./test/unitTest.html",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -w"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.7.2", "@babel/core": "^7.7.2",
...@@ -27,6 +32,7 @@ ...@@ -27,6 +32,7 @@
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1", "babel-preset-stage-0": "^6.24.1",
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"less": "^3.11.1",
"parcel-bundler": "^1.10.3", "parcel-bundler": "^1.10.3",
"webpack-cli": "^3.3.6" "webpack-cli": "^3.3.6"
}, },
...@@ -34,7 +40,12 @@ ...@@ -34,7 +40,12 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"js-file-download": "^0.4.5", "@babel/plugin-transform-runtime": "^7.6.2",
"vconsole": "^3.3.2" "@babel/runtime": "^7.7.2",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"js-file-download": "^0.4.10",
"vconsole": "^3.3.2",
"webpack": "^4.39.2",
"webpack-zepto": "0.0.1"
} }
} }
...@@ -26,6 +26,7 @@ export default class Camera { ...@@ -26,6 +26,7 @@ export default class Camera {
} }
// 访问用户媒体设备的兼容方法 // 访问用户媒体设备的兼容方法
// safari在getusermedia之后 才能拿到deviceid
run(deviceId, callback) { run(deviceId, callback) {
if (window.stream) { if (window.stream) {
window.stream.getTracks().forEach(function (track) { window.stream.getTracks().forEach(function (track) {
...@@ -41,7 +42,12 @@ export default class Camera { ...@@ -41,7 +42,12 @@ export default class Camera {
}; };
const error = this.error.bind(this); const error = this.error.bind(this);
if (this.deviceInfos.length) { if (this.deviceInfos.length) {
constraints.video.deviceId= {exact: deviceId || this.deviceInfos[0]}; constraints.video.deviceId = {exact: deviceId || this.deviceInfos[0].deviceId};
}
if (!constraints.video.deviceId) {
constraints = {
video: true
};
} }
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
......
...@@ -38,6 +38,9 @@ export default class GraphExecutor { ...@@ -38,6 +38,9 @@ export default class GraphExecutor {
else if (this.type === 'elementwise_add') { else if (this.type === 'elementwise_add') {
return this.inputs.X.concat(this.inputs.Y); return this.inputs.X.concat(this.inputs.Y);
} }
else if (this.type === 'concat') {
return this.inputs.X.concat(this.inputs.Y);
}
else if (this.type === 'relu' || this.type === 'leaky_relu') { else if (this.type === 'relu' || this.type === 'leaky_relu') {
return this.inputs.X; return this.inputs.X;
} }
...@@ -60,7 +63,13 @@ export default class GraphExecutor { ...@@ -60,7 +63,13 @@ export default class GraphExecutor {
} }
get outputsName() { get outputsName() {
if (this.type === 'conv2d') { if (this.outputs.Output) {
return this.outputs.Output;
}
else if (this.outputs.out) {
return this.outputs.out;
}
else if (this.type === 'conv2d') {
return this.outputs.Output; return this.outputs.Output;
} }
else if (this.type === 'depthwise_conv2d') { else if (this.type === 'depthwise_conv2d') {
......
...@@ -39,12 +39,15 @@ import softmax_conf from '../../shader/softmax/conf'; ...@@ -39,12 +39,15 @@ import softmax_conf from '../../shader/softmax/conf';
import batchnorm_params from '../../shader/batchnorm/params'; import batchnorm_params from '../../shader/batchnorm/params';
import batchnorm_func from '../../shader/batchnorm/main'; import batchnorm_func from '../../shader/batchnorm/main';
import batchnorm_conf from '../../shader/batchnorm/conf'; import batchnorm_conf from '../../shader/batchnorm/conf';
import reshape_params from '../../shader/reshape/params'; import reshape2_params from '../../shader/reshape2/params';
import reshape_func from '../../shader/reshape/main'; import reshape2_func from '../../shader/reshape2/main';
import reshape_conf from '../../shader/reshape/conf'; import reshape2_conf from '../../shader/reshape2/conf';
import transpose_params from '../../shader/transpose/params'; import bilinear_interp_params from '../../shader/bilinear_interp/params';
import transpose_func from '../../shader/transpose/main'; import bilinear_interp_func from '../../shader/bilinear_interp/main';
import transpose_conf from '../../shader/transpose/conf'; import bilinear_interp_conf from '../../shader/bilinear_interp/conf';
import transpose2_params from '../../shader/transpose2/params';
import transpose2_func from '../../shader/transpose2/main';
import transpose2_conf from '../../shader/transpose2/conf';
import conv2d_elementwise_add_params from '../../shader/conv2d_elementwise_add/params'; import conv2d_elementwise_add_params from '../../shader/conv2d_elementwise_add/params';
import conv2d_elementwise_add_func from '../../shader/conv2d_elementwise_add/main'; import conv2d_elementwise_add_func from '../../shader/conv2d_elementwise_add/main';
...@@ -183,15 +186,20 @@ export default { ...@@ -183,15 +186,20 @@ export default {
func: batchnorm_func, func: batchnorm_func,
confs: batchnorm_conf confs: batchnorm_conf
}, },
reshape: { reshape2: {
params: reshape_params, params: reshape2_params,
func: reshape_func, func: reshape2_func,
confs: reshape_conf confs: reshape2_conf
}, },
transpose: { bilinear_interp: {
params: transpose_params, params: bilinear_interp_params,
func: transpose_func, func: bilinear_interp_func,
confs: transpose_conf confs: bilinear_interp_conf
},
transpose2: {
params: transpose2_params,
func: transpose2_func,
confs: transpose2_conf
} }
}, },
atoms: { atoms: {
......
...@@ -108,6 +108,7 @@ export default class imageFeed { ...@@ -108,6 +108,7 @@ export default class imageFeed {
result[offset] = data[a] / 255; result[offset] = data[a] / 255;
result[offset] -= mean[k]; result[offset] -= mean[k];
result[offset] /= std[k]; result[offset] /= std[k];
//result[offset] = 0.5;
offset++; offset++;
} }
} }
...@@ -116,6 +117,46 @@ export default class imageFeed { ...@@ -116,6 +117,46 @@ export default class imageFeed {
return result; return result;
}; };
/**
* 全部转bgr * H * W
* @param shape
*/
allReshapeToBGR(imageData, opt, scaleSize) {
//const {sw, sh} = scaleSize;
const [b, c, h, w] = opt.targetShape;
let data = imageData.data || imageData;
// mean和std是介于0-1之间的
let mean = opt.mean;
let std = opt.std;
let dataLength = data.length;
// let result = new Float32Array(dataLength * 3);
let result = this.result;
// let offsetR = 0;
// let offsetG = dataLength / 4;
// let offsetB = dataLength / 2;
let offset = 0;
let size = h * w;
// h w c
for (let i = 0; i < h; ++i) {
let iw = i * w;
for (let j = 0; j < w; ++j) {
let iwj = iw + j;
for (let k = 0; k < c; ++k) {
let a = iwj * 4 + (2-k);
result[offset] = data[a];
result[offset] -= mean[2-k];
result[offset] /= std[2-k];
//result[offset] = 0.5;
offset++;
}
}
}
console.log('this is the end of reshapetorgb !!!');
console.dir(result);
return result;
};
/** /**
* 根据scale缩放图像 * 根据scale缩放图像
* @param image * @param image
...@@ -138,6 +179,8 @@ export default class imageFeed { ...@@ -138,6 +179,8 @@ export default class imageFeed {
sh = params.scale; sh = params.scale;
sw = Math.round(sh * width / height); sw = Math.round(sh * width / height);
} }
sw = params.scale;
sh = params.scale;
this.fromPixels2DContext.canvas.width = sw; this.fromPixels2DContext.canvas.width = sw;
this.fromPixels2DContext.canvas.height = sh; this.fromPixels2DContext.canvas.height = sh;
this.fromPixels2DContext.drawImage( this.fromPixels2DContext.drawImage(
...@@ -285,15 +328,16 @@ export default class imageFeed { ...@@ -285,15 +328,16 @@ export default class imageFeed {
data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight); data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight);
} }
else if (opt.scale) { // 兼容以前的,如果有scale就是短边缩放到scale模式 else if (opt.scale) { // 兼容以前的,如果有scale就是短边缩放到scale模式
scaleSize = this.reSize(pixels, opt); scaleSize = this.reSize(pixels, opt);
console.dir(scaleSize); console.dir(scaleSize);
console.dir(pixels); console.dir(pixels);
data = this.getImageData(opt, 0, 0, scaleSize); data = this.getImageData(opt, 0, 0, scaleSize);
data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight); data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight);
} }
else if (opt.targetSize) { // 如果有targetSize,就是装在目标宽高里的模式 TinyYolo的情况 else if (opt.targetSize) { // 如果有targetSize,就是装在目标宽高里的模式 TinyYolo的情况
scaleSize = this.fitToTargetSize(pixels, opt); scaleSize = this.fitToTargetSize(pixels, opt);
data = this.getImageData(opt, 0, 0, scaleSize); data = this.getImageData(opt, 0, 0, scaleSize);
data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight); data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight);
...@@ -309,7 +353,10 @@ export default class imageFeed { ...@@ -309,7 +353,10 @@ export default class imageFeed {
data = this.reshape(data, opt, scaleSize); data = this.reshape(data, opt, scaleSize);
} }
if (opt.targetShape) { if (opt.bgr) {
data = this.allReshapeToBGR(data, opt, scaleSize);
}
else if (opt.targetShape) {
data = this.allReshapeToRGB(data, opt, scaleSize); data = this.allReshapeToRGB(data, opt, scaleSize);
} }
return [{data: data, shape: opt.shape || opt.targetShape, name: 'image', canvas: data2}]; return [{data: data, shape: opt.shape || opt.targetShape, name: 'image', canvas: data2}];
......
...@@ -14,6 +14,7 @@ import Utils from '../utils/utils'; ...@@ -14,6 +14,7 @@ import Utils from '../utils/utils';
const factory = new Factory({}); const factory = new Factory({});
// 获取op的输入配置 // 获取op的输入配置
const opConfs = factory.getOpConfs(); const opConfs = factory.getOpConfs();
let opindex = 0;
export default class Graph { export default class Graph {
constructor(options) { constructor(options) {
...@@ -27,12 +28,19 @@ export default class Graph { ...@@ -27,12 +28,19 @@ export default class Graph {
this.feedOp = null; this.feedOp = null;
this.feedItem = null; this.feedItem = null;
this.test = false; this.test = false;
this.formatLayout = 'NCHW';
this.isExecuted = false; this.isExecuted = false;
// 网络层数 // 网络层数
this.iLayer = 0; this.iLayer = 0;
if (this.options && this.options.options && this.options.options.test === true) { if (this.options && this.options.options ) {
this.test = true; if (this.options.options.test === true) {
this.test = true;
}
if (this.options.options.formatLayout) {
this.formatLayout = this.options.options.formatLayout;
}
} }
if (!this.inst) { if (!this.inst) {
...@@ -83,6 +91,9 @@ export default class Graph { ...@@ -83,6 +91,9 @@ export default class Graph {
if (executor.type === 'fetch') { if (executor.type === 'fetch') {
return; return;
} }
opindex++;
// console.log(opindex);
//if (executor.opData) console.log(executor.opData.iLayer);
executor.execute(this.inst, this.isExecuted); executor.execute(this.inst, this.isExecuted);
if (executor.next) { if (executor.next) {
const id = executor.next; const id = executor.next;
...@@ -187,6 +198,106 @@ export default class Graph { ...@@ -187,6 +198,106 @@ export default class Graph {
return item; return item;
}); });
} }
execute_try(temp, ops, idtoindex, executed, inline, prev){
console.log('execute_try!first look at this op');
console.log(ops[temp]);
let canrun = this.checkifcanrun(temp, ops, idtoindex, executed);
if (canrun === false) {
// console.log('canrun === false!');
var a = inline.pop();
this.execute_try(idtoindex[a.id], ops, idtoindex, executed, inline, prev);
return;
}
if (prev >=0) {
ops[prev].next = ops[temp].id;
}
ops[temp].outputsName.forEach(function(item, index) {
executed[item] = true;
})
let next = this.getNextByOp(ops, ops[temp]);
// console.log('this is its next:');
// console.dir(next);
while (next.length === 1) {
let flag = true;
for (let i = 0; i < next[0].inputsName.length; i++){
if (executed[next[0].inputsName[i]] === false) flag = false;
}
if (flag === false) {
// console.log('can not execute next now! jump to another op:');
if (inline.length === 0) return;
prev = temp;
let a = inline.pop();
// console.dir(a);
ops[temp].next = a.id;
temp = idtoindex[a.id];
this.execute_try(temp, ops, idtoindex, executed, inline, prev);
return;
}
else {
// console.log('now execute next op! it is');
ops[temp].next = next[0].id;
temp = idtoindex[next[0].id];
// console.dir(ops[temp]);
next = this.getNextByOp(ops, ops[temp]);
// console.log('its next is: ');
ops[temp].outputsName.forEach(function(item, index) {
executed[item] = true;
})
// console.dir(next);
}
}
if (next.length > 1){
// console.log('next.length > 1!!!');
for (let i = next.length - 1; i >=0 ; i--){
inline.push(next[i]);
}
var a = inline.pop();
this.execute_try(idtoindex[a.id], ops, idtoindex, executed, inline, temp);
}
return;
}
arrangeMap(ops) {
// console.log('arrangeMap!');
// console.dir(ops);
var idtoindex = {};
var executed = {};
var inline = [];
let temp = 0;
// console.log('graph ops:');
// console.dir(ops);
let ops1 = ops;
ops1.forEach(function(item, index) {
idtoindex[item.id] = index;
// console.dir(item);
item.outputsName.forEach(function(i, idx){
executed[i] = false;
})
});
//ops[0].inputsName[0] = {name : "feed"};
// ops[0].outputsName[0] = {name : "image"};
this.execute_try(temp, ops, idtoindex, executed, inline, -1);
return ops;
}
checkifcanrun(temp, ops, executed){
if (!ops[temp].inputsName) return true;
for (let i = 0; i < ops[temp].inputsName.length; i++){
if (executed[ops[temp].inputsName[i]] === false) return false;
}
return true;
}
/** /**
* Get Ops Nets Start Node * Get Ops Nets Start Node
* @param ops * @param ops
...@@ -222,12 +333,23 @@ export default class Graph { ...@@ -222,12 +333,23 @@ export default class Graph {
return item; return item;
}); });
} }
formatWeight(vars) {
if (this.formatLayout === 'NHWC') {
vars.map((item) => {
if (item.data && item.shape) {
item.data = Utils.nhwc2nchw(item.data, item.shape);
}
});
}
};
/** /**
* Create Ops Executor Object Map * Create Ops Executor Object Map
* @param ops * @param ops
* @returns {*} * @returns {*}
*/ */
createOpsMap(ops) { createOpsMap(ops) {
// console.log('ops!!');
// console.dir(ops);
return ops.map((item, idx) => { return ops.map((item, idx) => {
item.idx = idx; item.idx = idx;
const graphExecutor = new GraphExecutor(item); const graphExecutor = new GraphExecutor(item);
...@@ -250,6 +372,17 @@ export default class Graph { ...@@ -250,6 +372,17 @@ export default class Graph {
}); });
} }
getNextByOp(ops, op) {
return ops.filter((item, key) => {
for (let i = 0; i < item.inputsName.length; i++) {
for(let j = 0; j < op.outputsName.length; j++) {
if (item.inputsName[i] === op.outputsName[j]) {
return true;
}
}
}
});
}
/** /**
* dispose * dispose
*/ */
......
module.exports.create = function (args, scope, gl) {
const output = scope[args.outputs.Out[0]]
return {
inferShape() {
output.dim = output.dim.forEach(d => d === -1 ? 1 : d)
},
compute() {
console.log(output)
}
}
}
\ No newline at end of file
module.exports.create = function (args, scope, gl) {
const output = scope[args.outputs.Out[0]]
const input = scope[args.inputs.X[0]]
return {
inferShape() {
output.dim = output.dim.map(d => d === -1 ? 1 : d)
},
compute() {
console.log(input)
console.log(output)
}
}
}
module.exports.create = function (args, scope, gl) {
// const output = scope[args.outputs.Out[0]]
return {
inferShape() {
// output.dim = output.dim.forEach(d => d === -1 ? 1 : d)
},
compute() {
console.log(`${args.type} is going to be implemented`)
}
}
}
\ No newline at end of file
...@@ -47,8 +47,15 @@ export default class Paddle { ...@@ -47,8 +47,15 @@ export default class Paddle {
const graph = new Graph(that.options); const graph = new Graph(that.options);
that.graph = graph; that.graph = graph;
that.graph.data = artifacts.data; that.graph.data = artifacts.data;
that.graph.formatWeight(that.graph.data.vars);
const opsMap = that.graph.createOpsMap(that.graph.data.ops, that.graph.data.vars); const opsMap = that.graph.createOpsMap(that.graph.data.ops, that.graph.data.vars);
that.graph.weightMap = that.graph.constructOpsMap(opsMap); const opsMap1 = that.graph.constructOpsMap(opsMap);
// console.log('opsMap1!');
// console.dir(opsMap1);
const opsMap2 = that.graph.arrangeMap(opsMap1);
// console.log('opsMap2!');
// console.dir(opsMap2);
that.graph.weightMap = opsMap2;
} }
/** /**
* Executes inference for the model for given input tensors. * Executes inference for the model for given input tensors.
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
import Gpu from '../gpu/gpu'; import Gpu from '../gpu/gpu';
import getMaxUniforms from '../test/getMaxUniforms'; import getMaxUniforms from '../test/getMaxUniforms';
import Factory from '../factory/fshader/factory'; import Factory from '../factory/fshader/factory';
import {getTextureShapeInfo} from '../utils/opData'; // import {getTextureShapeInfo} from '../utils/opData';
// 生成factory实例 // 生成factory实例
const factory = new Factory({}); // const factory = new Factory({});
/** /**
* @file gpu运行时 * @file gpu运行时
* @author wangqun@baidu.com, yangmingming@baidu.com * @author wangqun@baidu.com, yangmingming@baidu.com
...@@ -48,7 +48,7 @@ export default { ...@@ -48,7 +48,7 @@ export default {
gpu.attachFrameBuffer(opData.iLayer, outTensorId); gpu.attachFrameBuffer(opData.iLayer, outTensorId);
// let end = +Date.now(); // let end = +Date.now();
let bufferStatus = gpu.frameBufferIsComplete(); let bufferStatus = gpu.frameBufferIsComplete();
if (bufferStatus.isComplete) { // if (bufferStatus.isComplete) {
// start = +Date.now(); // start = +Date.now();
// timeObj['buferstatus-time'] = start - end; // timeObj['buferstatus-time'] = start - end;
// gpu.attachShader(opData.fshader); // gpu.attachShader(opData.fshader);
...@@ -62,7 +62,7 @@ export default { ...@@ -62,7 +62,7 @@ export default {
// 开始计算,执行 gl.drawArrays // 开始计算,执行 gl.drawArrays
this.gpu.render(opData.renderData, opData.iLayer, isRendered); this.gpu.render(opData.renderData, opData.iLayer, isRendered);
} // }
}); });
}, },
...@@ -86,6 +86,7 @@ export default { ...@@ -86,6 +86,7 @@ export default {
// 其实这里应该有个fetch的执行调用或者fetch的输出 // 其实这里应该有个fetch的执行调用或者fetch的输出
// log.start('后处理-读取数据'); // log.start('后处理-读取数据');
// 开始读数据 // 开始读数据
// window.log.end('执行时间');
return this.gpu.downloadFoat32TensorFromBuffer(pbo); return this.gpu.downloadFoat32TensorFromBuffer(pbo);
}, },
......
...@@ -8,15 +8,15 @@ export default ` ...@@ -8,15 +8,15 @@ export default `
void main(void) { void main(void) {
ivec4 oPos = getOutputTensorPos(); ivec4 oPos = getOutputTensorPos();
// 输出坐标转换为输入坐标 // 输出坐标转换为输入坐标
int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out; // int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out;
ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out); // ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out);
float o = 0.0; float o = 0.0;
if (new_oPos[dim] > inputs_dim[0] - 1) { if (oPos[dim] > inputs_dim[0] - 1) {
new_oPos[dim] = new_oPos[dim] - inputs_dim[0]; oPos[dim] = oPos[dim] - inputs_dim[0];
o = getValueFromTensorPos_counter(new_oPos.r, new_oPos.g, new_oPos.b, new_oPos.a); o = getValueFromTensorPos_counter(oPos.r, oPos.g, oPos.b, oPos.a);
} }
else { else {
o = getValueFromTensorPos_origin(new_oPos.r, new_oPos.g, new_oPos.b, new_oPos.a); o = getValueFromTensorPos_origin(oPos.r, oPos.g, oPos.b, oPos.a);
} }
setOutput(float(o)); setOutput(float(o));
} }
......
...@@ -7,8 +7,8 @@ export default ` ...@@ -7,8 +7,8 @@ export default `
// start函数 // start函数
void main(void) { void main(void) {
ivec4 oPos = getOutputTensorPosLIMIT_OUT(); ivec4 oPos = getOutputTensorPosLIMIT_OUT();
int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out; //int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out;
ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out); //ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out);
int x = oPos.a; int x = oPos.a;
int c = oPos.g; int c = oPos.g;
int y = oPos.b; int y = oPos.b;
......
...@@ -12,7 +12,12 @@ export default ` ...@@ -12,7 +12,12 @@ export default `
int y = oPos.b; int y = oPos.b;
int b = oPos.r; int b = oPos.r;
float res = 0.0; float res = 0.0;
int temp_x = 0;
int temp_y = 0;
float o = 0.0;
float f = 0.0;
if (x % 2 == 1) x = x - 2;
if (y % 2 == 1) y = y - 2;
// 重排遍历顺序 // 重排遍历顺序
//int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out; //int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out;
//int new_a = sumVal % width_shape_out; //int new_a = sumVal % width_shape_out;
...@@ -22,41 +27,37 @@ export default ` ...@@ -22,41 +27,37 @@ export default `
//int c = new_g; //int c = new_g;
//int y = new_b; //int y = new_b;
// 获取output的坐标 // 获取output的坐标
int oTensorChannel = (c / (channel_out / groups)) * channel_filter; int oTensorChannel = int(c * groups / channel_out) * channel_origin;
int oy = y;
int oy = y * 1 - padTop;
for (int fy = 0; fy < height_shape_filter; fy++) { for (int fy = 0; fy < height_shape_filter; fy++) {
if (oy >= height_shape_origin) {
break;
}
if (oy < 0) { if (oy < 0) {
oy += dilation_v; oy += dilation_v;
continue; continue;
} }
int ox = x * 1 - padLeft; int ox = x;
for (int fx = 0; fx < width_shape_filter; fx++) { for (int fx = 0; fx < width_shape_filter; fx++) {
if (ox >= width_shape_origin) {
break;
}
if (ox < 0) { if (ox < 0) {
ox += dilation_h; ox += dilation_h;
continue; continue;
} }
// channel计算 // channel计算
for (int j = 0; j < channel_filter; j++) { for (int j = 0; j < channel_origin; j++) {
float o = 0.0;
if (ox % stride_h == 0 && oy % stride_v == 0) { if (ox % stride_h == 0 && oy % stride_v == 0) {
int temp_x = int(ox / stride_h); temp_x = int(floor(float(ox) / float(stride_h)));
int temp_y = int(oy / stride_v); temp_y = int(floor(float(oy) / float(stride_v)));
o = getValueFromTensorPosLIMIT_ORIGIN_origin(b, oTensorChannel + j, temp_y, temp_x); if (temp_x < width_shape_origin && temp_y < height_shape_origin){
o = getValueFromTensorPosLIMIT_ORIGIN_origin(b, j, temp_y, temp_x);
f = getValueFromTensorPosLIMIT_FILTER_filter(j, c, fy, fx);
res += f * o;
}
} }
float f = getValueFromTensorPosLIMIT_FILTER_filter(c, j, fy, fx);
res += f * o;
} }
ox += dilation_h; ox += dilation_h;
} }
oy += dilation_v; oy += dilation_v;
} }
setOutput(res); setOutput(float(res));
} }
`; `;
...@@ -28,11 +28,13 @@ export default ` ...@@ -28,11 +28,13 @@ export default `
const int stride_h = int(STRIDES_X); const int stride_h = int(STRIDES_X);
const int stride_v = int(STRIDES_Y); const int stride_v = int(STRIDES_Y);
// padding的数目 // padding的数目
const int padLeft = width_shape_filter - PADDINGS_X - 1; //const int padLeft = width_shape_filter - PADDINGS_X - 1;
const int padTop = height_shape_filter - PADDINGS_Y - 1; //const int padTop = height_shape_filter - PADDINGS_Y - 1;
const int padLeft = PADDINGS_X;
const int padTop = PADDINGS_Y;
// dilation膨胀系数 // dilation膨胀系数
const int dilation_h = DILATION_H; const int dilation_h = DILATIONS_X;
const int dilation_v = DILATION_V; const int dilation_v = DILATIONS_Y;
// groups // groups
const int groups = GROUPS; const int groups = GROUPS;
......
...@@ -8,22 +8,23 @@ export default ` ...@@ -8,22 +8,23 @@ export default `
void main(void) { void main(void) {
// 输出数据 // 输出数据
ivec4 oPos = getOutputTensorPos(); ivec4 oPos = getOutputTensorPos();
int sumVal = oPos.g + oPos.a * channel_origin + oPos.b * channel_origin * width_shape_origin + oPos.r * channel_origin * width_shape_origin * height_shape_origin;
float o = getValueFromTensorPos_origin(oPos.r, oPos.g, oPos.b, oPos.a); float o = getValueFromTensorPos_origin(oPos.r, oPos.g, oPos.b, oPos.a);
ivec4 pos_counter; ivec4 pos_counter;
pos_counter.r = channel_out; float c = 0.0;
pos_counter.g = height_shape_origin;
pos_counter.b = width_shape_origin; if (axis == 1){
pos_counter.a = 1; c = getValueFromTensorPos_counter(0, oPos.r, oPos.g, oPos.b);
int index = 0; }
for (int i = 4 - length_shape_origin + axis; i < 4 - length_shape_origin + axis + length_shape_counter; i++ ){ else if (axis == 2){
if (index > 0) { c = getValueFromTensorPos_counter(0, 0, oPos.r, oPos.g);
index = index * pos_counter[i]; }
} else if (axis == 3){
index += oPos[i]; c = getValueFromTensorPos_counter(0, 0, 0, oPos.r);
} }
float c = getValueFromTensorPos_counter(oPos.r, oPos.g, oPos.b, oPos.a); else {
c = getValueFromTensorPos_counter(oPos.r, oPos.g, oPos.b, oPos.a);
}
float res = c + o; float res = c + o;
setOutput(res); setOutput(float(res));
} }
`; `;
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
export default ` export default `
// start函数 // start函数
void main(void) { void main(void) {
float res = (-1.0 / exp(-20.0)); float res = 0.0;
// 获取output的坐标 // 获取output的坐标
ivec4 out_pos = getOutputTensorPosLIMIT_OUT(); ivec4 out_pos = getOutputTensorPosLIMIT_OUT();
int b = out_pos[0]; int b = out_pos[0];
......
/* eslint-disable */
/**
* @file batchnorm的配置文件
* @author chenhaoze
*/
export default {
dep: [
{
func: 'getValueFromTensorPos',
conf: {
TENSOR_NAME: 'origin'
}
},
{
func: 'transferFromNHWCtoNCHW',
conf:{
}
}
],
conf: [
'WIDTH_SHAPE_ORIGIN',
'HEIGHT_SHAPE_ORIGIN',
'LENGTH_SHAPE_ORIGIN',
'WIDTH_TEXTURE_ORIGIN',
'HEIGHT_TEXTURE_ORIGIN',
'CHANNEL_ORIGIN',
'WIDTH_SHAPE_OUT',
'HEIGHT_SHAPE_OUT',
'WIDTH_TEXTURE_OUT',
'HEIGHT_TEXTURE_OUT',
'CHANNEL_OUT',
'OFFSET_Y_OUT',
'MULTI_VALUE',
'BIAS_VALUE',
'ACTIVE_FUNCTION'
],
input: [
{
tensor: 'origin',
variable: 'texture',
setter: 'initTexture',
type: 'texture'
}
]
};
/* eslint-disable */
/**
* @file reshape主函数
* @author chenhaoze
*/
export default `
// start函数
void main(void) {
// 输出数据
ivec4 oPos = getOutputTensorPos();
// 输出坐标转换为输入坐标
int sumVal = oPos.a + oPos.b * width_shape_out + oPos.g * height_shape_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out;
ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_origin, width_shape_origin, height_shape_origin, total_shape_origin);
float o = getValueFromTensorPos_origin(new_oPos.r, new_oPos.g, new_oPos.b, new_oPos.a);
setOutput(float(o));
}
`;
/* eslint-disable */
/**
* @file batchnorm参数文件
* @author chenhaoze
*/
export default `
// 输入数据
const int width_shape_origin = WIDTH_SHAPE_ORIGIN;
const int height_shape_origin = HEIGHT_SHAPE_ORIGIN;
const int length_shape_origin = LENGTH_SHAPE_ORIGIN;
const int width_texture_origin = WIDTH_TEXTURE_ORIGIN;
const int height_texture_origin = HEIGHT_TEXTURE_ORIGIN;
const int channel_origin = CHANNEL_ORIGIN;
const int total_shape_origin = TOTAL_SHAPE_ORIGIN;
// 输入数据
uniform sampler2D texture_origin;
`;
...@@ -9,10 +9,10 @@ void main(void) { ...@@ -9,10 +9,10 @@ void main(void) {
int length = int(target_value.length() / num); int length = int(target_value.length() / num);
ivec4 oPos = getOutputTensorPos(); ivec4 oPos = getOutputTensorPos();
// 输出坐标转换为输入坐标 // 输出坐标转换为输入坐标
int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out; //int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out;
ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out); //ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_out);
new_oPos[dim] = new_oPos[dim] + layer_run_time * length; oPos[dim] = oPos[dim] + layer_run_time * length;
float o = getValueFromTensorPos_origin(new_oPos.r, new_oPos.g, new_oPos.b, new_oPos.a); float o = getValueFromTensorPos_origin(oPos.r, oPos.g, oPos.b, oPos.a);
setOutput(float(o)); setOutput(float(o));
} }
`; `;
/* eslint-disable */
/**
* @file batchnorm的配置文件
* @author chenhaoze
*/
export default {
dep: [
{
func: 'getValueFromTensorPos',
conf: {
TENSOR_NAME: 'origin'
}
},
{
func: 'transferFromNHWCtoNCHW',
conf:{
}
}
],
conf: [
'WIDTH_SHAPE_ORIGIN',
'HEIGHT_SHAPE_ORIGIN',
'LENGTH_SHAPE_ORIGIN',
'WIDTH_TEXTURE_ORIGIN',
'HEIGHT_TEXTURE_ORIGIN',
'CHANNEL_ORIGIN',
'WIDTH_SHAPE_OUT',
'HEIGHT_SHAPE_OUT',
'WIDTH_TEXTURE_OUT',
'HEIGHT_TEXTURE_OUT',
'CHANNEL_OUT',
'OFFSET_Y_OUT',
'MULTI_VALUE',
'BIAS_VALUE',
'ACTIVE_FUNCTION'
],
input: [
{
tensor: 'origin',
variable: 'texture',
setter: 'initTexture',
type: 'texture'
}
]
};
/* eslint-disable */
/**
* @file transpose主函数
* @author chenhaoze
*/
export default `
// start函数
void main(void) {
// 输出数据
ivec4 oPos = getOutputTensorPos();
// 重排遍历顺序
//int sumVal = oPos.g + oPos.a * channel_out + oPos.b * channel_out * width_shape_out + oPos.r * channel_out * width_shape_out * height_shape_out;
//ivec4 new_oPos = transferFromNHWCtoNCHW(sumVal, channel_out, width_shape_out, height_shape_out, total_shape_origin);
// 转置 坐标变换
//oPos = new_oPos;
float o = 0.0;
if (perm_size == 1) {
o = getValueFromTensorPos_origin(oPos[0], oPos[1], oPos[2], oPos[3]);
}
else if (perm_size == 2) {
o = getValueFromTensorPos_origin(oPos[0], oPos[1], oPos[min(2 + perm_0, 3)], oPos[min(2 + perm_1, 3)]);
}
else if (perm_size == 3) {
o = getValueFromTensorPos_origin(oPos[0], oPos[min(1 + perm_0, 3)], oPos[min(1 + perm_1, 3)], oPos[min(1 + perm_2, 3)]);
}
else if (perm_size == 4) {
o = getValueFromTensorPos_origin(oPos[perm_0], oPos[perm_1], oPos[perm_2], oPos[perm_3]);
}
setOutput(float(o));
}
`;
/* eslint-disable */
/**
* @file batchnorm参数文件
* @author chenhaoze
*/
export default `
// 输入数据
const int width_shape_origin = WIDTH_SHAPE_ORIGIN;
const int height_shape_origin = HEIGHT_SHAPE_ORIGIN;
const int length_shape_origin = LENGTH_SHAPE_ORIGIN;
const int width_texture_origin = WIDTH_TEXTURE_ORIGIN;
const int height_texture_origin = HEIGHT_TEXTURE_ORIGIN;
const int channel_origin = CHANNEL_ORIGIN;
const int total_shape_origin = TOTAL_SHAPE_ORIGIN;
const int perm_size = PERM_SIZE;
const int perm_0 = PERM_0;
const int perm_1 = PERM_1;
const int perm_2 = PERM_2;
const int perm_3 = PERM_3;
// 输入数据
uniform sampler2D texture_origin;
`;
...@@ -65,8 +65,8 @@ const opBehavior = { ...@@ -65,8 +65,8 @@ const opBehavior = {
'mergeTensor' 'mergeTensor'
], ],
elementwise_add: [ elementwise_add: [
'needBatch', 'processAxis',
'processAxis' 'needBatch'
], ],
conv2d_elementwise_add: [ conv2d_elementwise_add: [
'mergeAttrs', 'mergeAttrs',
...@@ -95,11 +95,14 @@ const opBehavior = { ...@@ -95,11 +95,14 @@ const opBehavior = {
'reshape', 'reshape',
'needBatch' 'needBatch'
], ],
reshape: [ bilinear_interp:[
'needBatch'
],
reshape2: [
'needBatch', 'needBatch',
'inferShape' 'inferShape'
], ],
transpose: [ transpose2: [
'needBatch', 'needBatch',
'setPerm' 'setPerm'
], ],
...@@ -122,6 +125,7 @@ const mergeType = 'conv2d-elementwise_add'; ...@@ -122,6 +125,7 @@ const mergeType = 'conv2d-elementwise_add';
export default class OpData { export default class OpData {
constructor(name, input = {}, output = {}, attrs = {}) { constructor(name, input = {}, output = {}, attrs = {}) {
// console.dir(this);
this.realName = name; this.realName = name;
this.name = name; this.name = name;
this.attrs = attrs; this.attrs = attrs;
...@@ -150,7 +154,7 @@ export default class OpData { ...@@ -150,7 +154,7 @@ export default class OpData {
} }
inferShape(){ inferShape(){
if (this.name == 'reshape'){ if (this.name == 'reshape2'){
let inputShape = this.input.X[0].shape; let inputShape = this.input.X[0].shape;
let targetShape = this.attrs.new_shape; let targetShape = this.attrs.new_shape;
for (let i = 0; i < targetShape.length; i++){ for (let i = 0; i < targetShape.length; i++){
...@@ -201,6 +205,7 @@ export default class OpData { ...@@ -201,6 +205,7 @@ export default class OpData {
// 默认取第一个数据 // 默认取第一个数据
const data = this.output[key] || [{}]; const data = this.output[key] || [{}];
if (tensorName[key.toLowerCase()]) { if (tensorName[key.toLowerCase()]) {
// console.dir(this);
data.forEach(item => { data.forEach(item => {
item.tensorName = tensorName[key.toLowerCase()]; item.tensorName = tensorName[key.toLowerCase()];
tensorData.push(item); tensorData.push(item);
...@@ -276,6 +281,7 @@ export default class OpData { ...@@ -276,6 +281,7 @@ export default class OpData {
this.outputTensors.forEach(outTensor => { this.outputTensors.forEach(outTensor => {
const params = JSON.parse(JSON.stringify(this.data)); const params = JSON.parse(JSON.stringify(this.data));
// 获取output tensor的数据 // 获取output tensor的数据
tensorAttrs.forEach(attr => { tensorAttrs.forEach(attr => {
params[attr+ '_' + outTensor.name] = outTensor[attr]; params[attr+ '_' + outTensor.name] = outTensor[attr];
}); });
...@@ -289,7 +295,7 @@ export default class OpData { ...@@ -289,7 +295,7 @@ export default class OpData {
} }
setPerm(tensorData = []){ setPerm(tensorData = []){
let arrayPerm = this.attrs['perm']; let arrayPerm = this.attrs['axis'];
let l = arrayPerm.length; let l = arrayPerm.length;
if (l == 3) { if (l == 3) {
if (arrayPerm == [2,0,1]) { if (arrayPerm == [2,0,1]) {
...@@ -430,7 +436,15 @@ export default class OpData { ...@@ -430,7 +436,15 @@ export default class OpData {
} }
normalizeDim() { normalizeDim() {
const origin_shape = this.input.X[0].shape; let origin_shape_temp = this.input.X[0].shape;
if (origin_shape_temp.length < 4) {
let batch = [];
for (let i = 0; i < (4 - origin_shape_temp.length); i++) {
batch.push(1);
}
origin_shape_temp = batch.concat(origin_shape_temp);
}
const origin_shape = origin_shape_temp;
const axis = this.attrs.axis > -1 ? this.attrs.axis : origin_shape.length + this.attrs.axis; const axis = this.attrs.axis > -1 ? this.attrs.axis : origin_shape.length + this.attrs.axis;
const dim_value = []; const dim_value = [];
for (let index = 0; index < origin_shape[axis]; index++) { for (let index = 0; index < origin_shape[axis]; index++) {
...@@ -445,19 +459,14 @@ export default class OpData { ...@@ -445,19 +459,14 @@ export default class OpData {
processAxis() { processAxis() {
let shape_x = this.input.X[0].shape; let shape_x = this.input.X[0].shape;
let shape_y = this.input.Y[0].shape; let shape_y = this.input.Y[0].shape;
let y_length = shape_y.length; let axis_temp = this.attrs['axis'];
for (let i = shape_y.length - 1; i >=0 ;i--){ if (axis_temp == -1) {
if (shape_y[i] == 1) { this.attrs['axis'] = shape_x.length - shape_y.length;
y_length -= 1; }
} else {
} this.attrs['axis'] = 4 - shape_y.length - axis_temp;
let axis_temp = this.attrs['axis']; }
if (axis_temp == -1) {
this.attrs['axis'] = shape_x.length - y_length;
}
this.attrs['shape_length_origin'] = shape_x.length;
this.attrs['shape_length_counter'] = y_length;
} }
reshape(tensorData = []) { reshape(tensorData = []) {
......
...@@ -57,13 +57,6 @@ export default class Tensor { ...@@ -57,13 +57,6 @@ export default class Tensor {
} }
this.data = data; this.data = data;
} }
else {
if (opts.data.length > this.total) {
opts.data = opts.data.slice(0, this.total);
}
this.data = new Float32Array(opts.data);
debugger;
}
} else { } else {
// batchnorm的scale // batchnorm的scale
......
...@@ -283,6 +283,29 @@ export default { ...@@ -283,6 +283,29 @@ export default {
numbers.push(i + ": " + data[i]); numbers.push(i + ": " + data[i]);
} }
console.log(numbers) console.log(numbers)
},
softmax(nchwData) {
let result = new Float32Array(nchwData.length);
let maxValue = nchwData[0];
let tempValue = 0.0;
let sumValue = 0.0;
for (let i = 1; i < nchwData.lenght; i++) {
tempValue = nchwData[i];
if (maxValue < tempValue) {
maxValue = tempValue;
}
}
for (let i = 0; i < nchwData.length; i++) {
tempValue = Math.exp(nchwData[i] - maxValue);
result[i] = tempValue;
sumValue = sumValue + tempValue;
}
for (let i = 0; i < nchwData.length; i++) {
result[i] = result[i] / sumValue;
}
return result;
} }
}; };
/* eslint-enable */ /* eslint-enable */
此差异已折叠。
此差异已折叠。
{
"ops": [
{
"attrs": {
"axis": -1
},
"inputs": {
"X": ["concat.tmp_0"],
"Y": ["concat.tmp_1"]
},
"outputs": {
"Out": ["concat.tmp_2"]
},
"type": "concat"
}
],
"vars": [
{
"data": [1, 2, 3, 4, 5, 6, 7, 8],
"name": "concat.tmp_0",
"shape": [2, 2, 2]
},
{
"data": [11, 12, 13, 14],
"name": "concat.tmp_1",
"shape": [2, 2, 1]
},
{
"data": [1, 2, 11, 3, 4, 12, 5, 6, 13, 7, 8, 14],
"name": "concat.tmp_2",
"shape": [2, 2, 3]
}
]
}
{
"ops": [
{
"attrs": {
"Scale_in": 1.0,
"Scale_in_eltwise": 1.0,
"Scale_out": 1.0,
"Scale_weights": [
1.0
],
"data_format": "AnyLayout",
"dilations": [
1,
1
],
"exhaustive_search": false,
"force_fp32_output": false,
"fuse_relu": false,
"fuse_relu_before_depthwise_conv": false,
"fuse_residual_connection": false,
"groups": 2,
"is_test": 1,
"paddings": [
0,
0
],
"strides": [
1,
1
],
"use_cudnn": true,
"use_mkldnn": false,
"workspace_size_MB": 4096
},
"inputs": {
"Filter": [
"conv2d_0.w_0"
],
"Input": [
"pixel"
]
},
"outputs": {
"Output": [
"conv2d_0.tmp_0"
]
},
"type": "conv2d"
}
],
"vars": [
{
"data": [
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 2, 0, 2, 0, 2, 0, 2, 0,
0, 2, 0, 2, 0, 2, 0, 2, 0,
0, 2, 0, 2, 0, 2, 0, 2, 0,
0, 2, 0, 2, 0, 2, 0, 2, 0
],
"name": "pixel",
"persistable": 0,
"shape": [
1,
8,
3,
3
]
},
{
"data": [
0, 1, 0, 1,
0, 1, 0, 1,
0, 1, 0, 1,
0, 1, 0, 1,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2,
0, 2, 0, 2
],
"name": "conv2d_0.w_0",
"persistable": 1,
"shape": [
4,
4,
2,
2
]
},
{
"data": [
],
"name": "conv2d_1.b_0",
"persistable": 1,
"shape": [
50
]
},
{
"data": [
4, 4, 4, 4,
8, 8, 8, 8,
16, 16, 16, 16,
16, 16, 16, 16
],
"name": "conv2d_0.tmp_0",
"persistable": 0,
"shape": [
1,
4,
2,
2
]
},
]
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
{
"ops": [
{
"attrs": {
"bias": 0.0,
"bias_after_scale": true,
"scale": 1.0
},
"inputs": {
"X": [
"fc_0.tmp_2"
]
},
"outputs": {
"Out": [
"scale_0.tmp_0"
]
},
"type": "scale"
}
],
"vars": [
{
"data": [
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.0,
1.6504194778766687e-16
],
"name": "fc_0.tmp_2",
"persistable": 0,
"shape": [
10
]
},
{
"data": [
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.0,
1.6504194778766687e-16
],
"name": "scale_0.tmp_0",
"persistable": 0,
"shape": [
10
]
}
]
}
{
"ops": [
{
"attrs": {
"bias": 0.0,
"bias_after_scale": true,
"scale": 1.0
},
"inputs": {
"X": [
"fc_0.tmp_2"
]
},
"outputs": {
"Out": [
"scale_0.tmp_0"
]
},
"type": "scale"
}
],
"vars": [
{
"data": [
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.0,
1.6504194778766687e-16
],
"name": "fc_0.tmp_2",
"persistable": 0,
"shape": [
10
]
},
{
"data": [
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.6038109389511792e-28,
1.0,
1.6504194778766687e-16
],
"name": "scale_0.tmp_0",
"persistable": 0,
"shape": [
10
]
}
]
}
{
"ops": [
{
"attrs": {
"axis": 2,
"num": 2,
"sections": []
},
"inputs": {
"X": ["reshape2_3.tmp_0"]
},
"outputs": {
"Out": ["split_1.tmp_0", "split_1.tmp_1"]
},
"type": "split"
}
],
"vars": [
{
"data": [
1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24
],
"name": "reshape2_3.tmp_0",
"shape": [2, 2, 2, 3]
},
{
"data": [1, 2, 3, 7, 8, 9, 13, 14, 15, 16, 17, 18],
"name": "split_1.tmp_0",
"shape": [2, 2, 1, 3]
},
{
"data": [4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24],
"name": "split_1.tmp_1",
"shape": [2, 2, 1, 3]
}
]
}
import 'babel-polyfill'; import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle'; import Paddle from '../../src/paddle/paddle';
import Utils from '../../src/utils/utils';
const unitPath = { const unitPath = {
'conv2d': 'model.test.conv2d.json', 'conv2d': 'model.test.conv2d.json',
...@@ -9,16 +10,24 @@ const unitPath = { ...@@ -9,16 +10,24 @@ const unitPath = {
'relu': 'model.test.relu.json', 'relu': 'model.test.relu.json',
'scale': 'model.test.scale.json', 'scale': 'model.test.scale.json',
'softmax': 'model.test.softmax.json', 'softmax': 'model.test.softmax.json',
'relu6' : 'model.test.relu6.json' 'relu6' : 'model.test.relu6.json',
'elementwise' : 'model.test.elementwise_add.json',
'depthwise' : 'model.test.depthwise_conv2d.json',
'reshape' : 'model.test.reshape.json',
'bilinear_interp' : 'model.test.bilinear_interp.json',
'transpose' : 'model.test.transpose.json',
'conv2d_transpose': 'model.test.conv2d_transpose.json',
'elementwise_add': 'model.test.elementwise_add.json',
'concat': 'model.test.concat.json',
'split': 'model.test.split.json'
}; };
// 制定运行的 op // 制定运行的 op
const modelType = 'softmax'; const modelType = 'split';
// 制定运行的 op
const unitData = unitPath[modelType]; const unitData = unitPath[modelType];
let Diff = require('./diff');
let datas; let datas;
let otherResult; let output;
let output
async function run() { async function run() {
const path = 'test/unitData'; const path = 'test/unitData';
const MODEL_CONFIG = { const MODEL_CONFIG = {
...@@ -35,8 +44,9 @@ async function run() { ...@@ -35,8 +44,9 @@ async function run() {
let model = await paddle.load(); let model = await paddle.load();
datas = model.graph.data; datas = model.graph.data;
output = deepCopy(datas); output = deepCopy(datas);
// 测试单元
model.graph.weightMap.forEach(op => { model.graph.weightMap.forEach(op => {
const type = op.type; const type = op.type;
if (type !== 'feed' && type !== 'fetch') { if (type !== 'feed' && type !== 'fetch') {
...@@ -45,18 +55,22 @@ async function run() { ...@@ -45,18 +55,22 @@ async function run() {
} }
}); });
const executor = model.graph.weightMap; const executor = model.graph.weightMap;
let inst = model.graph.execute_(executor[0]); model.graph.execute_(executor[0]);
let result = model.graph.inst.read(); // NHWC输出
console.dir(['result', result]); let result = await model.graph.inst.read();
var one = model.graph.inst.read();
// var other = getResult('conv2d');
console.log('one'); // 获取 NHWC -> NCHW 的 输出
console.log(one); const outputNCHWShape = getOutputShape();
console.log('other'); const outputNHWCShape = nchwShape2nhwcShape(outputNCHWShape);
} let nchwResult = Utils.nhwc2nchw(result, outputNHWCShape);
console.log('result');
console.log(result);
console.log('NCHW RESULT');
console.log(nchwResult);
}
run(); run();
...@@ -64,90 +78,44 @@ function deepCopy (data) { ...@@ -64,90 +78,44 @@ function deepCopy (data) {
return JSON.parse(JSON.stringify(data)); return JSON.parse(JSON.stringify(data));
} }
// let output = deepCopy(datas);
let getTensor = function(id, times = 1) {
let find = 0;
let data = datas.ops.filter((item, idx) => {
if (id === item.type) {
++find;
if (find === times) {
return true;
}
}
});
return getInputs(data[0]);
};
let getInputs = function(data) {
Object.keys(data.inputs).forEach(function(key){
data.inputs[key] = getValue(data.inputs[key][0], datas);
});
Object.keys(data.outputs).forEach(function(key){
let out = getValue(data.outputs[key][0], datas)
data.outputs[key] = out;
otherResult = out[0].data;
});
return data;
};
let getResult = function(id) {
let data = output.ops.filter((item, idx) => {
if (id === item.type) {
return true; const getResult = function (id) {
} const data = output.ops.filter(item => id === item.type);
});
return getoutputs(data[0]); return getoutputs(data[0]);
}; };
let getoutputs = function(data) {
let otherResult;
Object.keys(data.outputs).forEach(function(key){
let out = getValue(data.outputs[key][0], output);
otherResult = out[0].data;
});
return otherResult;
};
let getValue = function(name, datas) { const getValue = function(name, datas) {
return datas.vars.filter((item, idx) => { return datas.vars.find(item => name === item.name);
if (name === item.name) {
return item;
}
});
}; };
// // 测试单元
// let item = getTensor('conv2d');
let func = function (model) {
// console.log(other);
// var one = inst.read();
// var other = getResult('softmax');
// var color ='';
// var span = null;
// var diff = Diff.diffChars(one.toString(), other.toString()),
// display = document.getElementById('display'),
// fragment = document.createDocumentFragment();
//
// diff.forEach(function(part){
// // green for additions, red for deletions
// // grey for common parts
// color = part.added ? 'green' :
// part.removed ? 'red' : 'grey';
// span = document.createElement('span');
// span.style.color = color;
// span.appendChild(document
// .createTextNode(part.value));
// fragment.appendChild(span);
// });
//
// display.appendChild(fragment);
const OUTPUT_KEYS = ['out', 'y', 'output'];
const getoutputs = function (data) {
const outputkey = Object.keys(data.outputs).find(key => OUTPUT_KEYS.includes(key.toLowerCase()));
const outputTensorId = data.outputs[outputkey].slice(-1)[0];
const outputTensor = getValue(outputTensorId, output);
return outputTensor;
}; };
function getOutputShape () {
var outputTensor = getResult(modelType);
return outputTensor.shape;
}
// NCHW shape 2 NHWC shape
function nchwShape2nhwcShape(nchw) {
let batchNCHW = nchw;
if (nchw.length < 4) {
let batch = [];
for (let i = 0; i < (4 - nchw.length); i++) {
batch.push(1);
}
batchNCHW = batch.concat(nchw);
}
const N = batchNCHW[0];
const C = batchNCHW[1];
const H = batchNCHW[2];
const W = batchNCHW[3];
return [N, H, W, C];
}
/**
* file tools/logger logger工具
* author saniac(snailsword@gmail.com)
*/
export default class Logger {
constructor() {
this.timeTable = {};
this.countTable = {};
this.duringTable = {};
this.lastStopTable = {};
}
start(key) {
let arr = this.timeTable[key];
if (!arr) {
arr = [{}];
}
else {
if (!arr[arr.length - 1].endTime) {
console.error('[logger] key:' + key + ' duplicate start logger');
return;
}
arr.push({});
}
arr[arr.length - 1].startTime = this.time;
this.timeTable[key] = arr;
return this;
}
end(key) {
// console.log(this.timeTable[key]);
if (!this.timeTable[key]) {
console.log(this.timeTable[key]);
console.error('[logger] key:' + key + ' no matching start logger');
return;
}
let currentObj = this.timeTable[key][this.timeTable[key].length - 1];
if (currentObj.endTime) {
console.error('[logger] key:' + key + ' duplicate end logger');
return;
}
currentObj.endTime = this.time;
currentObj.during = currentObj.endTime - currentObj.startTime;
return this;
}
// 数次数
count(key) {
if (this.countTable[key]) {
this.countTable[key]++;
}
else {
this.countTable[key] = 1;
}
return this;
}
// 看每次执行的时间间隔
during(key) {
if (this.lastStopTable[key]) {
this.duringTable[key].push(this.time - this.lastStopTable[key]);
this.lastStopTable[key] = this.time;
}
else {
this.lastStopTable[key] = this.time;
this.duringTable[key] = [];
}
return this;
}
get time() {
return +new Date().getTime();
}
get statistics() {
// time
let timeResult = [];
let item;
for (let key in this.timeTable) {
item = this.timeTable[key];
let len = item.length;
let max = 0;
let min = Number.MAX_VALUE;
let sum = 0;
for (let i = 0; i < len; i++) {
max = Math.max(max, item[i].during);
min = Math.min(min, item[i].during);
sum += item[i].during;
}
timeResult.push({
name: key,
length: len,
avg: sum / len,
max,
min
});
}
console.table(timeResult);
return {timeResult};
}
}
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import paddle.fluid as fluid
import paddle
import numpy as np
import collections
import math
import sys as sys
import os
import struct
#常量控制
#抽样打印数据数量
logDataCount = 50
# 输入模型所在目录
modelDir = "humanseg/"
# 输入模型名
modelName = "model"
# 输入参数名,当且仅当所有模型参数被保存在一个单独的二进制文件中,它才需要被指定,若为分片模型,请设置为None
paramsName = None
# 模型feed shape
inputShape = (1, 3, 192, 192)
# 输入数据
inputData = np.full(inputShape, 1, "float32")
# 输出模型目录
outputDir = "../dist/model/humanseg/"
# 权重分片扩展名
extensionName = ".dat"
# 输出各var数据
outputVarData = False
# 确认fluid的版本号
print(paddle.__version__)
# 采样输出list数据,采样的个数logDataCount为常量
def stridePrint1(data):
dataCount = len(data)
stride = math.floor(dataCount / logDataCount)
if stride == 0:
stride = 1
nums = []
# outputCount = logDataCount
# if dataCount < logDataCount:
# outputCount = dataCount
# for i in range(outputCount):
# # nums.append(str(i) + ": " + str(data[i]))
# nums.append(data[i])
for i in range(0, logDataCount):
item = data[i * stride]
nums.append(str(i * stride) + ": " + str(item))
print(nums)
def stridePrint(tensor):
length = len(tensor)
# if length < 3000:
# print(tensor)
# return
size = 20
stride = math.floor(length / size)
if stride == 0:
stride = 1
size = math.floor(length / stride)
nums = []
for i in range(0, size):
item = tensor[i * stride]
nums.append(str(i * stride) + ": " + str(item))
print(nums)
# 对字典进行排序,返回有序字典,默认升序
def sortDict(oldDict, reverse = False):
# 获得排序后的key list
keys = sorted(oldDict.keys(), reverse = reverse)
orderDict = collections.OrderedDict()
# 遍历 key 列表
for key in keys:
orderDict[key] = oldDict[key]
return orderDict
# 将权重数据分片输出到文件,默认分片策略为按4M分片
def sliceDataToBinaryFile(weightValueList, sliceMethod = 0):
# TODO: 分片这里不太对,待修改
totalWeightCount = len(weightValueList)
countPerSlice = 0
# sliceCount = 0
if sliceMethod == 0:
# 分片策略 0:按4M分片
countPerSlice = int(4 * 1024 * 1024 / 4)
# sliceCount = math.ceil(totalWeightCount / countPerSlice)
else:
# 分片策略 1:按<=4M等分
# TODO: 待实现
countPerSlice = 0
# sliceCount = 0
if not os.path.exists(outputDir):
os.makedirs(outputDir)
currentChunkIndex = 0
currentWeightIndex = 0
while currentWeightIndex < totalWeightCount - 1:
remainCount = totalWeightCount - currentWeightIndex
if remainCount < countPerSlice:
countPerSlice = remainCount
chunkPath = outputDir + 'chunk_%s' % (currentChunkIndex + 1) + extensionName
file = open(chunkPath, 'wb')
for i in weightValueList[currentWeightIndex : currentWeightIndex + countPerSlice]:
byte = struct.pack('f', float(i))
file.write(byte)
file.close()
currentWeightIndex = currentWeightIndex + countPerSlice
currentChunkIndex = currentChunkIndex + 1
# for debug
print("第" + str(currentChunkIndex + 1) + "片权重输出完毕,输出个数:" + str(countPerSlice) + " 剩余个数:" + str(totalWeightCount - currentWeightIndex))
# for debug
print("========权重输出完毕,共" + str(currentWeightIndex) + "个数据," + str(currentChunkIndex) + "个分片文件" + "========")
# 处理fluid的OP type与PaddleJS的OP type不对应情况
def mapToPaddleJSTypeName(fluidOPName):
if fluidOPName == "batch_norm":
return "batchnorm"
return fluidOPName
# 将shape扩充为4维
def padToFourDimShape(shape):
fourDimShape = []
if len(shape) == 4:
fourDimShape = shape
elif len(shape) < 4:
for i in range(0, 4 - len(shape)):
fourDimShape.append(1)
fourDimShape = fourDimShape + shape
else:
return []
return fourDimShape
# for debug,将NCHW排布的数据转为NHWC排布的数据
def convertNCHW2NHWC(data, shape):
fourDimShape = padToFourDimShape(shape)
N = fourDimShape[0]
C = fourDimShape[1]
H = fourDimShape[2]
W = fourDimShape[3]
print(fourDimShape)
HXW = H * W
CXHXW = C * H * W
index = 0
nhwcData = []
for n in range(0, N):
for h in range(0, H):
for w in range(0, W):
for c in range(0, C):
nhwcData.append(data[n * CXHXW + c * HXW + h * W + w])
index = index + 1
return nhwcData
# for debug 输出特定varName对应的数据
def writeTempOutputData(name):
# FIXME:待完善
return
dataList = np.array(fluid.global_scope().find_var(name).get_tensor()).flatten().tolist()
path = '/Users/bluebird/baidu/fluid_tools/check-temp/filter.txt'
if os.path.exists(path):
os.remove()
file = open(path,'a')
for a in range(0, len(dataList)):
file.write(str(dataList[a]))
file.write(",")
file.close()
def convertToPaddleJSModel():
# 1. 初始化fluid运行环境和配置
exe = fluid.Executor(fluid.CPUPlace())
[prog, feed_target_names, fetch_targets] = fluid.io.load_inference_model(dirname=modelDir, executor=exe, model_filename=modelName, params_filename=paramsName)
out = exe.run(prog, feed={feed_target_names[0]: inputData}, fetch_list=fetch_targets, return_numpy=False)
print(out)
index = 0
# 存放模型结构
modelInfo = {"vars": [], "ops": []}
# 存放var信息(未排序)
varInfoDict = {}
# 存放权重数值(未排序)
weightValueDict = {}
# 2. 获取program中所有的var,遍历并获取所有未排序的var信息和权重数值
vars = list(prog.list_vars())
for v in vars:
# 跳过feed和fetch
if "feed" == v.name:
continue
if "fetch" == v.name:
continue
print("Var index:" + str(index) + " name:" + v.name)
print(v)
index += 1
varShape = list(v.shape)
# FIXME:start paddlejs 不支持shape中为-1,这里需要手动过滤一下,支持了以后可以删除
varShapeExcludeNegativeOne = []
for s in varShape:
if s == -1:
continue
varShapeExcludeNegativeOne.append(s)
varShape = varShapeExcludeNegativeOne
# FIXME:end
# 存放variable信息,在dump成json时排序
varInfo = {}
varInfo["shape"] = varShape
# 数据是否是持久化数据,如weight为持久化数据,op的output不是持久化数据
# 只输出持久化数据,paddlejs中也仅读取持久化数据
varInfo["persistable"] = v.persistable
varInfoDict[v.name] = varInfo
# for debug,输出var变量
if outputVarData:
writeTempOutputData(v.name)
# persistable数据存入weightDict,等待排序
if v.persistable:
data = np.array(fluid.global_scope().find_var(v.name).get_tensor()).flatten().tolist()
weightValueDict[v.name] = data
# 3. 对var信息dict,按照key(var名)进行字母顺序排序
varInfoOrderDict = sortDict(varInfoDict)
# 4. 将var信息按照顺序,添加到model info的vars中
for key, value in varInfoOrderDict.items():
value["name"] = key
modelInfo["vars"].append(value)
# 5. 对权重数值dict,按照key(权重名)进行字母顺序排序,并组合到一起
weightValueOrderDict = sortDict(weightValueDict)
weightValues = []
for key, value in weightValueOrderDict.items():
weightValues += value
# 6. 分片输出权重
sliceDataToBinaryFile(weightValues)
# 7. 获取program中所有的op,按op顺序加入到model info
ops = prog.current_block().ops
feedOutputName = None
for op in ops:
opInfo = {}
# 获取OP type,需要映射到PaddleJS的名字
opInfo["type"] = mapToPaddleJSTypeName(op.type)
# 获取OP input
inputs = {}
for name in op.input_names:
value = op.input(name)
if len(value) <= 0:
continue
if value[0] == feedOutputName:
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入
# 这里修改feed后面的OP的input为image,建立前后关联
# 这里可能会有问题
inputs[name] = ["image"]
else:
inputs[name] = value
opInfo["inputs"] = inputs
# 获取OP output
outputs = {}
for name in op.output_names:
value = op.output(name)
if len(value) <= 0:
continue
if op.type == "feed":
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入
# 这里可能会有问题
feedOutputName = value[0]
outputs[name] = ["image"]
else:
outputs[name] = value
opInfo["outputs"] = outputs
# 获取OP attribute
attrs = {}
for name in op.attr_names:
# 过滤不需要的参数
if name in ["op_callstack", 'col', 'op_role', 'op_namescope', 'op_role_var']:
continue
value = op.attr(name)
attrs[name] = value
opInfo["attrs"] = attrs
# 存入modelInfo
modelInfo["ops"].append(opInfo)
# 8. 模型信息按照key字母顺序导出到json
outputModelPath = outputDir + "model.json"
with open(outputModelPath, 'w') as outputFile:
json.dump(modelInfo, outputFile, indent = 4, separators=(", ", ": "), sort_keys = True)
print("========模型结构输出完毕========")
convertToPaddleJSModel()
/**
* @file 打包到rd机器的配置
*/
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractLess = new ExtractTextPlugin({
filename: '[name].css'
});
module.exports = {
// mode: 'development',
mode: 'production',
devtool: 'none',
optimization: {
minimize: true
},
entry: {
index: ['./src/executor/runner']
},
output: {
filename: '../graphfe/dep/paddleweb/index.min.js',
path: path.resolve(__dirname, './'),
library: 'panorama',
libraryTarget: 'umd',
libraryExport: 'default'
},
module: {
rules: [{
test: /\.(es6|js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/transform-runtime']
}
}
}, {
test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
loader: 'url-loader?limit=30000&name=[name].[ext]'
}, {
test: /\.less$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract([
{loader: 'css-loader', options: {minimize: true}},
{loader: 'less-loader'}
])
}]
},
plugins: [extractLess],
resolve: {
extensions: ['.es6', '.js', '.json']
}
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册