learning_model 1.0.3 → 1.0.5

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/build/index.js CHANGED
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.LearningMobilenetImage = exports.LearningImage = void 0;
7
- var image_1 = __importDefault(require("./learning/image"));
7
+ const image_1 = __importDefault(require("./learning/image"));
8
8
  exports.LearningImage = image_1.default;
9
- var mobilenet_image_1 = __importDefault(require("./learning/mobilenet_image"));
9
+ const mobilenet_image_1 = __importDefault(require("./learning/mobilenet_image"));
10
10
  exports.LearningMobilenetImage = mobilenet_image_1.default;
@@ -31,45 +31,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
31
31
  step((generator = generator.apply(thisArg, _arguments || [])).next());
32
32
  });
33
33
  };
34
- var __generator = (this && this.__generator) || function (thisArg, body) {
35
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
36
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
37
- function verb(n) { return function (v) { return step([n, v]); }; }
38
- function step(op) {
39
- if (f) throw new TypeError("Generator is already executing.");
40
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
41
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
42
- if (y = 0, t) op = [op[0] & 2, t.value];
43
- switch (op[0]) {
44
- case 0: case 1: t = op; break;
45
- case 4: _.label++; return { value: op[1], done: false };
46
- case 5: _.label++; y = op[1]; op = [0]; continue;
47
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
48
- default:
49
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
50
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
51
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
52
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
53
- if (t[2]) _.ops.pop();
54
- _.trys.pop(); continue;
55
- }
56
- op = body.call(thisArg, _);
57
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
58
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
- }
60
- };
61
34
  Object.defineProperty(exports, "__esModule", { value: true });
62
- var tf = __importStar(require("@tensorflow/tfjs"));
63
- var LearningImage = /** @class */ (function () {
64
- function LearningImage(_a) {
65
- var _b = _a === void 0 ? {} : _a, _c = _b.epochs, epochs = _c === void 0 ? 10 : _c, _d = _b.batchSize, batchSize = _d === void 0 ? 16 : _d;
35
+ const tf = __importStar(require("@tensorflow/tfjs"));
36
+ class LearningImage {
37
+ constructor({ epochs = 10, batchSize = 16, limitSize = 2, } = {}) {
66
38
  this.trainImages = [];
67
39
  this.MOBILE_NET_INPUT_WIDTH = 224;
68
40
  this.MOBILE_NET_INPUT_HEIGHT = 224;
69
41
  this.MOBILE_NET_INPUT_CHANNEL = 3;
70
42
  this.IMAGE_NORMALIZATION_FACTOR = 255.0;
71
- this.onProgress = function () { };
72
- this.onLoss = function () { };
43
+ this.onProgress = () => { };
44
+ this.onLoss = () => { };
45
+ this.onTrainBegin = () => { };
46
+ this.onTrainEnd = () => { };
73
47
  this.model = null;
74
48
  this.epochs = epochs;
75
49
  this.batchSize = batchSize;
@@ -79,9 +53,9 @@ var LearningImage = /** @class */ (function () {
79
53
  this.limitSize = 2;
80
54
  }
81
55
  // 학습 데이타 등록
82
- LearningImage.prototype.addData = function (label, data) {
56
+ addData(label, data) {
83
57
  try {
84
- var tensor = tf.browser.fromPixels(data);
58
+ const tensor = tf.browser.fromPixels(data);
85
59
  console.log('addData', tensor);
86
60
  this.trainImages.push(tensor);
87
61
  this.labels.push(label);
@@ -94,163 +68,140 @@ var LearningImage = /** @class */ (function () {
94
68
  console.error('Model training failed', error);
95
69
  throw error;
96
70
  }
97
- };
71
+ }
98
72
  // 모델 학습 처리
99
- LearningImage.prototype.train = function () {
100
- return __awaiter(this, void 0, void 0, function () {
101
- var customCallback, _a, inputData, targetData, history_1, error_1;
102
- var _this = this;
103
- return __generator(this, function (_b) {
104
- switch (_b.label) {
105
- case 0:
106
- if (this.isRunning) {
107
- return [2 /*return*/, Promise.reject(new Error('Training is already in progress.'))];
108
- }
109
- customCallback = {
110
- onTrainBegin: function () {
111
- console.log('Training has started.');
112
- },
113
- onTrainEnd: function () {
114
- console.log('Training has ended.');
115
- _this.isRunning = false;
116
- },
117
- onBatchBegin: function (batch, logs) {
118
- console.log("Batch ".concat(batch, " is starting."));
119
- },
120
- onBatchEnd: function (batch, logs) {
121
- console.log("Batch ".concat(batch, " has ended."));
122
- },
123
- onEpochBegin: function (epoch, logs) {
124
- var progress = Math.floor(((epoch + 1) / _this.epochs) * 100);
125
- _this.onProgress(progress);
126
- console.log("Epoch ".concat(epoch + 1, " is starting."));
127
- },
128
- onEpochEnd: function (epoch, logs) {
129
- console.log("Epoch ".concat(epoch + 1, " has ended."));
130
- _this.onLoss(logs.loss);
131
- console.log('Loss:', logs.loss);
132
- }
133
- };
134
- _b.label = 1;
135
- case 1:
136
- _b.trys.push([1, 4, , 5]);
137
- this.isRunning = true;
138
- if (this.labels.length < this.limitSize) {
139
- return [2 /*return*/, Promise.reject(new Error('Please train Data need over 2 data length'))];
140
- }
141
- _a = this;
142
- return [4 /*yield*/, this._createModel(this.labels.length)];
143
- case 2:
144
- _a.model = _b.sent();
145
- inputData = this._preprocessedInputData(this.model);
146
- targetData = this._preprocessedTargetData();
147
- return [4 /*yield*/, this.model.fit(inputData, targetData, {
148
- epochs: this.epochs,
149
- batchSize: this.batchSize,
150
- callbacks: customCallback
151
- })];
152
- case 3:
153
- history_1 = _b.sent();
154
- console.log('Model training completed', history_1);
155
- return [2 /*return*/, history_1];
156
- case 4:
157
- error_1 = _b.sent();
158
- this.isRunning = false;
159
- console.error('Model training failed', error_1);
160
- throw error_1;
161
- case 5: return [2 /*return*/];
73
+ train() {
74
+ return __awaiter(this, void 0, void 0, function* () {
75
+ if (this.isRunning) {
76
+ return Promise.reject(new Error('Training is already in progress.'));
77
+ }
78
+ // 콜백 정의
79
+ const customCallback = {
80
+ onTrainBegin: (log) => {
81
+ this.onTrainBegin(log);
82
+ console.log('Training has started.');
83
+ },
84
+ onTrainEnd: (log) => {
85
+ this.onTrainEnd(log);
86
+ console.log('Training has ended.');
87
+ this.isRunning = false;
88
+ },
89
+ onBatchBegin: (batch, logs) => {
90
+ console.log(`Batch ${batch} is starting.`);
91
+ },
92
+ onBatchEnd: (batch, logs) => {
93
+ console.log(`Batch ${batch} has ended.`);
94
+ },
95
+ onEpochBegin: (epoch, logs) => {
96
+ //const progress = Math.floor(((epoch + 1) / this.epochs) * 100);
97
+ this.onProgress(epoch + 1);
98
+ console.log(`Epoch ${epoch + 1} is starting.`);
99
+ },
100
+ onEpochEnd: (epoch, logs) => {
101
+ console.log(`Epoch ${epoch + 1} has ended.`);
102
+ this.onLoss(logs.loss);
103
+ console.log('Loss:', logs.loss);
104
+ }
105
+ };
106
+ try {
107
+ this.isRunning = true;
108
+ if (this.labels.length < this.limitSize) {
109
+ return Promise.reject(new Error('Please train Data need over 2 data length'));
162
110
  }
163
- });
111
+ this.model = yield this._createModel(this.labels.length);
112
+ const inputData = this._preprocessedInputData(this.model);
113
+ const targetData = this._preprocessedTargetData();
114
+ const history = yield this.model.fit(inputData, targetData, {
115
+ epochs: this.epochs,
116
+ batchSize: this.batchSize,
117
+ callbacks: customCallback
118
+ });
119
+ console.log('Model training completed', history);
120
+ return history;
121
+ }
122
+ catch (error) {
123
+ this.isRunning = false;
124
+ console.error('Model training failed', error);
125
+ throw error;
126
+ }
164
127
  });
165
- };
128
+ }
166
129
  // 추론하기
167
- LearningImage.prototype.infer = function (data) {
168
- return __awaiter(this, void 0, void 0, function () {
169
- var tensor, resizedTensor, reshapedTensor, predictions, predictionsData, classProbabilities, i, className, probability, existingProbability, error_2;
170
- return __generator(this, function (_a) {
171
- switch (_a.label) {
172
- case 0:
173
- if (this.model === null) {
174
- throw new Error('Model is null');
175
- }
176
- _a.label = 1;
177
- case 1:
178
- _a.trys.push([1, 3, , 4]);
179
- tensor = tf.browser.fromPixels(data);
180
- resizedTensor = tf.image.resizeBilinear(tensor, [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT]);
181
- reshapedTensor = resizedTensor.expandDims(0);
182
- predictions = this.model.predict(reshapedTensor);
183
- return [4 /*yield*/, predictions.data()];
184
- case 2:
185
- predictionsData = _a.sent();
186
- classProbabilities = new Map();
187
- for (i = 0; i < predictionsData.length; i++) {
188
- className = this.labels[i];
189
- probability = predictionsData[i];
190
- existingProbability = classProbabilities.get(className);
191
- if (existingProbability !== undefined) {
192
- classProbabilities.set(className, existingProbability + probability);
193
- }
194
- else {
195
- classProbabilities.set(className, probability);
196
- }
197
- }
198
- console.log('Class Probabilities:', classProbabilities);
199
- return [2 /*return*/, classProbabilities];
200
- case 3:
201
- error_2 = _a.sent();
202
- throw error_2;
203
- case 4: return [2 /*return*/];
130
+ infer(data) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ if (this.model === null) {
133
+ throw new Error('Model is null');
134
+ }
135
+ try {
136
+ const tensor = tf.browser.fromPixels(data);
137
+ const resizedTensor = tf.image.resizeBilinear(tensor, [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT]);
138
+ const reshapedTensor = resizedTensor.expandDims(0); // 배치 크기 1을 추가하여 4차원으로 변환
139
+ const predictions = this.model.predict(reshapedTensor);
140
+ const predictionsData = yield predictions.data(); // 예측 텐서의 데이터를 비동기로 가져옴
141
+ const classProbabilities = new Map(); // 클래스별 확률 누적값을 저장할 맵
142
+ for (let i = 0; i < predictionsData.length; i++) {
143
+ const className = this.labels[i]; // 클래스 이름
144
+ const probability = predictionsData[i];
145
+ const existingProbability = classProbabilities.get(className);
146
+ if (existingProbability !== undefined) {
147
+ classProbabilities.set(className, existingProbability + probability);
148
+ }
149
+ else {
150
+ classProbabilities.set(className, probability);
151
+ }
204
152
  }
205
- });
153
+ console.log('Class Probabilities:', classProbabilities);
154
+ return classProbabilities;
155
+ }
156
+ catch (error) {
157
+ throw error;
158
+ }
206
159
  });
207
- };
160
+ }
208
161
  // 모델 저장
209
- LearningImage.prototype.saveModel = function () {
162
+ saveModel() {
210
163
  console.log('saved model');
211
- };
164
+ }
212
165
  // 진행중 여부
213
- LearningImage.prototype.running = function () {
166
+ running() {
214
167
  return this.isRunning;
215
- };
216
- LearningImage.prototype.ready = function () {
168
+ }
169
+ ready() {
217
170
  return this.isReady;
218
- };
171
+ }
219
172
  // target 라벨 데이타
220
- LearningImage.prototype._preprocessedTargetData = function () {
221
- var _this = this;
173
+ _preprocessedTargetData() {
222
174
  // 라벨 unique 처리 & 배열 리턴
223
175
  console.log('uniqueLabels.length', this.labels, this.labels.length);
224
- var labelIndices = this.labels.map(function (label) { return _this.labels.indexOf(label); });
176
+ const labelIndices = this.labels.map((label) => this.labels.indexOf(label));
225
177
  console.log('labelIndices', labelIndices);
226
- var oneHotEncode = tf.oneHot(tf.tensor1d(labelIndices, 'int32'), this.labels.length);
178
+ const oneHotEncode = tf.oneHot(tf.tensor1d(labelIndices, 'int32'), this.labels.length);
227
179
  console.log('oneHotEncode', oneHotEncode);
228
180
  return oneHotEncode;
229
- };
181
+ }
230
182
  // 입력 이미지 데이타
231
- LearningImage.prototype._preprocessedInputData = function (model) {
232
- var _this = this;
183
+ _preprocessedInputData(model) {
233
184
  // 이미지 배열을 배치로 변환 - [null, 224, 224, 3]
234
- var inputShape = model.inputs[0].shape;
185
+ const inputShape = model.inputs[0].shape;
235
186
  console.log('inputShape', inputShape);
236
187
  // inputShape를 이와 같이 포멧 맞춘다. for reshape to [224, 224, 3]
237
- var inputShapeArray = inputShape.slice(1);
188
+ const inputShapeArray = inputShape.slice(1);
238
189
  console.log('inputShapeArray', inputShapeArray);
239
- var inputBatch = tf.stack(this.trainImages.map(function (image) {
190
+ const inputBatch = tf.stack(this.trainImages.map((image) => {
240
191
  // 이미지 전처리 및 크기 조정 등을 수행한 후에
241
192
  // 모델의 입력 형태로 변환하여 반환
242
- var xs = _this._preprocessData(image); // 전처리 함수는 사용자 정의해야 함
193
+ const xs = this._preprocessData(image); // 전처리 함수는 사용자 정의해야 함
243
194
  return tf.reshape(xs, inputShapeArray);
244
195
  }));
245
196
  return inputBatch;
246
- };
197
+ }
247
198
  // 모델 학습하기 위한 데이타 전처리 단계
248
- LearningImage.prototype._preprocessData = function (tensor) {
199
+ _preprocessData(tensor) {
249
200
  try {
250
201
  // mobilenet model summary를 하면 위와 같이 224,224 사이즈의 입력값 설정되어 있다. ex) input_1 (InputLayer) [null,224,224,3]
251
- var resizedImage = tf.image.resizeBilinear(tensor, [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT]);
202
+ const resizedImage = tf.image.resizeBilinear(tensor, [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT]);
252
203
  // 이미지를 [0,1] 범위로 정규화 255로 나뉜 픽셀값
253
- var normalizedImage = resizedImage.div(this.IMAGE_NORMALIZATION_FACTOR);
204
+ const normalizedImage = resizedImage.div(this.IMAGE_NORMALIZATION_FACTOR);
254
205
  // expandDims(0)을 하여 차원을 추가하여 4D텐서 반환
255
206
  return normalizedImage.expandDims(0);
256
207
  }
@@ -258,49 +209,44 @@ var LearningImage = /** @class */ (function () {
258
209
  console.error('Failed to _preprocessData data', error);
259
210
  throw error;
260
211
  }
261
- };
212
+ }
262
213
  // 모델 저장
263
- LearningImage.prototype._createModel = function (numClasses) {
264
- return __awaiter(this, void 0, void 0, function () {
265
- var inputShape, model;
266
- return __generator(this, function (_a) {
267
- try {
268
- inputShape = [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT, this.MOBILE_NET_INPUT_CHANNEL];
269
- model = tf.sequential();
270
- model.add(tf.layers.conv2d({
271
- inputShape: inputShape,
272
- filters: 32,
273
- kernelSize: 3,
274
- activation: 'relu'
275
- }));
276
- model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
277
- model.add(tf.layers.conv2d({
278
- filters: 64,
279
- kernelSize: 3,
280
- activation: 'relu'
281
- }));
282
- model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
283
- model.add(tf.layers.flatten());
284
- model.add(tf.layers.dense({
285
- units: numClasses,
286
- activation: 'softmax'
287
- }));
288
- model.compile({
289
- loss: (numClasses === 2) ? 'binaryCrossentropy' : 'categoricalCrossentropy',
290
- optimizer: tf.train.adam(),
291
- metrics: ['accuracy']
292
- });
293
- model.summary();
294
- return [2 /*return*/, model];
295
- }
296
- catch (error) {
297
- console.error('Failed to load model', error);
298
- throw error;
299
- }
300
- return [2 /*return*/];
301
- });
214
+ _createModel(numClasses) {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ try {
217
+ const inputShape = [this.MOBILE_NET_INPUT_WIDTH, this.MOBILE_NET_INPUT_HEIGHT, this.MOBILE_NET_INPUT_CHANNEL];
218
+ const model = tf.sequential();
219
+ model.add(tf.layers.conv2d({
220
+ inputShape,
221
+ filters: 32,
222
+ kernelSize: 3,
223
+ activation: 'relu'
224
+ }));
225
+ model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
226
+ model.add(tf.layers.conv2d({
227
+ filters: 64,
228
+ kernelSize: 3,
229
+ activation: 'relu'
230
+ }));
231
+ model.add(tf.layers.maxPooling2d({ poolSize: 2 }));
232
+ model.add(tf.layers.flatten());
233
+ model.add(tf.layers.dense({
234
+ units: numClasses,
235
+ activation: 'softmax'
236
+ }));
237
+ model.compile({
238
+ loss: (numClasses === 2) ? 'binaryCrossentropy' : 'categoricalCrossentropy',
239
+ optimizer: tf.train.adam(),
240
+ metrics: ['accuracy']
241
+ });
242
+ model.summary();
243
+ return model;
244
+ }
245
+ catch (error) {
246
+ console.error('Failed to load model', error);
247
+ throw error;
248
+ }
302
249
  });
303
- };
304
- return LearningImage;
305
- }());
250
+ }
251
+ }
306
252
  exports.default = LearningImage;