learning_model 1.0.0 → 1.0.2
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/image.js +306 -0
- package/build/index.js +4 -194
- package/build/learning/image.js +10 -6
- package/build/learning/mobilenet_image.js +10 -6
- package/build/mobilenet_image.js +315 -0
- package/build/public/index.js +200 -0
- package/build/src/learning/base.js +2 -0
- package/build/src/learning/image.js +306 -0
- package/build/src/learning/mobilenet_image.js +315 -0
- package/package-lock.json +13302 -0
- package/package.json +11 -4
- package/public/index.ts +153 -0
- package/src/index.ts +5 -2
- package/tsconfig.json +2 -1
- package/types/index.d.ts +3 -1
- package/types/public/index.d.ts +1 -0
- package/types/src/index.d.ts +3 -0
- package/types/src/learning/base.d.ts +19 -0
- package/types/src/learning/image.d.ts +34 -0
- package/types/src/learning/mobilenet_image.d.ts +36 -0
- package/dist/index.bundle.js +0 -134179
- package/dist/index.html +0 -13
- package/dist/index.js +0 -154
- package/dist/learning/image.js +0 -244
- package/dist/learning/mobilenet_image.js +0 -248
- package/dist/learning/util.js +0 -14
- /package/{dist/learning → build}/base.js +0 -0
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "learning_model",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "learning model develop",
|
|
5
5
|
"main": "dist/index.bundle.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
6
|
+
"types": "dist/types/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "webpack serve --open --mode development",
|
|
9
|
-
"
|
|
9
|
+
"watch": "webpack --watch --mode=development",
|
|
10
|
+
"build": "tsc && webpack",
|
|
11
|
+
"tsc": "tsc"
|
|
10
12
|
},
|
|
11
13
|
"keywords": [
|
|
12
14
|
"tensorflow"
|
|
@@ -16,20 +18,25 @@
|
|
|
16
18
|
"dependencies": {
|
|
17
19
|
"@tensorflow-models/mobilenet": "^2.1.0",
|
|
18
20
|
"@tensorflow/tfjs": "^4.6.0",
|
|
19
|
-
"
|
|
21
|
+
"@tensorflow/tfjs-layers": "^4.6.0",
|
|
22
|
+
"canvas": "^2.11.2",
|
|
23
|
+
"learning_model": "^1.0.0"
|
|
20
24
|
},
|
|
21
25
|
"devDependencies": {
|
|
22
26
|
"@babel/core": "^7.15.0",
|
|
23
27
|
"@babel/preset-env": "^7.15.0",
|
|
24
28
|
"babel-loader": "^8.2.2",
|
|
25
29
|
"clean-webpack-plugin": "^4.0.0",
|
|
30
|
+
"copy-webpack-plugin": "^11.0.0",
|
|
26
31
|
"css-loader": "^6.8.1",
|
|
27
32
|
"glob": "^7.1.7",
|
|
28
33
|
"html-webpack-plugin": "^5.5.1",
|
|
29
34
|
"style-loader": "^3.3.3",
|
|
35
|
+
"terser-webpack-plugin": "^5.3.9",
|
|
30
36
|
"ts-loader": "^9.4.3",
|
|
31
37
|
"typescript": "^4.4.4",
|
|
32
38
|
"webpack": "^5.51.1",
|
|
39
|
+
"webpack-bundle-analyzer": "^4.8.0",
|
|
33
40
|
"webpack-cli": "^4.8.0",
|
|
34
41
|
"webpack-dev-server": "^4.1.0"
|
|
35
42
|
}
|
package/public/index.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
|
|
2
|
+
import LearningImage from '../src/learning/image';
|
|
3
|
+
|
|
4
|
+
// 프로그레스 바를 표시하는 클래스
|
|
5
|
+
class StatusBar {
|
|
6
|
+
constructor(private container: HTMLElement) {}
|
|
7
|
+
update(status: number, message: string) {
|
|
8
|
+
this.container.innerText = `Status: ${status} ${message}`;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async function appRun() {
|
|
14
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
15
|
+
const learningImage = new LearningImage({
|
|
16
|
+
epochs: 30,
|
|
17
|
+
batchSize: 32
|
|
18
|
+
});
|
|
19
|
+
learningImage.onProgress = (progress: number) => {
|
|
20
|
+
const element = document.getElementById('progress-bar');
|
|
21
|
+
if (element !== null) {
|
|
22
|
+
const bar = new StatusBar(element);
|
|
23
|
+
bar.update(progress, '%');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
learningImage.onLoss = (loss: number) => {
|
|
27
|
+
const element = document.getElementById('loss-bar');
|
|
28
|
+
if (element !== null) {
|
|
29
|
+
const bar = new StatusBar(element);
|
|
30
|
+
bar.update(loss, 'loss');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
34
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
35
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
36
|
+
|
|
37
|
+
// root UI
|
|
38
|
+
const container = document.createElement('div');
|
|
39
|
+
container.id = 'root';
|
|
40
|
+
|
|
41
|
+
// learning 준비 체크
|
|
42
|
+
const learningReadyCheck = () => {
|
|
43
|
+
if (!learningImage.ready()) {
|
|
44
|
+
window.alert('준비된 데이터가 없습니다.');
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (learningImage.running()) {
|
|
48
|
+
window.alert('이미 진행 중입니다.');
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// 이미지 저장 버튼 클릭
|
|
55
|
+
async function handleImageButtonClick(label: string) {
|
|
56
|
+
// Canvas 생성
|
|
57
|
+
const canvas = document.createElement('canvas');
|
|
58
|
+
const video = document.createElement('video');
|
|
59
|
+
|
|
60
|
+
// 웹캠 활성화
|
|
61
|
+
if (navigator.mediaDevices.getUserMedia) {
|
|
62
|
+
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
|
63
|
+
video.srcObject = stream;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 비디오가 메타데이터 로딩되면 캔버스에 그리고 이미지 캡처
|
|
67
|
+
video.addEventListener('loadedmetadata', () => {
|
|
68
|
+
video.play(); // 비디오 플레이 시작
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 비디오가 메타데이터 로딩되면 캔버스에 그리고 이미지 캡처
|
|
72
|
+
video.addEventListener('play', () => {
|
|
73
|
+
canvas.width = 128;
|
|
74
|
+
canvas.height = 128;
|
|
75
|
+
const context = canvas.getContext('2d');
|
|
76
|
+
if (context) {
|
|
77
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
78
|
+
learningImage.addData(label, context.getImageData(0, 0, canvas.width, canvas.height));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
container.appendChild(canvas);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 추론하기 버튼
|
|
85
|
+
async function handleInferButtonClick() {
|
|
86
|
+
if(!learningReadyCheck()) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Canvas 생성
|
|
91
|
+
const canvas = document.createElement('canvas');
|
|
92
|
+
const video = document.createElement('video');
|
|
93
|
+
|
|
94
|
+
// 웹캠 활성화
|
|
95
|
+
if (navigator.mediaDevices.getUserMedia) {
|
|
96
|
+
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
|
97
|
+
video.srcObject = stream;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 비디오가 메타데이터 로딩되면 캔버스에 그리고 이미지 캡처
|
|
101
|
+
video.addEventListener('loadedmetadata', () => {
|
|
102
|
+
video.play(); // 비디오 플레이 시작
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 비디오가 메타데이터 로딩되면 캔버스에 그리고 이미지 캡처
|
|
106
|
+
video.addEventListener('play', () => {
|
|
107
|
+
canvas.width = 128;
|
|
108
|
+
canvas.height = 128;
|
|
109
|
+
const context = canvas.getContext('2d');
|
|
110
|
+
if (context) {
|
|
111
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
112
|
+
learningImage.infer(context.getImageData(0, 0, canvas.width, canvas.height));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
container.appendChild(canvas);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Train 학습하기 버튼
|
|
119
|
+
async function handleTrainButtonClick() {
|
|
120
|
+
if(learningReadyCheck()) {
|
|
121
|
+
await learningImage.train();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// image button UI
|
|
126
|
+
const image1Button = document.createElement('button');
|
|
127
|
+
image1Button.textContent = '라벨1 이미지';
|
|
128
|
+
image1Button.addEventListener('click', () => handleImageButtonClick('라벨1 이미지'));
|
|
129
|
+
container.appendChild(image1Button);
|
|
130
|
+
|
|
131
|
+
// image button UI
|
|
132
|
+
const image2Button = document.createElement('button');
|
|
133
|
+
image2Button.textContent = '라벨2 이미지';
|
|
134
|
+
image2Button.addEventListener('click', () => handleImageButtonClick('라벨2 이미지'));
|
|
135
|
+
container.appendChild(image2Button);
|
|
136
|
+
|
|
137
|
+
// save button UI
|
|
138
|
+
const trainButton = document.createElement('button');
|
|
139
|
+
trainButton.textContent = '모델 Train';
|
|
140
|
+
trainButton.addEventListener('click', handleTrainButtonClick);
|
|
141
|
+
container.appendChild(trainButton);
|
|
142
|
+
document.body.appendChild(container);
|
|
143
|
+
|
|
144
|
+
// image button UI
|
|
145
|
+
const inferButton = document.createElement('button');
|
|
146
|
+
inferButton.textContent = '예측하기';
|
|
147
|
+
inferButton.addEventListener('click', () => handleInferButtonClick());
|
|
148
|
+
container.appendChild(inferButton);
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
appRun();
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
1
|
import LearningImage from './learning/image';
|
|
2
|
+
<<<<<<< HEAD
|
|
3
|
+
import LearningMobilenetImage from './learning/mobilenet_image';
|
|
4
|
+
=======
|
|
3
5
|
|
|
4
6
|
// 프로그레스 바를 표시하는 클래스
|
|
5
7
|
class StatusBar {
|
|
@@ -149,5 +151,6 @@ async function appRun() {
|
|
|
149
151
|
|
|
150
152
|
|
|
151
153
|
}
|
|
154
|
+
>>>>>>> 68f03c4696aa804e510cdbd6ebf6efd9e8eda5a4
|
|
152
155
|
|
|
153
|
-
|
|
156
|
+
export { LearningImage, LearningMobilenetImage };
|
package/tsconfig.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as tf from '@tensorflow/tfjs';
|
|
2
|
+
interface LearningInterface {
|
|
3
|
+
model: tf.LayersModel | null;
|
|
4
|
+
epochs: number;
|
|
5
|
+
batchSize: number;
|
|
6
|
+
labels: string[];
|
|
7
|
+
isRunning: boolean;
|
|
8
|
+
isReady: boolean;
|
|
9
|
+
limitSize: number;
|
|
10
|
+
onProgress(progress: number): void;
|
|
11
|
+
onLoss(loss: number): void;
|
|
12
|
+
addData(label: string, data: any): void;
|
|
13
|
+
train(): Promise<tf.History>;
|
|
14
|
+
infer(data: any): Promise<Map<string, number>>;
|
|
15
|
+
saveModel(): void;
|
|
16
|
+
running(): boolean;
|
|
17
|
+
ready(): boolean;
|
|
18
|
+
}
|
|
19
|
+
export default LearningInterface;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as tf from '@tensorflow/tfjs';
|
|
2
|
+
import LearningInterface from './base';
|
|
3
|
+
declare class LearningImage implements LearningInterface {
|
|
4
|
+
model: tf.LayersModel | null;
|
|
5
|
+
epochs: number;
|
|
6
|
+
batchSize: number;
|
|
7
|
+
labels: string[];
|
|
8
|
+
isRunning: boolean;
|
|
9
|
+
isReady: boolean;
|
|
10
|
+
limitSize: number;
|
|
11
|
+
trainImages: tf.Tensor3D[];
|
|
12
|
+
readonly MOBILE_NET_INPUT_WIDTH = 224;
|
|
13
|
+
readonly MOBILE_NET_INPUT_HEIGHT = 224;
|
|
14
|
+
readonly MOBILE_NET_INPUT_CHANNEL = 3;
|
|
15
|
+
readonly IMAGE_NORMALIZATION_FACTOR = 255;
|
|
16
|
+
constructor({ epochs, batchSize }?: {
|
|
17
|
+
modelURL?: string;
|
|
18
|
+
epochs?: number;
|
|
19
|
+
batchSize?: number;
|
|
20
|
+
});
|
|
21
|
+
onProgress: (progress: number) => void;
|
|
22
|
+
onLoss: (loss: number) => void;
|
|
23
|
+
addData(label: string, data: any): void;
|
|
24
|
+
train(): Promise<tf.History>;
|
|
25
|
+
infer(data: any): Promise<Map<string, number>>;
|
|
26
|
+
saveModel(): void;
|
|
27
|
+
running(): boolean;
|
|
28
|
+
ready(): boolean;
|
|
29
|
+
private _preprocessedTargetData;
|
|
30
|
+
private _preprocessedInputData;
|
|
31
|
+
private _preprocessData;
|
|
32
|
+
private _createModel;
|
|
33
|
+
}
|
|
34
|
+
export default LearningImage;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as tf from '@tensorflow/tfjs';
|
|
2
|
+
import LearningInterface from './base';
|
|
3
|
+
declare class LearningMobilenetImage implements LearningInterface {
|
|
4
|
+
model: tf.LayersModel | null;
|
|
5
|
+
epochs: number;
|
|
6
|
+
batchSize: number;
|
|
7
|
+
labels: string[];
|
|
8
|
+
modelURL: string;
|
|
9
|
+
isRunning: boolean;
|
|
10
|
+
isReady: boolean;
|
|
11
|
+
limitSize: number;
|
|
12
|
+
trainImages: tf.Tensor3D[];
|
|
13
|
+
readonly MOBILE_NET_INPUT_WIDTH = 224;
|
|
14
|
+
readonly MOBILE_NET_INPUT_HEIGHT = 224;
|
|
15
|
+
readonly MOBILE_NET_INPUT_CHANNEL = 3;
|
|
16
|
+
readonly IMAGE_NORMALIZATION_FACTOR = 255;
|
|
17
|
+
constructor({ modelURL, // 디폴트 mobilenet 이미지
|
|
18
|
+
epochs, batchSize }?: {
|
|
19
|
+
modelURL?: string;
|
|
20
|
+
epochs?: number;
|
|
21
|
+
batchSize?: number;
|
|
22
|
+
});
|
|
23
|
+
onProgress: (progress: number) => void;
|
|
24
|
+
onLoss: (loss: number) => void;
|
|
25
|
+
addData(label: string, data: any): void;
|
|
26
|
+
train(): Promise<tf.History>;
|
|
27
|
+
infer(data: any): Promise<Map<string, number>>;
|
|
28
|
+
saveModel(): void;
|
|
29
|
+
running(): boolean;
|
|
30
|
+
ready(): boolean;
|
|
31
|
+
private _preprocessedTargetData;
|
|
32
|
+
private _preprocessedInputData;
|
|
33
|
+
private _preprocessData;
|
|
34
|
+
private _createModel;
|
|
35
|
+
}
|
|
36
|
+
export default LearningMobilenetImage;
|