
我们经常讨论到的模型大都基于大文本的模型,鲜有谈及视觉这一块,今天我们结合文本模型来梳理探讨一下视觉的模型,计算机视觉(CV)和自然语言处理(NLP)是两个相对独立的研究领域,CV 模型(如 ResNet、ViT)专注于从图像中提取视觉特征,擅长分类、检测等任务,但无法理解图像的语义文本描述;NLP 模型则聚焦于文本的语义理解,却缺乏对视觉信息的感知能力,对单一的传统视觉和文本模型都有很大的局限性。
传统的跨模态任务(如图文检索、图像字幕)通常需要针对特定任务设计专用模型,且依赖大量标注数据,泛化能力差。例如,训练一个图像分类模型需要数万张标注好的图像,换一个分类类别就需要重新标注和训练,成本极高。这种模态割裂和任务专用的模式,限制了 AI 模型的通用能力。
CLIP,全称Contrastive Language-Image Pre-training,对比语言-图像预训练,在2021年由OpenAI提出,核心突破在于通过对比学习将图像和文本映射到同一个高维表征空间,让模型能够直接比较图像和文本的语义相似度。其核心思路是:利用互联网上海量的无结构化图文对(如网页中的图片和标题)进行预训练,让模型学习 “图像内容对应的文本描述” 这一通用规律,而非针对特定任务的特征。
CLIP 不再依赖人工标注的任务数据,而是从大规模的图文数据中学习通用的跨模态表征,这使得模型具备了强大的零样本迁移能力,无需针对新任务微调,仅通过文本提示即可完成新类别的识别。CLIP 重新定义了跨模态学习的范式,证明了大规模对比预训练能够实现通用的视觉 - 文本对齐。
CLIP 的零样本能力大幅降低了计算机视觉任务的落地成本:无需标注大量数据,即可快速适配新的分类场景(如商品分类、缺陷检测);同时,CLIP 也被广泛应用于图文检索、AIGC(如文生图的文本编码)、人机交互等场景,成为多模态 AI 的核心基础组件。

跨模态学习旨在建立不同模态数据(如视觉、文本、音频)之间的语义关联,将不同模态的信息映射到统一的表征空间,使得不同模态的特征可以直接进行比较和交互。对于 CLIP 而言,核心模态是图像和文本,其目标是让语义相似的图像和文本在表征空间中距离更近,语义无关的则距离更远。
对比学习是 CLIP 的核心训练范式,属于自监督学习的一种。其核心思想是:为每个样本构建“正样本对”和 “负样本对”,通过损失函数让模型学习区分正/负样本,正样本对的表征尽可能接近,负样本对的表征尽可能远离。
在 CLIP 中,一个批次batch内的每张图像对应的文本描述是其“正样本”,批次内其他所有图像和文本都是其“负样本”。例如,批次中有 N 个图文对,对于第 i 张图像,其正样本是第 i 个文本,负样本是其余 N-1 个文本;同理,对于第 i 个文本,其正样本是第 i 张图像,负样本是其余 N-1 张图像。
CLIP的"对齐"并非简单的特征匹配,而是语义层面的对齐。例如,图像是“一只猫坐在沙发上”,文本是“a cat on the sofa”,即使图像的像素细节或文本的表述方式略有不同,模型也能识别出二者的语义一致性,并将其表征拉近。
这种语义对齐使得模型能够理解图像的文本语义,也能理解文本的视觉含义,从而实现“用文本描述来定义图像类别”的零样本能力。
零样本学习(Zero-Shot Learning, ZSL)指模型在未见过某类别的训练数据时,能够识别该类别的样本。CLIP 的零样本推理核心在于:将新任务的类别转换为文本提示(如 “a photo of a [类别名]”),然后将待识别图像的特征与这些文本提示的特征进行相似度计算,相似度最高的文本对应的类别即为图像的预测类别。
例如,要识别 “熊猫”,只需构造文本 “a photo of a panda”,计算图像特征与该文本特征的余弦相似度,若相似度最高,则判定为熊猫。这种方式无需为 “熊猫” 类别标注任何图像数据,仅通过文本即可定义类别,实现零样本识别。
CLIP 采用“双编码器”架构,由图像编码器和文本编码器两部分组成,整体流程如下:
CLIP 提供了两种图像编码器选型,CNN(ResNet)与 Transformer(ViT)均经过适配改造:
CLIP 的文本编码器基于简化版的 Transformer Decoder仅保留编码器结构,针对短文本(图文对的文本通常较短)做了优化:
文本编码器的输出维度与图像编码器完全一致,确保二者的特征可以直接计算相似度。
1. 批量对比学习的实现逻辑
CLIP 的对比学习依赖 “批次内负样本”,批次大小(batch size)是影响训练效果的关键参数:批次越大,负样本越多,模型学习的对比信号越充分。OpenAI 的 CLIP 预训练使用了 32768 的超大批次,结合分布式训练实现。
批量对比的核心逻辑:
这种方式无需额外构造负样本,仅通过批次内的样本即可实现对比学习,大幅降低了训练成本。
2. 零样本分类的核心原理
CLIP 的零样本分类流程可概括为 “文本提示工程 + 相似度匹配”,具体步骤:
例如,分类类别为 “猫、狗、汽车”,构造文本提示:
计算图像特征与这三个文本特征的相似度,若 “a photo of a cat” 的相似度最高,则预测为猫。
CLIP 的零样本能力本质是 “将分类任务转换为图文相似度匹配任务”,利用预训练学到的图文语义对齐能力,无需微调即可适配新类别。
以下示例实现 “输入一张图像和多个文本,计算图像与每个文本的语义相似度”,计算机环境配置我们选择的是ViT-B/32模型并指定在CPU上运行,分别通过“一只猫”、“一只狗”、“一只趴在沙发上的猫”来体现相似度。
import torch
import clip
from PIL import Image
import matplotlib.pyplot as plt
# 1. 加载模型和预处理函数
# 可选模型:ViT-B/32, ViT-B/16, ViT-L/14, RN50, RN101等
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
# 2. 加载并预处理图像
# 替换为自己的图像路径
# image_path = "cat.jpg"
# image_path = "dog.jpg"
image_path = "cat2.jpg"
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device)
# 3. 定义待匹配的文本列表
texts = [
"a photo of a cat",
"a photo of a dog",
"a photo of a bird",
"a cat sitting on the sofa"
]
# 文本预处理
text = clip.tokenize(texts).to(device)
# 4. 模型推理:提取特征并计算相似度
with torch.no_grad():
# 提取图像和文本特征
image_features = model.encode_image(image)
text_features = model.encode_text(text)
# L2归一化(CLIP模型内部已做归一化,此处可省略,但显式归一化更稳妥)
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
# 计算相似度(图像特征与每个文本特征的点积)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
# 5. 输出结果
print("图像与各文本的相似度:")
for i, txt in enumerate(texts):
print(f"{txt}: {similarity[0][i].item():.4f}")
# 6. 可视化图像和相似度结果
plt.figure(figsize=(10, 5))
# 显示图像
plt.subplot(1, 2, 1)
plt.imshow(Image.open(image_path))
plt.axis("off")
plt.title("Input Image")
# 显示相似度柱状图
plt.subplot(1, 2, 2)
plt.bar(texts, similarity[0].cpu().numpy())
plt.xticks(rotation=45, ha="right")
plt.ylabel("Similarity")
plt.title("Text Similarity")
plt.tight_layout()
plt.show()原图图像:cat.jpg

图像的识别结果匹配度结果输出:
图像与各文本的相似度: a photo of a cat: 0.9666 a photo of a dog: 0.0048 a photo of a bird: 0.0005 a cat sitting on the sofa: 0.0281

原图图像:dog.jpg

图像的识别结果匹配度结果输出:
图像与各文本的相似度: a photo of a cat: 0.0005 a photo of a dog: 0.9994 a photo of a bird: 0.0001 a cat sitting on the sofa: 0.0000

原图图像:cat2.jpg

图像的识别结果匹配度结果输出:
图像与各文本的相似度: a photo of a cat: 0.0845 a photo of a dog: 0.0008 a photo of a bird: 0.0002 a cat sitting on the sofa: 0.9145

以下示例实现 “基于 CLIP 的零样本图像分类”,支持自定义分类类别,图片以上个示例中的图片为主,统一放置在test_images目录下,会根据 ["cat", "dog", "car", "tree", "book"] 这几个类别判断,每张图片属于每个属性的概览是多少,匹配最符合的那个类型。
import torch
import clip
from PIL import Image
import os
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 1. 初始化模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
# 2. 定义分类类别和提示模板
# 自定义分类类别
categories = ["cat", "dog", "car", "tree", "book"]
# 提示模板(可使用多个模板提升鲁棒性)
templates = [
"a photo of a {}",
"a picture of a {}",
"an image of a {}"
]
# 3. 生成所有类别对应的文本提示
text_prompts = []
for category in categories:
for template in templates:
text_prompts.append(template.format(category))
# 4. 加载并预处理待分类图像
# 批量处理示例:遍历文件夹中的图像
image_dir = "test_images/"
image_paths = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith((".jpg", ".png"))]
print(image_paths)
# 5. 批量推理
with torch.no_grad():
# 编码文本提示
text_tokens = clip.tokenize(text_prompts).to(device)
text_features = model.encode_text(text_tokens)
text_features /= text_features.norm(dim=-1, keepdim=True)
# 存储所有图像的结果
all_results = []
# 对每张图像进行分类
for img_path in image_paths:
# 预处理图像
image = preprocess(Image.open(img_path)).unsqueeze(0).to(device)
# 编码图像
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True)
# 计算图像与每个文本提示的相似度
similarity = image_features @ text_features.T
# 按类别聚合相似度(多个模板取平均)
category_scores = []
for i in range(len(categories)):
# 每个类别对应len(templates)个文本提示
start = i * len(templates)
end = start + len(templates)
avg_score = similarity[:, start:end].mean(dim=-1)
category_scores.append(avg_score.item())
# 预测类别(取分数最高的)
pred_idx = torch.argmax(torch.tensor(category_scores)).item()
pred_category = categories[pred_idx]
# 输出结果
print(f"图像:{img_path}")
print(f"分类结果:{pred_category}")
print(f"各类别得分:{dict(zip(categories, category_scores))}")
print("-" * 50)
# 保存结果
all_results.append({
"image_path": img_path,
"category_scores": category_scores,
"pred_category": pred_category
})
# 绘制分区块的条形图和原图
fig, axes = plt.subplots(2, 3, figsize=(20, 12))
for idx, result in enumerate(all_results[:3]): # 仅显示前三张图像的结果
# 显示原图
img_ax = axes[0, idx]
img = Image.open(result["image_path"])
img_ax.imshow(img)
img_ax.axis("off")
img_ax.set_title(f"原图:{result['image_path']}")
# 显示条形图
bar_ax = axes[1, idx]
# 为每个类别设置颜色,最高分标记为红色
colors = ["blue" if score != max(result["category_scores"]) else "red" for score in result["category_scores"]]
bar_ax.bar(categories, result["category_scores"], color=colors, alpha=0.6)
bar_ax.set_title(f"分类结果:{result['pred_category']}")
bar_ax.set_xlabel("类别")
bar_ax.set_ylabel("得分")
plt.tight_layout()
plt.show()图像的识别结果匹配度结果输出:
['test_images/cat.jpg', 'test_images/cat2.jpg', 'test_images/dog.jpg'] 图像:test_images/cat.jpg 分类结果:cat 各类别得分:{'cat': 0.285944402217865, 'dog': 0.2351067066192627, 'car': 0.19606192409992218, 'tree': 0.177148699760437, 'book': 0.1877281665802002} -------------------------------------------------- 图像:test_images/cat2.jpg 分类结果:cat 各类别得分:{'cat': 0.25495773553848267, 'dog': 0.21104760468006134, 'car': 0.1713184267282486, 'tree': 0.16746394336223602, 'book': 0.18521058559417725} -------------------------------------------------- 图像:test_images/dog.jpg 分类结果:dog 各类别得分:{'cat': 0.21453171968460083, 'dog': 0.2888471782207489, 'car': 0.18455737829208374, 'tree': 0.1804695874452591, 'book': 0.18529771268367767} --------------------------------------------------

代码解析与关键参数说明:
以下示例对批量处理的图片做一个简单的分类报告,由于样本数量极少,统计的指标比较简单,包括各类别平均置信度、图像宽高比例分布、各类别平均相似度得分等,根据时机需要可以调整统计指标。
import torch
import clip
from PIL import Image
import os
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.font_manager import FontProperties # 解决中文显示问题
# 解决matplotlib中文显示问题(可选,根据系统调整)
plt.rcParams["font.sans-serif"] = ["SimHei"] # 中文黑体
plt.rcParams["axes.unicode_minus"] = False # 正常显示负号
def get_image_aspect_ratio(image_path):
"""
计算图像宽高比,返回详细比例信息
:param image_path: 图像路径
:return: 包含分辨率、宽高比、比例类型的字典
"""
try:
with Image.open(image_path) as img:
width, height = img.size
# 计算最简整数比
gcd_val = np.gcd(width, height)
ratio_w = width // gcd_val
ratio_h = height // gcd_val
aspect_ratio = f"{ratio_w}:{ratio_h}"
# 定义常见比例类型
ratio_type = "其他"
if (ratio_w, ratio_h) == (1, 1):
ratio_type = "正方形 (1:1)"
elif (ratio_w, ratio_h) == (4, 3):
ratio_type = "标准屏 (4:3)"
elif (ratio_w, ratio_h) == (16, 9):
ratio_type = "宽屏 (16:9)"
elif (ratio_w, ratio_h) == (3, 2):
ratio_type = "照片 (3:2)"
return {
"path": img_path,
"width": width,
"height": height,
"aspect_ratio": aspect_ratio,
"ratio_type": ratio_type,
"ratio_value": width / height # 宽高比值
}
except Exception as e:
print(f"计算{image_path}比例失败:{e}")
return None
# 1. 初始化模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
print(f"使用设备:{device}")
# 2. 定义分类类别和提示模板
categories = ["cat", "dog", "car", "tree", "book"]
templates = [
"a photo of a {}",
"a picture of a {}",
"an image of a {}"
]
# 3. 生成所有类别对应的文本提示
text_prompts = []
for category in categories:
for template in templates:
text_prompts.append(template.format(category))
# 4. 加载并预处理待分类图像
image_dir = "test_images/"
if not os.path.exists(image_dir):
os.makedirs(image_dir)
print(f"创建空文件夹:{image_dir},请放入测试图像后重新运行")
exit()
image_paths = [os.path.join(image_dir, f) for f in os.listdir(image_dir)
if f.lower().endswith((".jpg", ".png", ".jpeg"))]
if not image_paths:
print(f"{image_dir} 中未找到jpg/png/jpeg格式图像")
exit()
print(f"找到{len(image_paths)}张图像:")
for path in image_paths:
print(f" - {path}")
# 5. 批量推理 + 数据收集
# 存储所有结果的列表
all_results = []
# 比例统计字典
ratio_stats = {
"正方形 (1:1)": 0,
"标准屏 (4:3)": 0,
"宽屏 (16:9)": 0,
"照片 (3:2)": 0,
"其他": 0
}
with torch.no_grad():
# 编码文本提示
text_tokens = clip.tokenize(text_prompts).to(device)
text_features = model.encode_text(text_tokens)
text_features /= text_features.norm(dim=-1, keepdim=True)
# 对每张图像进行分类
for img_path in image_paths:
# 计算图像比例
ratio_info = get_image_aspect_ratio(img_path)
if not ratio_info:
continue
# 更新比例统计
ratio_stats[ratio_info["ratio_type"]] += 1
# 预处理图像
image = preprocess(Image.open(img_path)).unsqueeze(0).to(device)
# 编码图像
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True)
# 计算相似度
similarity = image_features @ text_features.T
# 按类别聚合相似度(多个模板取平均)
category_scores = []
for i in range(len(categories)):
start = i * len(templates)
end = start + len(templates)
avg_score = similarity[:, start:end].mean(dim=-1)
category_scores.append(avg_score.item())
# 预测类别
pred_idx = torch.argmax(torch.tensor(category_scores)).item()
pred_category = categories[pred_idx]
# 收集结果
result = {
"image_name": os.path.basename(img_path),
"width": ratio_info["width"],
"height": ratio_info["height"],
"aspect_ratio": ratio_info["aspect_ratio"],
"ratio_type": ratio_info["ratio_type"],
"pred_category": pred_category,
"scores": dict(zip(categories, category_scores)),
"max_score": max(category_scores)
}
all_results.append(result)
# 输出结果
print(f"\n图像:{img_path}")
print(f"分辨率:{ratio_info['width']}×{ratio_info['height']} | 比例:{ratio_info['aspect_ratio']}")
print(f"分类结果:{pred_category} (置信度:{result['max_score']:.4f})")
print("各类别得分:")
for cat, score in result["scores"].items():
print(f" - {cat}: {score:.4f}")
print("-" * 80)
# 6. 生成可视化图表
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
fig.suptitle("CLIP零样本分类 + 图像比例分析报告", fontsize=16, fontweight="bold")
# 子图1:图像比例分布(饼图)
ratio_labels = list(ratio_stats.keys())
ratio_counts = [ratio_stats[label] for label in ratio_labels]
# 过滤掉数量为0的类别
ratio_labels_filtered = [l for l, c in zip(ratio_labels, ratio_counts) if c > 0]
ratio_counts_filtered = [c for c in ratio_counts if c > 0]
ax1.pie(
ratio_counts_filtered,
labels=ratio_labels_filtered,
autopct="%1.1f%%",
startangle=90,
colors=["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"]
)
ax1.set_title("图像比例分布", fontsize=14, pad=20)
# 子图2:分类结果分布(柱状图)
if all_results:
pred_categories = [r["pred_category"] for r in all_results]
cat_count = pd.Series(pred_categories).value_counts()
bars = ax2.bar(
cat_count.index,
cat_count.values,
color=["#3498DB", "#E74C3C", "#2ECC71", "#F39C12", "#9B59B6"]
)
ax2.set_title("分类结果分布", fontsize=14, pad=20)
ax2.set_xlabel("类别", fontsize=12)
ax2.set_ylabel("数量", fontsize=12)
# 为柱状图添加数值标签
for bar in bars:
height = bar.get_height()
ax2.text(
bar.get_x() + bar.get_width()/2.,
height + 0.05,
f"{int(height)}",
ha="center",
va="bottom",
fontsize=11
)
# 子图3:各类别平均置信度(柱状图)
if all_results:
cat_avg_scores = {}
for cat in categories:
scores = [r["scores"][cat] for r in all_results]
cat_avg_scores[cat] = np.mean(scores)
bars = ax3.bar(
list(cat_avg_scores.keys()),
list(cat_avg_scores.values()),
color=["#8E44AD", "#1ABC9C", "#F1C40F", "#E67E22", "#34495E"]
)
ax3.set_title("各类别平均置信度", fontsize=14, pad=20)
ax3.set_xlabel("类别", fontsize=12)
ax3.set_ylabel("平均相似度得分", fontsize=12)
# 添加数值标签
for bar in bars:
height = bar.get_height()
ax3.text(
bar.get_x() + bar.get_width()/2.,
height + 0.01,
f"{height:.3f}",
ha="center",
va="bottom",
fontsize=10
)
# 子图4:宽高比值分布(直方图)
if all_results:
ratio_values = [r["width"]/r["height"] for r in all_results]
ax4.hist(
ratio_values,
bins=8,
color="#74B9FF",
edgecolor="#2C3E50",
alpha=0.7
)
ax4.set_title("图像宽高比值分布", fontsize=14, pad=20)
ax4.set_xlabel("宽/高比值", fontsize=12)
ax4.set_ylabel("数量", fontsize=12)
# 添加均值线
mean_ratio = np.mean(ratio_values)
ax4.axvline(mean_ratio, color="red", linestyle="--", linewidth=2, label=f"均值:{mean_ratio:.2f}")
ax4.legend()
# 调整布局并保存图表
plt.tight_layout()
plt.savefig("clip_classification_ratio_analysis.png", dpi=150, bbox_inches="tight")
plt.show()
# 7. 导出结果到CSV(可选)
if all_results:
# 整理CSV数据格式
csv_data = []
for res in all_results:
row = {
"图像名称": res["image_name"],
"宽度": res["width"],
"高度": res["height"],
"宽高比": res["aspect_ratio"],
"比例类型": res["ratio_type"],
"预测类别": res["pred_category"],
"最高置信度": res["max_score"]
}
# 添加各类别得分
for cat in categories:
row[f"{cat}_得分"] = res["scores"][cat]
csv_data.append(row)
# 保存CSV
csv_path = "clip_classification_results.csv"
pd.DataFrame(csv_data).to_csv(csv_path, index=False, encoding="utf-8-sig")
print(f"\n结果已导出到:{csv_path}")
# 8. 输出统计总结
print("\n=== 统计总结 ===")
print(f"处理图像总数:{len(all_results)}")
print("图像比例统计:")
for ratio_type, count in ratio_stats.items():
if count > 0:
print(f" - {ratio_type}: {count}张 ({count/len(all_results)*100:.1f}%)")
print("分类结果统计:")
if all_results:
pred_categories = [r["pred_category"] for r in all_results]
for cat in categories:
count = pred_categories.count(cat)
if count > 0:
print(f" - {cat}: {count}张 ({count/len(all_results)*100:.1f}%)")图像的识别结果匹配度结果输出:
使用设备:cpu 找到3张图像: - test_images/cat.jpg - test_images/cat2.jpg - test_images/dog.jpg 图像:test_images/cat.jpg 分辨率:1200×800 | 比例:3:2 分类结果:cat (置信度:0.2859) 各类别得分: - cat: 0.2859 - dog: 0.2351 - car: 0.1961 - tree: 0.1771 - book: 0.1877 -------------------------------------------------------------------------------- 图像:test_images/cat2.jpg 分辨率:4080×1836 | 比例:20:9 分类结果:cat (置信度:0.2550) 各类别得分: - cat: 0.2550 - dog: 0.2110 - car: 0.1713 - tree: 0.1675 - book: 0.1852 -------------------------------------------------------------------------------- 图像:test_images/dog.jpg 分辨率:2048×1362 | 比例:1024:681 分类结果:dog (置信度:0.2888) 各类别得分: - cat: 0.2145 - dog: 0.2888 - car: 0.1846 - tree: 0.1805 - book: 0.1853 -------------------------------------------------------------------------------- 结果已导出到:clip_classification_results.csv === 统计总结 === 处理图像总数:3 图像比例统计: - 照片 (3:2): 1张 (33.3%) - 其他: 2张 (66.7%) 分类结果统计: - cat: 2张 (66.7%) - dog: 1张 (33.3%)

1. 零样本图像/视频分类
CLIP 最直接的应用是零样本分类,无需标注数据即可完成新类别的识别。例如:
2. 图文检索与生成
3. 多模态下游任务微调
CLIP 的预训练特征具有强通用性,可作为下游多模态任务的初始化权重:
CLIP提出了通用的跨模态预训练范式,通过大规模图文对比学习实现了视觉 - 文本的语义对齐;证明了零样本学习在计算机视觉任务中的可行性,大幅降低了视觉任务的标注成本;为多模态 AI 奠定了基础,推动了后续图文、视觉 - 语言交互模型的发展。
但由于预训练数据主要来自互联网,存在一些不可预知的错误,导致模型在特定场景下表现不佳,所以预训练做一些必要的处理是继续下一步的关键。虽然零样本能力强大,但在特定任务上仍不如微调后的专用模型。所以在使用过程中,做何种抉择也会是一种困扰,需要结合我们的经验和业务场景进行合理选择。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。