scikit-learn与Serverless架构结合
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scikit-learn与Serverless架构结合相关的知识,希望对你有一定的参考价值。
1 scikit-learn介绍
scikit-learn是一个面向Python的第三方提供的非常强力的机器学习库,简称sklearn,标志如下所示。它建立在NumPy、SciPy和Matplotlib上,包含从数据预处理到训练模型的各个方面。在人工智能算法开发过程中,研究人员不仅要开发模型,还要花很大力气在数据分析上,以根据数据特征进行算法选择。scikit-learn可以极大地节省编写代码的时间以及减少代码量,使开发者有更多的精力去分析数据、调整模型和修改超参,实现算法效率和效果之间的平衡。
scikit-learn学习库标志
scikit-learn的安装和使用相对来说比较简单。开发者可以通过pip或者conda命令进行scikit-learn学习库的安装。
通过pip命令进行安装:
pip install -U scikit-learn
通过conda命令进行安装:
conda install -c conda-forge scikit-learn
另外需要注意的是,随着Python版本的不断升级迭代,最新版本的scikit-learn已经在逐渐抛弃对老版本的支持。从官方的推荐来看,scikit-learn1.0.1版本推荐使用Python 3.7及以上版本,同时依赖NumPy 1.14.6及以上版本、SciPy 1.1.0及以上版本、joblib 0.11及以上版本、threadpoolctl 2.0.0及以上版本等。
2 scikit-learn实践:鸢尾花数据分类
1.鸢尾花数据集
在scikit-learn中包含许多常用的数据集,本案例选择的是比较基础的鸢尾花(Iris)数据集。该数据集包含3种不同类型的鸢尾花(Setosa、Versicolour和Virginica),其花瓣和萼片长度存储在150×4的numpy.ndarray数组中,行表示样本,列表示各个特征,分别是萼片长度、萼片宽度、花瓣长度和花瓣宽度。我们可以通过Matplotlib进行数据可视化,以便进一步了解鸢尾花数据集。
import matplotlib.pyplot as plt
from sklearn import datasets
iris = datasets.load_iris()
# 这里只选择其中两个特征进行展示
X = iris.data[:, :2]
y = iris.target
x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
plt.figure(2, figsize=(8, 6))
plt.clf()
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1, edgecolor="k")
plt.xlabel("Sepal length")
plt.ylabel("Sepal width")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()
得到的图像如下所示。
鸢尾花数据集展示
2.使用决策树进行分类
决策树(Decision Tree)用于在已知各种情况发生概率的基础上,求取净现值的期望值大于等于0的概率,从而评价项目风险,判断其可行性。其是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称为决策树。在机器学习中,决策树是一个预测模型,它代表的是对象属性与对象值之间的一种映射关系。熵(Entropy)表示的是系统的凌乱程度。这一度量基于信息学理论中熵的概念。
决策树是一种树形结构,其中每个内部节点表示一个属性的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。决策树是一种常用的分类方法。它是一种监督学习。所谓监督学习,就是给定一些样本,每个样本都有一组属性和一个类别,这些类别是事先确定的,通过学习得到一个分类器,这个分类器能够对新出现的对象给出正确的分类。
在scikit-learn学习库中应用决策树算法是非常简单和快捷的,只需要导入决策树相关的对象即可,例如:
from sklearn.tree import DecisionTreeClassifier
通过fit()方法,即可实现基础的数据训练操作,例如:
clf = DecisionTreeClassifier().fit(X, y)
针对鸢尾花分类,通过scikit-learn学习库使用决策树算法的完整代码:
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
import pickle
# 加载数据,前120个样本作为训练集,后120个样本作为测试集
iris = load_iris()
X = iris.data[:120]
y = iris.target[:120]
test_X = iris.data[120:]
test_y = iris.target[120:]
# 训练
clf = DecisionTreeClassifier().fit(X, y)
# 保存
save_path = r"./tree.dot"
with open(r"./tree.dot", wb) as f:
pickle.dump(clf, f)
# 加载模型
f = open(save_path, "rb")
tr = pickle.load(f)
# 测试和预测
Z = tr.predict(test_X)
print("Accuracy: ", accuracy_score(test_y, Z))
上述代码先进行了鸢尾花数据集的加载,然后通过决策树算法进行建模、训练,并对模型结果进行保存,再通过加载模型,对测试集进行相关的准确率分析,最终得到结果:
Accuracy: 0.8
至此,通过scikit-learn实现了非常经典的案例:鸢尾花数据分类。
从这个案例中不难发现,传统意义上需要通过原生写法实现的决策树等算法,通过scikit-learn学习库对外暴露的接口,可以最大效率地进行数据集的加载、模型的训练,以及最终结果的预测。
与Serverless架构结合:文本分类
1.本地开发
文本分类是人工智能中非常经典的研究方向。实现一个简单的文本分类器,通常会被学习者认为是学习scikit-learn过程中的一个最佳实践。
本实践案例是基于scikit-learn实现一个根据公司主营业务的描述划分公司类型的功能,并将这个功能部署到Serverless架构,对外暴露服务级API。
在开始之前,准备一定的公司类型以及相关的数据,例如本案例将公司类型分成20类:
C000001——电力、热力、燃气及水生产和供应业
C000002——建筑业
C000003——批发和零售业
C000004——交通运输、仓储和邮政业
C000005——农、林、牧、渔业
C000006——采矿业
C000007——制造业
C000008——租赁和商务服务业
C000009——科学研究和技术服务业
C000010——水利、环境和公共设施管理业
C000011——居民服务、修理和其他服务业
C000012——住宿和餐饮业
C000013——信息传输、软件和信息技术服务业
C000014——金融业
C000015——房地产业
C000017——卫生和社会工作
C000018——教育
C000020——文化、体育和娱乐业
以上20类中,每一类都有数量一致的相关文本描述,例如“电力、热力、燃气及水生产和供应业”类别中就有类似下面案例的近百个主营业务描述。
·电线电缆、绝缘工具、仪器仪表、电力施工工具、五金电料、绝缘材料、安全防护用品的加工销售;劳保用品的销售。
·风力发电设备的销售、安装、维修、调试及技术服务;电力工程、机电安装工程的设计、施工及技术服务;机电一体化设备、机械设备、液压工具、五金交电、仪器仪表、电线电缆、电子产品、办公用品、日用百货、消防器材、防盗报警器材、服装鞋帽、劳保用品的销售;货物及技术的进出口业务。
……
在自然语言处理领域,基础数据集准备完成之后,往往还需要准备一定量的辅助资源,例如屏蔽一些语气词的停词库,因为部分语气词对模型训练和预测有影响。
在完成基本的数据和相关的辅助资源准备之后,可以进行业务逻辑的开发。整个业务逻辑开发主要包括3部分,分别是模型数据初始化、模型建立以及最终结果的预测。
1)模型数据初始化,导入训练集、停词库等相关数据:
def modelData(self):
class_list = []
cut_word_data = []
with open("StopwordsCN.txt") as f:
stop_word_data = [eve_stop_word.replace("\\n", "")
for eve_stop_word in f.read-lines()]
for eve_dir in os.walk("Sample"):
eve_path_data = eve_dir[0]
for eve_file_data in eve_dir[2]:
new_path_data = os.path.join(eve_path_data, eve_file_data)
if ".txt" in new_path_data:
with codecs.open(new_path_data, "r","utf-8") as f:
file_content = f.read()
eve_content_fenci_data = []
for eve_word_data in jieba.cut(file_content):
if eve_word_data not in stop_word_data and len(eve_word_data) > 0:
eve_content_fenci_data.append(eve_word_data)
cut_word_data.append(" ".join(eve_content_fenci_data))
class_list.append(self.classDict[eve_path_data.split("/")[1]])
cut_word = pandas.DataFrame("class": class_list, "content": cut_word_data)
countVectorizer = CountVectorizer(min_df=0, token_pattern=r"\\b\\w+\\b")
textVector = countVectorizer.fit_transform(cut_word[content])
return (cut_word, countVectorizer, textVector)
2)模型建立,主要通过scikit-learn提供的贝叶斯模型,进行多项式分布的朴素贝叶斯模型建立:
def setModel(self,textVector, cut_word):
bys = MultinomialNB()
bys.fit(textVector, cut_word["class"])
return bys
3)最终结果的预测,即根据模型以及用户待推理预测的内容,返回最终结果:
def predictModel(self,bys,companyInfor, countVectorizer):
newTexts = companyInfor
for i in range(len(newTexts)):
newTexts[i] = " ".join(jieba.cut(newTexts[i]))
return bys.predict(countVectorizer.transform(newTexts))
在本地进行测试,以某建筑业公司的主营业务描述文本“建筑装饰装修工程、建筑幕墙工程、防腐保温工程、金属门窗工程;钢结构工程、建筑防水工程、园林绿化工程、管道工程、机电设备安装工程、消防设施工程、建筑智能化工程的设计、施工;电梯安装。(依法须经批准的项目,经相关部门批准后方可开展经营活动。)”为例:
model = BYSModel()
cut_word, countVectorizer, textVector = model.modelData()
temp_data = ["建筑装饰装修工程、建筑幕墙工程、防腐保温工程、金属门窗工程;钢结构工程、建筑防水工程、园林绿化工程、管道工程、机电设备安装工程、消防设施工程、建筑智能化工程的设计、施工;电梯安装。(依法须经批准的项目,经相关部门批准后方可开展经营活动。)"]
category = model.predictModel(model.setModel(textVector, cut_word),temp_data, countVectorizer)
print(category)
运行结果为:
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/sb/frfgq4nx44n34b33jlzy1mj80000gn/T/jieba.cache
Loading model cost 0.543 seconds.
Prefix dict has been built successfully. [建筑业]
可以看到,通过简单的数据处理以及基于scikit-learn进行模型建立,该项目已经可以正常进行符合预期的推理。
2.部署到Serverless架构
在将项目部署到Serverless架构之前,需要先按照Serverless架构的相关开发规范对业务逻辑进行升级,例如此处可以引入Bottle框架,进行参数的接收和结果的返回:
import Bottle
model = BYSModel()
cut_word, countVectorizer, textVector = model.modelData()
@bottle.route(/company/category, method=POST)
def category():
postData = json.loads(bottle.request.body.read().decode("utf-8"))
text = postData.get("text", None)
return model.predictModel(model.setModel(textVector, cut_word), [text], countVec-torizer)
app = bottle.default_app()
上面的代码是通过Bottle框架简单地将机器学习项目服务化。但是实际上,上面的代码还可包括部分优化操作,例如模型载入、初始化等相关操作:
model = BYSModel()
cut_word, countVectorizer, textVector = model.modelData()
上述两行代码并没有在category方法中执行,尽管这种做法会让实例启动时间有所增加,但是实际上在实例复用的时候,将会有比较明显的冷启动优化效果。
若使用Serverless Devs开发者工具进行项目的构建和部署,要根据Serverless Devs的相关规范对所需要的相关资源与运行路径进行描述:
edition: 1.0.0
name: companyCategory
#项目名称
access: alibaba.default
#密钥别名
services: companyCategory:
#服务名称
component: devsapp/fc
actions:
#自定义执行逻辑
pre-deploy:
#在部署之前运行
- run: s build --use-docker
#要运行的命令行
path: ./
#命令行运行的路径
post-deploy:
#在部署之后运行
- run: s nas command mkdir /mnt/auto/.s
path: ./
#命令行运行的路径
- run: s nas upload -r -n ./.s/build/artifacts/company-category/server/.s/python /mnt/auto/.s/python
#要运行的命令行
path: ./
#命令行运行的路径
props:
#组件的属性值
region: cn-hangzhou
service:
name: company-category
description: 公司主营业务分类
nasConfig: auto
vpcConfig: auto
logConfig: auto
function:
name: server
runtime: python3
codeUri: ./src
ossBucket: devsapp
handler: index.app
memorySize: 3072
timeout: 60
triggers:
- name: httpTrigger
type: http
config:
authType: anonymous
methods:
- GET
- POST
customDomains:
- domainName: auto
protocol: HTTP
routeConfigs:
- path: /
上述Yaml文件中不仅有资源属性的定义,在actions字段下还包括若干行为定义,这使得在通过Serverless Devs开发者工具执行deploy命令之前,会先在Docker环境中执行项目的构建操作:
$ s build--use-docker
执行build操作的前提是,项目已经给出合理的依赖文件,例如requirements.txt等。以本项目为例,依赖详情包括:
bottle==0.12.19
jieba==0.42.1
pandas==1.1.5
scikit_learn==0.24.2
scipy==1.1.0
numpy==1.18
完成部署操作之后,系统会自动在NAS中创建目录,并上传相对应的文件夹等:
$ s nas command mkdir /mnt/auto/.s $ s nas upload -r -n ./.s/build/artifacts/company-category/server/.s/python /mnt/ auto/.s/python
当s deploy-y命令执行完成之后,即可完成Serverless项目的创建。项目创建成功后的日志如下所示。
Serverless项目创建完成后的日志
此时,我们可以通过Postman工具对接口进行测试。以某交通运输公司的主营业务描述“普通货物仓储、配载;普通货物运输;货运代理服务”为例,测试结果如下所示。
通过Postman进行项目测试
可以看到,系统已经正确地输出相关的结果:交通运输、仓储和邮政业。
至此,基于scikit-learn学习库,在Serverless架构上成功部署了一个根据企业信息进行企业分类的自然语言处理项目,并对外提供API服务。
3.项目优化
虽然通过Serverless Devs开发者工具,本项目可以非常简单、快速、方便地部署到Server-less架构,但也有着比较多的优化空间,例如项目被部署到阿里云函数计算的Python运行时上,在部署前后将会面临诸多环境问题。
·部署前:机器学习项目往往存在部分不可跨平台使用的依赖库,此时我们需要了解线上实例的环境详情,或者使用相对应的工具模拟线上实例环境,进行依赖的安装、项目的构建。
·部署后:项目将会受到运行时环境的影响,而很难随着整体的技术迭代发展,例如目前阿里云函数计算的Python运行时版本是3.6,而很多依赖库没办法在Python 3.6版本下正常运作,例如最新的scikit-learn已经推荐使用Python 3.7及以上版本。
针对这类问题,可以考虑通过容器镜像的方法进行解决,即将项目打包成容器镜像部署到函数计算,这样可以最大限度地提高项目后期的灵活度,以及降低维护成本等。
以上是关于scikit-learn与Serverless架构结合的主要内容,如果未能解决你的问题,请参考以下文章