AWS Thai Blog

การสร้าง AI-powered search โดยการใช้ PostgreSQL, Amazon SageMaker และ pgvector extension บน PostgreSQL

ในปัจจุบัน องค์กรณ์ต่างๆ มีการมองหาวิธีการใหม่ๆ ในการปรับปรุงประสบการณ์ของผู้ใช้งาน โดยใช้ประโยชน์จากศักยภาพของ Generate AI และโมเดลภาษาขนาดใหญ่ หรือที่เรารู้จักกันในชื่อของ Large Language models (LLMs)

บทความนี้แปลมาจาก Building AI-powered search in PostgreSQL using Amazon SageMaker and pgvector โดยคุณ Krishna Sarabu

ในอุตสาหกรรมแฟชั่น Generative AI ได้เข้ามามีบทบาทในกระบวนการออกแบบและความคิดที่สร้างสรรค์ โดยการวิเคราะห์ข้อมูลของลูกค้า จากนั้น จะใช้ AI อัลกอริทึม ออกแบบเสื้อผ้าเครื่องแต่งกายที่มีเอกลักษณ์เฉพาะสำหรับลูกค้าท่านนั้นๆ เพื่อความเป็นส่วนตัว คุ้มค่าคุ้มราคา

Online Streaming Platform ก็ได้รับประโยชน์จากการมาของ Generative AI ด้วยเช่นกัน เช่นการค้นหาวีดีโอที่มีความคล้านคลึงกัน โดย AI อัลกอริทึมจะสามารถวิเคราะห์พฤติกรรมของผู้ใช้และแนะนำวีดีโอที่มีความคล้าย หรือ ใกล้เคียงกับที่พวกเค้าสนใจ และนำเสนอให้ลูกค้าเพื่อเพิ่มประสบการณ์ในการรับชมของลูกค้าได้ นอกจากนี้พวกบริการโฮสต์รูปภาพต่างๆ ก็สามารถที่จะใช้ AI อัลกอริทึม จัดการภาพที่ซ้ำกัน หรือ ค้นหาภาพที่มีความคล้ายกัน โดยอาจจะค้นหาจากคำค้นของลูกค้า เพื่อเพิ่มศักยภาพในการค้นหารูปภาพอีกด้วย

ในอุตสาหกรรมเคมีและอุตสาหกรรมชีววิทยา ก็เป็นอีกสาขาที่สามารถใช้ศักย์ภาพของ Generative AI เข้ามาช่วยงานปัจจุบัน โดยการใช้ AI ค้นหาความคล้ายคลึงกันของโมเลกุลและการค้นหาความคล้ายคลึงกันของการจำแนกลำดับดีเอ็นเอ และวิเคราะห์ลำดับของดีเอ็นเอ นอกจากนี้ AI ยังมีบทบาทสำคัญในการค้นคว้าและวิจัยยา และยังสามารถใช้เป็นการระบุตัวยาที่จะใช้งานได้อีกด้วย

ในบทความนี้ คุณจะได้เรียนรู้วิธีการสร้างโซลูชั่นที่ใช้ในการค้นหาความคล้ายกันของผลิตภัณฑ์ต่างๆ โดยการใช้งาน Amazon SageMaker, Amazon Relational Database Service (Amazon RDS) – PostgreSQL และ pgvector extension ของ PostgreSQL อีกด้วย

Pgvector เป็นโอเพ่นซอร์สสำหรับ PostgreSQL ที่สามารถจัดเก็บและค้นหาข้อมูล vector ผ่าน ML-generated embeddings. pgvector มีความสารถที่หลากหลาย ซึ่งผู้ใช้สามารถค้นหาสิ่งที่ต้องการทั้งที่เหมือน หรือ ที่แตกต่างออกมาได้อย่างใกล้เคียงที่สุด มันถูกออกแบบมาให้สามารถทำงานได้กับ PostgreSQL และฟีเจอร์อื่นๆ รวมไปถึงการทำ indexing ข้อมูลเหล่านั้นได้เพื่อช่วยในการค้นหาให้มีประสิทธิภาพมากยิ่งขึ้น ทั้งนี้คุณยังสามารถใช้งาน ML embeddings ร่วมกันกับ Amazon Bedrock ได้อีกด้วย (ปัจจุบัน Amazon Bedrock ยังเป็น preview อยู่นะครับ)

บทความนี้จะให้ข้อมูลเชิงลึกและตัวอย่างการใช้งานเกี่ยวกับการใช้งาน AI และ pgvector บน PostgreSQL สำหรับการค้นหาที่คล้ายคลึงกันและอื่นๆ อีกมากมาย มาเริ่มกันเลย!

ภาพรวมของ Vector Embeddings

Embeddings คือกระบวนการการแปลงวัตถุ เช่น ข้อความ รูปภาพ วิดีโอ หรือเสียง ให้แทนเป็นตัวเลขที่อยู่ในรูปแบบของเวกเตอร์ได้ โดยที่เทคนิคนี้ จะใช้ ML อัลกอริทึม เรียนรู้และทำความเข้าใจเกียวกับอัตลักษณ์ของข้อมมูลในรูปแบบข้างต้นที่กล่าวมา เรียนรู้หาความสัมพันธ์และรูปแบบของข้อมูล คุณสามารถใช้ผลของการแปลงเวกเตอร์ที่ได้เพื่อการใช้งานที่หลากหลาย เช่น การดึงข้อมูล การจัดหมวดหมู่ภาพ การประมวลผลภาษา และอื่นๆ อีกมากมาย

Vector embeddings ได้รับความนิยมเพิ่มมากขึ้นเนื่องจากความสามารถในการหาความหมายและความคล้ายคลึงกันของวัตถุในลักษณะที่สามารถคำนวณได้และปรับขนาดได้ รูปภาพตัวอย่างต่อไปนี้แสดงให้เห็นถึงการใส่คำต่างๆ ลงไปยังวัตถุที่เราต้องการได้ เพื่อบ่งบอกถึงความหมาย หรือ อัตลักษณ์ของวัตถุ

รูปที่ 1: word embeddings: คำที่มีความหมายคล้ายกันจะอยู่ใกล้กันในพื้นที่การใส่ข้อมูล

หลังจากสร้างข้อมูลใส่ลงไปแล้ว แอปพลิเคชันหรือนักวิจัยสามารถทำการค้นหาความคล้ายคลึงภายในเวกเตอร์ได้ การค้นหาความคล้ายคลึงกัน จะเป็นประโยชน์ต่องานในอุตสาหกรรมต่างๆ เช่น อีคอมเมิร์ซ ระบบการแนะนำการให้บริการ หรือใช้ในการการตรวจจับการฉ้อโกงได้อีกด้วย

ในบทความนี้ เราจะใช้โอเพ่นซอร์ที่เป็น extension ของ Amazon RDS for PostgreSQL ซึ่งสามารถจัดเก็บข้อมูล vector และสามารถทำการค้นหาข้อมูล vector ดังกล่าวได้ ตัวอย่างนี้จะเป็นการจำลองสถานะการของธุรกิจค้าปลีกออนไลน์ โดยเราจะสร้างชุดข้อมูล vector ของผลิตภัณฑ์ต่างๆ ด้วย Amazon SageMaker และเก็บไว้ใน RDS PostgreSQL จากนั้นเราจะใช้ pgvector ในการทำการค้นหาชุดข้อมูล vector ที่มีความคล้ายคลึงกันของแต่ละกลุ่มผลิตภัณฑ์ออกมาแสดงผล

ในบทความนี้เราใช้ pre-trained model, Hugging Face Inference Deep Learning Containers (DLC) และ Amazon SageMaker Python SDK เพื่อทำ real-time inference endpoint ที่รัน all-MiniLM-L6-v2 เพื่อใช้สร้างชุดข้อมูล vector ขึ้นมา จากนั้น เราจะเก็บข้อมูล vector เหล่านั้นลงใน RDS PostgreSQL ด้วย pgvector extension. สุดท้ายเราจะทำการ search ชุดข้อมูลเหล่านั้นผ่าน เพื่อค้นหารายการในแค็ตตาล็อกผลิตภัณฑ์ที่ตรงกับจุดประสงค์ในการค้นหาของลูกค้ามากที่สุด

Pgvector สามารถทำ indexing ได้ เพื่อช่วยเพิ่มประสิทธิภาพของการค้นหาให้ดียิ่งขึ้นอีกด้วย ลดเวลาการค้นหาความคล้านคลึงกันของวัตถุ หรือ ความคล้ายคลึงกันของข้อมูล vector ต่างๆ

มาเรียนรู้วิธีการทำงานของ pgvector กันดีกว่า ขั้นแรก เราสร้างและเชื่อมต่อกับฐานข้อมูล RDS PostgreSQL และติดตั้ง pgvector extension หลังจากการติดตั้งสำเร็จ คุณสามารถเริ่มต้นการจัดเก็บข้อมูล vector ต่างๆ ลงในฐานข้อมูลและดำเนินการค้นหาได้ตามต้องการ

CREATE EXTENSION vector;

เมื่อคุณเพิ่ม pgvector extension เข้าไปแล้ว จะมี data type ใหม่ขึ้นมาก นั่นก็คือ data type ที่เป็น vector เราสามารถตรวจสอบการติดตั้ง extension ได้โดยการเช็ค data type ที่เป็น vector ด้วยคำสั่งต่อไปนี้

SELECT typname FROM pg_type WHERE typname = 'vector';

ผลลัพธ์ที่ได้

typname
---------
 vector
(1 row)

จากนั้นเราจะใช้ sentence-transformers/all-MiniLM-L6-v2 โมเดลในการสร้างข้อมูล vector คุณสามารถใช้โค้ดด้านล่างสร้างตารางขึ้นมาทดสอบข้อมูล vector และลองค้นหา vector เบื้อต้น จากนั้นค่อยลบตารางดังกล่าวทิ้งได้

CREATE TABLE test_embeddings(product_id bigint, embeddings vector(3) );

INSERT INTO test_embeddings VALUES
(1, '[1, 2, 3]'), (2, '[2, 3, 4]'), (3, '[7, 6, 8]'), (4, '[8, 6, 9]');

SELECT product_id, embeddings, embeddings <-> '[3,1,2]' AS distance
FROM test_embeddings 
ORDER BY embeddings <-> '[3,1,2]';

DROP TABLE test_embeddings;

ตัวอย่างผลลัพธ์การค้นหาข้อมูล

 product_id | embeddings |     distance
------------+------------+-------------------
          1 | [1,2,3]    | 2.449489742783178
          2 | [2,3,4]    |                 3
          3 | [7,6,8]    | 8.774964387392123
          4 | [8,6,9]    |   9.9498743710662
(4 rows)

อ้างอิงจาก GitHub repo สำหรับรายละเอียดเพิ่มเติม

ตัวอย่าง: การใช้การค้นหาที่คล้ายคลึงกัน เพื่อปรับปรุงการค้นหาแคตตาล็อกผลิตภัณฑ์ในร้านค้าปลีกออนไลน์

ต่อไปนี้เป็นการสาธิตทีละขั้นตอนเพื่อทำการค้นหาความคล้ายคลึงกันของผลิตภัณฑ์ เราจะสร้าง vector สำหรับคำอธิบายผลิตภัณฑ์โดยใช้โมเดล Hugging Face ที่ได้รับการ pre-trained บน SageMaker เราจะใช้ Amazon RDS PostgreSQL เพื่อจัดเก็บและดำเนินการค้นหาความคล้ายคลึงกันด้วย pgvector extension

1.) ใช้ Jupyter notebook บน SageMaker ซึ่งเป็น ML compute instance โดยที่ SageMaker จะเป็นตัวจัดการเรื่องของทรัพยากรต่างๆ ที่จำเป็น

2.) ข้อมูลรายละเอียกสินค้าจะเป็นโอเพ่นซอร์ทที่เป็นภาษาเยอรมัน เราจะใช้ Amazon translate แปลงกลับมาเป็นภาษาอังกฤษ

3.) ใช้ pre-trained Hugging Face sentence transform model เพื่อสร้างชุดข้อมูล vector ติดตั้งลงบน SageMaker สำหรับการทำ real-time inference

4.) สร้างชุดข้อมูล vector โดยใช้ SageMaker real-time inference

5.) เก็บข้อมูล vector ที่ได้ลงใน RDS PostgreSQL

6.) ใช้ SageMaker real-time inference ในการเข้ารหัสของ vector

7.) ใช้ RDS PostgreSQL ในการค้นหาข้อมูลที่มีความคล้ายคลึงกันผ่าน pgvector extension

ข้อกำหนดเบื้องต้น

คุณต้องมี account AWS และมีสิทธิ์เบื้องต้นในหารใช้งาน AWS เซอร์วิสต่างๆ ในการรัน CloudFormation ที่ให้ไปได้

หากทำตามตัวอย่างต่อไปนี้ จะมีค่าใช้จ่ายเกิดขึ้น โปรดตรวจสอบหน้าราคาการใช้งาน AWS เซอร์วิสต่างๆ เพื่อเรียนรู้เพิ่มเติม

ในการเริ่มต้น ให้ทำตามขั้นตอนต่อไปนี้:

1.) Sign-in เข้า AWS management console ด้วย user – password ที่คุณมี

2.) เปิด launch stack ที่กำหนดให้ เพื่อใช้ในการสร้างเซอร์วิสต่างๆ ที่จะใช้งาน

3.) ในหน้าของ stack, เลือก checkbox ยอมรับการสร้าง IAM resources ต่างๆ

4.) เลือก create stack

5.) รอจนกระทั่ง stack จะถูกสร้างขึ้นมา ดูได้จากสถานะของ stack คุณจะเห็นคำว่า CREATE_COMPLETE

6.) กดเข้าไปดูที่ OUTPUT ของการสร้าง stack, เลือก notebookinstanceURL, จะปรากฏ URL ของ SageMaker notebook instance ขึ้นมา ซึ่งเราจะทำงานผ่าน notebook ตัวนี้เป็นหลัก

7.) เปิด notebook rdspg-vector.jpynb และรันโค้ดทีละเซล ตามลำดับใน notebook ได้เลย

Data ingestion

เราใช้ข้อมูล FEIDEGGER จากการวิจัยของ Zalando ซึ่งประกอบด้วยรูปภาพแฟชั่นที่มีความละเอียดสูง 8,732 ภาพ และคำอธิบายประกอบที่เป็นข้อความในภาษาเยอรมัน 5 รายการ โดยเราจะใช้ Amazon Translate เพื่อแปลคำอธิบายการแต่งกายแต่ละชุดจากภาษาเยอรมันเป็นภาษาอังกฤษ ดังนี้:

import urllib.request
import os
import json
import boto3

filename = 'metadata.json'

def download_metadata(url):
    if not os.path.exists(filename):
        urllib.request.urlretrieve(url, filename)

def translate_txt(data):
    results = {}
    results['url'] = data['url']
    results['descriptions'] = []
    results['split'] = data['split']
    translate = boto3.client(service_name='translate', use_ssl=True)
    for j in data['descriptions']:
        result = translate.translate_text(Text=str(j), 
                SourceLanguageCode="de", TargetLanguageCode="en")
        results['descriptions'].append(result['TranslatedText'])    
    return results
            
download_metadata('https://raw.githubusercontent.com/zalandoresearch/feidegger/master/data/FEIDEGGER_release_1.2.json')

with open(filename) as json_file:
    data = json.load(json_file)

# we are using realtime traslation which will take around ~30 min.

workers = 1 * cpu_count()

chunksize = 32

#Translate product descriptions in German to English
results = process_map(translate_txt, data, max_workers=workers, chunksize=chunksize)

SageMaker model hosting

ในส่วนนี้เราจะใช้ pre-trained all-MiniLM-L6-v2 Hugging Face sentence transformer model ที่อยู่ใน SageMaker และจะใช้สร้าง 384 dimensional vector สำหรับผลิตภัณฑ์เสื้อผ้าแต่ละตัว

1.) รันโค้ดต่อไปนี้

from sagemaker.huggingface.model import HuggingFaceModel

# Hub Model configuration. <https://huggingface.co/models>
hub = {
  'HF_MODEL_ID': 'sentence-transformers/all-MiniLM-L6-v2',
  'HF_TASK': 'feature-extraction'
}

# Deploy Hugging Face Model 
predictor = HuggingFaceModel(
               env=hub, # configuration for loading model from Hub
               role=role, # iam role with permissions to create an Endpoint
               transformers_version='4.26',
               pytorch_version='1.13',
               py_version='py39',
            ).deploy(
               initial_instance_count=1,
               instance_type="ml.m5.xlarge",
               endpoint_name="rdspg-vector",
            )

2.) ทดสอบ SageMaker real-time inference endpoint และสร้างชุดข้อมูล vector

def cls_pooling(model_output):
    # first element of model_output contains all token embeddings
    return [sublist[0] for sublist in model_output][0]

data = {
  "inputs": ' '.join(results[0].get('descriptions'))
}

res = cls_pooling( predictor.predict(data=data) )
print(len(res))

ผลลัพธ์ที่ได้จะเป็น 384-dimensional vector สำหรับข้อความอินพุตที่กำหนด

3.) สร้าง inference request โดยใช้ SageMaker เพื่อสร้าง vector 384 dimension สำหรับคำอธิบายแคตตาล็อกผลิตภัณฑ์:

def generate_embeddings(data):
    r = {}
    r['url'] = data['url']
    r['descriptions'] = data['descriptions']
    r['split'] = data['split']
    inp = {'inputs' : ' '.join( data['descriptions'] ) }
    vector = cls_pooling( predictor.predict(inp) )
    r['descriptions_embeddings'] = vector
    return r
    
workers = 1 * cpu_count()

chunksize = 32

# generate embeddings
data = process_map(generate_embeddings, results,
    max_workers=workers, chunksize=chunksize)

4.) เชื่อมต่อ RDS PostgreSQL และสร้าง table สำหรับเก็บข้อมูล vector ที่ได้มาจากการรันคำสั่งข้างต้น จากนั้นสร้าง index เพื่อให้สามารถค้นข้อมูลได้มีประสิทธิภาพมากยิ่งขึ้น

import psycopg2
from pgvector.psycopg2 import register_vector
import boto3 
import json 

client = boto3.client('secretsmanager')

response = client.get_secret_value(
    SecretId='rdspg-vector-secret'
)
database_secrets = json.loads(response['SecretString'])

dbhost = database_secrets['host']
dbport = database_secrets['port']
dbuser = database_secrets['username']
dbpass = database_secrets['password']

dbconn = psycopg2.connect(host=dbhost, user=dbuser, password=dbpass,
    port=dbport, connect_timeout=10)
dbconn.set_session(autocommit=True)

cur = dbconn.cursor()
cur.execute("CREATE EXTENSION IF NOT EXISTS vector;")
register_vector(dbconn)
cur.execute("DROP TABLE IF EXISTS products;")
cur.execute("""CREATE TABLE IF NOT EXISTS products(
  id bigserial primary key,
  description text,
  url text,
  split int,
  descriptions_embeddings vector(384)
);""")

for x in data:
    cur.execute("""INSERT INTO products (description, url, split, descriptions_embeddings)
	  VALUES (%s, %s, %s, %s);""",
	  (' '.join(x.get('descriptions', [])), x.get('url'), x.get('split'), x.get('descriptions_embeddings') ))

cur.execute("""CREATE INDEX ON products
  USING ivfflat (descriptions_embeddings vector_l2_ops) WITH (lists = 100);""")
cur.execute("VACUUM ANALYZE products;")
cur.close()
dbconn.close()

5.) รันคำสั่งค้นหาความคล้ายคลึงกันใน RDS สำหรับ PostgreSQL โดยใช้ pgvector extension:

import numpy as np
from skimage import io
import matplotlib.pyplot as plt
import requests

data = {"inputs": "red sleeveless summer wear"}

res1 = cls_pooling(predictor.predict(data=data)) 
client = boto3.client('secretsmanager')
response = client.get_secret_value( SecretId='rdspg-vector-secret' )
database_secrets = json.loads(response['SecretString'])
dbhost = database_secrets['host']
dbport = database_secrets['port']
dbuser = database_secrets['username']
dbpass = database_secrets['password']
dbconn = psycopg2.connect(host=dbhost, user=dbuser, password=dbpass, port=dbport, connect_timeout=10)
dbconn.set_session(autocommit=True)

cur = dbconn.cursor()

cur.execute("""SELECT id, url, description, descriptions_embeddings
  FROM products
  ORDER BY descriptions_embeddings <-> %s limit 2;""",
  (np.array(res1),))

r = cur.fetchall()
urls = []
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True

for x in r:
    url = x[1].split('?')[0]
    urldata = requests.get(url).content
    print("Product Item Id: " + str(x[0]))
    a = io.imread(url)
    plt.imshow(a)
    plt.axis('off')
    plt.show()

cur.close()
dbconn.close()

ผลลัพธ์ในส่วนที่คล้ายกันจะได้ตามตัวอย่างด้านล่าง

ตอนนี้ เมื่อลูกค้าป้อนคำค้นหา เช่น “ชุดฤดูร้อนแขนกุดสีแดง” ในใบแอพขายปลีกออนไลน์ของคุณ คุณลักษณะการค้นหาความคล้ายคลึงของ vector จะช่วยให้ลูกค้าของคุณได้รับผลลัพธ์ที่ตรงกันมากที่สุด

Cleanup

รันคำสั่งใน Jupyter notebook เพื่อลบโมเดล และ endpoint

predictor.delete_model()
predictor.delete_endpoint()

จากนั้นให้ทำการลบ CloudFormation template เพื่อลบ AWS เซอร์วิสอื่นๆ ที่ใช้ในตัวอย่างนี้

Conclusion

ในบทความนี้แสดงให้เห็นถึงการใช้งาน Generative AI บน SageMaker และ Amazon RDS PostgreSQL ร่วมกันกับ pgvector extension เพื่อสร้างประสบการณ์ใหม่ในการค้นหาผลิตภัณฑ์ โดยใช้การทำงานรวมกันกับโมเดลที่เป็นโอเพ่นซอร์ทต่างๆ เพิ่มความแม่นยำและความเร็วของการค้นหาความคล้ายคลึง คำแนะนำเฉพาะบุคคล และการตรวจจับการฉ้อโกง ซึ่งท้ายที่สุดจะนำไปสู่ความพึงพอใจของผู้ใช้และประสบการณ์ที่เป็นส่วนตัวมากขึ้น

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวอย่างโค้ดที่ใช้ในบทความนี้ สามารถดูเพิ่มเติมได้ที่ GitHub