Showing
17 changed files
with
1303 additions
and
0 deletions
소스 코드/README.md
0 → 100644
1 | +# gesture_test | ||
2 | + | ||
3 | +## Project setup | ||
4 | +``` | ||
5 | +npm install | ||
6 | +``` | ||
7 | + | ||
8 | +### Compiles and hot-reloads for development | ||
9 | +``` | ||
10 | +npm run serve | ||
11 | +``` | ||
12 | + | ||
13 | +### Compiles and minifies for production | ||
14 | +``` | ||
15 | +npm run build | ||
16 | +``` | ||
17 | + | ||
18 | +### Lints and fixes files | ||
19 | +``` | ||
20 | +npm run lint | ||
21 | +``` | ||
22 | + | ||
23 | +### Customize configuration | ||
24 | +See [Configuration Reference](https://cli.vuejs.org/config/). |
소스 코드/babel.config.js
0 → 100644
소스 코드/package-lock.json
0 → 100644
This diff could not be displayed because it is too large.
소스 코드/package.json
0 → 100644
1 | +{ | ||
2 | + "name": "gesture_test", | ||
3 | + "version": "0.1.0", | ||
4 | + "private": true, | ||
5 | + "scripts": { | ||
6 | + "serve": "vue-cli-service serve", | ||
7 | + "build": "vue-cli-service build", | ||
8 | + "lint": "vue-cli-service lint" | ||
9 | + }, | ||
10 | + "dependencies": { | ||
11 | + "bootstrap": "^4.5.0", | ||
12 | + "bootstrap-vue": "^2.15.0", | ||
13 | + "brain.js": "^2.0.0-beta.2", | ||
14 | + "chart.js": "^2.9.4", | ||
15 | + "core-js": "^3.6.5", | ||
16 | + "vue": "^2.6.11", | ||
17 | + "vue-chart.js": "^0.2.0", | ||
18 | + "vue-chartjs-typescript": "^3.3.3", | ||
19 | + "vue-class-component": "^7.2.3", | ||
20 | + "vue-graph": "^0.8.7", | ||
21 | + "vue-property-decorator": "^8.4.2", | ||
22 | + "vue-router": "^3.2.0", | ||
23 | + "vuex": "^3.4.0" | ||
24 | + }, | ||
25 | + "devDependencies": { | ||
26 | + "@typescript-eslint/eslint-plugin": "^2.33.0", | ||
27 | + "@typescript-eslint/parser": "^2.33.0", | ||
28 | + "@vue/cli-plugin-babel": "~4.4.0", | ||
29 | + "@vue/cli-plugin-eslint": "~4.4.0", | ||
30 | + "@vue/cli-plugin-router": "~4.4.0", | ||
31 | + "@vue/cli-plugin-typescript": "~4.4.0", | ||
32 | + "@vue/cli-plugin-vuex": "~4.4.0", | ||
33 | + "@vue/cli-service": "~4.4.0", | ||
34 | + "@vue/eslint-config-standard": "^5.1.2", | ||
35 | + "@vue/eslint-config-typescript": "^5.0.2", | ||
36 | + "eslint": "^6.7.2", | ||
37 | + "eslint-plugin-import": "^2.20.2", | ||
38 | + "eslint-plugin-node": "^11.1.0", | ||
39 | + "eslint-plugin-promise": "^4.2.1", | ||
40 | + "eslint-plugin-standard": "^4.0.0", | ||
41 | + "eslint-plugin-vue": "^6.2.2", | ||
42 | + "stylus": "^0.54.7", | ||
43 | + "stylus-loader": "^3.0.2", | ||
44 | + "typescript": "~3.9.3", | ||
45 | + "vue-template-compiler": "^2.6.11" | ||
46 | + }, | ||
47 | + "eslintConfig": { | ||
48 | + "root": true, | ||
49 | + "env": { | ||
50 | + "node": true | ||
51 | + }, | ||
52 | + "extends": [ | ||
53 | + "plugin:vue/essential", | ||
54 | + "@vue/standard", | ||
55 | + "@vue/typescript/recommended" | ||
56 | + ], | ||
57 | + "parserOptions": { | ||
58 | + "ecmaVersion": 2020 | ||
59 | + }, | ||
60 | + "rules": {} | ||
61 | + }, | ||
62 | + "browserslist": [ | ||
63 | + "> 1%", | ||
64 | + "last 2 versions", | ||
65 | + "not dead" | ||
66 | + ] | ||
67 | +} |
소스 코드/public/favicon.ico
0 → 100644
No preview for this file type
소스 코드/public/index.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | + <head> | ||
4 | + <meta charset="utf-8"> | ||
5 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
6 | + <meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||
7 | + <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||
8 | + <title><%= htmlWebpackPlugin.options.title %></title> | ||
9 | + </head> | ||
10 | + <body> | ||
11 | + <noscript> | ||
12 | + <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> | ||
13 | + </noscript> | ||
14 | + <div id="app"></div> | ||
15 | + <!-- built files will be auto injected --> | ||
16 | + </body> | ||
17 | +</html> |
소스 코드/src/App.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <Speech/> | ||
4 | + </div> | ||
5 | +</template> | ||
6 | + | ||
7 | +<style lang="stylus"> | ||
8 | +#app | ||
9 | + font-family Avenir, Helvetica, Arial, sans-serif | ||
10 | + -webkit-font-smoothing antialiased | ||
11 | + -moz-osx-font-smoothing grayscale | ||
12 | + text-align center | ||
13 | + color #2c3e50 | ||
14 | + margin-top 60px | ||
15 | +</style> | ||
16 | + | ||
17 | +<script> | ||
18 | +import Speech from './components/Speech' | ||
19 | + | ||
20 | +export default { | ||
21 | + name: 'app', | ||
22 | + components: { | ||
23 | + Speech | ||
24 | + } | ||
25 | +} | ||
26 | +</script> |
소스 코드/src/BarChart.js
0 → 100644
소스 코드/src/assets/logo.png
0 → 100644
6.69 KB
소스 코드/src/components/Speech.vue
0 → 100644
1 | +<template > | ||
2 | + <div class="main-layout"> | ||
3 | + <b-navbar variant="dark" type="dark" :sticky="sticky"> | ||
4 | + <b-navbar-brand href="#">발화 추천 알고리즘의 비교</b-navbar-brand> | ||
5 | + </b-navbar> | ||
6 | + <b-tabs | ||
7 | + class="pl-1 content-wrapper" | ||
8 | + vertical | ||
9 | + pills | ||
10 | + card | ||
11 | + v-model="tabIndex" | ||
12 | + @input="initializeCommonData" | ||
13 | + > | ||
14 | + <b-tab title="HMM" active> | ||
15 | + <b-row> | ||
16 | + <b-col> | ||
17 | + <div class="p-3"> | ||
18 | + <h5>추천 발화</h5> | ||
19 | + <b-form inline> | ||
20 | + <b-form-input v-model="userInputState" placeholder="추천 발화" class="m-2" :state="userInputState.length > 0 ? true : false"></b-form-input> | ||
21 | + <b-button class="m-2" @click="generateTrainingData" >학습 데이터 생성</b-button> | ||
22 | + </b-form> | ||
23 | + <b-alert | ||
24 | + :show="dismissCountDown" | ||
25 | + dismissible | ||
26 | + variant="warning" | ||
27 | + @dismissed="dismissCountDown=0" | ||
28 | + @dismiss-count-down="countDownChanged" | ||
29 | + > | ||
30 | + 최소 1개의 시나리오를 입력해주세요. | ||
31 | + </b-alert> | ||
32 | + </div> | ||
33 | + <div class="p-3"> | ||
34 | + <h5>시나리오</h5> | ||
35 | + <b-form> | ||
36 | + <template v-for="(scenario, index) of scenarioList"> | ||
37 | + <b-form-group | ||
38 | + :label="'시나리오-' + (index + 1)" | ||
39 | + :key="'scenario-' + index" | ||
40 | + > | ||
41 | + <div class="scenario-item"> | ||
42 | + <b-form-input v-model="scenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="scenario.sequence.length > 0 ? true : false"></b-form-input> | ||
43 | + <b-button class="m-2" @click="deleteScenario(scenario)">-</b-button> | ||
44 | + </div> | ||
45 | + </b-form-group> | ||
46 | + </template> | ||
47 | + <b-button class="m-2" @click="addNewItem">+</b-button> | ||
48 | + </b-form> | ||
49 | + </div> | ||
50 | + <div class="p-3"> | ||
51 | + <b-form inline> | ||
52 | + <b-form-input v-model="userInputScenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="userInputScenario.sequence.length > 0 ? true : false"></b-form-input> | ||
53 | + <b-button class="m-2" @click="detectSpeech" >발화 추천</b-button> | ||
54 | + </b-form> | ||
55 | + <span class="m-2">추천 발화: {{detectedSpeech}}</span> | ||
56 | + </div> | ||
57 | + <div class="p-3"> | ||
58 | + <h5>학습 데이터</h5> | ||
59 | + <b-table striped hover :items="displayTrainingSet"></b-table> | ||
60 | + </div> | ||
61 | + </b-col> | ||
62 | + <b-col> | ||
63 | + <div> | ||
64 | + <b-card | ||
65 | + title="HMM 학습 및 예측 시나리오" | ||
66 | + img-src="https://cdn.pixabay.com/photo/2017/01/23/08/13/microphone-2001751_1280.png" | ||
67 | + img-alt="Speech Recommendation" | ||
68 | + img-top | ||
69 | + style="max-width: 30rem;" | ||
70 | + tag="article" | ||
71 | + class="mb-2" | ||
72 | + > | ||
73 | + <b-card-text>1. 추천 발화 입력</b-card-text> | ||
74 | + <b-card-text>2. 입력한 추천 발화가 나올 수 있는 시나리오 입력("+" 버튼 클릭)</b-card-text> | ||
75 | + <b-card-text>3. "학습 데이터 생성" 버튼 클릭</b-card-text> | ||
76 | + <b-card-text>4. 추천 대상 발화의 수 만큼 (1 ~ 3)번 과정 반복</b-card-text> | ||
77 | + <b-card-text>5. 발화를 추천 받고자 하는 시나리오 입력</b-card-text> | ||
78 | + <b-card-text>6. "발화 추천" 버튼 클릭</b-card-text> | ||
79 | + <b-card-text>7. 추천 발화 확인</b-card-text> | ||
80 | + </b-card> | ||
81 | + </div> | ||
82 | + </b-col> | ||
83 | + </b-row> | ||
84 | + </b-tab> | ||
85 | + <b-tab title="MC"> | ||
86 | + <b-row> | ||
87 | + <b-col> | ||
88 | + <div class="p-3"> | ||
89 | + <h5>블록</h5> | ||
90 | + <b-alert | ||
91 | + :show="dismissCountDown" | ||
92 | + dismissible | ||
93 | + variant="warning" | ||
94 | + @dismissed="dismissCountDown=0" | ||
95 | + @dismiss-count-down="countDownChanged" | ||
96 | + > | ||
97 | + 10개의 발화를 입력해주세요. | ||
98 | + </b-alert> | ||
99 | + <b-form> | ||
100 | + <template v-for="(block, index) of blockList"> | ||
101 | + <b-form-group | ||
102 | + :label="'ID-' + index" | ||
103 | + :key="'block-' + index" | ||
104 | + > | ||
105 | + <div class="scenario-item"> | ||
106 | + <b-form-input v-model="block.speech" placeholder="발화를 입력해주세요." class="m-2" :state="block.speech.length > 0 ? true : false"></b-form-input> | ||
107 | + <b-button class="m-2" @click="deleteBlock(block)">-</b-button> | ||
108 | + </div> | ||
109 | + </b-form-group> | ||
110 | + </template> | ||
111 | + <b-button class="m-2" @click="addNewItem">+</b-button> | ||
112 | + <b-button class="m-2" @click="generateTrainingData" >학습 데이터 생성</b-button> | ||
113 | + </b-form> | ||
114 | + </div> | ||
115 | + <div class="p-3"> | ||
116 | + <b-form> | ||
117 | + <b-form-input v-model="userInputStateSequence" placeholder="추천하고자 하는 발화가 몇 번째 발화인지 입력해주세요" class="m-2" :state="userInputStateSequence.length > 0 ? true : false"></b-form-input> | ||
118 | + <b-button class="m-2" @click="detectSpeech" >발화 추천</b-button> | ||
119 | + <span class="m-2">추천 발화: {{detectedSpeech}}</span> | ||
120 | + </b-form> | ||
121 | + </div> | ||
122 | + <div class="p-3"> | ||
123 | + <h5>학습 데이터</h5> | ||
124 | + <b-table striped hover :items="displayTrainingSet"></b-table> | ||
125 | + </div> | ||
126 | + </b-col> | ||
127 | + <b-col> | ||
128 | + <div> | ||
129 | + <b-card | ||
130 | + title="MC 학습 및 예측 시나리오" | ||
131 | + img-src="https://cdn.pixabay.com/photo/2017/01/23/08/13/microphone-2001751_1280.png" | ||
132 | + img-alt="Speech Recommendation" | ||
133 | + img-top | ||
134 | + style="max-width: 30rem;" | ||
135 | + tag="article" | ||
136 | + class="mb-2" | ||
137 | + > | ||
138 | + <b-card-text>1. 시나리오 상 포함되는 블록 정보(ID) 입력("+" 버튼 클릭)</b-card-text> | ||
139 | + <b-card-text>2. "학습 데이터 생성" 버튼 클릭</b-card-text> | ||
140 | + <b-card-text>3. 추천 발화가 필요한 시나리오 상 순서 입력</b-card-text> | ||
141 | + <b-card-text>4. "발화 추천" 버튼 클릭</b-card-text> | ||
142 | + <b-card-text>5. 추천 발화 확인</b-card-text> | ||
143 | + </b-card> | ||
144 | + </div> | ||
145 | + </b-col> | ||
146 | + </b-row> | ||
147 | + </b-tab> | ||
148 | + <b-tab title="RNN"> | ||
149 | + <b-row> | ||
150 | + <b-col> | ||
151 | + <div class="p-3"> | ||
152 | + <h5>추천 발화</h5> | ||
153 | + <b-form inline> | ||
154 | + <b-form-input v-model="userInputState" placeholder="추천 발화" class="m-2" :state="userInputState.length > 0 ? true : false"></b-form-input> | ||
155 | + <b-button class="m-2" @click="generateTrainingData" >학습 데이터 생성</b-button> | ||
156 | + </b-form> | ||
157 | + <b-alert | ||
158 | + :show="dismissCountDown" | ||
159 | + dismissible | ||
160 | + variant="warning" | ||
161 | + @dismissed="dismissCountDown=0" | ||
162 | + @dismiss-count-down="countDownChanged" | ||
163 | + > | ||
164 | + 최소 1개의 시나리오를 입력해주세요. | ||
165 | + </b-alert> | ||
166 | + </div> | ||
167 | + <div class="p-3"> | ||
168 | + <h5>시나리오</h5> | ||
169 | + <b-form> | ||
170 | + <template v-for="(scenario, index) of scenarioList"> | ||
171 | + <b-form-group | ||
172 | + :label="'시나리오-' + (index + 1)" | ||
173 | + :key="'scenario-' + index" | ||
174 | + > | ||
175 | + <div class="scenario-item"> | ||
176 | + <b-form-input v-model="scenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="scenario.sequence.length > 0 ? true : false"></b-form-input> | ||
177 | + <b-button class="m-2" @click="deleteScenario(scenario)">-</b-button> | ||
178 | + </div> | ||
179 | + </b-form-group> | ||
180 | + </template> | ||
181 | + <b-button class="m-2" @click="addNewItem">+</b-button> | ||
182 | + </b-form> | ||
183 | + </div> | ||
184 | + <div class="p-3"> | ||
185 | + <b-form inline> | ||
186 | + <b-form-input v-model="userInputScenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="userInputScenario.sequence.length > 0 ? true : false"></b-form-input> | ||
187 | + <b-button class="m-2" @click="detectSpeech" >발화 추천</b-button> | ||
188 | + </b-form> | ||
189 | + <span class="m-2">추천 발화: {{detectedSpeech}}</span> | ||
190 | + </div> | ||
191 | + <div class="p-3"> | ||
192 | + <h5>학습 데이터</h5> | ||
193 | + <b-table striped hover :items="displayTrainingSet"></b-table> | ||
194 | + </div> | ||
195 | + </b-col> | ||
196 | + <b-col> | ||
197 | + <div> | ||
198 | + <b-card | ||
199 | + title="RNN 학습 및 예측 시나리오" | ||
200 | + img-src="https://cdn.pixabay.com/photo/2017/01/23/08/13/microphone-2001751_1280.png" | ||
201 | + img-alt="Speech Recommendation" | ||
202 | + img-top | ||
203 | + style="max-width: 30rem;" | ||
204 | + tag="article" | ||
205 | + class="mb-2" | ||
206 | + > | ||
207 | + <b-card-text>1. 추천 발화 입력</b-card-text> | ||
208 | + <b-card-text>2. 입력한 추천 발화가 나올 수 있는 시나리오 입력("+" 버튼 클릭)</b-card-text> | ||
209 | + <b-card-text>3. "학습 데이터 생성" 버튼 클릭</b-card-text> | ||
210 | + <b-card-text>4. 추천 대상 발화의 수 만큼 (1 ~ 3)번 과정 반복</b-card-text> | ||
211 | + <b-card-text>5. 발화를 추천 받고자 하는 시나리오 입력</b-card-text> | ||
212 | + <b-card-text>6. "발화 추천" 버튼 클릭</b-card-text> | ||
213 | + <b-card-text>7. 추천 발화 확인</b-card-text> | ||
214 | + </b-card> | ||
215 | + </div> | ||
216 | + </b-col> | ||
217 | + </b-row> | ||
218 | + </b-tab> | ||
219 | + <b-tab title="LSTM"> | ||
220 | + <b-row> | ||
221 | + <b-col> | ||
222 | + <div class="p-3"> | ||
223 | + <h5>추천 발화</h5> | ||
224 | + <b-form inline> | ||
225 | + <b-form-input v-model="userInputState" placeholder="추천 발화" class="m-2" :state="userInputState.length > 0 ? true : false"></b-form-input> | ||
226 | + <b-button class="m-2" @click="generateTrainingData" >학습 데이터 생성</b-button> | ||
227 | + </b-form> | ||
228 | + <b-alert | ||
229 | + :show="dismissCountDown" | ||
230 | + dismissible | ||
231 | + variant="warning" | ||
232 | + @dismissed="dismissCountDown=0" | ||
233 | + @dismiss-count-down="countDownChanged" | ||
234 | + > | ||
235 | + 최소 1개의 시나리오를 입력해주세요. | ||
236 | + </b-alert> | ||
237 | + </div> | ||
238 | + <div class="p-3"> | ||
239 | + <h5>시나리오</h5> | ||
240 | + <b-form> | ||
241 | + <template v-for="(scenario, index) of scenarioList"> | ||
242 | + <b-form-group | ||
243 | + :label="'시나리오-' + (index + 1)" | ||
244 | + :key="'scenario-' + index" | ||
245 | + > | ||
246 | + <div class="scenario-item"> | ||
247 | + <b-form-input v-model="scenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="scenario.sequence.length > 0 ? true : false"></b-form-input> | ||
248 | + <b-button class="m-2" @click="deleteScenario(scenario)">-</b-button> | ||
249 | + </div> | ||
250 | + </b-form-group> | ||
251 | + </template> | ||
252 | + <b-button class="m-2" @click="addNewItem">+</b-button> | ||
253 | + </b-form> | ||
254 | + </div> | ||
255 | + <div class="p-3"> | ||
256 | + <b-form inline> | ||
257 | + <b-form-input v-model="userInputScenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="userInputScenario.sequence.length > 0 ? true : false"></b-form-input> | ||
258 | + <b-button class="m-2" @click="detectSpeech" >발화 추천</b-button> | ||
259 | + </b-form> | ||
260 | + <span class="m-2">추천 발화: {{detectedSpeech}}</span> | ||
261 | + </div> | ||
262 | + <div class="p-3"> | ||
263 | + <h5>학습 데이터</h5> | ||
264 | + <b-table striped hover :items="displayTrainingSet"></b-table> | ||
265 | + </div> | ||
266 | + </b-col> | ||
267 | + <b-col> | ||
268 | + <div> | ||
269 | + <b-card | ||
270 | + title="LSTM 학습 및 예측 시나리오" | ||
271 | + img-src="https://cdn.pixabay.com/photo/2017/01/23/08/13/microphone-2001751_1280.png" | ||
272 | + img-alt="Speech Recommendation" | ||
273 | + img-top | ||
274 | + style="max-width: 30rem;" | ||
275 | + tag="article" | ||
276 | + class="mb-2" | ||
277 | + > | ||
278 | + <b-card-text>1. 추천 발화 입력</b-card-text> | ||
279 | + <b-card-text>2. 입력한 추천 발화가 나올 수 있는 시나리오 입력("+" 버튼 클릭)</b-card-text> | ||
280 | + <b-card-text>3. "학습 데이터 생성" 버튼 클릭</b-card-text> | ||
281 | + <b-card-text>4. 추천 대상 발화의 수 만큼 (1 ~ 3)번 과정 반복</b-card-text> | ||
282 | + <b-card-text>5. 발화를 추천 받고자 하는 시나리오 입력</b-card-text> | ||
283 | + <b-card-text>6. "발화 추천" 버튼 클릭</b-card-text> | ||
284 | + <b-card-text>7. 추천 발화 확인</b-card-text> | ||
285 | + </b-card> | ||
286 | + </div> | ||
287 | + </b-col> | ||
288 | + </b-row> | ||
289 | + </b-tab> | ||
290 | + <b-tab title="통합"> | ||
291 | + <b-row> | ||
292 | + <b-col> | ||
293 | + <div class="p-3"> | ||
294 | + <h5>추천 발화</h5> | ||
295 | + <b-form inline> | ||
296 | + <b-form-input v-model="userInputState" placeholder="추천 발화" class="m-2" :state="userInputState.length > 0 ? true : false"></b-form-input> | ||
297 | + <b-button class="m-2" @click="generateTrainingData" >학습 데이터 생성</b-button> | ||
298 | + </b-form> | ||
299 | + <b-alert | ||
300 | + :show="dismissCountDown" | ||
301 | + dismissible | ||
302 | + variant="warning" | ||
303 | + @dismissed="dismissCountDown=0" | ||
304 | + @dismiss-count-down="countDownChanged" | ||
305 | + > | ||
306 | + 최소 1개의 시나리오를 입력해주세요. | ||
307 | + </b-alert> | ||
308 | + </div> | ||
309 | + <div class="p-3"> | ||
310 | + <h5>시나리오</h5> | ||
311 | + <b-form> | ||
312 | + <template v-for="(scenario, index) of scenarioList"> | ||
313 | + <b-form-group | ||
314 | + :label="'시나리오-' + (index + 1)" | ||
315 | + :key="'scenario-' + index" | ||
316 | + > | ||
317 | + <div class="scenario-item"> | ||
318 | + <b-form-input v-model="scenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="scenario.sequence.length > 0 ? true : false"></b-form-input> | ||
319 | + <b-button class="m-2" @click="deleteScenario(scenario)">-</b-button> | ||
320 | + </div> | ||
321 | + </b-form-group> | ||
322 | + </template> | ||
323 | + <b-button class="m-2" @click="addNewItem">+</b-button> | ||
324 | + </b-form> | ||
325 | + </div> | ||
326 | + <div class="p-3"> | ||
327 | + <b-form inline> | ||
328 | + <b-form-input v-model="userInputScenario.sequence" placeholder="블록 ID를 쉼표로 구분하여 입력해주세요." class="m-2" :state="userInputScenario.sequence.length > 0 ? true : false"></b-form-input> | ||
329 | + <b-button class="m-2" @click="detectSpeech" >발화 추천</b-button> | ||
330 | + </b-form> | ||
331 | + <p class="m-2">추천 발화(HMM): {{detectedSpeechHMM}}</p> | ||
332 | + <p class="m-2">추천 발화(MC): {{detectedSpeechMC}}</p> | ||
333 | + <p class="m-2">추천 발화(RNN): {{detectedSpeechRNN}}</p> | ||
334 | + <p class="m-2">추천 발화(LSTM): {{detectedSpeechLSTM}}</p> | ||
335 | + </div> | ||
336 | + <div class="p-3"> | ||
337 | + <h5>학습 데이터</h5> | ||
338 | + <b-button class="m-2" @click="onClickShowTrainingData">{{ showTrainingData ? '숨기기' : '보이기' }}</b-button> | ||
339 | + <b-table v-if="showTrainingData" striped hover :items="displayTrainingSet"></b-table> | ||
340 | + </div> | ||
341 | + </b-col> | ||
342 | + <b-col> | ||
343 | + <div> | ||
344 | + <b-card | ||
345 | + title="통합 학습 및 예측 시나리오" | ||
346 | + img-src="https://cdn.pixabay.com/photo/2017/01/23/08/13/microphone-2001751_1280.png" | ||
347 | + img-alt="Speech Recommendation" | ||
348 | + img-top | ||
349 | + style="max-width: 30rem;" | ||
350 | + tag="article" | ||
351 | + class="mb-2" | ||
352 | + > | ||
353 | + <b-card-text>1. 추천 발화 입력</b-card-text> | ||
354 | + <b-card-text>2. 입력한 추천 발화가 나올 수 있는 시나리오 입력("+" 버튼 클릭)</b-card-text> | ||
355 | + <b-card-text>3. "학습 데이터 생성" 버튼 클릭</b-card-text> | ||
356 | + <b-card-text>4. 추천 대상 발화의 수 만큼 (1 ~ 3)번 과정 반복</b-card-text> | ||
357 | + <b-card-text>5. 발화를 추천 받고자 하는 시나리오 입력</b-card-text> | ||
358 | + <b-card-text>6. "발화 추천" 버튼 클릭</b-card-text> | ||
359 | + <b-card-text>7. 추천 발화 확인</b-card-text> | ||
360 | + </b-card> | ||
361 | + </div> | ||
362 | + </b-col> | ||
363 | + </b-row> | ||
364 | + <b-row> | ||
365 | + <b-col> | ||
366 | + <div class="p-3"> | ||
367 | + <h5>모델별 결과 확인</h5> | ||
368 | + <b-button class="m-2" @click="createGraph">그래프 생성</b-button> | ||
369 | + <div class="container"> | ||
370 | + <bar-chart | ||
371 | + v-if="showGraph" | ||
372 | + :chart-data="chartData" | ||
373 | + :options="options" | ||
374 | + /> | ||
375 | + </div> | ||
376 | + </div> | ||
377 | + </b-col> | ||
378 | + </b-row> | ||
379 | + </b-tab> | ||
380 | + </b-tabs> | ||
381 | + </div> | ||
382 | +</template> | ||
383 | + | ||
384 | +<script lang="ts"> | ||
385 | +import 'bootstrap/dist/css/bootstrap.css' | ||
386 | +import 'bootstrap-vue/dist/bootstrap-vue.css' | ||
387 | + | ||
388 | +import Vue from 'vue' | ||
389 | +import { Component, Prop } from 'vue-property-decorator' | ||
390 | + | ||
391 | +import * as brain from 'brain.js/src' | ||
392 | + | ||
393 | +// @ts-ignore | ||
394 | +import BarChart from '../BarChart.js' | ||
395 | + | ||
396 | +class Scenario { | ||
397 | + sequence: string; | ||
398 | + | ||
399 | + constructor (sequence: string) { | ||
400 | + this.sequence = sequence | ||
401 | + } | ||
402 | +} | ||
403 | + | ||
404 | +class Block { | ||
405 | + speech: string; | ||
406 | + | ||
407 | + constructor (speech: string) { | ||
408 | + this.speech = speech | ||
409 | + } | ||
410 | +} | ||
411 | + | ||
412 | +@Component({ | ||
413 | + components: { | ||
414 | + BarChart | ||
415 | + } | ||
416 | +}) | ||
417 | +export default class Speech extends Vue { | ||
418 | + private sticky = true | ||
419 | + private dismissCountDown = 0 | ||
420 | + private dismissSecs = 2 | ||
421 | + private tabIndex = 1 | ||
422 | + private showTrainingData = false | ||
423 | + | ||
424 | + // Graph | ||
425 | + private showGraph = false | ||
426 | + private chartData = { | ||
427 | + labels: ['HMM', 'RNN', 'LSTM'], | ||
428 | + datasets: [] as any[] | ||
429 | + } | ||
430 | + | ||
431 | + private options = { | ||
432 | + responsive: true, | ||
433 | + maintainAspectRatio: false | ||
434 | + } | ||
435 | + | ||
436 | + // 공통 | ||
437 | + private displayTrainingSet: any[] = [] | ||
438 | + private detectedSpeech = '' | ||
439 | + private singleTrainingData: any[] = [] | ||
440 | + private userInputState = '' | ||
441 | + private scenarioList: Scenario[] = [] | ||
442 | + private userInputScenario: Scenario = new Scenario('') | ||
443 | + private trainingSet: Map<string, any[]> = new Map() | ||
444 | + | ||
445 | + // HMM | ||
446 | + private observation2stateMatrix!: any[] | ||
447 | + private observation2observationMatrix!: any[] | ||
448 | + | ||
449 | + // MC | ||
450 | + private blockList: Block[] = [] | ||
451 | + private initProbList: number[] = [] | ||
452 | + private state2stateMatrix!: number[][] | ||
453 | + private userInputStateSequence = '' | ||
454 | + | ||
455 | + // RNN | ||
456 | + private netRnn = new brain.recurrent.RNN() | ||
457 | + | ||
458 | + // LSTM | ||
459 | + private netLstm = new brain.recurrent.LSTM() | ||
460 | + | ||
461 | + // ALL | ||
462 | + private detectedSpeechHMM = '' | ||
463 | + private detectedSpeechMC = '' | ||
464 | + private detectedSpeechRNN = '' | ||
465 | + private detectedSpeechLSTM = '' | ||
466 | + | ||
467 | + onClickShowTrainingData () { | ||
468 | + this.showTrainingData = !this.showTrainingData | ||
469 | + } | ||
470 | + | ||
471 | + createGraph () { | ||
472 | + const stateStrings = [...this.trainingSet.keys()] | ||
473 | + const chartDataEntry = { | ||
474 | + label: 'accuracy', | ||
475 | + data: [] as number[] | ||
476 | + } | ||
477 | + let totalNum = 0 | ||
478 | + let hmmCount = 0 | ||
479 | + let rnnCount = 0 | ||
480 | + let lstmCount = 0 | ||
481 | + | ||
482 | + for (let index = 0; index < stateStrings.length; index++) { | ||
483 | + const parsedSequenceList = this.trainingSet.get(stateStrings[index]) as any[] | ||
484 | + | ||
485 | + for (let secondIndex = 0; secondIndex < parsedSequenceList.length; secondIndex++) { | ||
486 | + const parsedSequence = parsedSequenceList[secondIndex] as number[] | ||
487 | + const parsedSequenceStr = parsedSequence.join() | ||
488 | + | ||
489 | + this.userInputScenario.sequence = parsedSequenceStr | ||
490 | + | ||
491 | + this.detectSpeechForHMM() | ||
492 | + if (this.detectedSpeechHMM === stateStrings[index]) { | ||
493 | + hmmCount++ | ||
494 | + } | ||
495 | + | ||
496 | + this.detectSpeechForRNN() | ||
497 | + if (this.detectedSpeechRNN === stateStrings[index]) { | ||
498 | + rnnCount++ | ||
499 | + } | ||
500 | + if (this.detectedSpeechLSTM === stateStrings[index]) { | ||
501 | + lstmCount++ | ||
502 | + } | ||
503 | + | ||
504 | + totalNum++ | ||
505 | + } | ||
506 | + } | ||
507 | + | ||
508 | + this.$set(chartDataEntry, 'data', [(hmmCount / totalNum) * 100, (rnnCount / totalNum) * 100, (lstmCount / totalNum) * 100]) | ||
509 | + this.$set(this.chartData, 'datasets', [chartDataEntry]) | ||
510 | + | ||
511 | + this.showGraph = true | ||
512 | + } | ||
513 | + | ||
514 | + initializeCommonData () { | ||
515 | + this.displayTrainingSet = [] | ||
516 | + this.singleTrainingData = [] | ||
517 | + this.userInputState = '' | ||
518 | + this.detectedSpeech = '' | ||
519 | + this.userInputStateSequence = '' | ||
520 | + this.trainingSet = new Map() | ||
521 | + | ||
522 | + if (this.tabIndex === 4) { | ||
523 | + this.observation2stateMatrix = [] | ||
524 | + this.observation2observationMatrix = [] | ||
525 | + this.state2stateMatrix = [] | ||
526 | + this.initProbList = [] | ||
527 | + this.blockList = [] | ||
528 | + | ||
529 | + this.netRnn = new brain.recurrent.RNN() | ||
530 | + this.netLstm = new brain.recurrent.LSTM() | ||
531 | + } | ||
532 | + } | ||
533 | + | ||
534 | + countDownChanged (dismissCountDown: number) { | ||
535 | + this.dismissCountDown = dismissCountDown | ||
536 | + } | ||
537 | + | ||
538 | + showAlert () { | ||
539 | + this.dismissCountDown = this.dismissSecs | ||
540 | + } | ||
541 | + | ||
542 | + clearHMM () { | ||
543 | + this.singleTrainingData = [] | ||
544 | + this.displayTrainingSet = [] | ||
545 | + } | ||
546 | + | ||
547 | + clearMC () { | ||
548 | + this.singleTrainingData = [] | ||
549 | + this.state2stateMatrix = [] | ||
550 | + this.displayTrainingSet = [] | ||
551 | + } | ||
552 | + | ||
553 | + clearRNN () { | ||
554 | + this.singleTrainingData = [] | ||
555 | + this.displayTrainingSet = [] | ||
556 | + } | ||
557 | + | ||
558 | + clearAll () { | ||
559 | + this.singleTrainingData = [] | ||
560 | + this.displayTrainingSet = [] | ||
561 | + } | ||
562 | + | ||
563 | + addNewItem () { | ||
564 | + if (this.tabIndex === 1) { | ||
565 | + const block: Block = new Block('') | ||
566 | + | ||
567 | + this.blockList.push(block) | ||
568 | + } else { | ||
569 | + const scenario: Scenario = new Scenario('') | ||
570 | + | ||
571 | + this.scenarioList.push(scenario) | ||
572 | + } | ||
573 | + } | ||
574 | + | ||
575 | + deleteScenario (input: Scenario) { | ||
576 | + const index = this.scenarioList.findIndex(scenario => scenario.sequence === input.sequence) | ||
577 | + | ||
578 | + if (index !== -1) { | ||
579 | + this.scenarioList.splice(index, 1) | ||
580 | + } | ||
581 | + } | ||
582 | + | ||
583 | + deleteBlock (input: Block) { | ||
584 | + const index = this.blockList.findIndex(block => block.speech === input.speech) | ||
585 | + | ||
586 | + if (index !== -1) { | ||
587 | + this.blockList.splice(index, 1) | ||
588 | + } | ||
589 | + } | ||
590 | + | ||
591 | + generateTrainingDataForHMM () { | ||
592 | + // 시나리오 입력 여부 체크 | ||
593 | + if (this.scenarioList.length === 0) { | ||
594 | + this.showAlert() | ||
595 | + | ||
596 | + return | ||
597 | + } | ||
598 | + | ||
599 | + // 기존 학습 데이터 및 출력 데이터 클리어 | ||
600 | + this.clearHMM() | ||
601 | + | ||
602 | + // 학습 데이터 생성 | ||
603 | + this.generateRandomSequenceForHMM() | ||
604 | + | ||
605 | + // 생성된 학습 데이터를 출력 데이터로 할당 | ||
606 | + this.displayTrainingSet = [...this.singleTrainingData] | ||
607 | + | ||
608 | + // 생성된 학습 데이터를 기반으로 학습 시작 | ||
609 | + this.trainingForHMM() | ||
610 | + } | ||
611 | + | ||
612 | + generateTrainingDataForMC () { | ||
613 | + // 블록 입력 여부 체크 | ||
614 | + if (this.blockList.length !== 10) { | ||
615 | + this.showAlert() | ||
616 | + | ||
617 | + return | ||
618 | + } | ||
619 | + | ||
620 | + // 기존 학습 데이터 및 출력 데이터 클리어 | ||
621 | + this.clearMC() | ||
622 | + | ||
623 | + // 학습 데이터 생성 및 초기 확률 계산 | ||
624 | + this.generateRandomSequenceForMC() | ||
625 | + | ||
626 | + // 생성된 학습 데이터를 출력 데이터로 할당 | ||
627 | + this.displayTrainingSet = [...this.singleTrainingData] | ||
628 | + | ||
629 | + // 생성된 학습 데이터를 기반으로 학습 시작 | ||
630 | + this.trainingForMC() | ||
631 | + } | ||
632 | + | ||
633 | + generateTrainingDataForRNN () { | ||
634 | + // 시나리오 입력 여부 체크 | ||
635 | + if (this.scenarioList.length === 0) { | ||
636 | + this.showAlert() | ||
637 | + | ||
638 | + return | ||
639 | + } | ||
640 | + | ||
641 | + // 기존 학습 데이터 및 출력 데이터 클리어 | ||
642 | + this.clearRNN() | ||
643 | + | ||
644 | + // 학습 데이터 생성 | ||
645 | + this.setTrainingDataForRNN() | ||
646 | + | ||
647 | + // 생성된 학습 데이터를 출력 데이터로 할당 | ||
648 | + this.displayTrainingSet = [...this.singleTrainingData] | ||
649 | + | ||
650 | + // 생성된 학습 데이터를 기반으로 학습 시작 | ||
651 | + this.trainingForRNN() | ||
652 | + } | ||
653 | + | ||
654 | + generateTrainingDataForAll () { | ||
655 | + // 시나리오 입력 여부 체크 | ||
656 | + if (this.scenarioList.length === 0) { | ||
657 | + this.showAlert() | ||
658 | + | ||
659 | + return | ||
660 | + } | ||
661 | + | ||
662 | + // 기존 학습 데이터 및 출력 데이터 클리어 | ||
663 | + this.clearAll() | ||
664 | + | ||
665 | + // 학습 데이터 생성 | ||
666 | + this.setTrainingDataForAll() | ||
667 | + | ||
668 | + // 생성된 학습 데이터를 출력 데이터로 할당 | ||
669 | + this.displayTrainingSet = [...this.singleTrainingData] | ||
670 | + | ||
671 | + this.trainingForHMM() | ||
672 | + this.trainingForMC() | ||
673 | + this.trainingForRNN() | ||
674 | + } | ||
675 | + | ||
676 | + generateTrainingData () { | ||
677 | + if (this.tabIndex === 0) { | ||
678 | + this.generateTrainingDataForHMM() | ||
679 | + } else if (this.tabIndex === 1) { | ||
680 | + this.generateTrainingDataForMC() | ||
681 | + } else if (this.tabIndex === 2 || this.tabIndex === 3) { | ||
682 | + this.generateTrainingDataForRNN() | ||
683 | + } else { | ||
684 | + this.generateTrainingDataForAll() | ||
685 | + } | ||
686 | + } | ||
687 | + | ||
688 | + parseSequence (sequence: string) { | ||
689 | + const parsedSequence: string[] = sequence.split(',') | ||
690 | + const resultSequence: number[] = [] | ||
691 | + | ||
692 | + for (let index = 0; index < parsedSequence.length; index++) { | ||
693 | + resultSequence.push(parseInt(parsedSequence[index])) | ||
694 | + } | ||
695 | + | ||
696 | + return resultSequence | ||
697 | + } | ||
698 | + | ||
699 | + // 100개의 랜덤 학습 데이터 생성 | ||
700 | + generateRandomSequenceForHMM () { | ||
701 | + // 학습 셋에 STATE 추가 | ||
702 | + this.trainingSet.set(this.userInputState, []) | ||
703 | + | ||
704 | + const parsedSequenceList: any[] = [] | ||
705 | + for (let index = 0; index < this.scenarioList.length; index++) { | ||
706 | + const parsedSequence = this.parseSequence(this.scenarioList[index].sequence) | ||
707 | + | ||
708 | + parsedSequenceList.push(parsedSequence) | ||
709 | + } | ||
710 | + | ||
711 | + const iter = this.trainingSet.get(this.userInputState) | ||
712 | + if (iter === null || iter === undefined) { | ||
713 | + return | ||
714 | + } | ||
715 | + | ||
716 | + for (let index = 0; index < 100; index++) { | ||
717 | + const randomIndex = Math.floor(Math.random() * parsedSequenceList.length) | ||
718 | + | ||
719 | + this.singleTrainingData.push(parsedSequenceList[randomIndex]) | ||
720 | + iter.push(parsedSequenceList[randomIndex]) | ||
721 | + } | ||
722 | + } | ||
723 | + | ||
724 | + // 100개의 랜덤 학습 데이터 생성 | ||
725 | + generateRandomSequenceForMC () { | ||
726 | + for (let index = 0; index < 10; index++) { | ||
727 | + this.initProbList[index] = 0 | ||
728 | + } | ||
729 | + | ||
730 | + for (let index = 0; index < 100; index++) { | ||
731 | + const generatedSequence = [] | ||
732 | + for (let secondIndex = 0; secondIndex < 5; secondIndex++) { | ||
733 | + const randomIndex = Math.floor(Math.random() * 10) | ||
734 | + | ||
735 | + this.initProbList[randomIndex]++ | ||
736 | + generatedSequence.push(randomIndex) | ||
737 | + } | ||
738 | + | ||
739 | + this.singleTrainingData.push(generatedSequence) | ||
740 | + } | ||
741 | + | ||
742 | + for (let index = 0; index < 10; index++) { | ||
743 | + this.initProbList[index] /= 500 | ||
744 | + } | ||
745 | + } | ||
746 | + | ||
747 | + setTrainingDataForAll () { | ||
748 | + // 학습 셋에 STATE 추가 | ||
749 | + this.trainingSet.set(this.userInputState, []) | ||
750 | + | ||
751 | + // MC 초기 확률 리스트 초기화 | ||
752 | + for (let index = 0; index < 10; index++) { | ||
753 | + this.initProbList[index] = 0 | ||
754 | + } | ||
755 | + | ||
756 | + const parsedSequenceList: any[] = [] | ||
757 | + for (let index = 0; index < this.scenarioList.length; index++) { | ||
758 | + const parsedSequence = this.parseSequence(this.scenarioList[index].sequence) | ||
759 | + | ||
760 | + parsedSequenceList.push(parsedSequence) | ||
761 | + } | ||
762 | + | ||
763 | + const iter = this.trainingSet.get(this.userInputState) | ||
764 | + if (iter === null || iter === undefined) { | ||
765 | + return | ||
766 | + } | ||
767 | + | ||
768 | + for (let index = 0; index < 100; index++) { | ||
769 | + const randomIndex = Math.floor(Math.random() * parsedSequenceList.length) | ||
770 | + | ||
771 | + this.singleTrainingData.push(parsedSequenceList[randomIndex]) | ||
772 | + for (let secondIndex = 0; secondIndex < 5; secondIndex++) { | ||
773 | + this.initProbList[parsedSequenceList[randomIndex][secondIndex]]++ | ||
774 | + } | ||
775 | + | ||
776 | + iter.push(parsedSequenceList[randomIndex]) | ||
777 | + } | ||
778 | + | ||
779 | + for (let index = 0; index < 10; index++) { | ||
780 | + this.initProbList[index] /= 500 | ||
781 | + } | ||
782 | + } | ||
783 | + | ||
784 | + setTrainingDataForRNN () { | ||
785 | + // 학습 셋에 STATE 추가 | ||
786 | + this.trainingSet.set(this.userInputState, []) | ||
787 | + | ||
788 | + const parsedSequenceList: any[] = [] | ||
789 | + for (let index = 0; index < this.scenarioList.length; index++) { | ||
790 | + const parsedSequence = this.parseSequence(this.scenarioList[index].sequence) | ||
791 | + | ||
792 | + parsedSequenceList.push(parsedSequence) | ||
793 | + } | ||
794 | + | ||
795 | + const iter = this.trainingSet.get(this.userInputState) | ||
796 | + if (iter === null || iter === undefined) { | ||
797 | + return | ||
798 | + } | ||
799 | + | ||
800 | + for (let index = 0; index < parsedSequenceList.length; index++) { | ||
801 | + const sequence = parsedSequenceList[index] | ||
802 | + | ||
803 | + this.singleTrainingData.push(sequence) | ||
804 | + iter.push(sequence) | ||
805 | + } | ||
806 | + } | ||
807 | + | ||
808 | + trainingForHMM () { | ||
809 | + const stateStrings = [...this.trainingSet.keys()] | ||
810 | + const nState = stateStrings.length | ||
811 | + const nObservation = 10 // 블록 ID (임시로 숫자로 가정... 0 ~ 9) | ||
812 | + const observation2stateMatrix = Array(nObservation).fill(null).map(() => Array(nState).fill(0)) | ||
813 | + const observation2observationMatrix = Array(nObservation).fill(null).map(() => Array(nObservation).fill(0)) | ||
814 | + | ||
815 | + let observationCount = 0 | ||
816 | + | ||
817 | + for (let i = 0; i < nState; i++) { | ||
818 | + const key = stateStrings[i] | ||
819 | + const observations: any[] = this.trainingSet.get(key)! | ||
820 | + for (let j = 0; j < observations.length; j++) { | ||
821 | + const observation: number[] = observations[j] | ||
822 | + for (let k = 0; k < observation.length - 1; k++) { | ||
823 | + observation2observationMatrix[observation[k]][observation[k + 1]]++ | ||
824 | + observation2stateMatrix[observation[k]][i]++ | ||
825 | + observationCount++ | ||
826 | + } | ||
827 | + observation2stateMatrix[observation[observation.length - 1]][i]++ | ||
828 | + } | ||
829 | + } | ||
830 | + | ||
831 | + for (let i = 0; i < nState; i++) { | ||
832 | + const key: string = stateStrings[i] | ||
833 | + const obervationTrainNum: number = this.trainingSet.get(key)!.length | ||
834 | + | ||
835 | + for (let j = 0; j < 10; j++) { | ||
836 | + observation2stateMatrix[j][i] = observation2stateMatrix[j][i] / obervationTrainNum | ||
837 | + } | ||
838 | + } | ||
839 | + | ||
840 | + for (let i = 0; i < 10; i++) { | ||
841 | + for (let j = 0; j < 10; j++) { | ||
842 | + observation2observationMatrix[i][j] = observation2observationMatrix[i][j] / observationCount | ||
843 | + } | ||
844 | + } | ||
845 | + | ||
846 | + this.observation2stateMatrix = observation2stateMatrix | ||
847 | + this.observation2observationMatrix = observation2observationMatrix | ||
848 | + | ||
849 | + console.log(JSON.stringify(observation2stateMatrix).replace(/([[)(.*)(]])/g, '[\n [$2]\n]').replace(/],/g, '],\n ')) | ||
850 | + console.log(JSON.stringify(observation2observationMatrix).replace(/([[)(.*)(]])/g, '[\n [$2]\n]').replace(/],/g, '],\n ')) | ||
851 | + } | ||
852 | + | ||
853 | + trainingForMC () { | ||
854 | + const nState = 10 | ||
855 | + const state2stateMatrix = Array(nState).fill(null).map(() => Array(nState).fill(0)) | ||
856 | + | ||
857 | + let stateCount = 0 | ||
858 | + for (let i = 0; i < this.singleTrainingData.length; i++) { | ||
859 | + const blockSequence: number[] = this.singleTrainingData[i] | ||
860 | + for (let j = 0; j < blockSequence.length - 1; j++) { | ||
861 | + state2stateMatrix[blockSequence[j]][blockSequence[j + 1]]++ | ||
862 | + stateCount++ | ||
863 | + } | ||
864 | + } | ||
865 | + | ||
866 | + for (let i = 0; i < 10; i++) { | ||
867 | + for (let j = 0; j < 10; j++) { | ||
868 | + state2stateMatrix[i][j] = state2stateMatrix[i][j] / stateCount | ||
869 | + | ||
870 | + if (state2stateMatrix[i][j] === 0) { | ||
871 | + state2stateMatrix[i][j] = 0.0001 | ||
872 | + } | ||
873 | + } | ||
874 | + } | ||
875 | + | ||
876 | + this.state2stateMatrix = state2stateMatrix | ||
877 | + | ||
878 | + console.log(JSON.stringify(state2stateMatrix).replace(/([[)(.*)(]])/g, '[\n [$2]\n]').replace(/],/g, '],\n ')) | ||
879 | + } | ||
880 | + | ||
881 | + trainingForRNN () { | ||
882 | + const stateString = [...this.trainingSet.keys()] | ||
883 | + const trainDataList: object[] = [] | ||
884 | + | ||
885 | + for (let i = 0; i < stateString.length; i++) { | ||
886 | + const key = stateString[i] | ||
887 | + const iter = this.trainingSet.get(key) as any[] | ||
888 | + | ||
889 | + for (let j = 0; j < iter.length; j++) { | ||
890 | + const trainEntry = { | ||
891 | + input: [], | ||
892 | + output: '' | ||
893 | + } | ||
894 | + | ||
895 | + trainEntry.input = iter[j] | ||
896 | + trainEntry.output = key | ||
897 | + | ||
898 | + trainDataList.push(trainEntry) | ||
899 | + } | ||
900 | + } | ||
901 | + | ||
902 | + if (this.tabIndex === 2) { | ||
903 | + this.netRnn.train(trainDataList, { | ||
904 | + iterations: 30, | ||
905 | + log: (details) => console.log(details), | ||
906 | + errorThresh: 0.011 | ||
907 | + }) | ||
908 | + } else if (this.tabIndex === 3) { | ||
909 | + this.netLstm.train(trainDataList, { | ||
910 | + iterations: 30, | ||
911 | + log: (details) => console.log(details), | ||
912 | + errorThresh: 0.011 | ||
913 | + }) | ||
914 | + } else { | ||
915 | + this.netRnn = new brain.recurrent.RNN() | ||
916 | + this.netLstm = new brain.recurrent.LSTM() | ||
917 | + | ||
918 | + this.netRnn.train(trainDataList, { | ||
919 | + iterations: 30, | ||
920 | + log: (details) => console.log('RNN: ' + details), | ||
921 | + errorThresh: 0.0001 | ||
922 | + }) | ||
923 | + | ||
924 | + this.netLstm.train(trainDataList, { | ||
925 | + iterations: 30, | ||
926 | + log: (details) => console.log('LSTN: ' + details), | ||
927 | + errorThresh: 0.0001 | ||
928 | + }) | ||
929 | + } | ||
930 | + } | ||
931 | + | ||
932 | + detectSpeech () { | ||
933 | + if (this.tabIndex === 0) { | ||
934 | + this.detectSpeechForHMM() | ||
935 | + } else if (this.tabIndex === 1) { | ||
936 | + this.detectSpeechForMC() | ||
937 | + } else if (this.tabIndex === 2 || this.tabIndex === 3) { | ||
938 | + this.detectSpeechForRNN() | ||
939 | + } else { | ||
940 | + this.detectSpeechForHMM() | ||
941 | + this.detectSpeechForMC() | ||
942 | + this.detectSpeechForRNN() | ||
943 | + } | ||
944 | + } | ||
945 | + | ||
946 | + detectSpeechForHMM () { | ||
947 | + const parsedSequence = this.parseSequence(this.userInputScenario.sequence) | ||
948 | + this.detectedSpeech = parsedSequence.toString() | ||
949 | + | ||
950 | + const stateStrings = [...this.trainingSet.keys()] | ||
951 | + const nState = stateStrings.length | ||
952 | + const likelyhoodofAllClass = Array(nState).fill(1) | ||
953 | + | ||
954 | + for (let i = 0; i < parsedSequence.length - 1; i++) { | ||
955 | + const previousState = parsedSequence[i] | ||
956 | + const currentState = parsedSequence[i + 1] | ||
957 | + | ||
958 | + for (let i = 0; i < nState; i++) { | ||
959 | + likelyhoodofAllClass[i] = likelyhoodofAllClass[i] * this.observation2observationMatrix[previousState][currentState] | ||
960 | + likelyhoodofAllClass[i] = likelyhoodofAllClass[i] * this.observation2stateMatrix[currentState][i] | ||
961 | + } | ||
962 | + } | ||
963 | + | ||
964 | + const i = likelyhoodofAllClass.indexOf(Math.max(...likelyhoodofAllClass)) | ||
965 | + if (this.tabIndex === 4) { | ||
966 | + this.detectedSpeechHMM = stateStrings[i] | ||
967 | + } else { | ||
968 | + this.detectedSpeechHMM = stateStrings[i] + ' ' + likelyhoodofAllClass[i].toString() | ||
969 | + } | ||
970 | + } | ||
971 | + | ||
972 | + detectSpeechForMC () { | ||
973 | + try { | ||
974 | + const stateStrings = [...this.trainingSet.keys()] | ||
975 | + | ||
976 | + let sequenceNum | ||
977 | + if (this.tabIndex === 4) { | ||
978 | + sequenceNum = this.parseSequence(this.userInputScenario.sequence).length | ||
979 | + } else { | ||
980 | + sequenceNum = parseInt(this.userInputStateSequence) | ||
981 | + } | ||
982 | + | ||
983 | + let resultMatrix: number[][] = this.state2stateMatrix | ||
984 | + for (let index = 1; index < sequenceNum; index++) { | ||
985 | + resultMatrix = this.multiplyMatrices(resultMatrix, this.state2stateMatrix) | ||
986 | + } | ||
987 | + | ||
988 | + const parsedSequence = this.parseSequence(this.userInputScenario.sequence) | ||
989 | + this.detectedSpeech = parsedSequence.toString() | ||
990 | + | ||
991 | + const nState = stateStrings.length | ||
992 | + const likelyhoodofAllClass = Array(nState).fill(0) | ||
993 | + | ||
994 | + for (let i = 0; i < nState; i++) { | ||
995 | + for (let j = 0; j < nState; j++) { | ||
996 | + likelyhoodofAllClass[i] += resultMatrix[j][i] * this.initProbList[j] | ||
997 | + } | ||
998 | + } | ||
999 | + | ||
1000 | + const i = likelyhoodofAllClass.indexOf(Math.max(...likelyhoodofAllClass)) | ||
1001 | + if (this.tabIndex === 4) { | ||
1002 | + this.detectedSpeechMC = stateStrings[i] | ||
1003 | + } else { | ||
1004 | + this.detectedSpeech = this.blockList[i].speech + ' ' + likelyhoodofAllClass[i].toString() | ||
1005 | + } | ||
1006 | + } catch (e) { | ||
1007 | + console.log(e) | ||
1008 | + } | ||
1009 | + } | ||
1010 | + | ||
1011 | + detectSpeechForRNN () { | ||
1012 | + if (this.userInputScenario.sequence === '') { | ||
1013 | + return | ||
1014 | + } | ||
1015 | + | ||
1016 | + const parsedSequence = this.parseSequence(this.userInputScenario.sequence) | ||
1017 | + let result = '' | ||
1018 | + if (this.tabIndex === 2) { | ||
1019 | + result = this.netRnn.run(parsedSequence) | ||
1020 | + } else if (this.tabIndex === 3) { | ||
1021 | + result = this.netLstm.run(parsedSequence) | ||
1022 | + } else { | ||
1023 | + this.detectedSpeechRNN = this.netRnn.run(parsedSequence) | ||
1024 | + this.detectedSpeechLSTM = this.netLstm.run(parsedSequence) | ||
1025 | + } | ||
1026 | + | ||
1027 | + this.detectedSpeech = result | ||
1028 | + } | ||
1029 | + | ||
1030 | + multiplyMatrices (mat1: number[][], mat2: number[][]) { | ||
1031 | + if (this.matricesAreValid(mat1, mat2)) { | ||
1032 | + const rows = this.getMatrixRows(mat1) | ||
1033 | + const cols = this.getMatrixColumns(mat2) | ||
1034 | + | ||
1035 | + return this.generateEmptyMatrix(rows, cols).map((resultRow, i) => | ||
1036 | + resultRow.map((element: number, j: number) => { | ||
1037 | + const column = mat2.map(row => row[j]) | ||
1038 | + const row = mat1[i] | ||
1039 | + | ||
1040 | + return this.dotProduct(row, column) | ||
1041 | + }) | ||
1042 | + ) | ||
1043 | + } else { | ||
1044 | + return mat1 | ||
1045 | + } | ||
1046 | + } | ||
1047 | + | ||
1048 | + getMatrixColumns (a: number[][]) { | ||
1049 | + return a[0].length | ||
1050 | + } | ||
1051 | + | ||
1052 | + getMatrixRows (a: number[][]) { | ||
1053 | + return a.length | ||
1054 | + } | ||
1055 | + | ||
1056 | + matricesAreValid (a: number[][], b: number[][]) { | ||
1057 | + return this.getMatrixColumns(a) === this.getMatrixRows(b) | ||
1058 | + } | ||
1059 | + | ||
1060 | + generateEmptyMatrix (rows: number, cols: number) { | ||
1061 | + return [...Array(rows)].fill(0).map(() => [...Array(cols)].fill(0)) | ||
1062 | + } | ||
1063 | + | ||
1064 | + dotProduct (a: number[], b: number[]) { | ||
1065 | + return a.map((value, i) => value * b[i]).reduce((acc, val) => acc + val, 0) | ||
1066 | + } | ||
1067 | +} | ||
1068 | +</script> | ||
1069 | + | ||
1070 | +<style scoped> | ||
1071 | +.main-layout { | ||
1072 | + height: 100%; | ||
1073 | + width: 100%; | ||
1074 | +} | ||
1075 | + | ||
1076 | +.scenario-item { | ||
1077 | + display: flex; | ||
1078 | + flex-direction: row; | ||
1079 | +} | ||
1080 | + | ||
1081 | +.content-wrapper { | ||
1082 | + min-width: 1024px; | ||
1083 | + height: 100%; | ||
1084 | +} | ||
1085 | +</style> |
소스 코드/src/main.ts
0 → 100644
1 | +import Vue from 'vue' | ||
2 | +import App from './App.vue' | ||
3 | +import BootstrapVue from 'bootstrap-vue' | ||
4 | +import 'bootstrap/dist/css/bootstrap.min.css' | ||
5 | +import 'bootstrap-vue/dist/bootstrap-vue.css' | ||
6 | + | ||
7 | +Vue.config.productionTip = false | ||
8 | +Vue.use(BootstrapVue) | ||
9 | + | ||
10 | +new Vue({ | ||
11 | + render: h => h(App) | ||
12 | +}).$mount('#app') |
소스 코드/src/shims-tsx.d.ts
0 → 100644
1 | +import Vue, { VNode } from 'vue' | ||
2 | + | ||
3 | +declare global { | ||
4 | + namespace JSX { | ||
5 | + // tslint:disable no-empty-interface | ||
6 | + interface Element extends VNode {} | ||
7 | + // tslint:disable no-empty-interface | ||
8 | + interface ElementClass extends Vue {} | ||
9 | + interface IntrinsicElements { | ||
10 | + [elem: string]: any; | ||
11 | + } | ||
12 | + } | ||
13 | +} |
소스 코드/src/shims-vue.d.ts
0 → 100644
소스 코드/tsconfig.json
0 → 100644
1 | +{ | ||
2 | + "compilerOptions": { | ||
3 | + "target": "esnext", | ||
4 | + "module": "esnext", | ||
5 | + "strict": true, | ||
6 | + "jsx": "preserve", | ||
7 | + "importHelpers": true, | ||
8 | + "moduleResolution": "node", | ||
9 | + "experimentalDecorators": true, | ||
10 | + "esModuleInterop": true, | ||
11 | + "allowSyntheticDefaultImports": true, | ||
12 | + "sourceMap": true, | ||
13 | + "baseUrl": ".", | ||
14 | + "types": [ | ||
15 | + "webpack-env" | ||
16 | + ], | ||
17 | + "paths": { | ||
18 | + "@/*": [ | ||
19 | + "src/*" | ||
20 | + ] | ||
21 | + }, | ||
22 | + "lib": [ | ||
23 | + "esnext", | ||
24 | + "dom", | ||
25 | + "dom.iterable", | ||
26 | + "scripthost" | ||
27 | + ] | ||
28 | + }, | ||
29 | + "include": [ | ||
30 | + "src/**/*.ts", | ||
31 | + "src/**/*.tsx", | ||
32 | + "src/**/*.vue", | ||
33 | + "tests/**/*.ts", | ||
34 | + "tests/**/*.tsx" | ||
35 | + ], | ||
36 | + "exclude": [ | ||
37 | + "node_modules" | ||
38 | + ], | ||
39 | +} |
제출물/~$최종발표자료.pptx
deleted
100644 → 0
No preview for this file type
제출물/최종발표영상.mov
0 → 100644
This file is too large to display.
No preview for this file type
-
Please register or login to post a comment