内容简介:想必大家都或多或少听过 TensorFlow 的大名,这是 Google 开源的一个深度学习框架,里面的模型和 API 可以说基本是一应俱全,但 TensorFlow 其实有很多让人吐槽的地方,比如 TensorFlow 早期是只支持静态图的,你要调试和查看变量的值的话就得一个个变量运行查看它的结果,这是极其不友好的,而 PyTorch、Chainer 等框架就天生支持动态图,可以直接进行调试输出,非常方便。另外 TensorFlow 的 API 各个版本之间经常会出现不兼容的情况,比如 1.4 升到 1.
想必大家都或多或少听过 TensorFlow 的大名,这是 Google 开源的一个深度学习框架,里面的模型和 API 可以说基本是一应俱全,但 TensorFlow 其实有很多让人吐槽的地方,比如 TensorFlow 早期是只支持静态图的,你要调试和查看变量的值的话就得一个个变量运行查看它的结果,这是极其不友好的,而 PyTorch、Chainer 等框架就天生支持动态图,可以直接进行调试输出,非常方便。另外 TensorFlow 的 API 各个版本之间经常会出现不兼容的情况,比如 1.4 升到 1.7,里面有相当一部分 API 都被改了,里面有的是 API 名,有的直接改参数名,有的还给你改参数的顺序,如果要做版本兼容升级,非常痛苦。还有就是用 TensorFlow 写个模型,其实相对还是比较繁琐的,需要定义模型图,配置 Loss Function,配置 Optimizer,配置模型保存位置,配置 Tensor Summary 等等,其实并没有那么简洁。
然而为啥这么多人用 TensorFlow?因为它是 Google 家的,社区庞大,还有一个原因就是 API 你别看比较杂,但是确实比较全,contrib 模块里面你几乎能找到你想要的所有实现,而且更新确实快,一些前沿论文现在基本都已经在新版本里面实现了,所以,它的确是有它自己的优势。
然后再说说 Keras,这应该是除了 TensorFlow 之外,用的第二广泛的框架了,如果你用过 TensorFlow,再用上 Keras,你会发现用 Keras 搭模型实在是太方便了,而且如果你仔细研究下它的 API 设计,你会发现真的封装的非常科学,我感觉如果要搭建一个简易版的模型,Keras 起码得节省一半时间吧。
一个好消息是 TensorFlow 现在已经把 Keras 包进来了,也就是说如果你装了 TensorFlow,那就能同时拥有 TensorFlow 和 Keras 两个框架,哈哈,所以你最后还是装个 TensorFlow 就够了。
还有另一个好消息,刚才我不是吐槽了 TensorFlow 的静态图嘛?这的确是个麻烦的东西,不过现在的 TensorFlow 不一样了,它支持了 Eager 模式,也就是支持了动态图,有了它,我们可以就像写 Numpy 操作一样来搭建模型了,要看某个变量的值,很简单,直接 print 就 OK 了,不需要再去调用各种 run 方法了,可以直接抛弃 Session 这些繁琐的东西,所以基本上和 PyTorch 是一个套路的了,而且这个 Eager 模式在后续的 TensorFlow 2.0 版本将成为主打模式。简而言之,TensorFlow 比之前好用多了!
好,以上说了这么多,我今天的要说的正题是什么呢?嗯,就是我基于 TensorFlow Eager 模式和 Keras 写了一个深度学习的框架。说框架也不能说框架,更准确地说应该叫脚手架,项目名字叫做 ModelZoo,中文名字可以理解成模型动物园。
有了这个脚手架,我们可以更加方便地实现一个深度学习模型,进一步提升模型开发的效率。
另外,既然是 ModelZoo,模型必不可少,我也打算以后把一些常用的模型来基于这个脚手架的架构实现出来,开源供大家使用。
动机
有人说,你这不是闲的蛋疼吗?人家 Keras 已经封装得很好了,你还写个啥子哦?嗯,没错,它的确是封装得很好了,但是我觉得某些地方是可以写得更精炼的。比如说,Keras 里面在模型训练的时候可以自定义 Callback,比如可以实现 Tensor Summary 的记录,可以保存 Checkpoint,可以配置 Early Stop 等等,但基本上,你写一个模型就要配一次吧,即使没几行代码,但这些很多情况都是需要配置的,所以何必每个项目都要再去写一次呢?所以,这时候就可以把一些公共的部分抽离出来,做成默认的配置,省去不必要的麻烦。
另外,我在使用过程中发现 Keras 的某些类并没有提供我想要的某些功能,所以很多情况下我需要重写某个功能,然后自己做封装,这其实也是一个可抽离出来的组件。
另外还有一个比较重要的一点就是,Keras 里面默认也不支持 Eager 模式,而 TensorFlow 新的版本恰恰又有了这一点,所以二者的兼并必然是一个绝佳的组合。
所以我写这个框架的目的是什么呢?
- 第一,模型存在很多默认配置且可复用的地方,可以将默认的一些配置在框架中进行定义,这样我们只需要关注模型本身就好了。
- 第二,TensorFlow 的 Eager 模式便于 TensorFlow 的调试,Keras 的高层封装 API 便于快速搭建模型,取二者之精华。
- 第三,现在你可以看到要搜一个模型,会有各种花式的实现,有的用的这个框架,有的用的那个框架,而且参数、数据输入输出方式五花八门,实在是让人头大,定义这个脚手架可以稍微提供一些规范化的编写模式。
- 第四,框架名称叫做 ModelZoo,但我的理想也并不仅仅于实现一个简单的脚手架,我的愿景是把当前业界流行的模型都用这个框架实现出来,格式规范,API 统一,开源之后分享给所有人用,给他人提供便利。
所以,ModelZoo 诞生了!
开发过程
开发的时候,我自己首先先实现了一些基本的模型,使用的是 TensorFlow Eager 和 Keras,然后试着抽离出来一些公共部分,将其封装成基础类,同时把模型独有的实现放开,供子类复写。然后在使用过程中自己还封装和改写过一些 工具 类,这部分也集成进来。另外就是把一些配置都规范化,将一些常用参数配置成默认参数,同时放开重写开关,在外部可以重定义。
秉承着上面的思想,我大约是在 10 月 6 日 那天完成了框架的搭建,然后在后续的几天基于这个框架实现了几个基础模型,最终打磨成了现在的样子。
框架介绍
GitHub 地址: https://github.com/ModelZoo/ModelZoo
框架我已经发布到 PyPi,直接使用 pip 安装即可,目前支持 Python 3,Python 2 尚未做测试,安装方式:
pip3 install model-zoo
其实我是很震惊,这个名字居然没有被注册!GitHub 和 PyPi 都没有!不过现在已经被我注册了。
OK,接下来让我们看看用了它能怎样快速搭建一个模型吧!
我们就以基本的线性回归模型为例来说明吧,这里有一组数据,是波士顿房价预测数据,输入是影响房价的各个因素,输出是房价本身,具体的数据集可以搜 Boston housing price regression dataset 了解一下。
总之,我们只需要知道这是一个回归模型就好了,输入 x 是一堆 Feature,输出 y 是一个数值,房价。好,那么我们就开始定义模型吧,模型的定义我们继承 ModelZoo 里面的 BaseModel 就好了,实现 model.py 如下:
from model_zoo.model import BaseModel import tensorflow as tf class BostonHousingModel(BaseModel): def __init__(self, config): super(BostonHousingModel, self).__init__(config) self.dense = tf.keras.layers.Dense(1) def call(self, inputs, training=None, mask=None): o = self.dense(inputs) return o
好了,这就定义完了!有人会说,你的 Loss Function 呢?你的 Optimizer 呢?你的 Checkpoint 保存呢?你的 Tensor Summary 呢?不需要!因为我已经把这些配置封装到 BaseModel 了,有默认的 Loss Function、Optimizer、Checkpoint、Early Stop、Tensor Summary,这里只需要关注模型本身即可。
有人说,要是想自定义 Loss Function 咋办呢?自定义 Optimizer 咋办呢?很简单,只需要复写一些基本的配置或复写某个方法就好了。
如改写 Optimizer,只需要重写 optimizer 方法即可:
def optimizer(self): return tf.train.AdamOptimizer(0.001)
好,定义了模型之后怎么办?那当然是拿数据训练了,又要写数据加载,数据标准化,数据切分等等操作了吧,写到什么方法里?定义成什么样比较科学?现在,我们只需要实现一个 Trainer 就好了,然后复写 prepare_data 方法就好了,实现 train.py 如下:
import tensorflow as tf from model_zoo.trainer import BaseTrainer from model_zoo.preprocess import standardize tf.flags.DEFINE_integer('epochs', 100, 'Max epochs') tf.flags.DEFINE_string('model_class', 'BostonHousingModel', 'Model class name') class Trainer(BaseTrainer): def prepare_data(self): from tensorflow.python.keras.datasets import boston_housing (x_train, y_train), (x_eval, y_eval) = boston_housing.load_data() x_train, x_eval = standardize(x_train, x_eval) train_data, eval_data = (x_train, y_train), (x_eval, y_eval) return train_data, eval_data if __name__ == '__main__': Trainer().run()
好了,完事了,模型现在已经全部搭建完成!在这里只需要实现 prepare_data 方法,返回训练集和验证集即可,其他的什么都不需要!
数据标准化在哪做的?这里我也封装好了方法。
运行在哪运行的?这里我也做好了封装。
模型保存在哪里做的?同样做好了封装。
Batch 切分怎么做的?这里也做好了封装。
我们只需要按照格式,返回这两组数据就好了,其他的什么都不用管!
那同样的,模型保存位置,模型名称,Batch Size 多大,怎么设置?还是简单改下配置就好了。
如要修改模型保存位置,只需要复写一个 Flag 就好了:
tf.flags.DEFINE_string('checkpoint_dir', 'checkpoints', help='Data source dir')
好了,现在模型可以训练了!直接运行上面的代码就好了:
python3 train.py
结果是这样子的:
Epoch 1/100 1/13 [=>............................] - ETA: 0s - loss: 816.1798 13/13 [==============================] - 0s 4ms/step - loss: 457.9925 - val_loss: 343.2489 Epoch 2/100 1/13 [=>............................] - ETA: 0s - loss: 361.5632 13/13 [==============================] - 0s 3ms/step - loss: 274.7090 - val_loss: 206.7015 Epoch 00002: saving model to checkpoints/model.ckpt Epoch 3/100 1/13 [=>............................] - ETA: 0s - loss: 163.5308 13/13 [==============================] - 0s 3ms/step - loss: 172.4033 - val_loss: 128.0830 Epoch 4/100 1/13 [=>............................] - ETA: 0s - loss: 115.4743 13/13 [==============================] - 0s 3ms/step - loss: 112.6434 - val_loss: 85.0848 Epoch 00004: saving model to checkpoints/model.ckpt Epoch 5/100 1/13 [=>............................] - ETA: 0s - loss: 149.8252 13/13 [==============================] - 0s 3ms/step - loss: 77.0281 - val_loss: 57.9716 .... Epoch 42/100 7/13 [===============>..............] - ETA: 0s - loss: 20.5911 13/13 [==============================] - 0s 8ms/step - loss: 22.4666 - val_loss: 23.7161 Epoch 00042: saving model to checkpoints/model.ckpt
可以看到模型每次运行都会实时输出训练集和验证集的 Loss 的变化,另外还会自动保存模型,自动进行 Early Stop,自动保存 Tensor Summary。
可以看到这里运行了 42 个 Epoch 就完了,为什么?因为 Early Stop 的存在,当验证集经过了一定的 Epoch 一直不见下降,就直接停了,继续训练下去也没什么意义了。Early Stop 哪里配置的?框架也封装好了。
然后我们还可以看到当前目录下还生成了 events 和 checkpoints 文件夹,这一个是 TensorFlow Summary,供 TensorBoard 看的,另一个是保存的模型文件。
现在可以打开 TensorBoard 看看有什么情况,运行命令:
cd events tensorboard --logdir=.
可以看到训练和验证的 Loss 都被记录下来,并化成了图表展示。而这些东西我们配置过吗?没有,因为框架封装好了。
好,现在模型有了,我们要拿来做预测咋做呢?又得构建一边图,又得重新加载模型,又得准备数据,又得切分数据等等,还是麻烦,并没有,这里只需要这么定义就好了,定义 infer.py 如下:
from model_zoo.inferer import BaseInferer from model_zoo.preprocess import standardize import tensorflow as tf tf.flags.DEFINE_string('checkpoint_name', 'model.ckpt-20', help='Model name') class Inferer(BaseInferer): def prepare_data(self): from tensorflow.python.keras.datasets import boston_housing (x_train, y_train), (x_test, y_test) = boston_housing.load_data() _, x_test = standardize(x_train, x_test) return x_test if __name__ == '__main__': result = Inferer().run() print(result)
这里只需要继承 BaseInferer,实现 prepare_data 方法就好了,返回的就是 test 数据集的 x 部分,其他的还是什么都不用干!
另外这里额外定义了一个 Flag,就是 checkpoint_name,这个是必不可少的,毕竟要用哪个 Checkpoint 需要指定一下。
这里我们还是那数据集中的数据当测试数据,来看下它的输出结果:
[[ 9.637125 ] [21.368305 ] [20.898445 ] [33.832504 ] [25.756516 ] [21.264557 ] [29.069794 ] [24.968184 ] ... [36.027283 ] [39.06852 ] [25.728745 ] [41.62165 ] [34.340042 ] [24.821484 ]]
就这样,预测房价结果就计算出来了,这个和输入的 x 内容都是一一对应的。
那有人又说了,我如果想拿到模型中的某个变量结果怎么办?还是很简单,因为有了 Eager 模式,直接输出就好。我要自定义预测函数怎么办?也很简单,复写 infer 方法就好了。
好,到现在为止,我们通过几十行代码就完成了这些内容:
- 数据加载和预处理
- 模型图的搭建
- Optimizer 的配置
- 运行结果的保存
- Early Stop 的配置
- Checkpoint 的保存
- Summary 的生成
- 预测流程的实现
总而言之,用了这个框架可以省去很多不必要的麻烦,同时相对来说比较规范,另外灵活可扩展。
以上就是 ModelZoo 的一些简单介绍。
愿景
现在这个框架刚开发出来几天,肯定存在很多不成熟的地方,另外文档也还没有来得及写,不过我肯定是准备长期优化和维护下去的。另外既然取名叫做 ModelZoo,我后面也会把一些常用的深度学习模型基于该框架实现出来并发布,包括 NLP、CV 等各大领域,同时在实现过程中,也会发现框架本身的一些问题,并不断迭代优化。
比如基于该框架实现的人脸情绪识别的项目: https://github.com/ModelZoo/EmotionRecognition
其识别准确率还是可以的,比如输入这些图片:
模型便可以输出对应的情绪类型和情绪分布:
Image Path: test1.png Predict Result: Happy Emotion Distribution: {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 1.0, 'Sad': 0.0, 'Surprise': 0.0, 'Neutral': 0.0} ==================== Image Path: test2.png Predict Result: Happy Emotion Distribution: {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.998, 'Sad': 0.0, 'Surprise': 0.0, 'Neutral': 0.002} ==================== Image Path: test3.png Predict Result: Surprise Emotion Distribution: {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Sad': 0.0, 'Surprise': 1.0, 'Neutral': 0.0} ==================== Image Path: test4.png Predict Result: Angry Emotion Distribution: {'Angry': 1.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Sad': 0.0, 'Surprise': 0.0, 'Neutral': 0.0} ==================== Image Path: test5.png Predict Result: Fear Emotion Distribution: {'Angry': 0.04, 'Disgust': 0.002, 'Fear': 0.544, 'Happy': 0.03, 'Sad': 0.036, 'Surprise': 0.31, 'Neutral': 0.039} ==================== Image Path: test6.png Predict Result: Sad Emotion Distribution: {'Angry': 0.005, 'Disgust': 0.0, 'Fear': 0.027, 'Happy': 0.002, 'Sad': 0.956, 'Surprise': 0.0, 'Neutral': 0.009}
如果大家对这个框架感兴趣,或者也想加入实现一些有趣的模型的话,可以在框架主页提 Issue 留言,我非常欢迎你的加入!另外如果大家感觉框架有不足的地方,也非常欢迎提 Issue 或发 PR,非常非常感谢!
最后,如果你喜欢的话,还望能赠予它一个 Star,这样我也更有动力去维护下去。
项目的 GitHub 地址: https://github.com/ModelZoo/ModelZoo 。
谢谢!
以上所述就是小编给大家介绍的《Python 深度学习脚手架 ModelZoo》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First JavaScript程序设计
[美]Eric T. Freeman、[美] Elisabeth Robson / 袁国忠 / 人民邮电出版社 / 2017-9 / 129.00 元
本书语言和版式活泼,内容讲解深入浅出,是难得的JavaScript入门书。本书内容涵盖JavaScript的基本知识以及对象、函数和浏览器文档对象模型等高阶主题。书中配备了大量有趣的实例、图示和练习,让读者轻轻松松掌握JavaScript。一起来看看 《Head First JavaScript程序设计》 这本书的介绍吧!