日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NLP在线医生(一)

發(fā)布時間:2024/3/12 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NLP在线医生(一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.1 背景介紹


  • 學(xué)習(xí)目標(biāo):
    • 了解智能對話系統(tǒng)的相關(guān)背景知識.
    • 掌握使用Unit對話API.

  • 什么是智能對話系統(tǒng)?
    • 隨著人工智能技術(shù)的發(fā)展, 聊天機(jī)器人, 語音助手等應(yīng)用在生活中隨處可見, 比如百度的小度, 阿里的小蜜, 微軟的小冰等等. 其目的在于通過人工智能技術(shù)讓機(jī)器像人類一樣能夠進(jìn)行智能回復(fù), 解決現(xiàn)實中的各種問題.


  • 從處理問題的角度來區(qū)分, 智能對話系統(tǒng)可分為:
    • 任務(wù)導(dǎo)向型: 完成具有明確指向性的任務(wù), 比如預(yù)定酒店咨詢, 在線問診等等.
    • 非任務(wù)導(dǎo)向型: 沒有明確目的, 比如算算術(shù), 播放音樂, 回答問題.

  • 我們的在線醫(yī)生項目就是任務(wù)導(dǎo)向型的智能對話系統(tǒng).

1.2 Unit對話API的使用


  • 學(xué)習(xí)目標(biāo):
    • 了解Unit平臺的相關(guān)知識.
    • 掌握調(diào)用Unit API的實現(xiàn)過程.

  • Unit平臺的相關(guān)知識:
    • Unit平臺是百度大腦開放的智能對話定制與服務(wù)平臺, 也是當(dāng)前最大的中文領(lǐng)域?qū)υ掗_放平臺之一. Unit對注冊用戶提供免費的對話接口服務(wù), 比如中文閑聊API, 百科問答API, 詩句生成API等, 通過這些API我們可以感受一下智能對話的魅力, 同時它也可以作為任務(wù)導(dǎo)向型對話系統(tǒng)無法匹配用戶輸入時的最終選擇.


  • Unit閑聊API演示:
用戶輸入 >>> "你好" Unit回復(fù) >>> "你好,想聊什么呢~" 用戶輸入 >>> "我想有一個女朋友!" Unit回復(fù) >>> "我也是想要一個女朋友~" 用戶輸入 >>> "晚吃啥呢想想" Unit回復(fù) >>> "想吃火鍋"
  • 調(diào)用Unit API的實現(xiàn)過程:
    • 第一步: 注冊登錄百度賬戶, 進(jìn)入Unit控制臺創(chuàng)建自己的機(jī)器人.
    • 第二步: 進(jìn)行相關(guān)配置, 獲得請求API接口需要的API Key與Secret Key.
    • 第三步: 在服務(wù)器上編寫API調(diào)用腳本并進(jìn)行測試.

  • 第一步: 注冊登錄百度賬戶, 進(jìn)入Unit控制臺創(chuàng)建自己的機(jī)器人.
    ai.baidu.com

  • 第二步: 進(jìn)行相關(guān)配置, 獲得請求API接口需要的API Key與Secret Key.
  • 點擊獲取API Key進(jìn)入百度云應(yīng)用管理頁面.

  • 點擊創(chuàng)建應(yīng)用, 進(jìn)入應(yīng)用信息表單填寫頁面.

  • 填寫完畢后, 點擊立即創(chuàng)建, 成功后會提示創(chuàng)建完畢.

  • 點擊返回應(yīng)用列表.
  • 可以看到創(chuàng)建的API Key和Secret Key, 至此創(chuàng)建流程結(jié)束.
  • 第三步: 在服務(wù)器上編寫API調(diào)用腳本并進(jìn)行測試
import json import random import requests# client_id 為官網(wǎng)獲取的AK, client_secret 為官網(wǎng)獲取的SK client_id = "1xhPonkmHqwolDt3GCICLX39" client_secret = "SRYsfjMGNuW8G265paMXLEjDTjO6O4RC"def unit_chat(chat_input, user_id="88888"):"""description:調(diào)用百度UNIT接口,回復(fù)聊天內(nèi)容Parameters----------chat_input : str用戶發(fā)送天內(nèi)容user_id : str發(fā)起聊天用戶ID,可任意定義Return----------返回unit回復(fù)內(nèi)容"""# 設(shè)置默認(rèn)回復(fù)內(nèi)容, 一旦接口出現(xiàn)異常, 回復(fù)該內(nèi)容chat_reply = "不好意思,俺們正在學(xué)習(xí)中,隨后回復(fù)你。"# 根據(jù) client_id 與 client_secret 獲取access_tokenurl = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s" % (client_id, client_secret)res = requests.get(url)access_token = eval(res.text)["access_token"]# 根據(jù) access_token 獲取聊天機(jī)器人接口數(shù)據(jù)unit_chatbot_url = "https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=" + access_token# 拼裝聊天接口對應(yīng)請求發(fā)送數(shù)據(jù),主要是填充 query 值post_data = {"log_id": str(random.random()),"request": {"query": chat_input,"user_id": user_id},"session_id": "","service_id": "S23245","version": "2.0"}# 將封裝好的數(shù)據(jù)作為請求內(nèi)容, 發(fā)送給Unit聊天機(jī)器人接口, 并得到返回結(jié)果res = requests.post(url=unit_chatbot_url, json=post_data)# 獲取聊天接口返回數(shù)據(jù)unit_chat_obj = json.loads(res.content)# print(unit_chat_obj)# 打印返回的結(jié)果# 判斷聊天接口返回數(shù)據(jù)是否出錯 error_code == 0 則表示請求正確if unit_chat_obj["error_code"] != 0: return chat_reply# 解析聊天接口返回數(shù)據(jù),找到返回文本內(nèi)容 result -> response_list -> schema -> intent_confidence(>0) -> action_list -> sayunit_chat_obj_result = unit_chat_obj["result"]unit_chat_response_list = unit_chat_obj_result["response_list"]# 隨機(jī)選取一個"意圖置信度"[+response_list[].schema.intent_confidence]不為0的技能作為回答unit_chat_response_obj = random.choice([unit_chat_response for unit_chat_response in unit_chat_response_list ifunit_chat_response["schema"]["intent_confidence"] > 0.0])unit_chat_response_action_list = unit_chat_response_obj["action_list"]unit_chat_response_action_obj = random.choice(unit_chat_response_action_list)unit_chat_response_say = unit_chat_response_action_obj["say"]return unit_chat_response_sayif __name__ == '__main__':while True:chat_input = input("請輸入:")print(chat_input)chat_reply = unit_chat(chat_input)print("用戶輸入 >>>", chat_input)print("Unit回復(fù) >>>", chat_reply)if chat_input == 'Q' or chat_input == 'q':break
  • 代碼位置: /data/doctor_online/main_serve/unit.py

  • 調(diào)用:
python unit.py
  • 輸出效果:
請輸入:你好啊 你好啊 用戶輸入 >>> 你好啊 Unit回復(fù) >>> 你也好啊~ 請輸入:今天天氣棒棒噠 今天天氣棒棒噠 用戶輸入 >>> 今天天氣棒棒噠 Unit回復(fù) >>> 必須的 請輸入:晚飯吃點什么? 晚飯吃點什么? 用戶輸入 >>> 晚飯吃點什么? Unit回復(fù) >>> 晚飯沒吃,減肥 請輸入:
  • 本章總結(jié):

    • 學(xué)習(xí)了智能對話系統(tǒng)的相關(guān)背景知識:
      • 什么是智能對話系統(tǒng)
      • 從處理問題的目的來區(qū)分, 智能對話系統(tǒng)的分類

    • 我們的在線醫(yī)生項目就是任務(wù)導(dǎo)向型的智能對話系統(tǒng).

    • 學(xué)習(xí)了Unit平臺的相關(guān)知識:
      • Unit平臺是百度大腦開放的智能對話定制與服務(wù)平臺, 也是當(dāng)前最大的中文領(lǐng)域?qū)υ掗_放平臺之一.

    • 學(xué)習(xí)了調(diào)用Unit API的實現(xiàn)過程:
      • 第一步: 注冊登錄百度賬戶, 進(jìn)入Unit控制臺創(chuàng)建自己的機(jī)器人.
      • 第二步: 進(jìn)行相關(guān)配置, 獲得請求API接口需要的API Key與Secret Key.
      • 第三步: 在服務(wù)器上編寫API調(diào)用腳本并進(jìn)行測試.

2.1 在線醫(yī)生的總體架構(gòu)

  • 學(xué)習(xí)目標(biāo):
    • 了解在線醫(yī)生項目的總體架構(gòu)

  • 項目整體架構(gòu)圖:


  • 架構(gòu)圖分析:
    • 整個項目分為: 在線部分和離線部分
    • 在線部分包括: werobot服務(wù)模塊, 主要邏輯服務(wù)模塊, 句子相關(guān)模型服務(wù)模塊, 會話管理模塊(redis), 圖數(shù)據(jù)庫模塊以及規(guī)則對話/Unit模塊.
    • 離線部分包括: 結(jié)構(gòu)與非結(jié)構(gòu)化數(shù)據(jù)采集模塊, NER模型使用模塊, 以及實體審核模型使用模塊.
    • 在線部分?jǐn)?shù)據(jù)流: 從用戶請求開始, 通過werobot服務(wù), 在werobot服務(wù)內(nèi)部請求主服務(wù), 在主服務(wù)中將調(diào)用會話管理數(shù)據(jù)庫redis, 調(diào)用句子相關(guān)模型服務(wù), 以及調(diào)用圖數(shù)據(jù)庫, 最后將查詢結(jié)果輸送給對話規(guī)則模版或者使用Unit對話API回復(fù).
    • 離線部分?jǐn)?shù)據(jù)流: 從數(shù)據(jù)采集開始, 將獲得結(jié)構(gòu)化和非結(jié)構(gòu)化的數(shù)據(jù), 對于結(jié)構(gòu)化數(shù)據(jù)將直接使用實體審核模型進(jìn)行審核, 然后寫入圖數(shù)據(jù)庫; 對于非結(jié)構(gòu)化數(shù)據(jù), 將使用NER模型進(jìn)行實體抽取, 然后通過實體審核后再寫入圖數(shù)據(jù)庫.

2.2 總體架構(gòu)中的工具介紹


  • 學(xué)習(xí)目標(biāo):
    • 了解總體架構(gòu)中使用了哪些工具.
    • 掌握總體架構(gòu)中各個工具的簡介, 作用, 安裝和基本使用方法.

  • 總體架構(gòu)中使用的工具:
    • Flask web服務(wù)框架
    • Redis數(shù)據(jù)庫
    • Gunicorn服務(wù)組件
    • Supervisor服務(wù)監(jiān)控器
    • Neo4j圖數(shù)據(jù)庫

  • Flask web服務(wù)框架:

  • 簡介:
    * Flask框架是當(dāng)下最受歡迎的python輕量級框架, 也是pytorch官網(wǎng)指定的部署框架. Flask的基本模式為在程序里將一個視圖函數(shù)分配給一個URL,每當(dāng)用戶訪問這個URL時,系統(tǒng)就會執(zhí)行給該URL分配好的視圖函數(shù),獲取函數(shù)的返回值,其工作過程見圖.


  • 作用:
    * 在項目中, Flask框架是主邏輯服務(wù)和句子相關(guān)模型服務(wù)使用的服務(wù)框架.

  • 安裝:
# 使用pip安裝Flask pip install Flask==1.1.1
  • 基本使用方法:
# 導(dǎo)入Flask類 from flask import Flask # 創(chuàng)建一個該類的實例app, 參數(shù)為__name__, 這個參數(shù)是必需的, # 這樣Flask才能知道在哪里可找到模板和靜態(tài)文件等東西. app = Flask(__name__)# 使用route()裝飾器來告訴Flask觸發(fā)函數(shù)的URL @app.route('/') def hello_world():"""請求指定的url后,執(zhí)行的主要邏輯函數(shù)"""# 在用戶瀏覽器中顯示信息:'Hello, World!'return 'Hello, World!'if __name__ == '__main__':app.run(host="0.0.0.0", port=5000)
  • 代碼位置: /data/doctor_onine/main_serve/app.py

  • 啟動服務(wù):
python app.py
  • 啟動效果:
    * 通過瀏覽器打開地址http://127.0.0.1:5000/可看見打印了’Hello, World’.

  • Redis數(shù)據(jù)庫:
    window下使用redis

先在redis目錄下cmd: redis-server.exe redis.windows.conf 啟動redis服務(wù)
再在redis目錄下另開cmd,輸入redis-cli -h 127.0.0.1 -p 6379 -a 密碼

  • 簡介:
    * Redis(全稱:Remote Dictionary Server 遠(yuǎn)程字典服務(wù))是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API.

  • 作用:
    * 在項目中, Redis用于會話管理數(shù)據(jù)庫, 保存用戶聊天歷史.

  • 安裝:
# 使用yum安裝redis yum install redis -y
  • 基本使用方法:
    * Redis支持四種數(shù)據(jù)結(jié)構(gòu)的存儲: String(字符串), Hash(散列), List(列表), Set(集合), Sorted Set(有序集合).
    * 在這里我們將著重介紹如何在python中使用Hash(散列)進(jìn)行讀寫.

  • 安裝python中的redis驅(qū)動:
# 使用pip進(jìn)行安裝 pip install redis
  • 啟動redis服務(wù):
# 啟動redis-server, 這里使用了默認(rèn)配置, 端口是6379. redis-server
  • 在python中使用Hash(散列)進(jìn)行讀寫:

如果redis 設(shè)置了密碼
需要
REDIS_CONFIG = {
‘host’:‘127.0.0.1’,
‘port’:6379,
‘password’:‘123456’
}
否則報錯:Authentication required.

# coding=utf-8 # redis配置 REDIS_CONFIG = {"host": "0.0.0.0","port": 6379 }# 導(dǎo)入redis驅(qū)動 import redis# 創(chuàng)建一個redis連接池 pool = redis.ConnectionPool( **REDIS_CONFIG) # 從連接池中初始化一個活躍的連接對象 r = redis.StrictRedis(connection_pool=pool) # hset表示使用hash數(shù)據(jù)結(jié)構(gòu)進(jìn)行數(shù)據(jù)寫入 # uid代表某個用戶的唯一標(biāo)識 uid = "8888" # key是需要記錄的數(shù)據(jù)描述 key = "該用戶最后一次說的話:".encode('utf-8') # value是需要記錄的數(shù)據(jù)具體內(nèi)容 value = "再見, 董小姐".encode('utf-8') r.hset(uid, key, value)# hget表示使用hash數(shù)據(jù)結(jié)構(gòu)進(jìn)行數(shù)據(jù)讀取 result = r.hget(uid, key) print(result.decode('utf-8'))
  • 輸出效果:
再見, 董小姐
  • Gunicorn服務(wù)組件:

  • 簡介:
    * Gunicorn是一個被廣泛使用的高性能的Python WSGI UNIX HTTP服務(wù)組件(WSGI: Web Server Gateway Interface),移植自Ruby的獨角獸(Unicorn )項目,具有使用非常簡單,輕量級的資源消耗,以及高性能等特點.

  • 作用:
    * 在項目中, Gunicorn和Flask框架一同使用, 能夠開啟服務(wù), 處理請求,因其高性能的特點能夠有效減少服務(wù)丟包率.

  • 安裝:
# 使用pip安裝gunicorn pip install gunicorn==20.0.4
  • 基本使用方法:
# 使用其啟動Flask服務(wù): gunicorn -w 1 -b 0.0.0.0:5000 app:app # -w 代表開啟的進(jìn)程數(shù), 我們只開啟一個進(jìn)程 # -b 服務(wù)的IP地址和端口 # app:app 是指執(zhí)行的主要對象位置, 在app.py中的app對象 # 如果使其在后臺運行可使用: # nohup gunicorn -w 1 -b 0.0.0.0:5001 app:app &
  • Supervisor服務(wù)監(jiān)控:
  • 簡介:
    * Supervisor是用Python開發(fā)的一個client/server服務(wù),是Linux/Unix系統(tǒng)下的一個進(jìn)程管理工具。它可以很方便的監(jiān)聽、啟動、停止、重啟一個或多個進(jìn)程, 并守護(hù)這些進(jìn)程。

  • 作用:
    * 在項目中, Supervisor用于監(jiān)控和守護(hù)主要邏輯服務(wù)和redis數(shù)據(jù)庫服務(wù).

  • 安裝:
# 使用yum安裝supervisor yum install supervisor -y
  • 基本使用方法:
# 編輯配置文件, 指明監(jiān)控和守護(hù)的進(jìn)程開啟命令, # 請查看/data/doctor_online/supervisord.conf文件 # 開啟supervisor, -c用于指定配置文件 sueprvisord -c /data/doctor_online/main_server/supervisord.conf# 查看監(jiān)控的進(jìn)程狀態(tài): supervisorctl status# main_server RUNNING pid 31609, uptime 0:32:20 # redis RUNNING pid 31613, uptime 0:32:18# 關(guān)閉supervisor supervisorctl shutdown
  • 還可以通過瀏覽器查看可視化監(jiān)控頁面: http://0.0.0.0:9001


  • Neo4j圖數(shù)據(jù)庫:
    • 因為在項目中, Neo4j圖數(shù)據(jù)庫作為核心的存儲和查詢數(shù)據(jù)庫, 后續(xù)課件中對其進(jìn)行詳細(xì)的介紹.

  • 本章總結(jié):

    • 學(xué)習(xí)了架構(gòu)圖分析:
      • 整個項目分為: 在線部分和離線部分
      • 在線部分包括: werobot服務(wù)模塊, 主要邏輯服務(wù)模塊, 句子相關(guān)模型服務(wù)模塊, 會話管理模塊(redis), 圖數(shù)據(jù)庫模塊以及規(guī)則對話/Unit模塊.
      • 離線部分包括: 結(jié)構(gòu)與非結(jié)構(gòu)化數(shù)據(jù)采集模塊, NER模型使用模塊, 以及實體審核模型使用模塊.

    • 學(xué)習(xí)了總體架構(gòu)中使用的工具:
      • Flask web服務(wù)框架
      • Redis數(shù)據(jù)庫
      • Gunicorn服務(wù)組件
      • Supervisor服務(wù)監(jiān)控器
      • Neo4j圖數(shù)據(jù)庫

    • Flask web服務(wù)框架:
      • 作用: 在項目中, Flask框架是主邏輯服務(wù)和句子相關(guān)模型服務(wù)使用的服務(wù)框架.

    • Redis數(shù)據(jù)庫:
      • 作用: 在項目中, Redis用于會話管理數(shù)據(jù)庫, 保存用戶聊天歷史.

    • Gunicorn服務(wù)組件:
      • 作用: 在項目中, Gunicorn和Flask框架一同使用, 能夠開啟服務(wù), 處理請求,因其高性能的特點能夠有效減少服務(wù)丟包率.

    • Supervisor服務(wù)監(jiān)控:
      • 作用: 在項目中, Supervisor用于監(jiān)控和守護(hù)主要邏輯服務(wù)和redis數(shù)據(jù)庫服務(wù).

3.1 neo4j簡介

  • 學(xué)習(xí)目標(biāo):
    • 了解neo4j圖數(shù)據(jù)庫的簡介, 版本說明.
    • 了解節(jié)點, 關(guān)系,屬性,標(biāo)簽的有關(guān)概念.


windows 下neo4j

警告: ERROR! Neo4j cannot be started using java version 1.7.0_75
解決: java JDK下載
并重新配置java JDK 環(huán)境變量后,可以正常啟動neo4j

瀏覽器登錄http://localhost:7474/browser/ 初始賬號密碼均為:neo4j
若出現(xiàn)問題:“ NotFoundError:無法在’Node’上執(zhí)行’removeChild’:要刪除的節(jié)點不是該節(jié)點的子節(jié)點。”并且應(yīng)用程序無法恢復(fù)。 更換chrome或者其他瀏覽器

  • neo4j簡介:
    • neo4j是由Java實現(xiàn)的開源NoSQL圖數(shù)據(jù)庫.自從2003年開始研發(fā), 到2007年發(fā)布第一版, 最新版本為3.3.5, neo4j現(xiàn)如今已經(jīng)被各行各業(yè)的數(shù)十萬家公司和組織采用.
    • neo4j實現(xiàn)了專業(yè)數(shù)據(jù)庫級別的圖數(shù)據(jù)模型的存儲. 與普通的圖處理或內(nèi)存級數(shù)據(jù)庫不同, neo4j提供了完整的數(shù)據(jù)庫特性, 包括ACID事物的支持, 集群支持, 備份與故障轉(zhuǎn)移等. 這使其適合于企業(yè)級生產(chǎn)環(huán)境下的各種應(yīng)用.

  • neo4j的版本說明:
    • 企業(yè)版: 需要高額的付費獲得授權(quán), 提供高可用, 熱備份等性能.
    • 社區(qū)開源版: 免費使用, 但只能單點運行.

  • neo4j圖形數(shù)據(jù)庫的有關(guān)概念:


  • 節(jié)點
    * 節(jié)點是主要的數(shù)據(jù)元素, 節(jié)點通過關(guān)系連接到其他節(jié)點, 節(jié)點可以具有一個或多個屬性
    (即存儲為鍵/值對的屬性), 節(jié)點有一個或多個標(biāo)簽, 用于描述其在圖表中的作用. 示例: Person>節(jié)點.
    * 可以將節(jié)點類比為關(guān)系型數(shù)據(jù)庫中的表, 對應(yīng)的標(biāo)簽可以類比為不同的表名, 屬性就是表中的列.

  • 關(guān)系
    * 關(guān)系連接兩個節(jié)點, 關(guān)系是方向性的, 關(guān)系可以有一個或多個屬性(即存儲為鍵/值對的
    屬性).

  • 屬性
    * 屬性是命名值, 其中名稱(或鍵)是字符串, 屬性可以被索引和約束, 可以從多個屬性創(chuàng)
    建復(fù)合索引.

  • 標(biāo)簽
    * 標(biāo)簽用于組節(jié)點到集, 節(jié)點可以具有多個標(biāo)簽, 對標(biāo)簽進(jìn)行索引以加速在圖中查找節(jié)點.

3.2 neo4j圖數(shù)據(jù)庫的安裝

  • 學(xué)習(xí)目標(biāo):
    • 掌握neo4j圖數(shù)據(jù)庫的安裝流程及其可視化后臺的登陸…

  • neo4j圖數(shù)據(jù)庫的安裝流程:
    • 第一步: 將neo4j安裝信息載入到y(tǒng)um檢索列表.
    • 第二步: 使用yum install命令安裝.
    • 第三步: 修改配置文件內(nèi)容 /etc/neo4j/neo4j.conf.
    • 第四步: 啟動neo4j數(shù)據(jù)庫.

  • 第一步: 將neo4j安裝信息載入到y(tǒng)um檢索列表
cd /tmp wget http://debian.neo4j.org/neotechnology.gpg.key rpm --import neotechnology.gpg.key cat <<EOF> /etc/yum.repos.d/neo4j.repo # 寫入下面內(nèi)容 [neo4j] name=Neo4j RPM Repository baseurl=http://yum.neo4j.org/stable enabled=1 gpgcheck=1
  • 第二步: 使用yum install命令安裝
yum install neo4j-3.3.5
  • 第三步: 修改配置文件默認(rèn)在/etc/neo4j/neo4j.conf, 為了方便顯示下面把一些修改顯示在這里
# 數(shù)據(jù)庫的存儲庫存儲位置、日志位置等 dbms.directories.data=/var/lib/neo4j/data dbms.directories.plugins=/var/lib/neo4j/plugins dbms.directories.certificates=/var/lib/neo4j/certificates dbms.directories.logs=/var/log/neo4j dbms.directories.lib=/usr/share/neo4j/lib dbms.directories.run=/var/run/neo4j# 導(dǎo)入的位置 dbms.directories.import=/var/lib/neo4j/import# 初始化內(nèi)存大小 dbms.memory.heap.initial_size=512m# Bolt 連接地址 dbms.connector.bolt.enabled=true dbms.connector.bolt.tls_level=OPTIONAL dbms.connector.bolt.listen_address=0.0.0.0:7687
  • 第四步: 啟動neo4j數(shù)據(jù)庫
# 啟動命令 neo4j start# 終端顯示如下, 代表啟動成功 Active database: graph.db Directories in use:home: /usr/neo4jconfig: /etc/neo4jlogs: /var/log/neo4jplugins: /var/lib/neo4j/pluginsimport: /var/lib/neo4j/importdata: /var/lib/neo4j/datacertificates: /var/lib/neo4j/certificatesrun: /var/run/neo4j Starting Neo4j.
  • neo4j的可視化管理后臺登陸:
    • 訪問地址: http://0.0.0.0:7474.
    • ConnectURL: bolt://0.0.0.0:7687
    • Username: neo4j
    • Password: neo4j (默認(rèn))


  • 小節(jié)總結(jié):

    • 學(xué)習(xí)了neo4j圖數(shù)據(jù)庫的安裝流程:
      • 第一步: 將neo4j安裝信息載入到y(tǒng)um檢索列表.
      • 第二步: 使用yum install命令安裝.
      • 第三步: 修改配置文件內(nèi)容 /etc/neo4j/neo4j.conf.
      • 第四步: 啟動neo4j數(shù)據(jù)庫.

    • 學(xué)習(xí)了neo4j的可視化管理后臺登陸:
      • 訪問地址: http://0.0.0.0:7474.
      • ConnectURL: bolt://0.0.0.0:7687
      • Username: neo4j
      • Password: neo4j (默認(rèn))

3.3 Cypher介紹與使用

  • 學(xué)習(xí)目標(biāo)
    • 了解Cypher的基本概念.
    • 掌握Cypher的基本命令和語法.

  • Cypher的基本概念:
    • Cypher是neo4j圖數(shù)據(jù)的查詢語言, 類似于mysql數(shù)據(jù)庫的sql語句, 但是它允許對圖形進(jìn)行富有表現(xiàn)力和有效的查詢和更新.

  • Cypher的基本命令和語法:
    • create命令
    • match命令
    • merge命令
    • relationship關(guān)系命令
    • where命令
    • delete命令
    • sort命令
    • 字符串函數(shù)
    • 聚合函數(shù)
    • index索引命令

  • create命令: 創(chuàng)建圖數(shù)據(jù)中的節(jié)點.

  • 演示:
# 創(chuàng)建命令格式: # 此處create是關(guān)鍵字, 創(chuàng)建節(jié)點名稱node_name, 節(jié)點標(biāo)簽Node_Label, 放在小括號里面() # 后面把所有屬于節(jié)點標(biāo)簽的屬性放在大括號'{}'里面, 依次寫出屬性名稱:屬性值, 不同屬性用逗號','分隔 # 例如下面命令創(chuàng)建一個節(jié)點e, 節(jié)點標(biāo)簽是Employee, 擁有id, name, salary, deptnp四個屬性: CREATE (e:Employee{id:222, name:'Bob', salary:6000, deptnp:12})
  • 效果


  • match命令: 匹配(查詢)已有數(shù)據(jù).

  • 演示:
# match命令專門用來匹配查詢, 節(jié)點名稱:節(jié)點標(biāo)簽, 依然放在小括號內(nèi), 然后使用return語句返回查詢結(jié)果, 和SQL很相似. MATCH (e:Employee) RETURN e.id, e.name, e.salary, e.deptno
  • 效果:


  • merge命令: 若節(jié)點存在, 則等效與match命令; 節(jié)點不存在, 則等效于create命令.

  • 演示:
MERGE (e:Employee {id:146, name:'Lucer', salary:3500, deptno:16})
  • 效果:


  • 然后再次用merge查詢, 發(fā)現(xiàn)數(shù)據(jù)庫中的數(shù)據(jù)并沒有增加, 因為已經(jīng)存在相同的數(shù)據(jù)了, merge匹配成功.

  • 演示:
MERGE (e:Employee {id:146, name:'Lucer', salary:3500, deptno:16})
  • 效果:


  • 使用create創(chuàng)建關(guān)系: 必須創(chuàng)建有方向性的關(guān)系, 否則報錯.

  • 演示:
# 創(chuàng)建一個節(jié)點p1到p2的有方向關(guān)系, 這個關(guān)系r的標(biāo)簽為Buy, 代表p1購買了p2, 方向為p1指向p2 CREATE (p1:Profile1)-[r:Buy]->(p2:Profile2)
  • 效果:


  • 使用merge創(chuàng)建關(guān)系: 可以創(chuàng)建有/無方向性的關(guān)系.

  • 演示:
# 創(chuàng)建一個節(jié)點p1到p2的無方向關(guān)系, 這個關(guān)系r的標(biāo)簽為miss, 代表p1-miss-p2, 方向為相互的 MERGE (p1:Profile1)-[r:miss]-(p2:Profile2)
  • 效果:


  • where命令: 類似于SQL中的添加查詢條件.

  • 演示:
# 查詢節(jié)點Employee中, id值等于123的那個節(jié)點 MATCH (e:Employee) WHERE e.id=123 RETURN e
  • 效果:


  • delete命令: 刪除節(jié)點/關(guān)系及其關(guān)聯(lián)的屬性.

  • 演示:
# 注意: 刪除節(jié)點的同時, 也要刪除關(guān)聯(lián)的關(guān)系邊 MATCH (c1:CreditCard)-[r]-(c2:Customer) DELETE c1, r, c2
  • 效果:


  • sort命令: Cypher命令中的排序使用的是order by.

  • 演示:
# 匹配查詢標(biāo)簽Employee, 將所有匹配結(jié)果按照id值升序排列后返回結(jié)果 MATCH (e:Employee) RETURN e.id, e.name, e.salary, e.deptno ORDER BY e.id# 如果要按照降序排序, 只需要將ORDER BY e.salary改寫為ORDER BY e.salary DESC MATCH (e:Employee) RETURN e.id, e.name, e.salary, e.deptno ORDER BY e.salary DESC
  • 效果:


  • 字符串函數(shù):
    • toUpper()函數(shù)
    • toLower()函數(shù)
    • substring()函數(shù)
    • replace()函數(shù)

  • toUpper()函數(shù): 將一個輸入字符串轉(zhuǎn)換為大寫字母.

  • 演示:
MATCH (e:Employee) RETURN e.id, toUpper(e.name), e.salary, e.deptno
  • 效果:


  • toLower()函數(shù): 講一個輸入字符串轉(zhuǎn)換為小寫字母.

  • 演示:
MATCH (e:Employee) RETURN e.id, toLower(e.name), e.salary, e.deptno
  • 效果:


  • substring()函數(shù): 返回一個子字符串.

  • 演示:
# 輸入字符串為input_str, 返回從索引start_index開始, 到end_index-1結(jié)束的子字符串 substring(input_str, start_index, end_index)# 示例代碼, 返回員工名字的前兩個字母 MATCH (e:Employee) RETURN e.id, substring(e.name,0,2), e.salary, e.deptno
  • 效果:


  • replace()函數(shù): 替換掉子字符串.

  • 演示:
# 輸入字符串為input_str, 將輸入字符串中符合origin_str的部分, 替換成new_str replace(input_str, origin_str, new_str)# 示例代碼, 將員工名字替換為添加后綴_HelloWorld MATCH (e:Employee) RETURN e.id, replace(e.name,e.name,e.name + "_HelloWorld"), e.salary, e.deptno
  • 效果:


  • 聚合函數(shù)
    • count()函數(shù)
    • max()函數(shù)
    • min()函數(shù)
    • sum()函數(shù)
    • avg()函數(shù)

  • count()函數(shù): 返回由match命令匹配成功的條數(shù).

  • 演示:
# 返回匹配標(biāo)簽Employee成功的記錄個數(shù) MATCH (e:Employee) RETURN count( * )
  • 效果:


  • max()函數(shù): 返回由match命令匹配成功的記錄中的最大值.

  • 演示:
# 返回匹配標(biāo)簽Employee成功的記錄中, 最高的工資數(shù)字 MATCH (e:Employee) RETURN max(e.salary)
  • 效果:


  • min()函數(shù): 返回由match命令匹配成功的記錄中的最小值.

  • 演示:
# 返回匹配標(biāo)簽Employee成功的記錄中, 最低的工資數(shù)字 MATCH (e:Employee) RETURN min(e.salary)
  • 效果:


  • sum()函數(shù): 返回由match命令匹配成功的記錄中某字段的全部加和值.

  • 演示:
# 返回匹配標(biāo)簽Employee成功的記錄中, 所有員工工資的和 MATCH (e:Employee) RETURN sum(e.salary)
  • 效果:


  • avg()函數(shù): 返回由match命令匹配成功的記錄中某字段的平均值.

  • 演示:
# 返回匹配標(biāo)簽Employee成功的記錄中, 所有員工工資的平均值 MATCH (e:Employee) RETURN avg(e.salary)
  • 效果:


  • 索引index
    • Neo4j支持在節(jié)點或關(guān)系屬性上的索引, 以提高查詢的性能.
    • 可以為具有相同標(biāo)簽名稱的所有節(jié)點的屬性創(chuàng)建索引.

  • 創(chuàng)建索引: 使用create index on來創(chuàng)建索引.

  • 演示:
# 創(chuàng)建節(jié)點Employee上面屬性id的索引 CREATE INDEX ON:Employee(id)
  • 效果:


  • 刪除索引: 使用drop index on來刪除索引.

  • 演示:
# 刪除節(jié)點Employee上面屬性id的索引 DROP INDEX ON:Employee(id)
  • 效果:


  • 小節(jié)總結(jié):

    • 學(xué)習(xí)了Cypher的基本概念:
      • Cypher是neo4j圖數(shù)據(jù)的查詢語言, 類似于mysql數(shù)據(jù)庫的sql語句, 但是它允許對圖形進(jìn)行富有表現(xiàn)力和有效的查詢和更新.

    • Cypher的基本命令和語法:
      • create命令
      • match命令
      • merge命令
      • relationship關(guān)系命令
      • where命令
      • delete命令
      • sort命令
      • 字符串函數(shù)
      • 聚合函數(shù)
      • index索引命令

    • create命令: 創(chuàng)建圖數(shù)據(jù)中的節(jié)點.
      • CREATE (e:Employee{id:222, name:‘Bob’, salary:6000, deptnp:12})

    • match命令: 匹配(查詢)已有數(shù)據(jù).
      • MATCH (e:Employee) RETURN e.id, e.name, e.salary, e.deptno

    • merge命令: 若節(jié)點存在, 則等效與match命令; 節(jié)點不存在, 則等效于create命令.
      • MERGE (e:Employee {id:145, name:‘Lucy’, salary:7500, deptno:12})

    • 使用create創(chuàng)建關(guān)系: 必須創(chuàng)建有方向性的關(guān)系, 否則報錯.
      • CREATE (p1:Profile1)-[r:Buy]->(p2:Profile2)

    • 使用merge創(chuàng)建關(guān)系: 可以創(chuàng)建有/無方向性的關(guān)系.
      • MERGE (p1:Profile1)-[r:miss]-(p2:Profile2)

    • where命令: 類似于SQL中的添加查詢條件.
      • MATCH (e:Employee) WHERE e.id=123 RETURN e

    • delete命令: 刪除節(jié)點/關(guān)系及其關(guān)聯(lián)的屬性.
      • MATCH (c1:CreditCard)-[r]-(c2:Customer) DELETE c1, r, c2

    • sort命令: Cypher命令中的排序使用的是order by.
      • MATCH (e:Employee) RETURN e.id, e.name, e.salary, e.deptno ORDER BY e.id

    • 字符串函數(shù):
      • toUpper()函數(shù)
      • toLower()函數(shù)
      • substring()函數(shù)
      • replace()函數(shù)

    • toUpper()函數(shù): 將一個輸入字符串轉(zhuǎn)換為大寫字母.
      • MATCH (e:Employee) RETURN e.id, toUpper(e.name), e.salary, e.deptno

    • toLower()函數(shù): 講一個輸入字符串轉(zhuǎn)換為小寫字母.
      • MATCH (e:Employee) RETURN e.id, toLower(e.name), e.salary, e.deptno

    • substring()函數(shù): 返回一個子字符串.
      • MATCH (e:Employee) RETURN e.id, substring(e.name,0,2), e.salary, e.deptno

    • replace()函數(shù): 替換掉子字符串.
      • MATCH (e:Employee) RETURN e.id, replace(e.name,e.name,e.name + “_HelloWorld”), e.salary, e.deptno

    • 聚合函數(shù)
      • count()函數(shù)
      • max()函數(shù)
      • min()函數(shù)
      • sum()函數(shù)
      • avg()函數(shù)

    • count()函數(shù): 返回由match命令匹配成功的條數(shù).
      • MATCH (e:Employee) RETURN count( * )

    • max()函數(shù): 返回由match命令匹配成功的記錄中的最大值.
      • MATCH (e:Employee) RETURN max(e.salary)

    • min()函數(shù): 返回由match命令匹配成功的記錄中的最小值.
      • MATCH (e:Employee) RETURN min(e.salary)

    • sum()函數(shù): 返回由match命令匹配成功的記錄中某字段的全部加和值.
      • MATCH (e:Employee) RETURN sum(e.salary)

    • avg()函數(shù): 返回由match命令匹配成功的記錄中某字段的平均值.
      • MATCH (e:Employee) RETURN avg(e.salary)

    • 索引index
      • Neo4j支持在節(jié)點或關(guān)系屬性上的索引, 以提高查詢的性能.
      • 可以為具有相同標(biāo)簽名稱的所有節(jié)點的屬性創(chuàng)建索引.

    • 創(chuàng)建索引: 使用create index on來創(chuàng)建索引.
      • CREATE INDEX ON:Employee(id)

    • 刪除索引: 使用drop index on來刪除索引.
      • DROP INDEX ON:Employee(id)

3.4 在Python中使用neo4j

  • 學(xué)習(xí)目標(biāo)
    • 了解python中neo4j-driver的相關(guān)知識.
    • 掌握neo4j中事務(wù)概念和操作方法.

  • neo4j-driver簡介:
    • neo4j-driver是一個python中的package, 作為python中neo4j的驅(qū)動, 幫助我們在python程序中更好的使用圖數(shù)據(jù)庫.

  • neo4j-driver的安裝:
pip install neo4j-driver
  • neo4j-driver使用演示:

config.py

# 設(shè)置neo4j圖數(shù)據(jù)庫的配置信息 NEO4J_CONFIG = {"uri": "bolt://127.0.0.1:7687","auth": ("username", "password"),"encrypted": False } from neo4j import GraphDatabase# 關(guān)于neo4j數(shù)據(jù)庫的用戶名,密碼信息已經(jīng)配置在同目錄下的config.py文件中 from config import NEO4J_CONFIGdriver = GraphDatabase.driver( **NEO4J_CONFIG)# 直接用python代碼形式訪問節(jié)點Company, 并返回所有節(jié)點信息 with driver.session() as session:cypher = "CREATE(c:Company) SET c.name='在線醫(yī)生' RETURN c.name"record = session.run(cypher)result = list(map(lambda x: x[0], record))print("result:", result)
  • 輸出效果:
result: ['在線醫(yī)生']
  • 事務(wù)的概念:
    • 如果一組數(shù)據(jù)庫操作要么全部發(fā)生要么一步也不執(zhí)行,我們稱該組處理步驟為一個事務(wù), 它是數(shù)據(jù)庫一致性的保證.

  • 使用事務(wù)的演示:
def _some_operations(tx, cat_name, mouse_name):tx.run("MERGE (a:Cat{name: $cat_name})""MERGE (b:Mouse{name: $mouse_name})""MERGE (a)-[r:And]-(b)",cat_name=cat_name, mouse_name=mouse_name)with driver.session() as session:session.write_transaction(_some_operations, "Tom", "Jerry")
  • 輸出效果:

查詢多個節(jié)點多個屬性
match(c:Cat) - [r] - (m:Mouse) return c.name, m.name


  • 小節(jié)總結(jié):

    • 學(xué)習(xí)了neo4j-driver簡介:
      • neo4j-driver是一個python中的package, 作為python中neo4j的驅(qū)動, 幫助我們在python程序中更好的使用圖數(shù)據(jù)庫.

    • 學(xué)習(xí)了neo4j-driver的安裝和使用方法.

    • 學(xué)習(xí)了事務(wù)的概念:
      • 如果一組數(shù)據(jù)庫操作要么全部發(fā)生要么一步也不執(zhí)行,我們稱該組處理步驟為一個事務(wù), 它是數(shù)據(jù)庫一致性的保證.

    • 學(xué)習(xí)了如何使用事務(wù)來向圖數(shù)據(jù)庫中寫入數(shù)據(jù).

4.1 離線部分簡要分析


  • 學(xué)習(xí)目標(biāo):
    • 了解離線部分的數(shù)據(jù)流水線以及組成部分.
    • 了解各個組成部分的作用.

  • 離線部分架構(gòu)圖:


  • 離線部分架構(gòu)展開圖:


  • 離線部分簡要分析:
    • 根據(jù)架構(gòu)展開圖圖,離線部分可分為兩條數(shù)據(jù)流水線,分別用于處理結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù). 這里稱它們?yōu)榻Y(jié)構(gòu)化數(shù)據(jù)流水線和非結(jié)構(gòu)化數(shù)據(jù)流水線.

  • 結(jié)構(gòu)化數(shù)據(jù)流水線的組成部分:
    • 結(jié)構(gòu)化數(shù)據(jù)爬蟲: 從網(wǎng)頁上抓取結(jié)構(gòu)化的有關(guān)醫(yī)學(xué)命名實體的內(nèi)容.
    • 結(jié)構(gòu)化數(shù)據(jù)的清洗: 對抓取的內(nèi)容進(jìn)行過濾和清洗, 以保留需要的部分.
    • 命名實體審核: 對當(dāng)前命名實體進(jìn)行審核, 來保證這些實體符合我們的要求.
    • 命名實體寫入數(shù)據(jù)庫: 將審核后的命名實體寫入數(shù)據(jù)庫之中, 供在線部分使用.

  • 非結(jié)構(gòu)化數(shù)據(jù)流水線的組成部分:
    • 非結(jié)構(gòu)化數(shù)據(jù)爬蟲: 從網(wǎng)頁上抓取非結(jié)構(gòu)化的包含醫(yī)學(xué)命名實體的文本.
    • 非結(jié)構(gòu)化數(shù)據(jù)清洗: 對非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行過濾和清洗, 以保留需要的部分.
    • 命名實體識別: 使用模型從非結(jié)構(gòu)化文本中獲取命名實體.
    • 命名實體審核: 對當(dāng)前命名實體進(jìn)行審核, 來保證這些實體符合我們的要求.
    • 命名實體寫入數(shù)據(jù)庫: 將審核后的命名實體寫入數(shù)據(jù)庫之中, 供在線部分使用.

  • 說明:
    • 因為本項目是以AI為核心的項目, 因為結(jié)構(gòu)化與非結(jié)構(gòu)化的數(shù)據(jù)爬蟲和清洗部分的內(nèi)容這里不做介紹, 但同學(xué)們要知道我們的數(shù)據(jù)來源.

4.2 結(jié)構(gòu)化數(shù)據(jù)流水線


  • 學(xué)習(xí)目標(biāo):
    • 了解需要進(jìn)行命名實體審核的數(shù)據(jù)內(nèi)容.
    • 掌握結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體審核的過程.
    • 掌握結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體寫入的過程.

  • 需要進(jìn)行命名實體審核的數(shù)據(jù)內(nèi)容:
... 踝部急性韌帶損傷.csv 踝部扭傷.csv 踝部骨折.csv 蹄鐵形腎.csv 蹼狀陰莖.csv 躁狂抑郁癥.csv 躁狂癥.csv 躁郁癥.csv 軀體形式障礙.csv 軀體感染伴發(fā)的精神障礙.csv 軀體感染所致精神障礙.csv 軀體感覺障礙.csv 軀體疾病伴發(fā)的精神障礙.csv 轉(zhuǎn)換性障礙.csv 轉(zhuǎn)移性小腸腫瘤.csv 轉(zhuǎn)移性皮膚鈣化病.csv 轉(zhuǎn)移性肝癌.csv 轉(zhuǎn)移性胸膜腫瘤.csv 轉(zhuǎn)移性骨腫瘤.csv 輪狀病毒性腸炎.csv 輪狀病毒所致胃腸炎.csv 軟產(chǎn)道異常性難產(chǎn).csv ...
  • 每個csv文件的名字都是一種疾病名.

  • 文件位置: /data/doctor_offline/structured/noreview/

  • 以躁狂癥.csv為例, 有如下內(nèi)容:
躁郁樣 躁狂 行為及情緒異常 心境高漲 情緒起伏大 技術(shù)狂躁癥 攻擊行為 易激惹 思維奔逸 控制不住的聯(lián)想 精神運動性興奮
  • csv文件的內(nèi)容是該疾病對應(yīng)的癥狀, 每種癥狀占一行.

  • 文件位置: /data/doctor_offline/structured/noreview/躁狂癥.csv

  • 進(jìn)行命名實體審核:
    • 進(jìn)行命名實體審核的工作我們這里使用AI模型實現(xiàn), 包括訓(xùn)練數(shù)據(jù)集, 模型訓(xùn)練和使用的整個過程, 因此這里內(nèi)容以獨立一章的形成呈現(xiàn)給大家, 具體參見[第五章: 命名實體審核任務(wù)].

  • 刪除審核后的可能存在的空文件:
# Linux 命令-- 刪除當(dāng)前文件夾下的空文件 find ./ -name "*" -type f -size 0c | xargs -n 1 rm -f
  • 代碼位置: 在/data/doctor_offline/structured/reviewed/目錄下執(zhí)行.

  • 命名實體寫入數(shù)據(jù)庫:

  • 將命名實體寫入圖數(shù)據(jù)庫的原因:
    * 寫入的數(shù)據(jù)供在線部分進(jìn)行查詢,根據(jù)用戶輸入癥狀來匹配對應(yīng)疾病.

  • 將命名實體寫入圖數(shù)據(jù)庫代碼:
# 引入相關(guān)包 import os import fileinput from neo4j import GraphDatabase from config import NEO4J_CONFIGdriver = GraphDatabase.driver( **NEO4J_CONFIG)def _load_data(path):"""description: 將path目錄下的csv文件以指定格式加載到內(nèi)存:param path: 審核后的疾病對應(yīng)癥狀的csv文件:return: 返回疾病字典,存儲各個疾病以及與之對應(yīng)的癥狀的字典{疾病1: [癥狀1, 癥狀2, ...], 疾病2: [癥狀1, 癥狀2, ...]"""# 獲得疾病csv列表disease_csv_list = os.listdir(path)# 將后綴.csv去掉, 獲得疾病列表disease_list = list(map(lambda x: x.split(".")[0], disease_csv_list))# 初始化一個癥狀列表, 它里面是每種疾病對應(yīng)的癥狀列表symptom_list = []# 遍歷疾病csv列表for disease_csv in disease_csv_list:# 將疾病csv中的每個癥狀取出存入symptom列表中# symptom = list(map(lambda x : x.strip(), fileinput.FileInput(os.path.join(path, disease_csv), openhook= fileinput.hook_encoded('utf-8'))))symptom = list(map(lambda x: x.strip(), fileinput.FileInput(os.path.join(path, disease_csv))))# 過濾掉所有長度異常的癥狀名symptom = list(filter(lambda x: 0<len(x)<100, symptom))symptom_list.append(symptom)# 返回指定格式的數(shù)據(jù) {疾病:對應(yīng)癥狀}return dict(zip(disease_list, symptom_list))def write(path):"""description: 將csv數(shù)據(jù)寫入到neo4j, 并形成圖譜:param path: 數(shù)據(jù)文件路徑"""# 使用_load_data從持久化文件中加載數(shù)據(jù)disease_symptom_dict = _load_data(path)# 開啟一個neo4j的sessionwith driver.session() as session:for key, value in disease_symptom_dict.items():cypher = "MERGE (a:Disease{name:%r}) RETURN a" %keysession.run(cypher)for v in value:cypher = "MERGE (b:Symptom{name:%r}) RETURN b" %vsession.run(cypher)cypher = "MATCH (a:Disease{name:%r}) MATCH (b:Symptom{name:%r}) \WITH a,b MERGE(a)-[r:dis_to_sym]-(b)" %(key, v)session.run(cypher)cypher = "CREATE INDEX ON:Disease(name)"session.run(cypher)cypher = "CREATE INDEX ON:Symptom(name)"session.run(cypher)
  • 調(diào)用:
# 輸入?yún)?shù)path為csv數(shù)據(jù)所在路徑 path = "/data/doctor_offline/structured/reviewed/" write(path)

fileinput UnicodeDecodeError: gbk codec cant decode byte 0x80 in position 2: illegal multibyte sequence
解決:symptom = list(map(lambda x : x.strip(), fileinput.FileInput(os.path.join(path, disease_csv), openhook= fileinput.hook_encoded(‘utf-8’))))
symptom = list(map(lambda x: x.strip(), fileinput.FileInput(os.path.join(path, disease_csv))))


  • 輸出效果:
    * 通過可視化管理后臺查看寫入效果.
MATCH(a:Disease) - [r:dis_to_sym] - (b:Symptom) RETURN a, r, b LIMIT 25 # 或者 MATCH p = () -[r : dis_to_sym] - () RETURN p LIMIT 25


4.3 非結(jié)構(gòu)化數(shù)據(jù)流水線


  • 學(xué)習(xí)目標(biāo):
    • 了解需要進(jìn)行命名實體識別的數(shù)據(jù)內(nèi)容.
    • 掌握非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體識別的過程.
    • 掌握非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體審核的過程.
    • 掌握非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體寫入的過程.

  • 需要進(jìn)行命名實體識別的數(shù)據(jù)內(nèi)容:
... 麻疹樣紅斑型藥疹.txt 麻疹病毒肺炎.txt 麻痹性臂叢神經(jīng)炎.txt 麻風(fēng)性周圍神經(jīng)病.txt 麻風(fēng)性葡萄膜炎.txt 黃體囊腫.txt 黃斑囊樣水腫.txt 黃斑裂孔性視網(wǎng)膜脫離.txt 黃韌帶骨化癥.txt 黏多糖貯積癥.txt 黏多糖貯積癥Ⅰ型.txt 黏多糖貯積癥Ⅱ型.txt 黏多糖貯積癥Ⅵ型.txt 黏多糖貯積癥Ⅲ型.txt 黏多糖貯積癥Ⅶ型.txt 黑色丘疹性皮膚病.txt ...
  • 每個txt文件的名字都是一種疾病名.

  • 文件位置: /data/doctor_offline/unstructured/norecognite/

  • 以黑色丘疹性皮膚病.txt為例, 有如下內(nèi)容:
初呈微小、圓形、皮膚色或黑色增深的丘疹,單個或少數(shù)發(fā)生于頜部或頰部,皮損逐漸增大增多,數(shù)年中可達(dá)數(shù)百,除眶周外尚分布于面部、頸部和胸上部。皮損大小形狀酷似脂溢性角化病及扁平疣鶒。不發(fā)生鱗屑,結(jié)痂和潰瘍,亦無瘙癢及其他主觀癥狀
  • txt中是對該疾病癥狀的文本描述.

  • 文件位置: /data/doctor_offline/unstructured/norecognite/黑色丘疹性皮膚病.txt

  • 進(jìn)行命名實體識別:
    • 進(jìn)行命名實體識別的工作我們這里使用AI模型實現(xiàn), 包括模型訓(xùn)練和使用的整個過程, 因此內(nèi)容以獨立一章的形成呈現(xiàn)給大家, 具體內(nèi)容在[第六章: 命名實體識別任務(wù)]

  • 進(jìn)行命名實體審核:
    • 同4.2 結(jié)構(gòu)化數(shù)據(jù)流水線中的命名實體審核.

  • 命名實體寫入數(shù)據(jù)庫:
    • 同4.2 結(jié)構(gòu)化數(shù)據(jù)流水線中的命名實體寫入數(shù)據(jù)庫.

  • 本章總結(jié):

    • 學(xué)習(xí)了離線部分的數(shù)據(jù)流水線以及組成部分.
      • 根據(jù)架構(gòu)展開圖圖,離線部分可分為兩條數(shù)據(jù)流水線,分別用于處理結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù). 這里稱它們?yōu)榻Y(jié)構(gòu)化數(shù)據(jù)流水線和非結(jié)構(gòu)化數(shù)據(jù)流水線.

    • 結(jié)構(gòu)化數(shù)據(jù)流水線的組成部分:
      • 結(jié)構(gòu)化數(shù)據(jù)爬蟲: 從網(wǎng)頁上抓取結(jié)構(gòu)化的有關(guān)醫(yī)學(xué)命名實體的內(nèi)容.
      • 結(jié)構(gòu)化數(shù)據(jù)的清洗: 對抓取的內(nèi)容進(jìn)行過濾和清洗, 以保留需要的部分.
      • 命名實體審核: 對當(dāng)前命名實體進(jìn)行審核, 來保證這些實體符合我們的要求.
      • 命名實體寫入數(shù)據(jù)庫: 將審核后的命名實體寫入數(shù)據(jù)庫之中, 供在線部分使用.

    • 非結(jié)構(gòu)化數(shù)據(jù)流水線的組成部分:
      • 非結(jié)構(gòu)化數(shù)據(jù)爬蟲: 從網(wǎng)頁上抓取非結(jié)構(gòu)化的包含醫(yī)學(xué)命名實體的文本.
      • 非結(jié)構(gòu)化數(shù)據(jù)清洗: 對非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行過濾和清洗, 以保留需要的部分.
      • 命名實體識別: 使用模型從非結(jié)構(gòu)化文本中獲取命名實體.
      • 命名實體審核: 對當(dāng)前命名實體進(jìn)行審核, 來保證這些實體符合我們的要求.
      • 命名實體寫入數(shù)據(jù)庫: 將審核后的命名實體寫入數(shù)據(jù)庫之中, 供在線部分使用.

    • 學(xué)習(xí)了需要進(jìn)行命名實體審核的數(shù)據(jù)內(nèi)容.

    • 學(xué)習(xí)了結(jié)構(gòu)化/非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體審核的過程.

    • 學(xué)習(xí)了結(jié)構(gòu)化/非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體寫入的過程.

    • 學(xué)習(xí)了需要進(jìn)行命名實體識別的數(shù)據(jù)內(nèi)容.

    • 非結(jié)構(gòu)化數(shù)據(jù)流水線中命名實體識別的過程.

5.1 任務(wù)介紹與模型選用

  • 學(xué)習(xí)目標(biāo):
    • 了解命名實體審核任務(wù)的相關(guān)知識.
    • 了解選用的模型及其原因.

  • NE審核任務(wù):
    • 一般在實體進(jìn)入數(shù)據(jù)庫存儲前, 中間都會有一道必不可少的工序, 就是對識別出來的實體進(jìn)行合法性的檢驗, 即命名實體(NE)審核任務(wù). 它的檢驗過程不使用上下文信息, 更關(guān)注于字符本身的組合方式來進(jìn)行判斷, 本質(zhì)上,它是一項短文本二分類問題.

  • 選用的模型及其原因:
    • 針對短文本任務(wù), 無須捕捉長距離的關(guān)系, 因此我們使用了傳統(tǒng)的RNN模型來解決, 性能和效果可以達(dá)到很好的均衡.
    • 短文本任務(wù)往往適合使用字嵌入的方式, 但是如果你的訓(xùn)練集不是很大,涉及的字?jǐn)?shù)有限, 那么可以直接使用預(yù)訓(xùn)練模型的字向量進(jìn)行表示即可. 我們這里使用了bert-chinese預(yù)訓(xùn)練模型來獲得中文漢字的向量表示.

5.2 訓(xùn)練數(shù)據(jù)集

  • 學(xué)習(xí)目標(biāo):
    • 了解訓(xùn)練數(shù)據(jù)集的樣式及其相關(guān)解釋.
    • 掌握將數(shù)據(jù)集加載到內(nèi)存中的過程.

  • 訓(xùn)練數(shù)據(jù)集的樣式:
1 手內(nèi)肌萎縮 0 縮萎肌內(nèi)手 1 尿黑酸 0 酸黑尿 1 單眼眼前黑影 0 影黑前眼眼單 1 憂郁 0 郁憂 1 紅細(xì)胞壽命縮短 0 短縮命壽胞細(xì)紅 1 皮膚黏蛋白沉積 0 積沉白蛋黏膚皮 1 眼神異常 0 常異神眼 1 陰囊墜脹痛 0 痛脹墜囊陰 1 動脈血氧飽和度降低 0 低降度和飽氧血脈動
  • 數(shù)據(jù)集的相關(guān)解釋:
    • 這些訓(xùn)練集中的正樣本往往是基于人工審核的標(biāo)準(zhǔn)命名實體.
    • 數(shù)據(jù)集中的第一列代表標(biāo)簽, 1為正標(biāo)簽, 代表后面的文字是命名實體. 0為負(fù)標(biāo)簽, 代表后面的文字不是命名實體.
    • 數(shù)據(jù)集中的第二列中的命名實體來源于數(shù)據(jù)庫中的癥狀實體名字, 它是結(jié)構(gòu)化爬蟲抓取的數(shù)據(jù). 而非命名實體則是它的字符串反轉(zhuǎn).
    • 正負(fù)樣本的比例是1:1.

  • 將數(shù)據(jù)集加載到內(nèi)存:
import pandas as pd from collections import Counter# 讀取數(shù)據(jù) train_data_path = "./train_data.csv" train_data= pd.read_csv(train_data_path, header=None, sep="\t")# 打印正負(fù)標(biāo)簽比例 print(dict(Counter(train_data[0].values)))# 轉(zhuǎn)換數(shù)據(jù)到列表形式 train_data = train_data.values.tolist() print(train_data[:10])
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 輸出效果:
# 正負(fù)標(biāo)簽比例 {1: 5740, 0: 5740}# 取出10條訓(xùn)練數(shù)據(jù)查看 [[1, '枕部疼痛'], [0, '痛疼部枕'], [1, '陶瑟征陽性'], [0, '性陽征瑟陶'], [1, '戀獸型性變態(tài)'], [0, '態(tài)變性型獸戀'], [1, '進(jìn)食困難'], [0, '難困食進(jìn)'], [1, '會陰瘺管或竇道形成'], [0, '成形道竇或管瘺陰會']]
  • 小節(jié)總結(jié):
    • 學(xué)習(xí)了訓(xùn)練數(shù)據(jù)集的樣式及其相關(guān)解釋.
    • 學(xué)習(xí)了將數(shù)據(jù)集加載到內(nèi)存中的過程.

5.3 BERT中文預(yù)訓(xùn)練模型

  • 學(xué)習(xí)目標(biāo):
    • 了解BERT中文預(yù)訓(xùn)練模型的有關(guān)知識和作用.
    • 掌握使用BERT中文預(yù)訓(xùn)練模型對句子編碼的過程.

  • BERT中文預(yù)訓(xùn)練模型:
    • BERT模型整體架構(gòu)基于Transformer模型架構(gòu), BERT中文預(yù)訓(xùn)練模型的解碼器和編碼器具有12層, 輸出層中的線性層具有768個節(jié)點, 即輸出張量最后一維的維度是768. 它使用的多頭注意力機(jī)制結(jié)構(gòu)中, 頭的數(shù)量為12, 模型總參數(shù)量為110M. 同時, 它在中文簡體和繁體上進(jìn)行訓(xùn)練, 因此適合中文簡體和繁體任務(wù).

  • BERT中文預(yù)訓(xùn)練模型作用:
    • 在實際的文本任務(wù)處理中, 有些訓(xùn)練語料很難獲得, 他們的總體數(shù)量和包含的詞匯總數(shù)都非常少, 不適合用于訓(xùn)練帶有Embedding層的模型, 但這些數(shù)據(jù)中卻又蘊含這一些有價值的規(guī)律可以被模型挖掘, 在這種情況下,使用預(yù)訓(xùn)練模型對原始文本進(jìn)行編碼是非常不錯的選擇, 因為預(yù)訓(xùn)練模型來自大型語料, 能夠使得當(dāng)前文本具有意義, 雖然這些意義可能并不針對某個特定領(lǐng)域, 但是這種缺陷可以使用微調(diào)模型來進(jìn)行彌補(bǔ).

  • 使用BERT中文預(yù)訓(xùn)練模型對句子編碼:
    bert 預(yù)訓(xùn)練模型地址
import torch import torch.nn as nn# 通過torch.hub(pytorch中專注于遷移學(xué)的工具)獲得已經(jīng)訓(xùn)練好的bert-base-chinese模型 model = torch.hub.load('huggingface/pytorch-transformers', 'model', 'bert-base-chinese')# 獲得對應(yīng)的字符映射器, 它將把中文的每個字映射成一個數(shù)字 tokenizer = torch.hub.load('huggingface/pytorch-transformers', 'tokenizer', 'bert-base-chinese')def get_bert_encode_for_single(text):"""description: 使用bert-chinese編碼中文文本:param text: 要進(jìn)行編碼的文本:return: 使用bert編碼后的文本張量表示"""# 首先使用字符映射器對每個漢字進(jìn)行映射# 這里需要注意, bert的tokenizer映射后會為結(jié)果前后添加開始和結(jié)束標(biāo)記即101和102 # 這對于多段文本的編碼是有意義的, 但在我們這里沒有意義, 因此使用[1:-1]對頭和尾進(jìn)行切片indexed_tokens = tokenizer.encode(text)[1:-1]# 之后將列表結(jié)構(gòu)轉(zhuǎn)化為tensortokens_tensor = torch.tensor([indexed_tokens])print(tokens_tensor)# 使模型不自動計算梯度with torch.no_grad():# 調(diào)用模型獲得隱層輸出encoded_layers, _ = model(tokens_tensor)# 輸出的隱層是一個三維張量, 最外層一維是1, 我們使用[0]降去它.print(encoded_layers.shape)encoded_layers = encoded_layers[0]return encoded_layers
  • 代碼位置: /data/doctor_offline/review_model/bert_chinese_encode.py

  • 輸入?yún)?shù):
text = "你好, 周杰倫"
  • 調(diào)用:
outputs = get_bert_encode_for_single(text) print(outputs) print(outputs.shape)
  • 輸出效果:
tensor([[ 3.2731e-01, -1.4832e-01, -9.1618e-01, ..., -4.4088e-01,-4.1074e-01, -7.5570e-01],[-1.1287e-01, -7.6269e-01, -6.4861e-01, ..., -8.0478e-01,-5.3600e-01, -3.1953e-01],[-9.3012e-02, -4.4381e-01, -1.1985e+00, ..., -3.6624e-01,-4.7467e-01, -2.6408e-01],[-1.6896e-02, -4.3753e-01, -3.6060e-01, ..., -3.2451e-01,-3.4204e-02, -1.7930e-01],[-1.3159e-01, -3.0048e-01, -2.4193e-01, ..., -4.5756e-02,-2.0958e-01, -1.0649e-01],[-4.0006e-01, -3.4410e-01, -3.8532e-05, ..., 1.9081e-01,1.7006e-01, -3.6221e-01]])torch.Size([6, 768])

注意:torch.hub.load無法下載時,利用迅雷等通過鏈接中 的地址進(jìn)行下載model.bin config.json vocab.txt并更改名稱
from transformers import BertModel, BertTokenizer

import torch from transformers import BertModel, BertTokenizer# 通過torch.hub(pytorch中專注于遷移學(xué)的工具)獲得已經(jīng)訓(xùn)練好的bert-base-chinese模型 # model = torch.hub.load('huggingface/pytorch-transformers', 'model', 'bert-base-chinese') # 獲得對應(yīng)的字符映射器, 它將把中文的每個字映射成一個數(shù)字 # tokenizer = torch.hub.load('huggingface/pytorch-transformers', 'tokenizer', 'bert-base-chinese') # model = BertModel.from_pretrained('./bert-base-chinese') tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/')def get_bert_encode_for_single(text):"""使用bert-base-chinese對中文文本進(jìn)行編碼:param text: 進(jìn)行編碼的中文文本:return: 編號后的張量"""# 使用字符映射器對每個漢字進(jìn)行映射# bert中tokenizer映射后會加入開始和結(jié)束標(biāo)記101,102 采用[1:-1]去除indexed_tokens = tokenizer.encode(text)[1 : -1]# 封裝為tensortokens_tensor = torch.tensor([indexed_tokens])print(tokens_tensor)# 預(yù)測部分-不需要求導(dǎo)with torch.no_grad():encoded_layers, _ = model(tokens_tensor)print('encoded_layers_shape:{}'.format(encoded_layers.shape))# 模型的輸出均為三維張量,第一維為1,只提取后兩個維度張量,需要[0]來降維encoded_layers = encoded_layers[0]return encoded_layersif __name__ == '__main__':text = '你好, 周杰倫'outputs = get_bert_encode_for_single(text)print('outputs:{}'.format(outputs))print('outputs.shape:{}'.format(outputs.shape)) tensor([[ 872, 1962, 117, 1453, 3345, 840]]) encoded_layers_shape:torch.Size([1, 6, 768]) outputs:tensor([[ 3.2731e-01, -1.4832e-01, -9.1618e-01, ..., -4.4088e-01,-4.1074e-01, -7.5570e-01],[-1.1287e-01, -7.6269e-01, -6.4861e-01, ..., -8.0478e-01,-5.3600e-01, -3.1953e-01],[-9.3014e-02, -4.4381e-01, -1.1985e+00, ..., -3.6624e-01,-4.7467e-01, -2.6408e-01],[-1.6897e-02, -4.3753e-01, -3.6060e-01, ..., -3.2451e-01,-3.4204e-02, -1.7930e-01],[-1.3159e-01, -3.0048e-01, -2.4193e-01, ..., -4.5757e-02,-2.0958e-01, -1.0649e-01],[-4.0006e-01, -3.4410e-01, -3.9786e-05, ..., 1.9081e-01,1.7006e-01, -3.6221e-01]]) outputs.shape:torch.Size([6, 768])
  • 小節(jié)總結(jié):

    • 學(xué)習(xí)了BERT中文預(yù)訓(xùn)練模型的有關(guān)知識:
      • BERT模型整體架構(gòu)基于Transformer模型架構(gòu), BERT中文預(yù)訓(xùn)練模型的解碼器和編碼器具有12層, 輸出層中的線性層具有768個節(jié)點, 即輸出張量最后一維的維度是768. 它使用的多頭注意力機(jī)制結(jié)構(gòu)中, 頭的數(shù)量為12, 模型總參數(shù)量為110M. 同時, 它在中文簡體和繁體上進(jìn)行訓(xùn)練, 因此適合中文簡體和繁體任務(wù).

    • 學(xué)習(xí)了BERT中文預(yù)訓(xùn)練模型的作用:
      • 在實際的文本任務(wù)處理中, 有些訓(xùn)練語料很難獲得, 他們的總體數(shù)量和包含的詞匯總數(shù)都非常少, 不適合用于訓(xùn)練帶有Embedding層的模型, 但這些數(shù)據(jù)中卻又蘊含這一些有價值的規(guī)律可以被模型挖掘, 在這種情況下, 使用預(yù)訓(xùn)練模型對原始文本進(jìn)行編碼是非常不錯的選擇, 因為預(yù)訓(xùn)練模型來自大型語料, 能夠使得當(dāng)前文本具有意義, 雖然這些意義可能并不針對某個特定領(lǐng)域, 但是這種缺陷可以使用微調(diào)模型來進(jìn)行彌補(bǔ).

    • 學(xué)習(xí)了使用BERT中文預(yù)訓(xùn)練模型對句子編碼的函數(shù): get_bert_encode_for_single(text)

5.4 構(gòu)建RNN模型

  • 學(xué)習(xí)目標(biāo):
    • 學(xué)習(xí)RNN模型的內(nèi)部結(jié)構(gòu)及計算公式.
    • 掌握RNN模型的實現(xiàn)過程.

  • 傳統(tǒng)RNN的內(nèi)部結(jié)構(gòu)圖:


  • 結(jié)構(gòu)解釋圖:


  • 內(nèi)部結(jié)構(gòu)分析:
    * 我們把目光集中在中間的方塊部分, 它的輸入有兩部分, 分別是h(t-1)以及x(t), 代表上一時間步的隱層輸出, 以及此時間步的輸入, 它們進(jìn)入RNN結(jié)構(gòu)體后, 會"融合"到一起, 這種融合我們根據(jù)結(jié)構(gòu)解釋可知, 是將二者進(jìn)行拼接, 形成新的張量[x(t), h(t-1)], 之后這個新的張量將通過一個全連接層(線性層), 該層>使用tanh作為激活函數(shù), 最終得到該時間步的輸出h(t), 它將作為下一個時間步的>輸入和x(t+1)一起進(jìn)入結(jié)構(gòu)體. 以此類推.

  • 內(nèi)部結(jié)構(gòu)過程演示:


  • 根據(jù)結(jié)構(gòu)分析得出內(nèi)部計算公式:


  • 激活函數(shù)tanh的作用:
    * 用于幫助調(diào)節(jié)流經(jīng)網(wǎng)絡(luò)的值, tanh函數(shù)將值壓縮在-1和1之間.


  • 構(gòu)建RNN模型的代碼分析:
class RNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):"""初始化函數(shù)中有三個參數(shù),分別是輸入張量最后一維的尺寸大小,隱層張量最后一維的尺寸大小, 輸出張量最后一維的尺寸大小"""super(RNN, self).__init__()# 傳入隱含層尺寸大小self.hidden_size = hidden_size# 構(gòu)建從輸入到隱含層的線性變化, 這個線性層的輸入尺寸是input_size + hidden_size# 這是因為在循環(huán)網(wǎng)絡(luò)中, 每次輸入都有兩部分組成,分別是此時刻的輸入xt和上一時刻產(chǎn)生的輸出ht-1.# 這個線性層的輸出尺寸是hidden_sizeself.i2h = nn.Linear(input_size + hidden_size, hidden_size)# 構(gòu)建從輸入到輸出層的線性變化, 這個線性層的輸入尺寸還是input_size + hidden_size# 這個線性層的輸出尺寸是output_size.self.i2o = nn.Linear(input_size + hidden_size, output_size)# 最后需要對輸出做softmax處理, 獲得結(jié)果.self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input, hidden):"""在forward函數(shù)中, 參數(shù)分別是規(guī)定尺寸的輸入張量, 以及規(guī)定尺寸的初始化隱層張量"""# 首先使用torch.cat將input與hidden進(jìn)行張量拼接combined = torch.cat((input, hidden), 1)# 通過輸入層到隱層變換獲得hidden張量hidden = self.i2h(combined)# 通過輸入到輸出層變換獲得output張量output = self.i2o(combined)# 對輸出進(jìn)行softmax處理output = self.softmax(output)# 返回輸出張量和最后的隱層結(jié)果return output, hiddendef initHidden(self):"""隱層初始化函數(shù)"""# 將隱層初始化成為一個1xhidden_size的全0張量return torch.zeros(1, self.hidden_size)
  • torch.cat演示:
>>> x = torch.randn(2, 3) >>> x tensor([[ 0.6580, -1.0969, -0.4614],[-0.1034, -0.5790, 0.1497]]) >>> torch.cat((x, x, x), 0) tensor([[ 0.6580, -1.0969, -0.4614],[-0.1034, -0.5790, 0.1497],[ 0.6580, -1.0969, -0.4614],[-0.1034, -0.5790, 0.1497],[ 0.6580, -1.0969, -0.4614],[-0.1034, -0.5790, 0.1497]]) >>> torch.cat((x, x, x), 1) ensor([[ 0.6580, -1.0969, -0.4614, 0.6580, -1.0969, -0.4614, 0.6580,-1.0969, -0.4614],[-0.1034, -0.5790, 0.1497, -0.1034, -0.5790, 0.1497, -0.1034,-0.5790, 0.1497]])
  • 代碼位置: /data/doctor_offline/review_model/RNN_MODEL.py

  • 實例化參數(shù):
input_size = 768 hidden_size = 128 n_categories = 2 # ner審核通過或者不通過
  • 輸入?yún)?shù):
input = torch.rand(1, input_size) hidden = torch.rand(1, hidden_size)
  • 調(diào)用:
from RNN_MODEL import RNN rnn = RNN(input_size, hidden_size, n_categories) outputs, hidden = rnn(input, hidden) print("outputs:", outputs) print("hidden:", hidden)
  • 輸出效果:
outputs: tensor([[-0.7858, -0.6084]], grad_fn=<LogSoftmaxBackward>) # [1, 2]hidden: tensor([[-4.8444e-01, -5.9609e-02, 1.7870e-01, -1.6553e-01, ... , 5.6711e-01]], grad_fn=<AddmmBackward>)) # [1, 128]
  • 小節(jié)總結(jié):
    • 學(xué)習(xí)了RNN模型的內(nèi)部結(jié)構(gòu)及計算公式.
    • 學(xué)習(xí)并實現(xiàn)了RNN模型的類: class RNN(nn.Module).

5.5 進(jìn)行模型訓(xùn)練

  • 學(xué)習(xí)目標(biāo):
    • 了解進(jìn)行模型訓(xùn)練的步驟.
    • 掌握模型訓(xùn)練中每個步驟的實現(xiàn)過程.

  • 進(jìn)行模型訓(xùn)練的步驟:
    • 第一步: 構(gòu)建隨機(jī)選取數(shù)據(jù)函數(shù).
    • 第二步: 構(gòu)建模型訓(xùn)練函數(shù).
    • 第三步: 構(gòu)建模型驗證函數(shù).
    • 第四步: 調(diào)用訓(xùn)練和驗證函數(shù).
    • 第五步: 繪制訓(xùn)練和驗證的損失和準(zhǔn)確率對照曲線.
    • 第六步: 模型保存.

  • 第一步: 構(gòu)建隨機(jī)選取數(shù)據(jù)函數(shù)
import pandas as pd import random from bert_chinese_encode import get_bert_encode_for_single import torch# 讀取數(shù)據(jù) train_data_path = './train_data.csv' train_data = pd.read_csv(train_data_path, header = None, sep = '\t', encoding = 'utf-8') trian_data = train_data.values.tolist()def randomTrainingExample(train_data):"""隨機(jī)選取數(shù)據(jù)函數(shù), train_data是訓(xùn)練集的列表形式數(shù)據(jù)"""# 從train_data隨機(jī)選擇一條數(shù)據(jù)category, line = random.choice(train_data)# 將里面的文字使用bert進(jìn)行編碼, 獲取編碼后的tensor類型數(shù)據(jù)line_tensor = get_bert_encode_for_single(line)# 將分類標(biāo)簽封裝成tensorcategory_tensor = torch.tensor([int(category)])# 返回四個結(jié)果return category, line, category_tensor, line_tensor
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 輸入?yún)?shù):
# 將數(shù)據(jù)集加載到內(nèi)存獲得的train_data
  • 調(diào)用:
# 選擇10條數(shù)據(jù)進(jìn)行查看 for i in range(10):category, line, category_tensor, line_tensor = randomTrainingExample(train_data)print('category =', category, '/ line =', line)
  • 輸出效果:
category = 1 / line = 觸覺失調(diào) category = 0 / line = 顫震性理生 category = 0 / line = 征壓血高娠妊 category = 1 / line = 食欲減退 category = 0 / line = 血淤道腸胃 category = 0 / line = 形畸節(jié)關(guān) category = 0 / line = 咳嗆水飲 category = 0 / line = 癥痣巨 category = 1 / line = 晝盲 category = 1 / line = 眼神異常
  • 第二步: 構(gòu)建模型訓(xùn)練函數(shù)
# 選取損失函數(shù)為NLLLoss() criterion = nn.NLLLoss() # 學(xué)習(xí)率為0.005 learning_rate = 0.005def train(category_tensor, line_tensor):"""模型訓(xùn)練函數(shù), category_tensor代表類別張量, line_tensor代表編碼后的文本張量"""# 初始化隱層 hidden = rnn.initHidden()# 模型梯度歸0rnn.zero_grad()# 遍歷line_tensor中的每一個字的張量表示for i in range(line_tensor.size()[0]):# 然后將其輸入到rnn模型中, 因為模型要求是輸入必須是二維張量, 因此需要拓展一個維度, 循環(huán)調(diào)用rnn直到最后一個字output, hidden = rnn(line_tensor[i].unsqueeze(0), hidden)# 根據(jù)損失函數(shù)計算損失, 輸入分別是rnn的輸出結(jié)果和真正的類別標(biāo)簽loss = criterion(output, category_tensor)# 將誤差進(jìn)行反向傳播loss.backward()# 更新模型中所有的參數(shù)for p in rnn.parameters():# 將參數(shù)的張量表示與參數(shù)的梯度乘以學(xué)習(xí)率的結(jié)果相加以此來更新參數(shù)p.data.add_(-learning_rate, p.grad.data)# 返回結(jié)果和損失的值return output, loss.item()
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 第三步: 模型驗證函數(shù)
def valid(category_tensor, line_tensor):"""模型驗證函數(shù), category_tensor代表類別張量, line_tensor代表編碼后的文本張量"""# 初始化隱層hidden = rnn.initHidden()# 驗證模型不自動求解梯度with torch.no_grad():# 遍歷line_tensor中的每一個字的張量表示 for i in range(line_tensor.size()[0]):# 然后將其輸入到rnn模型中, 因為模型要求是輸入必須是二維張量, 因此需要拓展一個維度, 循環(huán)調(diào)用rnn直到最后一個字output, hidden = rnn(line_tensor[i].unsqueeze(0), hidden) # 獲得損失loss = criterion(output, category_tensor)# 返回結(jié)果和損失的值return output, loss.item()
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 第四步: 調(diào)用訓(xùn)練和驗證函數(shù)
  • 構(gòu)建時間計算函數(shù):
import time import mathdef timeSince(since):"獲得每次打印的訓(xùn)練耗時, since是訓(xùn)練開始時間"# 獲得當(dāng)前時間now = time.time()# 獲得時間差,就是訓(xùn)練耗時s = now - since# 將秒轉(zhuǎn)化為分鐘, 并取整m = math.floor(s / 60)# 計算剩下不夠湊成1分鐘的秒數(shù)s -= m * 60# 返回指定格式的耗時return '%dm %ds' % (m, s)
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 輸入?yún)?shù):
# 假定模型訓(xùn)練開始時間是10min之前 since = time.time() - 10*60
  • 調(diào)用:
period = timeSince(since) print(period)
  • 輸出效果:
10m 0s
  • 調(diào)用訓(xùn)練和驗證函數(shù)并打印日志
# 設(shè)置迭代次數(shù)為50000步 n_iters = 50000# 打印間隔為1000步 plot_every = 1000# 初始化打印間隔中訓(xùn)練和驗證的損失和準(zhǔn)確率 train_current_loss = 0 train_current_acc = 0 valid_current_loss = 0 valid_current_acc = 0# 初始化盛裝每次打印間隔的平均損失和準(zhǔn)確率 all_train_losses = [] all_train_acc = [] all_valid_losses = [] all_valid_acc = []# 獲取開始時間戳 start = time.time()# 循環(huán)遍歷n_iters次 for iter in range(1, n_iters + 1):# 調(diào)用兩次隨機(jī)函數(shù)分別生成一條訓(xùn)練和驗證數(shù)據(jù)category, line, category_tensor, line_tensor = randomTrainingExample(train_data)category_, line_, category_tensor_, line_tensor_ = randomTrainingExample(train_data)# 分別調(diào)用訓(xùn)練和驗證函數(shù), 獲得輸出和損失train_output, train_loss = train(category_tensor, line_tensor)valid_output, valid_loss = valid(category_tensor_, line_tensor_)# 進(jìn)行訓(xùn)練損失, 驗證損失,訓(xùn)練準(zhǔn)確率和驗證準(zhǔn)確率分別累加train_current_loss += train_losstrain_current_acc += (train_output.argmax(1) == category_tensor).sum().item()valid_current_loss += valid_lossvalid_current_acc += (valid_output.argmax(1) == category_tensor_).sum().item()# 當(dāng)?shù)螖?shù)是指定打印間隔的整數(shù)倍時if iter % plot_every == 0:# 用剛剛累加的損失和準(zhǔn)確率除以間隔步數(shù)得到平均值train_average_loss = train_current_loss / plot_everytrain_average_acc = train_current_acc/ plot_everyvalid_average_loss = valid_current_loss / plot_everyvalid_average_acc = valid_current_acc/ plot_every# 打印迭代步, 耗時, 訓(xùn)練損失和準(zhǔn)確率, 驗證損失和準(zhǔn)確率print("Iter:", iter, "|", "TimeSince:", timeSince(start))print("Train Loss:", train_average_loss, "|", "Train Acc:", train_average_acc)print("Valid Loss:", valid_average_loss, "|", "Valid Acc:", valid_average_acc)# 將結(jié)果存入對應(yīng)的列表中,方便后續(xù)制圖all_train_losses.append(train_average_loss)all_train_acc.append(train_average_acc)all_valid_losses.append(valid_average_loss)all_valid_acc.append(valid_average_acc)# 將該間隔的訓(xùn)練和驗證損失及其準(zhǔn)確率歸0train_current_loss = 0train_current_acc = 0valid_current_loss = 0valid_current_acc = 0
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 輸出效果:
Iter: 1000 | TimeSince: 0m 56s Train Loss: 0.6127021567507527 | Train Acc: 0.747 Valid Loss: 0.6702297774022868 | Valid Acc: 0.7 Iter: 2000 | TimeSince: 1m 52s Train Loss: 0.5190641692602076 | Train Acc: 0.789 Valid Loss: 0.5217500487511397 | Valid Acc: 0.784 Iter: 3000 | TimeSince: 2m 48s Train Loss: 0.5398398997281778 | Train Acc: 0.8 Valid Loss: 0.5844468013737023 | Valid Acc: 0.777 Iter: 4000 | TimeSince: 3m 43s Train Loss: 0.4700755337187358 | Train Acc: 0.822 Valid Loss: 0.5140456306522071 | Valid Acc: 0.802 Iter: 5000 | TimeSince: 4m 38s Train Loss: 0.5260879981063878 | Train Acc: 0.804 Valid Loss: 0.5924804099237979 | Valid Acc: 0.796 Iter: 6000 | TimeSince: 5m 33s Train Loss: 0.4702717279043861 | Train Acc: 0.825 Valid Loss: 0.6675750375208704 | Valid Acc: 0.78 Iter: 7000 | TimeSince: 6m 27s Train Loss: 0.4734503294042624 | Train Acc: 0.833 Valid Loss: 0.6329268293256277 | Valid Acc: 0.784 Iter: 8000 | TimeSince: 7m 23s Train Loss: 0.4258338176879665 | Train Acc: 0.847 Valid Loss: 0.5356959595441066 | Valid Acc: 0.82 Iter: 9000 | TimeSince: 8m 18s Train Loss: 0.45773495503464817 | Train Acc: 0.843 Valid Loss: 0.5413714128659645 | Valid Acc: 0.798 Iter: 10000 | TimeSince: 9m 14s Train Loss: 0.4856756244019302 | Train Acc: 0.835 Valid Loss: 0.5450502399195044 | Valid Acc: 0.813
  • 第五步: 繪制訓(xùn)練和驗證的損失和準(zhǔn)確率對照曲線

plt.title(“your title name”, y=-0.1)設(shè)置y位置可以將title設(shè)置在圖像下方

import matplotlib.pyplot as pltplt.figure(0) plt.plot(all_train_losses, label="Train Loss") plt.plot(all_valid_losses, color="red", label="Valid Loss") plt.legend(loc='upper left')plt.savefig("./loss.png")plt.figure(1) plt.plot(all_train_acc, label="Train Acc") plt.plot(all_valid_acc, color="red", label="Valid Acc") plt.legend(loc='upper left')plt.savefig("./acc.png")
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 訓(xùn)練和驗證損失對照曲線:


  • 訓(xùn)練和驗證準(zhǔn)確率對照曲線:


  • 分析:
    * 損失對照曲線一直下降, 說明模型能夠從數(shù)據(jù)中獲取規(guī)律,正在收斂, 準(zhǔn)確率對照曲線中驗證準(zhǔn)確率一直上升,最終維持在0.98左右.

  • 第六步: 模型保存
# 保存路徑 MODEL_PATH = './BERT_RNN.pth' # 保存模型參數(shù) torch.save(rnn.state_dict(), MODEL_PATH)
  • 代碼位置: /data/doctor_offline/review_model/train.py

  • 輸出效果:
    * 在/data/doctor_offline/review_model/路徑下生成BERT_RNN.pth文件.

  • 小節(jié)總結(jié):
    • 學(xué)習(xí)了進(jìn)行模型訓(xùn)練的步驟:
      • 第一步: 構(gòu)建隨機(jī)選取數(shù)據(jù)函數(shù).
      • 第二步: 構(gòu)建模型訓(xùn)練函數(shù).
      • 第三步: 構(gòu)建模型驗證函數(shù).
      • 第四步: 調(diào)用訓(xùn)練和驗證函數(shù).
      • 第五步: 繪制訓(xùn)練和驗證的損失和準(zhǔn)確率對照曲線.
      • 第六步: 模型保存.

5.6 模型使用

  • 學(xué)習(xí)目標(biāo):
    • 掌握模型預(yù)測的實現(xiàn)過程.
    • 掌握模型批量預(yù)測的實現(xiàn)過程.

  • 模型預(yù)測的實現(xiàn)過程:
import os import torch import torch.nn as nn# 導(dǎo)入RNN模型結(jié)構(gòu) from RNN_MODEL import RNN # 導(dǎo)入bert預(yù)訓(xùn)練模型編碼函數(shù) from bert_chinese_encode import get_bert_encode_for_single# 預(yù)加載的模型參數(shù)路徑 MODEL_PATH = './BERT_RNN.pth'# 隱層節(jié)點數(shù), 輸入層尺寸, 類別數(shù)都和訓(xùn)練時相同即可 n_hidden = 128 input_size = 768 n_categories = 2# 實例化RNN模型, 并加載保存模型參數(shù) rnn = RNN(input_size, n_hidden, n_categories) rnn.load_state_dict(torch.load(MODEL_PATH))def _test(line_tensor):"""模型測試函數(shù), 它將用在模型預(yù)測函數(shù)中, 用于調(diào)用RNN模型并返回結(jié)果.它的參數(shù)line_tensor代表輸入文本的張量表示"""# 初始化隱層張量hidden = rnn.initHidden()# 與訓(xùn)練時相同, 遍歷輸入文本的每一個字符for i in range(line_tensor.size()[0]):# 將其逐次輸送給rnn模型output, hidden = rnn(line_tensor[i].unsqueeze(0), hidden)# 獲得rnn模型最終的輸出return outputdef predict(input_line):"""模型預(yù)測函數(shù), 輸入?yún)?shù)input_line代表需要預(yù)測的文本"""# 不自動求解梯度with torch.no_grad():# 將input_line使用bert模型進(jìn)行編碼output = _test(get_bert_encode_for_single(input_line))# 從output中取出最大值對應(yīng)的索引, 比較的維度是1_, topi = output.topk(1, 1)# 返回結(jié)果數(shù)值return topi.item()

tensor.topk演示:

>>> tr = torch.randn(1, 2) >>> tr tensor([[-0.1808, -1.4170]]) >>> tr.topk(1, 1) torch.return_types.topk(values=tensor([[-0.1808]]), indices=tensor([[0]]))
  • 代碼位置: /data/doctor_offline/review_model/predict.py

  • 輸入?yún)?shù):
input_line = "點瘀樣尖針性發(fā)多"
  • 調(diào)用:
result = predict(input_line) print("result:", result)
  • 輸出效果:
result: 0
  • 模型批量預(yù)測的實現(xiàn)過程:
def batch_predict(input_path, output_path):"""批量預(yù)測函數(shù), 以原始文本(待識別的命名實體組成的文件)輸入路徑和預(yù)測過濾后(去除掉非命名實體的文件)的輸出路徑為參數(shù)"""# 待識別的命名實體組成的文件是以疾病名稱為csv文件名, # 文件中的每一行是該疾病對應(yīng)的癥狀命名實體# 讀取路徑下的每一個csv文件名, 裝入csv列表之中csv_list = os.listdir(input_path)# 遍歷每一個csv文件for csv in csv_list:# 以讀的方式打開每一個csv文件with open(os.path.join(input_path, csv), "r") as fr:# 再以寫的方式打開輸出路徑的同名csv文件with open(os.path.join(output_path, csv), "w") as fw:# 讀取csv文件的每一行input_line = fr.readline()# 使用模型進(jìn)行預(yù)測res = predict(input_line)# 如果結(jié)果為1if res:# 說明審核成功, 寫入到輸出csv中fw.write(input_line + "\n")else:pass
  • 代碼位置: /data/doctor_offline/review_model/predict.py

  • 輸入?yún)?shù):
input_path = "/data/doctor_offline/structured/noreview/" output_path = "/data/doctor_offline/structured/reviewed/"
  • 調(diào)用:
batch_predict(input_path, output_path)
  • 輸出效果:
    • 在輸出路徑下生成與輸入路徑等數(shù)量的同名csv文件, 內(nèi)部的癥狀實體是被審核的可用實體.

  • 小節(jié)總結(jié):
    • 學(xué)習(xí)并實現(xiàn)了模型預(yù)測的函數(shù): predict(input_line).
    • 學(xué)習(xí)并實現(xiàn)了模型批量預(yù)測的函數(shù): batch_predict(input_path, output_path)

總結(jié)

以上是生活随笔為你收集整理的NLP在线医生(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。