在11月1日的“甲骨文数据库与云系列公益讲座”中,向大家介绍了如何在 Oracle Database 23ai 中运行人工智能模型。讲座后的一周里,收到了大量咨询,大家关注的焦点之一就是:如何在本地运行的 Oracle 数据库中部署自建的、专为企业定制的机器学习模型。有些客户甚至直接分享了具体应用场景,希望 Oracle 能提供相关的解决方案。
为此,今天我将通过一个实战案例,为大家展示如何在 10分钟内 将当前的机器学习模型迁移至 Oracle Database 23ai,并顺利运行。让我们一起看看如何利用 Oracle 强大的数据库功能,实现 AI 模型的快速部署,助力企业数据价值的全面释放!
今天,我们设定一个应用场景:一家为客户提供商品和服务的公司,需要对当前的客户进行评级,由于数据量很大,当前的操作是将Oracle Database 当作数据的容器,每次运行客户评级任务时,都需要从数据库中读取大量的数据到当前的机器学习环境中,然后进行推理。由于数据量大,当前机器学习环境以Python为主,因此每次推理都将耗费大量的时间。客户向Oracle咨询,可否将当前的推理模型放入Oracle数据库内部,从而加快推理过程,简化数据流程?并且可否给出一个可行性验证方案?
答案是肯定的,我们可以轻松地将您现有的基于Python、R以及其他可以转换为onnx格式的模型放入数据库中,只通过SQL对该模型进行调用并进行推理。
首先,让我们看看用于训练模型的测试数据(这份数据来自网络)是什么样子的?
我们可以看到,该训练数据由8068条, 有9个Features,以及一个Target(Segmentation),从字段名称上可以判断,这些Feature表示该用户基本信息。我们将使用这些测试数据,进行模型训练。
接下来,我们将使用这些训练数据,构建并训练模型,这是一个分类问题,因此我们将使用简单的神经网络分类算法。由于该程序比较简单,就不为您做程序解释。您可以根据自己的需要,使用适合您自己应用场景的模型和算法。这里需要注意的是,目前Oracle Database 23ai支持的外部模型格式为onnx,因此在程序的末尾,您需要将您训练好的模型保存为onnx格式。
在下面的代码清单中,我们首先导入了必要的软件包,然后加载数据并进行预处理,其中我们使用SimpleImputer 填充数值列的缺失值,然后填充类别列的缺失值并编码。接下来是对数据进行分离,分离出特征和目标,并按照8/2的比例对数据进行分割,分割为训练集和测试集。接下来就是将数据转换为张量,然后进行模型、损失函数以及优化器的初始化,并训练模型。
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.impute import SimpleImputer
from torch.utils.data import DataLoader, TensorDataset
import onnx
import torch.onnx
train_data_path = 'Train.csv'
train_data = pd.read_csv(train_data_path)
imputer = SimpleImputer(strategy='median')
train_data[['Work_Experience', 'Family_Size']] = imputer.fit_transform(train_data[['Work_Experience', 'Family_Size']])
label_encoders = {}
for column in ['Gender', 'Ever_Married', 'Graduated', 'Profession', 'Spending_Score', 'Var_1']:
train_data[column].fillna(train_data[column].mode()[0], inplace=True)
le = LabelEncoder()
train_data[column] = le.fit_transform(train_data[column])
label_encoders[column] = le
le = LabelEncoder()
train_data['Segmentation'] = le.fit_transform(train_data['Segmentation'])
label_encoders['Segmentation'] = le
X = train_data.drop(columns=['ID', 'Segmentation']).values
y = train_data['Segmentation'].values
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.long)
X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
y_val_tensor = torch.tensor(y_val, dtype=torch.long)
class SimpleNNClassifier(nn.Module):
def __init__(self, input_size, num_classes):
super(SimpleNNClassifier, self).__init__()
self.fc1 = nn.Linear(input_size, 64)
self.fc2 = nn.Linear(64, 32)
self.fc3 = nn.Linear(32, num_classes)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
model = SimpleNNClassifier(input_size=X_train.shape[1], num_classes=len(le.classes_))
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
epochs = 10
for epoch in range(epochs):
model.train()
optimizer.zero_grad()
outputs = model(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}")
当模型训练好之后,我们需要将模型转换为onnx格式。
onnx_file_path = "nn_classifier_model.onnx"
dummy_input = torch.randn(1, X_train.shape[1], dtype=torch.float32)
torch.onnx.export(
model,
dummy_input,
onnx_file_path,
input_names=['input'],
output_names=['output'],
opset_version=11,
dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}}
)
print(f"ONNX模型已保存到 {onnx_file_path}")
上述程序运行之后,将得到如下结果:
由于我们今天关注的重点是如何在Oracle Database 23ai中运行自己的人工智能模型,因此我们没有对模型进行优化,请忽略上面那些不理想的模型表现。
当我们得到onnx格式的模型之后,我们接下来要做的就是将模型上传到Oracle Database 23ai所在的服务器。今天我们使用的环境是运行在我的笔记本虚拟机中的Oracle Database 23ai,具体版本信息如下所示:
我将刚刚生成的onnx格式的模型放在/u01下面,并在数据库中创建一个目录对象,DM_DUMP指向/u01,然后授予用户的读写权限。
接下来只需要通过一段简短的PL/SQL代码即可将该模型导入数据库中。其中代码的18行,我们设定了模型在数据库中的名称,20-26行需要注意,这里设定的是模型导入时的参数,21行表明该模型是一个分类模型,23行则定义了后续使用模型进行推理时,要给出的特征名称,建议与稍后使用的数据表字段信息保持一致。
DECLARE
m_blob BLOB default empty_blob();
m_src_loc BFILE;
BEGIN
DBMS_LOB.createtemporary(m_blob, FALSE);
m_src_loc := BFILENAME('DM_DUMP', 'nn_classifier_model.onnx');
DBMS_LOB.fileopen(m_src_loc, DBMS_LOB.file_readonly);
DBMS_LOB.loadfromfile(m_blob, m_src_loc, DBMS_LOB.getlength(m_src_loc));
DBMS_LOB.CLOSE(m_src_loc);
DBMS_DATA_MINING.import_onnx_model(
'henry_BYOM_test',
m_blob,
JSON('{
"function": "classification",
"input": {
"input": ["Gender", "Ever_Married", "Age", "Graduated", "Profession", "Work_Experience", "Spending_Score", "Family_Size", "Var_1"]
}
}')
);
DBMS_LOB.freetemporary(m_blob);
END;
/
我们成功导入模型之后,就可以在数据库内部通过SQL语句直接使用该模型了。我们创建一个为模型提供特征数据的表,建表语句如下:
CREATE TABLE test1108 (
ID NUMBER,
Gender NUMBER,
Ever_Married NUMBER,
Age NUMBER,
Graduated NUMBER,
Profession NUMBER,
Work_Experience NUMBER,
Spending_Score NUMBER,
Family_Size NUMBER,
Var_1 NUMBER
);
接下来向该表中插入测试数据。我们可以看到该测试表中有2627条测试数据。
接下来我们就可以使用SQL语句调用模型了。其中PREDICTION(henry_BYOM_test using *)的含义是调用test1108表中的所有字段作为feature,并调用模型henry_BYOM_test进行推理。需要注意的是,我们没有对模型进行优化,甚至也没有进行特征工程,因为很显然ID字段是对预测没有帮助的干扰信息,我们应该在模型训练之前将其删除。
SELECT id,PREDICTION(henry_BYOM_test using *) PREDICT_client_level from test1108;
在上图中显示了用户的ID以及根据我们的模型为该客户预测的客户评分。
就是如此简单,只需简单的几个步骤,不到十分钟的时间,就可以将您自己的机器学习模型部署到本地运行的Oracle Database 23ai中。Oracle Database 23ai不只能载入传统的机器学习模型,LLM用的embedding模型等都可以载入,具体信息您可以观看11月1日公开课的视频回放,或咨询Oracle技术顾问。
相关链接:Oracle Database 23ai:在Oracle数据库中运行用户自定义的AI模型
想了解更多资讯
扫码关注👇
了解更多考试相关
扫码添加上智启元官方客服微信👇