注:本文主要是自己在做项目的过程中遇到的一些问题的解决经验,不一定完全符合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 = mself.n = ndef add(self):return self.m + self.nif __name__ == '__main__':foo1 = Foo1(1,2)print(foo1.add())

foo2.py的代码如下,

import pandas as pd
from foo1 import Foo1class 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.nif __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 Foo2if __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 ... 即可

mariadb不支持load data_不修改代码打包python机器学习工程相关推荐

  1. python如何修改代码_不修改代码打包python机器学习工程

    注:本文主要是自己在做项目的过程中遇到的一些问题的解决经验,不一定完全符合python开发规范,如读者有更好的方案欢迎讨论 机器学习模型与一般的代码逻辑不同,其输出结果通常不是显式地以代码的形式存在, ...

  2. 使用vite和Element Plus,实现部署后不修改代码/打包,新增主题/皮肤包

    Web前端界面切换主题/皮肤,是一个常见的需求.如果希望在打包部署后实现皮肤的修改甚至增加皮肤,不需要修改源码或者重新打包,类似于我们常见的皮肤包扩展,又该如何实现呢? 我使用类似上一期多语言包功能中 ...

  3. 朴素贝叶斯代码实现python

    P(B)称为"先验概率",即在A事件发生之前,对B事件概率的一个判断. P(B|A)称为"后验概率",即在A事件发生之后,对B事件概率的重新评估. P(A|B) ...

  4. python机器学习开源代码_Python简化代码机器学习库PyCaret 2.0发布

    字幕组双语原文:Python简化代码机器学习库PyCaret 2.0发布 英语原文:Announcing PyCaret 2.0 翻译:雷锋字幕组(Shangru) 我们激动的宣布,PyCaret第二 ...

  5. jz2440开发板移植U-boot之修改代码支持DM9000网卡

    今天我们来移植U-boot到jz2440开发板,修改代码支持DM9000网卡.查看之前写的移植记录请点击链接:点击查看之前的移植记录 现在大多数开发板都支持DM9000网卡.我们的U-boot源码里面 ...

  6. 移植uboot之修改代码支持NorFlash记录续集

    接着上一篇文章写的内容(上一篇文章链接:移植uboot之修改代码支持NORFLASH),上一篇结尾测试flash的擦除读写功能,结果无法写flash,卡在了这里: 前面已经擦除成功,这里写内容写不进去 ...

  7. am335x linux修改ip,Linux 修改代码以支持LED 控制(board-am335xevm)

    Linux 修改代码以支持LED 控制(board-am335xevm) Note: All the codes are changed at the file board-am335xevm.c d ...

  8. 五、移植u-boot-2016.03到Jz2440之修改代码支持NOR Flash

    5. 移植u-boot-2016.03修改代码支持NOR Flash 从上一节把uboot烧写到NAND启动后,最后打印出Flash: 0 Bytes,如下图所示.我们的Jz2440开发板的NOR F ...

  9. 【计算机系统结构】Self-modifying code 自修改代码

    Self-modifying code 在计算机科学中,自修改代码是一种代码,当代码执行时修改它自身的指令,通常用于减少指令路径长度以提高性能或简单地减少额外的,重复的,相似的代码,以此来简化维护.自 ...

最新文章

  1. 哪些人适合参加软件测试培训
  2. 解决 macOS 上 iterm2 使用 rz/sz 卡死的问题
  3. Android开源音乐播放器之播放器基本功能
  4. 当我真正开始爱自己——查理·卓别林
  5. EMUI10安装java_linux ubuntu系统安装java jdk和配置环境,pycharm安装
  6. android arm 寄存器,ARM汇编
  7. 吴恩达机器学习笔记二之多变量线性回归
  8. 学以致用二十二-----写一个基本环境设置的脚本
  9. SQLSERVER2008R2正确使用索引
  10. C++中对string对象的初始化及赋值方式总结
  11. JAVA项目实战开发电商项目案例(一)前后端项目分离
  12. 在Ubuntu安装QT及相关环境配置
  13. Android音视频开发之——音频非压缩编码和压缩编码,神级Android进阶笔记
  14. MongoDB Mobile Sync for iOS推出Beta版本
  15. 分享一点关于安装、使用达梦数据库的愚见
  16. 集大计算机与科学的研究生,明天,我是研究生丨感谢集大,我遇见了更好的自己...
  17. 视频监控在安防市场比重大 技术发展引出商机
  18. scrapy 两类item_手把手教你进行Scrapy中item类的实例化操作
  19. html雪碧图效果,综合雪碧图
  20. Xcode下载结果校验

热门文章

  1. [笔记].痛哉!!!Error: Can't access JTAG chain, Error: Operation failed
  2. C++的静态联编和动态联编
  3. Android项目增加混淆
  4. 第十五节,基本数据类型,元组tuple
  5. 4. Storm可靠性
  6. 在线JSON压缩工具
  7. spring加载classpath与classpath*的区别别
  8. Spring MVC测试框架详解——服务端测试
  9. 那些不可一世的安全软件巨头没落了吗?
  10. UNIX环境高级编程之第4章:文件和文件夹-习题