Tech

Financial AI와 지식그래프(Knowledge Graph) 구축 및 확장

Financial AI와 지식그래프(Knowledge Graph) 구축 및 확장
Min hyung So
Nov 4, 2022
“LG, 배터리 매출 역대 최대”라는 문장에서 LG는 ‘LG전자’일까요 아니면 ‘LG에너지솔루션’일까요? ‘삼성전자’와 ‘삼성전기’는 얼마나 유사한 기업일까요?

이러한 문제를 해결하기 위해 에이셀은 머신러닝과 자연어처리기술을 통해 딥러닝에 활용할 지식그래프(Knowledge Graph, KG)를 자체적으로 보유, 고도화하고 있습니다. 이번 포스트에서는 지식그래프(KG)를 구축하는 방법과 이를 확장해나가는 과정을 공유해보려 합니다.

1. Knowledge Graph, 지식그래프의 기본 개념

지식 그래프란 인간의 뇌가 지식을 축적하는 방식과 유사하게 대용량의 데이터를 아래의 그림처럼 그래프 형식으로 의미있게 연결하여 지식 정보를 저장하는 방법입니다. 지식 그래프를 이용하면 유사한 특성을 가진 데이터들을 쉽게 찾을 수 있을 뿐만 아니라 인공지능과 머신러닝을 위한 지식연료로 사용해 더욱 똑똑한 모델을 만들 수 있습니다. 에이셀이 어떻게 공공/오픈데이터를 활용하여 지식 그래프를 구축하고, 이를 확장시켜 나가는지에 대해 아래에서 다뤄보겠습니다.

Finance 지식그래프 예시

<읽기 전에 알면 좋을 용어>

  • Semantic Web : 시멘틱 웹은 인터넷 상에 있는 모든 데이터(관계를 추론할 수 있는 모든 데이터)를 기계가 읽을 수 있게 하는 프레임워크 및 기술입니다. RDF(Resource Description Framework)를 활용한 온톨로지 기술이 주를 이루고 있습니다.
  • RDF : RDF(Resource Description Framework)는 메타데이터를 기술하여 의미를 표현하기 위한 수단이며, 시멘틱 웹과 결합되어 많이 사용되고 있습니다. RDF는 <에어컨, 가격, 150만원>처럼 < Resource(대상), Property(속성), Value(값) >과 같은 Triple 형식으로 구성됩니다.
  • Ontology : 시멘틱 웹의 핵심 기술인 온톨로지는 특정 지식과 관련된 용어 및 용어 사이의 관계를 정의하고 있는 사전의 일종입니다. 객체와 관련된 정보를 온톨로지에 명시하면, 시멘틱 웹의 지식 식별 및 추론이 가능해집니다.

2. 에이셀 데이터로 Financial AI를 위한 지식그래프 구축하기

Finance 지식그래프는 에이셀이 자체적으로 보유하고 있는 데이터를 활용하여 Semantic Web RDF 형식으로 구축하였습니다. 이렇게 지식그래프 문법 형식을 구축해놓으면, 웹상에 있는 데이터를 지식그래프 온톨로지 형식에 맞는 정형화된 데이터로 생성 및 변환할 수 있습니다.

(1) 지식그래프 문법 형식 구축

에이셀이 보유한 데이터는 기업 형태나 관련 기업 및 인물 등에 대한 정보로 구성되어 있습니다. 이 데이터들에 적용할 수 있도록 Semantic Web RDF 표준 형식에 따라 지식그래프의 문법 형식을 구축합니다. 지식그래프 문법 형식을 구축하기 위한 RDF 표준 문법은 아래의 링크를 참고할 수 있습니다.

https://medium.com/r/?url=https%3A%2F%2Fwww.w3.org%2FTR%2Frdf-syntax-grammar%2F

이제 기존 서비스 운영에 사용하는 에이셀 데이터를 가져옵니다. 에이셀 데이터는 RDB 형식으로 저장되어 있습니다. 각 테이블에 대한 정보를 IRI(Internationalized Resource Identifier) 인스턴스로 만들어 그래프에 추가합니다.

(2) RDB 데이터를 (Subject, Predicate, Object) 형태의 정형화된 triple로 변환

RDF 문법 형식으로 지식그래프를 구축한 결과물은 .owl 온톨로지 형식으로 저장됩니다. 이 결과물의 온톨로지 형식에 맞게 XML, RDB로부터 입력된 데이터를 triple로 변환할 수 있습니다.

에이셀의 데이터는 지식그래프처럼 정형화된 형식의 데이터가 아니기 때문에, 구축해놓은 지식그래프 온톨로지에 따라 직접 데이터를 저장 및 추가하지 못합니다. 그렇기 때문에 모든 RDB 데이터를 (Subject, Predicate, Object) 형태의 triple로 생성 및 변환합니다. 이 때 추가적으로 reasoning 절차를 거쳐 지식그래프 온톨로지의 일관성을 확인하고 새로운 사실을 추론하여 추가로 데이터를 확보해줍니다.

(3) 그래프 DB에 지식그래프 저장

[
  {
    "metadata": {
      "id": "2d6fea35-f68e-461d-9b7b-5cd05be99451",
      "publisherId": "njpwerner.autodocstring",
      "publisherDisplayName": "njpwerner"
    },
    "name": "autodocstring",
    "publisher": "njpwerner",
    "version": "0.6.1"
  },
  {
    "metadata": {
      "id": "ac5787df-9b2d-441c-abf0-977d62bc66f0",
      "publisherId": "amazonwebservices.aws-toolkit-vscode",
      "publisherDisplayName": "amazonwebservices"
    },
    "name": "aws-toolkit-vscode",
    "publisher": "amazonwebservices",
    "version": "1.60.0"
  },
  {
    "metadata": {
      "id": "e337c67b-55c2-4fef-8949-eb260e7fb7fd",
      "publisherId": "Shan.code-settings-sync",
      "publisherDisplayName": "Shan"
    },
    "name": "code-settings-sync",
    "publisher": "Shan",
    "version": "3.4.3"
  },
  {
    "metadata": {
      "id": "438221f8-1107-4ccd-a6fe-f3b7fe0856b7",
      "publisherId": "mhutchie.git-graph",
      "publisherDisplayName": "mhutchie"
    },
    "name": "git-graph",
    "publisher": "mhutchie",
    "version": "1.30.0"
  },
  {
    "metadata": {
      "id": "9fa2a00e-3bfa-4c2a-abc4-a865bb2b5cf3",
      "publisherId": "VisualStudioExptTeam.intellicode-api-usage-examples",
      "publisherDisplayName": "VisualStudioExptTeam"
    },
    "name": "intellicode-api-usage-examples",
    "publisher": "VisualStudioExptTeam",
    "version": "0.2.6"
  },
  {
    "metadata": {
      "id": "4ad0ce32-ff3f-49f0-83b5-93e5dc00cfff",
      "publisherId": "ms-python.isort",
      "publisherDisplayName": "ms-python"
    },
    "name": "isort",
    "publisher": "ms-python",
    "version": "2022.8.0"
  },
  {
    "metadata": {
      "id": "c941a679-d500-46a8-b2a9-208063125901",
      "publisherId": "wholroyd.jinja",
      "publisherDisplayName": "wholroyd"
    },
    "name": "jinja",
    "publisher": "wholroyd",
    "version": "0.0.8"
  },
  {
    "metadata": {
      "id": "6c2f1801-1e7f-45b2-9b5c-7782f1e076e8",
      "publisherId": "ms-toolsai.jupyter",
      "publisherDisplayName": "ms-toolsai"
    },
    "name": "jupyter",
    "publisher": "ms-toolsai",
    "version": "2022.11.1003412109"
  },
  {
    "metadata": {
      "id": "9f6dc8db-620c-4844-b8c5-e74914f1be27",
      "publisherId": "ms-toolsai.jupyter-keymap",
      "publisherDisplayName": "ms-toolsai"
    },
    "name": "jupyter-keymap",
    "publisher": "ms-toolsai",
    "version": "1.0.0"
  },
  {
    "metadata": {
      "id": "b15c72f8-d5fe-421a-a4f7-27ed9f6addbf",
      "publisherId": "ms-toolsai.jupyter-renderers",
      "publisherDisplayName": "ms-toolsai"
    },
    "name": "jupyter-renderers",
    "publisher": "ms-toolsai",
    "version": "1.0.12"
  },
  {
    "metadata": {
      "id": "f1f59ae4-9318-4f3c-a9b5-81b2eaa5f8a5",
      "publisherId": "ms-python.python",
      "publisherDisplayName": "ms-python"
    },
    "name": "python",
    "publisher": "ms-python",
    "version": "2022.20.1"
  },
  {
    "metadata": {
      "id": "19e1cdbe-42df-443e-89c0-bfecc7204b1d",
      "publisherId": "tht13.python",
      "publisherDisplayName": "tht13"
    },
    "name": "python",
    "publisher": "tht13",
    "version": "0.2.3"
  },
  {
    "metadata": {
      "id": "0c9f60fd-5588-42f7-9176-e80c3ae111ec",
      "publisherId": "donjayamanne.python-environment-manager",
      "publisherDisplayName": "donjayamanne"
    },
    "name": "python-environment-manager",
    "publisher": "donjayamanne",
    "version": "1.0.4"
  },
  {
    "metadata": {
      "id": "f5188937-53e0-45bb-a16d-61231003fa3b",
      "publisherId": "donjayamanne.python-extension-pack",
      "publisherDisplayName": "donjayamanne"
    },
    "name": "python-extension-pack",
    "publisher": "donjayamanne",
    "version": "1.7.0"
  },
  {
    "metadata": {
      "id": "93ce222b-5f6f-49b7-9ab1-a0463c6238df",
      "publisherId": "ms-vscode-remote.remote-containers",
      "publisherDisplayName": "ms-vscode-remote"
    },
    "name": "remote-containers",
    "publisher": "ms-vscode-remote",
    "version": "0.266.1"
  },
  {
    "metadata": {
      "id": "11858313-52cc-4e57-b3e4-d7b65281e34b",
      "publisherId": "ms-vscode.remote-explorer",
      "publisherDisplayName": "ms-vscode"
    },
    "name": "remote-explorer",
    "publisher": "ms-vscode",
    "version": "0.0.3"
  },
  {
    "metadata": {
      "id": "607fd052-be03-4363-b657-2bd62b83d28a",
      "publisherId": "ms-vscode-remote.remote-ssh",
      "publisherDisplayName": "ms-vscode-remote"
    },
    "name": "remote-ssh",
    "publisher": "ms-vscode-remote",
    "version": "0.94.0"
  },
  {
    "metadata": {
      "id": "bfeaf631-bcff-4908-93ed-fda4ef9a0c5c",
      "publisherId": "ms-vscode-remote.remote-ssh-edit",
      "publisherDisplayName": "ms-vscode-remote"
    },
    "name": "remote-ssh-edit",
    "publisher": "ms-vscode-remote",
    "version": "0.84.0"
  },
  {
    "metadata": {
      "id": "f0c5397b-d357-4197-99f0-cb4202f22818",
      "publisherId": "ms-vscode-remote.remote-wsl",
      "publisherDisplayName": "ms-vscode-remote"
    },
    "name": "remote-wsl",
    "publisher": "ms-vscode-remote",
    "version": "0.72.0"
  },
  {
    "metadata": {
      "id": "f3cbfb84-b1e1-40ff-b70f-877253461260",
      "publisherId": "KevinRose.vsc-python-indent",
      "publisherDisplayName": "KevinRose"
    },
    "name": "vsc-python-indent",
    "publisher": "KevinRose",
    "version": "1.18.0"
  },
  {
    "metadata": {
      "id": "4b41a5a8-170e-4156-b2c0-10efb270abbc",
      "publisherId": "batisteo.vscode-django",
      "publisherDisplayName": "batisteo"
    },
    "name": "vscode-django",
    "publisher": "batisteo",
    "version": "1.10.0"
  },
  {
    "metadata": {
      "id": "ab4fb32a-befb-4102-adf9-1652d0cd6a5e",
      "publisherId": "ms-toolsai.vscode-jupyter-cell-tags",
      "publisherDisplayName": "ms-toolsai"
    },
    "name": "vscode-jupyter-cell-tags",
    "publisher": "ms-toolsai",
    "version": "0.1.6"
  },
  {
    "metadata": {
      "id": "e153ca70-b543-4865-b4c5-b31d34185948",
      "publisherId": "ms-toolsai.vscode-jupyter-slideshow",
      "publisherDisplayName": "ms-toolsai"
    },
    "name": "vscode-jupyter-slideshow",
    "publisher": "ms-toolsai",
    "version": "0.1.5"
  },
  {
    "metadata": {
      "id": "364d2426-116a-433a-a5d8-a5098dc3afbd",
      "publisherId": "ms-python.vscode-pylance",
      "publisherDisplayName": "ms-python"
    },
    "name": "vscode-pylance",
    "publisher": "ms-python",
    "version": "2022.12.20"
  },
  {
    "metadata": {
      "id": "23d72dfc-8dd1-4e30-926e-8783b4378f13",
      "publisherId": "ms-vscode-remote.vscode-remote-extensionpack",
      "publisherDisplayName": "ms-vscode-remote"
    },
    "name": "vscode-remote-extensionpack",
    "publisher": "ms-vscode-remote",
    "version": "0.23.0"
  },
  {
    "metadata": {
      "id": "876e8f93-74d0-4f4f-91b7-34a09f19f444",
      "publisherId": "VisualStudioExptTeam.vscodeintellicode",
      "publisherDisplayName": "VisualStudioExptTeam"
    },
    "name": "vscodeintellicode",
    "publisher": "VisualStudioExptTeam",
    "version": "1.2.29"
  }
]

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: 현재 파일",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "justMyCode": true,
            "args": ["./rsc/kowiki-20221120-pages-articles-multistream6.xml", "./rsc/parsed_infobox_20221120.json"]
        }
    ]
}

{
    "[CLS]": 0,
    "[SEP]": 1,
    "[PAD]": 2,
    "[MASK]": 3,
    "O": 4,
    "DAT-B": 5,
    "DAT-I": 6,
    "ORG-B": 7,
    "ORG-I": 8,
    "DUR-B": 9,
    "DUR-I": 10,
    "LOC-B": 11,
    "LOC-I": 12,
    "PER-B": 13,
    "PER-I": 14,
    "NOH-B": 15,
    "NOH-I": 16,
    "MNY-B": 17,
    "MNY-I": 18,
    "POH-B": 19,
    "POH-I": 20,
    "PNT-B": 21,
    "PNT-I": 22,
    "TIM-B": 23,
    "TIM-I": 24
}

지식그래프 문법 형식에 따라 생성한 지식그래프를 ntriples 형식의 파일로 저장합니다. 여기서 n-triples란 RDF 그래프를 위해 여러 줄의 triple 데이터를 저장 및 전송하는 format을 말합니다. 이렇게 변환된 ntriples 파일은 그 자체로 지식그래프의 역할을 수행합니다. 그렇기 때문에 RDF를 지원하는 AWS Neptune과 같은 그래프 DB에 정보를 저장하여 활용할 수 있습니다.

3. Wikipedia를 활용하여 지식그래프 확장하기

앞에서 구축한 지식그래프는 Finance Domain에 국한된 지식그래프입니다. 그렇기 때문에 Wikipedia를 활용하여 ‘Finance 지식그래프에서 찾을 수 없는 정보’를 지식그래프에 추가해준다면, 지식그래프 내의 기업들은 일반적 상식과도 연결될 수 있습니다. 이렇게 확장된 지식그래프를 활용한 검색시스템은 그렇지 않은 검색 시스템보다 더 좋은 검색 결과를 보여줄 수 있습니다. 저희는 아래와 같은 과정을 거쳐 지식그래프를 확장시켰습니다.

(1) Wikipedia에서 제공하는 한국어 덤프 데이터를 다운

위의 사이트에서 원하는 달을 선택하여, pages-articles-multistream.xml.bz2 파일을 다운로드 받습니다. 이 파일에는 일반 문서의 최신 버전만이 묶여 있고, 전체 편집 역사는 들어있지 않습니다. 대부분의 이용자는 이 파일을 이용하면 됩니다.

(2) Dbpedia에서 제공하는 Wikipedia의 온톨로지 양식을 다운

Dbpedia에서는 Wikipedia의 온톨로지 양식(mapping table)을 공유하고 있습니다. 이를 다운로드 받습니다. 또한, 한국어 Dbpedia에서 제공하는 온톨로지의 매핑 정보를 수집하여, 위에서 다운로드한 온톨로지에 추가해줍니다.

(3) Wikipedia 덤프에서 관계, 속성정보 수집

저희가 Wikipedia에서 온톨로지 데이터를 수집한 방식은 총 5가지입니다.

  • 한국어 Wikipedia 덤프데이터에서 표제어 문서에서 Infobox를 먼저 파싱합니다. 각 검색 표제어마다 Infobox가 존재합니다. Infobox는 표제어에 대한 관계, 속성정보를 포함하는 데이터입니다. 이는 Triple 형태로 뽑기에 간단하면서 적합한 데이터입니다.
  • Wikipedia 본문 내용 중에서 다른 페이지에서 해당 페이지를 링킹한 경우, 이러한 단어들 역시 같은 정보라는 사실을 추가합니다.
  • Wikipedia 본문의 최하단을 보면 표제어가 가진 분류정보와 멘션된 외부 링크들의 정보들을 수집할 수 있습니다. 이 역시 파싱해서 지식그래프에 추가해줍니다.
  • Wikipedia에는 아래와 같은 동음이의어 문서가 존재합니다. 이런 페이지 문서도 수집하여, 두 표제어가 동음이의어라는 정보를 지식그래프에 추가해줍니다.
Wikipedia의 동음이의어 문서
Wikipedia의 동음이의어 문서

  • 또한, Wikipedia의 넘겨주기 문서도 추가해줘서 넘겨주는 표제어와 넘겨받는 표제어가 같은 단어라는 정보 역시 추가해줍니다.

이렇게 5가지 방식으로 모은 데이터들은 정규화하여 문장부호나 오탈자를 체크해주고, (2)에서 얻은 Dbpedia 온톨로지를 활용하여 중복을 제거하며, 양식에 맞도록 데이터를 재정리해줍니다. 위의 과정을 거치면서 저희는 표제어들 간의 정보를 추출하여, 일반적인 상식에 대한 지식그래프를 구축할 수 있습니다.

(4) Finance 지식그래프에 Wiki 지식그래프를 연결하여 지식그래프 확장

2에서 생성한 Finance 지식그래프는 기업에 대한 내용이며, 3에서 생성하는 Wiki 지식그래프는 일반적인 지식에 관한 지식그래프입니다. 이 둘을 적절하게 연결해주어야 지식그래프가 확장되어 기업에 대한 지식그래프를 더욱 풍성하게 해줄 수 있습니다. 우리는 동일한 객체에 대해 자동, 수동 두 가지 방법을 통한 연결을 수행하여 2와 3을 연결한 지식그래프를 생성하였습니다.

  • 자동연결

Wikipedia의 표제어 중에서 상장기업에 해당하면서 주식코드를 가지며, 에이셀이 구축한 온톨로지 데이터에도 이미 존재하고 있는 경우에는 자동연결이 진행됩니다. 위키 페이지의 Infobox에서 시장정보를 찾고, 주식코드를 뽑습니다. 이를 동일한 주식코드를 가지는 에이셀의 기업을 찾아, 이 두 객체를 같은 기업으로 표현해줍니다. 그러면, 두 기업에 대한 지식그래프가 결합되어 하나의 데이터가 됩니다.

자동연결의 예시

  • 직접연결

Wikipedia의 표제어가 기업에 해당하지만 비상장기업이거나 주식코드가 없어서, 에이셀의 기업과 연결할 수 없는 경우에 해당합니다. 이러한 경우에는 위키 데이터와 기업 간의 관계를 관리자가 직접 체크해서, 두 기업이 일치하는지 확인하고 연결(Linking)정보를 구축합니다. 그 결과, 아래의 그림과 같이 위키의 표제어인 기업명과 에이셀의 기업명이 주식종목코드를 통해 연결되었습니다.

직접연결의 예시

  • 연결 결과

두 지식그래프를 연결한 결과 아래와 같이 기업명이 aicel:~~으로 변경되어서 표현됩니다. 에이셀의 온톨로지에 따라서 기업은 모회사가 어느 회사인지, 위키 정보로 알 수 있는 회사의 위치 정보나 기업이 속한 그룹이 어떻게 되는지에 대해서 표현됩니다. Dbpedia에서 얻은 온톨로지와 ko-Dbpedia에서 얻은 온톨로지가 혼재되어 있으며, 에이셀 온톨로지 역시 함께 섞여서 풍부한 관계정보를 가질 수 있습니다.

최종 연결된 지식 그래프 예시

4. 지식그래프(KG)를 활용하기

우리는 알게 모르게 다양한 지식그래프를 접하며, 이를 기업의 검색 시스템과 같은 서비스로서 자연스럽게 사용하고 있습니다. 예시로는 다음과 같습니다.

  • Aicel : 지식그래프를 임베딩하여 개체명연결 (Named Entity Linking, NEL)에서 정확한 개체명을 찾는데 이용합니다 . 또한, 뉴스에서 사용된 줄임말이나 일반 명사가 기업명과 얼마나 유사한지 체크하여 적합한 기업을 찾아줍니다. (지식그래프 임베딩에 대해서는 다른 포스팅에서 자세히 알아보도록 하겠습니다.)
  • Google : 지식 그래프는 Google 검색 엔진 결과 페이지(Google Search Engine Results Pages; SERPs)를 통해 표시되며, 사람들이 검색하는 내용을 기반으로 정보를 제공합니다. 이 지식 그래프는 Freebase, Wikipedia, CIA World Factbook 등의 데이터에서 파싱한 5억 개 이상의 개체명으로 구성되어 있습니다.
  • Retail : 지식 그래프는 up-sell 및 cross-sell 전략을 위해 사용됩니다. 인구통계적 그룹을 분석하여, 집단별/개인별 구매 행동과 인기 있는 구매 추세를 기반으로 제품을 추천합니다.
  • Entertainment : 지식 그래프는 넷플릭스, 서치엔진최적화 또는 소셜 미디어와 같은 콘텐츠 플랫폼을 위한 인공지능(AI) 기반 추천 엔진에도 활용됩니다. 소비자의 클릭 및 기타 온라인 행동을 기반으로, 이러한 콘텐츠 플랫폼은 지식그래프를 활용하여 사용자가 흥미로워할 새로운 콘텐츠를 추천합니다.
  • Finance : 금융 산업 내에서 KYC(Know Your Customer) 및 자금 세탁 방지에도 지식그래프가 사용되고 있습니다. 금융 범죄 예방 및 조사를 지원하여 은행 기관이 고객 간의 자금 흐름을 파악하고 규정을 준수하지 않는 고객을 식별할 수 있도록 그래프 검색 시스템을 활용합니다.
  • Healthcare : 지식 그래프는 또한 의학 연구 내의 관계를 정리하고 분류함으로써 의료 산업에 도움을 주고 있습니다. 또한, 병 진단을 검증하고 개인의 필요에 따라 치료 계획을 세워줘 소비자를 도울 수 있습니다.
up to nav button