理论+实例,带你入门Greenplum机器学习框架MADlib

2023-11-03 07:41

本文主要是介绍理论+实例,带你入门Greenplum机器学习框架MADlib,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

e45b2dd4-549c-4f09-82eb-5829b7a0ab56.jpg

本文由瀚高基础软件社区作者赫庆贺创作贡献


概述


本文介绍Greenplum和MADlib在机器学习方面的基本概念、架构和原理。并结合MNIST数据集完成对0-9阿拉伯数字的图形识别的应用实例。旨在为数据库开发者和DBA提供简单机器学习的了解和入门的方式。

一、知识与软件准备


1.1 Greenplum 


Greenplum是全球首个开源MPP数据库,内核基于PostgreSQL。作为PB级分布式数据库,支持大规模并行数据计算,被广泛应用于企业的OLAP业务场景。Greenplum集群的节点类型主要有master和segment。master提供数据库统一访问入口并协调各计算节点运行,segment作为物理存储和数据计算节点。通过增加segment节点可以实现系统性能的线性扩展。
Greenplum的并行计算能力和线性扩展能力赋能于MADlib,使其有更好的并发度,用更全量的数据和更少的数据移动来做模型训练。


1.2 MADlib


MADlib 是Apache 软件基金会顶级开源项目。作为一个机器学习函数库,MADlib能以扩展插件的形式嵌入到Greenplum和PostgreSQL数据库中,提供SQL层的接口。数据库用户可以直接通过SQL语言调用MADlib的接口完成机器学习的各个过程。
MADlib的架构如下:

6faa31c0-350c-4f23-a2f7-d07b60b77f90.png


为了保证执行效率,MADlib底层算法主要由C++编写,上层接口由python编写。目前已支持超过50种常用算法,并且为开发人员提供了扩展算法的方式。


所有算法都支持在Greenplum各个segment节点上并行运算,并将各个segment上的运算结果汇聚到master节点形成最终结果,计算时的数据仅在数据库内部移动。为了实现这一点,MADlib在数据库内创建一系列的汇聚函数(UDA)和计算函数(UDF)。在MADlib安装时这些函数会被创建在数据库内部。


MADlib支持深度学习算法,集成Keras、Tensorflow、Scipy库,并集成CUDA、CUDNN以支持GPU加速计算。


1.3 机器学习


机器学习是一门多领域交叉学科,涉及概率论、统计学、算法复杂度理论等多门学科。机器学习是人工智能(AI)的核心子领域,机器学习的理论基础是能够让计算机可以自动学习的算法。算法按照学习策略、应用领域、学习形式等方式划分为不同类别。常见机器学习算法有:朴素贝叶斯、线性回归、神经网络、决策树、支持向量机等等。幸运的是,作为一个软件开发者可以不用去了解算法的实现细节,直接调用函数库接口就能使用这些算法。机器学习已在生物特征检测、图像识别、数据挖掘、语义分析等多个领域有广泛应用。


传统方式下,计算机对某一个事物分类的判别方式通常需要一组事先定义好的阈值区间和一系列严格的判断逻辑组合来完成。例如让计算机判断一个物体是不是苹果,要事先告诉计算机苹果的定义是什么。


假设我们定义苹果的属性取值区间为:颜色为红色或青色,直径范围是2cm-10cm,重量范围20g-500g,口感香甜。


计算机判断物体是不是苹果的流程通常如下:


398caeb7-fbc9-43f0-b057-11ee5885cf80.png


机器学习则提供了另一种思路来解决这类问题。我们不需要给计算机预先定义苹果是什么。我们只需要告诉计算机这种东西是苹果、这种东西是苹果、这种东西也是苹果......


所有的苹果样例组成了数据集。通过机器学习算法对数据集的处理(训练)可以产生判断苹果的模型。随着数据集的变化,模型可以通过重复训练来优化调整。有了模型便可以判断一个新的物体是不是苹果了。


4af0ebcb-7974-4d11-a6e5-f5ccbf043a46.png


以上示例,对事务的分类判别方式称之为分类算法,分类算法仅仅是众多机器学习算法中的一种。除了分类算法还有用于预测连续性输出值的回归类算法,用来挖掘事务之间的关联关系的关联规则类算法等等。


1.4 数据集


机器学习中用来训练算法模型和测试算法正确性的数据。针对自身业务的机器学习模型训练最好使用自身应用场景的数据。也有许多不同应用场景下的公开数据集供学习研究使用。本文使用MNIST数据集作为训练和测试用数据。


MNIST来自美国国家标准与技术研究所(NIST),是被经常使用的典型数据集。MNIST由多人手写0-9的阿拉伯数字组成,可以把每个手写阿拉伯数字看做是一个28x28像素的图片,将图片转换成像素值的矩阵再以字节序的形式存储到文件中。


MNIST数据集的下载地址为:http://yann.lecun.com/exdb/mnist/


下载文件列表如图:


7a68586e-daf9-4a4d-8336-06aba762d9ac.png



下载后可以用gunzip工具将每个压缩文件解压。数据集包含60000个训练数据样本,10000个测试数据样本。文件分别以格式存储数据。

62296db0-6d88-4315-9e85-9bd3bf60b92e.png


1.5 数据处理代码


MNIST数据集需要将数据文件转换并导入Greenplum后才能被MADlib使用。为了方便数据集的处理,参照1.4节的数据文件格式,编写了代码文件mnist_transform.py:
import os  import struct  from PIL import Image  import numpy as np

def load_mnist(path, kind='train'): """Load MNIST data from files""" labels_path = os.path.join(path,'%s-labels-idx1-ubyte' % kind) images_path = os.path.join(path,'%s-images-idx3-ubyte' % kind) with open(labels_path, 'rb') as lbpath: magic, n = struct.unpack('>II', lbpath.read(8)) labels = np.fromfile(lbpath, dtype=np.uint8)
with open(images_path, 'rb') as imgpath: magic, num, rows, cols = struct.unpack('>IIII', imgpath.read(16)) images = np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784) return images, labels, num

def format_csv_line(seq, num, array): linestr="%d,%d,\"{" % (seq, num) for i in range(len(array)): linestr += "%d," % array[i] linestr = linestr[:-1] linestr += "}\"\n" return linestr

def array2csv(imgs, lbs, num, tofile): """covert np.array to CSV format file""" with open(tofile, "w") as f: for seq in range(num): f.write(format_csv_line(seq, lbs[seq], imgs[seq]))

def array2imgfile(idx, imgs, filename): """extract mnist data to png file by index""" imgarray=imgs[idx].reshape(28, 28) im = Image.fromarray(imgarray) im.save("/home/gpadmin/madlib/mnist/images/%s_idx_%d.png" % (filename, idx), format="png")

if __name__ == "__main__": imgs, lbs, count = load_mnist("/home/gpadmin/madlib/mnist", "train") array2csv(imgs, lbs, count, "/home/gpadmin/madlib/mnist/trans_data.csv") imgs, lbs, count = load_mnist("/home/gpadmin/madlib/mnist", "t10k") array2csv(imgs, lbs, count, "/home/gpadmin/madlib/mnist/test_data.csv") #array2imgfile(0,imgs,"test") print("transform completed.")

 load_mnist函数读取解压后的MNIST数据文件,并将数据放入numpy.array数组中。


array2csv函数将numpy.array数组中的数据装换成CSV格式文件,CSV文件可以通过copy命令导入数据库表,其格式与数据库表的格式要一致。请参考2.1节数据库表的创建语句。


array2imgfile 函数可以将数组中的一个样本转换成图片文件,以便通过图片查看器对数据样本进行可视查看。


二、应用实例


有了前面的各项准备工作,接下来我们要做的是以实现计算机对手写阿拉伯数字0-9的识别为例子,进一步探索Greenplum+MADlib机器学习方式。


具体过程是先将MNIST的数据集导入到Greenplum数据库中,使用MADlib提供接口,完成朴素贝叶斯算法模型的训练,并且使用训练的模型对测试数据进行识别。最后通过对比测试数据样本和识别结果来检验MADlib中朴素贝叶斯算法是否能对MNIST测试数据进行识别。


在进行第二章节的实例之前,需要先将Greenplum系统搭建好。Greenplum的安装方式可参考官方网站(https://cn.greenplum.org/)。


MADlib安装文档请参考:

https://cwiki.apache.org/confluence/display/MADLIB/Installation+Guide


安装时需要确保Greenplum已经启动,从源码编译安装到Greenplum时需要将编译好的函数库分发到各segment上。


本实例使用软件版本:

PostgreSQL 9.4.24 (Greenplum Database 6.0.0-beta.1 build dev)

MADlib version: 1.17.0


2.1 导入数据


以下步骤需要用客户端软件(如psql)连接到Greenplum数据库进行操作,使用PostgreSQL数据库时请酌情调整SQL。
创建训练数据表: CREATE TABLE mnist_example ( id int, label smallint, attributes smallint[]) DISTRIBUTED BY(id);   id 字段为样本编号。 label字段表示样本代表的阿拉伯数字。 attributes 字段是由784个元素构成的Array,用以保存样本图片的数据。
创建测试数据表: CREATE TABLE mnist_topredict ( id int, label smallint, attributes smallint[]) DISTRIBUTED BY(id);  
将MNIST的训练数据和测试数据转换成CSV格式: 运行mnist_transform.py文件的转换函数(python3):
imgs, lbs, count = load_mnist("/home/gpadmin/madlib/mnist", "train")  array2csv(imgs, lbs, count, "/home/gpadmin/madlib/mnist/trans_data.csv")  imgs, lbs, count = load_mnist("/home/gpadmin/madlib/mnist", "t10k")  array2csv(imgs, lbs, count, "/home/gpadmin/madlib/mnist/test_data.csv")

得到CSV文件:test_data.csv  trans_data.csv


导入训练数据到表mnist_example:

copy  mnist_example from '/home/gpadmin/madlib/mnist/trans_data.csv' CSV;   


导入测试数据到表mnist_topredict:

copy mnist_topredict from '/home/gpadmin/madlib/mnist/test_data.csv' CSV;  


2.2 训练模型
调用MADlib的API进行模型训练。 SELECT * FROM madlib.create_nb_prepared_data_tables('mnist_example','label','attributes',784,'mnist_feature_probs','mnist_priors');  
参数 'mnist_example' 为2.1步骤创建的训练数据表名。 参数 'label'  指定以mnist_example表中的lable字段作为分类字段。 参数 'attributes' 指定以mnist_example表的attributes字段作为特征字段。 参数 784  表示数据特征的个数,在本例中图片的每个像素都作为一个特征,图片是28*28=784像素的。 参数'mnist_feature_probs' 指定特征概率输出表的名称 参数'mnist_priors' 指定分类输出表的名称,此表统计训练数据中各个分类出现的次数。

2.3 样本识别结果


创建可用来查询识别结果的视图 mnist_classified。

SELECT madlib.create_nb_probs_view('mnist_feature_probs','mnist_priors','mnist_topredict','id','attributes',784,'mnist_classified'); 


参数'mnist_feature_probs'  'mnist_priors'同2.2节

参数'mnist_topredict' 为待识别数据表,'id' 'attributes' 784参数指定该表的键和属性字段以及特征数。

参数'mnist_classified'为创建的视图名称。


创建好的视图结构如下,


5202a944-f3c2-45c5-87e2-b87b6533731c.png


key 字段对应输入数据表(mnist_topredict)的id字段。 class 字段表示可能的阿拉伯数字 nb_prob 字段表示识别为对应class字段的概率,最大值为1。
对比查看对编号(key/id)为0的测试数据的识别结果以及待识别数据原型。
查看识别结果:

57832598-34d4-49e2-b0a1-0a47d654e311.png


可以看到识别为数字 7的概率有1(100%).识别为其他是数字的概率都远低于数字7. 查看对应编号为0(id)的数据样本:

fc83f8db-c777-454e-aff8-81c11ae82b64.png


编号为0的数据样本对应的阿拉伯数字为7。


通过mnist_transform.py文件里的array2imgfile函数将编号为0的测试数据转化为图片文件。


imgs, lbs, count = load_mnist("/home/gpadmin/madlib/mnist", "t10k")  array2imgfile(0,imgs,"test")

得到图片文件test_idx_0.png。 用图片查看器打开图片文件,验证为手写的数字 7。

d3046cc5-93c2-4218-9ae9-ae5ff376fd5f.png


对编号为0的测试数据样本识别达到期望目标。

再来看一个识别失败的例子。编号为1234的样本机器识别结果为:


dc26c226-b857-44bc-9991-6f3c57f1943e.png


机器识别为极大概率是数字5,其次为数字3,较小概率为数字8.为其他数字的概率远低于这三个。


对应的数据样本为:


f1c8e806-968d-4f7e-bc19-2e034e7a6c63.png


转换后的图片为:


1a5f849a-fe9e-41a1-86e4-af28077e8416.png


显然对这张图片的识别未达到预期结果。


2.3 识别的正确率    


我们将nb_prob值最大的一项对应的class值作为最终识别数字,然后统计一下对10000个测试数据的识别正确率。


在数据库中创建PL/pgSQL函数mnist_stat():

CREATE OR REPLACE FUNCTION mnist_stat() RETURNS integer AS $$    DECLARE      topredict   RECORD;      classified  RECORD;      total       integer := 0;      sucnum      integer := 0;      failnum     integer := 0;  BEGIN      RAISE NOTICE 'Begin statstics';      FOR topredict IN SELECT id,label FROM mnist_topredict  LOOP          EXECUTE  'SELECT key,class FROM mnist_classified WHERE key=$1 ORDER BY nb_prob DESC LIMIT 1 ' INTO STRICT classified USING topredict.id;          IF topredict.label = classified.class THEN              sucnum := sucnum + 1;          ELSE              failnum := failnum +1;              RAISE NOTICE 'id % failed: %  --- % ',topredict.id,topredict.label,classified.class;          END IF;          total := total + 1;
END LOOP; RAISE NOTICE 'total: % sucnum: % failnum:%',total,sucnum,failnum;
RETURN sucnum ; END; $$ LANGUAGE plpgsql;


执行统计过程:


testDB=# SELECT mnist_stat();


输出统计结果:

fa885b93-8121-454c-8277-9a16cdef339f.png


识别样本总数10000,识别正确数为8377,识别错误数为1623.正确率为83.77%。
在没有任何针对性优化的情况下,83.77%正确率可以说明Greenplum +MADlib进行图像识别的可行性,并不能说明这种方式的优劣。因为机器学习算法识别的正确率与很多因素相关,如训练数据数量、测试样本、使用的机器学习算法、算法使用的参数等等。对于如何优化和提升还需进一步深入学习研究。

参考资料:

http://docs.greenplum.org/6-4/analytics/madlib.html#topic9

http://madlib.apache.org/documentation.html

http://yann.lecun.com/exdb/mnist/




07d49c61-21bc-49a5-bb0f-d3d8a696b661.png

想学习机器学习算法?Greenplum原厂团队亲自操刀,和腾讯云大学合作打造了《基于 Greenplum 的机器学习算法与实践》系列课程。


十个章节,囊括了机器学习的前世今生、各大经典算法、深度学习、时间序列算法、图算法、数据分析扩展语言等丰富的内容,算法理论配合Greenplum应用实践。


十小时的精彩内容,免费贡献给社区,扫码或点击“阅读原文”即可开启你的学习之旅!


45770028-204b-4e79-a2e7-09feabdf97d0.jpg


bf9016b2-48c3-471e-8389-824d172bb4dd.png



c82d1672-8542-4df6-988f-36c89e334dfb.svg

近期活动

af4f73f6-d842-46ba-a433-bbc52f051d28.svg


06d27806-2bdb-4e3e-a966-6efbe8e6e1c7.jpg


点击文末“ 阅读原文 ”,获取课程链接

8fbd29e8-c45a-4842-aa10-b8b287c5a040.gif

82f83c8b-7ce6-4bea-b883-d97ff37e80b1.png来一波 “在看”、“分享”和 “赞” 吧!


本文分享自微信公众号 - Greenplum中文社区(GreenplumCommunity)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

这篇关于理论+实例,带你入门Greenplum机器学习框架MADlib的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/336650

相关文章

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

MySQL的索引失效的原因实例及解决方案

《MySQL的索引失效的原因实例及解决方案》这篇文章主要讨论了MySQL索引失效的常见原因及其解决方案,它涵盖了数据类型不匹配、隐式转换、函数或表达式、范围查询、LIKE查询、OR条件、全表扫描、索引... 目录1. 数据类型不匹配2. 隐式转换3. 函数或表达式4. 范围查询之后的列5. like 查询6

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin