learning_model 1.0.46 → 1.0.47
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.
|
@@ -29,7 +29,7 @@ declare class DataModel implements LearningInterface {
|
|
|
29
29
|
augmentData(data: number[]): number[];
|
|
30
30
|
normalizeData(data: number[]): number[];
|
|
31
31
|
train(): Promise<tf.History>;
|
|
32
|
-
infer(data: number[]): Promise<
|
|
32
|
+
infer(data: number[]): Promise<Map<string, number>>;
|
|
33
33
|
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
34
34
|
running(): boolean;
|
|
35
35
|
ready(): boolean;
|
|
@@ -132,10 +132,48 @@ class DataModel {
|
|
|
132
132
|
if (!this.isReady || !this.model) {
|
|
133
133
|
throw new Error('Model is not ready');
|
|
134
134
|
}
|
|
135
|
+
// 입력 데이터를 텐서로 변환
|
|
135
136
|
const input = tf.tensor2d([data], [1, data.length], 'float32');
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
try {
|
|
138
|
+
// 모델 예측 수행
|
|
139
|
+
const prediction = this.model.predict(input);
|
|
140
|
+
// 예측 결과 값들을 추출
|
|
141
|
+
const values = yield prediction.data();
|
|
142
|
+
// 클래스 이름과 확률을 저장할 Map 생성
|
|
143
|
+
const classProbabilities = new Map();
|
|
144
|
+
const EPSILON = 1e-6; // 매우 작은 값을 표현하기 위한 엡실론
|
|
145
|
+
// 라벨 맵을 가져옴
|
|
146
|
+
const labelMap = this.dataManager.getLabelMap();
|
|
147
|
+
const reverseLabelMap = Object.entries(labelMap).reduce((acc, [key, value]) => {
|
|
148
|
+
acc[value] = key;
|
|
149
|
+
return acc;
|
|
150
|
+
}, {});
|
|
151
|
+
// 각 클래스의 확률 계산 및 조정
|
|
152
|
+
for (let i = 0; i < values.length; i++) {
|
|
153
|
+
let probability = Math.max(0, Math.min(1, values[i])); // 확률 값을 0과 1 사이로 조정
|
|
154
|
+
probability = probability < EPSILON ? 0 : probability; // 매우 작은 확률 값을 0으로 간주
|
|
155
|
+
const className = reverseLabelMap[i]; // 클래스 이름을 문자열로 가져옴
|
|
156
|
+
if (className) {
|
|
157
|
+
const existingProbability = classProbabilities.get(className);
|
|
158
|
+
if (existingProbability !== undefined) {
|
|
159
|
+
classProbabilities.set(className, existingProbability + probability);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
classProbabilities.set(className, probability);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// 텐서 해제
|
|
167
|
+
prediction.dispose();
|
|
168
|
+
input.dispose();
|
|
169
|
+
console.log('classProbabilities', classProbabilities);
|
|
170
|
+
return classProbabilities;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
// 텐서 해제
|
|
174
|
+
input.dispose();
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
139
177
|
});
|
|
140
178
|
}
|
|
141
179
|
saveModel(handlerOrURL, config) {
|
|
@@ -16,7 +16,9 @@ const data_model_1 = __importDefault(require("./data_model"));
|
|
|
16
16
|
describe('LearningModel', () => {
|
|
17
17
|
let learningModel;
|
|
18
18
|
beforeEach(() => {
|
|
19
|
-
learningModel = new data_model_1.default(
|
|
19
|
+
learningModel = new data_model_1.default({
|
|
20
|
+
epochs: 10,
|
|
21
|
+
});
|
|
20
22
|
});
|
|
21
23
|
it('should add sufficient data and train the model', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
24
|
// 훈련 데이터 생성
|
|
@@ -39,6 +41,7 @@ describe('LearningModel', () => {
|
|
|
39
41
|
const classLabel = i % 2 === 0 ? 'class1' : 'class2'; // 두 개의 클래스를 번갈아가며 생성
|
|
40
42
|
const data = Array.from({ length: 3 }, () => Math.random() * 10); // 임의의 데이터 생성
|
|
41
43
|
yield learningModel.addData(classLabel, data);
|
|
44
|
+
yield learningModel.addData(classLabel, [1, 2, 4]);
|
|
42
45
|
}
|
|
43
46
|
// 모델 훈련
|
|
44
47
|
yield learningModel.train();
|
|
@@ -49,6 +52,5 @@ describe('LearningModel', () => {
|
|
|
49
52
|
console.log('result', result);
|
|
50
53
|
// 결과 평가
|
|
51
54
|
expect(result).toBeDefined();
|
|
52
|
-
expect(['class1', 'class2']).toContain(result);
|
|
53
55
|
}), 30000);
|
|
54
56
|
});
|
|
@@ -29,7 +29,7 @@ declare class DataModel implements LearningInterface {
|
|
|
29
29
|
augmentData(data: number[]): number[];
|
|
30
30
|
normalizeData(data: number[]): number[];
|
|
31
31
|
train(): Promise<tf.History>;
|
|
32
|
-
infer(data: number[]): Promise<
|
|
32
|
+
infer(data: number[]): Promise<Map<string, number>>;
|
|
33
33
|
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
34
34
|
running(): boolean;
|
|
35
35
|
ready(): boolean;
|
|
@@ -4,7 +4,9 @@ describe('LearningModel', () => {
|
|
|
4
4
|
let learningModel: LearningModel;
|
|
5
5
|
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
learningModel = new LearningModel(
|
|
7
|
+
learningModel = new LearningModel({
|
|
8
|
+
epochs: 10,
|
|
9
|
+
});
|
|
8
10
|
});
|
|
9
11
|
|
|
10
12
|
it('should add sufficient data and train the model', async () => {
|
|
@@ -32,6 +34,7 @@ describe('LearningModel', () => {
|
|
|
32
34
|
const classLabel = i % 2 === 0 ? 'class1' : 'class2'; // 두 개의 클래스를 번갈아가며 생성
|
|
33
35
|
const data = Array.from({ length: 3 }, () => Math.random() * 10); // 임의의 데이터 생성
|
|
34
36
|
await learningModel.addData(classLabel, data);
|
|
37
|
+
await learningModel.addData(classLabel, [1,2,4]);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
// 모델 훈련
|
|
@@ -46,6 +49,5 @@ describe('LearningModel', () => {
|
|
|
46
49
|
|
|
47
50
|
// 결과 평가
|
|
48
51
|
expect(result).toBeDefined();
|
|
49
|
-
expect(['class1', 'class2']).toContain(result);
|
|
50
52
|
}, 30000);
|
|
51
53
|
});
|
|
@@ -122,17 +122,63 @@ class DataModel implements LearningInterface {
|
|
|
122
122
|
return history;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
async infer(data: number[]): Promise<
|
|
125
|
+
public async infer(data: number[]): Promise<Map<string, number>> {
|
|
126
126
|
if (!this.isReady || !this.model) {
|
|
127
127
|
throw new Error('Model is not ready');
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// 입력 데이터를 텐서로 변환
|
|
130
131
|
const input = tf.tensor2d([data], [1, data.length], 'float32');
|
|
131
|
-
const prediction = this.model.predict(input) as tf.Tensor;
|
|
132
|
-
const result = prediction.argMax(-1).dataSync()[0];
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
try {
|
|
134
|
+
// 모델 예측 수행
|
|
135
|
+
const prediction = this.model.predict(input) as tf.Tensor<tf.Rank>;
|
|
136
|
+
|
|
137
|
+
// 예측 결과 값들을 추출
|
|
138
|
+
const values = await prediction.data();
|
|
139
|
+
|
|
140
|
+
// 클래스 이름과 확률을 저장할 Map 생성
|
|
141
|
+
const classProbabilities = new Map<string, number>();
|
|
142
|
+
const EPSILON = 1e-6; // 매우 작은 값을 표현하기 위한 엡실론
|
|
143
|
+
|
|
144
|
+
// 라벨 맵을 가져옴
|
|
145
|
+
const labelMap = this.dataManager.getLabelMap();
|
|
146
|
+
const reverseLabelMap = Object.entries(labelMap).reduce((acc, [key, value]) => {
|
|
147
|
+
acc[value] = key;
|
|
148
|
+
return acc;
|
|
149
|
+
}, {} as { [key: number]: string });
|
|
150
|
+
|
|
151
|
+
// 각 클래스의 확률 계산 및 조정
|
|
152
|
+
for (let i = 0; i < values.length; i++) {
|
|
153
|
+
let probability = Math.max(0, Math.min(1, values[i])); // 확률 값을 0과 1 사이로 조정
|
|
154
|
+
probability = probability < EPSILON ? 0 : probability; // 매우 작은 확률 값을 0으로 간주
|
|
155
|
+
const className = reverseLabelMap[i]; // 클래스 이름을 문자열로 가져옴
|
|
156
|
+
if (className) {
|
|
157
|
+
const existingProbability = classProbabilities.get(className);
|
|
158
|
+
if (existingProbability !== undefined) {
|
|
159
|
+
classProbabilities.set(className, existingProbability + probability);
|
|
160
|
+
} else {
|
|
161
|
+
classProbabilities.set(className, probability);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 텐서 해제
|
|
167
|
+
prediction.dispose();
|
|
168
|
+
input.dispose();
|
|
169
|
+
|
|
170
|
+
console.log('classProbabilities', classProbabilities);
|
|
171
|
+
return classProbabilities;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// 텐서 해제
|
|
174
|
+
input.dispose();
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
135
177
|
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
136
182
|
|
|
137
183
|
async saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void> {
|
|
138
184
|
if (!this.model) {
|