体系结构论文(五十三):Featherweight Soft Error Resilience for GPUs 【22‘ MIRCO】

Featherweight Soft Error Resilience for GPUs

一、文章介绍

背景:软错误通常由高能粒子(如宇宙射线和α粒子)打击电路造成的位翻转,可能导致程序崩溃或产生错误输出。随着电子技术的进步,电路对这种辐射引发的软错误变得更加敏感。由于GPU广泛应用于从嵌入式系统(如无人机和自动驾驶汽车)到高性能计算系统(如数据中心和超级计算机),保护GPU免受软错误变得至关重要。

问题:传统的错误检测方法(如指令复制)虽然可以检测软错误,但性能开销巨大。例如,在GPU上运行每条指令两次以进行比较,可能会导致性能下降50%左右。研究人员试图找到更高效的方法来减少这种开销。

Flame方案的目标

Flame是一种软硬件协同设计的方案,旨在为GPU提供软错误(soft errors)防护。Flame的目标是以低成本实现高效的错误防护,而不会牺牲GPU的性能优势。

Flame的工作原理

声学传感器 :Flame采用声学传感器检测软错误。粒子撞击电路时会产生声波,声学传感器能够在一定延迟内检测到错误。Flame利用这些传感器的最坏情况下的检测延迟(WCDL)来验证各个区域的正确性。

幂等处理:Flame将程序划分为多个幂等区域,每个区域都可以在不影响结果的情况下重新执行。通过检测到的错误,Flame能够重新执行出错的幂等区域,从而纠正错误。

软错误验证:每个幂等区域在继续执行下一个区域前,必须确保当前区域内没有错误。因此Flame需要等待WCDL验证该区域没有错误。但如果简单地在每个区域的边界处等待WCDL,会带来显著的性能损失。

性能优化:WCDL感知的warp调度

为了减少性能损失,Flame提出了一种基于WCDL感知的warp调度方案。在到达每个幂等区域的边界时,Flame会将当前的warp(线程组)暂停执行,并切换到其他准备好执行的warp,这类似于处理长延迟操作的调度机制。这样可以充分利用GPU的并行计算能力,隐藏区域验证的延迟,从而消除性能开销。

挑战与解决方案

一个挑战是:即使检测到错误,当前活动的warp可能不是产生错误的warp(因为warp可能已经暂停等待验证)。为了确保正确恢复,Flame设计了简单的硬件支持:在检测到错误时,重新执行所有未验证的warp。每个warp都会回到最近一次验证通过的区域边界,确保从正确的点开始恢复执行。

实验结果

实验表明,Flame在34个GPU基准测试中的平均性能开销接近于零(仅为0.6%)。

主要贡献

Flame是首个基于声学传感器检测和幂等处理恢复的轻量级GPU软错误防护方案。

它还识别并优化了GPU程序中的某些模式,以减少性能损失。

Flame的硬件复杂度极低,且声学传感器的面积开销不到1%。

二、背景及前置知识

A. 声学传感器基础的软错误检测

软错误来源

软错误,又称为瞬态故障,通常由高能粒子(如宇宙射线中的中子和电路中存在的α粒子)打击电路引发。

检测原理

当高能粒子打击硅片时,会产生大量的电子-空穴对,这会导致声子和光子的生成,继而产生一个强烈的声波,该声波以每秒10公里的速度在硅片上传播。

声学传感器可以通过测量悬臂梁结构的电容变化来检测这种声波,从而检测到粒子撞击产生的软错误。

传感器性能

单个声学传感器可以在500纳秒内检测到距离5毫米以内的粒子撞击,每个传感器的面积大约为一平方微米。

整个处理器管线可以通过网状声学传感器覆盖,产生不到1%的面积开销,并且不会增加制造过程中的金属层数量。

WCDL概念

声学传感器在最坏情况下的检测延迟(WCDL)内必须检测到错误。WCDL代表在某个区域结束后,需要等待一定的时间以确保没有检测到错误,程序才能继续执行下一个区域。

B. 区域级错误验证及缓冲技术

先前的解决方案

之前的工作采用了区域级错误验证 的思想,在程序执行过程中,将程序划分为多个区域,每个区域有两种状态:已验证未验证

每个区域在结束时,程序需要等待WCDL时间,以确保该区域没有软错误。如果在WCDL时间内未检测到错误,则该区域被标记为已验证,程序可以继续执行下一个区域。

缓冲存储机制

Turnstile和Turnpike依赖一个门控存储缓冲区来缓解WCDL的延迟问题。该缓冲区能够在程序执行时,将每个区域的所有写操作暂时保存起来,直到区域被验证为无错误。

当区域终止时,下一个区域可以立即开始执行,而无需等待之前区域的验证完成,因为所有的写操作都在缓冲区中排队处理。

这里我的理解是:通过将所有写操作存储在缓冲区中,而不是立即写入主存储器,门控存储缓冲区确保了只有在当前区域经过验证且无错误的情况下,才会真正将数据写入内存。如果发现错误,缓冲区中的写操作可以安全地丢弃,不会污染其他区域的数据。

C. 幂等恢复与区域划分

Flame的创新

与Turnstile和Turnpike针对CPU不同,GPU缺乏存储缓冲区,因此Flame无法采用相同的机制。为此,Flame选择了幂等处理作为替代方案。

幂等处理的概念

幂等区域是指可以被多次执行并且产生相同结果的代码区域。

为了实现幂等性,区域内不应包含任何反依赖,即不能存在"写后读"依赖,因为这会导致区域的输入在重新执行时发生变化,从而破坏幂等性。

内存反依赖:图2(a)中展示了两个指令对(2-3和4-7)存在内存反依赖,因为它们读取和写入相同的内存地址。Flame通过在指令之间插入区域边界来打破这种依赖。

寄存器反依赖:图2(b)展示了寄存器反依赖的问题,如指令5和6之间的r3反依赖。通过适当的区域划分或其他技术(如寄存器重命名或检查点)可以解决这些依赖。

D. 反依赖处理的两种方法

寄存器重命名

寄存器反依赖可以通过重命名反依赖的寄存器来消除。图3(a)中展示了将反依赖的r3重命名为r8,确保r3的初始值不会被覆盖,从而保持区域的幂等性。

这种方法的一个问题是可能会增加寄存器压力,导致更多的寄存器溢出,但实验表明对性能的影响较小。

寄存器检查点

寄存器检查点是一种替代寄存器重命名的方法,它将区域内重要的寄存器值保存到内存中。当错误发生时,可以通过加载检查点中的寄存器值来恢复执行。图3(b)展示了寄存器r3和r5在R1区域的检查点,以及R2区域的r1和r7检查点。

虽然检查点技术不会像寄存器重命名那样引起寄存器溢出问题,但它会导致存储操作的性能下降,因为GPU没有存储缓冲区。

E. 传感器检测延迟的挑战

检测延迟的问题

虽然声学传感器可以检测软错误并通过幂等恢复进行纠正,但由于检测延迟,可能无法在区域内完成错误检测。这就需要程序在每个区域结束时等待WCDL,以验证该区域是否无误。

Flame的优化:WCDL感知的warp调度

为了避免因WCDL带来的性能开销,Flame利用GPU的特性,提出了WCDL感知的warp调度。当warp到达区域边界时,Flame会暂停该warp的执行,并切换到另一个准备好的warp,利用GPU的并行计算能力来隐藏区域验证的延迟。

感知WCDL:Flame在每个warp到达区域边界时,暂停该warp的执行,因为此时它需要等待WCDL验证的完成。

切换到其他warp:Flame会将当前等待验证的warp从调度中暂时移除,然后切换到其他准备就绪的warp,继续执行其他并行任务。这就像GPU处理其他长延迟操作(如内存加载)时一样,通过调度其他warp来隐藏延迟。

假设GPU中有多个warp在执行,当前有一个warp执行到区域R1的边界,等待WCDL验证。如果没有Flame的优化,这个warp需要一直等到验证完成才能继续执行,这会造成GPU空闲。

而通过Flame的优化,GPU可以在这个warp到达区域边界并等待验证时,立即调度另一个warp去执行下一个区域的计算工作。当WCDL验证完成后,原warp会被重新调度,继续执行下一个区域R2的指令。

三、Flame 架构

这张图展示了Flame框架的高层次工作流程

  1. Flame编译器的角色

幂等区域划分

寄存器重命名

优化,例如扩大幂等区域的大小(减少区域的数量

  1. Flame GPU的运行

程序执行与验证:在Flame GPU中,程序按照幂等区域划分进行执行。每个区域执行完后,必须等待WCDL(最坏情况检测延迟)周期的验证,确认没有检测到软错误。如果通过验证(图中用"Verified"标示),则下一个区域可以继续执行。

错误检测与恢复:声学传感器在每个区域结束时对软错误进行检测,如果发现错误,Flame会触发错误恢复机制,重新执行未通过验证的区域。

1. 幂等区域与寄存器重命名

Flame通过编译器将整个GPU程序划分为若干个幂等区域。

Flame为每个区域处理寄存器的写后读反依赖问题。如果一个区域内部存在寄存器反依赖,Flame会通过寄存器重命名来消除这些依赖,从而确保该区域是幂等的。

2. 错误模型与传感器部署

Flame的错误模型主要针对由于宇宙射线或阿尔法粒子引发的软错误(如比特翻转)。为了检测这些错误,Flame在GPU的管道逻辑(pipeline logic)上部署声学传感器,而无需增加显著的硬件开销。

声学传感器:这些传感器可以检测比特翻转并实现单比特和多比特错误的检测和纠正。每个SM(流处理器)上部署200个传感器,能够达到20个周期的最坏检测延迟(WCDL)。

3. WCDL感知的warp调度

Flame通过GPU的warp调度机制解决了这个问题:

Warp并行性:GPU通常有许多warp并行执行。当一个warp因等待WCDL而停止时,调度器可以切换到其他warp来继续执行,这样就可以隐藏等待时间,不浪费计算资源。

调度机制 :Flame的调度器会将区域边界 视作一个长延迟指令(例如内存加载指令),这样在某个warp等待WCDL时,调度器会立即切换到其他warp。由于warp的调度切换时间通常比WCDL时间要长,这种机制可以隐藏WCDL延迟,前提是GPU上有足够多的warp可以调度。

4. 硬件支持:恢复PC表与区域边界队列

Flame的架构在传统GPU的基础上增加了少量的硬件支持:

恢复PC表(RPT):RPT记录每个warp最近验证通过的区域边界。当某个warp检测到错误时,Flame会将该warp的程序计数器(PC)设置为RPT中记录的恢复PC位置,从最近验证通过的区域边界重新执行。

区域边界队列(RBQ):Flame在调度器中引入了RBQ,用于追踪每个warp的区域边界和调度状态。当warp到达区域边界时,Flame将该warp放入RBQ,等待WCDL验证完成。验证通过后,调度器会从RBQ中取出warp,并让其继续执行。

图7展示了Flame架构中如何使用RPT来处理软错误的恢复。

时间线T1至T3的执行

T1时刻:两个warp(W1和W2)都在执行其第一个区域R1。此时还没有错误发生,两个warp都在正常执行。

T2时刻:W1的第一个区域R1已经被验证通过,因此其RPT表中保存的恢复PC被更新为第二个区域R2的起始位置。此时,W2仍然在执行R1,还未通过验证。

T3时刻的错误发生

T3时刻,发生了软错误,此时需要进行恢复。

W1由于R1已经通过验证,因此它的恢复PC指向R2,所以W1会从R2开始重新执行。

W2由于仍在R1中执行,且没有通过验证,因此它的恢复PC仍指向R1,所以W2会从R1重新开始执行。

对于W2也需要重新执行的疑问:

W1和W2作为幂等区域,为什么W1的验证失败要连坐W2???

5. 验证传送带的引入

Flame为了追踪每个warp的验证状态,设计了验证传送带的概念。

这种设计类比披萨店的传送带烤炉**【传送带烤炉是一种常用于比萨店的烹饪设备,它通过一个连续运行的传送带将比萨从一端送到另一端。在传送的过程中,烤炉内部的热源对比萨进行烘烤,直到比萨在传送带的末端时被烤熟】**:每一个warp像一个披萨面团,当它执行完某个区域到达边界后,会像放到传送带上的披萨一样,被放入验证队列。传送带以固定的速度运行,模拟WCDL延迟。等warp经过传送带的全程后,它就可以被认为是已验证的,类似于烤熟的披萨。

传送带的好处在于可以用一个统一的结构来追踪所有warp的验证状态,而不需要为每个warp分别设置一个计数器。

这里的意思是说:用一个统一的结构来追踪多个warp的验证状态。每当warp到达区域边界时,它就会被加入传送带,传送带按照固定的周期移动,每个warp在传送带经过足够的周期后自动通过验证。

6. 区域边界队列的工作原理

验证传送带的实现是通过RBQ来实现的。每当warp执行完某个幂等区域并到达边界时,调度器会将该warp的ID和一个有效位放入RBQ中。此时,这个warp从活跃warp池中移除,进入等待状态,直到验证完成。

RBQ的结构和作用

RBQ的长度与WCDL周期匹配,宽度为6位,其中5位用于存储32个warp的ID,1位用于标记有效位。当调度器在某一周期遇到某个warp到达区域边界时,它将该warp的信息插入RBQ。

每个周期,调度器会从RBQ中移除一个warp(就像从传送带末端取出烤熟的披萨)。如果该条目有效,说明这个warp已经经过了WCDL周期并成功验证,此时它可以重新回到活跃warp池,准备执行下一个区域。

当发生错误时,Flame会清空RBQ中的所有条目,因为这些warp可能处于未验证的状态,必须重新执行它们的最后一个区域。

这里我不太理解为什么要全部重新执行?? 执行那一个错的不就行了吗? 每一部分都是幂等区域,那么就不会相互影响

7. 错误处理与恢复机制

一旦检测到软错误,Flame会触发全局的错误恢复机制。由于在错误检测时,有多个warp可能正在执行不同的区域,而这些区域可能尚未通过验证,因此Flame必须重新执行这些warp的区域**【这里是文章的原话,but why?】**。具体流程如下:

  • 每个warp都有一个恢复PC表(RPT),记录该warp当前已验证的区域的起始位置。
  • 当错误发生时,调度器会重置所有warp的PC到其最近的验证区域,以确保所有warp从正确的区域重新开始执行。即使某些warp没有直接触发错误,也可能因为未完成验证而受到影响,因此它们也需要重新执行。

8. 案例解析

通过两个例子可以详细说明Flame在无错误和有错误场景下的工作机制。

Example A:无错误的执行流程
  • T1时刻,W1开始执行它的第一个区域R1。
  • T2时刻,W1完成R1并到达区域边界,被放入RBQ中开始WCDL验证。此时调度器调度W2执行它的第一个区域R1。
  • T3时刻,W2完成R1并到达区域边界,也被放入RBQ进行验证。此时,所有warp都在等待验证,GPU进入空闲状态。
  • T4时刻,W1的验证完成,调度器将其恢复到活跃warp池,并更新其恢复PC为R2(第二个区域的开始)。W1继续执行R2。
  • T5时刻,W2的验证也完成,调度器更新W2的恢复PC,并调度W2执行。
  • T6时刻,W1结束执行,W2继续执行其第二个区域R2。
Example B:有错误的恢复流程
  • T1时刻,W1完成其第一个区域并进入RBQ进行验证。
  • T2时刻,W1的R1区域通过验证,调度器更新它的恢复PC为R2的开始。此时W2正在执行R1,W3在等待R1的验证。
  • T3时刻 ,错误在W2的R1中被检测到。此时,Flame重置所有warp的PC:
    • W1已经验证过R1,因此它的PC被设置为R2的开始。
    • W2因为错误中断,必须从R1的开始重新执行。
    • W3由于R1尚未验证,也需要从R1重新开始执行。
  • T4时刻,W2重新执行R1,接着W3重新执行它的R1区域,最终确保错误不会扩散。

9. 原始幂等区域形成算法的优化

在原始的幂等区域形成算法中,所有同步原语(如barriers和atomic指令)被视为区域边界。这是因为这些同步操作确保了线程间的执行顺序和数据一致性,防止错误从一个warp传播到另一个warp。这个过程被称为同步级别的错误隔离

虽然同步操作确保了错误隔离,但它们也导致编译器在这些同步原语处插入区域边界。每次插入一个区域边界,都会导致幂等区域变得更小。因为验证过程需要等待WCDL,这使得频繁的区域验证增加了性能开销。

同步原语是在并发或并行计算中用于协调不同线程或进程的操作顺序,确保它们能够安全地访问共享资源或数据,并避免竞争或数据不一致性的问题。

简单来说,同步原语是为了解决多个线程或进程同时操作同一资源时产生的冲突或数据问题。

Flame的优化目标是去除不必要的同步边界,特别是在某些代码模式下,编译器可以识别WARAW(写后读再写)依赖,并将这些区域视为幂等的。这意味着,即使在barrier存在的情况下,代码中某些依赖关系也不会破坏幂等性。

如图10所示的代码模式中,A[id]的引用形成了写后读再写依赖。但编译器可以去除barrier引入的区域边界,并将整个代码段视为一个单一的幂等区域。

尽管去除了barrier边界,Flame仍然采用保守的策略,确保错误不会传播到其他线程块之外:

保守策略:Flame的编译器会识别特定的代码模式:如果某一段代码仅初始化共享内存,并且后续的所有依赖都来源于这段共享内存,那么它可以安全地去除barrier边界。这样,即使有错误发生,也只会在同一线程块内传播,而不会影响到其他线程块中的warp。

换句话说,如果共享内存是局部的,属于线程块范围,错误不会通过共享内存传播到其他线程块。

四、讨论

1. 额外的保护要求

Flame实现软错误恢复时,除了常规的软错误防护外,还有一些关键部件需要额外保护:

RBQ、RPT和Warp调度器:这些组件在错误检测和恢复过程中起到了至关重要的作用,因此需要额外的保护,防止它们自身受到软错误的影响。

AGU(地址生成单元):软错误可能导致地址生成错误,从而引发对错误位置的加载或存储操作。Flame假设AGU已经具备防软错误能力。

寄存器文件(RF)控制器保护:类似AGU的保护技术,Flame需要RF控制器具备防护软错误的能力,以确保每次访问寄存器时不会出现寻址错误。

2. 误报率

误报率指的是声学传感器检测到的那些并不引起实际错误的粒子撞击事件:

校准传感器:通过适当的校准,声学传感器能够避免检测到不会引发位翻转的粒子撞击,从而将这类"虚假检测"降低到零。即便如此,传感器仍然可能会报告错误,因为并非所有的粒子撞击都会导致用户可见的输出错误。

位屏蔽率:这表示即使发生位翻转,错误也可能不会传播到最终的输出结果。研究表明,GPU应用程序的位屏蔽率大约为63.5%,比CPU的位屏蔽率(约90%)低得多。

误报率计算:Tiwari等人的研究显示,超算中使用的GPU每一天会有0.5次错误发生。基于GPU应用的位屏蔽率,Flame预计每天会产生大约0.93次误报。这些误报带来的执行时间开销是可以忽略不计的,因为平均每个幂等区域的指令数大约为50.23条。

3. 错误隔离机制

Flame利用幂等区域,确保即使错误数据写入缓存层次结构,它们也不会被读取或传播:

无反依赖性:幂等区域没有反依赖性,这意味着错误数据不会被后续的读取操作使用。

区域验证与错误恢复:在一个区域结束前,所有错误都会被检测到并通过幂等恢复机制纠正。因此,即使错误数据写入缓存,等到该区域通过验证后,错误数据不会影响其他区域的执行

五、实验设置

1. 实验环境(Evaluation Environment)

GPU架构和设置
  • 实验主要基于Nvidia的GTX480 GPU,它使用Fermi架构,并配备ECC(错误纠正码)来保护其内存层次结构(包括寄存器文件、缓存和内存)。
  • 默认情况下,Flame使用20个周期的WCDL(最坏检测延迟)和GTO(Greedy Then Oldest)Warp调度器,这是GPGPU-Sim v4.0模拟器的默认模型。
仿真方法
  • 寄存器重命名和检查点:由于实现反依赖寄存器重命名和寄存器检查点需要寄存器信息,而Nvidia的PTX汇编使用虚拟寄存器,因此Flame的编译器在PTX级别对寄存器分配进行了修改,以实现这两种恢复技术。
  • 模拟工具:所有的模拟都是基于GPGPU-Sim v4.0进行的,Flame的编译器通过修改PTX代码来实现寄存器分配。
  • 测试基准:共测试了34个基准应用,主要来自Rodinia v3.1、Parboil、GPGPU-Sim、NPB、ALTIS、SHOC以及CUDA工具包的示例。图表列出了每个基准套件的应用程序。

2. 对比方案

1) 指令复制检测
  • SwapCodes:使用的是SwapCodes指令复制技术。SwapCodes通过将原始指令的输出寄存器与复制指令的输出寄存器进行ECC配对,从而避免了显式比较原始指令和复制指令的输出。
2) 混合检测
  • Tail-DMR:这种混合检测技术结合了声学传感器和指令复制,能够在不增加WCDL验证延迟的情况下检测软错误。Tail-DMR通过将每个区域划分为头部和尾部,在头部使用声学传感器,尾部使用指令复制(DMR),从而确保错误在区域内被检测到。

声学传感器用于在时间T1到T2期间检测错误,而DMR则用于在时间T2到T3期间检测尾部的错误。

六、实验结果

传感器数量对WCDL的影响

  1. X轴:传感器数量,表示每个SM上部署的声学传感器数量。
  2. Y轴:检测延迟(WCDL)
  3. 观察结果
    • 不同架构的曲线展示了检测延迟随着传感器数量的增加而减小,传感器越多,检测延迟越小。
    • GTX480、TITAN X、GV100和RTX2060的WCDL都随着传感器数量的增加而降低,但降低的趋势在传感器数量超过100时逐渐趋于平缓。
    • 对于GTX480,通过部署大约200个传感器,可以实现20个周期的WCDL,而500个传感器则可以将延迟降至10个周期以下。

不同检测/恢复方案的性能开销

  1. X轴:基准测试程序

  2. Y轴:归一化执行时间

  3. 颜色区分不同方案蓝色:Flame方案,结合传感器检测和寄存器重命名的恢复方式

  4. 主要结论

    • Flame (Sensor+Renaming) 在大多数基准测试中表现最佳,执行时间的开销极小,在某些基准(如Histogram和SP)中甚至出现了性能提升。
    • 其他方案,如传感器+检查点指令复制+重命名,由于增加了额外的计算开销,在一些基准测试中显著增加了执行时间(如LavaMD和Hotspot)。
    • 混合检测方案(Hybrid)的性能介于Flame和指令复制方案之间。尽管其使用了更复杂的检测机制,但其尾部DMR带来的开销仍然较高。

不同方案的平均性能开销

  1. X轴:不同方案的名称
  2. Y轴:归一化执行时间

冗余区域优化的影响

  1. 蓝色表示原始方案橙色表示优化方案
  2. X轴显示了一系列基准应用程序,Y轴表示归一化执行时间。

不同GPU架构实现20周期WCDL所需的传感器数量

不同WCDL周期对Flame性能的影响

  1. 此图展示了Flame在不同WCDL(从10到50周期)下的性能表现。
  2. X轴是基准应用程序,而Y轴是归一化执行时间。不同颜色代表了不同的WCDL设置(10, 20, 30, 40, 50周期)。
  3. 主要趋势:较小的WCDL值(例如10周期)可以显著减少性能开销。例

不同GPU调度算法对Flame性能的影响

不同GPU架构下的Flame性能表现

相关推荐
cloud studio AI应用3 分钟前
腾讯云 AI 代码助手:产品研发过程的思考和方法论
人工智能·云计算·腾讯云
禁默14 分钟前
第六届机器人、智能控制与人工智能国际学术会议(RICAI 2024)
人工智能·机器人·智能控制
Robot25122 分钟前
浅谈,华为切入具身智能赛道
人工智能
只怕自己不够好27 分钟前
OpenCV 图像运算全解析:加法、位运算(与、异或)在图像处理中的奇妙应用
图像处理·人工智能·opencv
果冻人工智能2 小时前
2025 年将颠覆商业的 8 大 AI 应用场景
人工智能·ai员工
代码不行的搬运工2 小时前
神经网络12-Time-Series Transformer (TST)模型
人工智能·神经网络·transformer
石小石Orz2 小时前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
孤独且没人爱的纸鹤2 小时前
【深度学习】:从人工神经网络的基础原理到循环神经网络的先进技术,跨越智能算法的关键发展阶段及其未来趋势,探索技术进步与应用挑战
人工智能·python·深度学习·机器学习·ai
阿_旭2 小时前
TensorFlow构建CNN卷积神经网络模型的基本步骤:数据处理、模型构建、模型训练
人工智能·深度学习·cnn·tensorflow
羊小猪~~2 小时前
tensorflow案例7--数据增强与测试集, 训练集, 验证集的构建
人工智能·python·深度学习·机器学习·cnn·tensorflow·neo4j