常见算法原理(线性回归、决策树、SVM、聚类等)

文章目录

机器学习算法是人工智能领域的核心工具,不同的算法适用于不同的问题场景。本文将深入讲解几种最常用的机器学习算法,包括线性回归、决策树、支持向量机和聚类算法,帮助读者理解它们的原理、应用场景以及实现方式。

线性回归:最简单却最实用的算法

线性回归是机器学习中最基础也是最重要的算法之一。虽然它看起来很简单,但在实际应用中却非常有效,很多复杂的算法都是在线性回归的基础上发展而来的。

线性回归的基本原理

线性回归的核心思想是找到一条直线(或者高维空间中的超平面),使得这条线能够最好地拟合数据点。用数学语言来说,就是找到一个函数关系,使得预测值和真实值之间的误差最小。

对于最简单的一元线性回归,我们要找的是这样一个函数:

y = wx + b

其中,x是输入特征,y是预测值,w是权重(斜率),b是偏置(截距)。我们的目标是找到最优的w和b,使得所有样本点到这条直线的距离之和最小。

这个距离通常用均方误差来衡量:

MSE = (1/n) * Σ(y_i - ŷ_i)²

其中,y_i是真实值,ŷ_i是预测值,n是样本数量。

梯度下降法求解

要找到最优的参数,最常用的方法就是梯度下降法。梯度下降的思想很直观:想象你站在山顶,想要下到山谷,最快的方法就是沿着最陡的方向往下走。在数学上,这个最陡的方向就是梯度的反方向。

具体的更新规则是:

w = w - α * ∂L/∂w

b = b - α * ∂L/∂b

其中,α是学习率,控制每次更新的步长。学习率太大可能导致震荡,太小则收敛速度慢。

下面用代码来实现一个简单的线性回归:

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

class LinearRegression:
    def __init__(self, learning_rate=0.01, iterations=1000):
        self.lr = learning_rate
        self.iterations = iterations
        self.w = None
        self.b = None
        self.losses = []
    
    def fit(self, X, y):
        # 初始化参数
        n_samples, n_features = X.shape
        self.w = np.zeros(n_features)
        self.b = 0
        
        # 梯度下降
        for i in range(self.iterations):
            # 前向传播:计算预测值
            y_pred = np.dot(X, self.w) + self.b
            
            # 计算损失
            loss = np.mean((y - y_pred) ** 2)
            self.losses.append(loss)
            
            # 计算梯度
            dw = -(2/n_samples) * np.dot(X.T, (y - y_pred))
            db = -(2/n_samples) * np.sum(y - y_pred)
            
            # 更新参数
            self.w -= self.lr * dw
            self.b -= self.lr * db
            
            if i % 100 == 0:
                print(f"Iteration {i}: Loss = {loss:.4f}")
    
    def predict(self, X):
        return np.dot(X, self.w) + self.b

# 生成示例数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

# 训练模型
model = LinearRegression(learning_rate=0.1, iterations=1000)
model.fit(X, y.ravel())

# 预测
X_test = np.array([[0], [2]])
predictions = model.predict(X_test)
print(f"预测结果: {predictions}")

# 可视化
plt.scatter(X, y, color='blue', label='真实数据')
plt.plot(X_test, predictions, color='red', linewidth=2, label='拟合直线')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.title('线性回归拟合结果')
plt.show()

多元线性回归

在实际应用中,我们通常需要处理多个特征的情况。多元线性回归的形式是:

y = w₁x₁ + w₂x₂ + ... + wₙxₙ + b

用向量形式表示就是:

y = w^T · x + b

求解方法和一元线性回归类似,只是梯度计算变成了向量形式。上面的代码实现实际上已经支持多元线性回归了。

线性回归的应用场景

线性回归适用于以下场景:

  • 房价预测:根据面积、地段、楼层等特征预测房价
  • 销售预测:根据广告投入、季节等因素预测销售额
  • 温度预测:根据历史数据预测未来温度
  • 股票趋势分析:分析股票价格的线性趋势

需要注意的是,线性回归假设特征和目标之间存在线性关系,如果关系是非线性的,需要进行特征工程或使用其他算法。

决策树:像人一样做决策

决策树是一种非常直观的算法,它的决策过程就像人类的思维方式一样,通过一系列的判断来得出结论。

决策树的基本原理

决策树通过树形结构来表示决策过程。每个内部节点表示一个特征的判断,每个分支表示判断的结果,每个叶子节点表示最终的决策结果。
晴天
阴天
雨天

正常
天气如何?
湿度如何?
去打球
不去打球
不去打球
去打球

构建决策树的关键问题是:如何选择最优的特征进行分裂?这就需要用到信息增益或基尼系数等指标。

信息熵与信息增益

信息熵是衡量数据不确定性的指标。熵越大,数据越混乱;熵越小,数据越纯净。

信息熵的计算公式:

H(D) = -Σ p_i * log₂(p_i)

其中,p_i是第i类样本在数据集中的比例。

信息增益表示使用某个特征进行分裂后,信息熵的减少量:

Gain(D, A) = H(D) - Σ (|D_v|/|D|) * H(D_v)

其中,D_v是特征A取值为v的样本子集。

我们选择信息增益最大的特征进行分裂,这样可以使得分裂后的子节点尽可能纯净。

基尼系数

除了信息增益,还可以使用基尼系数来选择分裂特征。基尼系数表示从数据集中随机抽取两个样本,其类别不一致的概率:

Gini(D) = 1 - Σ p_i²

基尼系数越小,数据集的纯度越高。

决策树的实现

下面用代码实现一个简单的决策树分类器:

python 复制代码
import numpy as np
from collections import Counter

class DecisionTreeNode:
    def __init__(self, feature=None, threshold=None, left=None, right=None, value=None):
        self.feature = feature      # 分裂特征的索引
        self.threshold = threshold  # 分裂阈值
        self.left = left           # 左子树
        self.right = right         # 右子树
        self.value = value         # 叶子节点的类别

class DecisionTree:
    def __init__(self, max_depth=10, min_samples_split=2):
        self.max_depth = max_depth
        self.min_samples_split = min_samples_split
        self.root = None
    
    def _entropy(self, y):
        """计算信息熵"""
        counter = Counter(y)
        probs = np.array(list(counter.values())) / len(y)
        return -np.sum(probs * np.log2(probs + 1e-10))
    
    def _information_gain(self, X, y, feature, threshold):
        """计算信息增益"""
        # 父节点熵
        parent_entropy = self._entropy(y)
        
        # 分裂
        left_mask = X[:, feature] <= threshold
        right_mask = ~left_mask
        
        if np.sum(left_mask) == 0 or np.sum(right_mask) == 0:
            return 0
        
        # 子节点熵
        n = len(y)
        n_left, n_right = np.sum(left_mask), np.sum(right_mask)
        e_left = self._entropy(y[left_mask])
        e_right = self._entropy(y[right_mask])
        child_entropy = (n_left / n) * e_left + (n_right / n) * e_right
        
        return parent_entropy - child_entropy
    
    def _best_split(self, X, y):
        """找到最优分裂点"""
        best_gain = -1
        best_feature = None
        best_threshold = None
        
        n_features = X.shape[1]
        for feature in range(n_features):
            thresholds = np.unique(X[:, feature])
            for threshold in thresholds:
                gain = self._information_gain(X, y, feature, threshold)
                if gain > best_gain:
                    best_gain = gain
                    best_feature = feature
                    best_threshold = threshold
        
        return best_feature, best_threshold
    
    def _build_tree(self, X, y, depth=0):
        """递归构建决策树"""
        n_samples, n_features = X.shape
        n_classes = len(np.unique(y))
        
        # 停止条件
        if depth >= self.max_depth or n_samples < self.min_samples_split or n_classes == 1:
            leaf_value = Counter(y).most_common(1)[0][0]
            return DecisionTreeNode(value=leaf_value)
        
        # 找到最优分裂点
        best_feature, best_threshold = self._best_split(X, y)
        
        if best_feature is None:
            leaf_value = Counter(y).most_common(1)[0][0]
            return DecisionTreeNode(value=leaf_value)
        
        # 分裂数据
        left_mask = X[:, best_feature] <= best_threshold
        right_mask = ~left_mask
        
        # 递归构建左右子树
        left_subtree = self._build_tree(X[left_mask], y[left_mask], depth + 1)
        right_subtree = self._build_tree(X[right_mask], y[right_mask], depth + 1)
        
        return DecisionTreeNode(best_feature, best_threshold, left_subtree, right_subtree)
    
    def fit(self, X, y):
        """训练决策树"""
        self.root = self._build_tree(X, y)
    
    def _predict_sample(self, x, node):
        """预测单个样本"""
        if node.value is not None:
            return node.value
        
        if x[node.feature] <= node.threshold:
            return self._predict_sample(x, node.left)
        else:
            return self._predict_sample(x, node.right)
    
    def predict(self, X):
        """预测多个样本"""
        return np.array([self._predict_sample(x, self.root) for x in X])

# 使用示例
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 加载数据
iris = load_iris()
X, y = iris.data, iris.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 训练模型
tree = DecisionTree(max_depth=5)
tree.fit(X_train, y_train)

# 预测
y_pred = tree.predict(X_test)
accuracy = np.mean(y_pred == y_test)
print(f"准确率: {accuracy:.4f}")

决策树的优缺点

优点:

  • 易于理解和解释,可以可视化
  • 不需要数据标准化
  • 可以处理数值型和类别型数据
  • 可以处理多输出问题

缺点:

  • 容易过拟合,需要剪枝
  • 对数据的微小变化敏感
  • 可能创建偏向某些类别的树
  • 训练时间较长

决策树的改进:随机森林

为了克服决策树容易过拟合的问题,可以使用集成学习方法,其中最著名的就是随机森林。随机森林通过构建多棵决策树,然后对它们的预测结果进行投票或平均,从而提高模型的泛化能力。
训练数据
决策树1
决策树2
决策树3
...
决策树N
投票/平均
最终预测

支持向量机:寻找最优分界线

支持向量机是一种非常强大的分类算法,它的核心思想是找到一个最优的超平面,使得不同类别的样本被正确分开,并且分类间隔最大。

SVM的基本原理

对于线性可分的数据,SVM要找的是这样一个超平面:

w^T · x + b = 0

使得所有样本点到这个超平面的距离之和最大。这个距离称为间隔(margin)。
SVM核心思想
找到最优超平面
最大化分类间隔
支持向量
距离超平面最近的点
决定超平面位置

数学上,这个问题可以表示为:

最小化:(1/2) ||w||²

约束条件:y_i(w^T · x_i + b) ≥ 1

其中,y_i是样本的类别标签(+1或-1),x_i是样本特征。

软间隔与惩罚参数

在实际应用中,数据往往不是完全线性可分的,可能存在一些噪声点。为了处理这种情况,引入了软间隔的概念,允许一些样本点违反间隔约束。

引入松弛变量ξ_i,优化目标变为:

最小化:(1/2) ||w||² + C * Σξ_i

约束条件:y_i(w^T · x_i + b) ≥ 1 - ξ_i,ξ_i ≥ 0

其中,C是惩罚参数,控制对误分类的惩罚程度。C越大,对误分类的惩罚越大,模型越复杂;C越小,模型越简单,但可能欠拟合。

核函数:处理非线性问题

当数据不是线性可分时,可以通过核函数将数据映射到高维空间,使其在高维空间中线性可分。

常用的核函数有:

  • 线性核:K(x, y) = x^T · y
  • 多项式核:K(x, y) = (x^T · y + c)^d
  • 高斯核(RBF):K(x, y) = exp(-γ||x - y||²)
  • Sigmoid核:K(x, y) = tanh(αx^T · y + c)

其中,RBF核是最常用的核函数,它可以将数据映射到无限维空间。

SVM的实现

下面用代码演示如何使用SVM:

python 复制代码
import numpy as np
from sklearn import svm
from sklearn.datasets import make_classification, make_circles
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 生成线性可分数据
X_linear, y_linear = make_classification(n_samples=100, n_features=2, n_redundant=0, 
                                         n_informative=2, n_clusters_per_class=1, 
                                         random_state=42)

# 生成非线性数据
X_nonlinear, y_nonlinear = make_circles(n_samples=100, noise=0.1, factor=0.5, random_state=42)

def plot_svm_decision_boundary(X, y, model, title):
    """绘制SVM决策边界"""
    plt.figure(figsize=(10, 6))
    
    # 创建网格
    h = 0.02
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    
    # 预测网格点
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    
    # 绘制决策边界
    plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdYlBu)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, edgecolors='black')
    
    # 绘制支持向量
    plt.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1],
                s=200, linewidth=1, facecolors='none', edgecolors='k', label='支持向量')
    
    plt.xlabel('特征1')
    plt.ylabel('特征2')
    plt.title(title)
    plt.legend()
    plt.show()

# 线性SVM
print("训练线性SVM...")
svm_linear = svm.SVC(kernel='linear', C=1.0)
svm_linear.fit(X_linear, y_linear)
print(f"线性SVM准确率: {svm_linear.score(X_linear, y_linear):.4f}")
plot_svm_decision_boundary(X_linear, y_linear, svm_linear, "线性SVM")

# RBF核SVM
print("\n训练RBF核SVM...")
svm_rbf = svm.SVC(kernel='rbf', C=1.0, gamma='auto')
svm_rbf.fit(X_nonlinear, y_nonlinear)
print(f"RBF核SVM准确率: {svm_rbf.score(X_nonlinear, y_nonlinear):.4f}")
plot_svm_decision_boundary(X_nonlinear, y_nonlinear, svm_rbf, "RBF核SVM")

# 比较不同C值的影响
print("\n比较不同C值的影响...")
for C in [0.1, 1, 10, 100]:
    model = svm.SVC(kernel='linear', C=C)
    model.fit(X_linear, y_linear)
    print(f"C={C}: 准确率={model.score(X_linear, y_linear):.4f}, "
          f"支持向量数量={len(model.support_vectors_)}")

SVM的应用场景

SVM适用于以下场景:

  • 文本分类:垃圾邮件检测、情感分析
  • 图像识别:人脸识别、手写数字识别
  • 生物信息学:蛋白质分类、基因分类
  • 金融预测:信用评分、股票预测

SVM的优点是在高维空间中表现良好,对于小样本数据也能取得不错的效果。但缺点是训练时间较长,对大规模数据不太适用。

聚类算法:发现数据的内在结构

聚类是无监督学习的典型代表,它的目标是将相似的样本归为一类,不同的样本分到不同的类。聚类不需要标签数据,完全依靠数据本身的特征进行分组。

K-Means聚类

K-Means是最常用的聚类算法,它的思想很简单:将数据分成K个簇,使得每个簇内的样本尽可能相似,不同簇之间的样本尽可能不同。


开始
随机初始化K个中心点
分配样本到最近的中心点
更新中心点位置
中心点是否变化?
结束

K-Means算法的步骤:

  1. 随机选择K个样本作为初始聚类中心
  2. 计算每个样本到各个聚类中心的距离,将样本分配给最近的聚类中心
  3. 重新计算每个簇的中心点(簇内所有样本的均值)
  4. 重复步骤2和3,直到聚类中心不再变化或达到最大迭代次数

K-Means的实现

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

class KMeans:
    def __init__(self, n_clusters=3, max_iters=100):
        self.n_clusters = n_clusters
        self.max_iters = max_iters
        self.centroids = None
        self.labels = None
    
    def fit(self, X):
        # 随机初始化聚类中心
        n_samples = X.shape[0]
        random_indices = np.random.choice(n_samples, self.n_clusters, replace=False)
        self.centroids = X[random_indices]
        
        for i in range(self.max_iters):
            # 分配样本到最近的聚类中心
            distances = np.sqrt(((X - self.centroids[:, np.newaxis])**2).sum(axis=2))
            self.labels = np.argmin(distances, axis=0)
            
            # 更新聚类中心
            new_centroids = np.array([X[self.labels == k].mean(axis=0) 
                                     for k in range(self.n_clusters)])
            
            # 检查是否收敛
            if np.allclose(self.centroids, new_centroids):
                print(f"在第{i+1}次迭代后收敛")
                break
            
            self.centroids = new_centroids
        
        return self
    
    def predict(self, X):
        distances = np.sqrt(((X - self.centroids[:, np.newaxis])**2).sum(axis=2))
        return np.argmin(distances, axis=0)

# 生成示例数据
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)

# 训练K-Means
kmeans = KMeans(n_clusters=4, max_iters=100)
kmeans.fit(X)

# 可视化结果
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y_true, cmap='viridis', alpha=0.6)
plt.title('真实分布')
plt.xlabel('特征1')
plt.ylabel('特征2')

plt.subplot(1, 2, 2)
plt.scatter(X[:, 0], X[:, 1], c=kmeans.labels, cmap='viridis', alpha=0.6)
plt.scatter(kmeans.centroids[:, 0], kmeans.centroids[:, 1], 
           c='red', marker='X', s=200, edgecolors='black', label='聚类中心')
plt.title('K-Means聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend()

plt.tight_layout()
plt.show()

如何选择K值

选择合适的K值是K-Means算法的关键问题。常用的方法有:

  1. 肘部法则:绘制不同K值对应的簇内误差平方和(SSE),选择曲线出现拐点的K值
python 复制代码
def elbow_method(X, max_k=10):
    """肘部法则选择K值"""
    sse = []
    for k in range(1, max_k + 1):
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        # 计算簇内误差平方和
        sse_k = sum([np.sum((X[kmeans.labels == i] - kmeans.centroids[i])**2) 
                     for i in range(k)])
        sse.append(sse_k)
    
    plt.figure(figsize=(8, 5))
    plt.plot(range(1, max_k + 1), sse, marker='o')
    plt.xlabel('聚类数量K')
    plt.ylabel('簇内误差平方和SSE')
    plt.title('肘部法则选择K值')
    plt.grid(True)
    plt.show()

elbow_method(X, max_k=10)
  1. 轮廓系数:衡量样本与其所在簇的相似度,取值范围[-1, 1],值越大表示聚类效果越好

层次聚类

除了K-Means,层次聚类也是一种常用的聚类方法。层次聚类不需要预先指定簇的数量,它通过构建一个树状结构来表示样本之间的层次关系。

层次聚类分为两种:

  • 自底向上(凝聚):开始时每个样本是一个簇,然后逐步合并最相似的簇
  • 自顶向下(分裂):开始时所有样本在一个簇中,然后逐步分裂
python 复制代码
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt

# 生成数据
X, _ = make_blobs(n_samples=50, centers=3, random_state=42)

# 层次聚类
linkage_matrix = linkage(X, method='ward')

# 绘制树状图
plt.figure(figsize=(12, 6))
dendrogram(linkage_matrix)
plt.title('层次聚类树状图')
plt.xlabel('样本索引')
plt.ylabel('距离')
plt.show()

DBSCAN:基于密度的聚类

DBSCAN是一种基于密度的聚类算法,它可以发现任意形状的簇,并且能够识别噪声点。

DBSCAN的核心概念:

  • 核心点:在半径ε内至少有MinPts个邻居的点
  • 边界点:不是核心点,但在某个核心点的ε邻域内
  • 噪声点:既不是核心点也不是边界点
python 复制代码
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons

# 生成月牙形数据
X, _ = make_moons(n_samples=200, noise=0.05, random_state=42)

# DBSCAN聚类
dbscan = DBSCAN(eps=0.3, min_samples=5)
labels = dbscan.fit_predict(X)

# 可视化
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', alpha=0.6)
plt.title('DBSCAN聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.colorbar(label='簇标签')
plt.show()

print(f"发现{len(set(labels)) - (1 if -1 in labels else 0)}个簇")
print(f"噪声点数量: {list(labels).count(-1)}")

聚类算法的应用场景

聚类算法在实际中有广泛的应用:

  • 客户细分:根据购买行为将客户分组
  • 图像分割:将图像分成不同的区域
  • 异常检测:识别与正常数据不同的异常点
  • 文档聚类:将相似的文档归为一类
  • 基因分析:根据基因表达模式对基因分组

算法选择指南

面对不同的问题,如何选择合适的算法呢?下面给出一些建议:






机器学习问题
有标签数据?
预测连续值?
聚类算法
回归算法
分类算法
线性回归

岭回归

Lasso回归
数据线性可分?
逻辑回归

线性SVM
决策树

随机森林

核SVM

神经网络
K-Means

层次聚类

DBSCAN

选择算法时需要考虑的因素:

  • 数据规模:大数据集适合线性模型、小数据集可以用SVM
  • 特征维度:高维数据适合线性模型或降维后使用
  • 数据分布:线性可分用线性模型,非线性用核方法或树模型
  • 可解释性:需要解释性用线性模型或决策树
  • 训练时间:时间紧张用简单模型,时间充足可以用复杂模型

总结

本文详细介绍了机器学习中最常用的几种算法:线性回归、决策树、支持向量机和聚类算法。每种算法都有其适用的场景和特点:

线性回归简单高效,适合处理线性关系的问题,是入门机器学习的最佳选择。通过梯度下降法,我们可以找到最优的参数,使得预测误差最小。

决策树直观易懂,可以处理非线性问题,通过信息增益或基尼系数选择最优分裂特征。虽然单棵决策树容易过拟合,但通过随机森林等集成方法可以大大提高性能。

支持向量机通过最大化分类间隔来找到最优分界线,对于高维数据表现优异。通过核函数,SVM可以处理非线性问题,是一种非常强大的分类算法。

聚类算法不需要标签数据,可以自动发现数据的内在结构。K-Means简单高效,层次聚类可以展示数据的层次关系,DBSCAN可以发现任意形状的簇并识别噪声点。

在实际应用中,没有一种算法是万能的,需要根据具体问题选择合适的算法。通常的做法是尝试多种算法,通过交叉验证等方法比较它们的性能,最终选择效果最好的模型。同时,特征工程、参数调优等技巧也对模型性能有重要影响。

掌握这些基础算法的原理和实现,是深入学习机器学习的重要基础。在此基础上,可以进一步学习深度学习、强化学习等更高级的技术。

相关推荐
数字游民952712 小时前
2小时VibeCoding了一个看图猜词小程序:猜对了么
人工智能·ai·小程序·ai绘画·数字游民9527
糠帅傅蓝烧牛肉面15 小时前
单实例多MCP聚合服务:两种实现方案深度对比
前端·docker·ai
未若君雅裁16 小时前
SpringAI基础入门
java·spring boot·ai
程序员泠零澪回家种桔子19 小时前
RAG中的Embedding技术
人工智能·后端·ai·embedding
leikooo19 小时前
Spring AI 工具调用回调与流式前端展示的完整落地方案
java·spring·ai·ai编程
imbackneverdie20 小时前
如何通过读文献寻找科研思路?
人工智能·ai·自然语言处理·aigc·ai写作·ai读文献
海绵宝宝de派小星20 小时前
如何开始学习AI?学习路径建议
ai
一叶飘零_sweeeet20 小时前
大模型和机器学习
ai
图生生21 小时前
AI溶图技术+光影适配:实现产品场景图的高质量合成
人工智能·ai