TensorFlow IO에서 PostgreSQL 데이터베이스 읽기

TensorFlow.org에서 보기 Google Colab에서 실행하기 GitHub에서소스 보기 노트북 다운로드하기

개요

이 튜토리얼에서는 PostgreSQL 데이터베이스 서버에서 tf.data.Dataset를 생성하는 방법을 보여줍니다. 생성된 Dataset를 훈련이나 추론 목적으로 tf.keras로 전달할 수 있습니다.

SQL 데이터베이스는 데이터 과학자에게 중요한 데이터 소스입니다. 가장 널리 사용되는 오픈 소스 SQL 데이터베이스 중 하나인 PostgreSQL은 기업에서 중요 데이터와 트랜잭션 데이터를 전사적으로 저장하는 데 보편적으로 사용됩니다. PostgreSQL 데이터베이스 서버에서 직접 Dataset를 만들고 훈련 또는 추론 목적으로 Datasettf.keras로 전달하면 데이터 파이프라인이 크게 간소화되고 데이터 과학자들이 머신러닝 모델을 빌드하는 데 집중할 수 있습니다.

설정 및 사용법

필요한 tensorflow-io 패키지를 설치하고 런타임 다시 시작하기

try:
  %tensorflow_version 2.x
except Exception:
  pass

!pip install -q tensorflow-io

PostgreSQL 설치 및 설정하기(선택 사항)

경고: 이 노트북은 Google Colab에서만 실행되도록 설계되었습니다. 여기서는 시스템에 패키지를 설치하고 sudo 액세스가 필요합니다. 로컬 Jupyter 노트북에서 실행하려면 주의해서 진행해야 합니다.

Google Colab에서 사용법을 데모하기 위해 PostgreSQL 서버를 설치합니다. 암호와 빈 데이터베이스도 필요합니다.

Google Colab에서 이 노트북을 실행하지 않거나 기존 데이터베이스를 사용하려는 경우 다음 설정을 건너뛰고 다음 섹션으로 진행하세요.

# Install postgresql server
sudo apt-get -y -qq update
sudo apt-get -y -qq install postgresql
sudo service postgresql start

# Setup a password `postgres` for username `postgres`
sudo -u postgres psql -U postgres -c "ALTER USER postgres PASSWORD 'postgres';"

# Setup a database with name `tfio_demo` to be used
sudo -u postgres psql -U postgres -c 'DROP DATABASE IF EXISTS tfio_demo;'
sudo -u postgres psql -U postgres -c 'CREATE DATABASE tfio_demo;'
Preconfiguring packages ...
Selecting previously unselected package libpq5:amd64.
(Reading database ... 226196 files and directories currently installed.)
Preparing to unpack .../0-libpq5_10.14-0ubuntu0.18.04.1_amd64.deb ...
Unpacking libpq5:amd64 (10.14-0ubuntu0.18.04.1) ...
Selecting previously unselected package postgresql-client-common.
Preparing to unpack .../1-postgresql-client-common_190ubuntu0.1_all.deb ...
Unpacking postgresql-client-common (190ubuntu0.1) ...
Selecting previously unselected package postgresql-client-10.
Preparing to unpack .../2-postgresql-client-10_10.14-0ubuntu0.18.04.1_amd64.deb ...
Unpacking postgresql-client-10 (10.14-0ubuntu0.18.04.1) ...
Selecting previously unselected package ssl-cert.
Preparing to unpack .../3-ssl-cert_1.0.39_all.deb ...
Unpacking ssl-cert (1.0.39) ...
Selecting previously unselected package postgresql-common.
Preparing to unpack .../4-postgresql-common_190ubuntu0.1_all.deb ...
Adding 'diversion of /usr/bin/pg_config to /usr/bin/pg_config.libpq-dev by postgresql-common'
Unpacking postgresql-common (190ubuntu0.1) ...
Selecting previously unselected package postgresql-10.
Preparing to unpack .../5-postgresql-10_10.14-0ubuntu0.18.04.1_amd64.deb ...
Unpacking postgresql-10 (10.14-0ubuntu0.18.04.1) ...
Selecting previously unselected package postgresql.
Preparing to unpack .../6-postgresql_10+190ubuntu0.1_all.deb ...
Unpacking postgresql (10+190ubuntu0.1) ...
Selecting previously unselected package sysstat.
Preparing to unpack .../7-sysstat_11.6.1-1ubuntu0.1_amd64.deb ...
Unpacking sysstat (11.6.1-1ubuntu0.1) ...
Setting up sysstat (11.6.1-1ubuntu0.1) ...

Creating config file /etc/default/sysstat with new version
update-alternatives: using /usr/bin/sar.sysstat to provide /usr/bin/sar (sar) in auto mode
Created symlink /etc/systemd/system/multi-user.target.wants/sysstat.service → /lib/systemd/system/sysstat.service.
Setting up ssl-cert (1.0.39) ...
Setting up libpq5:amd64 (10.14-0ubuntu0.18.04.1) ...
Setting up postgresql-client-common (190ubuntu0.1) ...
Setting up postgresql-common (190ubuntu0.1) ...
Adding user postgres to group ssl-cert

Creating config file /etc/postgresql-common/createcluster.conf with new version
Building PostgreSQL dictionaries from installed myspell/hunspell packages...
Removing obsolete dictionary files:
Created symlink /etc/systemd/system/multi-user.target.wants/postgresql.service → /lib/systemd/system/postgresql.service.
Setting up postgresql-client-10 (10.14-0ubuntu0.18.04.1) ...
update-alternatives: using /usr/share/postgresql/10/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode
Setting up postgresql-10 (10.14-0ubuntu0.18.04.1) ...
Creating new PostgreSQL cluster 10/main ...
/usr/lib/postgresql/10/bin/initdb -D /var/lib/postgresql/10/main --auth-local peer --auth-host md5
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /var/lib/postgresql/10/main ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default timezone ... Etc/UTC
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

Success. You can now start the database server using:

    /usr/lib/postgresql/10/bin/pg_ctl -D /var/lib/postgresql/10/main -l logfile start

Ver Cluster Port Status Owner    Data directory              Log file
10  main    5432 down   postgres /var/lib/postgresql/10/main /var/log/postgresql/postgresql-10-main.log
update-alternatives: using /usr/share/postgresql/10/man/man1/postmaster.1.gz to provide /usr/share/man/man1/postmaster.1.gz (postmaster.1.gz) in auto mode
Setting up postgresql (10+190ubuntu0.1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for ureadahead (0.100.0-21) ...
Processing triggers for libc-bin (2.27-3ubuntu1.2) ...
Processing triggers for systemd (237-3ubuntu10.38) ...
ALTER ROLE
NOTICE:  database "tfio_demo" does not exist, skipping
DROP DATABASE
CREATE DATABASE

필요한 환경 변수 설정하기

다음 환경 변수는 마지막 섹션의 PostgreSQL 설정을 기반으로 합니다. 다른 설정이 있거나 기존 데이터베이스를 사용하는 경우 적절하게 변경해야 합니다.

%env TFIO_DEMO_DATABASE_NAME=tfio_demo
%env TFIO_DEMO_DATABASE_HOST=localhost
%env TFIO_DEMO_DATABASE_PORT=5432
%env TFIO_DEMO_DATABASE_USER=postgres
%env TFIO_DEMO_DATABASE_PASS=postgres
env: TFIO_DEMO_DATABASE_NAME=tfio_demo
env: TFIO_DEMO_DATABASE_HOST=localhost
env: TFIO_DEMO_DATABASE_PORT=5432
env: TFIO_DEMO_DATABASE_USER=postgres
env: TFIO_DEMO_DATABASE_PASS=postgres

PostgreSQL 서버에서 데이터 준비하기

이 튜토리얼에서는 데모 목적으로 데이터베이스를 생성하고 데이터베이스에 일부 데이터를 채웁니다. 이 가이드에 사용된 데이터는 UCI 머신러닝 리포지토리에서 제공되는 대기 품질 데이터세트에서 가져온 것입니다.

다음은 대기 질 데이터세트의 일부를 미리 나타낸 것입니다.

날짜 시간 CO (GT) PT08.S1 (CO) NMHC (GT) C6H6 (GT) PT08.S2 (NMHC) NOx (GT) PT08.S3 (NOx) NO2 (GT) PT08.S4 (NO2) PT08.S5 (O3) RH AH
10/03/2004 18.00.00 2,6 1360 150 11,9 1046 166 1056 113 1692 년 1268 년 13,6 48,9 0,7578
10/03/2004 19.00.00 2 1292 112 9,4 955 103 1174 년 92 1559 년 972 13,3 47,7 0,7255
10/03/2004 20.00.00 2,2 1402 88 9,0 939 131 1140 년 114 1555 년 1074 11,9 54,0 0,7502
10/03/2004 21.00.00 2,2 1376 80 9,2 948 172 1092 122 1584 년 1203 년 11,0 60,0 0,7867
10/03/2004 22.00.00 1,6 1272 51 6,5 836 131 1205 년 116 1490 1110 년 11,2 59,6 0,7888

대기 품질 데이터세트 및 UCI 머신러닝 리포지토리에 대한 자세한 정보는 참고 문헌 섹션에서 확인할 수 있습니다.

데이터 준비를 단순화하기 위해 대기 품질 데이터세트의 SQL 버전이 준비되었으며 AirQualityUCI.sql로 제공됩니다.

테이블을 만드는 문은 다음과 같습니다.

CREATE TABLE AirQualityUCI (   Date DATE,   Time TIME,   CO REAL,   PT08S1 INT,   NMHC REAL,   C6H6 REAL,   PT08S2 INT,   NOx REAL,   PT08S3 INT,   NO2 REAL,   PT08S4 INT,   PT08S5 INT,   T REAL,   RH REAL,   AH REAL );

데이터베이스에 테이블을 만들고 데이터를 채우는 전체 명령은 다음과 같습니다.

curl -s -OL https://github.com/tensorflow/io/raw/master/docs/tutorials/postgresql/AirQualityUCI.sql

PGPASSWORD=$TFIO_DEMO_DATABASE_PASS psql -q -h $TFIO_DEMO_DATABASE_HOST -p $TFIO_DEMO_DATABASE_PORT -U $TFIO_DEMO_DATABASE_USER -d $TFIO_DEMO_DATABASE_NAME -f AirQualityUCI.sql

PostgreSQL 서버에서 데이터세트를 만들고 TensorFlow에서 사용하기

PostgreSQL 서버에서 데이터세트를 만들려면 queryendpoint 인수를 사용하여 tfio.experimental.IODataset.from_sql을 호출하기만 하면 됩니다. query는 테이블의 선택 열에 대한 SQL 쿼리이고 endpoint 인수는 주소 및 데이터베이스 이름입니다.

import os
import tensorflow_io as tfio

endpoint="postgresql://{}:{}@{}?port={}&dbname={}".format(
    os.environ['TFIO_DEMO_DATABASE_USER'],
    os.environ['TFIO_DEMO_DATABASE_PASS'],
    os.environ['TFIO_DEMO_DATABASE_HOST'],
    os.environ['TFIO_DEMO_DATABASE_PORT'],
    os.environ['TFIO_DEMO_DATABASE_NAME'],
)

dataset = tfio.experimental.IODataset.from_sql(
    query="SELECT co, pt08s1 FROM AirQualityUCI;",
    endpoint=endpoint)

print(dataset.element_spec)
{'co': TensorSpec(shape=(), dtype=tf.float32, name=None), 'pt08s1': TensorSpec(shape=(), dtype=tf.int32, name=None)}

위의 dataset.element_spec 출력에서 볼 수 있듯이 생성된 Dataset의 요소는 데이터베이스 테이블의 열 이름을 키로 사용하는 Python dict 객체입니다.

{   'co': TensorSpec(shape=(), dtype=tf.float32, name=None),   'pt08s1': TensorSpec(shape=(), dtype=tf.int32, name=None), }

추가 연산을 적용하기가 매우 편리합니다. 예를 들어 Datasetnoxno2 필드를 모두 선택하고 차이를 계산할 수 있습니다.

dataset = tfio.experimental.IODataset.from_sql(
    query="SELECT nox, no2 FROM AirQualityUCI;",
    endpoint=endpoint)

dataset = dataset.map(lambda e: (e['nox'] - e['no2']))

# check only the first 20 record
dataset = dataset.take(20)

print("NOx - NO2:")
for difference in dataset:
  print(difference.numpy())
NOx - NO2:
53.0
11.0
17.0
50.0
15.0
-7.0
-15.0
-14.0
-15.0
0.0
-13.0
-12.0
-14.0
16.0
62.0
28.0
14.0
3.0
9.0
34.0

생성된 Dataset는 이제 훈련 또는 추론 목적으로 tf.keras로 직접 전달할 수 있습니다.

참고 문헌

  • Dua, D. and Graff, C. (2019). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science.
  • S. De Vito, E. Massera, M. Piga, L. Martinotto, G. Di Francia, On field calibration of an electronic nose for benzene estimation in an urban pollution monitoring scenario, Sensors and Actuators B: Chemical, Volume 129, Issue 2, 22 February 2008, Pages 750-757, ISSN 0925-4005