learning_model 1.0.50 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/learning/mobilenet.ts +26 -0
- package/package.json +3 -3
- package/dist/index.bundle.js +0 -2
- package/dist/index.bundle.js.LICENSE.txt +0 -335
- package/dist/index.d.ts +0 -3
- package/dist/index.html +0 -1
- package/dist/index.js +0 -10
- package/dist/learning/base.d.ts +0 -23
- package/dist/learning/base.js +0 -2
- package/dist/learning/data_model.d.ts +0 -41
- package/dist/learning/data_model.js +0 -205
- package/dist/learning/data_model.test.d.ts +0 -1
- package/dist/learning/data_model.test.js +0 -56
- package/dist/learning/mobilenet.d.ts +0 -49
- package/dist/learning/mobilenet.js +0 -345
- package/dist/learning/mobilenet.test.d.ts +0 -1
- package/dist/learning/mobilenet.test.js +0 -79
- package/dist/lib/index.d.ts +0 -3
- package/dist/lib/learning/base.d.ts +0 -23
- package/dist/lib/learning/data_model.d.ts +0 -41
- package/dist/lib/learning/data_model.test.d.ts +0 -1
- package/dist/lib/learning/mobilenet.d.ts +0 -49
- package/dist/lib/learning/mobilenet.test.d.ts +0 -1
- package/dist/lib/utils/canvas.d.ts +0 -3
- package/dist/lib/utils/data_manager.d.ts +0 -15
- package/dist/lib/utils/dataset.d.ts +0 -6
- package/dist/lib/utils/tf.d.ts +0 -7
- package/dist/utils/canvas.d.ts +0 -3
- package/dist/utils/canvas.js +0 -47
- package/dist/utils/data_manager.d.ts +0 -15
- package/dist/utils/data_manager.js +0 -62
- package/dist/utils/dataset.d.ts +0 -6
- package/dist/utils/dataset.js +0 -21
- package/dist/utils/tf.d.ts +0 -7
- package/dist/utils/tf.js +0 -126
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const data_model_1 = __importDefault(require("./data_model"));
|
|
16
|
-
describe('LearningModel', () => {
|
|
17
|
-
let learningModel;
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
learningModel = new data_model_1.default({
|
|
20
|
-
epochs: 10,
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
it('should add sufficient data and train the model', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
-
// 훈련 데이터 생성
|
|
25
|
-
const numSamples = 2000; // 훈련 데이터 샘플 수
|
|
26
|
-
for (let i = 0; i < numSamples; i++) {
|
|
27
|
-
const classLabel = i % 2 === 0 ? 'class1' : 'class2'; // 두 개의 클래스를 번갈아가며 생성
|
|
28
|
-
const data = Array.from({ length: 3 }, () => Math.random() * 10); // 임의의 데이터 생성
|
|
29
|
-
yield learningModel.addData(classLabel, data);
|
|
30
|
-
}
|
|
31
|
-
// 모델 훈련
|
|
32
|
-
const history = yield learningModel.train();
|
|
33
|
-
// 훈련 결과 평가
|
|
34
|
-
expect(history).toBeDefined();
|
|
35
|
-
expect(learningModel.ready()).toBe(true);
|
|
36
|
-
}), 30000); // 타임아웃을 15초로 설정
|
|
37
|
-
it('should make predictions', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
-
// 훈련 데이터 생성
|
|
39
|
-
const numSamples = 100; // 훈련 데이터 샘플 수
|
|
40
|
-
for (let i = 0; i < numSamples; i++) {
|
|
41
|
-
const classLabel = i % 2 === 0 ? 'class1' : 'class2'; // 두 개의 클래스를 번갈아가며 생성
|
|
42
|
-
const data = Array.from({ length: 3 }, () => Math.random() * 10); // 임의의 데이터 생성
|
|
43
|
-
yield learningModel.addData(classLabel, data);
|
|
44
|
-
yield learningModel.addData(classLabel, [1, 2, 4]);
|
|
45
|
-
}
|
|
46
|
-
// 모델 훈련
|
|
47
|
-
yield learningModel.train();
|
|
48
|
-
// 테스트 데이터 생성
|
|
49
|
-
const testData = [4.0, 3.1, 5.2]; // 테스트할 데이터 생성
|
|
50
|
-
// 예측 수행
|
|
51
|
-
const result = yield learningModel.infer(testData);
|
|
52
|
-
console.log('result', result);
|
|
53
|
-
// 결과 평가
|
|
54
|
-
expect(result).toBeDefined();
|
|
55
|
-
}), 30000);
|
|
56
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import * as tf from '@tensorflow/tfjs';
|
|
2
|
-
import { io } from '@tensorflow/tfjs-core';
|
|
3
|
-
import LearningInterface from './base';
|
|
4
|
-
declare class LearningMobilenet implements LearningInterface {
|
|
5
|
-
model: tf.LayersModel | null;
|
|
6
|
-
epochs: number;
|
|
7
|
-
batchSize: number;
|
|
8
|
-
learningRate: number;
|
|
9
|
-
validateRate: number;
|
|
10
|
-
isRunning: boolean;
|
|
11
|
-
isReady: boolean;
|
|
12
|
-
isTrainedDone: boolean;
|
|
13
|
-
limitSize: number;
|
|
14
|
-
mobilenetModule: tf.LayersModel | null;
|
|
15
|
-
imageExamples: Float32Array[][];
|
|
16
|
-
classNumber: string[];
|
|
17
|
-
readonly MOBILE_NET_INPUT_WIDTH = 224;
|
|
18
|
-
readonly MOBILE_NET_INPUT_HEIGHT = 224;
|
|
19
|
-
readonly MOBILE_NET_INPUT_CHANNEL = 3;
|
|
20
|
-
readonly IMAGE_NORMALIZATION_FACTOR = 255;
|
|
21
|
-
constructor({ epochs, batchSize, limitSize, learningRate, validateRate, }?: {
|
|
22
|
-
epochs?: number;
|
|
23
|
-
batchSize?: number;
|
|
24
|
-
limitSize?: number;
|
|
25
|
-
learningRate?: number;
|
|
26
|
-
validateRate?: number;
|
|
27
|
-
});
|
|
28
|
-
onProgress: (progress: number) => void;
|
|
29
|
-
onLoss: (loss: number) => void;
|
|
30
|
-
onEvents: (logs: any) => void;
|
|
31
|
-
onTrainBegin: (log: any) => void;
|
|
32
|
-
onTrainEnd: (log: any) => void;
|
|
33
|
-
onEpochEnd: (epoch: number, logs: any) => void;
|
|
34
|
-
load({ jsonURL, labels }: {
|
|
35
|
-
jsonURL: string;
|
|
36
|
-
labels: Array<string>;
|
|
37
|
-
}): Promise<void>;
|
|
38
|
-
private registerClassNumber;
|
|
39
|
-
private _convertToTfDataset;
|
|
40
|
-
addData(label: string, data: any): Promise<void>;
|
|
41
|
-
init(): Promise<void>;
|
|
42
|
-
train(): Promise<tf.History>;
|
|
43
|
-
infer(data: any): Promise<Map<string, number>>;
|
|
44
|
-
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
45
|
-
running(): boolean;
|
|
46
|
-
ready(): boolean;
|
|
47
|
-
private _createModel;
|
|
48
|
-
}
|
|
49
|
-
export default LearningMobilenet;
|
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
///////////////////////////////////////////////////////////////////////////
|
|
3
|
-
///////////////////////////////////////////////////////////////////////////
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////
|
|
5
|
-
// mobilenet 모델을 이용한 전이학습 방법
|
|
6
|
-
///////////////////////////////////////////////////////////////////////////
|
|
7
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
-
if (k2 === undefined) k2 = k;
|
|
9
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
-
}
|
|
13
|
-
Object.defineProperty(o, k2, desc);
|
|
14
|
-
}) : (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
o[k2] = m[k];
|
|
17
|
-
}));
|
|
18
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
-
}) : function(o, v) {
|
|
21
|
-
o["default"] = v;
|
|
22
|
-
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
24
|
-
if (mod && mod.__esModule) return mod;
|
|
25
|
-
var result = {};
|
|
26
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
27
|
-
__setModuleDefault(result, mod);
|
|
28
|
-
return result;
|
|
29
|
-
};
|
|
30
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
31
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
32
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
33
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
34
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
35
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
36
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
const tf = __importStar(require("@tensorflow/tfjs"));
|
|
41
|
-
const tfjs_1 = require("@tensorflow/tfjs");
|
|
42
|
-
const tf_1 = require("../utils/tf");
|
|
43
|
-
const canvas_1 = require("../utils/canvas");
|
|
44
|
-
const dataset_1 = require("../utils/dataset");
|
|
45
|
-
class LearningMobilenet {
|
|
46
|
-
constructor({ epochs = 50, batchSize = 16, limitSize = 2, learningRate = 0.001, validateRate = 0.15, } = {}) {
|
|
47
|
-
this.imageExamples = [];
|
|
48
|
-
this.classNumber = [];
|
|
49
|
-
this.MOBILE_NET_INPUT_WIDTH = 224;
|
|
50
|
-
this.MOBILE_NET_INPUT_HEIGHT = 224;
|
|
51
|
-
this.MOBILE_NET_INPUT_CHANNEL = 3;
|
|
52
|
-
this.IMAGE_NORMALIZATION_FACTOR = 255.0;
|
|
53
|
-
// 진행 상태를 나타내는 이벤트를 정의합니다.
|
|
54
|
-
this.onProgress = () => { };
|
|
55
|
-
this.onLoss = () => { };
|
|
56
|
-
this.onEvents = () => { };
|
|
57
|
-
this.onTrainBegin = () => { };
|
|
58
|
-
this.onTrainEnd = () => { };
|
|
59
|
-
this.onEpochEnd = () => { };
|
|
60
|
-
this.model = null;
|
|
61
|
-
this.epochs = epochs;
|
|
62
|
-
this.batchSize = batchSize;
|
|
63
|
-
this.learningRate = learningRate;
|
|
64
|
-
this.validateRate = validateRate;
|
|
65
|
-
this.isRunning = false;
|
|
66
|
-
this.isReady = false;
|
|
67
|
-
this.isTrainedDone = false;
|
|
68
|
-
this.limitSize = limitSize;
|
|
69
|
-
this.mobilenetModule = null;
|
|
70
|
-
this.classNumber = [];
|
|
71
|
-
}
|
|
72
|
-
//
|
|
73
|
-
// 기존의 모델 로드
|
|
74
|
-
load({ jsonURL, labels }) {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
if (labels.length <= 0) {
|
|
77
|
-
return Promise.reject(new Error('Labels length is 0'));
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
this.model = yield tf.loadLayersModel(jsonURL);
|
|
81
|
-
for (var i = 0; i < labels.length; i++) {
|
|
82
|
-
this.registerClassNumber(labels[i]);
|
|
83
|
-
}
|
|
84
|
-
this.isReady = true;
|
|
85
|
-
this.model.summary();
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
console.error('Model load failed', error);
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
registerClassNumber(value) {
|
|
94
|
-
// 중복 값의 인덱스를 찾습니다.
|
|
95
|
-
const existingIndex = this.classNumber.indexOf(value);
|
|
96
|
-
// 중복 값이 있다면 해당 인덱스를 반환합니다.
|
|
97
|
-
if (existingIndex !== -1) {
|
|
98
|
-
return existingIndex;
|
|
99
|
-
}
|
|
100
|
-
// 중복 값이 없다면 새로운 항목을 추가하고 그 인덱스를 반환합니다.
|
|
101
|
-
this.classNumber.push(value);
|
|
102
|
-
return this.classNumber.length - 1;
|
|
103
|
-
}
|
|
104
|
-
_convertToTfDataset() {
|
|
105
|
-
for (let i = 0; i < this.imageExamples.length; i++) {
|
|
106
|
-
this.imageExamples[i] = (0, dataset_1.fisherYates)(this.imageExamples[i]);
|
|
107
|
-
}
|
|
108
|
-
const trainDataset = [];
|
|
109
|
-
const validationDataset = [];
|
|
110
|
-
for (let i = 0; i < this.imageExamples.length; i++) {
|
|
111
|
-
const classLength = this.imageExamples[i].length;
|
|
112
|
-
// 클래스의 전체 데이터 수를 사용하여 학습 및 검증 데이터 수 계산
|
|
113
|
-
const numValidation = Math.ceil(this.validateRate * classLength);
|
|
114
|
-
const numTrain = classLength - numValidation;
|
|
115
|
-
// One-Hot 인코딩을 사용하여 라벨 생성
|
|
116
|
-
const y = (0, dataset_1.flatOneHot)(i, this.classNumber.length);
|
|
117
|
-
// numTrain과 numValidation에 따라 데이터를 학습 및 검증 데이터로 분할
|
|
118
|
-
const classTrain = this.imageExamples[i].slice(0, numTrain).map(dataArray => ({ data: dataArray, label: y }));
|
|
119
|
-
trainDataset.push(...classTrain);
|
|
120
|
-
const classValidation = this.imageExamples[i].slice(numTrain, numTrain + numValidation).map(dataArray => ({ data: dataArray, label: y }));
|
|
121
|
-
validationDataset.push(...classValidation);
|
|
122
|
-
}
|
|
123
|
-
// Shuffle entire datasets
|
|
124
|
-
const shuffledTrainDataset = (0, dataset_1.fisherYates)(trainDataset);
|
|
125
|
-
const shuffledValidationDataset = (0, dataset_1.fisherYates)(validationDataset);
|
|
126
|
-
// Convert to tf.data.Dataset
|
|
127
|
-
const trainX = tf.data.array(shuffledTrainDataset.map(sample => sample.data));
|
|
128
|
-
const validationX = tf.data.array(shuffledValidationDataset.map(sample => sample.data));
|
|
129
|
-
const trainY = tf.data.array(shuffledTrainDataset.map(sample => sample.label));
|
|
130
|
-
const validationY = tf.data.array(shuffledValidationDataset.map(sample => sample.label));
|
|
131
|
-
return {
|
|
132
|
-
trainDataset: tf.data.zip({ xs: trainX, ys: trainY }),
|
|
133
|
-
validationDataset: tf.data.zip({ xs: validationX, ys: validationY })
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
// 학습 데이타 등록
|
|
137
|
-
addData(label, data) {
|
|
138
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
-
try {
|
|
140
|
-
if (this.mobilenetModule !== null) {
|
|
141
|
-
const cap = (0, tf_1.isTensor)(data) ? data : yield (0, tf_1.capture)(data, false);
|
|
142
|
-
const predict = tf.tidy(() => {
|
|
143
|
-
return this.mobilenetModule.predict(cap);
|
|
144
|
-
});
|
|
145
|
-
const activation = yield predict.data();
|
|
146
|
-
const classIndex = this.registerClassNumber(label);
|
|
147
|
-
if (!this.imageExamples[classIndex]) {
|
|
148
|
-
this.imageExamples[classIndex] = [];
|
|
149
|
-
}
|
|
150
|
-
this.imageExamples[classIndex].push(activation);
|
|
151
|
-
if (this.classNumber.length >= this.limitSize) {
|
|
152
|
-
this.isReady = true;
|
|
153
|
-
}
|
|
154
|
-
// Dispose of the prediction tensor to free memory
|
|
155
|
-
predict.dispose();
|
|
156
|
-
// If cap is not a tensor, we don't need to dispose it. Otherwise, we should.
|
|
157
|
-
if (!(0, tf_1.isTensor)(data)) {
|
|
158
|
-
cap.dispose();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
throw new Error('mobilenetModule is null');
|
|
163
|
-
}
|
|
164
|
-
return Promise.resolve();
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
console.error('Model training failed', error);
|
|
168
|
-
throw error;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
init() {
|
|
173
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
try {
|
|
175
|
-
this.mobilenetModule = yield (0, tf_1.loadModel)();
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
console.log('init Error', error);
|
|
179
|
-
throw error;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
// 모델 학습 처리
|
|
184
|
-
train() {
|
|
185
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
186
|
-
if (this.isRunning) {
|
|
187
|
-
return Promise.reject(new Error('Training is already in progress.'));
|
|
188
|
-
}
|
|
189
|
-
// 콜백 정의
|
|
190
|
-
const customCallback = {
|
|
191
|
-
onTrainBegin: (log) => {
|
|
192
|
-
this.isTrainedDone = false;
|
|
193
|
-
this.onTrainBegin(log);
|
|
194
|
-
},
|
|
195
|
-
onTrainEnd: (log) => {
|
|
196
|
-
this.isTrainedDone = true;
|
|
197
|
-
this.onTrainEnd(log);
|
|
198
|
-
this.isRunning = false;
|
|
199
|
-
},
|
|
200
|
-
onBatchBegin: (batch, logs) => {
|
|
201
|
-
//console.log(`Batch ${batch} is starting.`);
|
|
202
|
-
},
|
|
203
|
-
onBatchEnd: (batch, logs) => {
|
|
204
|
-
//console.log(`Batch ${batch} has ended.`);
|
|
205
|
-
},
|
|
206
|
-
onEpochBegin: (epoch, logs) => {
|
|
207
|
-
//console.log(`Epoch ${epoch+1} is starting.`, logs);
|
|
208
|
-
},
|
|
209
|
-
onEpochEnd: (epoch, logs) => {
|
|
210
|
-
this.onEpochEnd(epoch, logs);
|
|
211
|
-
this.onLoss(logs.loss);
|
|
212
|
-
this.onProgress(epoch + 1);
|
|
213
|
-
this.onEvents({
|
|
214
|
-
epoch: epoch,
|
|
215
|
-
logs: logs,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
try {
|
|
220
|
-
this.isRunning = true;
|
|
221
|
-
if (this.classNumber.length < this.limitSize) {
|
|
222
|
-
return Promise.reject(new Error('Please train Data need over 2 data length'));
|
|
223
|
-
}
|
|
224
|
-
const datasets = this._convertToTfDataset();
|
|
225
|
-
const trainData = datasets.trainDataset.batch(this.batchSize);
|
|
226
|
-
const validationData = datasets.validationDataset.batch(this.batchSize);
|
|
227
|
-
const optimizer = tf.train.adam(this.learningRate);
|
|
228
|
-
const trainModel = yield this._createModel(optimizer);
|
|
229
|
-
const jointModel = tf.sequential();
|
|
230
|
-
jointModel.add(this.mobilenetModule);
|
|
231
|
-
jointModel.add(trainModel);
|
|
232
|
-
this.model = jointModel;
|
|
233
|
-
const history = yield trainModel.fitDataset(trainData, {
|
|
234
|
-
epochs: this.epochs,
|
|
235
|
-
validationData: validationData,
|
|
236
|
-
callbacks: customCallback
|
|
237
|
-
});
|
|
238
|
-
optimizer.dispose();
|
|
239
|
-
return history;
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
this.isRunning = false;
|
|
243
|
-
console.error('Model training failed', error);
|
|
244
|
-
throw error;
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
// 추론하기
|
|
249
|
-
infer(data) {
|
|
250
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
251
|
-
if (this.model === null) {
|
|
252
|
-
return Promise.reject(new Error('Model is Null'));
|
|
253
|
-
}
|
|
254
|
-
try {
|
|
255
|
-
const classProbabilities = new Map();
|
|
256
|
-
const croppedImage = (0, canvas_1.cropTo)(data, 224, false);
|
|
257
|
-
const captured = yield (0, tf_1.capture)(croppedImage, false);
|
|
258
|
-
const logits = tf.tidy(() => {
|
|
259
|
-
return this.model.predict(captured);
|
|
260
|
-
});
|
|
261
|
-
const values = yield logits.data();
|
|
262
|
-
const EPSILON = 1e-6; // 매우 작은 값을 표현하기 위한 엡실론
|
|
263
|
-
for (let i = 0; i < values.length; i++) {
|
|
264
|
-
let probability = Math.max(0, Math.min(1, values[i])); // 확률 값을 0과 1 사이로 조정
|
|
265
|
-
probability = probability < EPSILON ? 0 : probability; // 매우 작은 확률 값을 0으로 간주
|
|
266
|
-
const className = this.classNumber[i]; // 클래스 이름
|
|
267
|
-
const existingProbability = classProbabilities.get(className);
|
|
268
|
-
if (existingProbability !== undefined) {
|
|
269
|
-
classProbabilities.set(className, existingProbability + probability);
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
classProbabilities.set(className, probability);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
console.log('classProbabilities', classProbabilities);
|
|
276
|
-
(0, tfjs_1.dispose)(logits);
|
|
277
|
-
return classProbabilities;
|
|
278
|
-
}
|
|
279
|
-
catch (error) {
|
|
280
|
-
throw error;
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
// 모델 저장
|
|
285
|
-
saveModel(handlerOrURL, config) {
|
|
286
|
-
var _a;
|
|
287
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
-
try {
|
|
289
|
-
console.log('saveModel try', this.isTrainedDone);
|
|
290
|
-
if (!this.isTrainedDone) {
|
|
291
|
-
return Promise.reject(new Error('Train is not done status'));
|
|
292
|
-
}
|
|
293
|
-
yield ((_a = this.model) === null || _a === void 0 ? void 0 : _a.save(handlerOrURL, config));
|
|
294
|
-
}
|
|
295
|
-
catch (e) {
|
|
296
|
-
console.log('saveModel Error', e);
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
// 진행중 여부
|
|
301
|
-
running() {
|
|
302
|
-
return this.isRunning;
|
|
303
|
-
}
|
|
304
|
-
ready() {
|
|
305
|
-
return this.isReady;
|
|
306
|
-
}
|
|
307
|
-
// 모델 저장
|
|
308
|
-
_createModel(optimizer) {
|
|
309
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
-
try {
|
|
311
|
-
// 입력 이미지 크기에 맞게 모델 구조 수정
|
|
312
|
-
let varianceScaling;
|
|
313
|
-
varianceScaling = tf.initializers.varianceScaling({});
|
|
314
|
-
const trainModel = tf.sequential({
|
|
315
|
-
layers: [
|
|
316
|
-
tf.layers.dense({
|
|
317
|
-
inputShape: this.mobilenetModule.outputs[0].shape.slice(1),
|
|
318
|
-
units: 128,
|
|
319
|
-
activation: 'relu',
|
|
320
|
-
kernelInitializer: varianceScaling,
|
|
321
|
-
useBias: true
|
|
322
|
-
}),
|
|
323
|
-
tf.layers.dense({
|
|
324
|
-
kernelInitializer: varianceScaling,
|
|
325
|
-
useBias: false,
|
|
326
|
-
activation: 'softmax',
|
|
327
|
-
units: this.classNumber.length,
|
|
328
|
-
})
|
|
329
|
-
]
|
|
330
|
-
});
|
|
331
|
-
trainModel.compile({
|
|
332
|
-
loss: 'categoricalCrossentropy',
|
|
333
|
-
optimizer: optimizer,
|
|
334
|
-
metrics: ['accuracy']
|
|
335
|
-
});
|
|
336
|
-
return trainModel;
|
|
337
|
-
}
|
|
338
|
-
catch (error) {
|
|
339
|
-
console.error('Failed to load model', error);
|
|
340
|
-
throw error;
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
exports.default = LearningMobilenet;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
-
};
|
|
37
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const tf = __importStar(require("@tensorflow/tfjs"));
|
|
40
|
-
const mobilenet_1 = __importDefault(require("./mobilenet"));
|
|
41
|
-
const fs = __importStar(require("fs"));
|
|
42
|
-
const { createCanvas, loadImage } = require('canvas');
|
|
43
|
-
let imageTensor1;
|
|
44
|
-
let imageTensor2;
|
|
45
|
-
// 이미지경로를 기준으로
|
|
46
|
-
function ImagePathToTensor(imagePath) {
|
|
47
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
const imageBuffer = fs.readFileSync(imagePath);
|
|
49
|
-
const image = yield loadImage(imageBuffer);
|
|
50
|
-
const canvas = createCanvas(image.width, image.height);
|
|
51
|
-
const ctx = canvas.getContext('2d');
|
|
52
|
-
ctx.drawImage(image, 0, 0);
|
|
53
|
-
const imageData = ctx.getImageData(0, 0, image.width, image.height);
|
|
54
|
-
return tf.tensor3d(imageData.data, [imageData.height, imageData.width, 4], 'int32');
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
describe('LearningMobilenetImage', () => {
|
|
58
|
-
const learning = new mobilenet_1.default({});
|
|
59
|
-
const image1Path = path.join(__dirname, '../../public/images/image1.jpeg');
|
|
60
|
-
const image2Path = path.join(__dirname, '../../public/images/image2.jpeg');
|
|
61
|
-
console.log('Resolved path for image1:', image1Path);
|
|
62
|
-
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
-
learning.init();
|
|
64
|
-
imageTensor1 = yield ImagePathToTensor(image1Path);
|
|
65
|
-
imageTensor2 = yield ImagePathToTensor(image2Path);
|
|
66
|
-
}));
|
|
67
|
-
it('loads an image and converts it to a tensor', () => {
|
|
68
|
-
expect(imageTensor1).toBeDefined();
|
|
69
|
-
expect(imageTensor1 instanceof tf.Tensor).toBe(true);
|
|
70
|
-
expect(imageTensor2).toBeDefined();
|
|
71
|
-
expect(imageTensor2 instanceof tf.Tensor).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
// test('mobilenet add data', () => {
|
|
74
|
-
// learning.addData("라벨1", imageTensor1);
|
|
75
|
-
// learning.addData("라벨1", imageTensor1);
|
|
76
|
-
// learning.addData("라벨2", imageTensor2);
|
|
77
|
-
// learning.addData("라벨2", imageTensor2);
|
|
78
|
-
// });
|
|
79
|
-
});
|
package/dist/lib/index.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as tf from '@tensorflow/tfjs';
|
|
2
|
-
import { io } from '@tensorflow/tfjs-core';
|
|
3
|
-
interface LearningInterface {
|
|
4
|
-
model: tf.LayersModel | null;
|
|
5
|
-
isRunning: boolean;
|
|
6
|
-
isReady: boolean;
|
|
7
|
-
onProgress(progress: number): void;
|
|
8
|
-
onLoss(loss: number): void;
|
|
9
|
-
onTrainBegin(log: any): void;
|
|
10
|
-
onTrainEnd(log: any): void;
|
|
11
|
-
onEpochEnd(epoch: number, logs: any): void;
|
|
12
|
-
addData(label: string, data: any): Promise<void>;
|
|
13
|
-
train(): Promise<tf.History>;
|
|
14
|
-
infer(data: any): Promise<any>;
|
|
15
|
-
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
16
|
-
running(): boolean;
|
|
17
|
-
ready(): boolean;
|
|
18
|
-
load({ jsonURL, labels }: {
|
|
19
|
-
jsonURL: string;
|
|
20
|
-
labels: Array<string>;
|
|
21
|
-
}): Promise<void>;
|
|
22
|
-
}
|
|
23
|
-
export default LearningInterface;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import * as tf from '@tensorflow/tfjs';
|
|
2
|
-
import { io } from '@tensorflow/tfjs-core';
|
|
3
|
-
import LearningInterface from './base';
|
|
4
|
-
import DataManager from '../utils/data_manager';
|
|
5
|
-
declare class DataModel implements LearningInterface {
|
|
6
|
-
epochs: number;
|
|
7
|
-
batchSize: number;
|
|
8
|
-
learningRate: number;
|
|
9
|
-
validateRate: number;
|
|
10
|
-
isTrainedDone: boolean;
|
|
11
|
-
limitSize: number;
|
|
12
|
-
isRunning: boolean;
|
|
13
|
-
isReady: boolean;
|
|
14
|
-
model: tf.LayersModel | null;
|
|
15
|
-
dataManager: DataManager;
|
|
16
|
-
constructor({ epochs, batchSize, limitSize, learningRate, validateRate, }?: {
|
|
17
|
-
epochs?: number;
|
|
18
|
-
batchSize?: number;
|
|
19
|
-
limitSize?: number;
|
|
20
|
-
learningRate?: number;
|
|
21
|
-
validateRate?: number;
|
|
22
|
-
});
|
|
23
|
-
onProgress(progress: number): void;
|
|
24
|
-
onLoss(loss: number): void;
|
|
25
|
-
onTrainBegin(log: any): void;
|
|
26
|
-
onTrainEnd(log: any): void;
|
|
27
|
-
onEpochEnd(epoch: number, logs: any): void;
|
|
28
|
-
addData(label: string, data: number[]): Promise<void>;
|
|
29
|
-
augmentData(data: number[]): number[];
|
|
30
|
-
normalizeData(data: number[]): number[];
|
|
31
|
-
train(): Promise<tf.History>;
|
|
32
|
-
infer(data: number[]): Promise<Map<string, number>>;
|
|
33
|
-
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
34
|
-
running(): boolean;
|
|
35
|
-
ready(): boolean;
|
|
36
|
-
load({ jsonURL, labels }: {
|
|
37
|
-
jsonURL: string;
|
|
38
|
-
labels: Array<string>;
|
|
39
|
-
}): Promise<void>;
|
|
40
|
-
}
|
|
41
|
-
export default DataModel;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import * as tf from '@tensorflow/tfjs';
|
|
2
|
-
import { io } from '@tensorflow/tfjs-core';
|
|
3
|
-
import LearningInterface from './base';
|
|
4
|
-
declare class LearningMobilenet implements LearningInterface {
|
|
5
|
-
model: tf.LayersModel | null;
|
|
6
|
-
epochs: number;
|
|
7
|
-
batchSize: number;
|
|
8
|
-
learningRate: number;
|
|
9
|
-
validateRate: number;
|
|
10
|
-
isRunning: boolean;
|
|
11
|
-
isReady: boolean;
|
|
12
|
-
isTrainedDone: boolean;
|
|
13
|
-
limitSize: number;
|
|
14
|
-
mobilenetModule: tf.LayersModel | null;
|
|
15
|
-
imageExamples: Float32Array[][];
|
|
16
|
-
classNumber: string[];
|
|
17
|
-
readonly MOBILE_NET_INPUT_WIDTH = 224;
|
|
18
|
-
readonly MOBILE_NET_INPUT_HEIGHT = 224;
|
|
19
|
-
readonly MOBILE_NET_INPUT_CHANNEL = 3;
|
|
20
|
-
readonly IMAGE_NORMALIZATION_FACTOR = 255;
|
|
21
|
-
constructor({ epochs, batchSize, limitSize, learningRate, validateRate, }?: {
|
|
22
|
-
epochs?: number;
|
|
23
|
-
batchSize?: number;
|
|
24
|
-
limitSize?: number;
|
|
25
|
-
learningRate?: number;
|
|
26
|
-
validateRate?: number;
|
|
27
|
-
});
|
|
28
|
-
onProgress: (progress: number) => void;
|
|
29
|
-
onLoss: (loss: number) => void;
|
|
30
|
-
onEvents: (logs: any) => void;
|
|
31
|
-
onTrainBegin: (log: any) => void;
|
|
32
|
-
onTrainEnd: (log: any) => void;
|
|
33
|
-
onEpochEnd: (epoch: number, logs: any) => void;
|
|
34
|
-
load({ jsonURL, labels }: {
|
|
35
|
-
jsonURL: string;
|
|
36
|
-
labels: Array<string>;
|
|
37
|
-
}): Promise<void>;
|
|
38
|
-
private registerClassNumber;
|
|
39
|
-
private _convertToTfDataset;
|
|
40
|
-
addData(label: string, data: any): Promise<void>;
|
|
41
|
-
init(): Promise<void>;
|
|
42
|
-
train(): Promise<tf.History>;
|
|
43
|
-
infer(data: any): Promise<Map<string, number>>;
|
|
44
|
-
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
45
|
-
running(): boolean;
|
|
46
|
-
ready(): boolean;
|
|
47
|
-
private _createModel;
|
|
48
|
-
}
|
|
49
|
-
export default LearningMobilenet;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|