개요

Tensorflow-models에 속해 있는 모델들의 전형적인 사용 구조를 설명하려고 함. 미래의 나를 위해... 이하 모든 글과 코드는 근본적으로 Tensorflow-models 공식 깃헙에 출처가 있음.

 


 

1. model loading : createDetector

_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",
  });

  console.log("model loading success!, detector: ", this._detector);
  return detector;
}

 


 

2. detect

  • detector.estimateHands(video or image)
  • estimateFaces 등 다양한 시리즈 있음
detect(imageData) {
  if (!this._detector) {
      this._createDetector().then(detector => {
          this._detector = detector;
          console.log("model loading success!, detector: ", this._detector);
      })
  }

  return new Promise((resolve, reject) => {   
      this._detector.estimateHands(imageData).then(result => {
          this._result = result;
          console.log(`this._result: `, this._result);

          this._result.forEach((res) => {
              console.log(`${res.handedness} hand keypoints:`);
              res.keypoints.forEach((keypoint, i) => {
                  let x = keypoint.x - 320;
                  let y = keypoint.y - 240;
                  console.log(`Keypoint ${i}: [${x}, ${y}]`);
              })
          })
          resolve(this._result);
      }).catch(e => {
          reject(e);
      });
  })
}

 


 

3. draw : draw(canvas) 등 매개 변수는 다양할 수 있음

  • drawKeypoint
  • drawPath
draw(canvas) {
    if (!canvas || !this.isExistContent(this._result)) return canvas;
    const ctx = canvas.getContext("2d");
    if (this._result) {
        this._result.forEach( (res) => {
            ctx.fillStyle = res.handedness === "Left" ? "Red" : "Blue";
            ctx.strokeStyle = "White";
            ctx.lineWidth = 2;
            res.keypoints.forEach(keypoint => {
                this._drawKeypoint(ctx, keypoint);
            });
            Object.keys(FINGER_INDICES).forEach(finger => {
                const points = FINGER_INDICES[finger].map(idx => res.keypoints[idx]);
                this._drawPath(ctx, points, false);
            });
        });
    }
    return canvas;
}

_drawKeypoint(ctx, keypoint) {
    ctx.beginPath();
    ctx.arc(keypoint.x - 2, keypoint.y - 2, 3, 0, 2 * Math.PI);
    ctx.fill();
}

_drawPath(ctx, points, closePath) {
    const region = new Path2D();
    region.moveTo(points[0].x, points[0].y);
    points.slice(1).forEach(point => region.lineTo(point.x, point.y));
    if (closePath) {
        region.closePath();
    }
    ctx.stroke(region);
}

 

 

이하 글은 Tensorflow-models 모델 로딩을 위해 공부하고 문제를 해결한 글입니다.

모델 버전 관리 - 1. model-loading 글 보러 가기 

2023.11.30 - [AI/TensorFlow | Tensorflow.js] - [Tensorflow-models] 모델 버전 관리 - 1. model loading

 


 

문제 인식

  • npm install 
    • npm install @tensorflow/tfjs npm install @tensorflow/tfjs-converter npm install @tensorflow/tfjs-core npm install @tensorflow-models/hand-pose-detection 등을 실행하여 npm 모듈을 설치할 때, peer dependency 충돌이 있으면 다음과 같은 오류가 발생함.
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: @tensorflow-models/mobilenet@2.0.4
npm ERR! Found: @tensorflow/tfjs-converter@4.10.0
npm ERR! node_modules/@tensorflow/tfjs-converter
npm ERR!   peer @tensorflow/tfjs-converter@"^4.9.0" from @tensorflow-models/hand-pose-detection@2.0.1
npm ERR!   node_modules/@tensorflow-models/hand-pose-detection
npm ERR!     @tensorflow-models/hand-pose-detection@"^2.0.1" from the root project
npm ERR!   @tensorflow/tfjs-converter@"4.10.0" from @tensorflow/tfjs@4.10.0
npm ERR!   node_modules/@tensorflow/tfjs
npm ERR!     @tensorflow/tfjs@"^4.10.0" from the root project
npm ERR!   2 more (the root project, @tensorflow-models/face-detection)
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @tensorflow/tfjs-converter@"~1.2.1" from @tensorflow-models/mobilenet@2.0.4
npm ERR! node_modules/@tensorflow-models/mobilenet
npm ERR!   @tensorflow-models/mobilenet@"2.0.4" from the root project
npm ERR!
npm ERR! Conflicting peer dependency: @tensorflow/tfjs-converter@1.2.11
npm ERR! node_modules/@tensorflow/tfjs-converter
npm ERR!   peer @tensorflow/tfjs-converter@"~1.2.1" from @tensorflow-models/mobilenet@2.0.4
npm ERR!   node_modules/@tensorflow-models/mobilenet
npm ERR!     @tensorflow-models/mobilenet@"2.0.4" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

 

  • npm 모듈 사용(실행)
    • 특정 모델을 로딩하여 예측 시도할 때 (코드 실행할 때), peer dependency 충돌이 있으면 다음과 같은 오류가 발생하기도 함
    • 그러나 오류 양상이 다양하므로 밑 종류 하나 만으로 한정할 수 없음
    • 따라서 ‘~찾을 수 없음’, ‘resolve 하다가 ~없어서 문제 발생함’ 등의 뉘앙스의 오류는 peer dependency로 인한 오류가 아닐까? 의심해야 함
client:159 ./node_modules/scratch-vm/node_modules/@tensorflow/tfjs-converter/dist/tf-converter.esm.js
Module build failed: Error: ENOENT: no such file or directory, open 'C:\Workspace\Rogic\scratch-gui\node_modules\scratch-vm\node_modules@tensorflow\tfjs-converter\dist\tf-converter.esm.js'

 

  • 주의할 점은 npm install 할 때를 제외하고, peer dependency로 인한 오류임에도 콘솔에서 직접적으로 알려주지 않는다는 것
    • 따라서 두번째 느낌으로 발생한 오류는 궁극적으로 peer dependency로 발생하는 오류일 수 있음을 인지해야 함
    • 여타 오류 해결 방법을 사용하기 전, 후에 peer dependency로 인한 오류가 아닐까? 의심해야 함

 


 

충돌 원인 : 실제 설치된 패키지 버전 ≠ peer dependency에서 요구하는 패키지 버전

  • peer dependency 의미
    • 친구 패키지 명 + 버전
    • 친구 패키지 : 해당 패키지를 정상적으로 활용하기 위해 필요한 다른 패키지
    • 즉 실제로 패키지에서 직접 require(import) 하지는 않더라도 호환성이 필요한 경우 명시하는 것
    • npm 3 버전까지는 peer dependency를 자동으로 설치해줌, 4 - 6 버전에서는 경고 메시지만 띄워줌, 7 버전부터는 peer dependency 버전이 맞지 않으면 설치 불가
      → 나의 npm - -version : 9.6.4 , 그렇다면 실제 설치된 버전 ≠ peer dependency 요구 버전이라면 해당 패키지 아예 설치 및 실행 불가? NO!
      → 해결법은 맨 마지막에!

 

  • peer dependency 확인
    • package-lock.json
"node_modules/@tensorflow-models/hand-pose-detection": {
    "version": "2.0.1",
    "resolved": "https://registry.npmjs.org/@tensorflow-models/hand-pose-detection/-/hand-pose-detection-2.0.1.tgz",
    "integrity": "sha512-zRA+jz2qOq5FMcyqSFxaQyi6T4YNbMbQhd6SQMI791FQ8yYj23kLgYa73g2NssR5AmM/2ATu9Vcjnf7LUrVLOQ==",
    "dependencies": {
        "rimraf": "^3.0.2",
        "tslib": "^2.6.1"
    },
    "peerDependencies": {
        "@mediapipe/hands": "~0.4.0",
        "@tensorflow/tfjs-backend-webgl": "^4.9.0",
        "@tensorflow/tfjs-converter": "^4.9.0",
        "@tensorflow/tfjs-core": "^4.9.0"
    }
  },
  • dependency vs dev dependency
    1. dependency
      • 앱에 종속된 가장 일반적인 종속성
      • 런타임빌드타임개발중 일 때 모두 필요
      • 따라서 앱이 빌드될 때 여기에 속해 있는 패키지들이 모두 번들에 포함되어 배포
    2. dev dependency
      • 빌드타임개발중 일 때 필요
      • 따라서 앱이 빌드될 때 도움 주거나 참조 되지만, 번들에 포함X

 


 

해결법 (요약)

  • npm 7 버전부터는 peer dependency 버전이 맞지 않으면 설치 불가
    • 그러나 무조건 peer dependency에서 얘기하는 딱! 그! 버전만 설치해야 패키지 실행할 수 있다는 것은 말이 안 됨 (사용자마다 프로젝트, pc 상황이 다를 수 있기 때문)
    • 해결 방법은 npm 공식 깃헙 블로그 기준 2가지가 있음 : --force 또는 --legacy-peer-deps
    • 더보기
      You have the option to retry with --force to bypass the conflict or --legacy-peer-deps command to ignore peer dependencies entirely (this behavior is similar to versions 4-6). - in npm github blog
  • 2가지 방법 요약
    --force --legacy-peer-deps
    충돌 우회 충돌 무시
    package-lock.json에 몇 가지의 다른 의존 버전들을 추가 peerDependency가 맞지 않아도 일단 설치
    • 이번 프로젝트에서는 주로 --legacy-peer-deps 를 활용하여 peer dependency 충돌 해결 (사수 제안)
    • 그러나 일반적인 경우 --force--legacy-peer-deps 로 적용해보는 것이 좋을 것 같음
      ( ∵ --force--legacy-peer-deps 보다 덜 강제적)

 


 

이번 프로젝트 (Tensorflow-models 구현) 에서 주의할 점

  • peer dependency를 설치한 경우, 해당 패키지가 실제 실행 가능한지 빌드 + 실행해서 확인 필수
    • 실행해보아야 하는 것 : ①모델 로딩(create detector) ②예측(estimateHands)
  • 해당 프로젝트의 경우 다음과 같은 버전 특징을 갖고 있었음
      hand-pose-detection face-landmarks-detection pose-detection
    peer dependency 권장 버전 "peerDependencies":
    { "@mediapipe/hands": "~0.4.0", "@tensorflow/tfjs-backend-webgl": "^4.9.0", "@tensorflow/tfjs-converter": "^4.9.0", "@tensorflow/tfjs-core": "^4.9.0" }
    "peerDependencies":
    { "@mediapipe/face_detection": "~0.4.0", "@tensorflow/tfjs-backend-webgl": "^4.4.0", "@tensorflow/tfjs-converter": "^4.4.0", "@tensorflow/tfjs-core": "^4.4.0" }
    "peerDependencies":
    { "@mediapipe/pose": "~0.5.0", "@tensorflow/tfjs-backend-wasm": "^4.10.0", "@tensorflow/tfjs-backend-webgl": "^4.10.0", "@tensorflow/tfjs-backend-webgpu": "^4.10.0", "@tensorflow/tfjs-converter": "^4.10.0", "@tensorflow/tfjs-core": "^4.10.0" }
    실제 실행 가능한 최소 버전 ( hand-pose-detection, face-landmarks-detection, pose-detection 최신 버전 기준) - tfjs, tfjs-core, tfjs-converter : ^3.3.0 - tfjs, tfjs-core, tfjs-converter : ^3.3.0 - tfjs, tfjs-core, tfjs-converter : ^4.4.0
    • 위처럼 ①모델마다 실제 실행 가능한 최소 버전 및 권장 peer dependency 버전이 상이하고 ②향후 프로젝트 확장 가능성 고려하여 , 사수님 제안으로 tfjs, tfjs-core, tfjs-converter 모델 모두 4.10.0 으로 설치함
    • tfjs, tfjs-core, tfjs-converter 모델은 2점대 이후로 버전이 한 몸으로 움직임. 따라서 버전업 할 때도 한 번에 했음
    • 위 3개 모델을 제외한 나머지 모델 ( ex. @tensorflow/tfjs-backend-webgl @tensorflow/tfjs-backend-wasm @tensorflow/tfjs-backend-webgpu) 은 위 3개 모델을 설치하면 자동 실행되므로 별도 설치 필요 없음
      ( 사실 @tensorflow/tfjs-converter 도 4점대 이후에는 포함되어있지만 그 전에는 포함되어 있지 않으므로, 보수적으로 별도 설치함)

 

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 파일
    1. json
      • 모델의 '구조' 해당하는 부분
      • 모델의 각 레이어에 대한 정보와 레이어가 어떻게 연결되어 있는지에 대한 정보
        →  이 때 레이어는 CNN의 그 layer임
      • 모델의 아키텍처의 모든 정보를 제공 → 이 파일만으로 모델의 구조를 재구성 가능
      • model.json의 weightsManifest 에서 바이너리 파일을 자동 참조
        → 따라서 바이너리 파일을 model.json과 동일한 디렉토리에 저장해놓는다면, 수동으로 경로를 지정할 필요 없음
      •  
      • 더보기
        "weightsManifest": [{"paths": ["group1-shard1of1.bin"],
    2. binary
      • 모델의 '가중치' 에 해당하는 부분 
      • 학습된 파라미터 포함 (ex. 각 레이어의 가중치와 편향 값 등)
      • 모델의 학습 결과를 저장하는 데 사용
      • 따라서 이 파일이 있어야만 학습된 모델을 이용하여 새로운 데이터 예측을 수행 가능
  • 오프라인으로 모델 다운 받은 모습

01

 


 

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()) 할 수 있음 
    1. 모델 버전 설정 : hand-pose-detection은 최신 버전 + tfjs는 peer dependency 충돌나도 실제 실행은 되는 버전으로 버전업
      모델 버전 관리 - 2. peer dependency 충돌 글 보러 가기 
           
    2. 옵션 detectorModelUrl, landmarkModelUrl 설정
_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 개발 : TensorFlow.js*의 hand-pose-detection 패키지를 이용하여 손가락 keypoints 예측
 * 보다 정확히 말하면 TensorFlow.js 의 tfjs-models 레포의 hand-pose-detection 패키지이다. 

사실 프로젝트 설명을 들었을 때 드는 감정은 '막막하다'였다. 차장님께서는 웹캠으로 손(가락)을 인식할 때마다 그 손가락의 좌표를 예측했으면 좋겠다고 하셨는데, 웹캠은 어떻게 연결되는건지, 손가락 좌표의 기준점은 어떻게 되어서 어떤 방식으로 계산되는건지, 그걸 전부 Node.js 서버로 어떻게 돌린다는 것인지 이해가 되지 않았다. (물론 내가 아직 handpose와 hand-pose-detection 패키지가 어떠한 방식으로 작동하는지 이해하지 못 한 탓도 있지만...) 이하부터는 내 삽질의 기록이다...

TensorFlow 란? -> https://merrykang.tistory.com/7
handpose vs hand-pose-detection 패키지 비교 -> https://merrykang.tistory.com/7

 


 

Npm을 이용하여 필요한 패키지 설치

 

실행 코드 및 고민의 흔적 
// 패키지 설치
// 아래와 같은 패키지에 대해 install, uninstall을 최소 100번 반복했음 
npm install @tensorflow-models/handpose (--legacy-peer-deps)
npm install @tensorflow/tfjs-core
npm install @tensorflow/tfjs-converter
npm install @tensorflow/tfjs
npm install @tensorflow/tfjs-node
npm install @tensorflow/tfjs-node-gpu

// Node.js 환경에서 파일 실행
// 해당 파일에는 require(node-gpu) 등의 코드가 적혀있어야함
node 파일경로/파일명.js

 

한계
  • node-cpu로 빌드까지는 성공 (명령어: node 실행파일명.js), 그러나 gpu 가동하지 못하는 문제
    • 이미지 프로세싱이므로 gpu 가동이 필수적이었다.
    • 그러나 CUDA 등 gpu 돌리는 데에 필요한 프로그램을 모두 설치해도 gpu 가동하지 못 했다. 
  • GPT 에 물어봐도 결국 버전 문제라는 답변
    • 즉, 위에서 적은 패키지와 peer 패키지의 버전이 호환되지 않는 문제가 발생했다.
    • 그러나 차장님은 빌드 되는데 나만 안 되는지 이해 불가, 모두 공통으로 빌드하고 있는 버전을 뒤로 하고 나만 다른 버전 사용할 수 없었다.
  • 파이썬 2.7 버전을 찾지 못하는 문제 
    • node.js 환경에서 gpu를 가동하려면 파이썬 2.7 버전을 이용해야한다.
    • 그러나 require(node-gpu) 한 채로 node 실행파일명.js로 파일을 실행하면 아래와 같은 오류가 반복적으로 발생했다.(내가 가장 많이 보았던 오류기도 함)
npm ERR! gyp ERR! find Python
npm ERR! gyp ERR! find Python Python is not set from command line or npm configuration
npm ERR! gyp ERR! find Python Python is not set from environment variable PYTHON
npm ERR! gyp ERR! find Python checking if "python3" can be used
npm ERR! gyp ERR! find Python - "python3" is not in PATH or produced an error
// ... 이런식으로 Python, python3 으로 명령어에 맞는 파이썬 프로그램을 찾지 못하는 문제

 

결론

위 오류가 계속 반복적으로 발생하고, 얘내들을 하루종일 붙잡고 있으면서 내 접근이 틀렸을 수도 있겠다고 생각했다. 따라서 ①연속적 이미지가 아닌 1개 이미지에 대해 좌표 예측을 시도하고 ②우선 html로 구현해야 겠다고 생각했다. 이러한 생각 하에 검색하던 도중 좋은 레퍼런스를 발견했다! https://da2so.tistory.com/44 다음 글에서는 1개 이미지 손 좌표를 예측하는 코드와 트러블 슈팅을 정리할 것이다.

 

TensorFlow.js (2) - WebGL 기반 hand pose detection

0. WebGL 기반 hand pose detection 오늘은 TensorFlow.js의 backend가 무엇이 있는 지 알아보고 사용가능한 backend 중 하나인 WebGL을 기반으로 hand pose detection을 해볼것입니다. hand pose detection만 하면 재미가 없

da2so.tistory.com

2023.10.30 8번째 글 완료!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

개요

회사에서 처음으로 프로젝트를 부여받았다. 손 이미지 좌표를 예측하는 AI를 개발하는 것이었고, 예측 과정은 다음과 같다. 

  1. 웹캠으로 손 영상이 들어옴
  2. 프레임 단위로 캡쳐된 이미지를 텐서* 형태로 변환
    * 텐서
     - 데이터가 3차 이상으로 들어있는 것; 3차원인 경우 x(row), y(column), z(depth)로 구성됨
     - 3차원 이상의 정보를 담을 수 있어 일반 테이블 구조보다 많은 정보를 담을 수 있음. 그러나 데이터 해석 시 데이터 구조에 대한 기초 지식이 요구됨
  3. 텐서 형태로 인식된 손의 좌표(x, y, z(깊이) 축)를 예측

위와 같은 과정을 수행하기 위해 차장님께 TensorflowHandpose, Handpose detection 라이브러리를 사용하면 된다고 전달받았다. 그러나  모르는 것 투성이었으므로 꼬리 문제 풀듯이 꼬리 개념으로 정리하고자 한다.

 


 

TensorFlow 란?

텐서플로(TensorFlow)는 구글(Google)에서 만든 데이터 흐름 프로그래밍을 위한 아파치 2.0 오픈소스 소프트웨어 라이브러리이다. 특히 머신러닝, 딥러닝 프로그램을 쉽게 구현할 수 있도록 해준다. 기본적으로 C++로 구현되어 있으며, Python, Java, Go 등 다양한 언어를 지원한다. 그러나 대부분의 편한 기능들이 Python 라이브러리로 구현되어 있어 언어로 개발하는 것이 편하다. 텐서플로의 라이브러리들은 깃헙에 정리 되어 있다. 이번 프로젝트를 수행하기 위해 나는 그중에서도 tfjs-models 라이브러리handpose, hand-pose-detection 패키지를 참고해야 했다. 그러나 각 패키지의 차이가 무엇인지, 둘 중 무엇을 더 중점적으로 사용해야 하는지 의문이 있었다.

 

Handpose 라이브러리 vs Handpose detection 패키지의 차이점
  Handpose Handpose detection
사용 예시  3D 손 부위 key points(landmarks) 감지를 위한 Media pipe hands 모델 구현  - Google's Real-time Hand pose Detection with Media pipe 모델 구현 
- TensorFlow Lite Micro Speech 예제에서 사용된 모델을 구현 
특징  - 손바닥, 손가락, 손목을 합친 21개의 key points 감지 
- 이미지 또는 비디오에서 손 추적 가능 
- 웹 어플리케이션에서 복잡한 3D key points 감지 기능이 필요한 경우 사용 
- 임베디드 시스템(마이크로 컨트롤러)에서 음성 명령과 함께 실시간으로 손 동작을 감지하는데에 사용하기 좋음

 

위와 같은 특징들로 인해 나는 프로젝트에서 Handpose 패키지를 중점적으로 사용하되, 웹캠 구현 등 기타  사항에서는 Handpose detection 패키지를 적극적으로 활용하기로 결정했다!

 


 

Human pose Estimation 이란?

현재 내가 하고 있는 프로젝트 내용, 텐서플로의 Handpose 및 Handpose detection 패키지는 모두 Human pose Estimation에 속한다.  이에 대한 이론적인 내용은 방대하므로 별도의 글에서 보다 구체적으로 정리하도록 하고, 이 글에서는 의미와 프로젝트와 관련된 내용만 간략하게 정리하고 넘어가고자 한다. 

 

의미

Human pose Estimation(& Tracking)은 Semantic key points*를 검출하고 ②key points 사이의 관련성을 찾고 ③지속적으로 추적하는 컴퓨터 비전**의 과제이다. 나는 Human pose Estimation 중에서도 첫 번째로 손 위치 추적에 대한 프로젝트를 부여받은 것이다. 명칭에서도 알 수 있듯 Human pose Estimation은 Pose Estimation의 한 종류이다. Pose Estimation(포즈 추정)은 컴퓨터 비전에서 유명한 과제 중 하나이다. 
  * Semantic key points : 의미 있는 점; 즉 사람 신체의 오른쪽 어깨, 왼쪽 무릎 등을 예로 들 수 있음
  **  컴퓨터 비전 (vision) : 사람의 시각을 모방하여 기계가 컴퓨터 영상을 처리할 수 있도록 도와줌

 

원리

대부분의 Pose Estimator는 2개 과정으로 위치를 추정한다. 

  • bounding box로 사람 또는 물체를 탐색한다.
  • 각 박스에서 탐색 대상의 key points를 찾아낸다. 사람의 경우 key points는 팔꿈치, 무릎, 손목 등이 될 수 있다. Single-pose estimation 의 경우 주어진 영상에서 하나의 물체의 pose를 추정하는 것이 목적이고, Multi-pose estimation의 경우 여러 물체를 탐지하는 것이 목적이 된다. 

 

Handpose 패키지를 이용한 AI 개발이 속하는 method의 범위

딥러닝의 빠른 발전으로 딥러닝 기반 Pose Estimation이 고전 방식에 비해 우월한 성능을 보이고 있으며 그 종류가 다양하다. 이번 프로젝트는 Node.js 기반 서버에서 동작하는 자사 제품에 추가될 기능이므로, 내 생각에는 Handpose 패키지를 이용한 프로젝트는 PoseNet 모델을 이용한 것이라고 볼 수 있을 것 같다. 

PoseNet
  - 경량으로 모바일 또는 웹 브라우저에서 작동하기 위한 모델 
  - TensorFlow.js 를 기반으로 구축된 사전 학습 모델

 

 


 

 

참고 자료

TensorFlow 란?

https://ko.wikipedia.org/wiki/%ED%85%90%EC%84%9C%ED%94%8C%EB%A1%9C

 

텐서플로 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 텐서플로(TensorFlow) 또는 텐서플로우는 다양한 작업에대해 데이터 흐름 프로그래밍을 위한 오픈소스 소프트웨어 라이브러리이다. 심볼릭 수학 라이브러리이자,

ko.wikipedia.org

https://excelsior-cjh.tistory.com/148

 

[러닝 텐서플로]Chap01 - 텐서플로 란?

Chap01 - 개요1.1 텐서플로 란? 텐서플로(TensorFlow)는 구글(Google)에서 만든, 딥러닝 프로그램을 쉽게 구현할 수 있도록 다양한 기능을 제공해주는 라이브러리다. 텐서플로 자체는 기본적으로 C++로 구

excelsior-cjh.tistory.com

 

Human pose Estimation 이란?

https://supermemi.tistory.com/entry/Human-Pose-Estimation-%EC%9D%B4%EB%9E%80-2022

 

Human Pose Estimation 이란? (2022)

Human Pose Estimation Ultimate Overview in 2022 Human Pose Estimation with Deep Learning - Ultimate Overview in 2022 - viso.ai Pose Estimation is a computer vision technique to predict and track the location of a person or object. List of use cases and arc

supermemi.tistory.com

https://viso.ai/deep-learning/pose-estimation-ultimate-overview/

 

Human Pose Estimation with Deep Learning - Ultimate Overview in 2023 - viso.ai

Pose Estimation is a computer vision technique to predict and track the location of a person or object. List of use cases and architectures.

viso.ai

 

개요

회사 내부 서버에 연결하여 각 프로젝트를 빌드하던 도중 문제가 발생했다. (구체적인 오류 내용은 이하와 같다.) 프로젝트를 빌드하기 위한 버전은 파이썬 2점대인데 현재 내 pc에 설치되어있는 파이썬 버전은 3점대였기 때문이다. 그러나 나는 ai 개발할 때 파이썬 3점대를 사용해야 했기 때문에 두 버전 모두 필요했다. 차장님께 여쭤보니 파이썬 2점대와 3점대를 동시 설치 -> 파이썬 2점대가 나오는 명령어와 3점대가 나오는 명령어를 별도 설정하면 된다고 하셨다. 고민의 시작...

Traceback (most recent call last):
  File "C:\Workspace\scratch-blocks\build.py", line 38, in <module>
    raise Exception("Blockly build only compatible with Python 2.x.\n"
Exception: Blockly build only compatible with Python 2.x.
You are using: 3.12.0 (tags/v3.12.0:0fb18b0, Oct  2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)]

 


 

1. 파이썬 2점대와 3점대를 모두 설치

파이썬 공식 홈페이지를 들어가 설치하면 된다. 어렵지 않다! 내가 설치해야 하는 버전은 빌드용 2.7.18이었고, ai 개발용 3.12였다. 설치 후 cmd 창을 열어 cmd의 루트 경로에서 버전을 확인하면 다음과 같이 나온다. 즉 현재 파이썬 2점대를 인식하지 못하므로, 설치만 하고 빌드를 하면 위 오류가 동일하게 발생한다. 따라서 파이썬 2점대를 인식할 수 있는 명령어를 등록해주어야 한다. 

python --version  // 결과 : Python 3.12.0
py --version  // 결과 : Python 3.12.0

 


 

2. 파이썬 명령어 등록 및 확인

등록해야 하는 명령어는 파이썬 2점대는 "python", 3점대는 "py"로 정해져 있었다. (따라서 후자는 별도로 명령어를 등록할 필요가 없었다.) 왜냐하면 빌드할 때 npm이 package.json을 방문하여 빌드 명령어를 찾는데, 그곳에 "python"으로 2점대의 파이썬을 실행시키기 때문이다. package.json은 PM을 제외하고는 수정할 수 없으므로 그곳에 적힌 명령어로 나도 맞추어야 했다.

 


 

파이썬 2점대 설치 경로 알아내기

파이썬 2점대의 설치 경로를 알아내야 하는데, 이는 "python" 명령어를 실행하면 해당 설치 경로에 있는 파일이 동작하도록 만들기 위해서다. 참고 자료에서도 그렇고, 나도 C 밑에 바로 저장되어 있었으므로 " C:\Python2718" 이라고 볼 수 있다. 

파이썬 설치 경로 확인

 


 

파이썬 2점대 링크 파일 생성
  • cmd를 관리자 권한으로 실행
    : 매우 중요하다!!!!!!! 관리자 권한으로 실행하지 않으면 '액세스가 거부되었습니다.' 하는 오류가 발생한다. 관리자여야 링크 생성할 수 있는 '액세스'가 있음을 기억하자!
  • 파이썬 2점대 명령어를 실행할 위치로 이동
    : 매우 중요하다!!!!!!! 나는 빌드하는 프로젝트 위치 ( ex. C://Workspace/gui) 로 cmd를 이동하지 않고, 계속 루트 경로에서 명령어를 생성하여 빌드할 때 명령어가 정상적으로 실행되지 않았다. 절대 꼭 까먹지 말고 위치 이동!!!!
  • mklink C:\Windows\python.exe [파이썬 2점대 설치경로]  실행
    : 링크를 만들다 | Windows 하에서 실행할 명령어(python) 입력 | 파이썬 2점대 설치 경로 라는 의미이다. 내가 실행했던 구체적인 코드와 결과는 다음과 같다. 
mklink C:\Windows\python.exe C:\Python27\python.exe
// 실행 결과 : C:\Windows\python2.exe <<===>> C:\Python2718\python.exe에 대한 기호화된 링크를 만들었습니다.

 


 

파이썬 명령어로 버전 확인
python --version // 실행 결과 : Python 2.7.18

 


 

마무리

위 과정을 끝내고 빌드를 다시 했더니 정상적으로 빌드가 가능했고, localhost:port번호로 자사 제품에 접속할 수 있었다. 사실 위와 같은 과정으로 pip 명령어 설정도 가능한데, 오늘의 글에서는 생략한다! 귀찮으니까 

2023.10.19 4번째 완료

 

 

+ Recent posts