Parris:机器学习算法自动化训练工具

Parris 是一个自动化训练机器学习算法的工具。如果各位读者经常需要构建并训练机器学习模型,且花费很多时间来设置运行服务器,使用远程登录服务以监控进程等。那么这个工具将对大家十分有帮助,甚至我们都不需要使用 SSH 访问服务器以完成训练。机器之心简要介绍了该工具,更详细的内容请查看该 GitHub 项目。

项目地址:https://github.com/jgreenemi/Parris

安装

我们需要一个 AWS 账户,并将 AWS 证书加载到工作站中(通过 $ aws configure 配置),我们还需要构建好的机器学习算法和数据集。此外,我们还需要一个 S3 存储体(bucket)或其它存储位置来存储算法的训练结果。

UNIX/Linux:

$ git clone https://github.com/jgreenemi/parris.git && cd parris
$ virtualenv -p python3 env
$ source env/bin/activate
(env) $ pip --version
pip 9.0.1 from .../env/lib/python3.6/site-packages (python 3.6)
(env) $ pip install -r requirements.txt 

Windows:

$ git clone https://github.com/jgreenemi/parris.git && cd parris
$ virtualenv -p python3.exe env
$ env\Scripts\activate
(env) $ pip --version
pip 9.0.1 from ...\python\python36\lib\site-packages (python 3.6)
(env) $ pip install -r requirements.txt

以上是简要的安装过程,后一部分我们将具体讨论如何使用 Parris,具体包括从配置环境到登录第一个机器学习训练堆栈的所有过程。当我们熟悉了这个工具后,我们可以查看该工具的配置参数,以理解更多的操作选项。参数配置与入门指导将共同帮助读者全面了解这个强大的工具。

此外,目前 FAQ 页面已经有很多关于该工具的问题。如果该文档没包含读者出现的问题,那么我们可以选择提交 GitHub Issue,这样其它读者就能查阅该问题与解答。

  • 入门指导地址:https://github.com/jgreenemi/Parris/blob/master/docs/GETTING-STARTED.md
  • 参数配置指导地址:https://github.com/jgreenemi/Parris/blob/master/docs/CONFIGURATION.md
  • 常见 FAQ 地址:https://github.com/jgreenemi/Parris/blob/master/docs/FAQ.md

开始使用 Parris


我们将介绍如何只用很简单的点击操作、命令行和脚本,就可以开始运行训练任务。

概览

Parris 的功能有:

  • 创建一个 Lambda 函数
  • 在调用 Lambda 函数的时候运行一个 CloudFormation 堆栈
  • 第一次运行时,在堆栈的 EC2 实例上运行一个 UserData 脚本,以启动训练过程
  • 训练完成的时候停止 EC2 实例

建立这个工具的目的在于减少训练机器学习算法过程中重复乏味的环境配置,同时通过更高效地利用服务器的运算时数以节省计算成本(服务器一旦启动就会立刻开始训练,并会按照你的配置停止训练)。

预备工作

请按照 README 中的说明进行设置,我们需要的是一个机器学习算法、可用的数据集,和一个用于启动训练过程的 Bash 脚本。

我将给出一个示例训练器脚本(trainer-script),以帮助你更好地理解使用细节。

关于训练结果提取的注意事项

训练器脚本或算法本身需要将其训练结果输出到外部(如另一个服务器、一个 S3 bucket,等)。CloudFormation 堆栈在训练结束之后会立即终止,从而其中的训练结果也将很快被删除。毕竟我们并不推荐在该服务器上保存任何时段的训练结果。

0. 准备配置

经过合适的设置之后,使用该工具的主要操作在于编辑 training-config.json 配置文件以及实际运行训练过程的 trainer-script.sh 脚本。由于是第一次进行设置,你还需要设置 lambda-config.json 配置文件(这个很简单,只需要写两行,每行是一个可选项)。

这里提供的配置是一个使用了我的 GitHub repo 之一的基础训练任务示例,以使你更好地理解。除了一些账户相关的设置如 IAM role 的 ARN 值和 S3 bucket 名,其它可以按原样直接运行。

1. 在 training-config 中:

  • 将 subnet-id 改写为你的 Subnet 之一的 ID(如果这里不理解,请先在你的 AWS 账户上设置 VPC、Subnet、Security Group 和 EC2 Keypair。如果你是第一次使用 AWS,在你的账户中会有一些默认的资源)。
  • 将 security-group-id 改写为你的 VPC 中的一个 Security Group。
  • 将 ec2-keypair-name 改写为你的一个 EC2 密匙对。
  • 将 instance-type 改写为 t2.micro 或另一种小型实例类型。由于运行这个堆栈仅仅是为了教学目的,我们希望使用计算成本更低的实例类型,并快速结束任务。t2.micro 是满足这一目的的最重要的一步。

         可以通过查看 AWS Simple Monthly Calculator 评估特定实例类型(如 EC2)的计算成本。

  • 所有其它的 training-config 参数可以保持不变,除非必要。可以查看 CONFIGURATION 文档了解各个参数的作用。

2. 在 lambda-config.json 中:

  • 将 lambda-role-arn 更新为你的一个 IAM role 的 ARN 值(如果这里不理解,可以查看以下亚马逊文档)。

Lambda IAM Execution Role 向导: http://docs.aws.amazon.com/lambda/latest/dg/with-s3-example-create-iam-role.html

在设置 IAM Role 的时候,你需要将一个或多个 Policy 附加于 Role 上以定义 Lambda 函数可以访问的一切。以下是我使用的案例,可以使 Lambda 函数启动一个新的 CloudFormation 堆栈、从 S3 bucket 中获取对象,以及对 EC2 实例进行大量运算:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:UpdateStack",
                "cloudformation:ValidateTemplate",
                "ec2:DetachVolume",
                "ec2:AttachVolume",
                "ec2:ModifyVolume",
                "ec2:ModifyVolumeAttribute",
                "ec2:DescribeInstances",
                "ec2:TerminateInstances",
                "ec2:DescribeTags",
                "ec2:CreateTags",
                "ec2:DescribeVolumesModifications",
                "ec2:RunInstances",
                "ec2:StopInstances",
                "ec2:DescribeVolumeAttribute",
                "ec2:CreateVolume",
                "ec2:DeleteVolume",
                "ec2:DescribeVolumeStatus",
                "ec2:StartInstances",
                "ec2:DescribeVolumes",
                "ec2:ModifyInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "s3:GetObject"
            ],
            "Resource": "*"
        }
    ]
}

我强烈推荐(虽然不是必要的)使用一个 Policy 以允许将 Lambda 函数写到一个 CloudWatch logstream 上。当 Lambda 函数出错的时候,可以通过读取日志查找错误。以下是我使用的在一个 Policy 上所有的 CloudWatch Write 许可,这使得可视化编辑器的设置变得非常简单:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:DeleteSubscriptionFilter",
                "logs:DeleteLogStream",
                "logs:CreateExportTask",
                "logs:DeleteResourcePolicy",
                "logs:CreateLogStream",
                "logs:DeleteMetricFilter",
                "logs:TagLogGroup",
                "logs:CancelExportTask",
                "logs:DeleteRetentionPolicy",
                "logs:GetLogEvents",
                "logs:AssociateKmsKey",
                "logs:FilterLogEvents",
                "logs:PutDestination",
                "logs:DisassociateKmsKey",
                "logs:UntagLogGroup",
                "logs:DeleteLogGroup",
                "logs:PutDestinationPolicy",
                "logs:TestMetricFilter",
                "logs:DeleteDestination",
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "logs:PutMetricFilter",
                "logs:PutResourcePolicy",
                "logs:PutSubscriptionFilter",
                "logs:PutRetentionPolicy"
            ],
            "Resource": "*"
        }
    ]
}

最后,我们需要设置 trainer-script.sh,从而切实运行训练过程。这一部分几乎完全由你自己编写,因为你的算法依赖项和输出训练结果的方法和我的示例将是不同的。

1. 在 trainer-script.sh 中:

  • 记住你的训练脚本是在一个新的服务器上运行的,因此关于依赖项、目录结构等所有设置都需要在训练开始前搞定。例如,如果你使用的是不同版本的 Python 或者需要复制一个 GitHub repo,确保写入这些步骤。

一旦完成以上步骤,基本上就可以开始使用这个工具了。如果你没有在 lambda-config.json 中使用 s3-training-bucket 值,那你就可以进行下一步了。如果你使用 S3 bucket 进行加载配置,你需要在 S3bucket 中加载以下的文件,命令的结构如下所示(没有写特定的目录或文件名)。

+---your-s3-bucket|   \---trainer-script.sh|   \---training-config.json|   \---lambda-config.json

完成之后,就可以进行下一步了。

1. 准备 Lambda 函数

在开始训练之前,我们需要一种开启方式,此时就需要 Lambda 配置。这一步需要你创建一个 AWS Lambda 函数,该函数可用于同一个算法的多个训练工作,或者不同算法的多个训练工作。

1. 在 Parris 包 root 中,激活 virtualenv。

2. 使用 $ python setup.py 创建 Lambda 函数

       a. 如果已经有 Lambda 函数,这一步将更新其代码包。

3. 如果一切顺利,则日志将输出配置用的 ARN 值。

2. 登录我们的第一个训练堆栈

注意,第一步可能需要付费,所以先确保你需要这个工具并在开始前先通读本文档,尤其是后面的第四步。

1. 打开 AWS 控制台并导航到你的 Lambda 函数。

2. 点击页面顶部的「Test」按钮,并手动调用函数。如果你并没有配置好的测试,那么就需要完成以下步骤:

  • 在 Saved Test Events 的 Test 按钮旁边的下拉菜单,点击「Configure test events」以创建一个新的。
  • 因为 Lambda 函数只有一个活动进程(即在调用时登录到一个新的 CloudFormation 堆栈),我们并不需要传递任何的参数(即使传递到 Lambda 的参数被接收了,那也不会使用)。
  • 创建一个名为 Parris-Test-Event、内容为 {} 的事件作为测试,并点击保存。
  • 在关闭创建对话框后,点击下拉菜单中新 Test Event 内的 Test 按钮,并等待用来更新的执行结果。

3. 当你的函数已经运行,执行结果应该出现「succeeded」,并输出 {}。

  • 如果函数报错,那么需要从执行结果定位错误地址。一般而的报错很可能是因为 Lambda 函数的 IAM 角色中缺少 IAM 许可。

4. 切换到 AWS 控制台的 CloudFormation 试图,并查看是否登录了新的 CloudFormation 栈。这大概只需要 1 到 2 分钟,但很依赖于我们登录的实例(Instance)。

  • 看不到你的 CloudFormation 栈?确保你在正确的区域。
  • 注意堆栈的名字应该匹配训练项目的名,即我们在 training-config.json 配置的名字。如果处于某些原因你们并没有配置训练项目名,那么栈的名字应该采用默认名「parris-stack」。

5. 切换到 AWS 控制台的 EC2 实例视图,以查看你登录的新实例。它应该处于「Running」状态,并运行你的训练项目。

注意,在该版本的工具中,CloudFormation 栈在完成训练后并不会终止。相反,EC2 实例将自行关闭。由于实例不再运行,因此我们能节省额外的成本。但若是要删除它,我们需要导航回控制台的 CloudFormation 视图,并点击下拉 Action 中删除堆栈的选项。

3. 获取训练结果

获取训练结果主要依赖于如何设置算法来保存结果参数。大多数情况下这些结果将保存至本地文件夹(即服务器的某处,可能在训练过程的包中)。但是,由于我们在该指南结束时需要终止该堆栈,因此我们想将它们挪到一个更永久的位置。

4. 终止 CloudFormation 栈

现在你已经创建了 CloudFormation 栈,并确认它按照预期工作,那么我们可以安全地终止该栈,以节省开销。

  • 1. 打开 AWS 管理控制台,导航至 CloudFormation 视图。
  • 2. 从列表中选择你安装的 CloudFormation 栈。
  • 3. 点击页面顶部的 Actions 下拉菜单,点击 Delete Stack。网页会询问是否确认删除,点击 Delete。
  • 4. 查看该栈的 Events 标签(页面底部)来追踪进程。你必须刷新该页面才能添加新的事件。
  • 5. CloudFormation 栈终止后,将从列表中消失。你可以点击列表左上角,将视图的 Filter 从 Active 更改至 Deleted,来确认是否已删除。查看该栈的当前名称,状态为「DELETE_COMPLETE」。那么此时你不需承担该训练资源所需的任何开销。

一般而言,你应该在每次训练工作完成时终止 CloudFormation 栈。尽管你可以更新 CloudFormation 栈,但该工具的运行原理是:训练工作被 EC2 实例上的 UserData 脚本启动,该脚本仅在该实例首次安装时运行。更新 CloudFormation 栈无法重新安装该实例(除少数环境),这取决于栈被更新的参数。大多数情况下,该实例可以停止再重新开始,但这不足以重新启动训练工作。由于终止和安装新实例与更新原有的实例相比,不需要额外的开销,因此算法训练最佳实践是终止栈,然后在需要重新训练时重新安装栈。

5. 更新 Lambda 函数

更新 Lambda 函数和在 lambda-function.py 文件中做出改变一样简单,重新运行$ python setup.py。脚本首先尝试创建 Lambda 函数,如果创建失败出现函数中已经存在的错误,则脚本将运行函数代码的更新版。

注意 Lambda 函数配置的特定细节(即内存)不要被脚本更新,你需要向脚本添加额外的逻辑来更新函数元数据,或删除原来的函数,使用更新后的元数据重新创建 Lambda 函数。原因在于 Lambda 函数有多种更新方式,没有一种方法能够覆盖所有场景,所以我提出一种最可能立即得到使用的方式。未来该工具可能包括覆盖所有场景的额外更新行为。

你可以通过以下方式测试更新行为:

1. 打开 lambda-function.py,定位至第 272 行 return return-values 语句。

2. 在返回语句上面插入新的一行,如下:

logging.warning('This is a synthetic warning message!')
   
   return return_values

 i. 任意信息在这里都可以运行,它可以出现在函数的大多数地方。只要我们更改代码,就可以展示更新后的 Lambda 函数。

3. 一旦作出更改,只需再次运行 $ python setup.py,查看更新 ARN 的日志记录输出。

4. 使用 Test 按钮再次启动 Lambda 函数,展开 Execution Result。日志输出框应该包括 Lambda 函数通常的日志输出,上面的应该是测试信息。

5. 确保终止 CloudFormation 栈,以节约成本。

6. 更新训练栈

更新 CloudFormation 栈的功能有限,因为 CloudFormation 栈不强制重启训练。因此,不推荐更新 CloudFormation 栈,需要重新训练时可以删除再重新安装 CloudFormation 栈。

7. 在 AWS 管理控制台之外开始训练

此时你已经完成了 Parris 的一般步骤!之后的工作更多地是为了更方便地使用该工具。我们的第一个示例是设置一个 IoT 设备以便根据需求开启新的训练工作。更多示例将包括设置常规重新训练的时间表(即针对你的应用依赖于需要在新数据集上重新训练的算法,才能保持有效)。

入门
1
暂无评论
暂无评论~