深度迁移学习
迁移学习
是一种机器学习技术,它允许一个预训练
的模型被用作起点,在此基础上进行微调
以适应新的任务或数据。其核心思想是利用从一个任务中学到的知识来帮助解决另一个相关的任务,即使这两个任务的数据分布不完全相同。这种方法可以加速学习过程,提高模型性能,并减少对新数据标注的依赖。
为什么要迁移
大数据与少标注的矛盾
在大数据的时代背景下,我们所面临的数据量呈现爆炸性增长,同时数据类型也变得日益复杂多样。这种大数据环境为机器学习提供了丰富的原料,但同时也带来了一系列挑战。其中最显著的问题之一就是大数据与少标注之间的矛盾。尽管我们可以获取到海量的数据,但大部分数据往往是没有标注的,只有少部分是标注的。
数据标注过程通常需要人工参与,而且标注质量对模型性能影响极大,这使得标注工作既昂贵又耗时。如果从头构建一个模型,代价高昂且费时。
因此,为了解决大数据与少标注之间的矛盾,迁移学习成为了一种非常有效的策略。通过迁移学习,我们可以将在一个领域或任务上学到的知识迁移到另一个相关领域或任务上,从而在不需要大量标注数据的情况下,实现模型的快速构建和强泛化能力。这不仅降低了数据收集和标注的成本,还大大缩短了模型的开发周期,为机器学习在更多领域的应用提供了可能。
大数据与计算能力的矛盾
事实上,大数据和高性能计算往往成为了只有大型企业或富裕机构才能玩得起的“游戏”。无论是数据的收集、存储,还是高性能计算资源的获取,都需要巨额的投资。这对于许多小型机构、创业公司或个人研究者来说,是一个难以逾越的门槛。
正是在这样的背景下,迁移学习的价值凸显出来。迁移学习允许我们将在一个任务或领域上学到的知识迁移到另一个相关任务或领域上。这意味着,即使我们没有足够的数据或计算能力从头开始训练一个模型,我们仍然可以借助迁移学习,利用已有的知识和模型,快速适应新的任务或环境,能够参与到人工智能的浪潮中来。
普适化模型与个性化的矛盾
在实际应用中,我们经常会遇到这样的情况:一个通用的机器学习模型可能在广泛的场景下表现良好,但当我们将其部署到特定的设备、环境或针对特定的用户群体时,其性能往往会受到影响。这是因为不同的设备、环境和用户有着各自独特的特点和需求,通常需要进行具体的优化和适配。
然而,个性化适配通常是一个复杂且耗时的过程。它可能涉及到数据收集、模型调整、参数优化等多个步骤,而且每个步骤都可能需要针对具体的情况进行定制。这不仅增加了开发的难度和成本,还延长了产品的上市时间。
更为复杂的是,对于不同的用户,我们可能还需要考虑不同的隐私处理方式。例如,在一些涉及敏感信息的场景下,我们可能需要使用更加严格的隐私保护技术来确保用户数据的安全和合规性。
迁移学习为解决上述问题提供了一种有效的途径。通过迁移学习,我们可以将在一个场景或任务上学到的知识迁移到另一个相关的场景或任务上。这样,我们不仅可以利用已有的知识和经验来加速新任务的学习过程,还可以在一定程度上实现个性化适配,提高模型在特定场景下的性能。同时,迁移学习也有助于降低数据收集和标注的成本,减轻隐私处理的负担,从而更加高效、灵活地应对各种复杂的应用需求。
如何迁移学习
迁移学习是一种机器学习技术,其中一个已经训练过的模型被用作新任务的起点。这种方法能够显著减少训练新模型所需的数据量和时间,并提高模型性能。以下是如何进行迁移学习的详细步骤:
1. 选择预训练模型
- 确定任务类型:首先,要明确你的任务类型,例如图像分类、文本生成或语音识别。
- 选择适合的模型:选择与你的任务相匹配的模型架构,例如,对于图像分类任务,可以选择ResNet、VGG等;对于自然语言处理任务,可以选择BERT、GPT等。
- 考虑模型大小和复杂度:根据你的计算资源和时间限制,选择一个适当大小和复杂度的模型。
2. 数据准备
- 收集数据:为你的任务收集相关数据集。这些数据应该与预训练模型所使用的数据有一定的
关联性
。 - 数据预处理:对收集到的数据进行清洗、标注和格式化,以使其与预训练模型的输入格式相匹配。这可能包括图像大小调整、归一化、文本分词等。
- 数据划分:将数据集划分为训练集、验证集和测试集,用于模型的训练、验证和评估。
3. 模型调整
- 修改输出层:将预训练模型的输出层替换为适合你的任务的新输出层。例如,在图像分类任务中,可能需要将输出层的神经元数量改为你的类别数。
- 冻结部分层:通常,预训练模型的底层特征较为通用,而高层特征更偏向于原始任务。因此,可以冻结模型的一部分底层,只训练高层部分。
- 添加自定义层:根据新任务的需求,在预训练模型的基础上添加新的层。例如,对于分类任务,可以在模型顶部添加一个新的全连接层。
4. 训练
- 加载预训练权重:从预训练模型中加载权重,作为新模型的初始权重。
- 选择合适的优化器:根据任务需求选择合适的优化器,如SGD、Adam等,并设置合适的学习率。
- 损失函数:根据你的任务类型选择合适的损失函数,例如交叉熵损失函数用于分类任务,均方误差损失函数用于回归任务。
学习率调整策略:使用学习率衰减策略,随着训练的进行逐渐减小学习率,以提高训练的稳定性。 - 正则化:使用正则化技术如Dropout、L1/L2正则化等来防止过拟合。
- 训练模型:使用训练集和验证集进行模型的训练。在训练过程中,监控模型在验证集上的性能,以防止过拟合。
- 使用回调:可以使用回调来在训练过程中执行特定操作,如学习率调整、模型保存等。
5. 评估
使用测试集评估模型的性能,以了解模型在新任务上的表现。评估指标的选择取决于你的任务类型,常见的评估指标包括准确率、精确率、召回率、F1分数等。
此外,还可以使用可视化工具和技术来分析模型的性能,例如混淆矩阵、ROC曲线、AUC值等。
6. 微调和迭代
根据评估结果,你可能需要对模型进行进一步的微调和迭代。微调可以包括调整模型结构、优化器参数、学习率等。迭代则是指重复上述步骤,不断改进模型性能,直到达到满意的结果。
通过以上步骤,你可以利用迁移学习技术快速构建和优化针对新任务的机器学习模型。这种方法能够充分利用现有资源和知识,提高模型的性能和开发效率。
迁移学习是个多目标优化问题
迁移学习可以视作一个多目标优化问题,涉及到在多个相互关联甚至可能冲突的目标之间寻求平衡。准确率、训练时间和所占GPU资源就是这些目标中的几个典型例子。
-
准确率与训练时间的权衡:
- 准确率是机器学习模型性能的核心指标之一,通常我们希望模型在测试集上能够达到尽可能高的准确率。
- 训练时间则是一个实际应用中非常重要的考虑因素,特别是在需要快速迭代和部署模型的情况下。
- 这两个目标往往是相互冲突的。例如,为了提高准确率,我们可能需要使用更复杂的模型结构或进行更长时间的训练,而这会增加训练时间。反之,如果为了追求更快的训练速度而使用简化的模型或较少的训练轮次,则可能会牺牲一定的准确率。
-
准确率与GPU显存资源的权衡:
- GPU显存资源是深度学习训练中的宝贵资源,限制了模型的大小和批量数据的大小。
- 使用更大的模型和更大的批量数据通常有助于提高准确率,因为这可以让模型捕获更复杂的模式和利用更高效的硬件并行性。
- 然而,更大的模型和批量数据也意味着需要更多的GPU显存资源。在资源有限的情况下,我们可能需要在模型大小、批量数据大小和准确率之间做出折中。
-
训练时间与GPU显存资源的权衡:
- 训练时间和GPU显存资源之间也存在一定的联系。例如,使用更大的批量数据通常可以加速训练(因为每次迭代中计算梯度更加高效),但这也会增加GPU显存的使用。
- 反之,如果为了节省GPU显存而减小批量数据的大小,则可能会降低训练速度,因为需要更多的迭代次数来达到相同的模型性能。
因此,在进行迁移学习时,我们需要综合考虑多个目标,并根据具体的应用需求和资源限制来做出合适的折中决策。这通常涉及到实验设计、参数调整和性能评估等多个步骤,以找到在给定约束条件下最优的迁移学习策略。
多目标优化问题的特点与数学描述
多目标优化问题是一类在现实生活中广泛存在的优化问题,其特点是同时考虑多个相互冲突的目标,需要在这些目标之间进行权衡和折中。以下是多目标优化问题的特点与数学描述的详细讲解:
特点:
- 目标间的不可公度性:各个子目标之间没有统一的度量标准,因此难以直接进行比较。例如,在一个涉及成本和时间的优化问题中,成本和时间的单位不同,无法直接相加或比较大小。
- 目标间的矛盾性:当优化一个子目标时,可能会导致其他子目标的性能变差。这种矛盾性使得同时优化所有目标变得困难。
- 解的最优性:与单目标优化不同,多目标优化问题通常没有唯一的最优解,而是存在一个解集,称为Pareto最优解集。在这个解集中,任何一个解的改进都将导致至少一个其他目标的性能下降。
数学描述:
多目标优化问题可以用以下数学形式来描述:
min x ∈ Ω F ( x ) = [ f 1 ( x ) , f 2 ( x ) , … , f N ( x ) ] T \min_{x \in \Omega} \mathbf{F}(x) = \left[ f_1(x), f_2(x), \ldots, f_N(x) \right]^T x∈ΩminF(x)=[f1(x),f2(x),…,fN(x)]T
其中:
- x x x 是一个决策向量,属于决策空间 Ω \Omega Ω。
- F ( x ) \mathbf{F}(x) F(x) 是一个目标向量,包含 N N N 个子目标函数 f 1 ( x ) , f 2 ( x ) , … , f N ( x ) f_1(x), f_2(x), \ldots, f_N(x) f1(x),f2(x),…,fN(x)。
- min x ∈ Ω F ( x ) \min_{x \in \Omega} \mathbf{F}(x) minx∈ΩF(x) 表示在决策空间 Ω \Omega Ω 中找到一个决策向量 x x x,使得目标向量 F ( x ) \mathbf{F}(x) F(x) 在某种意义下达到最优。
此外,多目标优化问题还可能包含一些约束条件,如等式约束和不等式约束:
- 等式约束: h j ( x ) = 0 , j = 1 , 2 , … , m h_j(x) = 0, \quad j = 1, 2, \ldots, m hj(x)=0,j=1,2,…,m
- 不等式约束: g i ( x ) ≤ 0 , i = 1 , 2 , … , p g_i(x) \leq 0, \quad i = 1, 2, \ldots, p gi(x)≤0,i=1,2,…,p
这些约束条件限定了决策向量的可行域。
Pareto解
Pareto解,也被称为非支配解或不受支配解(nondominated solutions),是多目标优化中的一个重要概念。在多目标优化问题中,由于存在多个相互冲突的目标,一个解可能在某个目标上表现很好,但在其他目标上表现很差。Pareto解就是在不削弱任何一个目标函数性能的前提下,无法再进一步改进任何一个目标函数的解。
具体来说,假设我们有两个解S1和S2,如果S1在所有目标上都不比S2差,并且至少在一个目标上比S2好,那么我们就说S1支配S2。如果一个解没有被其他任何解所支配,那么它就被称为Pareto解。换句话说,Pareto解是这样一种解,在不使其他目标变坏的情况下,我们无法通过改变这个解来使任何一个目标变得更好。
在数学上,定义如下:
给定两个决策向量 x 1 x_1 x1 和 x 2 x_2 x2,如果对于所有子目标函数 f i ( x ) f_i(x) fi(x),都有 f i ( x 1 ) ≤ f i ( x 2 ) f_i(x_1) \leq f_i(x_2) fi(x1)≤fi(x2),并且至少存在一个 j j j 使得 f j ( x 1 ) < f j ( x 2 ) f_j(x_1) < f_j(x_2) fj(x1)<fj(x2),则称 x 1 x_1 x1 Pareto支配 x 2 x_2 x2。
Pareto最优解是指在可行域中不存在其他解能够Pareto支配它的解。所有Pareto最优解的集合构成了Pareto最优解集,而Pareto最优解集在目标空间中的像称为Pareto前沿。
如何解决多目标优化问题
解决多目标优化问题的智能优化算法有很多种,以下是对一些常见算法的简要介绍:
-
遗传算法(Genetic Algorithm, GA):
- 遗传算法是一种模拟生物进化过程的搜索启发式算法,它通过选择、交叉(杂交)和变异等操作来逐步演化出一组解。
- 在多目标优化问题中,遗传算法可以同时处理多个目标,并通过选择机制(如轮盘赌选择、锦标赛选择等)来平衡不同目标之间的权衡。
- 遗传算法具有全局搜索能力,能够探索解空间的不同区域,并找到一组近似最优解(Pareto最优解)。
-
粒子群优化算法(Particle Swarm Optimization, PSO):
- 粒子群优化算法是一种模拟鸟群、鱼群等群体行为的优化算法。它通过个体和群体的历史最佳位置信息来更新粒子的速度和位置。
- 在多目标优化中,粒子群优化算法可以采用特定的多目标版本,如多目标粒子群优化(MOPSO),通过维护一个外部存档来存储找到的Pareto最优解,并利用这些信息来指导搜索过程。
-
蚁群优化算法(Ant Colony Optimization, ACO):
- 蚁群优化算法是模拟蚂蚁觅食行为的优化算法,通过蚂蚁在解空间中释放信息素并跟随信息素浓度较高的路径来寻找最优解。
- 在多目标优化问题中,蚁群优化算法可以通过定义信息素更新规则、路径选择策略等来处理多个目标之间的权衡。
-
模拟退火算法(Simulated Annealing, SA):
- 模拟退火算法是一种模拟物理中固体退火过程的优化算法,它通过模拟高温物体逐渐降温的过程来寻找全局最优解。
- 在多目标优化中,模拟退火算法可以与其他技术结合,如权重和方法,来同时考虑多个目标。
-
进化算法(Evolutionary Algorithm, EA):
- 进化算法是一类模拟生物进化过程的优化算法的总称,包括遗传算法、进化策略、进化规划等。
- 进化算法通过种群中个体的适应度评估和选择、交叉、变异等操作来搜索最优解,特别适合处理多目标优化问题。
-
人工免疫算法(Artificial Immune Algorithm, AIA):
- 人工免疫算法是模拟生物免疫系统功能的优化算法,通过模拟抗体与抗原的结合、克隆选择、记忆细胞等机制来寻找最优解。
- 在多目标优化中,人工免疫算法可以利用抗体的多样性和记忆机制来处理多个目标之间的权衡。
这些智能优化算法通常具有全局搜索能力,能够处理复杂的非线性问题和多模态问题。它们在不同的应用领域中都得到了广泛应用,如工程设计、经济调度、路径规划等。需要注意的是,每种算法都有其特点和适用场景,选择哪种算法取决于具体问题的性质和要求。
非支配排序遗传算法
NSGA-II,全称为Non-dominated Sorting Genetic Algorithm II,即非支配排序遗传算法,是一种基于支配关系与Pareto最优解的多目标优化算法。其核心在于选择操作执行前的根据个体之间的支配关系进行的分层。
在选择操作之前,种群会根据个体之间的支配与非支配关系进行排序。首先,找出该种群中的所有非支配个体,这些个体没有被其他任何个体支配,并赋予他们一个共享的虚拟适应度值,形成第一个非支配最优层。接着,忽略已分层的个体,对剩下的个体继续按照支配与非支配关系进行分层,并赋予新的虚拟适应度值,这个值要小于上一层的值。这样的操作会一直持续,直到种群中的所有个体都被分层。每一层中的个体具有相同的非支配序,而层与层之间按照非支配序的大小进行排列。
在NSGA-II中,还引入了拥挤度和拥挤度比较算子。拥挤度用于衡量种群中给定点的周围个体的密度,用来维持种群的多样性,防止超级个体的过度繁殖,并避免早熟收敛。拥挤度比较算子则使得算法能够根据个体的非支配序和拥挤度,在两个不同的个体中选择一个更优越的个体。
以下是NSGA-II算法的详细过程,以二进制编码为例进行介绍:
- 编码
编码是将问题的解空间映射到遗传算法的搜索空间的过程。在二进制编码中,每个解被表示为一个二进制字符串(也称为染色体或基因型)。例如,如果问题的解 x x x是一个在0到1023之间的整数,我们可以使用10位二进制数来表示它(因为2^10 = 1024,足够覆盖整个解空间)。这样,解空间中的每个整数都对应于一个长度为10的二进制字符串。
- 初始种群生成
随机生成一个包含N个个体的初始种群。每个个体都是通过随机选择0或1来生成的,以形成一个二进制字符串。
- 交叉和变异
交叉和变异操作与基本的遗传算法类似。在二进制编码中,交叉可以采用单点交叉、多点交叉等方式,变异则是随机翻转某个基因位。
-
交叉:选择两个父代个体,随机选择一个或多个交叉点,交换交叉点前后的部分基因,生成新的子代个体。
-
变异:随机选择个体中的某个基因位,翻转该基因位的值。
- 非支配排序
非支配排序是NSGA-II算法的核心步骤之一。它的目的是根据个体之间的支配关系,将种群中的个体分为不同的非支配层(也称为前沿)。首先,找出种群中所有不被其他任何个体支配的个体,并将它们放入第一层。然后,从种群中移除这些个体,并重复该过程,直到种群中的所有个体都被分配到某个非支配层中。
- 拥挤距离计算
在每个非支配层内,为了保持种群的多样性,NSGA-II使用拥挤距离来度量个体之间的相似性。拥挤距离是根据个体在目标空间中的邻近个体来计算的。拥挤距离较大的个体在种群中具有较高的多样性。
- 选择
在选择操作中,NSGA-II使用精英保留策略,精英保留策略是指将当前种群中的优秀个体直接保留到下一代,能够有效地避免父代种群中优秀个体的流失。具体做法是,将当前种群和子代种群合并,然后按照非支配排序和拥挤度选择出与原始种群大小相同的个体作为下一代种群。首先,按照非支配排序的层次选择个体。如果一个个体位于更高级的非支配层,或者位于同一非支配层但具有更大的拥挤距离,则选择该个体进入下一代种群。
- 终止条件
重复步骤3到7,直到满足终止条件(如达到最大迭代次数、达到满意的解质量等)。
NSGA-II的优点在于其采用了快速非支配排序算法,降低了计算的复杂度,具有优秀的收敛性;另一方面,它引入了精英策略,保证了找到的最优解不会被抛弃,提高了搜索效率。同时,利用拥挤度和拥挤度比较算子不仅克服了NSGA中需要人为指定共享参数的缺陷,而且将其作为种群中个体间的比较标准,使得准Pareto面上的个体能均匀分布,保持了种群的多样性。
然而,NSGA-II也存在一些缺点,例如对于高维问题和复杂的多峰问题,其性能可能会下降,而且算法中的参数设置也可能对结果产生较大影响。
基于NSGA-II的深度迁移学习
接下来,我们把深度迁移学习可以定义为这样的一个多目标优化问题,其中优化目标包括最小化训练时间和最小化分类错误率。此外,该问题还受到一系列约束条件的限制,包括Freeze Weights Layers的值域、MiniBatchSize的选择范围、Initial Learn Rate的设定区间、Learn Rate Drop Factor的上下界,以及Momentum的取值范围。
数学形式表达
优化目标:
min x ∈ Ω F ( x ) = [ f 1 ( x ) , f 2 ( x ) ] T \min_{x \in \Omega} \mathbf{F}(x) = \left[ f_1(x), f_2(x)\right]^T x∈ΩminF(x)=[f1(x),f2(x)]T
-
f
1
f_1
f1:
Training_Time
-
f
2
f_2
f2:
Classification_Error_Rate
约束条件:
-
x
1
x_1
x1:
2 <= Freeze_Weights_Layers <= 129
-
x
2
x_2
x2:
Mini_Batch_Size ∈ {25, 50, 75, 100}
-
x
3
x_3
x3:
1/128 <= Initial_Learn_Rate <= 1
-
x
4
x_4
x4:
1/128 <= Learn_Rate_Drop_Factor <= 1
-
x
5
x_5
x5:
0.5 + 0.5 / 32 <= Momentum <= 1
实验参数
数据集: flower_photos
网络模型: googlenet
NSGA-II的参数:
种群大小为50,进化代数为20,编码方案如下表所示:
参数 | 值域 | 编码长度 |
---|---|---|
Freeze Weights Layers | [2,129] | 7 |
Initial Learn Rate | [1/128,1] | 7 |
Learn Rate Drop Factor | [1/128,1] | 7 |
Momentum | [0.5+0.5/32,1] | 5 |
MiniBatch Size | {25, 50, 75, 100} | 3 |
实验结果
每三代画一个图,一共4个图,如下所示。
最优解如下所示:
evaluate_objective.m
%% 评价函数
function f = evaluate_objective(x)
load Flower_data;
%% 解码
Nfr=bin2dec(num2str(x(1:7)))+2; %%% 冻结层数
%Nfr=bin2dec(num2str(x(1:7)))/2+60; %%% 冻结层数
Ril=1/(bin2dec(num2str(x(8:14)))+1); %%% 初始学习率
Rld=1/(bin2dec(num2str(x(15:21)))+1); %%% Learn rate drop
Rm=0.5+0.5/(bin2dec(num2str(x(22:26)))+1); %%% Momentum
M0=[25 50 75 100];
Nmb=M0(bin2dec(num2str(x(27:28)))+1); %%% MinibatchSize
%% 建立深度迁移模型
net=googlenet;
lgraph = layerGraph(net);
newLearnableLayer = fullyConnectedLayer(5, 'Name','new_fc', ...
'WeightLearnRateFactor',10, 'BiasLearnRateFactor',10);
lgraph = replaceLayer(lgraph,'loss3-classifier',newLearnableLayer);
newClassLayer = classificationLayer('Name','new_classoutput');
lgraph = replaceLayer(lgraph,'output',newClassLayer);
%%%%%%% 冻结网络层
layers = lgraph.Layers;
connections = lgraph.Connections;
layers(1:Nfr) = freezeWeights(layers(1:Nfr));
lgraph = createLgraphUsingConnections(layers,connections);
%% Training options
options = trainingOptions('sgdm', ...
'InitialLearnRate',Ril,...
'LearnRateSchedule','piecewise', ...
'LearnRateDropFactor',Rld, ...
'LearnRateDropPeriod',3, ...
'MaxEpochs',20, ...
'MiniBatchSize',Nmb, ...
'Momentum',Rm,...
'ExecutionEnvironment','gpu');
%% 训练网络
tic
net = trainNetwork(augimdsTrain,lgraph,options);
f(1)=toc;
[YPred,~] = classify(net,augimdsValidation);
f(2)=1-mean(YPred == imdsValidation.Labels);
% end
nsga_deep_transfer.m
clc;
clear;
addpath('D:\MATLAB_project\智能计算方法及应用\homework5\deep transfer')
addpath('D:\MATLAB_project\智能计算方法及应用\homework5\NSGA-II')
addpath('C:\Users\kilog\Documents\MATLAB\Examples\R2020a\nnet\TransferLearningUsingGoogLeNetExample')
%%
tic
pop = 25;
gen = 12;
M=2; %%%%%%%%%%%% 目标个数
V=28; %%% 染色体长度
% Initialize the population
chromosome = initialize_variables(pop,M,V);
%% Sort the initialized population
chromosome = non_domination_sort_mod(chromosome,M,V);
%% Start the evolution process
for i = 1 : gen
% Select the parents
pool = round(pop/2);
tour = 2;
parent_chromosome = tournament_selection(chromosome,pool,tour);
% Perfrom crossover and Mutation operator
offspring_chromosome = genetic_operator(parent_chromosome,M,V);
% Intermediate population
[main_pop,temp] = size(chromosome);
[offspring_pop,temp] = size(offspring_chromosome);
intermediate_chromosome(1:main_pop,:) = chromosome;
intermediate_chromosome(main_pop + 1 : main_pop + offspring_pop,1 : M+V) = ...
offspring_chromosome;
% Non-domination-sort of intermediate population
intermediate_chromosome = ...
non_domination_sort_mod(intermediate_chromosome,M,V);
% Perform Selection
chromosome = replace_chromosome(intermediate_chromosome,M,V,pop);
f1_x(i,:)=chromosome(:,V + 1);
f2_x(i,:)=chromosome(:,V + 2);
if ~mod(i,3)
fprintf('%d\n',i);
figure('Position',[500 400 400 360]);
plot(chromosome(:,V + 1),chromosome(:,V + 2),'*','MarkerSize',5);hold on;
idp=find(chromosome(:,V+3)==1);
plot(chromosome(idp,V + 1),chromosome(idp,V + 2),'ro','MarkerSize',8,'LineWidth',2.8);hold on;
title('深度迁移性能分布');
xlabel('训练时间');
ylabel('分类错误率');
end
end
t=toc;
save Final_results;
%