python list是有序的,感觉还是改成list之后,print net 会出问题
Q1
class MySequential2(nn.Module):
"""顺序块"""
# 使用list
def __init__(self, *args):
super(MySequential2, self).__init__()
self.sequential = []
for module in args:
self.sequential.append(module)
def forward(self, X):
# OrderedDict保证了按照成员添加的顺序遍历它们
for module in self.sequential:
X = module(X)
return X
linear1 = nn.Linear(20, 256)
relu = nn.ReLU()
linear2 = nn.Linear(256, 10)
net = MySequential(linear1, relu, linear2)
net2 = MySequential2(linear1, relu, linear2)
# 结果一样
# print(net(X))
# print(net2(X))
# 使用_modules方便打印net的网络结构和参数,而list则无法做到
# print(net, '\n', net.state_dict())
# print(net2, '\n', net2.state_dict())
Q2
class MyBlock(nn.Module):
def __init__(self, block1, block2):
super(MyBlock, self).__init__()
self.block1 = block1
self.block2 = block2
def forward(self, X):
X = torch.cat((self.block1(X), self.block2(X)), 1)
return X
block = MyBlock(nn.Linear(20, 5), nn.Linear(20, 5))
net = nn.Sequential(block, nn.ReLU(), nn.Linear(10, 5))
print(net(X).shape)
Q3
class Factory(nn.Module):
def __init__(self, block, ins, outs, k):
super().__init__()
self.dims = []
self.dims.append(ins)
for i in range(k):
self.dims.append(8 * pow(2, i + 1))
self.dims.append(outs)
for idx in range(k):
self._modules[str(idx)] = block(self.dims[idx], self.dims[idx + 1])
def forward(self, X):
for block in self._modules.values():
X = block(X)
return X
net = Factory(nn.Linear, 20, 10, 3)
print(net)
5.1.4 效率这一章就仅是提一下“在深度学习环境中,我们担⼼
速度极快的GPU可能要等到CPU运⾏Python代码后才能运⾏另⼀个作业”吗。。。之后有什么好的建议吗?因为我最近就是遇到这个CPU限制GPU性能的问题
可是换成list之后并没有报错-------
我跟着代码运行并查看了输出:
Factory
中的
for idx in range(k):
self._modules[str(idx)] = block(self.dims[idx], self.dims[idx + 1])
需要修改为
for idx in range(k+1):
self._modules[str(idx)] = block(self.dims[idx], self.dims[idx + 1])
这样输出的net层才包含了输出的维度(outs)
是的!应该是range(k + 1)
,非常感谢您的指正!
net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
net2 = MySequential2(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
结果不一样的原因应该是线性层的权值不同,网络结构相同,但是每层的参数不同
有一个问题,
class MYS(nn.Module):
def init(self, *args):
super().init()
for idx,module in enumerate(args):
self._modules[str(idx)]=module
def forward(self, x):
for b in self._modules.values():
x=b(x)
return x
在自定义顺序块这段代码中,按理说self._modules只在MYS类里面调用,所以写成self.__modules也是可以的,但是为什么写成后面这一种报错了,错误类型是’MYS’ object has no attribute ‘_MYS__modules’
怎么我的torch里没有concat这个方法
def Factory(Linear,inputs,outputs):
# 确保尺寸相同
can = torch.cat((inputs,outputs))
list = []
size=inputs.size()
for i,_ in enumerate(torch.arange(size[1])):#一定要注意这里啊啊啊啊啊啊啊啊
#i单独一个会返回value
list.append(Linear(int(can[0,i]),int(can[1,i])))
return list
class Linear(nn.Module):
def init(self, input1, output1):
super().init()
self.Linear = nn.Linear(input1, output1)
def forward(self, X):
return self.Linear(X)
这个第三题不是说写函数吗,大家是怎么想到直接写一个类的?
因为_module是字典,字典的键是字符串,索引的时候也是用键来索引,要有getitem的话,就用list来储存module吧,就是你说的用idx
没看懂,只在类里面调用,为什么就可以加两个下划线,人家_module在基类里就是这么命名的,多加一个下划线为啥还能用
test1 _Module改成list
class MySequential(nn.Module):
def __init__(self, *args):
super().__init__()
for idx, module in enumerate(args):
# 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员
# 变量_modules中。_module的类型是OrderedDict
self._modules[str(idx)] = module
def forward(self, X):
# OrderedDict保证了按照成员添加的顺序遍历它们
for block in self._modules.values():
X = block(X)
return X
class MySequential2(nn.Module):
def __init__(self, *args):
super().__init__()
self.seq = []
for i in args:
self.seq.append(i)
def forward(self, X):
# OrderedDict保证了按照成员添加的顺序遍历它们
for idx in range(len(self.seq)):
X = self.seq[idx](X)
return X
X = torch.rand(2,20)
net1 = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
net2 = MySequential2(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
print(net1(X).shape)
print(net2(X).shape)
torch.Size([2, 10]) torch.Size([2, 10])
结果 形状是一致的,感觉没什么问题
test2 形成类似 Lenet5 当中的平行块
net1 =nn.Sequential(nn.Linear(256,20))
net2 =nn.Sequential(nn.Linear(256,10))
class Test2(nn.Module):
def __init__(self):
super().__init__()
self.block1= net1
self.block2= net2
def forward(self,X):
return torch.cat([self.block1(X),self.block2(X)],1)
X = torch.rand(2,256)
test2 = Test2()
print(test2(X).shape)
torch.Size([2, 30])
两个网络输出拼在一起
test3 参考 ResNet, 就是多个同样的块实例拼接
emmm,我也不知道我这个到底有没有不一样跟_modules自带的有序字典,有佬能给我讲讲吗:
class MySequential(nn.Module): # 定义一个名为MySequential的类,继承自nn.Module
def __init__(self, *args): # 定义初始化函数,接受可变数量的参数
super().__init__() # 调用父类的初始化方法
self.ls = []
for module in enumerate(args): # 遍历传入的参数,args是一个包含了所有参数的元组
# 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员
# 变量_modules中。_modules的类型是OrderedDict
self.ls.append(module) # 将每个传入的module按顺序添加到_modules中
def forward(self, X): # 定义前向传播函数,接受输入X
for block in self.ls: # 遍历保存的各个module
X = block(X) # 将输入X通过每个module执行前向传播操作
return X # 返回最终的输出
我个人感觉效果是一样的哒
torch.concat 是 torch.cat 的别名
不是这个原因,是print(net)时出问题,在print的重构函数里,是以dict操作的
你好。试了下,如你所说如果是list存储,print(net)不显示内部modules(为空);但是原理是什么,print是针对nn.Module重构吗?
没错。离谱的是最新版把module改为了“_module”,还是少了个“s”。
第2题严谨点,forward似乎用for遍历返回_modules输出比较好,虽然不影响本题(只有net1和net2)。