使用多种工具组合进行分布式超参数优化

编译:yxy

出品:ATYUN订阅号

在这篇文章中,我介绍如何使用工具组合来加速超参数优化任务。这里提供了Ubuntu的说明,但可以合理地应用于任何*nix系统。

什么是超参数优化?

超参数优化(HO)是一种为机器学习任务选择最佳参数的方法。这些参数包括:

  • 层数
  • 学习率
  • 批量大小
  • 层的类型
  • Dropout
  • 优化算法(SGD,Adam,rmsprop等)

对于任何给定的问题,什么样的网络配置最适合于给定的任务可能不那么明显,因此我们可以使用超参数优化,通过智能地迭代你想要优化的参数的搜索空间来为我们决定。Hyperopt使用Tree-Structure Parzen估计器,非常擅长快速确定最佳参数集。它的工作原理是运行和评估模型,返回损失分数,然后运行另一个参数略有不同的模型,旨在最大限度地减少误差分数。对你来说困难的部分是为你的问题设计一个搜索空间,这可能非常大。为了节省时间,我们可以在任意数量的机器上同时运行这些模型,甚至让每台机器运行多个模型(前提是它有足够的内核)。

幸运的是,有些python库可以帮助我们完成所有这些工作!

要求

你会需要:

  • 安装了以下Python包
    • theano,tensorflow或tensorflow-gpu
    • hyperopt
    • hyperas
    • pymongo
    • PSSH
  • 安装了以上所有的几台机器
  • 一个带有jobs数据库的Mongodb实例

我强烈建议使用pyenv来使用最新版本的python,并防止我们安装的包与系统包冲突。如果你可以访问所有计算机可用的网络驱动器,请设置$PYENV_ROOT为这些计算机所有文件都可见(或至少在所有计算机上都有一个公共路径)。安装所用的库(你可以使用你想要使用的任何keras后端交换tensorflow,如theano tensorflow-gpu tensorflow cntk):

export PYENV_ROOT="$HOME/.pyenv"
curl-L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
echo'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
echo'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
sudo apt install-y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev
env PYTHON_CONFIGURE_OPTS="--enable-shared" MAKEOPTS="-j 8" pyenv install3.6.5
pyenv local3.6.5
pip install tensorflow git+https://github.com/hyperopt/hyperopt git+https://github.com/maxpumperla/hyperas keras pssh matplotlib h5py pymongo

你现在将拥有一个自包含的python安装在$HOME/.pyenv/versions/3.6.5。请记住,它需要构建一个python安装,因此可能需要一段时间。你可以将~/.pyenv文件夹复制到要运行的任何计算机上。只需记住将你的~/.bash_profile(或其他与此相同的)复制到你想要作为“工作者”的每台机器上。

代码

我们还需要选择一项优化任务!Hyperas使用模板生成hyperopt可以使用的代码,因此你需要严格遵循这个模板。创建一个名为optimise_task.py的文件。我们将找到单层稠密网络的最佳的层数和dropout参数(在搜索空间内,参见l1_size和l1_dropout变量)来解决MNIST任务。不同参数分布的文档在这里:

https://github.com/hyperopt/hyperopt/wiki/FMin#21-parameter-expressions

为达到我们的目的:

  • quniform是具有给定间隔和步长的离散值的正态分布。在我们的示例中,它将返回范围[12,256]中的浮点数,step=4
  • uniform是连续值的正态分布

Hyperas.distributions中提供了更多可用的分布:https://github.com/maxpumperla/hyperas/blob/master/hyperas/distributions.py

from hyperasimport optim
from hyperas.distributionsimport quniform, uniform
from hyperoptimport STATUS_OK, tpe, mongoexp
import keras
from keras.layersimport Dense, Dropout
from keras.modelsimport Sequential
from keras.optimizersimport RMSprop
from keras.datasetsimport mnist
import tempfile
from datetimeimport datetime


def data():
    (x_train, y_train), (x_test, y_test)= mnist.load_data()
    x_train= x_train.reshape(60000,784)
    x_test= x_test.reshape(10000,784)
    x_train= x_train.astype('float32')
    x_test= x_test.astype('float32')
    x_train/= 255
    x_test/= 255
    num_classes= 10
    y_train= keras.utils.to_categorical(y_train, num_classes)
    y_test= keras.utils.to_categorical(y_test, num_classes)
    return x_train, y_train, x_test, y_test


def create_model(x_train, y_train, x_test, y_test):
    """
    Create your model...
    """

    l1_size= {{quniform(12,256,4)}}
    l1_dropout= {{uniform(0.001,0.7)}}

    params= {
        'l1_size': l1_size,
        'l1_dropout': l1_dropout
    }
    num_classes= 10
    model= Sequential()
    model.add(Dense(int(l1_size), activation='relu'))
    model.add(Dropout(l1_dropout))
    model.add(Dense(num_classes, activation='softmax'))
    model.compile(loss='categorical_crossentropy',
                  optimizer=RMSprop(),
                  metrics=['accuracy'])
    start= datetime.now()
    model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test))
    score, acc= model.evaluate(x_test, y_test, verbose=0)
    out= {
        'loss':-acc,
        'score': score,
        'status': STATUS_OK,
        'duration': (datetime.now()- start).total_seconds(),
        'ho_params': params,
        'model_config': model.get_config()
    }
    # optionally store a dump of your model here so you can get it from the database later
    temp_name= tempfile.gettempdir()+'/'+next(tempfile._get_candidate_names())+ '.h5'
    model.save(temp_name)
    withopen(temp_name,'rb') as infile:
        model_bytes= infile.read()
    out['model_serial']= model_bytes
    return out


if __name__== "__main__":
    trials= mongoexp.MongoTrials('mongo://username:pass@mongodb.host:27017/jobs/jobs', exp_key='mnist_test')
    best_run, best_model= optim.minimize(model=create_model,
                                          data=data,
                                          algo=tpe.suggest,
                                          max_evals=10,
                                          trials=trials,
                                          keep_temp=True) # this last bit is important
    print("Best performing model chosen hyper-parameters:")
    print(best_run)

请注意实验密钥的名称:mnist_test,这将是mongodb中jobs数据库的jobs集合的密钥。每个模型完成后,它将存储在mongodb中。可以将权重存储在输出文档中(输出model.get_weights(),但是mongodb每个文档的限制为4MB。为了解决这个问题,GridFS用于在模型本身的数据库中临时存储blob。

我也将持续时间存储在result对象中,因为你可能会发现两个损失非常相似的模型,但损失稍微好一些的模型可能会有更高的运行时间。

运行

运行它有两个部分:

  1. 试验控制器,它决定每个模型运行时将使用的参数
  2. 实际运行单个模型的工作者

调节器

从计算机运行它(它必须在所有jobs运行时处于活动状态):

python optimise_task.py

你应该得到一个调用的输出文件temp_model.py(如果你没有,请确保你已经更新到github的最新hyperas代码)。确保该文件对工作者可见。

工作者

工作者是你的所有其他机器(也可能包括控制器机器)。确保你安装了pyenv,只需压缩.pyenv文件夹并将其复制到工作机器上的主目录并解压即可。这样你就不会错过任何依赖。

运行以下命令:

mkdir hyperopt_job
touch hyperopt_job/job.sh
chmod+x hyperopt_job/job.sh

将temp_model.py文件复制到hyperopt_job文件夹中( ~/hyperopt_job/job.sh):

#!/bin/bash
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
export PYTHONPATH=~/hyperopt_job/
cd ~/hyperopt_job
pyenv local3.6.5
hyperopt-mongo-worker--mongo="mongo://username:password@mongodb.host:27017/jobs" --exp-key=mnist_test

现在你可以在你的工作机器上运行~/hyperopt_job/job.sh了!请记住,他们需要能够访问mongodb。工作者继续运行,直到你达到max_evals末尾定义的optimise_task.py。

如果.pyenv文件夹还不存在,您还可以让该脚本从URL中获取压缩版本的.pyenv文件夹,方法是在脚本前加上如下内容:

if [ !-d"$HOME/.pyenv" ]; then
    wget https://url.to/mypenv.zip
    unzip mypyenv.zip
fi

如果工作者计算机上的主驱动器空间有限,请考虑解压缩到tmp目录并设置相应地PYENV_ROOT环境变量。

你可能需要:

  • 通过ssh或常规登录登录计算机
  • 开始屏幕
  • 启动脚本

我们可以通过使用pssh对给定主机列表自动执行上述操作来做得更好。

pssh-h hosts.txt  bash-c"nohup  ~/hyperopt_job/job.sh &"

结果

完成所有工作后,你可以使用mongodb浏览器(如Robo3T)查看结果。下面一个小脚本,用于从数据库中获取具有最低损失分数的模型并反序列化你的模型:

from pymongoimport MongoClient, ASCENDING
from keras.modelsimport load_model
import tempfile
c= MongoClient('mongodb://username:pass@mongodb.host:27017/jobs')
best_model= c['jobs']['jobs'].find_one({'exp_key':'mnist_test','result.status':'ok'}, sort=[('result.loss', ASCENDING)])
temp_name= tempfile.gettempdir()+'/'+next(tempfile._get_candidate_names())+ '.h5'
withopen(temp_name,'wb') as outfile:
    outfile.write(best_model['result']['model_serial'])
model= load_model(temp_name)
# do things with your model here
model.summary()

你可以使用以下代码将搜索空间子集的结果可视化(具有2个以上参数的典型搜索空间,因此可能并不清楚哪一个(或哪个组合)对你的模型性能影响最大):

from collectionsimport defaultdict
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from pymongoimport MongoClient
import numpy as np

if __name__== "__main__":
    # get the data
    jobs= MongoClient('mongodb://username:pass@mongodb.host:27017/jobs')['jobs']['jobs']
    cursor= jobs.find({'exp_key':'mnist_test','result.status':'ok'})
    results= defaultdict(lambda: defaultdict(list))
    fig= plt.figure()
    ax= fig.add_subplot(111, projection='3d')
    for iin ax.get_xticklabels():
        i.set_rotation(90)

    for rowin cursor:
        cc= row['tid']
        results[cc]['x'].append(row['result']['loss'])
        results[cc]['y'].append(row['result']['ho_params']['l1_size'])
        results[cc]['z'].append(row['result']['ho_params']['l1_dropout'])

    colors= cm.rainbow(np.linspace(0,1,len(results)))
    it= iter(colors)
    for k, vin results.items():
        ax.scatter(v['x'], v['y'], v['z'], label=k, color=next(it))
    ax.set_xlabel('RMSE')
    ax.set_ylabel('Layer Count')
    ax.set_zlabel('L1 Size')
    plt.title("Hyperparameter Optimisation Results")
    plt.show()

下面是我的一个实验的输出,正如你所看到的,优化器可以快速找到聚集在给定搜索空间的最小可实现错误评分附近的模型:

原文发布于微信公众号 - ATYUN订阅号(atyun_com)

原文发表时间:2018-08-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

Tensorboard入门 | TensorFlow深度学习笔记

Tensorboard是TensorFlow自带的一个强大的可视化工具 01 功 能 这是TensorFlow在MNIST实验数据上得到Tensorboard...

42850
来自专栏ATYUN订阅号

防止在训练模型时信息丢失 用于TensorFlow、Keras和PyTorch的检查点教程

如果你玩过电子游戏,你就会明白为什么检查点(chekpoint)是有用的了。举个例子,有时候你会在一个大Boss的城堡前把你的游戏的当前进度保存起来——以防进入...

65350
来自专栏CreateAMind

开源|MultiNet模型解决Kitti数据集自动驾驶中的道路分割、车辆检测和街道分类(附源代码)

MultiNet能够同时完成道路分割、汽车检测和道路分类的任务。MultiNet模型的实时存档速度和分割性能都处于最先进水平。详细的模型描述请查阅我们的论文。

32330
来自专栏SIGAI学习与实践平台

编写基于TensorFlow的应用之构建数据pipeline

本文主要以MNIST数据集为例介绍TFRecords文件如何制作以及加载使用。所讲内容可以在SIGAI 在线编程功能中的sharedata/intro_to_t...

13820
来自专栏梦里茶室

TensorFlow 深度学习笔记 逻辑回归 实践篇

Practical Aspects of Learning Install Ipython NoteBook 可以参考这个教程 可以直接安装anaconda,里...

22770
来自专栏小巫技术博客

A008-drawable资源

关于drawable资源笔者之前有写过两篇文章: Android-自定义图像资源的使用(1) Android-自定义图像资源的使用(2) 这里笔者就不做过多的赘...

9020
来自专栏简书专栏

基于tensorboard的模型训练过程可视化

2018年9月14日笔记 阅读本文的前提是已经阅读《基于tensorflow的一元二次方程回归预测》,文章链接:https://www.jianshu.com...

26630
来自专栏racaljk

2017第八届蓝桥杯决赛(C++ B组)4.发现环

小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。 不过在最...

27440
来自专栏云计算教程系列

如何在Ubuntu 14.04第2部分上查询Prometheus

Prometheus是一个开源监控系统和时间序列数据库。在如何在Ubuntu 14.04第1部分中查询Prometheus,我们设置了三个演示服务实例,向Pro...

12300
来自专栏专知

【前沿】Pytorch开源VQA神经网络模块,让你快速完成看图问答

【导读】近期,NLP专家Harsh Trivedi使用Pytorch实现了一个视觉问答的神经模块网络,想法是参考CVPR2016年的论文《Neural Modu...

30680

扫码关注云+社区

领取腾讯云代金券