merry가 참고하여 구현한 Tensorflow-models 공식 깃헙 바로가기
이하 모든 내용의 근본 출처는 위의 공식 깃헙임을 밝힙니다.
문제 인식
- model loading이 되지 않았음.
- 내가 구현 시도한 hand-ppse-detection 모델은 model loading에 해당하는 것이 createDetector 함수인데, 이하에서 설명할 해결하기 위한 노력을 모두 해보아도 밑 오류로 귀결되었음.
- 이번 글의 문제는 시리즈 2편에서 작성할 peer dependency 까지 모두 이해해야 해결 가능함.
detector-handpose.js:179 Error in animate: Error: Weight StatefulPartitionedCall/model/conv_handedness/MatMul/ReadVariableOp has unknown quantization dtype float16.
Supported quantization dtypes are: 'uint8' and 'uint16'.
1. createDetector() 함수 구조
export async function createDetector(
model: SupportedModels,
modelConfig?: MediaPipeHandsMediaPipeModelConfig | MediaPipeHandsTfjsModelConfig) // createDetector() 함수의 옵션
- hand-pose-detection이 아닌 face-landmarks-detection과 pose-detection도 모델 로딩 함수 구조는 거의 동일함
- createDetector() 함수의 옵션
// MediaPipeHandsTfjsModelConfig
/* `detectorModelUrl`: Optional. An optional string that specifies custom url of
* the detector model. This is useful for area/countries that don't have access
* to the model hosted on tf.hub.
*
* `landmarkModelUrl`: Optional. An optional string that specifies custom url of
* the landmark model. This is useful for area/countries that don't have access
* to the model hosted on tf.hub.
*/
export interface MediaPipeHandsTfjsModelConfig extends MediaPipeHandsModelConfig {
runtime: 'tfjs';
detectorModelUrl?: string;
landmarkModelUrl?: string;
}
// MediaPipeHandsMediaPipeModelConfig
export interface MediaPipeHandsMediaPipeModelConfig extends MediaPipeHandsModelConfig {
runtime: 'mediapipe';
solutionPath?: string;
}
- 이번 프로젝트 특성 상 온라인 환경이 아니어도 (인터넷이 끊어져도) 기능이 정상적으로 작동되어야 했음.
- 따라서 tensorflow-hub (최근 kaggle로 이관되었음) 에서 모델을 다운로드 받았음
- 그래서 위 옵션들 중 detectorModelUrl, landmarkModelUrl 을 실제 모델이 저장된 위치로 올바르게 설정해야 했음.
- 그러나 아무리 설정해도 문제 인식에서 제시한 오류만 출력됨
2. 해결하기 위한 노력
1) 오프라인으로 다운로드 받은 모델 구조 파악
- 전체 모델 구조 = detector + landmark
- 각 detector, landmark 구조 = json + binary 파일
- json
- 모델의 '구조' 해당하는 부분
- 모델의 각 레이어에 대한 정보와 레이어가 어떻게 연결되어 있는지에 대한 정보
→ 이 때 레이어는 CNN의 그 layer임 - 모델의 아키텍처의 모든 정보를 제공 → 이 파일만으로 모델의 구조를 재구성 가능
- model.json의 weightsManifest 에서 바이너리 파일을 자동 참조
→ 따라서 바이너리 파일을 model.json과 동일한 디렉토리에 저장해놓는다면, 수동으로 경로를 지정할 필요 없음 - 더보기
"weightsManifest": [{"paths": ["group1-shard1of1.bin"],
- binary
- 모델의 '가중치' 에 해당하는 부분
- 학습된 파라미터 포함 (ex. 각 레이어의 가중치와 편향 값 등)
- 모델의 학습 결과를 저장하는 데 사용
- 따라서 이 파일이 있어야만 학습된 모델을 이용하여 새로운 데이터 예측을 수행 가능
- json
- 오프라인으로 모델 다운 받은 모습
2) detector, landmark 파일을 각각 Url 옵션에 넣으면 된다고 생각했음
- 그러나 어떠한 String 형식으로 넣어야 하는지 의문
- 해결법
- 힌트 : detectorModelUrl, landmarkModelUrl에 특정 경로를 쓰면, localhost:포트번호/ ~ 이하 경로에서 파일을 찾음
- 따라서 GUI(빌드 시작점)에서 VM에 저장된 tensorflow-models를 찾을 수 있도록 경로를 작성해주어야 함
→ 이 경로는 webpack.config.js 에 저장되어 있음. 만약 아래 구조로 저장되어있지 않다면 내가 직접 설정해야 함 - 이하 예시처럼 설정되어 있다면 해결법 내의 Url 설정한 것처럼 설정하여 VM에 저장된 tensorflow-models 파일들에 접근 가능함
plugins: base.plugins.concat([
new CopyWebpackPlugin({
patterns: [
{
from: 'node_modules/scratch-vm/tensorflow-models',
to: 'static/tensorflow-models'
},
3) model.json과 binary 파일 위치를 url 구조로 바꾸어주는 코드 사용해보기
- 2) 실행했는데 계속 문제 인식에서 언급한 quantization 오류 발생함
- 따라서 이하 제시한 model.json과 binary 파일 위치를 url 구조로 바꾸어주는 코드 사용하기도 했었음
- 물론 정상적으로 모델 로딩하지 못 하여 문제 인식에서 언급한 quantization 오류 또 발생함
_bindPage () {
return new Promise((resolve, reject) => {
this.knn = knnClassifier.create();
tf.ready().then(() => {
// 바이너리 파일을 읽어와 blob -> url중 필요한 값 추출
let blobList = [];
const binaryLength = 4
for (let i = 1; i <= binaryLength; i++) {
const binary = require(`!!url-loader!./mobilenet-model/group1-shard${i}of${binaryLength}.bin`);
const blob = this._b64toBlob(binary.default.slice(binary.default.indexOf('base64,') + 7))
const url = URL.createObjectURL(blob)
const urlArr = url.split("/");
blobList.push(urlArr[urlArr.length - 1]);
}
// json data를 읽어와서 바이너리 파일 url을 이용한 paths 값 수정
const modelJson = require('./mobilenet-model/model.json');
modelJson.weightsManifest[0].paths = blobList;
const blob = new Blob([JSON.stringify(modelJson)]);
mobilenetModule.load({
version: 1,
alpha: 1.00,
modelUrl: URL.createObjectURL(blob)
}).then(module => {
this.mobilenet = module;
resolve();
}).catch(err => {
this.mobilenet = null;
this.knn = null;
console.warn(err)
reject(err);
});
});
});
}
_b64toBlob (b64Data, contentType = '', sliceSize = 512) {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
해결법 (요약)
- 이하 2가지가 모두 충족되어야 정상적으로 모델 로딩 (createDetector()) 할 수 있음
- 모델 버전 설정 : hand-pose-detection은 최신 버전 + tfjs는 peer dependency 충돌나도 실제 실행은 되는 버전으로 버전업
→ 모델 버전 관리 - 2. peer dependency 충돌 글 보러 가기
- 옵션 detectorModelUrl, landmarkModelUrl 설정
- 모델 버전 설정 : hand-pose-detection은 최신 버전 + tfjs는 peer dependency 충돌나도 실제 실행은 되는 버전으로 버전업
_createDetector() {
const model = SupportedModels.MediaPipeHands;
const detector = createDetector(model, {
runtime: "tfjs",
modelType: "lite",
maxHands: 2, // or 2~10.
flipHorizontal: false,
staticImageMode: false,
detectorModelUrl:
"/static/tensorflow-models/tfjs-model_handpose_3d_detector_lite_1/model.json",
landmarkModelUrl:
"/static/tensorflow-models/tfjs-model_handpose_3d_landmark_lite_1/model.json",
});
return detector;
}
'AI > Image' 카테고리의 다른 글
[Tensorflow-models] model loading - 1. 로딩 방법 ①CDN ②npm install ③오프라인 저장 (1) | 2023.11.30 |
---|---|
[Tensorflow-models] 모델의 전형적인 사용 구조 (0) | 2023.11.30 |
[Tensorflow-models] 모델 버전 관리 - 2. peer dependency 충돌 (1) | 2023.11.30 |
[Practice] TensorFlow.js hand-pose-detection 패키지를 이용하여 손가락 keypoints 예측하는 AI 개발 (1) | 2023.10.30 |
[Theory] TensorFlow란? | Human pose Estimation이란? (1) | 2023.10.25 |