在 Amazon EKS 上部署生成式 AI 模型

6ab6169def2cf89da50d240bcb284a41.gif

导言

生成式 AI 正在改变企业的运作方式,并加快创新的步伐。总体而言,人工智能正在改变企业利用技术的方式。生成式 AI 技术包括微调和部署大型语言模型(LLM),并允许开发人员访问这些模型以执行提示和对话。负责在 Kubernetes 上制定标准的平台团队可以在 Amazon EKS 上微调和部署大语言模型。

本文将通过一个端到端的例子带您了解如何在 Amazon EKS 上构建生成式 AI 系统。Amazon EKS 是一项托管的 Kubernetes 服务,可以在亚马逊云科技上轻松实现部署、管理和扩展容器化的应用程序。

Amazon EKS 的核心优势之一是其可扩展性,数据节点的动态扩展很好满足了大语言模型对于计算资源的灵活要求。例如,Amazon EKS 集群可以扩展到支持数万个容器,这使其成为密集型人工智能工作负载的理想选择。除了可扩展性,Amazon EKS 还提供高度定制化功能,允许用户根据具体需求对配置进行调整。Amazon EKS 具有强大的内置的保障措施,可保护您的人工智能模型和数据。

生成式 AI 模型是人工智能/机器学习领域的一个重大突破,因为它具有广泛的适用性,而且非人工智能专家也能轻松使用。传统上,利用人工智能意味着为每种特定的用例创建专门的模型,每次都需要大量的计算资源和人力资源。生成式 AI 通过创建基础模型克服了这一瓶颈。对基础模型进行微调,使其适用于多种用例,从而实现重复使用,而无需重复从头开始构建模型。目前最常见的是基础模型利用 Transformer(文本生成)/ Diffusers(即图像生成)来实现这种适应性。这些模型具有广泛的用例和行业垂直领域的潜在适用性,从聊天机器人和虚拟助手到完全通过文本提示生成视频的市场营销,不一而足。

大语言模型包含数十亿参数,需要大量资源来进行高性能训练和低延迟推理。Amazon EKS 可作为一个有效的协调器,帮助实现这些生成式 AI 工作负载所需的快速扩缩容,同时提供满足企业管理和控制的工具。Amazon EKS 不仅可以简化管理,还提供各种开源工具,以应对独特的机器学习方面的挑战。Amazon EKS 可让您完全控制自己的环境,从而确保最佳成本效益。

解决方案概述

在 Amazon EKS 上部署

Stable Diffusion 模型的架构

49cdc7fd43d445220f080e55e29a6121.png

即使在 Kubernetes 环境中,也有大量可用来构建和运行模型的工具。一个新兴的工具栈是 Jupterhub,Argo Workflows,Ray 和 Kubernetes,我们称之为 JARK Stack。

89a2cf52a5930665f2d36e8594a6346c.png

JARK 架构

JupyterHub 提供了一个共享平台,用于运行在商业、教育和研究领域广受欢迎的一些 notebook 。它促进了交互式计算,用户可以在这里执行代码、可视化结果并协同工作。在生成式 AI 领域,JupyterHub 加速了实验过程,尤其是反馈环节。数据工程师也可以在这里一起为模型创建相关的提示工程。

Argo Workflows  是一个开源的容器原生的工作流引擎,用于在 Kubernetes 上协调并行作业。它提供了一个结构化和自动化的流水线,专为微调模型而定制。

这个 Argo 的工作流水线包含以下几个阶段:

  • 数据准备:组织和预处理训练数据集

  • 模型配置:定义大语言模型微调的架构和超参数

  • 微调:执行训练计划

  • 验证:衡量微调模型的性能

  • 超参数调优:优化设置,实现最佳性能

  • 模型评估:使用测试数据评估模型效率

  • 部署:托管模型,满足推理需求

Ray 是一个开源分布式计算框架,可轻松扩展应用程序并使用最先进的机器学习库。Ray 用于在多个节点上分布式训练生成模型,从而加快训练过程,并允许处理更大的数据集。

Ray Serve 是一个功能强大的模型服务库,用于创建在线推理应用编程接口(API)。值得注意的是,它与 PyTorch,Keras 和 Tensorflow 等主要框架兼容。它针对大语言模型服务进行了优化,具有流式响应、动态请求批处理和多节点/多 GPU(图形处理单元)支持等功能。除模型服务外,Ray Serve 还可以将多个模型和业务规则整合到一个服务中。Ray Serve 基于 Ray 构建,旨在实现跨机器的可扩展性,并提供资源节约型调度。关于和 JupyterHub 的关系,虽然两者之间的联系看起来不大,但这两种工具都可以成为更大的机器学习生态的一部分,JupyterHub 可以促进交互式计算,而 Ray Serve 则可以处理模型部署和服务。

Kubernetes 是一个功能强大的容器编排平台,可自动部署、扩展和管理容器化应用程序。Kubernetes 为在容器中运行和扩展生成式 AI 模型提供了基础架构,从而确保了高可用性、容错性和极高的资源利用率。

解决方案架构

49c2cbac01a6b2c86899fb4e00131c8c.png

演练

关于如何在 Amazon EKS 上

微调和部署模型的分步指南

具体例子

正如我们前面提到的,大多数下游用例都需要根据业务需求为特定任务微调大语言模型。这通常只需要一个实例相对较少的小型数据集,而且在大多数情况下只需一个 GPU 即可完成。在本文中,我们将以 Dreambooth 为例,展示如何调整类似 Stable Diffusion 这种文生图的模型来为一个主题(例如,狗)在不同的场景生成不同的背景图像。Dreambooth 相关的论文描述了一种将唯一标识符与主题(如[v]狗的照片)绑定的方法,以便根据输入提示(如[v]狗在月球上的照片)在逼真的图像中合成所述主题的照片。

  • Dreambooth 相关的论文

    https://arxiv.org/abs/2208.12242

Dreambooth 相关的商业应用可能包括如下几个:

  1. 根据文字描述为社交媒体平台、电子商务网站和其他在线平台生成图片。

  2. 为用户创建个性化头像。

  3. 为网店生成产品图像。

  4. 制作营销材料和生成使用视觉教具的教学内容。

在本文的剩余部分,我们将我们的示例模型和推理服务称为 dogbooth。为了在 Amazon EKS 上微调 dogbooth ,我们使用了几种开源技术来支持实现。除了 JARK Stack,我们还利用了 Hugging Face 的两个库,它们为我们提供了个性化 Stable Diffusion 模型的工具:Accelerate 和 Diffusers。

Accelerate 是一个开源库,专门用于简化和优化深度学习模型的训练和微调过程。就我们的目的而言,它提供了一个上层应用程序接口(API),让我们可以轻松地尝试不同的超参数和训练配置,而无需每次重写训练循环,并有效利用可用的硬件资源。

Diffusers 是最先进的预训练 diffusion 模型库,用于生成图像、音频甚至 3D分子结构。他们以脚本集的形式提供了易于使用的训练示例,演示了如何在各种个性化任务中有效地使用 Diffusers,如 Unconditional Training、Text-to-Image Training、Dreambooth、ControlNet、Custom Diffusion 等。

在 Amazon EKS 上部署 Stable Diffusion 

模型的步骤

先决条件

  1. Amazon Command Line Interface (Amazon CLI) v2 – the CLI for Amazon services

    https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

  2. kubectl – the Kubernetes CLI

    https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

  3. Terraform 1.5 – an infrastructure as code tool

    https://developer.hashicorp.com/terraform/downloads

  4. Hugging Face Tokenwith write scope

    https://huggingface.co/docs/hub/security-tokens

  5. jq – a lightweight and flexible command line JSON processor

    https://jqlang.github.io/jq/

第一步:下载代码

git clone https://github.com/awslabs/data-on-eks.git

第二步:部署 Amazon EKS

进入第一步下载的代码目录,到 ai-ml/jark-stack 目录下并执行 install.sh 脚本。这个脚本会执行 Terraform 命令来创建基础设施。值得注意的是资源默认会被部署到 us-west-2 region,可以通过更新文件 variables.tf 里面的值来指定其他的 Amazon Region。整个部署过程大概需要耗时 30 分钟。

cd data-on-eks/ai-ml/jark-stack/terraform
export TF_VAR_huggingface_token=hf_XXXXXXXXXX


./install.sh  


Initializing ...
Initializing the backend...
Initializing modules...


Initializing provider plugins...
Terraform has been successfully initialized!
...
SUCCESS: Terraform apply of all modules completed successfully

部署的主要资源清单如下:

  • VPC (subnets, route tables, NAT gateway)

  • Amazon EKS cluster

  • Core-Managed Node Group

  • GPU-Managed Node Group

  • A kubernetes secret for Hugging Face token

  • Add-ons

Add-ons

让我们来看一下部署了哪些 add-ons。

aws eks update-kubeconfig --name jark-stack --region us-west-2


kubectl get deployments -A
                                                                
NAMESPACE              NAME                                                 READY   UP-TO-DATE   AVAILABLE   AGE
ingress-nginx          ingress-nginx-controller                             1/1     1            1           36h
jupyterhub             hub                                                  1/1     1            1           36h
jupyterhub             proxy                                                1/1     1            1           36h
kube-system            aws-load-balancer-controller                         2/2     2            2           36h
kube-system            coredns                                              2/2     2            2           2d5h
kube-system            ebs-csi-controller                                   2/2     2            2           2d5h
kuberay-operator       kuberay-operator                                     1/1     1            1           36h
nvidia-device-plugin   nvidia-device-plugin-node-feature-discovery-master   1/1     1            1           36h

Amazon EBS CSI Driver

这个 Driver 允许 Amazon EKS 管理 Amazon EBS 持久卷的生命周期。默认的 StorageClass 是 gp3 。

Amazon Load Balancer Controller

这个 controller 为 Amazon EKS 管理 Amazon ELB。您需要一个网络负载均衡器来访问我们的 Jupyter notebook,最终还需要另一个网络负载均衡器来为我们的自托管推理服务提供入口,这将在本文的后面部分讨论。

NVIDIA Device Plugin

NVIDIA Device Plugin 是一个 Kubernetes DaemonSet,它是 Kubernetes 集群和其底层 GPU 之间的桥梁,允许我们在集群上运行支持 GPU 的容器。

JupyterHub

Terraform 脚本安装了 JupyterHub。在本例中,我们将 values.yaml 传递给了 Helm Chart,这个 values.yaml 定义了 JupyterHub 使用负载均衡器对外提供服务、对 GPU 资源的要求、基于 Amazon EBS 的存储卷用于持久化。请注意,我们展示了 Notebook 基于用户名和密码的基本用户身份验证,仅供演示之用。对于实际场景的设置,请考虑使用 identity provider。

...
proxy:
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-type: external
      service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true'
      service.beta.kubernetes.io/aws-load-balancer-ip-address-type: ipv4
singleuser:
  image:
    name: public.ecr.aws/h3o5n2r0/gpu-jupyter
    tag: v1.5_cuda-11.6_ubuntu-20.04_python-only
    pullPolicy: Always
..
  extraResource:
    limits:
      nvidia.com/gpu: "1"
  extraEnv:
    HUGGING_FACE_HUB_TOKEN:
      valueFrom:
        secretKeyRef:
          name: hf-token
          key: token
  storage:
    capacity: 100Gi
...
      - name: notebook
        configMap:
          name: notebook
...

Ingress-Nginx

Ingress-Nginx 允许我们使用一些路径重写的规则,在同一个负载均衡器上同时暴露 Ray dashboard 和推理入口。还允许我们运行多个 Ray 服务入口,并使用基于路径的路由方式来实现同一个负载均衡器提供不同版本的模型服务。

Kuberay-Operator

KubeRay Operator 使在 Kubernetes 上部署和管理 Ray 集群变得简单便捷。Ray 集群被定义为 custom resource,由高容错性的 Ray Controller 管理。KubeRay Operator 可自动执行 Ray 集群生命周期管理、自动扩展和其他关键功能。 稍后,我们将介绍如何使用集群上的 RayService 自定义资源定义为 dogbooth 创建推理服务。

第三步:微调 Stable Diffusion 模型

现在,您可以开始尝试使用我们的模型,并准备一个 Jupyter Notebook,帮助我们根据您的需求进行个性化设置。

下面首先获取负载均衡器的域名。

kubectl get svc proxy-public -n jupyterhub --output jsonpath='{.status.loadBalancer.ingress[0].hostname}'

使用浏览器打开上述域名,并使用在 jupyterhub-values.yaml 文件配置的用户名密码登陆。如下图。

209f3945afa4fe0f27acc1eda84a0bfe.png

这会触发在 g5 节点上创建了一个 Jupyter-user1 的 Pod。执行 kubectl get pods -n jupyterhub 即可看到类似下图的结果。

df9fa4a9ed1f0d19d272e56da19e5c90.png

当这个 Pod 正常运行之后,您的浏览器就会自动跳转到 notebook console。点击打开 dogbooth 目录里面的 Python noteboot。如下图所示。

824aaaad9c26cf2971d36771c8bf564e.png

打开之后,您就可以逐步执行这个 jupyter notebook 定义的内容了。如下图所示,第一步执行了 nvidia-smi 命令去确认当前的 Notebook 实例是运行在 GPU 节点上的并且可以见到 GPU 芯片的详细信息。

bd96343d5de25e219ca9cec37de16348.png

接下来的四步就是配置开发环境,包括从 GitHub 下载 diffusers 库和安装 Python 依赖。另外,为了实现 memory efficient attention,还需要安装 xFormers。

28919213db55698493ac2aaf19c825e4.png

接下来就是安装 bitsandbytes,它可以允许我们使用 8-bit 的优化器进一步减少内存的需求。

a4e26091d859d98448b8c82d9c8ac200.png

成功安装 bitsandbytes 之后,下一步就是要配置 dreambooth 训练脚本所需要的环境。这包括安装一些额外的依赖包,配置默认加速设置,登录 HuggingFace 并下载示例数据集。

ecde0be6db421ec284d5f1db3d37bb13.png

现在,您可以为输入模型的位置、数据集目录和微调后模型的输出目录设置环境变量,然后开始微调模型。HuggingFace accelerate 会完成所有繁重的工作,帮助我们对模型进行实验。以下示例中使用的超参数经过优化,可在 1 个配备 24 GB 内存的英伟达 A10G GPU 上成功运行训练。

8e960c184e4619bc09f600981839b871.png

完成这项工作大约需要 1.5 个小时。您可以通过更改一些超参数(如 -max_train_steps=400 )来减少训练时间,但这是以牺牲模型的性能和准确性为代价的。

训练脚本完成后,您就可以验证模型是否已创建,并运行样本推理以检查其性能如何。

15f67aa4e77b492b11111cebff6c5dc2.png

打开 dog-bucket.png,这张图片在/home/jovyan/diffusers/examples/deambooth 目录下。

9f280fb05ef900e4b8ffb4ff54e99db6.png

由于 HuggingFace accelerate 也会将模型上传到 HuggingFace,因此您甚至可以在其托管推理 API 上测试推理样本。您可以在这里找到您的模型 https://huggingface.co/spaces//dogbooth  或者在您指定的模型输出目录中。

7abdd2869579dbc4a6b084d8401dfcc0.png

如果模型过拟合或者欠拟合,请参考 HuggingFace 对 dreambooth 的深入分析(https://huggingface.co/blog/dreambooth),以帮助您调整超参数,提高模型性能。这些建议超出了本文的讨论范围。

第四步:提供大语言模型服务

现在您已经拥有了一个微调过的模型,可以使用这个模型在 Amazon EKS 上创建推理节点了。

您可以使用 RayService 自定义资源定义(CRD)来部署一个带有 RayServe 应用程序的 Ray 集群,该应用程序会调用您之前通过 accelerate 训练脚本微调并推送到 HuggingFace 的模型。

定义 RayService 入口

RayServe 的 Python 应用程序被打包成一个容器镜像,在部署的时候可以被拉取到 RayCluster 中。Ray 的文档提供了使用 Ray Serve 和 FastAPI 创建推理应用程序的示例代码。我们对提供的 Python 代码进行了调整,通过向 RayService 配置传递环境变量 MODEL_ID,将推送到 HuggingFace 的自定义 dogbooth 模型的 model_id 作为该环境变量的值传递进去,如以下步骤所示。同时可以在 src/service/dogbooth.py 查看相关的 Python 代码。想要查看 RayCluster 的 head 和 worker 节点的容器镜像的 Dockerfile, 可以在这里 src/service/Dockerfile 找到。


探索更高级的 RayService 的配置将作为练习留给读者。

定义 RayService

现在可以部署 RayService 了。我们在目录 data-on-eks/ai-ml/jark-stack/terraform/src/service 提供了 RayService 的 Kubernetes 定义文件 ray-service.yaml。这个文件主要包含了如下定义:

  1. 创建名为 dogbooth 的命名空间,用以部署 RayCluster。

  2. 创建一个 ingress, 以便通过 ingress-nginx 将 RayService 入口暴露给亚马逊云科技网络负载均衡器,并为界面和推理服务提供基于路径的路由。

  3. 编辑 env_vars 下的 MODEL_ID,将模型库更改为微调后的模型库。

---
apiVersion: v1
kind: Namespace
metadata:
  name: dogbooth
---
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
  name: dogbooth
  namespace: dogbooth
spec:
...
  serveConfig:
    importPath: dogbooth:entrypoint
    runtimeEnv: |
      env_vars: {"MODEL_ID": "askulkarni2/dogbooth"}
  rayClusterConfig:
    rayVersion: '2.6.0'
    headGroupSpec:
...
      template:
        spec:
          containers:
            - name: ray-head
              image: $SERVICE_REPO:0.0.1-gpu
              resources:
                limits:
                  cpu: 2
                  memory: 16Gi
                  nvidia.com/gpu: 1
...
    workerGroupSpecs:
      - replicas: 1
...
        template:
          spec:
            containers:
              - name: ray-worker
                image: $SERVICE_REPO:0.0.1-gpu
...
                resources:
                  limits:
                    cpu: "2"
                    memory: "16Gi"
                    nvidia.com/gpu: 1
...
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dogbooth
  namespace: dogbooth
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/\$1"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
        - path: /dogbooth/(.*)
          pathType: ImplementationSpecific
          backend:
            service:
              name: dogbooth-head-svc
              port:
                number: 8265
        - path: /dogbooth/serve/(.*)
          pathType: ImplementationSpecific
          backend:
            service:
              name: dogbooth-head-svc
              port:
                number: 8000

执行命令 kubectl apply -f src/service/ray-service.yaml 在 dogbooth 命名空间中创建 RayService。

一旦执行,RayCluster 的 head 和 worker 节点就会被调度到 GPU 节点上,同时推理入口会被创建并通过负载均衡器向我们提供服务。因为基于 GPU 的 rayproject/ray-ml:2.6.0-gpu 基础镜像比较大,整个部署过程会持续大概 8 分钟左右。

执行 kubectl get pods -n dogbooth –watch 命令观察并等待 Pods 正常运行。之后就可以执行命令 kubectl get ingress dogbooth -n dogbooth --output jsonpath='{.status.loadBalancer.ingress[0].hostname}' 获取负载均衡器的域名来访问 Ray 的控制台。在浏览器中打开获取到的连接(类似 http://k8s-ingressn-ingressn-xxx.elb.us-east-1.amazonaws.com/dogbooth/) ,您可以见到如下图所示的界面。

954de2f21950bce1666ac80044656ab5.png

最后,通过以下提示验证我们的 dogbooth 模型部署,例如:

http://k8s-ingressn-ingressn-xxx.elb.us-east-1.amazonaws.com/dogbooth/serve/imagine?prompt=a photo of [v]dog on the beach

但 Argo Workflows 在哪里?

很高兴您能这么问,我们并没有忘记 Argo Workflows。我们前面讨论的步骤非常适合在问题形成和用例分析的早期阶段进行实验。一旦您找到了符合特定目标的模型,并希望将其部署到生产环境中,这时候协调数据科学家,开发者,运营团队和领域专家的就是 MLOps 了。这种协作可确保模型的开发、部署和管理符合业务目标,并满足运营要求。这就是工作流引擎发挥作用的地方。业界比较流行的工作流引擎有 Kubeflow Pipeline(基于 Argo Workflows),Apache Airflow,Amazon Step Functions 等等。我们在这篇文章(https://aws.amazon.com/blogs/containers/dynamic-spark-scaling-on-amazon-eks-with-argo-workflows-and-events/)中介绍了类似的方法,使用 Argo Events 和 Argo Workflows 作为 Kubernetes 原生的 Workflow 引擎来编排使用 Spark 进行的数据处理作业。进一步延展,我们可以开始思考怎么利用类似方法为生成式 AI 项目构建一个 MLOps 平台。我们将在接下来的文章和 re:Invent 研讨会中更深入地探讨这个系列的话题。

清理资源

要清理在本文中创建的相关资源,执行以下命令即可。

./cleanup.sh

这个脚本会删除 RayService 和执行 terraform destroy 命令删除所有基础设施。

总结

在这篇文章中,我们向您介绍了生成式 AI 模型的出现、它们的优势、关键用例以及创建高适用性输出所需的资源密集性质。我们还谈到了 Amazon EKS 对于实现这些用例所具备的关键优势。Amazon EKS 通过它内置的可扩展性、弹性和跨环境的可重复部署,使客户能够拥有更多的控制权、更大的灵活性以及更高的成本效益。然后,我们还向您介绍了利用 JARK Stack 在 Amazon EKS 上部署生成式 AI 模型的步骤。

亚马逊云科技通过 DataonEKS 项目向您提供了加速采纳机器学习的能力。DataonEKS 是亚马逊云科技的一个开源项目,为在 Amazon EKS 上部署数据工作负载提供最佳实践、基准报告、基础设施即代码(Terraform)模板、部署示例和参考架构。

此外,亚马逊云科技还提供 Amazon Bedrock 和 Amazon Sagemaker 等全托管的机器学习解决方案,可用于轻松部署现成的基础模型,或创建和运行自己的模型。

生成式 AI 处于非常早期的阶段,几乎每天都在快速发展和持续创新。亚马逊云科技很高兴能成为您的合作伙伴,利用我们在市场上最全面、最完整的机器学习功能支持您任何的生成式 AI 需求。我们期待与您在生成式 AI 和机器学习之旅以及未来的道路上合作!

  • 原文链接:https://aws.amazon.com/blogs/containers/deploy-generative-ai-models-on-amazon-eks/

本篇作者

ceeb1b5f4897f4bd6f9efad99cdfbde1.jpeg

Sanjeev Ganjihal

亚马逊云科技高级解决方案架构师。Sanjeev 专注于服务网格、GitOps、IAC、自动扩展和成本优化。他帮助客户在亚马逊云科技上运行、构建和扩展容器化工作负载。

3a61c19690d84c8c1b882303cf6b3e0d.jpeg

Apoorva Kulkarni

亚马逊云科技高级解决方案架构师。Apoorva 帮助客户在亚马逊云科技的容器服务上构建现代应用程序平台。

d0d3998b9a5a648b1cbd443fb1b34a38.jpeg

Rama Prasanna Ponnuswami

亚马逊云科技 WorldWide Goto-Market Specialist,专注于 EKS/EKS-A 领域。Rama 与世界各地的客户合作,指导他们使用亚马逊云科技提供的各种容器解决方案,加速他们的云/容器现代化之旅。

417ee4d4568e11931b9b7d163e9790d6.jpeg

Roland Barcia

亚马逊云科技解决方案架构师总监。Roland 花了 25 年的时间帮助客户构建和现代化系统,并领导着一支专注于 Kubernetes、应用程序现代化、微服务、无服务器、集成和平台工程的全球团队。

校译作者

729b1b61f554df8b814a0c9913b76fe1.png

梁宇

亚马逊云科技专业服务团队 DevOps 顾问,主要负责 DevOps 技术实施。尤为热衷云原生服务及其相关技术。在工作之余,他喜欢运动,以及和家人一起旅游。

b5e71bb441f6e7cc66e96aa207e508bc.gif

星标不迷路,开发更极速!

关注后记得星标「亚马逊云开发者」

94680a64dbbc1ac2c57a8043e6bbd9c3.gif

听说,点完下面4个按钮

就不会碰到bug了!

748ead87eae6525bd76e02928abb086b.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/359828.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

搭建WebGL开发环境

前言 本篇文章介绍如何搭建WebGL开发环境 WebGL WebGL的技术规范继承自免费和开源的OpenGL ES标准,从某种意义上说,WebGL就是Web版的OpenGL ES,而OpenGL ES是从OpenGL中派生出来的。他们的应用环境有区别,一般来说:…

聊聊百度造车

10月27日,极越-01上市,一个月后大幅降价,时至今日距离发布已经过去了两个月,官方迟迟不肯公布销量,实际情况大家也都心知肚明。 如今小米汽车技术发布会风头无两,而同一年宣布造车的极越却无人问津&#x…

算法随想录第四十八天打卡| 198.打家劫舍 , 213.打家劫舍II , 337.打家劫舍III

详细布置 今天就是打家劫舍的一天,这个系列不算难,大家可以一口气拿下。 198.打家劫舍 视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili 代码随想录 class Solution(…

【智能家居入门3】(MQTT服务器、MQTT协议、微信小程序、STM32)

前面已经写了三篇博客关于智能家居的,服务器全都是使用ONENET中国移动,他最大的优点就是作为数据收发的中转站是免费的。本篇使用专门适配MQTT协议的MQTT服务器,有公用的,也可以自己搭建(应该要钱)&#xf…

华为配置ARP安全综合功能实验

配置ARP安全综合功能示例 组网图形 图1 配置ARP安全功能组网图 ARP安全简介配置注意事项组网需求配置思路操作步骤配置文件 ARP安全简介 ARP(Address Resolution Protocol)安全是针对ARP攻击的一种安全特性,它通过一系列对ARP表项学习和A…

Qt应用开发(安卓篇)——调用ioctl、socket等C函数

一、前言 在 Qt for Android 中没办法像在嵌入式linux中一样直接使用 ioctl 等底层函数,这是因为因为 Android 平台的安全性和权限限制。 在 Android 中,访问设备硬件和系统资源需要特定的权限,并且需要通过 Android 系统提供的 API 来进行。…

在线版XD,免费使用,功能全面,设计神器!

Adobe XD是什么软件? Adobe XD软件是一个结合设计和建立原型功能的一站式UX/UI设计平台。在XD软件中,数字团队可以进行移动应用、网页设计和原型制作。与此同时,Adobe XD软件也是一种跨平台设计产品,结合设计和建立原型功能&…

力扣 122.买卖股票的最佳时机 II

代码&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {if(prices.size()1) return 0;int res 0;int i0;while(i<prices.size()-1){int ji1;if(prices[j]>prices[i]){//在找到对应元素的下一个元素比他大的时候买入while(j1 < p…

研学活动报名平台源码开发方案

一、项目背景与目标 &#xff08;一&#xff09;项目背景 研学活动报名平台旨在为活动组织者提供方便快捷的研学活动管理工具&#xff0c;同时为用户提供全面的活动搜索、报名和支付等功能。通过该系统&#xff0c;活动组织者能够更好地管理活动报名信息&#xff0c;用户也可…

系统架构设计师-22年-下午题目

系统架构设计师-22年-下午题目 更多软考知识请访问 https://ruankao.blog.csdn.net/ 试题一必答&#xff0c;二、三、四、五题中任选两题作答 试题一 (25分) 说明 某电子商务公司拟升级其会员与促销管理系统&#xff0c;向用户提供个性化服务&#xff0c;提高用户的粘性。…

Unity之第一人称角色控制

目录 第一人称角色控制 &#x1f634;1、准备工作 &#x1f4fa;2、鼠标控制摄像机视角 &#x1f3ae;3、角色控制 &#x1f603;4.杂谈 第一人称角色控制 专栏Unity之动画和角色控制-CSDN博客的这一篇也有讲到角色控制器&#xff0c;是第三人称视角的&#xff0c;以小编…

【LeetCode】142. 环形链表 II

leetcode题目链接 142. 环形链表 II /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ typedef struct ListNode ListNode;ListNode *detectCycle(ListNode *head) {ListNode *slow head, *fast head;while (…

【读点论文】SPTS Single-Point Text Spotting

SPTS Single-Point Text Spotting ABSTRACT 现有的场景文本识别(即&#xff0c;端到端文本检测和识别)方法依赖于昂贵的边界框注释(例如&#xff0c;文本行&#xff0c;词级或字符级边界框)。我们首次证明&#xff0c;训练场景文本识别模型可以通过对每个实例的单点进行极低成…

Cmake编译Opencv3.3.1遇到有些文件无法下载的错误解决:

前言&#xff1a; 对于&#xff0c;opencv有些配置文件错误并未致命&#xff0c;所以&#xff0c;有错误也不影响后续的编译&#xff1a;但是&#xff0c;后引用如果要用&#xff0c;在回过头来还是要解决的。 问题表述&#xff1a; 比如&#xff0c;有些文件下载的错误&am…

uni-app在hbuilderx打开微信开发工具运行

一、运行设置配置微信开发者工具路径 运行-运行到小程序模拟器-运行设置 配置微信开发工具的安装路径&#xff08;可浏览文件位置选择&#xff09;&#xff1b;web服务器端口号在第二步骤获得&#xff1b; 二、打开微信开发者工具设置-安全设置 打开服务端口开关&#xff0…

qt中使用mysql 数据库

QT 版本介绍 虽然版本是这个&#xff0c;但是工作目录确是&#xff1a; 下面陈述安装步骤 第一步&#xff1a; 就是安装MYSQL 数据库&#xff0c;在此不再赘述了&#xff0c;很多博主已经上传了。 第二步&#xff1a; 就是拷贝QT 对应mysql 的版本驱动到 QT 的编译器文件中…

华为VRP系统简介

因为现在国内主流是华为、华三、锐捷的设备趋势&#xff0c;然后考的证书也是相关的&#xff0c;对于华为设备的一个了解也是需要的。 一、VRP概述 华为的VRP(通用路由平台)是华为公司数据通信产品的通用操作系统平台&#xff0c;作为华为公司从低端到核心的全系列路由器、以太…

vue核心知识点

一、Vue基础知识点总结 开发vue项目的模式有两种&#xff1a; 基于vue.js&#xff0c;在html中引入vue.js&#xff0c;让vue.js管理div#app元素。基于脚手架环境&#xff1a;通过vue脚手架环境可以方便的创建一个通用的vue项目框架的模板&#xff0c;在此基础之上开发vue项目…

Flutter 点击空白处关闭软键盘,点击非TextField 关闭软键盘的方法

1&#xff1a;点击空白处(非控件上)关闭软键盘。 此方法有个问题&#xff0c;就是点击非空白区域&#xff0c;不会关闭软键盘&#xff0c;比如点击旁边的其他按钮&#xff0c;则软键盘还在。只适合点击空白处关闭软键盘 在 main.dart 入口 build 中增加 builder: (context, ch…

计算机网络_1.4 计算机网络的定义和分类

1.4 计算机网络的定义和分类 一、计算机网络的定义&#xff08;无唯一定义&#xff09;二、计算机网络的分类&#xff08;从不同角度分类&#xff09;1、交换方式2、使用者3、传输介质4、覆盖范围5、拓扑结构 笔记来源&#xff1a; B站 《深入浅出计算机网络》课程 一、计算机…