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 파일로 변환하는 코드이다. 이 짧은 코드를 실행하기 위해 여러 트러블슈팅의 과정을 거쳤다.
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
해결 방법: 참고 깃헙 이슈 사이트
결론: pip install --no-deps tensorflowjs
명령어로 설치
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)
공식문서를 통해 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
이미지를 사용하기로 결정하였다.
도커 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
모듈을 설치하였다.문제: 로컬 파일을 도커 컨테이너로 가져와 실행하기
해결 방법:
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 파일)을 도커 컨테이너에 로드해주었다. tensorflowjs
와 tensorflow-hub
, jaxlib
을 설치하였다.py 파일명.py
로 파이썬 파일을 실행하였다.docker cp [container_name]:[container에서 가져오고 싶은 파일 경로] [로컬에 저장하고 싶은 절대 경로]
(docker cp hungry_jones:/app/predict_emergency_level_model C:/Users/siwon/Desktop/Voyage99/projects/CodeBlue-AI-server
)문제: .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)
문제: 우리의 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:/"로 변경해보고 했는데 결국 해결이 되지 않았다.
여기서 계속 에러 수정을 시도하고 있다가 시니어 코치님 멘토링 시간이 돼서 멘토링을 하면서 어떤식으로 인공지능 모델을 우리의 프로젝트에 연결할 수 있는지를 질문하였는데, 내가 시도한 방식은 일단 dependency가 생기는 것이기 때문에 지양해야하고 모델 구동용 서버를 따로 파서 MSA화 시키는 것이 적절하다고 말씀해주셔서 그 방향으로 연결을 하는 것으로 결정하였다.
앞으로 할 task이다.