注:本文主要是自己在做项目的过程中遇到的一些问题的解决经验,不一定完全符合python开发规范,如读者有更好的方案欢迎讨论

机器学习模型与一般的代码逻辑不同,其输出结果通常不是显式地以代码的形式存在,而是基于大量第三方框架的API表示的,例如scikit-learn、tensorflow。由于机器学习模型训练时间很长,更无法在需要使用的时候立即训练得到。所以需要将模型持久化方便二次开发或调用。

在模型持久化之前,最好先将当前的工程打包成python的package,并将模型暴露成唯一的借口。这可以避免将其他业务层的代码与模型代码混在一起,增强可读性。网上的教程比较混乱,这里是我整理的一种比较简便的形式。以下是一个示例项目的目录结构组织形式。该示例项目可以在我的github上查看。

my_package是机器学习工程的包,通过__init__.py标志该目录为package。在开发my_package的时候包含了三个文件夹model/和src/,分别存放模型数据文件和主要代码。模型的类Foo2存放在foo2.py中。稍后讲如何在不修改模型代码的前提下将该工程封装成package并提供接口调用Foo2。我们先来看如果做好了这一步,会有多么方便。

foo1.py的代码如下,

class Foo1:

def __init__(self, m=None, n=None):

self.m = m

self.n = n

def add(self):

return self.m + self.n

if __name__ == '__main__':

foo1 = Foo1(1,2)

print(foo1.add())

foo2.py的代码如下,

import pandas as pd

from foo1 import Foo1

class Foo2(Foo1):

def __init__(self, m=None, n=None):

super(Foo2, self).__init__(m, n)

def load_data(self, file='../model/test.txt'):

df = pd.read_csv(file, sep = ',', header = None)

self.m = df[0][0]

self.n = df[1][0]

def multiply(self):

return self.m*self.n

if __name__ == '__main__':

#foo2 = Foo2(1,2)

#print(foo2.multiply())

foo2 = Foo2()

foo2.load_data()

print(foo2.multiply())

工程中各个模块之间的依赖关系通过foo1.py和foo2.py展示。可以看到foo2.py需要用到foo1.py中的类Foo1,因而需要from foo1 import Foo1。单独运行foo2.py会打印结果。然而作为一个package,这样写是不太合规范的,应当在foo2.py中使用from .foo1 import Foo1(多了一个点)。这样在my_package/__init__.py 中就不需要添加工程的路径到sys.path中了(见下文)。但是坏处是使得foo2.py无法单独运行了,因为直接运行python foo2.py时,入口在foo2.py的目录,程序只能找到foo1却无法找到 .foo1。本着不修改原始代码的原则,这里采用较不规范的from foo1 import Foo1写法。

main.py的代码如下,

from my_package import Foo2

if __name__ == '__main__':

foo2 = Foo2()

foo2.load_data(file='my_package/model/test.txt')

print(foo2.multiply())

在main.py中,我们不用关心Foo2这个类存放在my_package中哪个子目录的哪个文件中,只需要简单 from ... import ... 即可。否则需要通过 from my_package.src.foo2 import Foo2,这就要求使用my_package的人对各个类的位置十分熟悉。代码中提供了foo2.load_data方法,该方法的输入是数据文件路径。这是因为我们可能需要测试新的数据,因而通常这样的操作会将文件输入路径作为变量暴露出来,而不持久化在代码中。

现在将如何将原始的工程封装成package。首先是在各个目录(my_package/,model/和src/)下添加__init__.py文件,内容暂时为空。__init__.py文件的存在使得当前目录成为独立的package。然而作为一个整体的package,我们需要告诉程序各个包之间的关系。这就需要在__init__.py文件中添加必要的内容。需要说明的是,import的时候,__init__.py文件中的代码会先于目录中的代码文件运行,这有助于标识依赖关系。

my_package/__init__.py 中的内容如下:

# import sys

# sys.path.append('my_package/src')

# import sys

# from os.path import abspath, join, dirname

# sys.path.insert(0, join(abspath(dirname(__file__)), 'src'))

import sys

from os.path import abspath, join, dirname

my_path = join(abspath(dirname(__file__)), 'src')

if my_path not in sys.path:

sys.path.insert(0, my_path)

from .src import Foo2

#from .src import Foo1

model/__init__.py 中不需要添加代码。

src/__init__.py 中的内容如下:

from .foo2 import Foo2

#from .foo1 import Foo1

刚才提到由于不修改原始代码中import的方式,现在需要在my_package/__init__.py中修改sys.path。这里展示了三种做法,前两种注释掉了。第一种方法最简单。第二种方法的缺点是如果反复的运行main.py,会不断地将 'my_package/src' 增加sys.path中。第三种方法避免了这个问题。

再来看如何将Foo2这个类一层层地暴露出来。src/__init__.py 中首先指明了Foo2在foo2.py这个模块中。当程序运行到这里时,Foo2就存在于src的命名空间中了。因而在my_package/__init__.py 中就可以直接from .src import Foo2,进一步将Foo2放在my_package的命名空间中。如此,在main.py中就可以直接from my_package import Foo2。Foo1的暴露方法类似,不过我们这里不需要使用Foo1。

最后总结一下步骤:

1、在工程目录及各个子目录中增加__init__.py

2、my_package/__init__.py 中增加修改sys.path的代码

3、按照目录关系,将需要暴露的类或函数由内至外逐级写在各目录的__init__.py中

4、在需要调用的时候直接from my_package import ... 即可

python如何修改代码_不修改代码打包python机器学习工程相关推荐

  1. python新手入门教程思路-Python新手入门教程_教你怎么用Python做数据分析

    Python新手入门教程_教你怎么用Python做数据分析 跟大家讲了这么多期的Python教程,有小伙伴在学Python新手教程的时候说学Python比较复杂的地方就是资料太多了,比较复杂.很多网上 ...

  2. c++hello world代码_在 Rust 代码中编写 Python 是种怎样的体验?

    作者 | Mara Bos,Rust资深工程师译者 | Arvin 责编 | 屠敏头图 | CSDN 下载自东方 IC出品 | CSDN(ID:CSDNnews) 以下为译文: 大约一年前,我发布了一 ...

  3. c++hello world代码_在Rust代码中编写Python是种怎样的体验?

    作者 | Mara Bos,Rust资深工程师译者 | Arvin,编辑 | 屠敏来源 | CSDN(ID:CSDNnews)大约一年前,我发布了一个名为inline-python(https://c ...

  4. python动态执行代码_第6.6节 Python动态执行小结

    一.    Python动态执行支持通过输入数据流或文件传入Python源代码串,进行编译后执行,可以通过这种方式扩展Python程序的功能: 二.    动态执行方法可能导致恶意攻击,因此使用时需要 ...

  5. python输出等腰三角形代码_酷呆了!Python开发web应用的一些中级技巧

    上一篇文章,介绍了如何用python和flask来开发web应用,是不是觉得用python做web应用很简单? (1)URL如何传递参数? (2)网页如何重定向? 阅读前,还是希望大家能告诉我,关于您 ...

  6. python灰色模型代码_几行代码搞定ML模型,低代码机器学习Python库正式开源

    机器之心报道 机器之心编辑部 PyCaret 库支持在「低代码」环境中训练和部署有监督以及无监督的机器学习模型,提升机器学习实验的效率. 想提高机器学习实验的效率,把更多精力放在解决业务问题而不是写代 ...

  7. python低代码_几行代码搞定ML模型,低代码机器学习Python库正式开源

    PyCaret 库支持在「低代码」环境中训练和部署有监督以及无监督的机器学习模型,提升机器学习实验的效率. 想提高机器学习实验的效率,把更多精力放在解决业务问题而不是写代码上?低代码平台或许是个不错的 ...

  8. latex附录中放python代码_在Latex中插入Python代码

    这里指的插入是指最终能在生成的pdf中显示高亮的Python代码. 在Latex中插入Python代码,需要一个第三发的宏包pythonhighlight: https://github.com/ol ...

  9. python执行一段代码_我发现了个 Python 黑魔法,执行任意代码都会自动念上一段 『平安经』...

    最近的"平安经"可谓是引起了不小的风波啊. 作为一个正儿八经的程序员,最害怕的就是自己的代码上线出现各种各样的 BUG. 为此明哥就研究了一下,如何在你执行任意 Python 代码 ...

最新文章

  1. Java中ThreadPoolExecutor的参数理解
  2. 解决Select2控件不能在jQuery UI Dialog中不能搜索的bug
  3. 日照油库系统推荐_战“疫”快报(3.21)| 油库三期工程罐基础混凝土浇筑全部完成...
  4. 服务器字体指定 iconfont 字体的下载与使用 200303
  5. mysql 怎么算第二天_mysql 第二天
  6. Wix学习整理(6)——安装快捷方式
  7. 2020离散数学系列
  8. 智能优化算法:蝙蝠算法-附代码
  9. jmeter分布式部署
  10. 人工智能表格票据识别-要素信息自动识别提取
  11. 如何批量生成Code32条形码
  12. Unity图片闪烁效果
  13. 5.1.2全景声音箱摆位_全景声音响系统--音箱应该如何摆位(5.1.2、5.1.4篇)
  14. 这,才是有本事的男人
  15. CATIA Automation 编程初探
  16. 【C语言编程】 大小写字母互换
  17. 欧姆龙 PLC CP1E-N30SDR-A 与 NPN型编码器连接
  18. 呆呆木的《愚人码头》
  19. 关于:first-child的误区
  20. 主观下线和客观下线的情况

热门文章

  1. windos 服务怎么写_周岁邀请函怎么写
  2. html快捷保存图片,如何使用360浏览器快速保存图片
  3. 【C语言】fgets函数返回值
  4. vscode 里解决跨域的插件_VSCode里的逆天插件,可边写代码边画逻辑流程图了
  5. greenplum 替代mysql_转:MySQL到Greenplum迁移分析
  6. Java讲课笔记04:变量与常量
  7. 频率副词always,usually,often...用法_16
  8. mysql中的lgwr_MySQL Replication和Oracle logical standby的原理对比
  9. bzoj3214 [Zjoi2013]丽洁体 dp
  10. bzoj2424 [HAOI2010]订货 费用流