SugarAddict commited on
Commit
2eefb14
·
1 Parent(s): b5a9c4d

Upload 8 files

Browse files
Files changed (9) hide show
  1. .gitattributes +1 -0
  2. bar.png +0 -0
  3. data2_pro.xlsx +3 -0
  4. flip.py +92 -0
  5. naive_bayes_model.pkl +3 -0
  6. stop_words.txt +746 -0
  7. train_eval.py +119 -0
  8. updated_predict.py +223 -0
  9. utils.py +156 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ data2_pro.xlsx filter=lfs diff=lfs merge=lfs -text
bar.png ADDED
data2_pro.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a445e6894cb129b40c63aa4cdb2a1a177e532fa6214fd21292a9b5c1cf0cbcc6
3
+ size 79735899
flip.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import gradio as gr
3
+ import random
4
+ import time
5
+ from updated_predict import working_func
6
+
7
+ theme = gr.themes.Soft(
8
+ primary_hue="emerald",
9
+ secondary_hue="teal",
10
+ neutral_hue="indigo",
11
+ # text_size="text_lg",
12
+ # radius_size="radius_lg",
13
+ ).set(
14
+ #body_background_fill='*checkbox_label_background_fill',
15
+ #body_background_fill='*block_title_background_fill',
16
+ body_background_fill='*background_fill_secondary',
17
+ background_fill_primary='*neutral_200',
18
+ block_background_fill='*table_even_background_fill',
19
+ button_border_width='*block_title_border_width',
20
+ button_shadow='*button_shadow_hover'
21
+ )
22
+
23
+
24
+ def flip_text(x):
25
+ return x[::-1]
26
+
27
+
28
+ def flip_image(x):
29
+ return np.fliplr(x)
30
+
31
+ def diagnosed_huxi():
32
+ return "呼吸科"
33
+
34
+ def diagnosed_shennei():
35
+ return "神经内科"
36
+
37
+ def diagnosed_xiaohua():
38
+ return "内科 消化科/胃肠科"
39
+
40
+ def diagnosed_xinnei():
41
+ return "内科 心脏内科"
42
+ text_output = gr.Textbox(label="科室")
43
+
44
+ with gr.Blocks(theme=theme) as demo:
45
+ gr.Markdown("医疗分诊助手")
46
+ gr.Image("bar.png")
47
+ with gr.Tab("常见疑问"):
48
+ with gr.Row():
49
+ btn1 = gr.Button(value="癫痫")
50
+ btn1.click(diagnosed_shennei, inputs=[], outputs=[text_output])
51
+
52
+ btn2 = gr.Button(value="咳嗽")
53
+ btn2.click(diagnosed_huxi, inputs=[], outputs=[text_output])
54
+
55
+ btn3 = gr.Button(value="感冒")
56
+ btn3.click(diagnosed_huxi, inputs=[], outputs=[text_output])
57
+
58
+
59
+ with gr.Row():
60
+ btn4 = gr.Button(value="高血压")
61
+ btn4.click(diagnosed_xinnei, inputs=[], outputs=[text_output])
62
+
63
+ btn5 = gr.Button(value="发烧")
64
+ btn5.click(diagnosed_huxi, inputs=[], outputs=[text_output])
65
+
66
+ btn6 = gr.Button(value="胃炎")
67
+ btn6.click(diagnosed_xiaohua, inputs=[], outputs=[text_output])
68
+
69
+ with gr.Row():
70
+ text_output.render()
71
+
72
+ with gr.Tab("手动键入"):
73
+ chatbot = gr.Chatbot()
74
+ msg = gr.Textbox()
75
+ clear = gr.ClearButton([msg, chatbot])
76
+ def respond(message, chat_history):
77
+ result = working_func(message)
78
+ bot_message = "科室:" + result[0] + ',' + result[1] + '\n' + "回答:" + result[2]
79
+ chat_history.append((message, bot_message))
80
+ time.sleep(2)
81
+ return "", chat_history
82
+
83
+
84
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
85
+
86
+ with gr.Accordion("Open for More!"):
87
+ gr.Markdown("Look at me...")
88
+
89
+ #text_button.click(flip_text, inputs=text_input, outputs=text_output)
90
+ #image_button.click(flip_image, inputs=image_input, outputs=image_output)
91
+
92
+ demo.launch()
naive_bayes_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33e0de74a3ee49f0bbae068452f0e357d0fbcc4e39ad7f3c7353324ece2adf96
3
+ size 480800
stop_words.txt ADDED
@@ -0,0 +1,746 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $
2
+ 0
3
+ 1
4
+ 2
5
+ 3
6
+ 4
7
+ 5
8
+ 6
9
+ 7
10
+ 8
11
+ 9
12
+ ?
13
+ _
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ 一些
22
+ 一何
23
+ 一切
24
+ 一则
25
+ 一方面
26
+ 一旦
27
+ 一来
28
+ 一样
29
+ 一般
30
+ 一转眼
31
+ 万一
32
+
33
+ 上下
34
+
35
+
36
+ 不仅
37
+ 不但
38
+ 不光
39
+ 不单
40
+ 不只
41
+ 不外乎
42
+ 不如
43
+ 不妨
44
+ 不尽
45
+ 不尽然
46
+ 不得
47
+ 不怕
48
+ 不惟
49
+ 不成
50
+ 不拘
51
+ 不料
52
+ 不是
53
+ 不比
54
+ 不然
55
+ 不特
56
+ 不独
57
+ 不管
58
+ 不至于
59
+ 不若
60
+ 不论
61
+ 不过
62
+ 不问
63
+
64
+ 与其
65
+ 与其说
66
+ 与否
67
+ 与此同时
68
+
69
+ 且不说
70
+ 且说
71
+ 两者
72
+
73
+ 个别
74
+
75
+
76
+ 为了
77
+ 为什么
78
+ 为何
79
+ 为止
80
+ 为此
81
+ 为着
82
+
83
+ 乃至
84
+ 乃至于
85
+
86
+
87
+ 之一
88
+ 之所以
89
+ 之类
90
+ 乌乎
91
+
92
+
93
+
94
+ 也好
95
+ 也罢
96
+
97
+ 二来
98
+
99
+ 于是
100
+ 于是乎
101
+ 云云
102
+ 云尔
103
+
104
+
105
+
106
+ 人们
107
+ 人家
108
+ 什么
109
+ 什么样
110
+
111
+ 介于
112
+
113
+ 仍旧
114
+
115
+ 从此
116
+ 从而
117
+
118
+ 他人
119
+ 他们
120
+
121
+ 以上
122
+ 以为
123
+ 以便
124
+ 以免
125
+ 以及
126
+ 以故
127
+ 以期
128
+ 以来
129
+ 以至
130
+ 以至于
131
+ 以致
132
+
133
+
134
+ 任何
135
+ 任凭
136
+ 似的
137
+
138
+ 但凡
139
+ 但是
140
+
141
+ 何以
142
+ 何况
143
+ 何处
144
+ 何时
145
+ 余外
146
+ 作为
147
+
148
+ 你们
149
+ 使
150
+ 使得
151
+ 例如
152
+
153
+ 依据
154
+ 依照
155
+ 便于
156
+
157
+ 俺们
158
+
159
+ 倘使
160
+ 倘或
161
+ 倘然
162
+ 倘若
163
+
164
+ 假使
165
+ 假如
166
+ 假若
167
+ 傥然
168
+
169
+
170
+ 先不先
171
+ 光是
172
+ 全体
173
+ 全部
174
+
175
+ 关于
176
+
177
+ 其一
178
+ 其中
179
+ 其二
180
+ 其他
181
+ 其余
182
+ 其它
183
+ 其次
184
+ 具体地说
185
+ 具体说来
186
+ 兼之
187
+
188
+
189
+ 再其次
190
+ 再则
191
+ 再有
192
+ 再者
193
+ 再者说
194
+ 再说
195
+
196
+
197
+ 况且
198
+
199
+ 几时
200
+
201
+ 凡是
202
+
203
+ 凭借
204
+ 出于
205
+ 出来
206
+ 分别
207
+
208
+ 则甚
209
+
210
+ 别人
211
+ 别处
212
+ 别是
213
+ 别的
214
+ 别管
215
+ 别说
216
+
217
+ 前后
218
+ 前此
219
+ 前者
220
+ 加之
221
+ 加以
222
+
223
+ 即令
224
+ 即使
225
+ 即便
226
+ 即如
227
+ 即或
228
+ 即若
229
+
230
+
231
+
232
+ 又及
233
+
234
+ 及其
235
+ 及至
236
+ 反之
237
+ 反而
238
+ 反过来
239
+ 反过来说
240
+ 受到
241
+
242
+ 另一方面
243
+ 另外
244
+ 另悉
245
+
246
+ 只当
247
+ 只怕
248
+ 只是
249
+ 只有
250
+ 只消
251
+ 只要
252
+ 只限
253
+
254
+ 叮咚
255
+
256
+ 可以
257
+ 可是
258
+ 可见
259
+
260
+ 各个
261
+ 各位
262
+ 各种
263
+ 各自
264
+
265
+ 同时
266
+
267
+ 后者
268
+
269
+ 向使
270
+ 向着
271
+
272
+
273
+ 否则
274
+
275
+ 吧哒
276
+
277
+
278
+
279
+
280
+
281
+
282
+ 呜呼
283
+
284
+
285
+ 呵呵
286
+
287
+ 呼哧
288
+
289
+
290
+
291
+
292
+
293
+
294
+ 咱们
295
+
296
+
297
+
298
+ 哈哈
299
+
300
+
301
+ 哎呀
302
+ 哎哟
303
+
304
+
305
+
306
+
307
+
308
+ 哪个
309
+ 哪些
310
+ 哪儿
311
+ 哪天
312
+ 哪年
313
+ 哪怕
314
+ 哪样
315
+ 哪边
316
+ 哪里
317
+
318
+ 哼唷
319
+
320
+ 唯有
321
+
322
+
323
+
324
+
325
+ 啪达
326
+ 啷当
327
+
328
+
329
+ 喔唷
330
+
331
+
332
+ 嗡嗡
333
+
334
+
335
+
336
+
337
+ 嘎登
338
+
339
+
340
+
341
+
342
+ 嘿嘿
343
+
344
+ 因为
345
+ 因了
346
+ 因此
347
+ 因着
348
+ 因而
349
+ 固然
350
+
351
+ 在下
352
+ 在于
353
+
354
+ 基于
355
+ 处在
356
+
357
+ 多么
358
+ 多少
359
+
360
+ 大家
361
+
362
+ 她们
363
+
364
+
365
+ 如上
366
+ 如上所述
367
+ 如下
368
+ 如何
369
+ 如其
370
+ 如同
371
+ 如是
372
+ 如果
373
+ 如此
374
+ 如若
375
+ 始而
376
+ 孰料
377
+ 孰知
378
+
379
+ 宁可
380
+ 宁愿
381
+ 宁肯
382
+
383
+ 它们
384
+
385
+ 对于
386
+ 对待
387
+ 对方
388
+ 对比
389
+
390
+
391
+
392
+ 尔后
393
+ 尔尔
394
+ 尚且
395
+
396
+ 就是
397
+ 就是了
398
+ 就是说
399
+ 就算
400
+ 就要
401
+
402
+ 尽管
403
+ 尽管如此
404
+ 岂但
405
+
406
+
407
+ 已矣
408
+
409
+ 巴巴
410
+
411
+ 并且
412
+ 并非
413
+ 庶乎
414
+ 庶几
415
+ 开外
416
+ 开始
417
+
418
+ 归齐
419
+
420
+ 当地
421
+ 当然
422
+ 当着
423
+
424
+ 彼时
425
+ 彼此
426
+
427
+
428
+
429
+
430
+ 得了
431
+
432
+ 怎么
433
+ 怎么办
434
+ 怎么样
435
+ 怎奈
436
+ 怎样
437
+ 总之
438
+ 总的来看
439
+ 总的来说
440
+ 总的说来
441
+ 总而言之
442
+ 恰恰相反
443
+
444
+ 惟其
445
+ 慢说
446
+
447
+ 我们
448
+
449
+ 或则
450
+ 或是
451
+ 或曰
452
+ 或者
453
+ 截至
454
+
455
+ 所以
456
+ 所在
457
+ 所幸
458
+ 所有
459
+
460
+ 才能
461
+
462
+ 打从
463
+
464
+ 抑或
465
+
466
+
467
+ 按照
468
+ 换句话说
469
+ 换言之
470
+
471
+ 据此
472
+ 接着
473
+
474
+ 故此
475
+ 故而
476
+ 旁人
477
+
478
+ 无宁
479
+ 无论
480
+
481
+ 既往
482
+ 既是
483
+ 既然
484
+ 时候
485
+
486
+ 是以
487
+ 是的
488
+
489
+
490
+ 替代
491
+
492
+
493
+ 有些
494
+ 有关
495
+ 有及
496
+ 有时
497
+ 有的
498
+
499
+
500
+ 朝着
501
+
502
+ 本人
503
+ 本地
504
+ 本着
505
+ 本身
506
+
507
+ 来着
508
+ 来自
509
+ 来说
510
+ 极了
511
+ 果然
512
+ 果真
513
+
514
+ 某个
515
+ 某些
516
+ 某某
517
+ 根据
518
+
519
+ 正值
520
+ 正如
521
+ 正巧
522
+ 正是
523
+
524
+ 此地
525
+ 此处
526
+ 此外
527
+ 此时
528
+ 此次
529
+ 此间
530
+ 毋宁
531
+
532
+ 每当
533
+
534
+ 比及
535
+ 比如
536
+ 比方
537
+ 没奈何
538
+ 沿
539
+ 沿着
540
+ 漫说
541
+
542
+ 然则
543
+ 然后
544
+ 然而
545
+
546
+ 照着
547
+ 犹且
548
+ 犹自
549
+ 甚且
550
+ 甚么
551
+ 甚或
552
+ 甚而
553
+ 甚至
554
+ 甚至于
555
+
556
+ 用来
557
+
558
+ 由于
559
+ 由是
560
+ 由此
561
+ 由此可见
562
+
563
+ 的确
564
+ 的话
565
+ 直到
566
+ 相对而言
567
+ 省得
568
+
569
+ 眨眼
570
+
571
+ 着呢
572
+
573
+ 矣乎
574
+ 矣哉
575
+
576
+ 竟而
577
+
578
+
579
+ 等到
580
+ 等等
581
+ 简言之
582
+
583
+ 类如
584
+ 紧接着
585
+
586
+ 纵令
587
+ 纵使
588
+ 纵然
589
+
590
+ 经过
591
+ 结果
592
+
593
+ 继之
594
+ 继后
595
+ 继而
596
+ 综上所述
597
+ 罢了
598
+
599
+
600
+ 而且
601
+ 而况
602
+ 而后
603
+ 而外
604
+ 而已
605
+ 而是
606
+ 而言
607
+
608
+ 能否
609
+
610
+
611
+ 自个儿
612
+ 自从
613
+ 自各儿
614
+ 自后
615
+ 自家
616
+ 自己
617
+ 自打
618
+ 自身
619
+
620
+ 至于
621
+ 至今
622
+ 至若
623
+
624
+ 般的
625
+
626
+ 若夫
627
+ 若是
628
+ 若果
629
+ 若非
630
+ 莫不然
631
+ 莫如
632
+ 莫若
633
+
634
+ 虽则
635
+ 虽然
636
+ 虽说
637
+
638
+
639
+ 要不
640
+ 要不是
641
+ 要不然
642
+ 要么
643
+ 要是
644
+ 譬喻
645
+ 譬如
646
+
647
+ 许多
648
+
649
+ 设使
650
+ 设或
651
+ 设若
652
+ 诚如
653
+ 诚然
654
+
655
+ 说来
656
+
657
+ 诸位
658
+ 诸如
659
+
660
+ 谁人
661
+ 谁料
662
+ 谁知
663
+ 贼死
664
+ 赖以
665
+
666
+
667
+ 起见
668
+
669
+ 趁着
670
+ 越是
671
+
672
+
673
+
674
+ 较之
675
+
676
+
677
+
678
+ 还是
679
+ 还有
680
+ 还要
681
+
682
+ 这一来
683
+ 这个
684
+ 这么
685
+ 这么些
686
+ 这么样
687
+ 这么点儿
688
+ 这些
689
+ 这会儿
690
+ 这儿
691
+ 这就是说
692
+ 这时
693
+ 这样
694
+ 这次
695
+ 这般
696
+ 这边
697
+ 这里
698
+ 进而
699
+ ���
700
+ 连同
701
+ 逐步
702
+ 通过
703
+ 遵循
704
+ 遵照
705
+
706
+ 那个
707
+ 那么
708
+ 那么些
709
+ 那么样
710
+ 那些
711
+ 那会儿
712
+ 那儿
713
+ 那时
714
+ 那样
715
+ 那般
716
+ 那边
717
+ 那里
718
+
719
+ 鄙人
720
+ 鉴于
721
+ 针对
722
+
723
+
724
+ 除了
725
+ 除外
726
+ 除开
727
+ 除此之外
728
+ 除非
729
+
730
+ 随后
731
+ 随时
732
+ 随着
733
+ 难道说
734
+ 非但
735
+ 非徒
736
+ 非特
737
+ 非独
738
+
739
+
740
+ 顺着
741
+ 首先
742
+
743
+
744
+
745
+
746
+
train_eval.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: UTF-8
2
+ import numpy as np
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+ from sklearn import metrics
7
+ import time
8
+ from utils import get_time_dif
9
+ from tensorboardX import SummaryWriter
10
+
11
+
12
+ # 权重初始化,默认xavier
13
+ def init_network(model, method='xavier', exclude='embedding', seed=123):
14
+ for name, w in model.named_parameters():
15
+ if exclude not in name:
16
+ if 'weight' in name:
17
+ if method == 'xavier':
18
+ nn.init.xavier_normal_(w)
19
+ elif method == 'kaiming':
20
+ nn.init.kaiming_normal_(w)
21
+ else:
22
+ nn.init.normal_(w)
23
+ elif 'bias' in name:
24
+ nn.init.constant_(w, 0)
25
+ else:
26
+ pass
27
+
28
+
29
+ def train(config, model, train_iter, dev_iter, test_iter):
30
+ start_time = time.time()
31
+ model.train()
32
+ optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate)
33
+
34
+ # 学习率指数衰减,每次epoch:学习率 = gamma * 学习率
35
+ # scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
36
+ total_batch = 0 # 记录进行到多少batch
37
+ dev_best_loss = float('inf')
38
+ last_improve = 0 # 记录上次验证集loss下降的batch数
39
+ flag = False # 记录是否很久没有效果提升
40
+ writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))
41
+ for epoch in range(config.num_epochs):
42
+ print('Epoch [{}/{}]'.format(epoch + 1, config.num_epochs))
43
+ # scheduler.step() # 学习率衰减
44
+ for i, (trains, labels) in enumerate(train_iter):
45
+ outputs = model(trains)
46
+ model.zero_grad()
47
+ loss = F.cross_entropy(outputs, labels)
48
+ loss.backward()
49
+ optimizer.step()
50
+ if total_batch % 100 == 0:
51
+ # 每多少轮输出在训练集和验证集上的效果
52
+ true = labels.data.cpu()
53
+ predic = torch.max(outputs.data, 1)[1].cpu()
54
+ train_acc = metrics.accuracy_score(true, predic)
55
+ dev_acc, dev_loss = evaluate(config, model, dev_iter)
56
+ if dev_loss < dev_best_loss:
57
+ dev_best_loss = dev_loss
58
+ torch.save(model.state_dict(), config.save_path)
59
+ improve = '*'
60
+ last_improve = total_batch
61
+ else:
62
+ improve = ''
63
+ time_dif = get_time_dif(start_time)
64
+ msg = 'Iter: {0:>6}, Train Loss: {1:>5.2}, Train Acc: {2:>6.2%}, Val Loss: {3:>5.2}, Val Acc: {4:>6.2%}, Time: {5} {6}'
65
+ print(msg.format(total_batch, loss.item(), train_acc, dev_loss, dev_acc, time_dif, improve))
66
+ writer.add_scalar("loss/train", loss.item(), total_batch)
67
+ writer.add_scalar("loss/dev", dev_loss, total_batch)
68
+ writer.add_scalar("acc/train", train_acc, total_batch)
69
+ writer.add_scalar("acc/dev", dev_acc, total_batch)
70
+ model.train()
71
+ total_batch += 1
72
+ if total_batch - last_improve > config.require_improvement:
73
+ # 验证集loss超过1000batch没下降,结束训练
74
+ print("No optimization for a long time, auto-stopping...")
75
+ flag = True
76
+ break
77
+ if flag:
78
+ break
79
+ writer.close()
80
+ test(config, model, test_iter)
81
+
82
+
83
+ def test(config, model, test_iter):
84
+ # test
85
+ model.load_state_dict(torch.load(config.save_path))
86
+ model.eval()
87
+ start_time = time.time()
88
+ test_acc, test_loss, test_report, test_confusion = evaluate(config, model, test_iter, test=True)
89
+ msg = 'Test Loss: {0:>5.2}, Test Acc: {1:>6.2%}'
90
+ print(msg.format(test_loss, test_acc))
91
+ print("Precision, Recall and F1-Score...")
92
+ print(test_report)
93
+ print("Confusion Matrix...")
94
+ print(test_confusion)
95
+ time_dif = get_time_dif(start_time)
96
+ print("Time usage:", time_dif)
97
+
98
+
99
+ def evaluate(config, model, data_iter, test=False):
100
+ model.eval()
101
+ loss_total = 0
102
+ predict_all = np.array([], dtype=int)
103
+ labels_all = np.array([], dtype=int)
104
+ with torch.no_grad():
105
+ for texts, labels in data_iter:
106
+ outputs = model(texts)
107
+ loss = F.cross_entropy(outputs, labels)
108
+ loss_total += loss
109
+ labels = labels.data.cpu().numpy()
110
+ predic = torch.max(outputs.data, 1)[1].cpu().numpy()
111
+ labels_all = np.append(labels_all, labels)
112
+ predict_all = np.append(predict_all, predic)
113
+
114
+ acc = metrics.accuracy_score(labels_all, predict_all)
115
+ if test:
116
+ report = metrics.classification_report(labels_all, predict_all, target_names=config.class_list, digits=4)
117
+ confusion = metrics.confusion_matrix(labels_all, predict_all)
118
+ return acc, loss_total / len(data_iter), report, confusion
119
+ return acc, loss_total / len(data_iter)
updated_predict.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from importlib import import_module
2
+ import torch
3
+ import pandas as pd
4
+ import pickle as pkl
5
+ from tqdm import tqdm
6
+ from numpy.linalg import norm
7
+ from utils import build_vocab, build_iterator
8
+ import numpy as np
9
+ import os
10
+ from sklearn.feature_extraction.text import CountVectorizer
11
+ import jieba
12
+ import joblib
13
+ from sklearn.model_selection import train_test_split
14
+ import fasttext
15
+ import gradio as gr
16
+
17
+
18
+ MAX_VOCAB_SIZE = 10000
19
+ UNK, PAD = '<UNK>', '<PAD>'
20
+ module = import_module("models.TextCNN")
21
+ dataset = 'THUCNews'
22
+ embedding = 'embedding_SougouNews.npz' # 预训练的词向量表
23
+ config = module.Config(dataset, embedding)
24
+ model = module.Model(config).to(config.device)
25
+ model.load_state_dict(torch.load(config.save_path))
26
+ model.eval()
27
+
28
+
29
+ def build_dataset(content, config, ues_word):
30
+ if ues_word:
31
+ tokenizer = lambda x: x.split(' ') # 以空格隔开,word-level
32
+ else:
33
+ tokenizer = lambda x: [y for y in x] # char-level
34
+ if os.path.exists(config.vocab_path):
35
+ vocab = pkl.load(open(config.vocab_path, 'rb')) #打开词表文件
36
+ else:
37
+ vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
38
+ pkl.dump(vocab, open(config.vocab_path, 'wb'))
39
+ def load_dataset(pad_size=32):
40
+ contents = []
41
+ words_line = []
42
+ token = tokenizer(content)
43
+ seq_len = len(token)
44
+ if pad_size:
45
+ if len(token) < pad_size:
46
+ token.extend([PAD] * (pad_size - len(token)))
47
+ else:
48
+ token = token[:pad_size]
49
+ seq_len = pad_size
50
+ for word in token:
51
+ words_line.append(vocab.get(word, vocab.get(UNK)))
52
+ contents.append((words_line, -1, seq_len))
53
+ return contents # [([...], 0), ([...], 1), ...]
54
+ train = load_dataset(config.pad_size)
55
+ return vocab, train
56
+
57
+ def wordvector(config,df,pad_size=32):
58
+ wordvectorlist = []
59
+ answerlist = []
60
+ sentences = []
61
+ department = []
62
+ tokenizer = lambda x: [y for y in x] # char-level
63
+ if os.path.exists(config.vocab_path):
64
+ vocab = pkl.load(open(config.vocab_path, 'rb')) # 打开词表文件
65
+ else:
66
+ vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
67
+ pkl.dump(vocab, open(config.vocab_path, 'wb'))
68
+ for row in df.index:
69
+ content = df.loc[row]['ask']
70
+ answer = df.loc[row]['answer']
71
+ department.append(df.loc[row]['department'])
72
+ answerlist.append(answer)
73
+ sentences.append(content)
74
+ words_line = []
75
+ token = tokenizer(content)
76
+ if pad_size:
77
+ if len(token) < pad_size:
78
+ token.extend([PAD] * (pad_size - len(token)))
79
+ else:
80
+ token = token[:pad_size]
81
+ seq_len = pad_size
82
+ for word in token:
83
+ words_line.append(vocab.get(word, vocab.get(UNK)))
84
+ vector = words_line
85
+ wordvectorlist.append(vector)
86
+ return wordvectorlist, answerlist
87
+ def cos_similarity_test(vector,word_vector_list):
88
+ best_cosine = -10
89
+ for i in range(len(word_vector_list)):
90
+ best_index = 0
91
+ B = word_vector_list[i]
92
+ cosine = np.dot(vector, B) / (norm(vector) * norm(B))
93
+ if cosine > best_cosine:
94
+ best_cosine = cosine
95
+ best_index = i
96
+ return best_index
97
+
98
+ def predict_single_text(text,flag):
99
+ # 预测单条文本的分类
100
+ ft_model = None
101
+ if flag == 4:
102
+ ft_model = fasttext.load_model("./fasttext_model_erke.bin")
103
+ if flag == 5:
104
+ ft_model = fasttext.load_model("./fasttext_model_waike.bin")
105
+ prediction = ft_model.predict([text], k=1) # k=1表示只返回概率最高的标签
106
+ if prediction:
107
+ label = prediction[0][0][len('__label__'):] # 获取标签
108
+ str = prediction[0][0][0]
109
+ label = str[9:-1]
110
+ # print(str)
111
+ confidence = prediction[1][0] # 获取置信度
112
+ return label, confidence
113
+ else:
114
+ return None, None
115
+ def proceed(content,NumOfChamber,content_vector):
116
+ with open('./stop_words.txt', 'r', encoding="utf-8") as f:
117
+ stop_words = list(l.strip() for l in f.readlines())
118
+ stop_words.extend(['\n', '(', ')', ' ']) # 由于停用词中没有'\n'和中文的左右括号和空格,所以单独再加上去
119
+ if NumOfChamber == 0:
120
+ print("大类为:男科")
121
+ file = pd.read_csv("./THUCNews/data/Data/nanke/nanke1.csv", encoding='utf-8')
122
+ df = file[["department", "ask", "answer"]]
123
+ word_vector_list, answer_list = wordvector(config, df)
124
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
125
+ most_similar_answer = answer_list[most_similar_index]
126
+ return None, most_similar_answer
127
+ if NumOfChamber == 2:
128
+ print("大类为:妇产科")
129
+ file = pd.read_csv("./THUCNews/data/Data/fuchanke/fuchanke1.csv", encoding='utf-8')
130
+ df = file[["department", "ask", "answer"]]
131
+ word_vector_list, answer_list = wordvector(config, df)
132
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
133
+ most_similar_answer = answer_list[most_similar_index]
134
+ return None, most_similar_answer
135
+ if NumOfChamber == 3:
136
+ print("大类为:肿瘤科")
137
+ file = pd.read_csv("./THUCNews/data/Data/zhongliuke/zhongliuke1.csv", encoding='utf-8')
138
+ df = file[["department", "ask", "answer"]]
139
+ word_vector_list, answer_list = wordvector(config, df)
140
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
141
+ most_similar_answer = answer_list[most_similar_index]
142
+ return None, most_similar_answer
143
+ if NumOfChamber == 1:
144
+ print("大类为:内科")
145
+ data2 = pd.read_excel(io="data2_pro.xlsx", engine="openpyxl")
146
+ department_counts = data2['department'].value_counts()
147
+ underrepresented_categories = department_counts[department_counts < 20000].index
148
+ data2 = data2[~data2['department'].isin(underrepresented_categories)]
149
+ data2['Pre_Text'].fillna('', inplace=True)
150
+ X = data2['Pre_Text'] # 文本数据
151
+ y = data2['department'] # 标签
152
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
153
+ count_vectorizer = CountVectorizer(stop_words=stop_words, max_features=5000)
154
+ X_train_count = count_vectorizer.fit_transform(X_train)
155
+ X_test_count = count_vectorizer.transform(X_test)
156
+ input_text = content
157
+ nb_classifier = joblib.load('naive_bayes_model.pkl')
158
+ input_text_processed = " ".join([w for w in list(jieba.cut(str(input_text))) if w not in stop_words])
159
+ input_text_processed = count_vectorizer.transform([input_text_processed])
160
+ predicted_department = nb_classifier.predict(input_text_processed)
161
+
162
+ file = pd.read_csv("./THUCNews/data/Data/neike/neike1.csv", encoding='utf-8')
163
+ df = file[file["department"] == predicted_department[0]]
164
+ df = df[["department", "ask", "answer"]]
165
+ word_vector_list, answer_list = wordvector(config, df)
166
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
167
+ most_similar_answer = answer_list[most_similar_index]
168
+ return predicted_department[0], most_similar_answer
169
+ if NumOfChamber == 4:
170
+ print("大类为:儿科")
171
+ input_text = ' '.join([word for word in jieba.lcut(content) if word not in stop_words])
172
+ predicted_department, confidence_score = predict_single_text(input_text,4)
173
+ file = pd.read_csv("./THUCNews/data/Data/erke/erke1.csv", encoding='utf-8')
174
+ df = file[file["department"] == predicted_department]
175
+ df = df[["department", "ask", "answer"]]
176
+ word_vector_list, answer_list = wordvector(config, df)
177
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
178
+ most_similar_answer = answer_list[most_similar_index]
179
+ return predicted_department, most_similar_answer
180
+ if NumOfChamber == 5:
181
+ print("大类为:外科")
182
+ input_text = ' '.join([word for word in jieba.lcut(content) if word not in stop_words])
183
+ predicted_department, confidence_score = predict_single_text(input_text,5)
184
+ file = pd.read_csv("./THUCNews/data/Data/waike/waike1.csv", encoding='utf-8')
185
+ print(type(predicted_department))
186
+ print(predicted_department)
187
+ df = file[file["department"] == predicted_department]
188
+ df = df[["department", "ask", "answer"]]
189
+ word_vector_list, answer_list = wordvector(config, df)
190
+ most_similar_index = cos_similarity_test(content_vector,word_vector_list)
191
+ most_similar_answer = answer_list[most_similar_index]
192
+ return predicted_department, most_similar_answer
193
+
194
+
195
+
196
+ def working_func(content):
197
+ # content = input("请输入您的病情描述:")
198
+ vocab, train_data = build_dataset(content,config, False)
199
+ content_vector = train_data[0][0]
200
+ config.n_vocab = len(vocab)
201
+ train_iter = build_iterator(train_data, config)
202
+ predict_all = np.array([], dtype=int)
203
+ labels_all = np.array([], dtype=int)
204
+ result_list = ["男科","内科","妇产科","肿瘤科","儿科","外科"]
205
+ text = []
206
+ for texts, labels in train_iter:
207
+ outputs = model(texts)
208
+ labels = labels.data.cpu().numpy()
209
+ predic = torch.max(outputs.data, 1)[1].cpu().numpy()
210
+ labels_all = np.append(labels_all, labels)
211
+ predict_all = np.append(predict_all, predic)
212
+ result = predict_all[0] # 大科室对应的 数字顺序
213
+ DaKeShi = result_list[result]
214
+ text.append(DaKeShi)
215
+ XiaoKeShi, most_similar_answer = proceed(content, result, content_vector)
216
+ text.append(XiaoKeShi)
217
+ text.append(most_similar_answer)
218
+ print(XiaoKeShi)
219
+ print(most_similar_answer)
220
+ return text
221
+
222
+
223
+
utils.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: UTF-8
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import pickle as pkl
6
+ from tqdm import tqdm
7
+ import time
8
+ from datetime import timedelta
9
+
10
+
11
+ MAX_VOCAB_SIZE = 10000 # 词表长度限制
12
+ UNK, PAD = '<UNK>', '<PAD>' # 未知字,padding符号
13
+
14
+
15
+ def build_vocab(file_path, tokenizer, max_size, min_freq):
16
+ vocab_dic = {}
17
+ with open(file_path, 'r', encoding='UTF-8') as f:
18
+ for line in tqdm(f):
19
+ lin = line.strip()
20
+ if not lin:
21
+ continue
22
+ content = lin.split('\t')[0]
23
+ for word in tokenizer(content):
24
+ vocab_dic[word] = vocab_dic.get(word, 0) + 1
25
+ vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True)[:max_size]
26
+ vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}
27
+ vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})
28
+ return vocab_dic
29
+
30
+
31
+ def build_dataset(config, ues_word):
32
+ if ues_word:
33
+ tokenizer = lambda x: x.split(' ') # 以空格隔开,word-level
34
+ else:
35
+ tokenizer = lambda x: [y for y in x] # char-level
36
+ if os.path.exists(config.vocab_path):
37
+ vocab = pkl.load(open(config.vocab_path, 'rb')) #打开词表文件
38
+ else:
39
+ vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
40
+ pkl.dump(vocab, open(config.vocab_path, 'wb'))
41
+ print(f"Vocab size: {len(vocab)}")
42
+
43
+ def load_dataset(path, pad_size=32):
44
+ contents = []
45
+ with open(path, 'r', encoding='UTF-8') as f:
46
+ for line in tqdm(f):
47
+ lin = line.strip()
48
+ if not lin:
49
+ continue
50
+ content, label = lin.split('\t')
51
+ words_line = []
52
+ token = tokenizer(content)
53
+ seq_len = len(token)
54
+ if pad_size:
55
+ if len(token) < pad_size:
56
+ token.extend([PAD] * (pad_size - len(token)))
57
+ else:
58
+ token = token[:pad_size]
59
+ seq_len = pad_size
60
+ # word to id
61
+ for word in token:
62
+ words_line.append(vocab.get(word, vocab.get(UNK)))
63
+ contents.append((words_line, int(label), seq_len))
64
+ return contents # [([...], 0), ([...], 1), ...]
65
+ train = load_dataset(config.train_path, config.pad_size)
66
+ dev = load_dataset(config.dev_path, config.pad_size)
67
+ test = load_dataset(config.test_path, config.pad_size)
68
+ return vocab, train, dev, test
69
+
70
+
71
+ class DatasetIterater(object):
72
+ def __init__(self, batches, batch_size, device):
73
+ self.batch_size = batch_size
74
+ self.batches = batches
75
+ self.n_batches = len(batches) // batch_size
76
+ self.residue = False # 记录batch数量是否为整数
77
+ # if len(batches) % self.n_batches != 0:
78
+ # self.residue = True
79
+ self.residue = True #手动加一句
80
+ self.index = 0
81
+ self.device = device
82
+
83
+ def _to_tensor(self, datas):
84
+ x = torch.LongTensor([_[0] for _ in datas]).to(self.device)
85
+ y = torch.LongTensor([_[1] for _ in datas]).to(self.device)
86
+
87
+ # pad前的长度(超过pad_size的设为pad_size)
88
+ seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)
89
+ return (x, seq_len), y
90
+
91
+ def __next__(self):
92
+ if self.residue and self.index == self.n_batches:
93
+ batches = self.batches[self.index * self.batch_size: len(self.batches)]
94
+ self.index += 1
95
+ batches = self._to_tensor(batches)
96
+ return batches
97
+
98
+ elif self.index >= self.n_batches:
99
+ self.index = 0
100
+ raise StopIteration
101
+ else:
102
+ batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]
103
+ self.index += 1
104
+ batches = self._to_tensor(batches)
105
+ return batches
106
+
107
+ def __iter__(self):
108
+ return self
109
+
110
+ def __len__(self):
111
+ if self.residue:
112
+ return self.n_batches + 1
113
+ else:
114
+ return self.n_batches
115
+
116
+
117
+ def build_iterator(dataset, config):
118
+ iter = DatasetIterater(dataset, config.batch_size, config.device)
119
+ return iter
120
+
121
+
122
+ def get_time_dif(start_time):
123
+ """获取已使用时间"""
124
+ end_time = time.time()
125
+ time_dif = end_time - start_time
126
+ return timedelta(seconds=int(round(time_dif)))
127
+
128
+
129
+ if __name__ == "__main__":
130
+ '''提取预训练词向量'''
131
+ # 下面的目录、文件名按需更改。
132
+ train_dir = "./THUCNews/data/train.txt"
133
+ vocab_dir = "./THUCNews/data/vocab.pkl"
134
+ pretrain_dir = "./THUCNews/data/sgns.sogou.char"
135
+ emb_dim = 300
136
+ filename_trimmed_dir = "./THUCNews/data/embedding_SougouNews"
137
+ if os.path.exists(vocab_dir):
138
+ word_to_id = pkl.load(open(vocab_dir, 'rb'))
139
+ else:
140
+ # tokenizer = lambda x: x.split(' ') # 以词为单���构建词表(数据集中词之间以空格隔开)
141
+ tokenizer = lambda x: [y for y in x] # 以字为单位构建词表
142
+ word_to_id = build_vocab(train_dir, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
143
+ pkl.dump(word_to_id, open(vocab_dir, 'wb'))
144
+
145
+ embeddings = np.random.rand(len(word_to_id), emb_dim)
146
+ f = open(pretrain_dir, "r", encoding='UTF-8')
147
+ for i, line in enumerate(f.readlines()):
148
+ # if i == 0: # 若第一行是标题,则跳过
149
+ # continue
150
+ lin = line.strip().split(" ")
151
+ if lin[0] in word_to_id:
152
+ idx = word_to_id[lin[0]]
153
+ emb = [float(x) for x in lin[1:301]]
154
+ embeddings[idx] = np.asarray(emb, dtype='float32')
155
+ f.close()
156
+ np.savez_compressed(filename_trimmed_dir, embeddings=embeddings)