作业帖 | 百度深度学习集训营
DJ星尘 发布于2019-12-09 23:08 浏览:29081 回复:949
48
收藏
最后编辑于2020-06-28

百度深度学习集训营已经正式开营,每个阶段的作业都将有各自的奖励,欢迎大家学习~

PS:如遇帖子过期、审核不通过的情况,请先复制内容保存在word文档,然后根据提示,完成个人实名验证,刷新后重新粘贴复制的内容,即可提交~

欢迎大家报名参加~

1月9日作业:

作业9-1:在第二章中学习过如何设置学习率衰减,这里建议使用分段衰减的方式,衰减系数为0.1, 根据ResNet目前的训练情况,应该在训练到多少步的时候设置衰减合适?请设置好学习率衰减方式,在眼疾识别数据集iChallenge-PM上重新训练ResNet模型。

作业9-1奖励:在作业中随机各抽取5名同学送出飞桨本+数据线+飞桨贴纸

回复帖子形式:  作业9-1:XXX

抽奖作业截止时间:2020年1月13日中午12点之前

作业9-2奖励:在作业中随机各抽取5名同学送出飞桨本+数据线+飞桨贴纸

回复帖子形式:  作业9-2:XXX

抽奖作业截止时间:2020年1月13日中午12点之前

 

1月7日作业:

作业8:如果将LeNet模型中的中间层的激活函数Sigmoid换成ReLU,在眼底筛查数据集上将会得到什么样的结果?Loss是否能收敛,ReLU和Sigmoid之间的区别是引起结果不同的原因吗?请发表你的观点

作业8奖励:在作业中随机各抽取5名同学送出飞桨本+数据线+飞桨贴纸

回复帖子形式:  作业8:XXX

获奖同学:#820 thunder95、#819 你还说不想我吗、 #818 百度用户#0762194095、#817 呵赫 he、#816 星光1dl

1月2日作业

作业7-1  计算卷积中一共有多少次乘法和加法操作

输入数据形状是[10, 3, 224, 224],卷积核kh = kw = 3,输出通道数为64,步幅stride=1,填充ph = pw =1

完成这样一个卷积,一共需要做多少次乘法和加法操作?

提示:先看输出一个像素点需要做多少次乘法和加法操作,然后再计算总共需要的操作次数

提交方式:请回复乘法和加法操作的次数,例如:乘法1000,加法1000

作业7-1奖励:抽取5人赢得飞桨定制本+数据线,截止时间2020年1月6日中午12点之前

回复帖子形式:  作业7-1:XXX

作业7-2奖励:从正确答案中抽取5人获得飞桨定制本+50元京东卡,截止时间2020年1月6日中午12点之前 

 

12月31日作业

作业6-1:

1.将普通神经网络模型的每层输出打印,观察内容
2.将分类准确率的指标 用PLT库画图表示
3.通过分类准确率,判断以采用不同损失函数训练模型的效果优劣
4.作图比较:随着训练进行,模型在训练集和测试集上的Loss曲线
5.调节正则化权重,观察4的作图曲线的变化,并分析原因
作业6-1奖励:抽取5人赢得飞桨定制本+数据线 ,回复帖子形式:  作业6-1:XXX

作业6-2:

正确运行AI Studio《百度架构师手把手教深度学习》课程里面的作业3 的极简版代码,分析训练过程中可能出现的问题或值得优化的地方,通过以下几点优化:

(1)样本:数据增强的方法

(2)假设:改进网络模型

(2)损失:尝试各种Loss

(2)优化:尝试各种优化器和学习率

目标:尽可能使模型在mnist测试集上的分类准确率最高

提交实现最高分类准确率的代码和模型,我们筛选最优结果前10名进行评奖

作业6-2奖励:飞桨定制本+50元京东卡

 

12月25日作业

12月23日作业

作业4-1:在AI studio上运行作业2,用深度学习完成房价预测模型

作业4-1奖励:飞桨定制本+ 《深度学习导论与应用实践》教材,选取第2、3、23、123、223、323…名同学送出奖品

作业4-2:回复下面问题,将答案回复帖子下方:

通过Python、深度学习框架,不同方法写房价预测,Python编写的模型 和 基于飞桨编写的模型在哪些方面存在异同?例如程序结构,编写难易度,模型的预测效果,训练的耗时等等?

回复帖子形式:  作业4-2:XXX

作业4-2奖励:在12月27日(本周五)中午12点前提交的作业中,我们选出最优前五名,送出百度定制数据线+《深度学习导论与应用实践》教材


12月17日作业

完成下面两个问题,并将答案回复在帖子下面,回帖形式:作业3-1(1)XX(2)XX

作业奖励:在2019年12月20日中午12点之前提交,随机抽取5名同学进行点评,礼品是本+数据线

12月12日作业

获奖者:第12名:飞天雄者                                     

12月10日作业
作业1-1:在AI Studio平台上https://aistudio.baidu.com/aistudio/education/group/info/888 跑通房价预测案例

作业1-1奖励:最先完成作业的前3名,以及第6名、66名、166名、266名、366名、466名、566名、666名的同学均可获得飞桨定制大礼包:飞桨帽子、飞桨数据线 、飞桨定制logo笔

作业1-1的获奖者如图:

作业1-2:完成下面两个问题,并将答案发布在帖子下面
①类比牛顿第二定律的案例,在你的工作和生活中还有哪些问题可以用监督学习的框架来解决?假设和参数是什么?优化目标是什么?
②为什么说AI工程师有发展前景?怎样从经济学(市场供需)的角度做出解读?
作业1-2奖励:回复帖子且点赞top5,获得《深度学习导论与应用实践》教材+飞桨定制本

点赞Top5获奖者:1.飞天雄者  2.God_s_apple  3.177*******62   4.学痞龙   5.故乡237、qq526557820

作业截止时间2020年1月10日,再此之前完成,才有资格参加最终Mac大奖评选

 

报名流程:

1.加入QQ群:726887660,班主任会在QQ群里进行学习资料、答疑、奖品等活动

2.点此链接,加入课程报名并实践:https://aistudio.baidu.com/aistudio/course/introduce/888

温馨提示:课程的录播会在3个工作日内上传到AI studio《百度架构师手把手教深度学习》课程上

 

收藏
点赞
48
个赞
共949条回复 最后由superbusiness0回复于2020-06-28 20:29
#853飞天雄者回复于2020-01-10 10:56:53

作业8:

LeNet模型中的中间层的激活函数为Sigmoid,用在眼底筛查数据集上进行训练,Loss并不能很好的收敛,准确率也不好。

将LeNet模型中的中间层的激活函数Sigmoid换成ReLU,在眼底筛查数据集上Loss是能够收敛,并且准确率也极大的提高。

Sigmoid可以造成梯度消失,而Relu可以很好的将梯度传播下去不会造成梯度消失。Relu的这个特性可以让模型更好的收敛。

0
#852yuzaihuan回复于2020-01-10 08:13:35

作业8-1:

使用Sigmoid激活函数的输出:

使用Relu激活函数的输出:

 

在相同的训练次数和网络结构下,后者明显优于前者,这主要是由于Relu能有效减缓过拟合的发生的概率,同时,计算量也比Sigmoid小很多。

0
#851lurui0001回复于2020-01-09 23:36:03

2.理论作业:
①类比牛顿第二定律的案例,在你的工作和生活中还有哪些问题可以用监督学习的框架来解决?假设和参数是什么?优化目标是什么?

答:焦耳定律中热量Q,电流I,电阻R,时间t的关系,可以使用监督。参数I,R,t,假设:Q=K*I*I*R*t,优化目标:不同t,I,R,下产生热量Q,与系数K的关系,确定K.,使得K的误差方均值最小

②为什么说AI工程师有发展前景?怎样从经济学(市场供需)的角度做出解读?

答:AI工程师从事于AI行业,这个市场并没有发展到完全成熟的阶段,技术在不断增长,需求也在培育中增长,属于行业发展周期的扩张期,AI工程师需求不断扩大,可以与行业共同走向繁荣成熟期。

0
#850跌路冷回复于2020-01-09 21:18:53

作业8:

使用relu激活函数,Loss可以收敛。

Sigmoid函数一旦进入饱和区,则梯度变化将很小,即Loss基本不再下降

0
#849跌路冷回复于2020-01-09 21:17:46

使用relu激活函数,Loss可以收敛。

Sigmoid函数一旦进入饱和区,则梯度变化将很小,即Loss基本不再下降

0
#848为人名服务11i回复于2020-01-09 21:13:36

作业8:如果将LeNet模型中的中间层的激活函数Sigmoid换成ReLU,在眼底筛查数据集上将会得到什么样的结果?Loss是否能收敛,ReLU和Sigmoid之间的区别是引起结果不同的原因吗?请发表你的观点。

1. 针对眼底筛查数据集

1) 若在LeNet模型中的中间层的激活函数使用Sigmoid函数,在5次epoch后,在验证集上的准确率在57.25%左右,loss几乎不再改变;在10次epoch后,在验证集上的准确率也在57.25%左右,Loss也几乎不再改变。

2) 若在LeNet模型中的中间层的激活函数使用Relu函数,在5次epoch后,在验证集上的准确率在90.75%左右,loss仍在变化;在10次epoch后,在验证集上的准确率也在92.50%左右,Loss仍在改变。

具体结果如下图1-图4所示。

                      图1 Sigmoid函数 Epoch = 5                                                  图2 Relu函数 Epoch = 5

          

                  图3  Sigmoid函数 Epoch = 10                                            图4  Relu函数 Epoch = 10

2. 分析产生二者区别的原因

在实验中,由于只改变了激活函数这一项,因此激活函数是引起结果不同的根本原因,同时,Relu函数相比于Sigmoid函数,促使结果的分类精度更高,训练收敛速度也更快,进一步分析,大体有三点原因:

1)采用sigmoid作为激活函数时,指数级别的运算,运算量大,同时,在反向传播求误差梯度时,求导涉及到除法,计算量相对较大,而采用Relu激活函数,整个过程的计算量会小很多;

2)Relu激活函数会使一部分神经元的输出为0,这样就造成了神经网络的稀疏性,并且减少了各个参数之间的相互依存关系,缓解了过拟合问题的发生,也就是大家常说的:在生物上的合理性,它是单边的,相比sigmoid激活函数,更符合生物神经元的特征;

3)对于深层的神经网络,sigmoid函数在反向传播的过程中,很容易就会出现梯度消失的情况,即在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,从而无法完成深层神经网络的训练。

2
#847tichen858回复于2020-01-09 20:18:39

作业8-1:

变更为relu后能够收敛,收敛速度加快。可能原因是relu计算更为简单,计算量更少。

0
#846189*****101回复于2020-01-09 20:16:53

作业8:如果将LeNet模型中的中间层的激活函数Sigmoid换成ReLU,在眼底筛查数据集上将会得到什么样的结果?Loss是否能收敛,ReLU和Sigmoid之间的区别是引起结果不同的原因吗?请发表你的观点

换成Relu激活函数以后,可以发现loss会收敛,而且收敛更快,根据这两个函数的特性可以发现,sigmoid函数只有在中间小范围内梯度较大,而在两端很大的范围内梯度几乎为0,反向传播时会出现梯度消失的现象,Relu函数则不同,在大于0时梯度一直为1,不会有梯度消失的现象。

0
#845弋褫回复于2020-01-09 20:01:58

作业8-1:sigmoid 换成relu,loss收敛,准确度提升,运行结果如下图

从纵坐标及曲线可以看出,sigmoid的loss下降到0.7附近不再下降,而relu则下降到0.1一下还有下降趋势,

在此项目中relu优势比sigmoid大

 

分析

sigmoid和relu的函数图像如下

可以看出,

sigmoid非常容易达到平缓区域,其梯度接近0,导致loss收敛缓慢。

relu在大于0的部分,梯度始终是一个常数,

 

0
#844189******30回复于2020-01-09 19:55:04

作业8:如果将LeNet模型中的中间层的激活函数Sigmoid换成ReLU,在眼底筛查数据集上将会得到什么样的结果?Loss是否能收敛,ReLU和Sigmoid之间的区别是引起结果不同的原因吗?请发表你的观点

将卷积层的Sigmoid换成ReLU能够使模型的loss下降更快,也减少了同样其他参数情况下的训练用时。因为relu激活函数解决了深层网络的梯度消散现象,使模型更快收敛,而且其只将输入大于1的神经元传入下一层,使模型集中学习重要的图像特征,并减少了运算量。

但试验得出:后面分类的全连接层还是sigmoid激活函数效果更好。

0
#843Exile_Saber回复于2020-01-09 19:11:38

将激活函数改成relu后,准确度有了很大程度的提高,模型训练效果显著。

原因分析:由于sigmoid函数两端倒数为0,容易导致后面的隐藏层激活后反向传播值为0,起不到更新网络参数的作用

     而relu激活函数就不存在这个问题,relu激活函数在大于0的部分的倒数全部为1,小于0的部分为0

sigmoid:

relu:

 

0
#842xlwan11回复于2020-01-09 18:40:28

作业7-1:

乘法:((224+2-3)/1+1)*10*3*64*9=867041280次

加法:((224+2-3)/1+1)*10*3*64*(8+1)=867041280次

作业7-2:

0
#841aaaLKgo回复于2020-01-09 18:23:22

作业8:

使用Sigmoid函数训练的结果:

使用ReLU函数训练的结果:

 

从结果上来看,ReLU的准确率和损失都比Sigmoid好上很多,在ReLU上能达到90%以上的准确率。

分析:

从函数性质上来看,ReLU是分段线性函数,而Sigmoid是指数曲线。同时,ReLU的导数分别是 0 和 1,因此导数链式传播很快,而Sigmoid的导数是二次函数,因此比ReLU的传播要慢。因此在计算上,ReLU的计算速度会比Sigmoid快上很多。这在实际计算中是能感受到的。

从导数上来看,ReLU的导数分别是 0 和 1,一旦节点计算结果为负,就会使这部分输出为0,使得网络不会训练这部分参数,从而产生一定的稀疏性,有一定的正则化效果。因此整体效果会比Sigmoid好上很多。

另外,更为重要的是,Sigmoid函数的导数为 x (1 - x),其极值分别 0 和 0.25 ,而深度神经网络多层的导数链式传播使得多个Sigmoid导数相乘,因此会出现 0.25^N ~ 0,从而使得反向传播的梯度逐渐趋向于0,因此损失无法再通过梯度进行传播,故参数再也无法继续更新,导致网络训练整体出现停滞。从上述结果中我们也可以看到,使用Sigmoid的训练,其准确率一直停留在0.5275,损失一直为0.69,其根本原因就是Sigmoid导致的梯度消失问题,参数无法更新。

而ReLU由于分段线性产生非线性函数,正数部分梯度相乘一直为1,因此既不会出现梯度消失,也不会出现梯度爆炸的问题,在这点上,ReLU比传统Sigmoid优秀很多。

0
#840魏俊1975回复于2020-01-09 17:29:06

作业8:

激活函数为sigmod时损失无法收敛,主要是因为sigmod容易梯度消失,在深层网络中尤其如此。

start training ... epoch: 0, batch_id: 0, loss is: [0.70030516] epoch: 0, batch_id: 10, loss is: [0.69729173] epoch: 0, batch_id: 20, loss is: [0.6988058] epoch: 0, batch_id: 30, loss is: [0.699013]

激活函数为relu时损失可以收敛,只要X值大于零就可以反向传播。而且Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。不过Relu也有缺陷:当Relu输出为0后,梯度没发反向传递,这个Relu就死掉了,就是说在反向传播的过程中很快让一些神经元的导数永远为0,这些神经元被永久遗弃了;为了不让Relu武断的置零,给了很小的系数,这种LeakyRelu作为激活函数的方法解决此了问题。

start training ... epoch: 0, batch_id: 0, loss is: [0.63210124] epoch: 0, batch_id: 10, loss is: [0.74558866] epoch: 0, batch_id: 20, loss is: [0.35315874] epoch: 0, batch_id: 30, loss is: [0.23432064] [validation] accuracy/loss: 0.9149999618530273/0.2930580973625183

分析:由于其他训练条件相同,只有激活函数不同,所以可以认为造成上述结果的原因就是使用了不同的激活函数。    

0
#839aaaLKgo回复于2020-01-09 17:15:52

作业6-1:

1. 将普通神经网络模型的每层输出打印,观察内容

class MNIST(fluid.dygraph.Layer):
​    def __init__(self, name_scope):
​        super(MNIST, self).__init__(name_scope)
​        name_scope = self.full_name()
​        self.conv1 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2)
​        self.pool1 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
​        self.conv2 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2)
​        self.pool2 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
​        self.fc = FC(name_scope, size=10, act='softmax')

​    # 加入对每一层输入和输出的尺寸和数据内容的打印,根据check参数决策是否打印每层的参数和输出尺寸
​    def forward(self, inputs, label=None, check_shape=False, check_content=False):
​        # 给不同层的输出不同命名,方便调试
​        outputs1 = self.conv1(inputs)
​        outputs2 = self.pool1(outputs1)
​        outputs3 = self.conv2(outputs2)
​        outputs4 = self.pool2(outputs3)
​        outputs5 = self.fc(outputs4)
​        return outputs5

########## print network layer's superparams ##############

conv1-- kernel_size:[20, 1, 5, 5], padding:[2, 2], stride:[1, 1]

conv2-- kernel_size:[20, 20, 5, 5], padding:[2, 2], stride:[1, 1]

pool1-- pool_type:max, pool_size:[2, 2], pool_stride:[2, 2]

pool2-- pool_type:max, poo2_size:[2, 2], pool_stride:[2, 2]

fc-- weight_size:[980, 10], bias_size_[10], activation:softmax

########## print shape of features of every layer ###############

inputs_shape: [100, 1, 28, 28]

outputs1_shape: [100, 20, 28, 28]

outputs2_shape: [100, 20, 14, 14]

outputs3_shape: [100, 20, 14, 14]

outputs4_shape: [100, 20, 7, 7]

outputs5_shape: [100, 10]

########## print network layer's superparams ##############

conv1-- kernel_size:[20, 1, 5, 5], padding:[2, 2], stride:[1, 1]

conv2-- kernel_size:[20, 20, 5, 5], padding:[2, 2], stride:[1, 1]

pool1-- pool_type:max, pool_size:[2, 2], pool_stride:[2, 2]

pool2-- pool_type:max, poo2_size:[2, 2], pool_stride:[2, 2]

fc-- weight_size:[980, 10], bias_size_[10], activation:softmax

########## print shape of features of every layer ###############

inputs_shape: [100, 1, 28, 28]

outputs1_shape: [100, 20, 28, 28]

outputs2_shape: [100, 20, 14, 14]

outputs3_shape: [100, 20, 14, 14]

outputs4_shape: [100, 20, 7, 7]

outputs5_shape: [100, 10]

########## print convolution layer's kernel ###############

conv1 params -- kernel weights: name tmp_7228, dtype: VarType.FP32 shape: [5, 5] lod: {} dim: 5, 5 layout: NCHW dtype: float data: [0.285795 -0.497442 -0.329033 -0.196272 0.0283462 -0.265686 -0.0366497 -0.235756 -0.579852 0.352782 0.129043 0.0992124 0.428927 -0.0236315 -0.0549529 -0.116191 -0.139062 -0.142551 0.199173 -0.119843 -0.441896 -0.76332 -0.447826 -0.117968 -0.41601]

conv2 params -- kernel weights: name tmp_7230, dtype: VarType.FP32 shape: [5, 5] lod: {} dim: 5, 5 layout: NCHW dtype: float data: [0.0184141 -0.00476859 -0.00105555 -0.0506164 0.0424409 0.00563936 0.125538 0.0111884 0.00202755 -0.0478399 -0.00854358 -0.00799576 0.0125132 0.0170239 -0.0108752 0.0953443 -0.105848 0.130076 -0.0698557 -0.039382 -0.0417719 0.0329137 0.00646807 -0.0582326 0.028017]

2. 将分类准确率的指标 用PLT库画图表示

3. 通过分类准确率,判断以采用不同损失函数训练模型的效果优劣

交叉熵损失函数最好

a)cross_entropy

b)sigmoid_cross_entropy_with_logits

c)square_error_cost

4.作图比较:随着训练进行,模型在训练集和测试集上的Loss曲线

5.调节正则化权重,观察4的作图曲线的变化,并分析原因

正则化权重越大 对参数训练的抑制作用越大

regularization=fluid.regularizer.L2Decay(regularization_coeff=0.8)

regularization=fluid.regularizer.L2Decay(regularization_coeff=0.5)

regularization=fluid.regularizer.L2Decay(regularization_coeff=0.1)

regularization=fluid.regularizer.L2Decay(regularization_coeff=0.01)

data_writerloss = []
data_writeracc = []
data_writer_x = []
evaldata_writerloss = []
evaldata_writeracc = []
evaldata_writer_x = []
with fluid.dygraph.guard(place):
    # params_dict, opt_dict = fluid.load_dygraph(params_path)
    model = MNIST("mnist")
    # model.load_dict(params_dict)
    model.train()
    train_loader = paddle.batch(paddle.dataset.mnist.train(), batch_size=100)
    eval_loader = paddle.batch(paddle.dataset.mnist.test(), batch_size=10000)#
    boundaries =[20*600,40*600,60*600,70*600]
    values = [0.003,0.001,0.0005,0.00025,0.0001]
    
    # optimizer = fluid.optimizer.SGDOptimizer(learning_rate=fluid.layers.piecewise_decay(boundaries, values),
    # regularization=fluid.regularizer.L2Decay(regularization_coeff=0.001))
    #RMSPropOptimizer
    optimizer = fluid.optimizer.AdamOptimizer(learning_rate=fluid.layers.piecewise_decay(boundaries, values),
    regularization=fluid.regularizer.L2Decay(regularization_coeff=1.0))
    # optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.003,
    # regularization=fluid.regularizer.L2Decay(regularization_coeff=0.0015))
    #optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=fluid.layers.piecewise_decay(boundaries, values),
    # momentum=0.95,
    # regularization=fluid.regularizer.L2Decay(regularization_coeff=0.001))
    # optimizer.set_dict(opt_dict)
    EPOCH_NUM = 5
    scalar_x = 0
    markers = ['+', 'x', 'o', 's']
    print('train')
    for epoch_id in range(0,EPOCH_NUM):
        for batch_id, data in enumerate(train_loader()):
            model.train()
            image_data = np.array([np.reshape(x[0],[1,28,28]).astype('float32') for x in data])
            label_data = np.array([np.reshape(x[1], [1]).astype('int64') for x in data])#.reshape(-1, 1)
            # 将数据转为飞桨动态图格式
            image = fluid.dygraph.to_variable(image_data)
            label = fluid.dygraph.to_variable(label_data)
            # 前向计算的过程
            predict,avg_acc = model(image,label)
            loss = fluid.layers.cross_entropy(predict, label)
            avg_loss = fluid.layers.mean(loss)
            # break

            #后向传播,更新参数的过程
            avg_loss.backward()
            optimizer.minimize(avg_loss)
            model.clear_gradients()

            #每训练了1000批次的数据,打印下当前Loss的情况
            if batch_id !=0 and batch_id % 50 == 0:
            # clear()
            # print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
            print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), avg_acc.numpy()))
            # print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(),acc))

            data_writeracc.append(avg_acc.numpy()[0])
            # data_writeracc.append(acc)
            data_writerloss.append(avg_loss.numpy()[0])
            data_writer_x.append(scalar_x)
            scalar_x = scalar_x + 50


        model.eval()
        for batch_id, data in enumerate(eval_loader()):
            image_data = np.array([np.reshape(x[0],[1,28,28]).astype('float32') for x in data])
            label_data = np.array([np.reshape(x[1], [1]).astype('int64') for x in data])#.reshape(-1, 1)
            # 将数据转为飞桨动态图格式
            image = fluid.dygraph.to_variable(image_data)
            label = fluid.dygraph.to_variable(label_data)
            # 前向计算的过程
            predict,avg_acc = model(image,label)
            loss = fluid.layers.cross_entropy(predict, label)
            avg_loss = fluid.layers.mean(loss)

            # clear()
            print('--------------eval-------------')
            print("epoch: {}, batch: {}, loss is: {}, acc is {}".format(epoch_id, batch_id, avg_loss.numpy(), avg_acc.numpy()))
            print('--------------eval-------------')
            print('--',avg_loss.numpy()[0])
            evaldata_writeracc.append(avg_acc.numpy()[0])
            # data_writeracc.append(acc)
            evaldata_writerloss.append(avg_loss.numpy()[0])

# 查看测试集准确率及loss
clear()
plt.figure()
plt.title("train",fontsize=24)
plt.xlabel('x',fontsize=14)
plt.ylabel("acc/loss",fontsize=14)
plt.plot(data_writer_x,data_writeracc,color='red',label='train_acc',marker='+')
plt.plot(data_writer_x,data_writerloss,color='green',label='train_loss',marker='*')
plt.plot(data_writer_x,evaldata_writeracc,color='blue',label='eval_acc',marker='+')
plt.plot(data_writer_x,evaldata_writerloss,color='purple',label='eval_loss',marker='*')

plt.legend(['tain_acc','train_loss','eval_acc','eval_loss'],loc=1)
plt.grid()# 生成网格
plt.show()
0
#838w305158509回复于2020-01-09 17:00:53

作业8:

sigmoid:

ReLU:

通过对比可以看出使用relu激活函数有更快的训练速度,和更高的精度。分析如下:

1.采用sigmoid函数(指数运算),计算量大,而采用Relu激活函数,整个过程的计算量节省很多。(AlexNet论文里说大概比sigmoid快6倍。)
2,对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,从而无法完成深层网络的训练。
3,Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。
4.Relu也有缺陷:当Relu输出为0后,梯度没发反向传递,这个Relu就死掉了,就是说在反向传播的过程中很快让一些神经元的导数永远为0,这些神经元被永久遗弃了;为了不让Relu武断的置零,给了很小的系数,这种LeakyRelu作为激活函数的方法解决此了问题。

0
#837七海鬼武回复于2020-01-09 16:56:11

作业8:

激活函数为sigmod时损失无法收敛

start training ... epoch: 0, batch_id: 0, loss is: [0.70030516] epoch: 0, batch_id: 10, loss is: [0.69729173] epoch: 0, batch_id: 20, loss is: [0.6988058] epoch: 0, batch_id: 30, loss is: [0.699013]

激活函数为relu时损失可以收敛

start training ... epoch: 0, batch_id: 0, loss is: [0.63210124] epoch: 0, batch_id: 10, loss is: [0.74558866] epoch: 0, batch_id: 20, loss is: [0.35315874] epoch: 0, batch_id: 30, loss is: [0.23432064] [validation] accuracy/loss: 0.9149999618530273/0.2930580973625183

分析:由于其他训练条件相同,只有激活函数不同,所以可以认为造成上述结果的原因就是使用了不同的激活函数。    

 

0
#836aaaLKgo回复于2020-01-09 16:53:37

作业5-1:

 

作业5-2:

在计算机视觉中,主要有四大基本任务,分别是图像分类、物体定位、物体检测、图像分割,其他任务都是这四类任务的拓展,其中图像分类、检测、分割中的卷积神经网络算法较多,这里主要简单介绍一下这三类任务所涉及的网络的主要的特点。

一、图像分类:

图像分类主要是一个多分类任务,目标就是将图像中的各个类别给区分开。这类任务是最最基础的任务,因此相关的卷积网络架构最多,这里主要介绍最有代表性的十个个左右。

1. LeNet-5

CNN的开山鼻祖,由LeCun设计,创造了卷积层和池化层,虽然现在看来是最普通的卷积神经网络,但是它的出现是具有划时代意义的。
2. AlexNet

真正带领CNN走向神坛的卷积神经网络,获得了2012年ImageNet大赛的冠军。其结构与LeNet-5相似,但参数更多、网络更深,同时第一次利用GPU加速了网络计算。主要特点包括:ReLU激活函数确保没有梯度消失的情况、dropout随机失活、Image Augmentation数据增广增加了更多数据样例、使用更深更大的卷积网络。
3. VGG-16 / VGG-19

2014年ImageNet大赛的亚军网络。其结构相当简单,只是大量3x3卷积和2x2池化的大量堆积,以此代替5x5卷积,在相同计算量的前提下,节省了大量参数。另外,网络还使用了超大的全连接层,有利于最后的分类,不过也带来了巨量的参数。除此之外,VGG的训练离不开合适的网络初始化和批归一化BN。
4. GoogLeNet

2014年ImageNet大赛的冠军网络。来自于Google,他们提出了Inception结构,同时用1×1、3×3、5×5卷积和3×3池化进行多分支处理,并级联结果。另外,为了降低计算量,还用了1×1卷积降维。GoogLeNet使用了全局平均汇合替代全连接层,使网络参数大幅减少。
5. Inception V3 / V4

在GoogLeNet的基础上进一步降低参数。其和GoogLeNet有相似的Inception模块,但将7×7和5×5卷积分解成若干等效3×3卷积,并在网络中后部分把3×3卷积分解为1×3和3×1卷积。这使得在相似的网络参数下网络可以部署到42层。此外,Inception v3使用了批量归一层。Inception v3是GoogLeNet计算量的2.5倍,而错误率较后者下降了3%。Inception v4在Inception模块基础上结合了残差模块,进一步降低了0.4%的错误率。
6. ResNet

2015年的ImageNet大赛的冠军网络。ResNet旨在解决网络加深后训练难度增大的现象。其提出了residual模块,包含两个3×3卷积和一个短路连接。短路连接可以有效缓解反向传播时由于深度过深导致的梯度消失现象,这使得网络加深之后性能不会变差。短路连接是深度学习又一重要思想,除计算机视觉外,短路连接也被用到了机器翻译、语音识别/合成领域。此外,具有短路连接的ResNet可以看作是许多不同深度而共享参数的网络的集成,网络数目随层数指数增加。ResNet的关键点是:(1). 使用短路连接,使训练深层网络更容易,并且重复堆叠相同的模块组合。(2). ResNet大量使用了批量归一层。(3). 对于很深的网络(超过50层),ResNet使用了更高效的瓶颈(bottleneck)结构。ResNet在ImageNet上取得了超过人的准确率。
7. ResNeXt

ResNet的另一改进。传统的方法通常是靠加深或加宽网络来提升性能,但计算开销也会随之增加。ResNeXt旨在不改变模型复杂度的情况下提升性能。受精简而高效的Inception模块启发,ResNeXt将ResNet中非短路那一分支变为多个分支。和Inception不同的是,每个分支的结构都相同。ResNeXt的关键点是:(1). 沿用ResNet的短路连接,并且重复堆叠相同的模块组合。(2). 多分支分别处理。(3). 使用1×1卷积降低计算量。其综合了ResNet和Inception的优点。此外,ResNeXt巧妙地利用分组卷积进行实现。ResNeXt发现,增加分支数是比加深或加宽更有效地提升网络性能的方式。ResNeXt的命名旨在说明这是下一代(next)的ResNet。
8. DenseNet

DenseNet 其目的也是避免梯度消失。和residual模块不同,dense模块中任意两层之间均有短路连接。也就是说,每一层的输入通过级联(concatenation)包含了之前所有层的结果,即包含由低到高所有层次的特征。和之前方法不同的是,DenseNet中卷积层的滤波器数很少。DenseNet只用ResNet一半的参数即可达到ResNet的性能。实现方面,作者在大会报告指出,直接将输出级联会占用很大GPU存储。后来,通过共享存储,可以在相同的GPU存储资源下训练更深的DenseNet。但由于有些中间结果需要重复计算,该实现会增加训练时间。
9. SENet

2017年ImageNet的冠军网络。SENet通过额外的分支(gap-fc-fc-sigm)来得到每个通道的[0, 1]权重,自适应地校正原各通道激活值响应。以提升有用的通道响应并抑制对当前任务用处不大的通道响应。


二、物体检测:

物体检测是比图像分类更艰巨的任务,它除了需要分别图像中不同物体的类别,同时还需要给出该物体在图像中的具体位置,而且图像中的类别和数量都不固定。在物体检测中,根据候选框的提出方法主要分为两个流派的算法,分别是两刀流算法和一刀流算法。

(一)两刀流

两刀流目标检测算法,又称为基于候选框的目标检测算法,其基本思想是使用不同大小的窗口在图像上滑动,在每个区域,对窗口内的区域进行目标定位。即将每个窗口内的区域前馈网络,其分类分支用于判断该区域的类别,回归分支用于输出包围盒。其代表算法主要有以下三种:

1. RCNN

利用深度学习进行目标检测的鼻祖,其方法是先利用一些非深度学习的类别无关的无监督方法,在图像中找到一些可能包含目标的候选区域。之后,对每个候选区域前馈网络,进行目标定位,即两分支(分类+回归)输出。其中,我们仍然需要回归分支的原因是,候选区域只是对包含目标区域的一个粗略的估计,我们需要有监督地利用回归分支得到更精确的包围盒预测结果。
2. Fast-RCNN

R-CNN的弊端是需要多次前馈网络,这使得R-CNN的运行效率不高,预测一张图像需要47秒。Fast R-CNN同样基于候选区域进行目标检测,但受SPPNet启发,在Fast R-CNN中,不同候选区域的卷积特征提取部分是共享的。也就是说,我们先将整副图像前馈网络,并提取conv5卷积特征。之后,基于在原始图像上运行候选区域生成算法的结果在卷积特征上进行采样,这一步称为兴趣区域汇合。最后,对每个候选区域,进行目标定位,即两分支(分类+回归)输出。Fast-RCNN的最大贡献在于提出了RoI pooling
3. Faster-RCNN

Fast R-CNN测试时每张图像前馈网络只需0.2秒,但瓶颈在于提取候选区域需要2秒。Faster R-CNN不再使用现有的无监督候选区域生成算法,而利用候选区域网络从conv5特征中产生候选区域,并且将候选区域网络集成到整个网络中端到端训练。Faster R-CNN的测试时间是0.2秒,接近实时。后来有研究发现,通过使用更少的候选区域,可以在性能损失不大的条件下进一步提速。Faster-RCNN最大的贡献在于提出了RPN网络,以及anchor box的概念。
(二)一刀流

一刀流目标检测算法,又称为基于直接回归的目标检测算法,其基本思想在于基于候选区域的方法由于有两步操作,虽然检测性能比较好,但速度上离实时仍有一些差距。基于直接回归的方法不需要候选区域,直接输出分类/回归结果。这类方法由于图像只需前馈网络一次,速度通常更快,可以达到实时。

1. YOLO v1 / v2 / v3

将图像划分成7×7的网格,其中图像中的真实目标被其划分到目标中心所在的网格及其最接近的锚盒。对每个网格区域,网络需要预测:每个锚盒包含目标的概率(不包含目标时应为0,否则为锚盒和真实包围盒的IoU)、每个锚盒的4个坐标、该网格的类别概率分布。每个锚盒的类别概率分布等于每个锚盒包含目标的概率乘以该网格的类别概率分布。
2. SSD

相比YOLO,SSD在卷积特征后加了若干卷积层以减小特征空间大小,并通过综合多层卷积层的检测结果以检测不同大小的目标。此外,类似于Faster R-CNN的RPN,SSD使用3×3卷积取代了YOLO中的全连接层,以对不同大小和长宽比的锚盒来进行分类/回归。SSD取得了比YOLO更快,接近Faster R-CNN的检测性能。
3. RetinaNet

RetinaNet认为,基于直接回归的方法性能通常不如基于候选区域方法的原因是,前者会面临极端的类别不平衡现象。基于候选区域的方法可以通过候选区域过滤掉大部分的背景区域,但基于直接回归的方法需要直接面对类别不平衡。因此,RetinaNet通过改进经典的交叉熵损失以降低对已经分的很好的样例的损失值,提出了焦点(focal)损失函数,以使模型训练时更加关注到困难的样例上。RetinaNet取得了接近基于直接回归方法的速度,和超过基于候选区域的方法的性能。
三、图像分割:

图像分割在目标检测的任务上更进一步,除了检测物体的类别外,还需要检测出图中哪个像素点是属于物体的。

1. Mask-RCNN

用FPN进行目标检测,并通过添加额外分支进行语义分割(额外分割分支和原检测分支不共享参数),即Mask R-CNN有三个输出分支(分类、坐标回归、和分割)。此外,Mask R-CNN的其他改进有:(1). 改进了RoI汇合,通过双线性差值使候选区域和卷积特征的对齐不因量化而损失信息。(2). 在分割时,Mask R-CNN将判断类别和输出模板(mask)这两个任务解耦合,用sigmoid配合对率(logistic)损失函数对每个类别的模板单独处理,取得了比经典分割方法用softmax让所有类别一起竞争更好的效果。
2. DeepLab v1 /v2 /v3

谷歌出品,必属精品。主要贡献在于,其一,用上采样滤波器进行卷积,或“多孔卷积”,是稠密预测任务中的强有力的工具;其二,提出了多孔空间金字塔池化(ASPP),可以在多尺度上鲁棒地分割物体;其三,合并深度卷积网络和概率图模型方法,增强对物体边界的定位。

 

作业5-3:

手写数字识别,优化算法对比:

综上,在学习率0.1,0.01,0.001各算法的效果如上。综合来看Adam下降最快,并且最稳定。

0
#835Casla711回复于2020-01-09 16:35:35

作业4-2:

共同点:整个代码的基本思路是一致的,大的模块功能都差不多

不同点:用飞桨框架写直接调用轮子就可以了,更加快捷,简便,高效,训练耗时更低

0
#834涛声荡漾回复于2020-01-09 16:33:04

作业5-1:

# 加载相关库
import os
import random
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, FC
import numpy as np
from PIL import Image

import gzip
import json


# 定义数据集读取器
def load_data(mode='train'):

    # 读取数据文件
    datafile = './work/mnist.json.gz'
    print('loading mnist dataset from {} ......'.format(datafile))
    data = json.load(gzip.open(datafile))
    # 读取数据集中的训练集,验证集和测试集
    train_set, val_set, eval_set = data

    # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS
    IMG_ROWS = 28
    IMG_COLS = 28
    # 根据输入mode参数决定使用训练集,验证集还是测试
    if mode == 'train':
        imgs = train_set[0]
        labels = train_set[1]
    elif mode == 'valid':
        imgs = val_set[0]
        labels = val_set[1]
    elif mode == 'eval':
        imgs = eval_set[0]
        labels = eval_set[1]
    # 获得所有图像的数量
    imgs_length = len(imgs)
    # 验证图像数量和标签数量是否一致
    assert len(imgs) == len(labels), \
          "length of train_imgs({}) should be the same as train_labels({})".format(
                  len(imgs), len(labels))

    index_list = list(range(imgs_length))

    # 读入数据时用到的batchsize
    BATCHSIZE = 100

    # 定义数据生成器
    def data_generator():
        # 训练模式下,打乱训练数据
        if mode == 'train':
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        # 按照索引读取数据
        for i in index_list:
            # 读取图像和标签,转换其尺寸和类型
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('int64')
            imgs_list.append(img) 
            labels_list.append(label)
            # 如果当前数据缓存达到了batch size,就返回一个批次数据
            if len(imgs_list) == BATCHSIZE:
                yield np.array(imgs_list), np.array(labels_list)
                # 清空数据缓存列表
                imgs_list = []
                labels_list = []

        # 如果剩余数据的数目小于BATCHSIZE,
        # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)

    return data_generator

# 定义模型结构
class MNIST(fluid.dygraph.Layer):
     def __init__(self, name_scope):
         super(MNIST, self).__init__(name_scope)
         name_scope = self.full_name()
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv1 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool1 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv2 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool2 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义全连接层,输出节点数为10,激活函数使用softmax
         self.fc = FC(name_scope, size=10, act='softmax')
         
    # 定义网络的前向计算过程
     def forward(self, inputs):
         x = self.conv1(inputs)
         x = self.pool1(x)
         x = self.conv2(x)
         x = self.pool2(x)
         x = self.fc(x)
         return x

#优化算法的学习率设置有所差别,进行训练得到模型参数
with fluid.dygraph.guard():
    model = MNIST("mnist")
    model.train()
    #调用加载数据的函数
    train_loader = load_data('train')
    
    #设置不同初始学习率
    optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01)
    #optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.001)
    #optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.1)
    #optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=0.01)
    #optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.01)
    #optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.01)
    
    EPOCH_NUM = 5
    for epoch_id in range(EPOCH_NUM):
        for batch_id, data in enumerate(train_loader()):
            #准备数据,变得更加简洁
            image_data, label_data = data
            image = fluid.dygraph.to_variable(image_data)
            label = fluid.dygraph.to_variable(label_data)
            
            #前向计算的过程
            predict = model(image)
            
            #计算损失,取一个批次样本损失的平均值
            loss = fluid.layers.cross_entropy(predict, label)
            avg_loss = fluid.layers.mean(loss)
            
            #每训练了100批次的数据,打印下当前Loss的情况
            if batch_id % 100 == 0:
                print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
            
            #后向传播,更新参数的过程
            avg_loss.backward()
            optimizer.minimize(avg_loss)
            model.clear_gradients()

    #保存模型参数
    fluid.save_dygraph(model.state_dict(), 'mnist')

#进行100张随机图片的测试
with fluid.dygraph.guard():
    print('start evaluation......')
    datafile = './work/mnist.json.gz'
    print('loading mnist dataset from {}......'.format(datafile))
    data = json.load(gzip.open(datafile))
    _,_,eval_set = data ###_,_=这个占用内存么?
    #随机抽取100张图片
    num_img = 100
    test_imgs = eval_set[0]
    test_labs = eval_set[1]
    index = list(range(len(test_imgs)))
    random.shuffle(index)
    imgs_list = []
    labels_list = []
    for i in range(num_img):
        img = np.reshape(test_imgs[index[i]],[1,28,28]).astype('float32')
        label = np.array(test_labs[index[i]]).astype('int64')
        imgs_list.append(img)
        labels_list.append(label)
    test_img = np.array(imgs_list)
    test_lab = np.array(labels_list)
    print('There are {} eval images in total.'.format(test_img.shape[0]))
    
    #加载模型
    model = MNIST('mnist')
    model_state_dict,_ = fluid.load_dygraph('mnist')
    model.load_dict(model_state_dict)
    model.eval()
    
    #预测图片
    print(test_img.shape,type(test_img),'a')
    test_img = fluid.dygraph.to_variable(test_img) #转化为paddle数据
    print(test_img.shape,type(test_img),'b')
    results = model(test_img)
    print(results.shape)
    results_num = np.argmax(results.numpy(),axis=1) #获取概率最大值
    correct_cls = (results_num == test_lab)
    acc = np.sum(correct_cls)/num_img
    
    print('{}张测试图片测试的准确率是:{}%'.format(num_img,acc*100))

结果如下所示:

loading mnist dataset from ./work/mnist.json.gz ......
epoch: 0, batch: 0, loss is: [2.5407598]
epoch: 0, batch: 100, loss is: [0.64208215]
epoch: 0, batch: 200, loss is: [0.44292954]
epoch: 0, batch: 300, loss is: [0.3241967]
epoch: 0, batch: 400, loss is: [0.27491534]
start evaluation......
loading mnist dataset from ./work/mnist.json.gz......
There are 100 eval images in total.
(100, 1, 28, 28)  a
[100, 1, 28, 28]  b
[100, 10]
100张测试图片测试的准确率是:95.0%


作业5-2 计算机视觉常见卷积网络:
LeNet、Alexnet、GoogleNet、VGG、ResNext、ShuffleNet、MobileNet
作业5-3:
①通过loss判断优化算法:adam效果最好,代码与结果如下:

# 加载相关库
import os
import random
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, FC
import numpy as np
from PIL import Image

import gzip
import json

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


# 定义数据集读取器
def load_data(mode='train'):

    # 读取数据文件
    datafile = './work/mnist.json.gz'
    print('loading mnist dataset from {} ......'.format(datafile))
    data = json.load(gzip.open(datafile))
    # 读取数据集中的训练集,验证集和测试集
    train_set, val_set, eval_set = data

    # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS
    IMG_ROWS = 28
    IMG_COLS = 28
    # 根据输入mode参数决定使用训练集,验证集还是测试
    if mode == 'train':
        imgs = train_set[0]
        labels = train_set[1]
    elif mode == 'valid':
        imgs = val_set[0]
        labels = val_set[1]
    elif mode == 'eval':
        imgs = eval_set[0]
        labels = eval_set[1]
    # 获得所有图像的数量
    imgs_length = len(imgs)
    # 验证图像数量和标签数量是否一致
    assert len(imgs) == len(labels), \
          "length of train_imgs({}) should be the same as train_labels({})".format(
                  len(imgs), len(labels))

    index_list = list(range(imgs_length))

    # 读入数据时用到的batchsize
    BATCHSIZE = 100

    # 定义数据生成器
    def data_generator():
        # 训练模式下,打乱训练数据
        if mode == 'train':
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        # 按照索引读取数据
        for i in index_list:
            # 读取图像和标签,转换其尺寸和类型
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('int64')
            imgs_list.append(img) 
            labels_list.append(label)
            # 如果当前数据缓存达到了batch size,就返回一个批次数据
            if len(imgs_list) == BATCHSIZE:
                yield np.array(imgs_list), np.array(labels_list)
                # 清空数据缓存列表
                imgs_list = []
                labels_list = []

        # 如果剩余数据的数目小于BATCHSIZE,
        # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)

    return data_generator

# 定义模型结构
class MNIST(fluid.dygraph.Layer):
     def __init__(self, name_scope):
         super(MNIST, self).__init__(name_scope)
         name_scope = self.full_name()
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv1 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool1 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv2 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool2 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义全连接层,输出节点数为10,激活函数使用softmax
         self.fc = FC(name_scope, size=10, act='softmax')
         
    # 定义网络的前向计算过程
     def forward(self, inputs):
         x = self.conv1(inputs)
         x = self.pool1(x)
         x = self.conv2(x)
         x = self.pool2(x)
         x = self.fc(x)
         return x

fileName = ['SGD', 'Momentum', 'Adagrad', 'Adam']
lr = 0.001
def train( option, epoch_num):
    with fluid.dygraph.guard():
        model = MNIST("mnist")
        model.train()
        #调用加载数据的函数
        train_loader = load_data('train')
        
        #设置不同初始学习率
        if option == fileName[0]:
            optimizer = fluid.optimizer.SGDOptimizer(learning_rate=lr)
        elif option == fileName[1]:
            optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=lr, momentum=0.9)
        elif option == fileName[2]:
            optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=lr)
        elif option == fileName[3]:
            optimizer = fluid.optimizer.AdamOptimizer(learning_rate=lr)
        
        avgLostArr=[]
        EPOCH_NUM = epoch_num
        for epoch_id in range(EPOCH_NUM):
            for batch_id, data in enumerate(train_loader()):
                #准备数据,变得更加简洁
                image_data, label_data = data
                image = fluid.dygraph.to_variable(image_data)
                label = fluid.dygraph.to_variable(label_data)
                
                #前向计算的过程
                predict = model(image)
                
                #计算损失,取一个批次样本损失的平均值
                loss = fluid.layers.cross_entropy(predict, label)
                avg_loss = fluid.layers.mean(loss)
                avgLostArr.append(avg_loss.numpy()[0])
                
                #每训练了100批次的数据,打印下当前Loss的情况
                if batch_id % 100 == 0:
                    print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
                
                #后向传播,更新参数的过程
                avg_loss.backward()
                optimizer.minimize(avg_loss)
                model.clear_gradients()
    
        #保存模型参数
        fluid.save_dygraph(model.state_dict(), 'mnist')
        
        optimizerName = option+'_lr_'+str(lr)
        np.save('./'+optimizerName,np.array(avgLostArr))

for i in range(4):
    train(fileName[i],5)
color = ['red','orange','blue','green']

def showPic():
    learning_rate = str(lr)
    plt.figure(figsize=(12,8),dpi=80)
    for i in range(len(fileName)):
        loss = np.load(fileName[i]+'_lr_'+learning_rate+'.npy')
        loss = loss[:200]
        plt.plot(range(len(loss)),loss,label=fileName[i]+'_lr_'+learning_rate,color=color[i])
    plt.legend(loc='upper right')
    plt.xlabel('Iteration(learning rate = {})'.format(learning_rate))
    plt.ylabel('Loss')
    plt.show()
showPic()

结果如下图所示:

②通过loss下降趋势判断最佳学习率:0.01

# 加载相关库
import os
import random
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, FC
import numpy as np
from PIL import Image

import gzip
import json

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


# 定义数据集读取器
def load_data(mode='train'):

    # 读取数据文件
    datafile = './work/mnist.json.gz'
    print('loading mnist dataset from {} ......'.format(datafile))
    data = json.load(gzip.open(datafile))
    # 读取数据集中的训练集,验证集和测试集
    train_set, val_set, eval_set = data

    # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS
    IMG_ROWS = 28
    IMG_COLS = 28
    # 根据输入mode参数决定使用训练集,验证集还是测试
    if mode == 'train':
        imgs = train_set[0]
        labels = train_set[1]
    elif mode == 'valid':
        imgs = val_set[0]
        labels = val_set[1]
    elif mode == 'eval':
        imgs = eval_set[0]
        labels = eval_set[1]
    # 获得所有图像的数量
    imgs_length = len(imgs)
    # 验证图像数量和标签数量是否一致
    assert len(imgs) == len(labels), \
          "length of train_imgs({}) should be the same as train_labels({})".format(
                  len(imgs), len(labels))

    index_list = list(range(imgs_length))

    # 读入数据时用到的batchsize
    BATCHSIZE = 100

    # 定义数据生成器
    def data_generator():
        # 训练模式下,打乱训练数据
        if mode == 'train':
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        # 按照索引读取数据
        for i in index_list:
            # 读取图像和标签,转换其尺寸和类型
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('int64')
            imgs_list.append(img) 
            labels_list.append(label)
            # 如果当前数据缓存达到了batch size,就返回一个批次数据
            if len(imgs_list) == BATCHSIZE:
                yield np.array(imgs_list), np.array(labels_list)
                # 清空数据缓存列表
                imgs_list = []
                labels_list = []

        # 如果剩余数据的数目小于BATCHSIZE,
        # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)

    return data_generator

# 定义模型结构
class MNIST(fluid.dygraph.Layer):
     def __init__(self, name_scope):
         super(MNIST, self).__init__(name_scope)
         name_scope = self.full_name()
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv1 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool1 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv2 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核为2,采用最大池化方式
         self.pool2 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type='max')
         # 定义全连接层,输出节点数为10,激活函数使用softmax
         self.fc = FC(name_scope, size=10, act='softmax')
         
    # 定义网络的前向计算过程
     def forward(self, inputs):
         x = self.conv1(inputs)
         x = self.pool1(x)
         x = self.conv2(x)
         x = self.pool2(x)
         x = self.fc(x)
         return x


lr = [0.0001,0.001,0.01,0.1]
def train( learning_rate, epoch_num):
    with fluid.dygraph.guard():
        model = MNIST("mnist")
        model.train()
        #调用加载数据的函数
        train_loader = load_data('train')
        
        #设置不同初始学习率
        optimizer = fluid.optimizer.AdamOptimizer(learning_rate=learning_rate)
        
        avgLostArr=[]
        EPOCH_NUM = epoch_num
        for epoch_id in range(EPOCH_NUM):
            for batch_id, data in enumerate(train_loader()):
                #准备数据,变得更加简洁
                image_data, label_data = data
                image = fluid.dygraph.to_variable(image_data)
                label = fluid.dygraph.to_variable(label_data)
                
                #前向计算的过程
                predict = model(image)
                
                #计算损失,取一个批次样本损失的平均值
                loss = fluid.layers.cross_entropy(predict, label)
                avg_loss = fluid.layers.mean(loss)
                avgLostArr.append(avg_loss.numpy()[0])
                
                #每训练了100批次的数据,打印下当前Loss的情况
                if batch_id % 100 == 0:
                    print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
                
                #后向传播,更新参数的过程
                avg_loss.backward()
                optimizer.minimize(avg_loss)
                model.clear_gradients()
    
        #保存模型参数
        fluid.save_dygraph(model.state_dict(), 'mnist')
        
        optimizerName = 'Adam_lr_'+str(learning_rate)
        np.save('./'+optimizerName,np.array(avgLostArr))

for i in range(4):
    train(lr[i],5)
color = ['red','orange','blue','green']

def showPic():
    #learning_rate = str(lr[i])
    plt.figure(figsize=(12,8),dpi=80)
    for i in range(len(lr)):
        loss = np.load('Adam_lr_'+str(lr[i])+'.npy')
        loss = loss[10:210]
        plt.plot(range(len(loss)),loss,label='Adam_lr_'+str(lr[i]),color=color[i])
    plt.legend(loc='upper right')
    plt.xlabel('Iteration')
    plt.ylabel('Loss')
    plt.show()
showPic()


结果如下图所示:

0
TOP
切换版块