日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NLP在线医生(一)

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

1.1 背景介紹


  • 學習目標:
    • 了解智能對話系統的相關背景知識.
    • 掌握使用Unit對話API.

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


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

  • 我們的在線醫生項目就是任務導向型的智能對話系統.

1.2 Unit對話API的使用


  • 學習目標:
    • 了解Unit平臺的相關知識.
    • 掌握調用Unit API的實現過程.

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


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

  • 第一步: 注冊登錄百度賬戶, 進入Unit控制臺創建自己的機器人.
    ai.baidu.com

  • 第二步: 進行相關配置, 獲得請求API接口需要的API Key與Secret Key.
  • 點擊獲取API Key進入百度云應用管理頁面.

  • 點擊創建應用, 進入應用信息表單填寫頁面.

  • 填寫完畢后, 點擊立即創建, 成功后會提示創建完畢.

  • 點擊返回應用列表.
  • 可以看到創建的API Key和Secret Key, 至此創建流程結束.
  • 第三步: 在服務器上編寫API調用腳本并進行測試
import json import random import requests# client_id 為官網獲取的AK, client_secret 為官網獲取的SK client_id = "1xhPonkmHqwolDt3GCICLX39" client_secret = "SRYsfjMGNuW8G265paMXLEjDTjO6O4RC"def unit_chat(chat_input, user_id="88888"):"""description:調用百度UNIT接口,回復聊天內容Parameters----------chat_input : str用戶發送天內容user_id : str發起聊天用戶ID,可任意定義Return----------返回unit回復內容"""# 設置默認回復內容, 一旦接口出現異常, 回復該內容chat_reply = "不好意思,俺們正在學習中,隨后回復你。"# 根據 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"]# 根據 access_token 獲取聊天機器人接口數據unit_chatbot_url = "https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=" + access_token# 拼裝聊天接口對應請求發送數據,主要是填充 query 值post_data = {"log_id": str(random.random()),"request": {"query": chat_input,"user_id": user_id},"session_id": "","service_id": "S23245","version": "2.0"}# 將封裝好的數據作為請求內容, 發送給Unit聊天機器人接口, 并得到返回結果res = requests.post(url=unit_chatbot_url, json=post_data)# 獲取聊天接口返回數據unit_chat_obj = json.loads(res.content)# print(unit_chat_obj)# 打印返回的結果# 判斷聊天接口返回數據是否出錯 error_code == 0 則表示請求正確if unit_chat_obj["error_code"] != 0: return chat_reply# 解析聊天接口返回數據,找到返回文本內容 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"]# 隨機選取一個"意圖置信度"[+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回復 >>>", chat_reply)if chat_input == 'Q' or chat_input == 'q':break
  • 代碼位置: /data/doctor_online/main_serve/unit.py

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

    • 學習了智能對話系統的相關背景知識:
      • 什么是智能對話系統
      • 從處理問題的目的來區分, 智能對話系統的分類

    • 我們的在線醫生項目就是任務導向型的智能對話系統.

    • 學習了Unit平臺的相關知識:
      • Unit平臺是百度大腦開放的智能對話定制與服務平臺, 也是當前最大的中文領域對話開放平臺之一.

    • 學習了調用Unit API的實現過程:
      • 第一步: 注冊登錄百度賬戶, 進入Unit控制臺創建自己的機器人.
      • 第二步: 進行相關配置, 獲得請求API接口需要的API Key與Secret Key.
      • 第三步: 在服務器上編寫API調用腳本并進行測試.

2.1 在線醫生的總體架構

  • 學習目標:
    • 了解在線醫生項目的總體架構

  • 項目整體架構圖:


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

2.2 總體架構中的工具介紹


  • 學習目標:
    • 了解總體架構中使用了哪些工具.
    • 掌握總體架構中各個工具的簡介, 作用, 安裝和基本使用方法.

  • 總體架構中使用的工具:
    • Flask web服務框架
    • Redis數據庫
    • Gunicorn服務組件
    • Supervisor服務監控器
    • Neo4j圖數據庫

  • Flask web服務框架:

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


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

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

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

  • Redis數據庫:
    window下使用redis

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

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

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

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

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

如果redis 設置了密碼
需要
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 }# 導入redis驅動 import redis# 創建一個redis連接池 pool = redis.ConnectionPool( **REDIS_CONFIG) # 從連接池中初始化一個活躍的連接對象 r = redis.StrictRedis(connection_pool=pool) # hset表示使用hash數據結構進行數據寫入 # uid代表某個用戶的唯一標識 uid = "8888" # key是需要記錄的數據描述 key = "該用戶最后一次說的話:".encode('utf-8') # value是需要記錄的數據具體內容 value = "再見, 董小姐".encode('utf-8') r.hset(uid, key, value)# hget表示使用hash數據結構進行數據讀取 result = r.hget(uid, key) print(result.decode('utf-8'))
  • 輸出效果:
再見, 董小姐
  • Gunicorn服務組件:

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

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

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

  • 作用:
    * 在項目中, Supervisor用于監控和守護主要邏輯服務和redis數據庫服務.

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


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

  • 本章總結:

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

    • 學習了總體架構中使用的工具:
      • Flask web服務框架
      • Redis數據庫
      • Gunicorn服務組件
      • Supervisor服務監控器
      • Neo4j圖數據庫

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

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

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

    • Supervisor服務監控:
      • 作用: 在項目中, Supervisor用于監控和守護主要邏輯服務和redis數據庫服務.

3.1 neo4j簡介

  • 學習目標:
    • 了解neo4j圖數據庫的簡介, 版本說明.
    • 了解節點, 關系,屬性,標簽的有關概念.


windows 下neo4j

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

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

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

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

  • neo4j圖形數據庫的有關概念:


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

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

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

  • 標簽
    * 標簽用于組節點到集, 節點可以具有多個標簽, 對標簽進行索引以加速在圖中查找節點.

3.2 neo4j圖數據庫的安裝

  • 學習目標:
    • 掌握neo4j圖數據庫的安裝流程及其可視化后臺的登陸…

  • neo4j圖數據庫的安裝流程:
    • 第一步: 將neo4j安裝信息載入到yum檢索列表.
    • 第二步: 使用yum install命令安裝.
    • 第三步: 修改配置文件內容 /etc/neo4j/neo4j.conf.
    • 第四步: 啟動neo4j數據庫.

  • 第一步: 將neo4j安裝信息載入到yum檢索列表
cd /tmp wget http://debian.neo4j.org/neotechnology.gpg.key rpm --import neotechnology.gpg.key cat <<EOF> /etc/yum.repos.d/neo4j.repo # 寫入下面內容 [neo4j] name=Neo4j RPM Repository baseurl=http://yum.neo4j.org/stable enabled=1 gpgcheck=1
  • 第二步: 使用yum install命令安裝
yum install neo4j-3.3.5
  • 第三步: 修改配置文件默認在/etc/neo4j/neo4j.conf, 為了方便顯示下面把一些修改顯示在這里
# 數據庫的存儲庫存儲位置、日志位置等 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# 導入的位置 dbms.directories.import=/var/lib/neo4j/import# 初始化內存大小 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數據庫
# 啟動命令 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 (默認)


  • 小節總結:

    • 學習了neo4j圖數據庫的安裝流程:
      • 第一步: 將neo4j安裝信息載入到yum檢索列表.
      • 第二步: 使用yum install命令安裝.
      • 第三步: 修改配置文件內容 /etc/neo4j/neo4j.conf.
      • 第四步: 啟動neo4j數據庫.

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

3.3 Cypher介紹與使用

  • 學習目標
    • 了解Cypher的基本概念.
    • 掌握Cypher的基本命令和語法.

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

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

  • create命令: 創建圖數據中的節點.

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


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

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


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

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


  • 然后再次用merge查詢, 發現數據庫中的數據并沒有增加, 因為已經存在相同的數據了, merge匹配成功.

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


  • 使用create創建關系: 必須創建有方向性的關系, 否則報錯.

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


  • 使用merge創建關系: 可以創建有/無方向性的關系.

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


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

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


  • delete命令: 刪除節點/關系及其關聯的屬性.

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


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

  • 演示:
# 匹配查詢標簽Employee, 將所有匹配結果按照id值升序排列后返回結果 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
  • 效果:


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

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

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


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

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


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

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


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

  • 演示:
# 輸入字符串為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
  • 效果:


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

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

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


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

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


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

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


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

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


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

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


  • 索引index
    • Neo4j支持在節點或關系屬性上的索引, 以提高查詢的性能.
    • 可以為具有相同標簽名稱的所有節點的屬性創建索引.

  • 創建索引: 使用create index on來創建索引.

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


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

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


  • 小節總結:

    • 學習了Cypher的基本概念:
      • Cypher是neo4j圖數據的查詢語言, 類似于mysql數據庫的sql語句, 但是它允許對圖形進行富有表現力和有效的查詢和更新.

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

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

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

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

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

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

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

    • delete命令: 刪除節點/關系及其關聯的屬性.
      • 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

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

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

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

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

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

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

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

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

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

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

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

    • 索引index
      • Neo4j支持在節點或關系屬性上的索引, 以提高查詢的性能.
      • 可以為具有相同標簽名稱的所有節點的屬性創建索引.

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

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

3.4 在Python中使用neo4j

  • 學習目標
    • 了解python中neo4j-driver的相關知識.
    • 掌握neo4j中事務概念和操作方法.

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

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

config.py

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

  • 使用事務的演示:
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")
  • 輸出效果:

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


  • 小節總結:

    • 學習了neo4j-driver簡介:
      • neo4j-driver是一個python中的package, 作為python中neo4j的驅動, 幫助我們在python程序中更好的使用圖數據庫.

    • 學習了neo4j-driver的安裝和使用方法.

    • 學習了事務的概念:
      • 如果一組數據庫操作要么全部發生要么一步也不執行,我們稱該組處理步驟為一個事務, 它是數據庫一致性的保證.

    • 學習了如何使用事務來向圖數據庫中寫入數據.

4.1 離線部分簡要分析


  • 學習目標:
    • 了解離線部分的數據流水線以及組成部分.
    • 了解各個組成部分的作用.

  • 離線部分架構圖:


  • 離線部分架構展開圖:


  • 離線部分簡要分析:
    • 根據架構展開圖圖,離線部分可分為兩條數據流水線,分別用于處理結構化數據和非結構化數據. 這里稱它們為結構化數據流水線和非結構化數據流水線.

  • 結構化數據流水線的組成部分:
    • 結構化數據爬蟲: 從網頁上抓取結構化的有關醫學命名實體的內容.
    • 結構化數據的清洗: 對抓取的內容進行過濾和清洗, 以保留需要的部分.
    • 命名實體審核: 對當前命名實體進行審核, 來保證這些實體符合我們的要求.
    • 命名實體寫入數據庫: 將審核后的命名實體寫入數據庫之中, 供在線部分使用.

  • 非結構化數據流水線的組成部分:
    • 非結構化數據爬蟲: 從網頁上抓取非結構化的包含醫學命名實體的文本.
    • 非結構化數據清洗: 對非結構化數據進行過濾和清洗, 以保留需要的部分.
    • 命名實體識別: 使用模型從非結構化文本中獲取命名實體.
    • 命名實體審核: 對當前命名實體進行審核, 來保證這些實體符合我們的要求.
    • 命名實體寫入數據庫: 將審核后的命名實體寫入數據庫之中, 供在線部分使用.

  • 說明:
    • 因為本項目是以AI為核心的項目, 因為結構化與非結構化的數據爬蟲和清洗部分的內容這里不做介紹, 但同學們要知道我們的數據來源.

4.2 結構化數據流水線


  • 學習目標:
    • 了解需要進行命名實體審核的數據內容.
    • 掌握結構化數據流水線中命名實體審核的過程.
    • 掌握結構化數據流水線中命名實體寫入的過程.

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

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

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

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

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

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

  • 命名實體寫入數據庫:

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

  • 將命名實體寫入圖數據庫代碼:
# 引入相關包 import os import fileinput from neo4j import GraphDatabase from config import NEO4J_CONFIGdriver = GraphDatabase.driver( **NEO4J_CONFIG)def _load_data(path):"""description: 將path目錄下的csv文件以指定格式加載到內存:param path: 審核后的疾病對應癥狀的csv文件:return: 返回疾病字典,存儲各個疾病以及與之對應的癥狀的字典{疾病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))# 初始化一個癥狀列表, 它里面是每種疾病對應的癥狀列表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)# 返回指定格式的數據 {疾病:對應癥狀}return dict(zip(disease_list, symptom_list))def write(path):"""description: 將csv數據寫入到neo4j, 并形成圖譜:param path: 數據文件路徑"""# 使用_load_data從持久化文件中加載數據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)
  • 調用:
# 輸入參數path為csv數據所在路徑 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 非結構化數據流水線


  • 學習目標:
    • 了解需要進行命名實體識別的數據內容.
    • 掌握非結構化數據流水線中命名實體識別的過程.
    • 掌握非結構化數據流水線中命名實體審核的過程.
    • 掌握非結構化數據流水線中命名實體寫入的過程.

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

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

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

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

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

  • 進行命名實體審核:
    • 同4.2 結構化數據流水線中的命名實體審核.

  • 命名實體寫入數據庫:
    • 同4.2 結構化數據流水線中的命名實體寫入數據庫.

  • 本章總結:

    • 學習了離線部分的數據流水線以及組成部分.
      • 根據架構展開圖圖,離線部分可分為兩條數據流水線,分別用于處理結構化數據和非結構化數據. 這里稱它們為結構化數據流水線和非結構化數據流水線.

    • 結構化數據流水線的組成部分:
      • 結構化數據爬蟲: 從網頁上抓取結構化的有關醫學命名實體的內容.
      • 結構化數據的清洗: 對抓取的內容進行過濾和清洗, 以保留需要的部分.
      • 命名實體審核: 對當前命名實體進行審核, 來保證這些實體符合我們的要求.
      • 命名實體寫入數據庫: 將審核后的命名實體寫入數據庫之中, 供在線部分使用.

    • 非結構化數據流水線的組成部分:
      • 非結構化數據爬蟲: 從網頁上抓取非結構化的包含醫學命名實體的文本.
      • 非結構化數據清洗: 對非結構化數據進行過濾和清洗, 以保留需要的部分.
      • 命名實體識別: 使用模型從非結構化文本中獲取命名實體.
      • 命名實體審核: 對當前命名實體進行審核, 來保證這些實體符合我們的要求.
      • 命名實體寫入數據庫: 將審核后的命名實體寫入數據庫之中, 供在線部分使用.

    • 學習了需要進行命名實體審核的數據內容.

    • 學習了結構化/非結構化數據流水線中命名實體審核的過程.

    • 學習了結構化/非結構化數據流水線中命名實體寫入的過程.

    • 學習了需要進行命名實體識別的數據內容.

    • 非結構化數據流水線中命名實體識別的過程.

5.1 任務介紹與模型選用

  • 學習目標:
    • 了解命名實體審核任務的相關知識.
    • 了解選用的模型及其原因.

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

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

5.2 訓練數據集

  • 學習目標:
    • 了解訓練數據集的樣式及其相關解釋.
    • 掌握將數據集加載到內存中的過程.

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

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

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

5.3 BERT中文預訓練模型

  • 學習目標:
    • 了解BERT中文預訓練模型的有關知識和作用.
    • 掌握使用BERT中文預訓練模型對句子編碼的過程.

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

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

  • 使用BERT中文預訓練模型對句子編碼:
    bert 預訓練模型地址
import torch import torch.nn as nn# 通過torch.hub(pytorch中專注于遷移學的工具)獲得已經訓練好的bert-base-chinese模型 model = torch.hub.load('huggingface/pytorch-transformers', 'model', 'bert-base-chinese')# 獲得對應的字符映射器, 它將把中文的每個字映射成一個數字 tokenizer = torch.hub.load('huggingface/pytorch-transformers', 'tokenizer', 'bert-base-chinese')def get_bert_encode_for_single(text):"""description: 使用bert-chinese編碼中文文本:param text: 要進行編碼的文本:return: 使用bert編碼后的文本張量表示"""# 首先使用字符映射器對每個漢字進行映射# 這里需要注意, bert的tokenizer映射后會為結果前后添加開始和結束標記即101和102 # 這對于多段文本的編碼是有意義的, 但在我們這里沒有意義, 因此使用[1:-1]對頭和尾進行切片indexed_tokens = tokenizer.encode(text)[1:-1]# 之后將列表結構轉化為tensortokens_tensor = torch.tensor([indexed_tokens])print(tokens_tensor)# 使模型不自動計算梯度with torch.no_grad():# 調用模型獲得隱層輸出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

  • 輸入參數:
text = "你好, 周杰倫"
  • 調用:
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無法下載時,利用迅雷等通過鏈接中 的地址進行下載model.bin config.json vocab.txt并更改名稱
from transformers import BertModel, BertTokenizer

import torch from transformers import BertModel, BertTokenizer# 通過torch.hub(pytorch中專注于遷移學的工具)獲得已經訓練好的bert-base-chinese模型 # model = torch.hub.load('huggingface/pytorch-transformers', 'model', 'bert-base-chinese') # 獲得對應的字符映射器, 它將把中文的每個字映射成一個數字 # 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對中文文本進行編碼:param text: 進行編碼的中文文本:return: 編號后的張量"""# 使用字符映射器對每個漢字進行映射# bert中tokenizer映射后會加入開始和結束標記101,102 采用[1:-1]去除indexed_tokens = tokenizer.encode(text)[1 : -1]# 封裝為tensortokens_tensor = torch.tensor([indexed_tokens])print(tokens_tensor)# 預測部分-不需要求導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])
  • 小節總結:

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

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

    • 學習了使用BERT中文預訓練模型對句子編碼的函數: get_bert_encode_for_single(text)

5.4 構建RNN模型

  • 學習目標:
    • 學習RNN模型的內部結構及計算公式.
    • 掌握RNN模型的實現過程.

  • 傳統RNN的內部結構圖:


  • 結構解釋圖:


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

  • 內部結構過程演示:


  • 根據結構分析得出內部計算公式:


  • 激活函數tanh的作用:
    * 用于幫助調節流經網絡的值, tanh函數將值壓縮在-1和1之間.


  • 構建RNN模型的代碼分析:
class RNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):"""初始化函數中有三個參數,分別是輸入張量最后一維的尺寸大小,隱層張量最后一維的尺寸大小, 輸出張量最后一維的尺寸大小"""super(RNN, self).__init__()# 傳入隱含層尺寸大小self.hidden_size = hidden_size# 構建從輸入到隱含層的線性變化, 這個線性層的輸入尺寸是input_size + hidden_size# 這是因為在循環網絡中, 每次輸入都有兩部分組成,分別是此時刻的輸入xt和上一時刻產生的輸出ht-1.# 這個線性層的輸出尺寸是hidden_sizeself.i2h = nn.Linear(input_size + hidden_size, hidden_size)# 構建從輸入到輸出層的線性變化, 這個線性層的輸入尺寸還是input_size + hidden_size# 這個線性層的輸出尺寸是output_size.self.i2o = nn.Linear(input_size + hidden_size, output_size)# 最后需要對輸出做softmax處理, 獲得結果.self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input, hidden):"""在forward函數中, 參數分別是規定尺寸的輸入張量, 以及規定尺寸的初始化隱層張量"""# 首先使用torch.cat將input與hidden進行張量拼接combined = torch.cat((input, hidden), 1)# 通過輸入層到隱層變換獲得hidden張量hidden = self.i2h(combined)# 通過輸入到輸出層變換獲得output張量output = self.i2o(combined)# 對輸出進行softmax處理output = self.softmax(output)# 返回輸出張量和最后的隱層結果return output, hiddendef initHidden(self):"""隱層初始化函數"""# 將隱層初始化成為一個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

  • 實例化參數:
input_size = 768 hidden_size = 128 n_categories = 2 # ner審核通過或者不通過
  • 輸入參數:
input = torch.rand(1, input_size) hidden = torch.rand(1, hidden_size)
  • 調用:
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]
  • 小節總結:
    • 學習了RNN模型的內部結構及計算公式.
    • 學習并實現了RNN模型的類: class RNN(nn.Module).

5.5 進行模型訓練

  • 學習目標:
    • 了解進行模型訓練的步驟.
    • 掌握模型訓練中每個步驟的實現過程.

  • 進行模型訓練的步驟:
    • 第一步: 構建隨機選取數據函數.
    • 第二步: 構建模型訓練函數.
    • 第三步: 構建模型驗證函數.
    • 第四步: 調用訓練和驗證函數.
    • 第五步: 繪制訓練和驗證的損失和準確率對照曲線.
    • 第六步: 模型保存.

  • 第一步: 構建隨機選取數據函數
import pandas as pd import random from bert_chinese_encode import get_bert_encode_for_single import torch# 讀取數據 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):"""隨機選取數據函數, train_data是訓練集的列表形式數據"""# 從train_data隨機選擇一條數據category, line = random.choice(train_data)# 將里面的文字使用bert進行編碼, 獲取編碼后的tensor類型數據line_tensor = get_bert_encode_for_single(line)# 將分類標簽封裝成tensorcategory_tensor = torch.tensor([int(category)])# 返回四個結果return category, line, category_tensor, line_tensor
  • 代碼位置: /data/doctor_offline/review_model/train.py

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

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

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

  • 輸入參數:
# 假定模型訓練開始時間是10min之前 since = time.time() - 10*60
  • 調用:
period = timeSince(since) print(period)
  • 輸出效果:
10m 0s
  • 調用訓練和驗證函數并打印日志
# 設置迭代次數為50000步 n_iters = 50000# 打印間隔為1000步 plot_every = 1000# 初始化打印間隔中訓練和驗證的損失和準確率 train_current_loss = 0 train_current_acc = 0 valid_current_loss = 0 valid_current_acc = 0# 初始化盛裝每次打印間隔的平均損失和準確率 all_train_losses = [] all_train_acc = [] all_valid_losses = [] all_valid_acc = []# 獲取開始時間戳 start = time.time()# 循環遍歷n_iters次 for iter in range(1, n_iters + 1):# 調用兩次隨機函數分別生成一條訓練和驗證數據category, line, category_tensor, line_tensor = randomTrainingExample(train_data)category_, line_, category_tensor_, line_tensor_ = randomTrainingExample(train_data)# 分別調用訓練和驗證函數, 獲得輸出和損失train_output, train_loss = train(category_tensor, line_tensor)valid_output, valid_loss = valid(category_tensor_, line_tensor_)# 進行訓練損失, 驗證損失,訓練準確率和驗證準確率分別累加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()# 當迭代次數是指定打印間隔的整數倍時if iter % plot_every == 0:# 用剛剛累加的損失和準確率除以間隔步數得到平均值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# 打印迭代步, 耗時, 訓練損失和準確率, 驗證損失和準確率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)# 將結果存入對應的列表中,方便后續制圖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)# 將該間隔的訓練和驗證損失及其準確率歸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
  • 第五步: 繪制訓練和驗證的損失和準確率對照曲線

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

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

  • 訓練和驗證損失對照曲線:


  • 訓練和驗證準確率對照曲線:


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

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

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

  • 小節總結:
    • 學習了進行模型訓練的步驟:
      • 第一步: 構建隨機選取數據函數.
      • 第二步: 構建模型訓練函數.
      • 第三步: 構建模型驗證函數.
      • 第四步: 調用訓練和驗證函數.
      • 第五步: 繪制訓練和驗證的損失和準確率對照曲線.
      • 第六步: 模型保存.

5.6 模型使用

  • 學習目標:
    • 掌握模型預測的實現過程.
    • 掌握模型批量預測的實現過程.

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

  • 輸入參數:
input_line = "點瘀樣尖針性發多"
  • 調用:
result = predict(input_line) print("result:", result)
  • 輸出效果:
result: 0
  • 模型批量預測的實現過程:
def batch_predict(input_path, output_path):"""批量預測函數, 以原始文本(待識別的命名實體組成的文件)輸入路徑和預測過濾后(去除掉非命名實體的文件)的輸出路徑為參數"""# 待識別的命名實體組成的文件是以疾病名稱為csv文件名, # 文件中的每一行是該疾病對應的癥狀命名實體# 讀取路徑下的每一個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()# 使用模型進行預測res = predict(input_line)# 如果結果為1if res:# 說明審核成功, 寫入到輸出csv中fw.write(input_line + "\n")else:pass
  • 代碼位置: /data/doctor_offline/review_model/predict.py

  • 輸入參數:
input_path = "/data/doctor_offline/structured/noreview/" output_path = "/data/doctor_offline/structured/reviewed/"
  • 調用:
batch_predict(input_path, output_path)
  • 輸出效果:
    • 在輸出路徑下生成與輸入路徑等數量的同名csv文件, 內部的癥狀實體是被審核的可用實體.

  • 小節總結:
    • 學習并實現了模型預測的函數: predict(input_line).
    • 學習并實現了模型批量預測的函數: batch_predict(input_path, output_path)

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国产精品入口传媒 | 亚洲一级电影 | 最新av免费在线观看 | 久久精品香蕉 | 色婷婷激情综合 | 久草在线这里只有精品 | 国产精品免费麻豆入口 | 日韩精品在线免费观看 | 高清免费av在线 | 中文字幕亚洲综合久久五月天色无吗'' | 视频在线观看入口黄最新永久免费国产 | 久久艹艹 | 99热99热| 国产中文字幕在线免费观看 | 国产黄色av影视 | av在线收看 | 天天综合天天做 | 五月开心婷婷网 | 黄色av网站在线观看 | 丰满少妇在线观看 | 国产高清在线观看av | 国产免码va在线观看免费 | 在线观看视频你懂得 | av在线收看| 欧美性极品xxxx娇小 | 欧美二区三区91 | av成人在线看 | 麻豆精品在线 | 欧美激情在线网站 | 国产伦精品一区二区三区四区视频 | 五月激情站 | 中文在线免费视频 | 91在线超碰| 涩涩色亚洲一区 | 亚洲精品免费看 | 天天射天天搞 | 99久热在线精品视频成人一区 | 91成人免费视频 | 91看毛片 | 米奇四色影视 | 日本中文字幕久久 | 日韩高清不卡一区二区三区 | 日本在线视频网址 | 婷婷久久五月 | 国产午夜精品免费一区二区三区视频 | 偷拍精品一区二区三区 | 欧美日韩在线视频一区 | 国产另类xxxxhd高清 | www.人人干| 国产精品女同一区二区三区久久夜 | 我要色综合天天 | a电影在线观看 | 天天爽人人爽 | 天天艹天天操 | av电影在线不卡 | 婷婷成人在线 | 久久99热这里只有精品国产 | 久久香蕉电影 | 精品久久久久久国产偷窥 | 亚洲黄色免费网站 | 亚洲国产中文字幕在线观看 | 五月激情丁香婷婷 | 亚洲精品在线观 | 色吊丝在线永久观看最新版本 | 成片人卡1卡2卡3手机免费看 | 五月天电影免费在线观看一区 | 伊人婷婷网 | 中文字幕在线观看网址 | 美女国产精品 | 精品人人爽 | 久久久久久久久久免费视频 | av网站在线观看播放 | 天天干 夜夜操 | 成年人在线视频观看 | 黄色毛片一级 | 伊色综合久久之综合久久 | 色综合久久88 | 国产精品女同一区二区三区久久夜 | 国产亚洲成人精品 | 久久99深爱久久99精品 | 成年美女黄网站色大片免费看 | 麻豆影音先锋 | 中文字幕影片免费在线观看 | 在线精品播放 | 中文av字幕在线观看 | 在线观看的黄色 | 久久丁香网 | 日本三级吹潮在线 | 国产麻豆剧果冻传媒视频播放量 | 91精品久久久久久 | 人人澡人摸人人添学生av | 精品99999| www久草| 婷婷国产一区二区三区 | 高清av免费观看 | av福利在线播放 | 麻豆一级视频 | 操操操天天操 | 精品美女在线视频 | 国产不卡视频 | 国产精品电影一区二区 | 亚洲日韩精品欧美一区二区 | 在线免费日韩 | 五月婷婷丁香六月 | 久久视讯| 五月婷婷综合色拍 | 97视频在线免费播放 | 亚洲黄色小说网址 | 亚洲精品成人 | 91热爆在线观看 | 国产中文字幕在线免费观看 | 黄色影院在线免费观看 | 97综合在线 | 国产麻豆精品久久一二三 | 天天草夜夜 | 黄色三级在线看 | 狠狠操欧美 | 亚洲第一香蕉视频 | 五月综合| 色视频网址 | 日韩高清毛片 | 国产黄色观看 | 在线观看免费国产小视频 | 91热| 色com| 国产精品福利在线 | 亚洲精品小视频 | 国产亚洲情侣一区二区无 | 婷婷草| 欧美日韩高清免费 | 一本一道波多野毛片中文在线 | 欧美一级网站 | av电影免费在线看 | 韩国av三级| 国产网红在线 | 婷婷丁香狠狠爱 | 欧美网址在线观看 | 国产精品久久久久久久久久免费 | 99热最新精品 | 91精选在线 | 国产精品原创 | 黄色毛片观看 | 成人影视免费 | 国产精品麻豆99久久久久久 | 在线观看黄色免费视频 | 精品亚洲视频在线 | 丰满少妇一级 | 亚洲国产高清在线观看视频 | 日韩另类在线 | 黄色三级久久 | www.久久久精品| 精品久久美女 | 亚洲精品xx | 久久免费电影网 | 操操综合网| 久久综合中文色婷婷 | 久久精品伊人 | 欧美最猛性xxxxx(亚洲精品) | 在线观看免费黄视频 | 亚洲最新视频在线播放 | 一级片免费观看视频 | 韩国av三级 | 在线视频精品播放 | 黄色毛片一级片 | 91成人亚洲 | 国产黄色片一级三级 | 91桃色免费观看 | 国产精品久久久久久久电影 | 久久影院一区 | 日韩欧美在线观看一区二区 | 亚洲专区在线播放 | 亚洲精品国产视频 | 国产又粗又硬又长又爽的视频 | 2024国产在线 | 丁香av| 国产一级在线视频 | 成人av地址| av韩国在线 | 日韩精品播放 | 最新日本中文字幕 | 天天干,天天插 | 国产日产亚洲精华av | 亚洲精品乱码久久久久久高潮 | 99久久久久久久久 | 黄在线 | 久久久精品二区 | 亚洲在线视频免费观看 | 99国产在线视频 | 精品99在线| 色婷婷成人网 | 婷婷www | 99色资源| 欧美a级免费视频 | 精品久久久久久亚洲综合网站 | 国产99久久久精品视频 | 国产色在线观看 | 天天综合在线观看 | 国产r级在线观看 | 亚州免费视频 | 亚洲伦理一区 | 81精品国产乱码久久久久久 | 久久久91精品国产 | 国产涩涩在线观看 | 亚洲成a人片在线观看网站口工 | 中文字幕高清免费日韩视频在线 | 久久视频在线 | 久久96国产精品久久99漫画 | 黄色视屏在线免费观看 | 久久综合给合久久狠狠色 | 国产精品不卡在线观看 | 久射网| 亚洲免费公开视频 | 日韩欧美在线影院 | 久久免费99精品久久久久久 | av九九九| 日韩av免费在线看 | 欧美人人 | 欧美成人区 | 韩国中文三级 | 操操操com | 国产精品在线看 | 亚洲va欧美va | 国产精品久久久久久久妇 | 午夜av在线电影 | 超碰在线日韩 | 中文字幕亚洲不卡 | 麻豆视频网址 | 深爱激情婷婷网 | 国产一级一级国产 | 国产91全国探花系列在线播放 | 99热精品国产一区二区在线观看 | 丁香六月久久综合狠狠色 | 日韩美女一级片 | 日韩字幕在线观看 | 午夜久久久久久久 | 欧美 日韩 国产 中文字幕 | a黄色片 | 国产亚洲亚洲 | 一级一片免费看 | 国产精品欧美一区二区三区不卡 | av在线电影网站 | 91.麻豆视频 | 欧美伦理电影一区二区 | 日日操狠狠干 | 亚洲精品99久久久久久 | av在线中文 | 国产欧美精品一区二区三区四区 | 日韩专区中文字幕 | 日批网站免费观看 | 99亚洲国产精品 | 国产va精品免费观看 | 91精品啪 | 国产成人一级电影 | 天天插天天狠天天透 | 在线观看精品一区 | 国内精品久久天天躁人人爽 | 久草线 | 色午夜 | 亚洲精品在线观看不卡 | 亚州国产精品久久久 | 麻豆传媒视频在线 | 在线高清av| 91夫妻自拍 | 免费日韩一区二区三区 | 天天插天天爽 | 91精品国产麻豆 | 日产av在线播放 | 国产精品一区欧美 | 国产色久| 国产高清综合 | 麻豆国产电影 | 精品嫩模福利一区二区蜜臀 | 国产日韩高清在线 | 在线视频 区 | 国产小视频免费在线观看 | 69久久99精品久久久久婷婷 | 久久99免费 | 欧美黄在线 | 三级动图 | 国产99久久精品一区二区永久免费 | 最新免费av在线 | 一区二区欧美在线观看 | 91在线视频 | 久草在线免费看视频 | 日韩成人欧美 | 久久 一区 | 91视频下载 | 精品视频国产一区 | 国产视频欧美视频 | 成人亚洲精品国产www | 国产精品视频在线观看 | 国产精品理论片在线播放 | 深爱婷婷 | 91高清完整版在线观看 | 在线不卡中文字幕播放 | 日韩三级免费观看 | 日韩二区三区在线 | 国产精品久久在线观看 | 日韩免费视频网站 | 亚洲综合色站 | 欧美 日韩 性 | 欧美一级片免费观看 | av一区二区在线观看中文字幕 | 婷婷丁香色 | 国产精品成久久久久三级 | 国产91精品看黄网站 | 天天干天天干天天色 | 日韩一区二区三区在线观看 | 欧美伊人网 | 成人av高清在线观看 | 91精品国产成人 | 中文字幕在线久一本久 | 国产一区二区精品 | 高潮久久久久久 | a视频在线 | 国产日韩中文字幕 | 亚洲专区 国产精品 | 欧美日韩二区在线 | 国产一区免费 | av在线成人 | 国产精品久久久久永久免费观看 | 成人午夜av电影 | 欧美在线视频第一页 | 黄色一级大片免费看 | 狠狠狠的干 | 日韩高清久久 | 亚洲国产操 | 色.www | 日本性xxxxx 亚洲精品午夜久久久 | 91亚洲综合 | 成人一区二区在线观看 | 婷婷综合激情 | 欧美成人视 | 在线观看v片 | 国产美女免费观看 | 四虎国产精品成人免费4hu | 久久艹免费 | www.久久久精品 | 日韩在线观看影院 | 久久久黄色av | 国产亚洲精品久久网站 | 国产成人三级在线 | 国产成人一区在线 | 国产麻豆剧果冻传媒视频播放量 | 国产免费久久 | av免费在线网站 | 中文字幕在线播放视频 | 中文字幕第一页在线 | 亚洲精品国产自产拍在线观看 | 国产精品成久久久久 | 免费网站污 | 国产成人一区二区三区久久精品 | 欧美日韩一区二区三区视频 | 中文字幕在线看视频国产 | 蜜臀av夜夜澡人人爽人人 | 欧美午夜视频在线 | 亚洲精品乱码久久久久久写真 | 国产在线永久 | 黄色一级性片 | 欧美成a人片在线观看久 | 国产精品久久久久久久久久免费看 | 在线观看视频黄色 | 欧美在线视频一区二区三区 | 大胆欧美gogo免费视频一二区 | 亚洲国产激情 | 久久久成人精品 | 91成人免费在线视频 | 日韩a免费 | 国产精品999久久久 久产久精国产品 | 色姑娘综合天天 | 亚洲综合一区二区精品导航 | 国产成人精品a | 亚洲丝袜一区 | 久久不见久久见免费影院 | 亚洲日韩中文字幕在线播放 | 色婷婷综合久久久久中文字幕1 | 成人免费一级片 | 四虎8848免费高清在线观看 | 亚洲欧美激情精品一区二区 | 欧美极品xxx | 免费看亚洲毛片 | 午夜av影院 | 婷婷色综合色 | 日韩免费三级 | 精品嫩模福利一区二区蜜臀 | 国产高清精 | 黄色在线观看免费 | av一区在线 | 国产日产精品一区二区三区四区 | 欧美日韩在线第一页 | 手机看片99 | 免费在线一区二区三区 | 国产精品理论片在线观看 | 婷婷色亚洲 | 在线看成人 | 久久免费视频国产 | 日韩av福利在线 | 国产一区二区午夜 | 婷婷看片 | av在线亚洲天堂 | 精品久久一区 | 欧亚日韩精品一区二区在线 | 国产不卡免费 | 久久一区二区免费视频 | 激情亚洲综合在线 | 色婷婷免费视频 | 99麻豆久久久国产精品免费 | 国产美女视频一区 | 91视频在线看 | 日韩久久久久久久久 | 中文字幕日本在线 | 9999在线观看 | 欧美不卡在线 | 91精品国产九九九久久久亚洲 | 欧美在线视频一区二区三区 | 狠狠干狠狠色 | av在线播放中文字幕 | 日日夜夜狠狠操 | 欧美成人理伦片 | 国产精品一区二区免费在线观看 | 色的网站在线观看 | 91色国产在线 | 国产日韩欧美视频在线观看 | 97色在线视频 | 日韩精品播放 | 亚洲精品看片 | 四虎永久免费在线观看 | 久色网 | 麻豆免费在线视频 | 欧美色精品天天在线观看视频 | 欧美最猛性xxxxx免费 | 久草在线在线精品观看 | 久久草草影视免费网 | 麻豆视频国产 | 日韩电影中文字幕在线 | 久热av| 精品国产一区二区三区在线观看 | 国产男女无遮挡猛进猛出在线观看 | 91大神精品视频在线观看 | 欧美整片sss | 国产1区2区3区在线 亚洲自拍偷拍色图 | 国产美腿白丝袜足在线av | 久久久亚洲成人 | 狠狠狠干狠狠 | 中文字幕二区在线观看 | 精品视频97| 狠狠干电影| 久久久精品一区二区三区 | 97av色 | 丁香婷婷激情国产高清秒播 | 激情欧美一区二区免费视频 | 日日日视频 | 一区免费视频 | www激情久久 | 四虎www.| 亚洲欧美在线视频免费 | 亚洲性xxxx| 天天色.com | 中文字幕日本在线观看 | 三级黄色免费 | 国产精品欧美日韩在线观看 | 97人人艹 | 日本精品久久久久影院 | 国产视频美女 | 色综合久久66 | 亚洲精品在线视频观看 | 日韩视频专区 | 成人av片在线观看 | 人人添人人澡人人澡人人人爽 | 92国产精品久久久久首页 | 99视屏 | 欧美激情视频免费看 | 一区二区三区免费网站 | av中文字幕在线免费观看 | 狠狠色噜噜狠狠狠 | 国产一级视频在线免费观看 | 99精品视频免费全部在线 | 天天色天天操综合网 | 亚洲精品视频中文字幕 | 天天干天天玩天天操 | 草莓视频在线观看免费观看 | 三上悠亚一区二区在线观看 | 啪啪肉肉污av国网站 | 国产字幕在线看 | 国产成人一级 | 天天色天天搞 | 久久兔费看a级 | 91爱爱网址 | 92中文资源在线 | 免费看色的网站 | 97成人在线免费视频 | 五月综合激情婷婷 | 麻豆高清免费国产一区 | 久久综合影院 | 91理论片午午伦夜理片久久 | 99精品99 | 久操中文字幕在线观看 | 人人澡人人草 | 亚洲精品国偷自产在线99热 | 欧美精品国产精品 | 韩国av永久免费 | 二区三区视频 | 99精品视频播放 | 在线日韩亚洲 | 看片一区二区三区 | 欧美日韩高清在线一区 | 欧美一级性 | 99中文在线| 99热精品国产一区二区在线观看 | 99re8这里有精品热视频免费 | 久久久网页 | 一区二区三区免费在线播放 | 国产亚洲精品xxoo | 91精品视频网站 | 久久老司机精品视频 | 视频国产 | 久久久一本精品99久久精品 | 免费亚洲片| 97在线免费观看 | 91亚洲免费| 欧美性性网 | 亚洲精选99| 综合网天天 | 精品久久久久久久久久久久久久久久 | av中文字幕免费在线观看 | 美女免费视频一区二区 | 亚洲欧洲美洲av | 97超碰资源 | 久久99精品久久久久久清纯直播 | 中文字幕在线视频免费播放 | 日韩在线观看视频中文字幕 | 亚洲毛片视频 | 玖玖爱国产在线 | 97视频在线观看播放 | 中文字幕色在线视频 | 最近中文字幕视频完整版 | 久久99精品久久久久久秒播蜜臀 | 亚洲黄色在线免费观看 | 免费人成网ww44kk44 | 毛片在线播放网址 | 一区二区三区四区久久 | 色噜噜日韩精品一区二区三区视频 | .国产精品成人自产拍在线观看6 | 欧美日韩精品在线播放 | 91视频传媒 | 成年人免费看的视频 | 999国内精品永久免费视频 | 日本一区二区不卡高清 | 一区二区三区免费在线 | 国产精品mm | 最近中文字幕完整视频高清1 | 91视频久久 | 日韩首页 | 日韩欧美在线观看一区二区三区 | 国产黄色片久久久 | 日日干干夜夜 | 国产成人三级在线 | 人人干人人上 | 丁香午夜 | 久久国产精品久久w女人spa | 黄色电影小说 | 亚洲精品美女久久 | 亚洲国产精品一区二区久久,亚洲午夜 | 中文在线中文a | 久久综合色8888 | 精品久久久久久久久久久久久久久久久久 | a视频在线 | 69视频永久免费观看 | 中文字幕人成乱码在线观看 | 美女网站色免费 | 91av原创| 日韩欧美视频在线播放 | 在线观看的av网站 | 97视频免费在线看 | 久久久www成人免费毛片 | 久久超碰97 | 亚洲精品乱码久久久久久蜜桃欧美 | 97成人在线观看 | 日本99精品 | 久久这里只精品 | 久久久91精品国产一区二区精品 | 久久精品99国产精品 | 国产一区福利 | 日韩av影视| 国产成人一区二区三区 | 天天搞天天 | 蜜臀久久99精品久久久久久网站 | 久久久精品二区 | 成人午夜精品福利免费 | 久久综合中文色婷婷 | 久久99免费视频 | 久久视频精品在线观看 | 黄色最新网址 | 亚洲成人资源 | 久久黄色影视 | 久久视频6 | 午夜精品成人一区二区三区 | 操久在线 | 特级xxxxx欧美 | 国产美女永久免费 | 日韩av电影一区 | 超碰97在线资源站 | 91大神精品视频在线观看 | 一级黄毛片 | 婷婷在线资源 | 亚洲国产最新 | 日韩美一区二区三区 | 免费看高清毛片 | 婷婷丁香狠狠爱 | 高清国产在线一区 | 国产高清在线不卡 | 视频国产| 亚洲精品国产自产拍在线观看 | 一区二区免费不卡在线 | 成年人黄色免费网站 | 日韩在线电影一区 | 免费成人av在线看 | 亚洲 欧美 日韩 综合 | 日日夜夜亚洲 | 麻豆视频入口 | 成人久久精品 | 国产精品孕妇 | 久久成人欧美 | 国产日产高清dvd碟片 | 中文 一区二区 | 日韩av快播电影网 | 国产h片在线观看 | 91精品视频一区 | www.久草.com| 在线免费观看黄色av | 欧美二区三区91 | 91精品在线观看入口 | 午夜 在线 | 日产av在线播放 | 久久激情五月丁香伊人 | www.777奇米| 亚洲精品系列 | 精品国产一区二区三区久久 | 激情xxxx | 久久a级片 | 懂色av一区二区在线播放 | 国产日韩精品一区二区在线观看播放 | 亚洲国产精品500在线观看 | 国产成人精品在线观看 | 麻豆视频免费版 | 精品亚洲免费 | 国产精品久久艹 | av免费观看网站 | 精品国产日本 | 日本黄色免费在线 | 亚洲精品99久久久久久 | av电影中文字幕在线观看 | 欧美了一区在线观看 | 中文字幕免费高清在线观看 | 欧美日韩国产免费视频 | 一本一道波多野毛片中文在线 | 黄色免费电影网站 | 亚洲jizzjizz日本少妇 | 久久伦理电影网 | 成人h电影在线观看 | 97人人模人人爽人人少妇 | 久久久久久久久久久久久国产精品 | 免费美女久久99 | 在线超碰av| 久久96国产精品久久99漫画 | 黄色一级免费网站 | 91在线免费播放视频 | 国色综合| 久久久国产精品网站 | sesese图片 | 99视频在线精品国自产拍免费观看 | 91精品久久香蕉国产线看观看 | 亚洲精品中文字幕视频 | 国产99视频在线观看 | 成人在线视频在线观看 | 久久久久久久久久网站 | 国产精品99久久久久久有的能看 | 亚洲在线日韩 | 日韩av午夜在线观看 | 国产在线综合视频 | 国产不卡在线 | 日韩免费看片 | 亚洲电影网站 | 精品久久久一区二区 | 久久精品视频观看 | 国产精品久久久久久高潮 | 狠狠色噜噜狠狠 | 国产成人久久精品77777综合 | 国产福利资源 | 91男人影院 | 国产高清亚洲 | 狠狠干夜夜爽 | 久草电影免费在线观看 | 欧美日韩一区二区免费在线观看 | 国产一级精品绿帽视频 | 日本成人免费在线观看 | 97电影手机 | 天堂久色| 国产在线 一区二区三区 | 五月天激情电影 | 免费黄色特级片 | 91成人午夜 | 日韩午夜在线观看 | 日韩黄在线观看 | 色婷婷视频网 | 亚洲精品国偷拍自产在线观看 | 一区二区三区日韩在线观看 | 成人啪啪18免费游戏链接 | 亚洲高清资源 | 欧美一区二区三区四区夜夜大片 | 亚洲成av人影院 | 久久看免费视频 | 日韩欧美在线一区 | 欧美日一级片 | 96av麻豆蜜桃一区二区 | 麻豆成人网 | 97超视频免费观看 | 在线天堂中文在线资源网 | 欧美日韩性 | 国产中年夫妇高潮精品视频 | 亚洲精品国产麻豆 | 色一级片 | 久久久wwww | 国产99一区二区 | 亚洲 欧洲av| 亚洲综合激情五月 | 亚洲精品国偷拍自产在线观看蜜桃 | 激情欧美日韩一区二区 | 人人澡人人模 | 精品国产aⅴ麻豆 | 香蕉在线观看 | 亚洲综合网 | 色综合国产 | 91少妇精拍在线播放 | 成人永久视频 | 在线观看国产永久免费视频 | 97色在线| 手机看片1042 | 开心色激情网 | 91豆花在线 | 国产在线观看免 | 天天干天天拍天天操 | 久久五月激情 | 日韩黄色网络 | 99精品视频在线播放观看 | 色婷婷av一区二 | 日韩成人免费在线 | 黄污在线看 | 久久久一本精品99久久精品 | 中文在线中文资源 | 色婷婷狠狠干 | 东方av在线免费观看 | 中文字幕在线影院 | 插久久| 99久久久久免费精品国产 | 久久黄页| 天天干天天射天天操 | 一级黄毛片 | 国产日产av | 蜜臀av性久久久久蜜臀aⅴ四虎 | 亚欧日韩av | 欧美人zozo| 四虎亚洲精品 | 97人人爽 | 国产黄网在线 | 超碰97久久 | 久久蜜臀一区二区三区av | 日韩中文在线播放 | 亚洲精品国产精品国自产观看浪潮 | 亚洲国产剧情av | 国产精品大尺度 | 五月天激情电影 | 亚洲视频一级 | 国产成人免费观看久久久 | 黄色特级毛片 | 久久久久二区 | 国产一区二区精品久久91 | 久久国产精品99久久久久久进口 | 青草视频网| 在线一二区 | www.亚洲| 成人97视频| 国产精品国产毛片 | av福利在线导航 | 久久只精品99品免费久23小说 | 91色偷偷 | 日韩欧美v | 国产精品久久久久久五月尺 | 免费久久视频 | 色婷婷播放 | 亚洲日本一区二区在线 | 亚洲无人区小视频 | 国产啊v在线观看 | 免费黄色av. | bbb搡bbb爽爽爽| 国产精品国产三级国产不产一地 | 日日夜夜免费精品 | 精品国产成人av在线免 | 午夜 久久 tv | 性色av免费观看 | 国产一级二级在线观看 | 丁香六月婷婷综合 | 久久国产经典视频 | 亚洲国内精品视频 | 99久久精品久久久久久清纯 | 日本精品一区二区在线观看 | 在线看不卡av | 国产999视频在线观看 | 粉嫩av一区二区三区入口 | 亚洲精品久久久久999中文字幕 | 久久综合狠狠综合久久狠狠色综合 | 麻豆一二| 99精品国产一区二区 | 日韩在线免费小视频 | 国产剧情av在线播放 | av黄色影院| 欧美日韩国产综合网 | 999色视频 | 国产日韩视频在线观看 | 免费aa大片 | 亚洲精品久久激情国产片 | 99精品欧美一区二区三区 | 欧美十八 | 香蕉色综合 | 国产午夜精品久久久久久久久久 | 国产理论免费 | av手机版 | av成人在线观看 | 亚洲精选在线观看 | 色婷婷免费 | 91人网站| 91av在线免费看 | 日韩精品久久久久久久电影竹菊 | 天天操网站| 日日干天天爽 | 成人一区二区三区中文字幕 | 在线综合色 | 爱爱av网站 | 一区二区三区视频网站 | 精品人人人人 | 人人射人人爱 | 在线免费视频 你懂得 | 欧美色图88 | 国产成人精品久久二区二区 | 青青河边草免费观看完整版高清 | 超碰夜夜 | 久久久受www免费人成 | 亚洲欧美色婷婷 | 天天爱天天射 | 成人在线一区二区三区 | 久艹视频在线免费观看 | 婷婷色在线 | 色偷偷97 | 日日射天天射 | 91黄色成人| 综合网av | 日本黄区免费视频观看 | 黄色成人毛片 | 成年人视频在线免费观看 | 激情伊人五月天久久综合 | 日韩精品一区二区三区不卡 | 很污的网站 | 日日夜夜国产 | 国产日本在线 | 欧美亚洲精品在线观看 | 日韩av快播电影网 | 免费看污污视频的网站 | 在线看污网站 | 久久婷婷网 | 91精品在线观看入口 | 天天摸夜夜添 | 亚洲国产精品传媒在线观看 | 亚洲成a人片77777潘金莲 | 国产精品毛片久久久 | 日韩中文字幕免费看 | 成人午夜剧场在线观看 | 伊人夜夜 | 日韩av电影一区 | 97在线视频观看 | 视频在线观看91 | 国产免费观看高清完整版 | 亚洲欧美日韩精品一区二区 | 免费看片亚洲 | 色网站免费在线观看 | 91中文字幕在线观看 | 日韩精品一区二区三区在线播放 | 在线之家免费在线观看电影 | 久久久久免费精品 | 五月天婷婷视频 | 国产精品99蜜臀久久不卡二区 | 丁香久久 | 日韩中文幕 | 国产精品一区二区三区四区在线观看 | 亚洲国产成人高清精品 | av 一区二区三区 | 国产精品一区二区精品视频免费看 | www.天天色.com | 欧美日韩国产精品一区二区亚洲 | 蜜臀久久99精品久久久无需会员 | 中文字幕日韩一区二区三区不卡 | 免费黄色av电影 | 中文字幕在线视频精品 | 九色91在线 | 全久久久久久久久久久电影 | 99久久一区 | 一区二区三区免费在线观看视频 | 最近更新好看的中文字幕 | 91在线porny国产在线看 | 日韩激情综合 | 国产高清视频在线免费观看 | 久久综合久久伊人 | 亚洲爱爱视频 | 亚洲国产精品一区二区久久,亚洲午夜 | 免费看的黄色网 | 天天看天天干天天操 | 久久久久久久久久毛片 | 欧美一区二区视频97 | 丁香六月久久综合狠狠色 | 黄色小网站在线观看 | 在线观看日韩专区 | 国产美女搞久久 | 波多野结衣视频一区二区 | 久久精品视频日本 | 911久久香蕉国产线看观看 | 超碰在线公开免费 | 免费观看www小视频的软件 | 五月婷婷久草 | 久久精品一二区 | 人人盈棋牌 | 日日草av| 国产美女网站视频 | 在线国产一区 | 超碰97人人干 | 精品久久久久久一区二区里番 | 日韩美女高潮 | 欧美伦理电影一区二区 | se视频网址| 高潮久久久 | 欧美日韩亚洲在线观看 | 99久久婷婷国产综合亚洲 | 国产精品一区二区在线 | 国产精品久久伊人 | 亚洲一级国产 | 免费在线观看av | 高清一区二区三区 | 一区 在线 影院 | 九九免费观看视频 | 日韩精品免费在线观看视频 | 人人爱人人爽 | 成人午夜网址 | 久草在线视频首页 | 天天操天天射天天舔 | 在线免费观看视频一区二区三区 | 91在线看黄 | 日韩中文字幕亚洲一区二区va在线 | www.人人草| 一级黄色片在线观看 | 久久这里只有精品视频首页 | 五月激情婷婷丁香 | 色香蕉在线| 免费成人在线观看 | 日韩精品一区不卡 | 国产精品色婷婷视频 | 三级黄色免费片 | 国产三级久久久 | 国产精品美女久久久久久久网站 | 国产高清视频免费观看 | aav在线| 成人毛片一区二区三区 | 久草视频视频在线播放 | 在线视频1卡二卡三卡 | 中文字幕 国产 一区 | 免费观看高清 | 亚洲精品久久久久中文字幕二区 | 亚洲精品国产精品国自产 | 在线 你懂| 成年人国产视频 | 99999精品视频 | 9幺看片 | 国产精品免费观看网站 | 人人网人人爽 | 超级碰99| 国产色视频网站2 | 精品久久久久国产免费第一页 | 成年人免费在线 | 亚洲涩涩网站 | 久久国产精品免费一区 | 狂野欧美激情性xxxx | 免费看av片网站 | 99精品黄色| 亚洲精品视频在线播放 | 亚洲欧洲国产精品 | 国产手机免费视频 | 国产精品乱码久久 | 国产精品11 | 亚洲国产成人精品在线观看 | 精品日韩在线 | 成人av一区二区兰花在线播放 |