《第四章》
4.1模型构造
# Multilayer perceptrons,多层感知机
class MLP(nn.Block):
# 声明带有模型参数的层,这里声明了两个全连接层
def __init__(self, **kwargs):
# 调用MLP父类Block的构造函数来进行必要的初始化。这样在构造实例时还可以指定其他函数
# 参数,如“模型参数的访问、初始化和共享”一节将介绍的模型参数params
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Dense(256, activation='relu') # 隐藏层
self.output = nn.Dense(10) # 输出层
# 定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出
# MLP类中无须定义反向传播函数。系统将通过自动求梯度而自动生成反向传播所需的backward函数。
def forward(self, x):
return self.output(self.hidden(x))
X = nd.random.uniform(shape=(2, 20))
net = MLP()
net.initialize()
net(X)模型构造-->实例化-->初始化-->前向计算
系统将通过自动求梯度而自动生成反向传播所需的
backward函数。Sequential类继承自Block类,成员变量_children里,其类型是OrderedDict。当MySequential实例调用initialize函数时,系统会自动对_children里所有成员初始化.
self.params.get_constant创建的随机权重参数不会在训练中被迭代.
都是block的子类的实例,可以在net.add()中嵌套使用。
练习
如果不在
MLP类的__init__函数里调用父类的__init__函数,会出现什么样的错误信息? 答:'NestMLP' object has no attribute '_children';成员变量_children里,其类型是OrderedDict。当MySequential实例调用如果去掉
FancyMLP类里面的asscalar函数,会有什么问题?答:会将1和0.8广播成和X相同的向量来比较,如果是只有一个的一维数据还好,其他的话会产生错误判断。
如果将
NestMLP类中通过Sequential实例定义的self.net改为self.net = [nn.Dense(64, activation='relu'), nn.Dense(32, activation='relu')],会有什么问题?答:定义失败,Changing attribute type for net from <class 'mxnet.gluon.nn.basic_layers.Sequential'> to <class 'list'>is not allowed.
4.2模型参数的访问、初始化和共享
访问多层感知机net中隐藏层的所有参数。索引0表示隐藏层为Sequential实例最先添加的层。每次新建的dense不会被自动删掉,所以执行多次的话,dense0_会依次递增。
MXNet的init模块里提供了多种预设的初始化方法。也可以用自定义的方法初始化
可以通过设置params来共享初始化参数或自定义。
练习
查阅有关
init模块的MXNet文档,了解不同的参数初始化方法。答:https://mxnet.apache.org/api/python/docs/api/initializer/index.html
有上采样、常量、描述符、混合方法、正态、均值、一值、零值、Xavier(特殊均值)等多种初始化方法。
尝试在
net.initialize()后、net(X)前访问模型参数,观察模型参数的形状。答:模型参数形状如下。
构造一个含共享参数层的多层感知机并训练。在训练过程中,观察每一层的模型参数和梯度。
答:共享层的weight一致,grad会根据共享的次数累加。(未测试)
4.3延后初始化
当调用initialize时,因为不知道输入参数X的形状,所以后续结点的形状也不知。
只有当net(X)时,才真正初始化。
避免延后初始化的方法有两种:
练习
如果在下一次前向计算
net(X)前改变输入X的形状,包括批量大小和输入个数,会发生什么?答:改变形状(2,10):Shape inconsistent, Provided = [256,20], inferred shape=(256,10)
改变输入个数:Shape inconsistent;改变批量大小,不改变输入个数:无影响。
4.4自定义层
练习
自定义一个层,使用它做一次前向计算。
4.5读取与存储
练习
即使无须把训练好的模型部署到不同的设备,存储模型参数在实际中还有哪些好处?
答:1.通过外存来存储,减少内存的压力。2.方便其他训练模型的复用。3.方便导入到其他地方。
4.6GPU计算
所有nd有关的变量的初始化,记得加上ctx=mx.gpu()
net.initialize()时,记得加上ctx=mx.gpu()
cpu和gpu上的变量不能同时运算,不同gpu上的也不能运算,因为I/O耗费时间。
GPU的并行运算优于CPU
练习
试试大一点儿的计算任务,如大矩阵的乘法,看看使用CPU和GPU的速度区别。如果是计算量很小的任务呢?
答:大矩阵乘法gpu比cpu快,两个(3000,3000)矩阵相乘(ps:不要玩太嗨了,内存会爆满),如果是计算量很小的任务,两者差不多。
但是,如果只是计算的话,速度好像都很快,接近0s,如果加上print,才有显著的区别。gpu为0.04s;cpu为2s。猜测一:print需要输出,gpu输出比cpu快;(经过测试,输出速度一致)猜测二:只计算的时候,使用了异步并行计算的方法,使得时间计算接近于0.
GPU上应如何读写模型参数?
答:1.输入参数X记得ctx=mx.gpu();2.initialize记得ctx=mx.gpu();其他可以同正常那样操作。
最后更新于
这有帮助吗?