【机器学习学习笔记】思考机器学习在基础设施方面能做的事情
首先
总结一下我为了获得AWS机器学习专家认证所学到的内容。
我会结合实践,对机器学习的构建进行描述。
为了减少构建过程中的工作时间,我努力进行自动化。
机器学习的过程
首先,我們將總結機器學習的主要任務。在這篇文章中,我們將特別關注基礎設施相關的內容。
– 标注
调整数据,以便在推理和学习等任务中更方便地使用。
为数据添加标签,用于分类模型。
存储和处理大量数据。
考虑开发模型并编写代码。
准备编写代码所需的工具。
为执行工具准备资源。
使用大量数据进行学习。
通过重复学习来提高。
对资源进行调整优化。
将已经训练好的模型转换为用于推理的模型。
使用已经训练好的模型进行部署和应用。
在机器学习中,我认为准备数据并将模型训练到目标精度非常重要。因此,我想不会想在其他事情上费心。因此,我会考虑在基础设施方面是否可以实现自动化和节省时间。
※仅提供一种中文翻译选项:
※ 参考
思考基础设施能够实现的事情。
在建立方面进行实践。
自动化以前使用IaC手动完成的任务。
我会思考如何建立服务器。虽然不想花费太多时间,但是由于需要按照现有环境来进行,我认为这会很困难。因此,我希望借鉴经验,并将已经完成的事情自动化,使得操作更加轻松。这次我将进行以下事项。
・使用CloudFormation创建服务器。
・从shell文件构建k8s。
・使用k8s清单文件创建容器注册表。
使用CloudFormation创建服务器。
接下来,我们将进行以下实践。
虽然CloudFormation的基本原理与过去相同,但我们增加了EC2实例的容量。这是因为未来我们将使用更大的容器镜像。
Resources:
ec2:
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: t2.medium
KeyName: <key-name>
ImageId: ami-02892a4ea9bfa2192
NetworkInterfaces:
- AssociatePublicIpAddress: 'true'
DeviceIndex: '0'
SubnetId: !Ref <public-subnet>
GroupSet:
- !Ref <security-group>
BlockDeviceMappings:
- DeviceName: "/dev/xvda"
Ebs:
VolumeSize: 20
VolumeType: "gp2"
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-ec2'
使用shell脚本进行k8s的构建。
我会在EC2上创建一个k8s环境。由于在之前的文章中已经介绍过,所以我们将采用相同的方法。如果是第一次创建k8s环境,您需要查找官方页面等来进行错误处理。在本文中,我们将以shell文件的形式重新使用之前文章中的内容。
从k8s的清单文件创建容器注册表。
我们将通过后述的方式推送图像以创建POD。为此,我们将创建一个容器注册表。虽然有很多方法可供选择,但这次我们将在本地创建。如果本地有k8s环境,可以使用容器快速准备。有对应的容器镜像可供使用,只需使用它即可。这次我们将它作为POD创建。
先创建一个适用于POD的命名空间。
kind: Namespace
apiVersion: v1
metadata:
name: myns
kubectl apply -f namespace.yaml
POD的yaml配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: myns
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: docker.io/registry:2.8.1
volumeMounts:
- name: registry-config
mountPath: /etc/docker/registry
- name: registry-storage
mountPath: /var/lib/registry
- name: registry-ui
image: docker.io/joxit/docker-registry-ui:2.2.1
envFrom:
- configMapRef:
name: registry-ui-config
volumes:
- name: registry-config
configMap:
name: registry-config
- name: registry-storage
hostPath:
path: /home/ec2-user/registry
type: DirectoryOrCreate
以下将详细介绍有关yaml配置的内容。
・货运集装箱
・音量
使用ConfigMap来配置容器注册表。以下是ConfigMap的yaml文件。
apiVersion: v1
kind: ConfigMap
metadata:
name: registry-config
namespace: myns
data:
config.yml: |
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ['*']
Access-Control-Allow-Headers: ['*']
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
---
apiVersion: v1
kind: ConfigMap
metadata:
name: registry-ui-config
namespace: myns
data:
REGISTRY_URL: http://localhost:30500
REGISTRY_TITLE: "local registry"
URL和端口将在后面总结。
使用创建的yaml文件创建POD。
创建后,尝试从浏览器访问容器注册表。
因为还没有推送容器镜像,所以没有显示任何内容。如果已经推送并且注册表的 POD 发生故障,Deployment 会重新启动 POD,并加载本地保存的镜像。
使用Jupyter容器映像来节省安装的麻烦。
为了编写代码,我们首先要准备Jupyter。由于容器映像与容器注册表一样是公开的,我们可以使用它。
接下来,我们要创建一个用于运行Jupyter的POD的yaml文件。只需在Deployment中指定Jupyter映像即可完成。
apiVersion: apps/v1
kind: Deployment
metadata:
name: jupyter
namespace: myns
spec:
replicas: 1
selector:
matchLabels:
app: jupyter
template:
metadata:
labels:
app: jupyter
spec:
containers:
- name: jupyter
image: docker.io/jupyter/base-notebook:python-3.10.4
我会创建一个 POD 并尝试从浏览器进行访问。
要首次访问 Jupyter,您需要一个令牌,可以从启动日志中确认。
$ JUPYTER_POD=`kubectl get pod -n myns | grep jupyter | awk '{print $1}'`
$ kubectl logs -n myns $JUPYTER_POD
・・・
To access the server, open this file in a browser:
file:///home/jovyan/.local/share/jupyter/runtime/jpserver-7-open.html
Or copy and paste one of these URLs:
http://jupyter-7f5b78d4cf-qjbhb:8888/lab?token=<token>
or http://127.0.0.1:8888/lab?token=<token>
・・・
我能够访问。
我是第一次使用。可以执行脚本和使用Markdown呢。
※仅需一个翻译选项,以下是参考翻译:
请提供以下内容的中文本地化翻译。
※参考
为了对数据进行整理,准备使用Fluentd。
我们要考虑如何准备学习和推理所需的数据。我们考虑对数据进行以下处理:
· 整形:将数据转换为可处理的格式。
· 分类:对数据进行加工并打上标签。
· 过滤:剔除不需要的数据。
因为有Fluentd这种方法来实现这些,所以我会尝试制作。另外,由于创建Fluentd的配置文件很困难,为了减轻负担,我也会尝试使用Fluentd的图形用户界面功能。
首先,创建容器镜像。
执行以下命令。
#!/bin/bash -ex
REGISTRY_HOST='localhost:30500'
echo 'install git'
sudo yum install git -y
echo 'build fluentd-ui'
COMMIT_ID='d48d672ebc505b7a2ac4ff35afdbb8f843a62ef3'
FLUENTD_UI_VERSION='v1.2.2'
LOCAL_REPO_DIR="$HOME/fluentd-ui"
git clone https://github.com/fluent/fluentd-ui.git $LOCAL_REPO_DIR
cd $LOCAL_REPO_DIR
git checkout $COMMIT_ID
IMAGE=$REGISTRY_HOST/fluent/fluentd-ui:$FLUENTD_UI_VERSION
sudo docker build -t $IMAGE $LOCAL_REPO_DIR
sudo docker push $IMAGE
以下是正在进行的工作:
– 安装git
– 克隆包含用于构建的源文件的git仓库
– 构建并推送fluentd-ui
由于容器注册表使用Service并使用端口30500,因此在构建和推送时需要进行相应的指定。详细信息将在后续说明。
创建一个使用push的镜像来创建Fluentd的POD的yaml文件。
apiVersion: apps/v1
kind: Deployment
metadata:
name: fluentd
namespace: myns
spec:
replicas: 1
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
containers:
- name: fluentd
image: localhost:30500/fluent/fluentd-ui:v1.2.2
POD创建后,我们将尝试通过浏览器进行访问。
初始登录信息如下:
– 账户名:admin
– 密码:changeme
我能够访问。
从浏览器上看,似乎可以编辑设置文件和查看日志。
还可以将Fluentd、Elasticsearch和Kibana结合起来,以便进行数据图表和搜索等操作。
准备使用Jenkins来管理处理的进展。
想象一下学习的时候,可能需要使用大量数据进行长时间的处理。如果能够自动化这个过程,我认为开发者的负担将会减轻。
在Jenkins中,您可以实现以下功能:
•将一段代码整理为工作任务,可以定期反复执行。
•拥有GitHub插件,可以更方便地管理源代码。
•具备通知功能,可以更容易地发现问题。
因为Jenkins也有容器镜像可供使用,所以我会尝试一下。
我将创建一个用于创建Jenkins的POD的yaml文件。
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: myns
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: docker.io/jenkins/jenkins:jdk11
初次登录密码好像在/var/jenkins_home/secrets/initialAdminPassword中。
$ JENKINS_POD=`kubectl get pod -n myns | grep jenkins | awk '{print $1}'`
$ kubectl exec -n myns $JENKINS_POD -- cat /var/jenkins_home/secrets/initialAdminPassword
登录后,可以安装各种插件,包括GitHub。
您可以通过“Jenkins管理”->“系统设置”来设置邮件作为通知功能。
我试着发送了一封电子邮件,收到了以下的邮件。
为了直观地确认资源情况,准备使用Grafana。
在学习的过程中,可以想象到处理的数据量增加和处理的情况变得更为复杂。这可能会导致服务器的CPU和内存不足。在处理被中断之前,我们希望采取措施,如增加资源或减少处理量等来应对这种情况。因此,我们准备使用Grafana作为监控资源的方法。在Grafana中,我们可以做到以下几点:
– 对指标进行可视化展示。
– 对指标进行警报。
由于使用Operator,安装Grafana会更加容易,因此让我们试试看。
执行以下命令。
#!/bin/bash -ex
SCRIPT_DIR=$(cd $(dirname $0); pwd)
echo 'install helm'
HELM_VERSION='v3.8.1'
cd $HOME
curl "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" -o helm.tar.gz
tar -zxvf helm.tar.gz
mv linux-amd64 helm
echo 'export PATH=$PATH:$HOME/helm' >> $HOME/.bashrc
source .bashrc
helm version
echo 'install prometheus operator'
cd $SCRIPT_DIR
PROMETHEUS_OPERATOR_VERSION='36.0.0'
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--version $PROMETHEUS_OPERATOR_VERSION \
--create-namespace \
-n monitoring \
-f prometheus/prometheus-operator-values.yaml
grafana:
service:
type: NodePort
port: 3000
targetPort: 3000
nodePort: 30300
prometheus:
service:
type: NodePort
port: 9090
targetPort: 9090
nodePort: 30090
正在进行的工作如下:
– 安装Helm
– 安装Prometheus Operator
另外,在helm安装时使用了yaml文件,目的是将Grafana的Service类型设置为NodePort。具体细节将在后面说明。
接下来,让我们实际尝试访问一下。
初始用户的用户名和密码已经在k8s环境的Secret中记录。
$ kubectl describe secret -n monitoring kube-prometheus-stack-grafana
Name: kube-prometheus-stack-grafana
Namespace: monitoring
Labels: app.kubernetes.io/instance=kube-prometheus-stack
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=grafana
app.kubernetes.io/version=8.5.3
helm.sh/chart=grafana-6.29.6
Annotations: meta.helm.sh/release-name: kube-prometheus-stack
meta.helm.sh/release-namespace: monitoring
Type: Opaque
Data
====
admin-password: 13 bytes
admin-user: 5 bytes
ldap-toml: 0 bytes
$ kubectl -n monitoring get secret kube-prometheus-stack-grafana -o jsonpath="{.data.admin-user}" | base64 --decode
*** #username
$ kubectl -n monitoring get secret kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode
*** #Password
在默认情况下,仪表板已经创建好了,您可以查看之前创建的POD所使用的内存和CPU的情况。
此外,您可以创建联系点和警报规则,以便使用警报功能。可以指定警报接收方为电子邮件、Microsoft Teams等。
此外还可以使用Prometheus。
从本地电脑的浏览器访问POD的方法【参考】
总结
这次,我们通过本地PC的浏览器访问了创建的POD。具体方法是通过SSH端口转发和Service的NodePort相结合。首先,我们将POD内部容器正在等待连接的端口分配给节点的端口。我们假设节点能够通过本地PC进行SSH连接,而其他端口是空闲的情况。因此,通过SSH端口转发,我们可以访问容器分配的端口。以下是从浏览器访问容器镜像的路径示意图。
本地PC通过SSH连接到EC2,但是服务通过registry-ui容器在端口80上进行访问。
响应将在本地PC的端口80上进行监听。可以通过浏览器的URL http://localhost:80 来访问。
用NodePort进行端口分配
根据使用的容器端口,在Service中需要设置NodePort。以下是节点和分配的容器端口的总结。
此外,还提供了一个示例的容器注册表服务的YAML文件。
apiVersion: v1
kind: Service
metadata:
name: registry-service
namespace: myns
spec:
type: NodePort
ports:
- name: "registry"
protocol: "TCP"
port: 25000
targetPort: 5000
nodePort: 30500
- name: "registry-ui"
protocol: "TCP"
port: 20080
targetPort: 80
nodePort: 30080
selector:
app: registry
SSH端口转发方法
使用分配的节点端口号,进行SSH端口转发。
通过使用Teraterm的功能,可以省略SSH连接的设置,更加便捷。
在连接Teraterm的情况下输入所需的信息。
您可以使用一个Teraterm来设置多个端口转发。本地端口对应于在浏览器中输入的端口。
如果每次都很麻烦设置,您还可以将Teraterm的当前设置保存到INI文件中,并在启动时加载它。
我现在要开始学习。
我还有很多机器学习方面尚未学习的内容。以下是我希望今后学习的内容:
– Spark 分布式处理架构
– AWS SageMaker
– 学习性能评估
– 模型参数调优
最后
关于我提到的功能,我认为AWS也可以实现。AWS提供了自己开发的中间件和托管服务。最近感觉AWS非常强大,我希望学会熟练使用它。