层和块

python list是有序的,感觉还是改成list之后,print net 会出问题

1 Like

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)
8 Likes

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)

2 Likes

是的!应该是range(k + 1),非常感谢您的指正! :blush:

net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
net2 = MySequential2(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
结果不一样的原因应该是线性层的权值不同,网络结构相同,但是每层的参数不同

1 Like

有一个问题,
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 的别名

我初次读完这节也感觉少了点东西。查看了网页版的原文,在mxnet里还有一小节,其他版本里没有。

2 Likes

不是这个原因,是print(net)时出问题,在print的重构函数里,是以dict操作的

你好。试了下,如你所说如果是list存储,print(net)不显示内部modules(为空);但是原理是什么,print是针对nn.Module重构吗?

没错。离谱的是最新版把module改为了“_module”,还是少了个“s”。

第2题严谨点,forward似乎用for遍历返回_modules输出比较好,虽然不影响本题(只有net1和net2)。