【增强学习】利用云服务进行分布式增强学习(Kubernetes 编辑)
本文是一篇关于自制强化学习框架的解说文章。
这篇文章的代码位置:examples/kubernetes
免费章节的延续。
1:使用云服务进行分布式强化学习(免费版)
2:这里
3:使用云服务进行分布式强化学习(GKE/付费版)
请参考前篇文章了解有关架构等的概述。
首先我们在本地创建一个kubernetes。
整体印象
这次想构建的组合包含了多个服务。
对于像这样集成多个服务器的方法之一,有 Kubernetes(k8s)。
因为是第一次接触k8s,请宽容一些…。
简单来说,k8s的概念是指一个Pod是一个虚拟的计算机,而Pod内包含多个Docker容器。下面是我们即将创建的整体架构图。

创建三个大型Pod。
-
- RedisPod
RedisPod是一个Pod,里面包含了一个Redis服务器容器和一个Redis-commander(用于GUI界面)容器。它兼任了TaskBoard、ParameterBoard和Queue三个角色的功能。只有通过外部或内部的访问可以连接到这个Pod。
TrainerPod
TrainerPod是一个Pod,里面只有一个Trainer用的容器运行。
ActorPod
一共有N个ActorPods启动,每个ActorPod里面只有一个Actor用的容器运行。
作为一个Actor,我会使用Pod的复制功能来复制。(我不确定这是正确的用法)每个Pod都会通过Service的概念进行连接。(在图中表示为箭头)
* Pod内的容器可以直接使用localhost进行通信。
* 可以将Redis的不同角色分割到不同的Pod中。最初将队列的角色分割到另一个Pod中并使用RabbitMQ,但这太复杂了,所以我们进行了整合。
Docker桌面版 + Kubernetes
由于DockerDesktop在官方提供了K8s功能,所以我将利用它来学习K8s。
如果没有安装Docker Desktop,则可以从以下链接进行安装:
以下是启用K8s的步骤。
https://matsuand.github.io/docs.docker.jp.onthefly/desktop/kubernetes/
只需要一种选项:详细内容省略,但是如果有效,它将会启动起来。k8s似乎是按照上下文单位来处理项目的,并且应该会有一个名为docker-desktop的东西。
为了确认能否使用 “kubectl” 命令,我们可以通过以下方式检查上下文。
# コンテキスト変更
> kubectl config use-context docker-desktop
> kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* docker-desktop docker-desktop docker-desktop
Pod的概念
我在这里曾经纠结过,所以现在我把备忘录写下来。
在k8s中有Pod、ReplicaSet和Deployment的概念,它们分别代表以下含义。
-
- Podはk8sの最小単位で1つのPodに複数のコンテナが入り、Pod内は同じリソースが共有される(CPU,メモリやネットワーク等が共通)
-
- ReplicaSetは同じPodを複製する機能
- DeploymentはReplicaSetをラップし、デプロイ・更新・ロールバック等も含めて管理する
在包含关系上,Deployment ⊃ ReplicaSet ⊃ Pod。
使用Deployment基本上没有问题,但对于像这次的批处理需求来说,似乎与之不兼容,下面的GKE文章中的资源分配会失败一次又一次…。
Deployment可能功能稍微复杂,所以我们基本上使用Pod。
一般来说,如果不使用Deployment,而是使用Pod的话,情况如下(据ChatGPT所述)。
-
- 学習やテスト:Deploymentは複数のPodを管理するためのもので、単一のPodを使う場合は直接Podを定義することがあります
-
- 一時的なジョブやタスク:例えばバッチ処理やデータのクリーニングなどの一時的な作業を行う場合は、そのジョブ専用のPodを直接作成することがあります
- 特定の制御が必要な場合:Deploymentはデプロイや更新の管理に便利なツールですが、特定の制御が必要な場合はPodを直接作成する場合があります
基本上這種情況應該就是這樣。
這是我個人的理解,永續性服務應該使用Deployment,而批次處理系統則更適合使用Pod(或者ReplicaSet),這樣能保持更穩定的印象。
1. 启动Redis
首先,我们尝试启动可以直接使用Web上的容器镜像的Redis。
下面是指南。
由于GEA还存在,所以我想要分开工作目录。
目录结构如下。
./
└ docker_desktop/ # new
└ redis.yaml # new
apiVersion: v1
kind: Service
metadata:
name: redis-internal-service
spec:
type: ClusterIP
selector:
app: redis
ports:
- name: redis-internal-port
protocol: TCP
port: 6379
targetPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-external-service
spec:
type: NodePort
selector:
app: redis
ports:
- name: redis-external-port
protocol: TCP
port: 6379
nodePort: 30001
- name: redis-web-port
protocol: TCP
port: 8081
nodePort: 30002
---
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
data:
redis.conf: |-
bind 0.0.0.0
port 6379
---
apiVersion: v1
kind: Pod
metadata:
name: redis-pod
labels:
app: redis
spec:
containers:
- name: redis-server
image: redis:7.2-alpine
ports:
- containerPort: 6379
command: ["redis-server", "/etc/redis/redis.conf"]
volumeMounts:
- name: redis-config
mountPath: /etc/redis
resources:
limits:
cpu: "900m"
- name: redis-commander
image: rediscommander/redis-commander:latest
env: [{"name": "REDIS_HOSTS", "value": "local:localhost:6379"}]
ports:
- containerPort: 8081
resources:
limits:
cpu: "200m"
memory: "64Mi"
volumes:
- name: redis-config
configMap:
name: redis-config
本内容涉及创建Redis的Pod,并在集群内打开6379端口,向外部打开30001端口(Redis)和30002端口(Redis管理界面)。
创建文件后,在提示符下执行以下命令,启动它。
> kubectl apply -f ./docker_desktop/redis.yaml
你可以在下面进行确认。
> kubectl get pods
NAME READY STATUS RESTARTS AGE
redis-pod 2/2 Running 0 14s
如果启动成功,您就可以从以下位置进入管理界面。
如果要删除,请参考以下内容。
> kubectl delete -f ./docker_desktop/redis.yaml
2. 创建容器镜像
创建用于Actor/Trainer使用的容器映像。
此映像也将在GKE中使用相同的版本。
下面是在此处创建的文件。
./
├ docker_desktop/
| └ redis.yaml
|
├ dockerfile # new
├ server_actor.py # new
└ server_trainer.py # new
首先,我们将创建一个用于入口点的代码。
from srl.runner.distribution import RedisParameters, actor_run_forever
from srl.utils.common import logger_print
logger_print()
actor_run_forever(RedisParameters(host="redis-internal-service"), None)
from srl.runner.distribution import RedisParameters, trainer_run_forever
from srl.utils.common import logger_print
logger_print()
trainer_run_forever(RedisParameters(host="redis-internal-service"),None)
由于来自k8s内部的访问,您可以通过”redis-internal-service”进行访问。
(在redis.yaml文件中定义了这个)
接下来,创建Dockerfile。
Tensorflow镜像的尺寸很大……
# syntax=docker/dockerfile:1
# --- select image CPU(1.76GB) or GPU(7.38GB)
FROM tensorflow/tensorflow:2.14.0-gpu
#FROM tensorflow/tensorflow:2.14.0
WORKDIR /code
RUN apt-get update \
&& apt install -y --no-install-recommends git \
&& apt-get install -y --no-install-recommends libgl1-mesa-dev libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/* \
&& pip install --no-cache-dir git+https://github.com/pocokhc/simple_distributed_rl@v0.13.3 \
# 必要なライブラリを適宜入れる
&& pip install --no-cache-dir opencv-python pygame gymnasium redis async_timeout
# エントリーポイントのファイルをコピー
COPY server_*.py /code/
以下将用图像来表示。
> docker build --pull --rm -t srl_qiita:latest .
3. 演员/训练师清单文件
最后,将为演员/训练师创建一个清单文件。
./
├ docker_desktop/
| ├ redis.yaml
| ├ actor.yaml # new
| └ trainer.yaml # new
|
├ dockerfile
├ server_actor.py
└ server_trainer.py
apiVersion: v1
kind: Pod
metadata:
name: trainer-pod
spec:
containers:
- name: trainer-node
image: srl_qiita:latest
imagePullPolicy: Never # この行でローカルのimageを見るようにしている
#command: ["sh", "-c", "while true; do sleep 3600; done"]
command: ["python", "-u", "/code/server_trainer.py"]
resources:
limits:
cpu: "950m"
※DockerDesktop的k8s不支持GPU。
※我们通过添加”-u”选项来使python的print输出到k8s的日志中。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: actor-pods
spec:
replicas: 1 # ここがそのままActor数になる
selector:
matchLabels:
app: actor
template:
metadata:
labels:
app: actor
spec:
containers:
- name: actor-node
image: srl_qiita:latest
imagePullPolicy: Never # この行でローカルのimageを見るようにしている
#command: ["sh", "-c", "while true; do sleep 3600; done"]
command: ["python", "-u", "/code/server_actor.py"]
resources:
limits:
cpu: "950m"
Actor是在ReplicaSet中创建的。
replicas的数量表示要复制的Pod数量,也就是Actor的数量。
然而,这个数量也需要相应的CPU资源…。
我将在下面启动。(Wǒ .)
> kubectl apply -f ./docker_desktop/trainer.yaml
> kubectl apply -f ./docker_desktop/actor.yaml
我会在下面进行确认。
> kubectl get pods
NAME READY STATUS RESTARTS AGE
actor-pods-2h47z 1/1 Running 0 61s
redis-pod 2/2 Running 0 19m
trainer-pod 1/1 Running 0 13s
如果无法启动,请将命令更改为调试模式并启动,然后尝试进入内部进行调查(在下面输入pods的名称)。
> kubectl exec -it [NAME] -- bash
另外,查看每个Pod的日志请使用以下方法。
使用-f选项可以实时查看日志。
> kubectl logs -f [NAME]
4. 学习的执行 de
準备就绪后将开始学习。
将会连接到 Redis 的端口 30001。
import srl
from srl.algorithms import dqn
from srl.runner.distribution import RedisParameters
rl_config = dqn.Config()
rl_config.hidden_block.set_mlp((64, 64))
rl_config.memory.set_proportional_memory()
rl_config.memory.capacity = 5000
runner = srl.Runner("Pendulum-v1", rl_config)
runner.train_distribution(
RedisParameters(host="localhost", port=30001),
actor_num=1,
max_train_count=20_000,
)
print(runner.evaluate())
执行结果
> python main.py
18:45:35 ACTIVE 1.00s( - left), 0tr (-1451.4eval)
trainer 573db05d-d1e4-4178-a2c0-b36f03fbf303 0.9s: 0tr/s, 0recv/s, tr, 0recv
actor0 not assigned
18:46:36 ACTIVE 1.0m( 3.5m left), 4487tr (-1244.9eval)
trainer 573db05d-d1e4-4178-a2c0-b36f03fbf303 10.2s: 74tr/s, 440recv/s, 4487tr, 26578recv
actor0 b456bf97-deda-4839-8a83-fb26977abe18 10.2s: 372st/s, 371send/s, 22461st, 22424send
18:47:36 ACTIVE 2.0m( 1.7m left), 10291tr (-0.968eval)
trainer 573db05d-d1e4-4178-a2c0-b36f03fbf303 9.5s: 96tr/s, 455recv/s, 10291tr, 54000recv
actor0 b456bf97-deda-4839-8a83-fb26977abe18 9.5s: 457st/s, 457send/s, 50006st, 49987send
18:48:36 ACTIVE 3.0m(43.33s left), 15941tr (-127.4eval)
trainer 573db05d-d1e4-4178-a2c0-b36f03fbf303 9.8s: 93tr/s, 444recv/s, 15941tr, 80832recv
actor0 b456bf97-deda-4839-8a83-fb26977abe18 9.8s: 446st/s, 447send/s, 76966st, 76950send
18:49:11 END 3.6m( 0.00s left), 20000tr ( -13.4eval)
trainer 573db05d-d1e4-4178-a2c0-b36f03fbf303 1.0s: 115tr/s, 436recv/s, 20000tr, 96217recv
actor0 b456bf97-deda-4839-8a83-fb26977abe18 5.0s: 509st/s, 509send/s, 94930st, 94915send
[-13.179330630227923, -302.80894811078906, -12.675792848691344, -128.10729961842299, -247.43346573412418, -12.799946028739214, -365.9429765045643, -132.10430204682052, -14.009112168103456, -134.4337202552706]
当完成后我会删除。
这个结构完全没有保存到数据库,所以删除后将会重新初始化。
# 一括削除
> kubectl delete -f ./docker_desktop
# 一括起動
> kubectl apply -f ./docker_desktop
我接下来想要在 Google Kubernetes Engine(GKE)上创建这个k8s环境。
【强化学习】使用云服务进行分布式强化学习(GKE/付费版本)