0

0

【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型

P粉084495128

P粉084495128

发布时间:2025-08-01 17:36:12

|

600人浏览过

|

来源于php中文网

原创

本文介绍将paddlepaddle及paddlehub模型通过转换为onnx模型,再用openvino调用的方案。因paddle模型在云函数部署麻烦、存储空间大且intel cpu上预测速度不稳,而openvino可优化且支持onnx模型。文中详述环境配置,以及两种模型转换为onnx并在openvino调用的步骤,还提及相关问题与解决尝试。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【paddlepaddle+openvino】用paddehub的onnx模型 - php中文网

一、前言

1. 使用OpenVINO或ONNX部署的需求来源

  • PaddlePaddle的模型在serverless云函数部署上较麻烦或无法在较少存储空间的环境下部署,整个PaddlePaddle太大了,除非用Paddle Lite否则根本无法放进云函数运行
  • 在intel cpu的云服务器上可以看出其预测速度不是很稳定,有优化空间,OpenVINO可能可以优化这部分
  • PaddleHub有很多amazing的模型,但无法在云函数部署或无法在较少存储空间的环境下部署,涉及的import包太多太大

2. OpenVINO及ONNX的当前状态

  • OpenVINO 在2020.04开始就可以直接调用onnx模型了
  • ONNX模型还是支持较多的PaddlePaddle的算子
  • 但OpenVINO暂未直接支持Paddle模型,要用dev版来部署我也一直没跑通,环境配置较麻烦
  • Paddle模型转ONNX已较成熟,且ONNX能直接被OpenVINO调用
  • 转换成ONNX模型也可以较方便用在其他地方

3. 本项目方案

  • 所以,综合简单方便的原则,我采用的方案是:
  1. 使用PaddlePaddle模型或PaddleHub模型转成ONNX模型
  2. OpenVINO调用ONNX模型的方案。环境既简单,也能用到OpenVINO在intel设备上的加速效果。

二、环境配置

  • aistudio的限制,OpenVINO调用模型还是不行,但亲测在自己的centOS服务器运行没问题。
  • 傻瓜式配置,仅需下面的几个pip安装即可,无需编译。
In [2]
!pip install -q  paddle2onnx
!pip install -q  openvino
!pip install -q onnx
!pip install -q onnxruntime
   

三、PaddlePaddle模型及PaddleHub模型在OpenVINO中使用

  • PaddlePaddle搭建模型时通常从vision库的backbone搭起,所以本次测试使用mobilenet
  • PaddleHub中有很多amazing的模型,例如:风格迁移模型StyleProNet(PaddleHub官方介绍)
  • 风格迁移模型StyleProNet有2个网络(如下图),一个是encoder,一个是decoder,我们分别对他们进行转换,转换2个ONNX模型来调用,【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网            

1 PaddlePaddle模型转成ONNX,在OpenVINO调用

  • 这里仅展示动态图的,静态图也可参考另一位大大的项目Paddle2.0导出ONNX模型和推理

1.1 准备PaddlePaddle动态图模型

选用了vision库中的mobilenet V2为实例,把其设为eval模式。大家看到net的打印,看到是一层层网络结构

In [25]
import osimport timeimport paddle# 从模型代码中导入模型from paddle.vision.models import mobilenet_v2# 实例化模型net = mobilenet_v2()print(net)# 将模型设置为推理状态net.eval()
   

1.2 转换Paddle模型为ONNX

In [27]
# 定义输入数据input_spec = paddle.static.InputSpec(shape=[None, 3, 224, 224], dtype='float32', name='image')# ONNX模型导出# enable_onnx_checker设置为True,表示使用官方ONNX工具包来check模型的正确性,需要安装ONNX(pip install onnx)paddle.onnx.export(net, 'mobilenet_v2', input_spec=[input_spec], opset_version=12, enable_onnx_checker=True)
       
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/dygraph_to_static/convert_call_func.py:89: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  func_in_dict = func == v
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/math_op_patch.py:322: UserWarning: /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/vision/models/mobilenetv2.py:99
The behavior of expression A + B has been unified with elementwise_add(X, Y, axis=-1) from Paddle 2.0. If your code works well in the older versions but crashes in this version, try to use elementwise_add(X, Y, axis=0) instead of A + B. This transitional warning will be dropped in the future.
  op_type, op_type, EXPRESSION_MAP[method_name]))
       
2021-09-11 22:40:22 [INFO]	ONNX model genarated is valid.
2021-09-11 22:40:22 [INFO]	ONNX model saved in mobilenet_v2.onnx
       

1.3 ONNX模型测试及调用

  • 误差很少,转换没问题
In [28]
# 动态图导出的ONNX模型测试import timeimport numpy as npfrom onnxruntime import InferenceSession# 加载ONNX模型sess = InferenceSession('mobilenet_v2.onnx')# 准备输入x = np.random.random((1, 3, 224, 224)).astype('float32')# 模型预测start = time.time()
ort_outs = sess.run(output_names=None, input_feed={'image': x})
end = time.time()print("Exported model has been predicted by ONNXRuntime!")print('ONNXRuntime predict time: %.04f s' % (end - start))# 对比ONNXRuntime和Paddle预测的结果paddle_outs = net(paddle.to_tensor(x))

diff = ort_outs[0] - paddle_outs.numpy()
max_abs_diff = np.fabs(diff).max()if max_abs_diff < 1e-05:    print("The difference of results between ONNXRuntime and Paddle looks good!")else:
    relative_diff = max_abs_diff / np.fabs(paddle_outs.numpy()).max()    if relative_diff < 1e-05:        print("The difference of results between ONNXRuntime and Paddle looks good!")    else:        print("The difference of results between ONNXRuntime and Paddle looks bad!")    print('relative_diff: ', relative_diff)print('max_abs_diff: ', max_abs_diff)
       
Exported model has been predicted by ONNXRuntime!
ONNXRuntime predict time: 0.0125 s
The difference of results between ONNXRuntime and Paddle looks good!
max_abs_diff:  3.0553338e-13
       

2 PaddleHub 模型在OpenVINO中使用

  • a. 步骤:

    a.1 PaddleHub模型导出inference模型

    a.2 inference模型转成ONNX模型

    a.3 在OpenVINO调用

  • b. PaddleHub模型中有很多直接有 save_inference_model 方法,可以直接导出。

  • c. 本次测试模型:

    c.1 分类模型,mobilenet_v3_large_imagenet_ssld

    c.2 风格转换模型,stylepro_artistic

2.1 PaddleHub模型导出inference模型

    1. mobilenet_v3模型
In [ ]
import paddleimport paddlehub as hub# 定义输入数据input_spec = paddle.static.InputSpec(shape=[None, 3, 224, 224], dtype='float32', name='image')# ONNX模型导出#paddle.onnx.export(model, 'stylepro', input_spec=[input_spec], opset_version=12)#Source: https://www.paddlepaddle.org.cn/hublistmodel = hub.Module(name="mobilenet_v3_large_imagenet_ssld")
model.save_inference_model(dirname="mobilenet_v3_large_imagenet_ssld/", 
                           model_filename="mobilenet_v3_large_imagenet_ssld/inference.pdmodel", 
                           params_filename="mobilenet_v3_large_imagenet_ssld/inference.pdiparams")#paddle.onnx.export(model, 'mobilenet', input_spec=[input_spec], opset_version=11)
       
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/__init__.py:107: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import MutableMapping
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/rcsetup.py:20: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import Iterable, Mapping
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/colors.py:53: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import Sized
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/scipy/linalg/__init__.py:217: DeprecationWarning: The module numpy.dual is deprecated.  Instead of using dual, use the functions directly from numpy or scipy.
  from numpy.dual import register_func
       
Download https://bj.bcebos.com/paddlehub/paddlehub_dev/mobilenet_v3_large_imagenet_ssld_1.0.0.tar.gz
[##################################################] 100.00%
Decompress /home/aistudio/.paddlehub/tmp/tmpgvkuhymh/mobilenet_v3_large_imagenet_ssld_1.0.0.tar.gz
[##################################################] 100.00%
       
[2021-09-11 21:26:50,522] [    INFO] - Successfully installed mobilenet_v3_large_imagenet_ssld-1.0.0
[2021-09-11 21:26:50,548] [ WARNING] - The _initialize method in HubModule will soon be deprecated, you can use the __init__() to handle the initialization of the object
       
    1. stylepro_artistic模型
In [ ]
import paddleimport paddlehub as hub# ONNX模型导出#paddle.onnx.export(model, 'stylepro', input_spec=[input_spec], opset_version=12)#Source: https://www.paddlepaddle.org.cn/hublistmodel = hub.Module(name="stylepro_artistic")
model.save_inference_model(dirname="stylepro_artistic/", 
                           model_filename="stylepro_artistic/inference.pdmodel", 
                           params_filename="stylepro_artistic/inference.pdiparams")#paddle.onnx.export(model, 'mobilenet', input_spec=[input_spec], opset_version=11)
       
Download https://bj.bcebos.com/paddlehub/paddlehub_dev/stylepro_artistic_1.0.1.tar.gz
[##################################################] 100.00%
Decompress /home/aistudio/.paddlehub/tmp/tmpc94wa04d/stylepro_artistic_1.0.1.tar.gz
[##################################################] 100.00%
       
[2021-09-11 21:28:03,186] [    INFO] - Successfully installed stylepro_artistic-1.0.1
[2021-09-11 21:28:03,208] [ WARNING] - The _initialize method in HubModule will soon be deprecated, you can use the __init__() to handle the initialization of the object
       

2.2 inference模型转onnx模型

  • 尝试了inference模型直接转OpenVINO的IR模型,但环境一直没配置好,【Failed】
  • 尝试了inference模型转ONNX模型,模型转成功了,onnx.checker.check_model(onnx_model)检测模型也是ok的.【Sucess】
In [6]
# stylepro_artistic 模型的encoder 与decoder!paddle2onnx \
    --model_dir stylepro_artistic/encoder \
    --model_filename inference.pdmodel \
    --params_filename inference.pdiparams \
    --save_file stylepro_artistic_encoder.onnx \
    --opset_version 12!paddle2onnx \
    --model_dir stylepro_artistic/decoder \
    --model_filename inference.pdmodel \
    --params_filename inference.pdiparams \
    --save_file stylepro_artistic_decoder.onnx \
    --opset_version 12
   
In [7]
# mobilenet模型!paddle2onnx \
    --model_dir mobilenet_v3_large_imagenet_ssld \
    --model_filename inference.pdmodel \
    --params_filename inference.pdiparams \
    --save_file mobilenet_v3_large_imagenet_ssld.onnx \
    --opset_version 12
   

查看模型

There’s An AI For That
There’s An AI For That

全球领先的 AI 聚合器,收集10,225个AI工具,可用于超过2,548个任务。

下载
  • 转换成功的ONNX模型可以使用Netron观看结构,看到输入输出的维度,看到整个模型结构

  • Netron是很方便的工具,能看几乎你能想到的所有框架的模型(tf,keras,CoreML,ONNX,PaddlePaddle....),推荐下载使用 http://www.electronjs.org/apps/netron

  • 可以看到stylepro_artistic_encoder.onnx的输出是 512* 64* 64

【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网        

  • 对应地,stylepro_artistic_decoder.onnx的输入是 512* 64* 64

【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网        

2.3 OpenVINO中调用

  • 先尝试了ONNX中调用,尽管模型检查都没问题,但在onnxruntime.InferenceSession(onnx_file)时一直都报错nvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Failed to load model with error: Unknown model file format version.暂未解决
  • 尝试用OpenVINO调用,在自己服务器是成功的,在aistudio上运行,会因权限等问题报`GLIBC_2.27' not found 的错误

下方代码为PaddleHub的mobilenet模型的调用

In [ ]
import os, os.pathimport sysimport jsonimport urllib.requestimport cv2import numpy as npfrom imagenet_class_index_json import imagenet_classes #print(imagenet_classes['12']) imagenet类别index对应表from openvino.inference_engine import IENetwork, IECore, ExecutableNetworkfrom IPython.display import Imagedef image_preprocess_mobilenetv3(img_path):
    img = cv2.imread(img_path)
    img = cv2.resize(img, (224,224))
    img = np.transpose(img, [2,0,1]) / 255
    img = np.expand_dims(img, 0)
    img_mean = np.array([0.485, 0.456,0.406]).reshape((3,1,1))
    img_std = np.array([0.229, 0.224, 0.225]).reshape((3,1,1))
    img -= img_mean
    img /= img_std    return img.astype(np.float32)def top_k(result, topk=5):
    #imagenet_classes = json.loads(open("utils/imagenet_class_index.json").read())
    indices = np.argsort(-result[0])    for i in range(topk):        print("Class name:","'"+imagenet_classes[str(indices[0][i])][1]+"'",              ", probability:", result[0][0][indices[0][i]])
              
ie = IECore()

onnx_model='mobilenet_v3_large_imagenet_ssld.onnx'# 直接使用ONNX格式加载net = ie.read_network(model=onnx_model)

filename = "/root/tmp/test1.jpg"test_image = image_preprocess_mobilenetv3(filename) 

# pdmodel might be dynamic shape, this will reshape based on the inputinput_key = list(net.input_info.items())[0][0] # 'inputs'net.reshape({input_key: test_image.shape})#load the network on CPUexec_net = ie.load_network(net, 'CPU') 
assert isinstance(exec_net, ExecutableNetwork)#perform the inference stepoutput = exec_net.infer({input_key: test_image})
result_ie = list(output.values())print(result_ie)#Image(filename=filename)
       
---------------------------------------------------------------------------ImportError Traceback (most recent call last)python-input-26-58940573a306> in  ----> 1 from openvino.inference_engine import IECore 2onnx_model 3 ie = IECore() 4 onnx_model='mobilenet_v2.onnx' 5 # 直接使用ONNX格式加载 /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/openvino/inference_engine/__init__.py in  ----> 1 from .ie_api import * 2 __all__ = ['IENetwork', "TensorDesc", "IECore", "Blob", "PreProcessInfo", "get_version"] 3 __version__ = get_version() 4 ImportError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.27' not found (required by /opt/conda/envs/python35-paddle120-env/bin/../lib/libngraph.so)

下方为PaddleHub的stylepro_artistic模型的使用

  • 步骤:

    1. 图片前处理
    2. 模板图片与内容图片通过 OpenVINO encode模型分别获取feature
    3. 两图片的feature根据alpha融合
    4. 融合的feature通过 OpenVINO decode模型转换得到图片
    5. 图片后处理并保存
  • 代码参考:

    1. github中的PaddleHub项目 stylepro_artistic
    2. 图片前后处理就是参考原代码,放在processor.py中。
  • 效果展示:

     content原图,				pattern样式图片
               
【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网 【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网        
	输出的图片out
【PaddlePaddle+OpenVINO】用PaddeHub的ONNX模型 - php中文网        
  • 备注:

同样地,需要在自己的服务器或电脑运行,aistudio上跑OpenVINO会报GLIBC_2.27的错。但代码亲测有效。

In [3]
import os, os.pathimport sysimport jsonimport urllib.requestimport cv2import numpy as npfrom processor import *from openvino.inference_engine import IENetwork, IECore, ExecutableNetworkfrom IPython.display import Image

modelPath=""picPath='work/'def decodeImg(input_data,onnx_model=modelPath+'stylepro_artistic_decoder.onnx'):    
    #onnx_model=rootPath+'stylepro_artistic_encoder.onnx'
    ie = IECore()    #
    net = ie.read_network(model=onnx_model)    # pdmodel might be dynamic shape, this will reshape based on the input
    input_key = list(net.input_info.items())[0][0] # 'inputs'
    net.reshape({input_key: input_data.shape})    #load the network on CPU
    exec_net = ie.load_network(net, 'CPU')    assert isinstance(exec_net, ExecutableNetwork)    #perform the inference step
    output = exec_net.infer({input_key: input_data})
    result_ie =list(output.values())[0]
    result_ie=np.array(result_ie)    #filter and print the top 5 results 
    print(result_ie.shape)    # ´(1, 1, 512, 28, 28)
    return result_iedef encodeFeat(picname,onnx_model=modelPath+'stylepro_artistic_encoder.onnx'):
    
    #onnx_model=rootPath+'stylepro_artistic_encoder.onnx'
    ie = IECore()    # 
    net = ie.read_network(model=onnx_model)
    test_image = image_preprocess(picname) 
    # pdmodel might be dynamic shape, this will reshape based on the input
    input_key = list(net.input_info.items())[0][0] # 'inputs'
    net.reshape({input_key: test_image.shape})    #load the network on CPU
    exec_net = ie.load_network(net, 'CPU')    assert isinstance(exec_net, ExecutableNetwork)    #perform the inference step
    output = exec_net.infer({input_key: test_image})
    result_ie =list(output.values())
    result_ie=np.array(result_ie)    #filter and print the top 5 results 
    print(result_ie.shape)    # output is :(1, 1, 512, 28, 28)
    return result_ie


content =cv2.imread(picPath+ "jj6.jpg")

pattern =cv2.imread(picPath+ "shahua.jpg")## get feature of pattern picture and content picturefea1=outputFeat(content)
fea2=outputFeat(pattern)##fr_feats = fr(fea1,fea2,1)print('fr_feats',fr_feats.shape)

output=decodeImg(fr_feats)
output=np.squeeze(output)#print('output',output.shape)#out=post_process(output,content.shape)print('out,',out['data'].shape)
cv2.imwrite(picPath+'out.jpg',out['data'])
       
---------------------------------------------------------------------------ImportError Traceback (most recent call last) in  6 import numpy as np 7 from processor import * ----> 8 fromopenvino.inference_engine import IENetwork, IECore, ExecutableNetwork 9 from IPython.display import Image 10 /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/openvino/inference_engine/__init__.py in  ----> 1 from .ie_api import * 2 __all__ = ['IENetwork', "TensorDesc", "IECore", "Blob", "PreProcessInfo", "get_version"] 3 __version__ = get_version() 4 ImportError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.27' not found (required by /opt/conda/envs/python35-paddle120-env/bin/../lib/libngraph.so)

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

6

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

6

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

8

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

14

2026.02.27

Golang 高级特性与最佳实践:提升代码艺术
Golang 高级特性与最佳实践:提升代码艺术

本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。

17

2026.02.27

Golang 测试与调试专题:确保代码可靠性
Golang 测试与调试专题:确保代码可靠性

本专题聚焦 Golang 的测试与调试体系,系统讲解单元测试、表驱动测试、基准测试与覆盖率分析方法,并深入剖析调试工具与常见问题定位思路。通过实践示例,引导建立可验证、可回归的工程习惯,从而持续提升代码可靠性与可维护性。

2

2026.02.27

漫蛙app官网链接入口
漫蛙app官网链接入口

漫蛙App官网提供多条稳定入口,包括 https://manwa.me、https

130

2026.02.27

deepseek在线提问
deepseek在线提问

本合集汇总了DeepSeek在线提问技巧与免登录使用入口,助你快速上手AI对话、写作、分析等功能。阅读专题下面的文章了解更多详细内容。

8

2026.02.27

AO3官网直接进入
AO3官网直接进入

AO3官网最新入口合集,汇总2026年可用官方及镜像链接,助你快速稳定访问Archive of Our Own平台。阅读专题下面的文章了解更多详细内容。

208

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 9.9万人学习

Git 教程
Git 教程

共21课时 | 3.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号