[TIL] 인공지능 모델 Nest 프로젝트에 연동 시도

김시원·2023년 6월 17일
0

TIL

목록 보기
48/50
post-custom-banner

📌 What I tried

1. Tensorflow.js 및 관련 모듈을 활용하여 keras h5 모델을 ts 환경에서 import 해서 사용하기

Node.js 환경에서 .h5 형식의 모델과 .pkl 형식의 토크나이저를 사용할 수 없어, 이를 .json 형식으로 변환하는 과정이 필요

import tensorflowjs as tfjs
from tensorflow.keras.models import load_model

model = load_model('rnn_model_v3.h5')
tfjs.converters.save_keras_model(model, './predict_emergency_level_model')

위 코드가 .h5 형식의 모델을 tensorflow.js가 인식할 수 있는 .json 파일로 변환하는 코드이다. 이 짧은 코드를 실행하기 위해 여러 트러블슈팅의 과정을 거쳤다.

Issue #1

  • 문제: tensorflowjs 모듈 설치 중 다음과 같은 에러:
Collecting flax>=0.5.3 (from tensorflowjs)
  Using cached flax-0.5.3-py3-none-any.whl (202 kB)
ERROR: Cannot install flax because these package versions have conflicting dependencies.

The conflict is caused by:
    optax 0.1.5 depends on jaxlib>=0.1.37
    optax 0.1.4 depends on jaxlib>=0.1.37
    optax 0.1.3 depends on jaxlib>=0.1.37
    optax 0.1.2 depends on jaxlib>=0.1.37
    optax 0.1.1 depends on jaxlib>=0.1.37
    optax 0.1.0 depends on jaxlib>=0.1.37
    optax 0.0.91 depends on jaxlib>=0.1.37
    optax 0.0.9 depends on jaxlib>=0.1.37
    optax 0.0.8 depends on jaxlib>=0.1.37
    optax 0.0.6 depends on jaxlib>=0.1.37
    optax 0.0.5 depends on jaxlib>=0.1.37
    optax 0.0.3 depends on jaxlib>=0.1.37
    optax 0.0.2 depends on jaxlib>=0.1.37
    optax 0.0.1 depends on jaxlib>=0.1.37

To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts

Issue #2

  • 문제: python 파일 실행시 다음과 같은 에러:
ERROR: Could not find a version that satisfies the requirement tensorflow-decision-forests>=1.3.0 (from tensorflowjs) (from versions: none)
ERROR: No matching distribution found for tensorflow-decision-forests>=1.3.0 (from tensorflowjs)
  • 해결 방법:
  1. 참고 Tensorflow 공식문서 사이트

    공식문서를 통해 pip3 install tensorflow_decision_forests --upgrade 이 명령어로 에러가 뜨는 모듈을 설치하였지만,
    => ERROR: Could not find a version that satisfies the requirement tensorflow_decision_forests (from versions: none) ERROR: No matching distribution found for tensorflow_decision_forests
    이런 에러가 지속되었고, 도커의 tensorflow/build 이미지를 사용하기로 결정하였다.

  2. 도커 tensorflow/build 컨테이너 내에서 파이썬 파일 실행

    2-1. docker pull tensorflow/build:latest-python3.8 명령어로 도커 이미지를 pull해왔다.
    2-2. docker run -it tensorflow/build:latest-python3.8 bash 명령어로 이미지로 컨테이너를 실행하였다.
    2-3. 위 명령어로 도커 컨테이너에 접속해서 파이썬 가상환경 설정을 해주었다.
    2-4. 위 명령어로 도커 컨테이너에 접속해서 pip install tensorflow_decision_forests로 모듈을 설치하였다. (중간에 numpy 모듈 버전 degrade도 해주었다.)

  • 결론: tensorflow/build 도커 컨테이너 환경에서 tensorflow_decision_forests 모듈을 설치하였다.

Issue #3

  • 문제: 로컬 파일을 도커 컨테이너로 가져와 실행하기

  • 해결 방법:

  1. docker cp [저장하고 싶은 로컬 파일의 절대 경로] [container_name]:[container에 저장하고 싶은 경로] (docker cp C:/Users/siwon/Desktop/Voyage99/projects/CodeBlue-AI-server/rnn_model_v3.h5 hungry_jones:/app ) 명령어로 로컬에 있는 파일 (.h5 모델 파일과 실행시킬 py 파일)을 도커 컨테이너에 로드해주었다.
  2. 추가로 tensorflowjstensorflow-hub, jaxlib을 설치하였다.
  3. py 파일명.py로 파이썬 파일을 실행하였다.
    원했던 predict_emergency_level_model 폴더가 생성되었다.
  4. 컨테이너에 생성된 파일을 다시 우리 로컬로 불러오기 위해 해당 명령어를 사용했다. docker cp [container_name]:[container에서 가져오고 싶은 파일 경로] [로컬에 저장하고 싶은 절대 경로] (docker cp hungry_jones:/app/predict_emergency_level_model C:/Users/siwon/Desktop/Voyage99/projects/CodeBlue-AI-server )
    원했던 .bin 파일과 .json 파일이 잘 불러와졌다.
  • 결론: 도커 명령어만 잘 쓰면 됌

Issue #4

  • 문제: .pkl 형식의 토크나이저도 .json으로 변환하기

  • 해결 방법:

import pickle
import json

# pickle 파일로부터 토크나이저를 불러옴
with open('tokenizer.pkl', 'rb') as f:
    tokenizer = pickle.load(f)

# 토크나이저의 word_index를 json 파일로 저
with open('tokenizer.json', 'w') as f:
    json.dump(tokenizer.word_index, f)
  • 해결: 로컬에서 파이썬 파일을 실행해서 해결하였다.

Issue #5

  • 문제: 우리의 Nest 프로젝트에서 모델과 토크나이저를 활용하여 모델 실행하기

  • 해결 방법:
    일단 해당 코드가 잘 실행되는지 확인하기 위해 js로 테스트해보았다.

const tf = require("@tensorflow/tfjs");
const fs = require("fs");

// 전처리용 상수
const MAX_LEN = 18;
const STOPWORDS = ["의","로","을","가","이"];

// 기존 모델 및 토크나이저 불러오기
const modelPath =
  "file://C:/Users/siwon/Desktop/Voyage99/projects/CodeBlue-AI-server/predict_emergency_level_model/model.json";
const tokenizerPath =
  "C:/Users/siwon/Desktop/Voyage99/projects/CodeBlue-AI-server/tokenizer.json";

async function loadModel(modelPath) {
  const model = await tf.loadLayersModel(modelPath);
  return model;
}

// 파일 로드
let tokenizer;
fs.readFile(tokenizerPath, "utf8", (err, data) => {
  if (err) {
    console.error("파일을 읽을 수 없습니다:", err);
    return;
  }

  tokenizerData = JSON.parse(data);
});

// 문장 예측
async function emergencyLevelPrediction(sampleSentence) {
  // 모델 불러오기
  const model = await loadModel(modelPath);

  // 샘플 문장 전처리 (토큰화, 불용어 제거)
  let sampleSentenceArr = sampleSentence.split(" ");
  sampleSentenceArr = sampleSentenceArr.filter(
    (word) => !STOPWORDS.includes(word)
  );
  // 샘플 문장을 토큰화하고 패딩
  const encodedSample = sampleSentenceArr.map(
    (word) => tokenizer.word_index[word] || 0
  );
  const paddedSample = padSequences([encodedSample], MAX_LEN, "post");
  // 샘플 문장 응급도 예상
  const prediction = model.predict(tf.tensor2d(paddedSample));
  let emergencyLevel;
  let confidence;

  if (!Array.isArray(prediction)) {
    emergencyLevel = prediction.argMax(-1).dataSync()[0] + 1;
    confidence = prediction.dataSync()[emergencyLevel - 1];
  }
  console.log(`응급도: ${emergencyLevel}, 확신도: ${confidence * 100.0}%`);
}

function padSequences(
  sequences,
  maxLen,
  padding = "post",
  truncating = "post",
  value = 0
) {
  return sequences.map((seq) => {
    // truncate
    if (seq.length > maxLen) {
      if (truncating === "pre") {
        seq.splice(0, seq.length - maxLen);
      } else {
        seq.splice(maxLen, seq.length - maxLen);
      }
    }
    // pad
    if (seq.length < maxLen) {
      const pad = [];
      for (let i = 0; i < maxLen - seq.length; i++) {
        pad.push(value);
      }
      if (padding === "pre") {
        seq = pad.concat(seq);
      } else {
        seq = seq.concat(pad);
      }
    }
    return seq;
  });
}

// 예시 문장
emergencyLevelPrediction(
  "응급환자는 심장마비로 인해 의식을 잃고 쓰러졌습니다. 호흡 곤란 상태입니다."
); // 예상: 1


여기서 계속 모델 파일 경로에 대한 절대 경로 사용 관련 에러가 떴다. 이 에러를 고쳐보려고 모델 path 설정을 그냥 "C:/"에서 "file://C:/"로 변경해보고 했는데 결국 해결이 되지 않았다.

  • 결론: 절대 경로 관련 에러 해결 못함

🤚 여기서 STOP

여기서 계속 에러 수정을 시도하고 있다가 시니어 코치님 멘토링 시간이 돼서 멘토링을 하면서 어떤식으로 인공지능 모델을 우리의 프로젝트에 연결할 수 있는지를 질문하였는데, 내가 시도한 방식은 일단 dependency가 생기는 것이기 때문에 지양해야하고 모델 구동용 서버를 따로 파서 MSA화 시키는 것이 적절하다고 말씀해주셔서 그 방향으로 연결을 하는 것으로 결정하였다.

2. 파이썬 구동 Flask 서버를 구축하여 Nest 프로젝트에서 인공지능 모델 사용시 Flask 서버를 통해 모델 실행

앞으로 할 task이다.

post-custom-banner

0개의 댓글