learning_model 1.0.51 → 1.0.53

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/Makefile CHANGED
@@ -2,4 +2,10 @@ install:
2
2
  npm install --save-dev ts-jest
3
3
 
4
4
  ts:
5
- yarn test
5
+ yarn test
6
+
7
+ build:
8
+ npm run tsc
9
+
10
+ publish: build
11
+ npm publish
@@ -1,5 +1,4 @@
1
1
  import * as tf from '@tensorflow/tfjs';
2
- import '@tensorflow/tfjs-backend-wasm';
3
2
  import { io } from '@tensorflow/tfjs-core';
4
3
  import LearningInterface from './base';
5
4
  declare class LearningMobilenet implements LearningInterface {
@@ -38,7 +38,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  const tf = __importStar(require("@tensorflow/tfjs"));
41
- require("@tensorflow/tfjs-backend-wasm"); // WebAssembly 백엔드 추가
41
+ const tfjs_backend_wasm_1 = require("@tensorflow/tfjs-backend-wasm");
42
42
  const tfjs_1 = require("@tensorflow/tfjs");
43
43
  const tf_1 = require("../utils/tf");
44
44
  const canvas_1 = require("../utils/canvas");
@@ -187,8 +187,6 @@ class LearningMobilenet {
187
187
  return __awaiter(this, void 0, void 0, function* () {
188
188
  const isWasmSupported = yield this.checkWasmSupport();
189
189
  if (isWasmSupported) {
190
- yield tf.setBackend('wasm');
191
- yield tf.ready();
192
190
  console.log('Backend is set to WebAssembly');
193
191
  }
194
192
  else {
@@ -201,6 +199,8 @@ class LearningMobilenet {
201
199
  checkWasmSupport() {
202
200
  return __awaiter(this, void 0, void 0, function* () {
203
201
  try {
202
+ const wasmVersion = tf.version['tfjs-backend-wasm'] || tf.version['tfjs-core'];
203
+ (0, tfjs_backend_wasm_1.setWasmPaths)(`https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${wasmVersion}/dist/`);
204
204
  yield tf.setBackend('wasm');
205
205
  yield tf.ready();
206
206
  return true;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DataModel = exports.LearningMobilenet = void 0;
7
+ const mobilenet_1 = __importDefault(require("./learning/mobilenet"));
8
+ exports.LearningMobilenet = mobilenet_1.default;
9
+ const data_model_1 = __importDefault(require("./learning/data_model"));
10
+ exports.DataModel = data_model_1.default;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,215 @@
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ const tf = __importStar(require("@tensorflow/tfjs"));
49
+ const data_manager_1 = __importDefault(require("../utils/data_manager"));
50
+ class DataModel {
51
+ constructor({ epochs = 50, batchSize = 16, limitSize = 2, learningRate = 0.001, validateRate = 0.15, } = {}) {
52
+ this.model = null;
53
+ this.dataManager = new data_manager_1.default();
54
+ this.epochs = epochs;
55
+ this.batchSize = batchSize;
56
+ this.learningRate = learningRate;
57
+ this.validateRate = validateRate;
58
+ this.isRunning = false;
59
+ this.isReady = false;
60
+ this.isTrainedDone = false;
61
+ this.limitSize = limitSize;
62
+ }
63
+ onProgress(progress) {
64
+ console.log(`Training progress: ${progress}%`);
65
+ }
66
+ onLoss(loss) {
67
+ console.log(`Loss: ${loss}`);
68
+ }
69
+ onTrainBegin(log) {
70
+ console.log('Training started', log);
71
+ }
72
+ onTrainEnd(log) {
73
+ console.log('Training ended', log);
74
+ }
75
+ onEpochEnd(epoch, logs) {
76
+ console.log(`Epoch ${epoch} ended with logs:`, logs);
77
+ }
78
+ addData(label, data) {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ const normalizedData = this.normalizeData(data);
81
+ const augmentedData = this.augmentData(normalizedData);
82
+ yield this.dataManager.addData(label, augmentedData);
83
+ });
84
+ }
85
+ augmentData(data) {
86
+ return data.map(value => value + (Math.random() * 0.1 - 0.05)); // 약간의 노이즈 추가
87
+ }
88
+ normalizeData(data) {
89
+ const mean = data.reduce((sum, value) => sum + value, 0) / data.length;
90
+ const std = Math.sqrt(data.reduce((sum, value) => sum + Math.pow(value - mean, 2), 0) / data.length);
91
+ return data.map(value => (value - mean) / std);
92
+ }
93
+ train() {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ if (this.isRunning) {
96
+ throw new Error('Training is already in progress');
97
+ }
98
+ const { xs, ys } = this.dataManager.convertToTensors();
99
+ const jointModel = tf.sequential();
100
+ jointModel.add(tf.layers.dense({
101
+ units: 32,
102
+ activation: 'relu',
103
+ inputShape: [xs.shape[1]],
104
+ kernelRegularizer: tf.regularizers.l2({ l2: 0.01 }) // L2 정규화 추가
105
+ }));
106
+ jointModel.add(tf.layers.dropout({ rate: 0.5 })); // 드롭아웃 레이어 추가
107
+ jointModel.add(tf.layers.dense({
108
+ units: 16,
109
+ activation: 'relu',
110
+ kernelRegularizer: tf.regularizers.l2({ l2: 0.01 }) // L2 정규화 추가
111
+ }));
112
+ jointModel.add(tf.layers.dropout({ rate: 0.5 })); // 드롭아웃 레이어 추가
113
+ jointModel.add(tf.layers.dense({ units: Object.keys(this.dataManager.getLabelMap()).length, activation: 'softmax' }));
114
+ jointModel.compile({
115
+ optimizer: tf.train.adam(this.learningRate), // 학습률 조정
116
+ loss: 'sparseCategoricalCrossentropy',
117
+ metrics: ['accuracy']
118
+ });
119
+ this.model = jointModel;
120
+ this.isRunning = true;
121
+ const history = yield jointModel.fit(xs, ys, {
122
+ epochs: this.epochs,
123
+ batchSize: this.batchSize,
124
+ validationSplit: 0.2,
125
+ callbacks: {
126
+ onEpochEnd: (epoch, logs) => this.onEpochEnd(epoch, logs),
127
+ onBatchEnd: (batch, logs) => {
128
+ },
129
+ onTrainBegin: (logs) => this.onTrainBegin(logs),
130
+ onTrainEnd: (logs) => {
131
+ this.isRunning = false;
132
+ this.isReady = true;
133
+ this.onTrainEnd(logs);
134
+ },
135
+ }
136
+ });
137
+ return history;
138
+ });
139
+ }
140
+ infer(data) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ if (!this.isReady || !this.model) {
143
+ throw new Error('Model is not ready');
144
+ }
145
+ // 입력 데이터를 텐서로 변환
146
+ const input = tf.tensor2d([data], [1, data.length], 'float32');
147
+ try {
148
+ // 모델 예측 수행
149
+ const prediction = this.model.predict(input);
150
+ // 예측 결과 값들을 추출
151
+ const values = yield prediction.data();
152
+ // 클래스 이름과 확률을 저장할 Map 생성
153
+ const classProbabilities = new Map();
154
+ const EPSILON = 1e-6; // 매우 작은 값을 표현하기 위한 엡실론
155
+ // 라벨 맵을 가져옴
156
+ const labelMap = this.dataManager.getLabelMap();
157
+ const reverseLabelMap = Object.entries(labelMap).reduce((acc, [key, value]) => {
158
+ acc[value] = key;
159
+ return acc;
160
+ }, {});
161
+ // 각 클래스의 확률 계산 및 조정
162
+ for (let i = 0; i < values.length; i++) {
163
+ let probability = Math.max(0, Math.min(1, values[i])); // 확률 값을 0과 1 사이로 조정
164
+ probability = probability < EPSILON ? 0 : probability; // 매우 작은 확률 값을 0으로 간주
165
+ const className = reverseLabelMap[i]; // 클래스 이름을 문자열로 가져옴
166
+ if (className) {
167
+ const existingProbability = classProbabilities.get(className);
168
+ if (existingProbability !== undefined) {
169
+ classProbabilities.set(className, existingProbability + probability);
170
+ }
171
+ else {
172
+ classProbabilities.set(className, probability);
173
+ }
174
+ }
175
+ }
176
+ // 텐서 해제
177
+ prediction.dispose();
178
+ input.dispose();
179
+ console.log('classProbabilities', classProbabilities);
180
+ return classProbabilities;
181
+ }
182
+ catch (error) {
183
+ // 텐서 해제
184
+ input.dispose();
185
+ throw error;
186
+ }
187
+ });
188
+ }
189
+ saveModel(handlerOrURL, config) {
190
+ return __awaiter(this, void 0, void 0, function* () {
191
+ if (!this.model) {
192
+ throw new Error('No model to save');
193
+ }
194
+ yield this.model.save(handlerOrURL, config);
195
+ });
196
+ }
197
+ running() {
198
+ return this.isRunning;
199
+ }
200
+ ready() {
201
+ return this.isReady;
202
+ }
203
+ load(_a) {
204
+ return __awaiter(this, arguments, void 0, function* ({ jsonURL, labels }) {
205
+ this.model = yield tf.loadLayersModel(jsonURL);
206
+ this.isReady = true;
207
+ // Assuming the labels are provided in the correct order
208
+ this.dataManager = new data_manager_1.default();
209
+ labels.forEach((label, index) => {
210
+ this.dataManager.getLabelMap()[label] = index;
211
+ });
212
+ });
213
+ }
214
+ }
215
+ exports.default = DataModel;
@@ -0,0 +1,56 @@
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,5 +1,4 @@
1
1
  import * as tf from '@tensorflow/tfjs';
2
- import '@tensorflow/tfjs-backend-wasm';
3
2
  import { io } from '@tensorflow/tfjs-core';
4
3
  import LearningInterface from './base';
5
4
  declare class LearningMobilenet implements LearningInterface {