过拟合与欠拟合的诊断宝典:实践中的深度解析
发布时间: 2024-11-23 23:14:55 阅读量: 28 订阅数: 30
图像识别中的过拟合与欠拟合:识别精度的双刃剑
![过拟合与欠拟合的诊断宝典:实践中的深度解析](https://media.geeksforgeeks.org/wp-content/cdn-uploads/20190523171258/overfitting_2.png)
# 1. 过拟合与欠拟合现象概述
在机器学习模型的训练过程中,过拟合与欠拟合是两个常见的问题,它们影响着模型的性能和泛化能力。**过拟合**是指模型在训练数据上表现良好,但在未见过的数据上表现不佳,这种情况通常是因为模型太过复杂,捕捉到了训练数据中的噪声和细节,而非数据的真实分布。相反,**欠拟合**则出现在模型过于简单,无法捕捉到数据中的基本结构,导致在训练和测试数据上都表现不好。
理解这两者的区别是至关重要的,因为它们直接关系到模型的预测精度和实际应用效果。本章将概述过拟合与欠拟合的基本概念,并简要介绍它们如何影响机器学习流程,为后续章节中深入探讨如何诊断和解决这些问题打下基础。
# 2. 诊断过拟合与欠拟合的理论基础
## 2.1 模型能力与泛化误差
### 2.1.1 模型复杂度对泛化能力的影响
在机器学习中,模型的复杂度直接影响其拟合训练数据的能力。一个模型的复杂度高,意味着它有更多参数或更复杂的函数形式,这使得模型可以更好地捕捉数据中的细微模式。然而,过于复杂的模型也有可能过度拟合训练数据,导致泛化能力下降。
在实际应用中,模型复杂度的选择需要在拟合能力与泛化能力之间找到平衡。理解模型复杂度对泛化误差的影响,有助于我们在训练过程中选择合适的模型结构和参数。例如,在使用决策树模型时,树的深度是一个影响复杂度的重要参数。树太深可能导致过拟合,太浅则可能导致欠拟合。
### 2.1.2 泛化误差与偏差-方差权衡
泛化误差是由偏差(Bias)和方差(Variance)两部分组成的。偏差反映了模型预测的平均值与真实值之间的差异,而方差则是衡量模型输出在不同训练集样本上的变动情况。一个好的模型需要在偏差和方差之间取得平衡,这通常被称为偏差-方差权衡。
- **偏差**通常与模型的欠拟合有关,高偏差表明模型未能捕捉数据中的潜在规律。
- **方差**则与模型的过拟合相关,高方差意味着模型对训练数据中的随机误差过度敏感。
在实践中,我们通常使用一系列技术来降低泛化误差,比如增加数据量、减少模型复杂度、或者使用正则化方法。
## 2.2 常用的评价指标
### 2.2.1 训练误差与验证误差
训练误差是指模型在训练集上的平均损失。理论上,我们希望训练误差尽可能低,因为这表明模型在学习训练数据时效果好。然而,训练误差过低可能是过拟合的信号,特别是当验证误差与训练误差之间存在较大差异时。
验证误差是指模型在独立的验证集上的平均损失。通过比较训练误差与验证误差,我们可以评估模型的泛化能力。如果验证误差显著高于训练误差,则模型可能过拟合;如果两者都高,则可能是欠拟合。
### 2.2.2 过拟合与欠拟合的指标判定
过拟合与欠拟合的指标判定通常涉及多种评估方法,除了比较训练误差和验证误差外,还可以使用以下几种方法:
- **学习曲线**:绘制训练误差和验证误差随训练数据量增加的变化曲线,分析过拟合或欠拟合现象。
- **正则化指标**:如权重的L1或L2范数,可以帮助我们评估模型复杂度的高低。
- **信息论指标**:如交叉熵,可以用于评估模型预测的不确定性。
### 2.2.3 预测误差与性能指标
预测误差是指模型在未见过的数据上的误差,它是评估泛化能力的最终指标。性能指标则是在特定任务中评价模型的实用指标,常见的性能指标包括:
- **准确率(Accuracy)**:正确预测样本的比例,常用于分类任务。
- **均方误差(MSE)**:预测值与真实值差的平方的平均值,常用于回归任务。
- **F1分数**:精确率和召回率的调和平均,综合考虑了模型的精确度和召回率。
通过以上指标,我们可以全面地评估模型的性能,从而判断是否存在过拟合或欠拟合。
## 2.3 数据集的角色和影响
### 2.3.1 训练集、验证集和测试集的作用
在机器学习中,数据集通常被分为训练集、验证集和测试集。
- **训练集**用于训练模型,帮助模型学习数据的内在规律。
- **验证集**用于模型选择和调整,评估模型在未见过的数据上的性能,以此来进行超参数调整。
- **测试集**在模型构建完成后用于最终评估模型的泛化能力。
通过合理划分数据集,我们可以在一定程度上减少过拟合的风险,并确保模型的泛化能力。
### 2.3.2 数据集大小与质量对泛化的影响
数据集的大小和质量对模型的泛化能力有着直接的影响:
- **数据集大小**:较大的数据集通常能够提供更多的信息供模型学习,从而减少过拟合的可能性。但数据集并非越大越好,当数据集超过一定规模后,对性能的提升有限,同时会增加计算成本。
- **数据集质量**:高质量的数据集应该具有代表性,能够覆盖各种情况。数据预处理如去噪、归一化等,能有效提升数据集质量,减少过拟合的风险。
在实践中,我们需要平衡数据集的大小和质量,以达到最佳的泛化效果。
# 3. 过拟合与欠拟合的诊断方法
## 3.1 直观方法:可视化诊断
直观的诊断方法为理解和判断模型是否过拟合或欠拟合提供了直接的视觉工具。其中最常用的是损失曲线的绘制与分析以及模型预测的分布可视化。
### 3.1.1 损失曲线的绘制与分析
损失曲线是训练过程中损失函数值随迭代次数变化的图形。通过绘制训练集和验证集上的损失曲线,可以直观地观察模型的泛化性能。
```python
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
# 假设 train_losses 和 val_losses 分别是训练和验证的损失
train_losses = [0.2, 0.18, 0.16, 0.15, 0.14, 0.13, 0.12, 0.11, 0.10, 0.10]
val_losses = [0.35, 0.25, 0.20, 0.22, 0.24, 0.25, 0.26, 0.27, 0.28, 0.30]
plt.plot(train_losses, label='Training loss')
plt.plot(val_losses, label='Validation loss')
plt.title('Training and Validation Losses')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
```
分析损失曲线时,理想情况下,随着训练的进行,训练损失和验证损失都应该呈现下降趋势。如果训练损失继续下降,而验证损失开始上升或趋于平坦,表明模型开始在训练集上过拟合。如果训练和验证损失都停留在较高的水平,可能表明模型欠拟合。
### 3.1.2 模型预测的分布可视化
模型预测的分布可视化可以通过绘制预测值和实际值的分布图来实现,这可以帮助我们观察模型的预测是否集中在正确的区域。
```python
import numpy as np
import seaborn as sns
# 假设 predictions 和 actuals 是模型的预测值和实际值
predictions = np.random.normal(0, 1, 1000)
actuals = np.random.normal(0, 1, 1000)
sns.kdeplot(predictions, label='Predictions')
sns.kdeplot(actuals, label='Actuals', color='red')
plt.title('Distribution of Predictions and Actuals')
plt.xlabel('Value')
plt.ylabel('Density')
plt.legend()
plt.show()
```
若预测值的分布与实际值的分布大致重合,说明模型的预测能力较好。若二者存在显著差异,则可能表明模型存在欠拟合或过拟合问题。
## 3.2 数值方法:统计测试
为了定量地评估模型的泛化能力,统计测试提供了一种数值诊断的方法。
### 3.2.1 假设检验与显著性分析
假设检验是一种统计方法,用来判断两个变量之间是否具有统计上的显著差异。在模型性能评估中,可以使用假设检验来判断模型在训练集和验证集上的表现是否存在显著差异。
```python
from scipy import stats
# 假设 train_scores 和 val_scores 是模型在训练集和验证集上的评分
train_scores = np.random.normal(0.8, 0.02, 100)
val_scores = np.random.normal(0.78, 0.02, 100)
t_stat, p_val = stats.ttest_ind(train_scores, val_scores)
print(f"t-statistic: {t_stat}, p-value: {p_val}")
```
如果 p 值很小,表明两个评分存在显著差异。对于一个表现良好的模型,通常希望 p 值较高,表明训练和验证评分没有显著差异,即模型泛化能力较好。
### 3.2.2 K折交叉验证与模型比较
K折交叉验证是另一种常用的统计测试方法,它通过将数据集分成 K 个子集,并轮流使用其中的一个子集作为验证集,其余作为训练集来评估模型性能。
```python
from sklearn.model_selection import cross_val_score
# 假设 model 是一个已训练好的模型,X 是特征,y 是标签
scores = cross_val_score(model, X, y, cv=5)
print(f"Cross-validation scores: {scores}")
print(f"Mean score: {scores.mean()}")
```
通过比较不同模型在 K 折交叉验证中的均值和方差,可以判断模型的泛化能力以及在不同数据子集上的稳定性。
## 3.3 模型复杂度调整
调整模型复杂度是解决过拟合和欠拟合问题的一种重要手段。
### 3.3.1 参数调整与正则化技术
调整模型的参数可以改变其复杂度,例如减少神经网络中的层数或神经元数量。同时,正则化技术通过在损失函数中加入惩罚项,防止模型过于依赖训练数据的特定特征。
```python
from sklearn.linear_model import Ridge
# 假设 X_train, y_train 是训练数据集
model = Ridge(alpha=0.5) # alpha 是正则化强度参数
model.fit(X_train, y_train)
# 模型训练后的系数
print(f"Coefficients: {model.coef_}")
```
通过调整正则化强度(例如,alpha 参数),可以控制模型复杂度以防止过拟合。
### 3.3.2 神经网络结构优化
对于深度学习模型,优化神经网络结构是调整复杂度的一种有效手段。例如,减少层的数量、神经元数目或者改变激活函数类型,都可能对防止过拟合有所帮助。
```python
from keras.models import Sequential
from keras.layers import Dense, Dropout
# 假设 X_train, y_train 是训练数据集
model = Sequential([
Dense(64, activation='relu', input_shape=(input_dim,)),
Dropout(0.5), # Dropout层帮助减少过拟合
Dense(32, activation='relu'),
Dense(1)
])
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(X_train, y_train, epochs=20)
```
在本例中,Dropout层被加入到模型中,该层在训练过程中随机丢弃部分神经元,有助于减少过拟合现象。
通过第三章的介绍,我们了解了过拟合和欠拟合的诊断方法,包括直观的可视化诊断、数值方法的统计测试以及模型复杂度的调整技术。接下来,我们将探讨更为深入的过拟合与欠拟合应对策略。
# 4. 过拟合与欠拟合的应对策略
过拟合与欠拟合是机器学习模型训练过程中常见的两个问题。它们严重影响模型的泛化能力,即模型在未知数据上的性能。在这一章中,我们将深入探讨如何通过一系列策略来应对过拟合和欠拟合,使模型能够更好地适应新的数据集。
## 4.1 正则化技术的应用
### 4.1.1 L1和L2正则化原理与实现
L1和L2正则化是防止过拟合的常用方法,它们通过在损失函数中添加一个与模型复杂度相关的项来限制模型的复杂度,从而增强模型的泛化能力。在数学上,L1正则化对应于权重向量的L1范数,而L2正则化对应于权重向量的L2范数。
**代码实现:**
```python
import numpy as np
from sklearn.linear_model import Ridge, Lasso
# 假设 X, y 是训练数据和标签
# 使用 L2 正则化
model_l2 = Ridge(alpha=1.0) # alpha 是正则化强度
model_l2.fit(X, y)
# 使用 L1 正则化
model_l1 = Lasso(alpha=0.1)
model_l1.fit(X, y)
# 模型评估等后续步骤...
```
**参数解释:**
- `alpha`:控制正则化的强度,alpha值越大,正则化效果越强。
正则化通过在损失函数中添加惩罚项,使得模型在训练过程中偏向于学习较小的权重值。L1正则化能够使某些权重归零,从而产生稀疏模型,有助于特征选择;而L2正则化则倾向于让所有权重都较小但非零。
### 4.1.2 Dropout和Batch Normalization
Dropout是一种在神经网络训练过程中临时丢弃一部分神经元的技术,其目的是为了减少神经元之间复杂的共适应关系。Dropout可以被视为一种模型集成的方法,通过在每次训练时随机关闭一部分神经元,迫使网络学习到更加鲁棒的特征表示。
**代码实现:**
```python
from keras.models import Sequential
from keras.layers import Dense, Dropout
model = Sequential()
model.add(Dense(64, input_dim=64, activation='relu'))
model.add(Dropout(0.5)) # Dropout率为0.5
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X_train, y_train, epochs=10, batch_size=32)
```
**参数解释:**
- `Dropout(0.5)`:表示在每个训练批次中,有50%的节点会被随机丢弃。
Batch Normalization是一种用于深度神经网络的优化技术,通过规范化层输入的均值和方差,加快训练速度,同时对过拟合也有一定的抑制作用。Batch Normalization可以理解为一种内部协变量偏移的解决方案,即在训练过程中自动调整网络各层的输入分布,以保持其稳定性。
## 4.2 数据增强与扩增技术
### 4.2.1 图像、文本等数据增强方法
数据增强是一种通过人工方式生成新数据的技术,它可以在不直接收集新数据的情况下扩充现有的数据集。对于图像数据,常用的数据增强手段包括旋转、缩放、翻转、裁剪等。对于文本数据,则可以采用同义词替换、句子重排、随机插入等方法。
**代码示例:**
```python
from keras.preprocessing.image import ImageDataGenerator
# 图像数据增强
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
datagen.fit(X_train) # 对训练集应用数据增强
```
### 4.2.2 合成数据和迁移学习
合成数据是通过某种算法人工生成的数据,它可以用来补充真实数据集的不足。迁移学习则是将从一个领域学到的知识应用到另一个相关领域。在深度学习中,迁移学习通常涉及使用在大规模数据集(如ImageNet)上预训练的模型,并对其在新任务上进行微调。
**代码示例:**
```python
from keras.applications import VGG16
from keras.layers import Dense
from keras.models import Model
# 加载预训练的VGG16模型
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# 冻结预训练模型的层
for layer in base_model.layers:
layer.trainable = False
# 添加自定义层
x = base_model.output
x = Dense(256, activation='relu')(x)
predictions = Dense(num_classes, activation='softmax')(x)
# 构建最终模型
model = Model(inputs=base_model.input, outputs=predictions)
# 编译和训练模型
model.compile(optimizer='adam', loss='categorical_crossentropy')
model.fit(train_data, train_labels, epochs=10)
```
## 4.3 早期停止与集成学习
### 4.3.1 早停法原理及实践
早停法是一种防止过拟合的技巧,它监控验证集的性能,并在性能不再提升或开始下降时停止训练。通过这种方法,我们可以捕捉到模型在验证集上表现最好的时刻,并防止模型继续学习训练集中的噪声。
**代码示例:**
```python
from keras.callbacks import EarlyStopping
# 设置早停的回调函数
early_stopping = EarlyStopping(monitor='val_loss', patience=5, verbose=1)
# 使用回调函数训练模型
model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=50, callbacks=[early_stopping])
```
**参数解释:**
- `monitor='val_loss'`:监控验证集的损失。
- `patience=5`:如果验证集上的损失在5个epoch内没有改善,则停止训练。
### 4.3.2 Bagging、Boosting与Stacking方法
Bagging、Boosting和Stacking是集成学习的三种主要方法,它们通过组合多个模型来提高整体的性能。
- Bagging(Bootstrap Aggregating)是一种并行集成方法,它通过训练多个独立的模型,并结合它们的预测结果来减少方差。典型的Bagging算法包括随机森林。
- Boosting是一种顺序集成方法,它通过按顺序训练模型,每个新模型都专注于前一个模型预测错误的样本,典型的Boosting算法包括AdaBoost、Gradient Boosting。
- Stacking是一种将不同的模型组合在一起的集成方法。它训练一个元模型来结合不同模型的预测。
以上方法都是防止过拟合的有效技术,每种方法在不同场景下的性能可能会有所不同,需要根据具体问题来选择使用。
在本章节中,我们介绍了应对过拟合与欠拟合的策略,这些技术的正确应用能够显著提高机器学习模型的泛化能力,使其在面对新的、未知数据时更加健壮和准确。通过理解这些概念,并结合实际代码示例和参数说明,从业者可以更加自信地在项目中应用这些策略,以达到更好的训练效果。
# 5. 深度学习中过拟合与欠拟合的案例分析
## 5.1 图像识别案例研究
### 5.1.1 卷积神经网络的过拟合与优化
在深度学习的图像识别领域,卷积神经网络(CNN)是一种十分强大的工具。然而,即使是强大的CNN也可能遭受过拟合问题,尤其是在面对有限的训练数据时。过拟合会导致模型对训练集的噪声过度敏感,从而丧失对新数据的泛化能力。在这种情况下,我们通常会采取一些优化策略来缓解过拟合现象。
**数据增强**是一种有效的手段,通过旋转、缩放、剪切、翻转和颜色变化等方法生成新的训练样本,可以显著增加训练数据的多样性,从而提升模型的泛化能力。例如,使用Python的`ImageDataGenerator`类可以轻松地应用数据增强技术:
```python
from keras.preprocessing.image import ImageDataGenerator
# 创建一个ImageDataGenerator实例
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
# 流式生成增强后的图像
train_generator = datagen.flow_from_directory(
'data/train',
target_size=(150, 150),
batch_size=32,
class_mode='binary')
```
在上述代码中,我们配置了多种数据增强选项,并通过`flow_from_directory`方法从目录中加载图像,实时地对图像进行增强。
**正则化**是另一种常用的优化策略,特别是L2正则化(权重衰减)在CNN中广泛使用,以防止权重过大而导致过拟合。在模型训练过程中,通过向损失函数添加一个与权重大小成正比的项,可以有效控制权重的大小。在Keras中,可以通过添加`kernel_regularizer`来实现:
```python
from keras import regularizers
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(150, 150, 3),
activation='relu',
kernel_regularizer=regularizers.l2(0.001)))
model.add(MaxPooling2D(pool_size=(2, 2)))
# 添加更多层...
```
以上代码展示了如何在CNN模型的第一个卷积层中添加L2正则化。
### 5.1.2 数据集不平衡处理与实例
数据集的不平衡是导致欠拟合的常见原因,特别是在分类问题中。数据不平衡意味着模型可能没有足够的训练样本来学习如何识别某些类别。举个例子,如果一个分类任务中有10个类别,而其中一个类别的样本数量远远少于其他类别,模型在学习过程中可能会忽略这个稀有类别。
处理数据集不平衡的一种方法是通过**重采样**。可以采取上采样(增加少数类的样本)或者下采样(减少多数类的样本)。对于上采样,我们可以简单地复制少数类的样本,或者使用技术如SMOTE(Synthetic Minority Over-sampling Technique)生成新的合成样本。在下采样中,我们可以随机删除多数类的样本,使得每个类别的样本数量更加平衡。
为了实例化这一过程,我们可以考虑以下Python代码片段:
```python
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split
# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 应用SMOTE生成过采样的少数类样本
smote = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)
# 再次分割数据集以避免过拟合
X_train, X_val, y_train, y_val = train_test_split(X_train_resampled, y_train_resampled, test_size=0.2, random_state=42)
```
通过上述代码,我们首先分割数据集,并且应用SMOTE算法对训练数据进行重采样。然后我们再次分割数据,得到新的训练集和验证集,这样做有助于防止过拟合,并保持对模型泛化性能的监控。
## 5.2 自然语言处理案例研究
### 5.2.1 RNN与Transformer的泛化问题
在自然语言处理(NLP)中,循环神经网络(RNN)和Transformer架构已被广泛应用于诸如机器翻译、文本生成和情感分析等多种任务。然而,这些模型同样面临过拟合的风险,特别是在处理长序列或者数据量较少的任务时。
由于RNN的结构特点,它在处理长序列数据时容易丢失长期依赖信息,这可能导致泛化问题。为了解决这个问题,人们提出了如长短时记忆网络(LSTM)和门控循环单元(GRU)等改进的RNN架构。这些模型通过门控制机制来维持和更新长期状态,有效解决了传统RNN在长序列上的过拟合问题。
与此同时,Transformer模型采用自注意力(Self-Attention)机制来处理序列中的元素,能够同时考虑所有输入序列的元素,这大大增强了模型捕捉长距离依赖的能力。然而,Transformer模型由于其复杂性,在小规模数据集上也很容易发生过拟合。为了克服这个问题,可以通过模型简化、正则化技术(如dropout)或者数据增强等手段进行优化。
**Dropout**是一种常用的正则化技术,通过随机丢弃网络中的一部分神经元来降低模型复杂性,从而提高泛化能力。在Transformer模型中,可以对自注意力层或前馈网络层应用dropout,以减少过拟合的风险。下面是一个在Transformer模型中实现dropout的简单示例:
```python
import tensorflow as tf
from tensorflow.keras.layers import Dropout
# 假设已有Transformer编码器和解码器层的实现
# 创建一个完整的Transformer模型
transformer = tf.keras.models.Sequential([
TransformerEncoderLayer(...),
Dropout(0.1),
TransformerDecoderLayer(...),
Dropout(0.1),
...
])
# 编译模型
transformer.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 训练模型
transformer.fit(train_padded, train_labels, epochs=5, validation_data=(val_padded, val_labels))
```
### 5.2.2 预训练模型与微调策略
预训练模型和微调(fine-tuning)策略在NLP任务中具有重要的作用。预训练模型,如BERT、GPT和XLNet等,通过在大规模语料库上进行预训练,学习到了丰富的语言知识。这些知识不仅包括词汇和语法知识,还涵盖了世界知识和语言的多样性。
微调预训练模型是指在一个特定任务的较小语料集上进一步训练模型。通过微调,模型能够更好地适应具体的任务需求,同时利用预训练阶段学到的泛化知识。微调的过程中,通常只需要调整最后几层的参数,或者根据具体任务微调整个模型的某些部分。这不仅有助于提高模型的性能,还能有效减少过拟合的风险。
一个微调预训练模型的典型例子是在情感分析任务中使用BERT模型:
```python
from transformers import BertTokenizer, TFBertForSequenceClassification
import tensorflow as tf
# 加载预训练的BERT模型和分词器
model = TFBertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# 编码输入文本
input_text = "Replace me by any text you'd like."
encoded_input = tokenizer(input_text, return_tensors='tf')
output = model(encoded_input)
# 微调模型
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=3e-5), loss=model.compute_loss, metrics=['accuracy'])
model.fit(train_dataset, epochs=3, batch_size=16)
```
在这段代码中,我们使用了`transformers`库中的`TFBertForSequenceClassification`类来加载一个预训练好的BERT模型,并针对特定任务进行微调。`train_dataset`是一个TensorFlow的数据集实例,包含了我们需要训练的样本和标签。通过调整学习率和训练轮数,我们可以控制模型在特定数据集上的学习程度,以避免过拟合。
通过这种方式,我们不仅提高了模型对特定任务的性能,还利用了预训练模型的强大泛化能力。
0
0