使用 MLRun 和 MinIO 设置开发机器

news2024/11/26 23:33:46

MLOps 之于机器学习,就像 DevOps 之于传统软件开发一样。两者都是一组旨在改善工程团队(开发或 ML)和 IT 运营 (Ops) 团队之间协作的实践和原则。目标是使用自动化来简化开发生命周期,从规划和开发到部署和运营。这些方法的主要好处之一是持续改进。

在之前关于 MLOps 工具主题的文章中,我介绍了 KubeFlow Pipelines 2.0 和 MLflow。在这篇文章中,我想介绍 MLRun,这是另一个 MLOps 工具,如果您正在为您的组织购买 MLOps 工具,则应考虑使用该工具。但在深入研究之前,让我们快速了解一下 MLOps 的前景。

MLOps 格局

虽然这三种工具都旨在为您的所有 AI/ML 需求提供完整的端到端工具,但它们都以不同的动机或设计目标开始。

  • KubeFlow 着手实现 Kubernetes 的民主化。KubeFlow 的核心 KubeFlow Pipelines 要求代码通过部署到 Kubernetes Pod 的无服务器函数运行。

  • MLflow 最初是一种工具,用于跟踪实验以及与 ML 实验相关的所有内容,例如指标、项目(数据)和模型本身。MLflow 了解常用的 ML 框架,如果选择,可以要求 MLflow 自动捕获它认为重要的所有实验数据。

  • MLRun 的使命是消除样板代码,这与其他 MLOps 工具不同。它还需要创建无服务器函数,但它更进一步,因为它知道流行的 ML 框架——因此,不需要对纪元循环进行编码,并且对分布式训练的代码支持较低。

关于 MLRun 的更多信息

MLRun 是一个开源 MLOps 框架,最初由专门从事数据科学的公司 Iguazio 创建。2023 年 1 月,Iguazio 被麦肯锡公司收购,现在是麦肯锡人工智能部门 QuantumBlack 的一部分。

让我们看一下安装选项和需要部署的服务。

安装选项

MLRun 网站推荐了三种在本地安装 MLRun 的方法。Iguazio 还维护托管服务。

本地选项:

  • 本地部署:在笔记本电脑或单个服务器上使用 Docker 撰写文件部署 MLRun 服务。此选项需要 Docker Desktop,并且比 Kubernetes 安装更简单。它非常适合试验 MLRun 功能;但是,您将无法横向扩展计算资源。

  • Kubernetes 集群:在自己的 Kubernetes 集群上部署 MLRun 服务。此选项支持弹性缩放;但是,安装起来更复杂,因为它需要您自行安装 Kubernetes。您还可以使用此选项部署到 Docker Desktop 启用的 Kubernetes 集群。

  • Amazon Web Services (AWS):在 AWS 上部署 MLRun 服务。此选项是安装 MLRun 的最简单方法。MLRun 软件是免费的;但是,AWS 基础设施服务是有成本的。

托管服务:

此外,如果您不介意共享环境,那么 Iguazio 提供托管服务。Iguazio 提供 14 天免费试用。

MLRun 服务简介

MLRun UI:MLRun UI 是一个基于 Web 的用户界面,您可以在其中查看项目和项目运行。

MLRun API:MLRun API 是代码将用于创建项目和启动运行的编程接口。

Nuclio:Nuclio 是一个开源的无服务器计算平台,专为高性能应用程序而设计,特别是在数据处理、实时分析和事件驱动架构方面。它抽象了基础架构管理的复杂性,使开发人员能够专注于编写和部署函数或微服务。

MinIO:将 MLRun 部署到 Kubernetes 集群时,MLRun 使用 MinIO 进行对象存储。我们将把它包含在我们的本地 Docker compose 部署中,因为在后续的文章中,我们需要从对象存储中读取用于模型训练的数据集。当我们创建一个简单的烟雾测试笔记本时,我们也将在这篇文章中使用它,以确保 MLRun 正常启动并运行。

安装 MLRun 服务

我将在此处展示的安装与 MLRun 安装和设置指南中显示的略有不同。首先,我想在此安装中包含 MinIO,以便我们的无服务器函数可以从对象存储加载数据集。此外,我想要用于运行 Jupyter Notebooks 和 MLRun API 的单独服务。(包含 Jupyter 的 MLRun 的 Docker Compose 文件将 MLRun API 和 Jupyter Notebook 服务打包到同一服务中。最后,我将重要的环境变量放在 .env 文件中,这样就不需要手动创建环境变量。MLRun 服务的 Docker Compose 文件和 config.env 文件如下所示。您也可以在此处下载它们以及本文的所有代码。

services:
 init_nuclio:
   image: alpine:3.18
   command:
     - "/bin/sh"
     - "-c"
     - |
       mkdir -p /etc/nuclio/config/platform; \
       cat << EOF | tee /etc/nuclio/config/platform/platform.yaml
       runtime:
         common:
           env:
             MLRUN_DBPATH: http://${HOST_IP:?err}:8080
       local:
         defaultFunctionContainerNetworkName: mlrun
         defaultFunctionRestartPolicy:
           name: always
           maxRetryCount: 0
         defaultFunctionVolumes:
           - volume:
               name: mlrun-stuff
               hostPath:
                 path: ${SHARED_DIR:?err}
             volumeMount:
               name: mlrun-stuff
               mountPath: /home/jovyan/data/
       logger:
         sinks:
           myStdoutLoggerSink:
             kind: stdout
         system:
           - level: debug
             sink: myStdoutLoggerSink
         functions:
           - level: debug
             sink: myStdoutLoggerSink
       EOF
   volumes:
     - nuclio-platform-config:/etc/nuclio/config

 jupyter:
   image: "mlrun/jupyter:${TAG:-1.6.2}"
   ports:
     #- "8080:8080"
     - "8888:8888"
   environment:
     MLRUN_ARTIFACT_PATH: "/home/jovyan/data/{{project}}"
     MLRUN_LOG_LEVEL: DEBUG
     MLRUN_NUCLIO_DASHBOARD_URL: http://nuclio:8070
     MLRUN_HTTPDB__DSN: "sqlite:home/jovyan/data/mlrun.db?check_same_thread=false"
     MLRUN_UI__URL: http://localhost:8060
     # using local storage, meaning files / artifacts are stored locally, so we want to allow access to them
     MLRUN_HTTPDB__REAL_PATH: "/home/jovyan/data"
     # not running on k8s meaning no need to store secrets
     MLRUN_SECRET_STORES__KUBERNETES__AUTO_ADD_PROJECT_SECRETS: "false"
     # let mlrun control nuclio resources
     MLRUN_HTTPDB__PROJECTS__FOLLOWERS: "nuclio"
   volumes:
     - "${SHARED_DIR:?err}:/home/jovyan/data"
   networks:
     - mlrun

 mlrun-api:
   image: "mlrun/mlrun-api:${TAG:-1.6.2}"
   ports:
     - "8080:8080"
   environment:
     MLRUN_ARTIFACT_PATH: "${SHARED_DIR}/{{project}}"
     # using local storage, meaning files / artifacts are stored locally, so we want to allow access to them
     MLRUN_HTTPDB__REAL_PATH: /data
     MLRUN_HTTPDB__DATA_VOLUME: "${SHARED_DIR}"
     MLRUN_LOG_LEVEL: DEBUG
     MLRUN_NUCLIO_DASHBOARD_URL: http://nuclio:8070
     MLRUN_HTTPDB__DSN: "sqlite:data/mlrun.db?check_same_thread=false"
     MLRUN_UI__URL: http://localhost:8060
     # not running on k8s meaning no need to store secrets
     MLRUN_SECRET_STORES__KUBERNETES__AUTO_ADD_PROJECT_SECRETS: "false"
     # let mlrun control nuclio resources
     MLRUN_HTTPDB__PROJECTS__FOLLOWERS: "nuclio"
   volumes:
     - "${SHARED_DIR:?err}:/data"
   networks:
     - mlrun

 mlrun-ui:
   image: "mlrun/mlrun-ui:${TAG:-1.6.2}"
   ports:
     - "8060:8090"
   environment:
     MLRUN_API_PROXY_URL: http://mlrun-api:8080
     MLRUN_NUCLIO_MODE: enable
     MLRUN_NUCLIO_API_URL: http://nuclio:8070
     MLRUN_NUCLIO_UI_URL: http://localhost:8070
   networks:
     - mlrun

 nuclio:
   image: "quay.io/nuclio/dashboard:${NUCLIO_TAG:-stable-amd64}"
   ports:
     - "8070:8070"
   environment:
     NUCLIO_DASHBOARD_EXTERNAL_IP_ADDRESSES: "${HOST_IP:?err}"
   volumes:
     - /var/run/docker.sock:/var/run/docker.sock
     - nuclio-platform-config:/etc/nuclio/config
   depends_on:
     - init_nuclio
   networks:
     - mlrun

 minio:
   image: quay.io/minio/minio
   #network_mode: "host"
   volumes:
     #- /d/data:/data
     #- ./data:/data
     - ~/minio-data:/data
   ports:
     - 9000:9000
     - 9001:9001
   #extra_hosts:
   #  - "host.docker.internal:host-gateway"
   environment:
     MINIO_ROOT_USER: 'minio_user'
     MINIO_ROOT_PASSWORD: 'minio_password'
     MINIO_ADDRESS: ':9000'
     MINIO_STORAGE_USE_HTTPS: False
     MINIO_CONSOLE_ADDRESS: ':9001'
     #MINIO_LAMBDA_WEBHOOK_ENABLE_function: 'on'
     #MINIO_LAMBDA_WEBHOOK_ENDPOINT_function: 'http://localhost:5000'
   command: minio server /data
   healthcheck:
     test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
     interval: 30s
     timeout: 20s
     retries: 3
   networks:
     - mlrun
  
volumes:
 nuclio-platform-config: {}

networks:
 mlrun:
   name: mlrun

文件名: compose-with-jupyter-minio.yaml

# MLRun configuration
HOST_IP=127.17.0.01
SHARED_DIR=~/mlrun-data

文件名: config.env

运行下面显示的 docker-compose 命令将启动我们的服务。

docker-compose -f compose-with-jupyter-minio.yaml --env-file config.env up -d

服务在 Docker 中运行后,导航到以下 URL 以查看 Jupyter、MinIO、MLRun 和 Nuclio 的控制台。

  • Jupyter Notebook:http://localhost:8888/lab

  • MinIO控制台:http://localhost:9001/browser

  • MLRun 控制台:http://localhost:8060/mlrun/projects

  • Nuclio 控制台:http://localhost:8070/projects

在结束在开发计算机上设置 MLRun 的练习之前,让我们创建并运行一个简单的无服务器函数,以确保一切正常。

运行简单的无服务器函数

在本演示中,我们将使用 Jupyter 服务器。它已经安装了 Python mlrun 库。如果您需要其他库,可以启动终端选项卡并安装它们。我们将需要 minio Python SDK。下面的屏幕截图显示了如何启动终端窗口并安装 minio 库。

单击“终端”按钮,您将获得一个类似于下面所示的选项卡。

此选项卡的操作方式与 Mac 上的“终端”应用程序类似。它允许您将所需的任何库安装到 Jupyter 服务中,我们的函数将在其中执行。

安装库后,创建一个名为“simple demo”的新文件夹并导航到它。下载此帖子的示例代码,并将以下文件上传到新文件夹:

  • simple_serverless_function.py
  • simple_serverless_function_setup.ipynb
  • minio.env
  • mlrun.env
  • minio_utilities.py

我们要发送到 MLRun 的函数是 simple_serverless_function.py,如下所示。函数名称为“train_model”——我们不会在这篇文章中训练实际模型。我们只是想让无服务器函数正常工作。请注意,此函数具有“mlrun.handler()”装饰器。它包装了能够解析和保存输入和输出的函数。此外,它不必是密封的(仅使用其中定义的资源)——它可以使用在模块级别导入的库,这些库可以是其他代码模块。在我们的例子中,我们有一个位于同一目录中的minio实用程序模块。

from typing import Dict

import mlrun
import minio_utilities as mu

@mlrun.handler()
def train_model(data_bucket: str=None, training_parameters: Dict=None):
   logger = mu.create_logger()
   logger.info(data_bucket)
   logger.info(training_parameters)
   bucket_list = mu.get_bucket_list()
   logger.info(bucket_list)

文件名: simple_serverless_function.py

在功能方面,这个函数所做的只是记录输入参数,只是为了好玩,我正在连接到 MinIO 以获取所有存储桶的列表。作为这个简单演示的一部分,我想证明 MinIO 的连接性。minio_utilities.py 中的 get_bucket_list() 函数如下所示。


import logging
import os
import sys
from typing import Any, Dict, List, Tuple

from dotenv import load_dotenv
from minio import Minio
from minio.error import S3Error


LOGGER_NAME = 'train'
LOGGING_LEVEL = logging.INFO

load_dotenv('minio.env')
MINIO_URL = os.environ['MINIO_URL']
MINIO_ACCESS_KEY = os.environ['MINIO_ACCESS_KEY']
MINIO_SECRET_KEY = os.environ['MINIO_SECRET_KEY']
if os.environ['MINIO_SECURE']=='true': MINIO_SECURE = True
else: MINIO_SECURE = False


def create_logger() -> None:
   logger = logging.getLogger(LOGGER_NAME)

   #if not logger.hasHandlers():
   logger.setLevel(LOGGING_LEVEL)
   formatter = logging.Formatter('%(process)s %(asctime)s | %(levelname)s | %(message)s')

   stdout_handler = logging.StreamHandler(sys.stdout)
   stdout_handler.setLevel(logging.DEBUG)
   stdout_handler.setFormatter(formatter)

   logger.handlers = []
   logger.addHandler(stdout_handler)

   return logger


def get_bucket_list() -> List[str]:
   logger = create_logger()

   # Get data of an object.
   try:
       # Create client with access and secret key
       client = Minio(MINIO_URL,  # host.docker.internal
                   MINIO_ACCESS_KEY, 
                   MINIO_SECRET_KEY,
                   secure=MINIO_SECURE)

       buckets = client.list_buckets()

   except S3Error as s3_err:
       logger.error(f'S3 Error occurred: {s3_err}.')
       raise s3_err
   except Exception as err:
       logger.error(f'Error occurred: {err}.')
       raise err

   return buckets

文件名: minio_utilities.py

用于保存 MinIO 连接信息的“minio.env”文件如下所示。您需要获取自己的访问密钥和密钥,并将它们放入此文件中。另外,请注意,我使用“minio”作为 MinIO 的主机名。这是因为我们从与 MinIO 相同的 Docker Compose 网络中的服务进行连接。如果要从此网络外部连接到此 MinIO 实例,请使用 localhost。


MINIO_URL=minio:9000
MINIO_ACCESS_KEY=lwycuW6S5f7yJZt65tRK
MINIO_SECRET_KEY=d6hXquiXGpbmfR8OdX7Byd716hmhN87xTyCX8S0K
MINIO_SECURE=false

minio.env file

回顾一下,我们有一个无服务器函数,它记录了传递给它的所有输入参数。它还连接到 MinIO 并获取存储桶列表。我们现在唯一需要做的就是打包我们的函数并将其传递给 MLRun。我们将在 simple_serverless_function_setup.ipynb 笔记本中执行此操作。下面是这个笔记本中的单元格。

导入我们需要的库。


import os
import mlrun

下面的单元格使用“mlrun.env”文件来通知我们的环境在哪里可以找到 MLRun API 服务。它还将 MLRun 连接到兼容 S3 的对象存储,以保存项目。这是我们通过 docker compose 文件创建的 MinIO 实例。


# Set the environment:
mlrun.set_environment(env_file='mlrun.env', artifact_path='s3://mlrun/simple-demo')

# remote MLRun service address
MLRUN_DBPATH=http://mlrun-api:8080

# AWS S3/services credentials
S3_ENDPOINT_URL=minio:9000
AWS_ACCESS_KEY_ID={Put MinIO access key here.}
AWS_SECRET_ACCESS_KEY={Put MinIO secret key here.}

文件名: mlrun.env file

接下来,我们创建一个 MLRun 项目。此项目将与我们的所有指标和工件相关联。用于此步骤的项目目录是代码所在的文件夹。


# Create the project:
project_name='simple-test'
project_dir = os.path.abspath('./')
project = mlrun.get_or_create_project(project_name, project_dir, user_project=False)
print(project_dir)

set_function() 方法告诉 MLRun 在哪里可以找到你的函数以及你希望它如何运行。handler 参数必须包含使用 mlrun.handler() 装饰器批注的函数的名称。

# Create the serverless function.
trainer = project.set_function(
   "simple_serverless_function.py", name="trainer", kind="job",
   image="mlrun/mlrun",
   handler="train_model"
)

下面的单元格创建了一些示例模型训练参数。

# Sample hyperparameters
training_parameters = {
   'batch_size': 32,
   'device': 'cpu',
   'dropout_input': 0.2,
   'dropout_hidden': 0.5,
   'epochs': 5,
   'input_size': 784,
   'hidden_sizes': [1024, 1024, 1024, 1024],
   'lr': 0.025,
   'momentum': 0.5,
   'output_size': 10,
   'smoke_test_size': -1
   }

最后,我们开始运行该函数,如下所示。“local”参数告诉 MLRun 在当前系统上运行该函数,在本例中为 Jupyter Notebook 服务器。如果设置为 False,则该函数将发送到 Nuclio。此外,“inputs”参数的类型需要为 Dict[str, str];如果您使用其他任何东西,则会出现错误。


# Run the function.
trainer_run = project.run_function(
   "trainer",
   inputs={"data_bucket": "mnist"},
   params={"training_parameters": training_parameters},
   local=True
)

在 MLRun UI 中查看结果

功能完成后,转到 MLRun 主页以查找您的项目。单击表示项目的磁贴。我们的函数是在“简单测试”项目下运行的。

下一页将显示所有运行中与项目相关的所有内容。如下所示。

在“作业和工作流”部分下查看,然后单击要查看的运行。这将显示有关运行的详细信息,如下所示。

对调试有用的是“日志”选项卡。在这里,我们可以看到我们从简单函数中记录的消息,这些函数记录了输入参数,连接到 MinIO,然后记录了在 MinIO 中找到的所有存储桶。

摘要和后续步骤

在这篇文章中,我们使用 Docker Compose 在开发机器上安装了 MLRun。我们还创建并运行了一个简单的无服务器函数,以了解如何在 MLRun 中构建代码。我们的代码能够连接到 MinIO 以编程方式检索存储桶列表。我们还将 MLRun 配置为使用 MinIO 进行工件存储。

显然,我们简单的无服务器功能几乎没有触及 MLRun 可以做的事情的表面。接下来的步骤包括使用流行的框架实际训练模型,使用 MLRun 进行分布式训练,以及探索对大型语言模型的支持。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

来聊聊redis文件事件驱动的设计

写在文章开头 近期团队安排变得比较紧急&#xff0c;关于redis系列的更新相对放缓一些&#xff0c;而我们今天要讨论的就是redis中关于事件模型的设计&#xff0c;我们都知道redis通过单线程实现高效的网络IO处理&#xff0c;本文会从源码的角度来讲解一下redis中文件事件驱动…

国内怎样使用GPT4 turbo

GPT是当前最为熟知的大模型&#xff0c;它优越的性能一直遥遥领先于其它一众厂商&#xff0c;然而如此优秀的AI在中国境内却是无法正常使用的。本文将告诉你4种使用gpt4的方法&#xff0c;让你突破限制顺利使用。 官方售价是20美元/月&#xff0c;40次提问/3小时&#xff0c;需…

CSDN自定义模块全攻略,DIY系统原有样式打造专属个性化主页!

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f4af;如何通过HTMLCSS自定义模板diy出自己的个性化csdn主页&#x…

Developer Day北京站倒计时三天|请查收您的参会指南!

MongoDB Developer Day 6/22北京站 倒计时3天&#xff0c;期待您的出席&#xff01; 请收藏您的行前温馨贴士⬇️ MongoDB Developer Day 专为开发者打造的动手实操工作坊和模型设计优化专场&#xff01; 本活动针对开发者和产品负责人设计&#xff0c;旨在学习NoSQL数据建…

同三维T80004EH-N HDMI高清NDI编码器

1路HDMI 1路3.5音频输入,支持NDI 产品简介&#xff1a; 同三维T80004EH-N 高清HDMI编码器是专业的NDI高清音视频编码产品&#xff0c;该产品支持1路高清HDMI音视频采集功能&#xff0c;1路3.5MM独立音频接口采集功能。编码输出双码流H.265/H.264格式&#xff0c;音频MP3/AAC格…

初阶 《数组》 3. 数组越界

3. 数组越界 数组的下标是有范围限制的。 数组的下规定是从0开始的&#xff0c;如果数组有n个元素&#xff0c;最后一个元素的下标就是n-1。 所以数组的下标如果小于0&#xff0c;或者大于n-1&#xff0c;就是数组越界访问了&#xff0c;超出了数组合法空间的访问。 C语言本身…

VUE面试题汇总(九)

之间联系&#xff08;Model 和 ViewModel 的双向数据绑定&#xff09; 解析&#xff1a; MVVM 是 Model-View-ViewModel 的缩写。MVVM 是一种设计思想。Model 层代表数据模型&#xff0c;也可以在 Model 中定义数据修改和操作的业务逻辑&#xff1b;View 代表 UI 组件&#xf…

种子流媒体服务器TorrServer

什么是 TorrServer &#xff1f; TorrServer 是一个允许用户在线查看种子而无需预先下载文件的程序。 TorrServer 的核心功能包括缓存种子以及通过 HTTP 协议进行后续数据传输&#xff0c;允许根据系统参数和用户的互联网连接速度调整缓存大小。 软件特点 缓存流媒体本地和远程…

金蝶云星空与MES系统深度集成对接案例全公开

项目背景 深圳市某自动化设备有限公司&#xff0c;自2006年成立以来&#xff0c;一直专注于高端精密自动化设备的研发、生产与销售。作为一家高科技企业&#xff0c;公司依托深圳这一经济特区的地理优势&#xff0c;构建了覆盖全国的服务网络&#xff0c;并拥有两个先进的生产…

爬虫超详细介绍

爬虫&#xff08;Spider&#xff09;是一种自动化程序&#xff0c;用于在互联网上获取信息。 其工作原理主要可以分为以下几个步骤&#xff1a; 发起请求&#xff1a; 爬虫首先需要向目标网站发起HTTP请求&#xff0c;以获取网页的内容。这个请求可以包含一些额外的信息&…

【C++】类和对象(四)拷贝构造、赋值运算符重载

文章目录 四、拷贝构造函数干嘛的&#xff1f;写拷贝构造函数的注意事项正确写法 不显示定义拷贝构造函数的情况浅拷贝:one:示例&#xff1a;内置类型:two:示例&#xff1a;自定义类型一个提问 深拷贝 五、赋值运算符重载运算符重载函数原型注意调用时的两种书写方式完整实现代…

skywalking segment索引占用elasticsearch大量磁盘空间

现象&#xff1a; skywalking segment索引占用elasticsearch大量磁盘空间 原因 recordDataTTL 是SkyWalking的一个配置项&#xff0c;用于设置记录数据的存活时间&#xff08;TTL, Time To Live&#xff09;。SkyWalking是一个开源的应用性能监控系统&#xff0c;用于监控分…

tplink安防监控raw文件转码合成mp4的方法

Tplink(深圳普联)专业的网络设备生产商&#xff0c;属于安防监控市场的后来者。Tplink的安防产品恢复了很多&#xff0c;其嵌入式文件系统也一直迭代更新。今天要说的案例比较特殊&#xff0c;其不仅仅要求恢复&#xff0c;还要求能解析出音频并且要求画面和声音实现“同步”。…

入门Rabbitmq

1、什么是消息队列 消息队列&#xff1a;应用之间传递消息的方式&#xff0c;允许应用程序异步发送和接收消息&#xff0c;不需要连接对方 消息&#xff1a;文本字符串&#xff0c;对象.... 队列&#xff1a;存储数据。先进先出 2、应用场景 ①库存系统挂掉之后 MQ会等待&…

AI PPT生成器,一键在线智能生成PPT工具

PPT作为商业沟通和教育培训中的重要工具&#xff0c;PPT制作对于我们来说并不陌生。但是传统的PPT制作不仅耗时&#xff0c;而且想要做出精美的PPT&#xff0c;需要具备一定的设计技能。下面小编就来和大家分享几款AI PPT工具&#xff0c;只要输入主题&#xff0c;内容就可以在…

本地快速部署大语言模型开发平台Dify并实现远程访问保姆级教程

文章目录 前言1. Docker部署Dify2. 本地访问Dify3. Ubuntu安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署大语言模型应用开发平台Dify,并结合cpolar内网穿透工具实现公网环境远程访问…

C# WPF入门学习主线篇(二十八)—— 使用集合(ObservableCollection)

C# WPF入门学习主线篇&#xff08;二十八&#xff09;—— 使用集合&#xff08;ObservableCollection&#xff09; 在WPF中&#xff0c;数据绑定是构建动态和响应式用户界面的关键。ObservableCollection是一个特别有用的集合类型&#xff0c;它不仅支持数据绑定&#xff0c;还…

在Tomcat中部署war包

1、准备war包 确保已经有一个有效的war包&#xff0c;该war包包含了web应用程序的所有内容&#xff1b; 2、停止tomcat服务器 在部署之前&#xff0c;确保tomcat服务器已经停止&#xff0c;进入tomcat的配置目录执行命令&#xff1a;[路径]/tomcat/conf&#xff1b; 在Linux…

windows系统实现应用程序开机即运行(不登录系统也行)

由于近期需要设置一个Java程序开机自启动&#xff0c;因此试了一下方法&#xff0c;总结了两点&#xff0c;一个是需要用户登录系统之后再启动&#xff0c;一种是不需要登录&#xff0c;只要开机就会启动。 先看准备工作&#xff0c;写一个启动脚本&#xff1a; echo on E: cd…

[STM32]万年历

[STM32]万年历 需要资料的请在文章末尾获取~ ​​ 01描述 使用原件&#xff1a;stm32f103c8t6最小系统板x1&#xff0c;0.96寸OLED显示屏四角x1&#xff0c;4x4矩阵按键x1; 键位对应图&#xff1a; 1&#xff0c; 2&#xff0c; 3&#xff0c; 4------------- 切换页面 设置…