学习笔记2

零碎:

collections.OrderedDict 是 Python 标准库中的一种数据结构,有序的字典类(dictionary subclass),可以记住字典元素添加的顺序

pytorch

1. tensor的基本数据

目录:


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


(1)torch.tensor创建

可以接受各种数据类型作为输入,并返回一个新的张量

import torch
a = torch.FloatTensor(2,3)
b = torch.FloatTensor([2,3,4,5])
a,b

结果:

(tensor([[1.0561e-38, 1.0102e-38, 9.6429e-39],
         [8.4490e-39, 9.6429e-39, 9.1837e-39]]),
 tensor([2., 3., 4., 5.]))
torch.tensor()和torch.tensor([])区别
# 创建一个包含单个值的张量
tensor_a = torch.tensor(5)
print(tensor_a)

# 创建一个从列表中创建的张量
tensor_b = torch.tensor([1, 2, 3])
print(tensor_b)

import torch

# 创建一个空的张量
empty_tensor = torch.tensor([])
print(empty_tensor)

(2)torch.IntTensor整数型

用于生成数据类型为整型的Tensor

参数可以是列表,也可以是一个维度值

import torch
a = torch.IntTensor(2,3)
b = torch.IntTensor([2,3,4,5])
a,b
结果
(tensor([[0, 0, 0],
        [0, 0, 0]], dtype=torch.int32), tensor([2, 3, 4, 5], dtype=torch.int32))

(3)torch.randn随机数

  • 用于生成数据类型为浮点数且维度指定的随机Tensor
  • 和在numpy中使用的numpy.randn类似
  • 随机生成的浮点数的取值满足均值为0,方差为1的正态分布
import torch
a = torch.randn(2,3)
a
tensor([[-1.1486, -1.4540, -0.8042],
        [ 0.1975, -1.0651, -1.1379]])

(4)torch.range规定范围

生成数据类型为浮点型指定范围内的Tensor

参数有三个,起始值,结束值,步长

a = torch.range(1,20,2)
a
结果:
tensor([ 1.,  3.,  5.,  7.,  9., 11., 13., 15., 17., 19.])

(5)torch.zeros/ones/empty

  • torch.zeros :浮点型且维度指定,元素值全部为0。

  • torch.ones :生成全1的数组

  • torch.empty:创建一个未被初始化数值的tensor,tensor的大小是由size确定

    ​ 这里可以是一个list 也可以是一个tuple

import torch
a = torch.zeros(3,4)
tensor([[9.1837e-39, 4.6837e-39, 9.2755e-39],
        [1.0837e-38, 8.4490e-39, 9.2755e-39]])

2.tensor的计算


目录:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


(1)torch.abs绝对值

返回输入参数的绝对值作为输出

import torch
a = torch.randn(2,3)
print(a)
b = torch.abs(a)
print(b)
结果:
tensor([[ 0.8940, -0.1397,  0.2802],
        [ 2.1344,  1.3253, -0.8328]])
tensor([[0.8940, 0.1397, 0.2802],
        [2.1344, 1.3253, 0.8328]])

(2)torch.add求和

就是求和

import torch
a = torch.randn(2,3)
b = torch.randn(2,3)
print(a)
print(b)
c = torch.add(a,b)
print(c)
结果:
tensor([[ 0.1822,  0.3149, -1.3069],
        [ 1.4597,  0.8170, -0.3673]])
tensor([[-0.2853,  0.7806,  1.2908],
        [-0.0537,  0.7209, -1.0830]])
tensor([[-0.1031,  1.0956, -0.0161],
        [ 1.4060,  1.5380, -1.4503]])

再一个例子:对c与一个标量10相加

e = torch.add(c,10)
print(e)
结果:
tensor([[11.3519, 13.3578, 10.6071],
        [10.4409, 11.2167,  7.1050]])

(3)tensor.clamp上下限

参数:预处理张量 + 下限 + 上限

超过下限的值定为min

超过上线的值定为max

其余不改变

import torch
a = torch.randn(2,3)
b = torch.randn(2,3)
print(a)
b = torch.clamp(a,-0.2,0.2)
print(b)
结果:
tensor([[ 0.1204,  1.2552, -0.0253],
        [ 0.8156, -2.3537,  0.3768]])
tensor([[ 0.1204,  0.2000, -0.0253],
        [ 0.2000, -0.2000,  0.2000]])

(4)torch.div求商

就是求商

result_tensor = torch.div(input_tensor, other_tensor)


  • 张量相除
import torch
a = torch.randn(2,3)
b = torch.randn(2,3)
c = torch.div(a,b)
print(a)
print(b)
print(c)
结果:
tensor([[ 0.7099,  0.4389, -1.0387],
        [-0.2901, -0.6581,  0.7899]])
tensor([[-2.9549,  1.3680,  1.0147],
        [-2.0475,  1.0217, -1.3405]])
tensor([[-0.2402,  0.3208, -1.0236],
        [ 0.1417, -0.6441, -0.5893]])

  • 张量除以标量
d = torch.div(c,2)
print(c)
print(d)
结果:
tensor([[ 0.9959,  0.2897,  0.3066],
        [-0.4423,  0.6936,  1.5915]])
tensor([[ 0.4980,  0.1449,  0.1533],
        [-0.2211,  0.3468,  0.7958]])

(5)torch.pow幂次方

求幂结果

import torch
b = torch.randn(2,3)
c = torch.pow(b,2)
print(b)
print(c)
结果:
tensor([[-0.1403, -0.5332,  0.2666],
        [ 1.4707, -1.0248,  0.7824]])
tensor([[0.0197, 0.2843, 0.0711],
        [2.1629, 1.0502, 0.6122]])

(6)torch.mm矩阵相乘

要遵循矩阵相乘的规律

import torch
a = torch.randn(2,3)
b = torch.randn(3,4)
c = torch.mm(a,b)
print(c)

(7)torch.mv(mat, vec)矩阵向量相乘

  • 功能:执行矩阵与向量的乘法运算
  • 参数:矩阵+向量

mat 必须是一个二维张量,vec 必须是一个一维张量,返回一个一维向量

import torch
a = torch.randn(2,3)
b = torch.randn(3)
c = torch.mv(a,b)
print(a)
print(b)
print(c)
结果:
tensor([[ 1.0841, -1.4717, -0.1817],
        [ 0.7554, -0.6128, -0.2065]])
tensor([ 0.4840, -0.6109, -0.3883])
tensor([1.4943, 0.8201])

(8)torch.mul(input, other)

输入张量对应位置元素的乘积

import torch
# 创建两个输入张量
input_tensor = torch.tensor([2, 3, 4])
other_tensor = torch.tensor([5, 6, 7])
# 对两个张量进行逐元素相乘
result_tensor = torch.mul(input_tensor, other_tensor)
print(result_tensor)  # 输出: tensor([10, 18, 28])

3.神经网络工具箱torch.nn

3.1 nn.Module类

1. nn.Module类
nn.Module是PyTorch提供的神经网络类,并在类中实现了网络各层的定义及前向计算与反向传播机制。在实际使用时,如果想要实现某个神经网络,只需继承nn.Module,在初始化中定义模型结构与参数,在函数forward()中编写网络前向过程即可。

(1)nn.Parameter函数

使用 nn.Parameter将一个张量标记为模型参数后,该参数将被添加到模型的参数列表中,并且在模型进行反向传播计算梯度时,PyTorch 将会自动跟踪该参数的梯度并进行更新。


(2)forward()函数与反向传播

  1. forward() 函数:这个方法定义了输入数据如何在网络中传播,并最终得到输出结果,就是前向传播

  2. )反向传播:通过反向传播算法可以计算损失函数对模型参数的梯度,从而更新模型参数以降低损失函数的数值。

    在 PyTorch 中,一般通过以下几个步骤来完成反向传播:

    • 利用模型的 forward() 方法计算输出
    • 计算损失函数
    • 调用 backward() 方法计算梯度
    • 调用优化器的 step() 方法来更新模型参数

3.多个Module的嵌套

可以通过将多个 nn.Module 的子类进行嵌套来构建更复杂的神经网络模型


4.nn.Module与nn.functional库

5.nn.Sequential()模块

class MLP(nn.Module):
    def __init__(self, in_dim, hid_dim1, hid_dim2, out_dim):
        super(MLP, self).__init__()
# __init__ 方法:在初始化阶段,定义了 MLP 的结构。它接受输入特征维度 in_dim、两个隐藏层的维度 hid_dim1 和 hid_dim2,以及输出维度 out_dim。
        self.layer = nn.Sequential(
            nn.Linear(in_dim, hid_dim1),
            nn.ReLU(),
            nn.Linear(hid_dim1, hid_dim2),
            nn.ReLU(),
            nn.Linear(hid_dim2, out_dim),
        )

    def forward(self, x):
        x = self.layer(x)
        x = torch.sigmoid(x)
        return x
# 定义了数据在模型中的前向传播过程。输入数据 x 首先经过 nn.Sequential 容器中的三个线性层和两个 ReLU 激活函数,最后输出预测结果,使用 Sigmoid 函数作为最后一层的激活函数可以将网络的输出解释为样本属于正类的概率

4.torch实现一个完整的神经网络

以下是例子:

model = MLP()  # 创建一个MLP神经网络模型实例
criterion = get_loss()  # 获得损失函数,回归问题通常会使用MSE损失,而分类问题通常会使用交叉熵损失
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 使用Adam优化器来更新模型参数,学习率为0.001

# 训练模型
num_epochs = 100  # 设置训练的epoch数量为100
for epoch in range(num_epochs):  # 对于每一轮
    # 训练
    outputs = model(X_tensor)  # 进行前向传播,得到模型的输出
    loss = criterion(outputs, y_tensor)  # 计算模型输出与真实标签之间的损失
    optimizer.zero_grad()  # 梯度清零,避免梯度累加
    loss.backward()  # 反向传播,计算梯度
    optimizer.step()  # 更新模型参数
    
    if (epoch + 1) % 1 == 0:  # 每训练1个epoch后
        acc, recall = calculate_accuracy_recall(outputs, y_tensor)  # 计算模型的准确率和召回率
    

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()  # 初始化神经网络模型
        self.fc1 = nn.Linear(2, 64)  # 输入层到第一隐藏层的全连接层
        self.fc2 = nn.Linear(64, 32)  # 第一隐藏层到第二隐藏层的全连接层
        self.fc3 = nn.Linear(32, 2)  # 第二隐藏层到输出层的全连接层
        self.relu = nn.ReLU()  # 激活函数ReLU
        self.softmax = nn.Softmax(dim=1)  # Softmax函数,用于多分类问题

    def forward(self, x):
        out = self.fc1(x)  # 数据前向传播至第一隐藏层
        out = self.relu(out)  # 激活函数处理
        out = self.fc2(out)  # 数据前向传播至第二隐藏层
        out = self.relu(out)  # 激活函数处理
        out = self.fc3(out)  # 数据前向传播至输出层
        out = self.softmax(out)  # Softmax处理得到最终输出
        return out  # 返回输出结果

5. 简单神经网络搭建:通过继承 Module 类自定义模型

  1. Module 类的一些核心方法和属性
  • __init__(self): 初始化方法,用于初始化 Module 类的实例。
  • forward(self, *input): 前向传播方法,定义了模型的前向计算逻辑。
  • add_module(self, name, module): 添加子模块的方法。
  • cuda(self, device=None): 将模型参数移动到 GPU 上。
  • cpu(self): 将模型参数移动到 CPU 上。
  • __call__(self, *input, **kwargs): 使实例能够像函数一样被调用,实际会调用 forward 方法。
  • parameters(self, recurse=True): 返回模型的参数迭代器。
  • named_parameters(self, prefix='', recurse=True): 返回模型的命名参数迭代器。
  • children(self): 返回模型的子模块迭代器。
  • named_children(self): 返回模型的命名子模块迭代器。
  • modules(self): 返回模型及其子模块的迭代器。
  • named_modules(self, memo=None, prefix=''): 返回模型及其子模块的命名迭代器。
  • train(self, mode=True): 设置模型为训练模式。
  • eval(self): 设置模型为评估模式。
  • zero_grad(self): 将模型的梯度清零。
  • __repr__(self): 返回模型的可打印表示形式。
  • __dir__(self): 返回模型的属性列表。

  • 具有可学习参数的层(如全连接层、卷积层等)放在构造函数__init__()中
  • 不具有可学习参数的层(如ReLU、dropout、BatchNormanation层)可放可不放在构造函数中,如果不放在构造函数__init__里面,则在forward方法里面可以使用nn.functional来代替

例子:

下面的是将所有的层都放在了构造函数__init__里面,但是只是定义了一系列的层,各个层之间到底是什么连接关系并没有

import torch

class MyNet(torch.nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()  # 调用父类的构造函数,初始化模型
        self.conv1 = torch.nn.Conv2d(3, 32, 3, 1, 1)  # 创建第一个卷积层
        self.relu1 = torch.nn.ReLU()  # 创建第一个ReLU激活函数层
        self.max_pooling1 = torch.nn.MaxPool2d(2, 1)  # 创建第一个最大池化层

        self.conv2 = torch.nn.Conv2d(3, 32, 3, 1, 1)  # 创建第二个卷积层
        self.relu2 = torch.nn.ReLU()  # 创建第二个ReLU激活函数层
        self.max_pooling2 = torch.nn.MaxPool2d(2, 1)  # 创建第二个最大池化层

        self.dense1 = torch.nn.Linear(32 * 3 * 3, 128)  # 创建第一个全连接层
        self.dense2 = torch.nn.Linear(128, 10)  # 创建第二个全连接层

    def forward(self, x):
        x = self.conv1(x)  # 第一个卷积层操作
        x = self.relu1(x)  # 第一个ReLU激活函数操作
        x = self.max_pooling1(x)  # 第一个最大池化操作
        x = self.conv2(x)  # 第二个卷积层操作
        x = self.relu2(x)  # 第二个ReLU激活函数操作
        x = self.max_pooling2(x)  # 第二个最大池化操作
        x = self.dense1(x)  # 第一个全连接层操作
        x = self.dense2(x)  # 第二个全连接层操作
        return x

model = MyNet()
print(model)
'''
运行结果为:
MyNet(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 第一个卷积层信息
  (relu1): ReLU()  # 第一个ReLU激活函数信息
  (max_pooling1): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)  # 第一个最大池化层信息
  (conv2): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 第二个卷积层信息
  (relu2): ReLU()  # 第二个ReLU激活函数信息
  (max_pooling2): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)  # 第二个最大池化层信息
  (dense1): Linear(in_features=288, out_features=128, bias=True)  # 第一个全连接层信息
  (dense2): Linear(in_features=128, out_features=10, bias=True)  # 第二个全连接层信息
)
'''

将没有训练参数的层没有放在构造函数里面了,所以这些层就不会出现在model里面,但是运行关系是在forward里面通过functional的方法实现的。

import torch  # 引入torch模块
import torch.nn.functional as F  # 引入torch.nn.functional模块,并使用F作为别名
 
class MyNet(torch.nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()  # 调用父类的构造函数
        self.conv1 = torch.nn.Conv2d(3, 32, 3, 1, 1)  # 创建第一个卷积层
        self.conv2 = torch.nn.Conv2d(3, 32, 3, 1, 1)  # 创建第二个卷积层
 # 去掉了激活层和最大池化层,后面forward用F模块里面的
        self.dense1 = torch.nn.Linear(32 * 3 * 3, 128)  # 创建第一个全连接层
        self.dense2 = torch.nn.Linear(128, 10)  # 创建第二个全连接层
 
    def forward(self, x):
        x = self.conv1(x)  # 第一个卷积层操作
        x = F.relu(x)  # 使用F模块中的ReLU激活函数
        x = F.max_pool2d(x)  # 使用F模块中的最大池化函数
        x = self.conv2(x)  # 第二个卷积层操作
        x = F.relu(x)  # 使用F模块中的ReLU激活函数
        x = F.max_pool2d(x)  # 使用F模块中的最大池化函数
        x = self.dense1(x)  # 第一个全连接层操作
        x = self.dense2(x)  # 第二个全连接层操作
        return x
 
model = MyNet()
print(model)
'''
运行结果为:
MyNet(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (conv2): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (dense1): Linear(in_features=288, out_features=128, bias=True)
  (dense2): Linear(in_features=128, out_features=10, bias=True)
)
'''


6. module的多种实现

PyTorch 中用于构建神经网络的模块和容器有:

  1. Container(Module): 现已不再使用。一般指代包含其他模块的复杂模块。
  2. Sequential(Module): 用于按顺序连接多个层或模块的容器。它按照添加的顺序依次执行每个模块。
  3. ModuleList(Module): 用于存储子模块的列表,类似 Python 列表的方式进行索引访问。
  4. ModuleDict(Module): 使用字典的形式存储子模块,可以通过键来访问子模块。
  5. ParameterList(Module): 专门用于存储参数,可以通过索引访问,并且会被视为模型的一部分。
  6. ParameterDict(Module): 用于存储参数,可以通过键来访问,并且会被视为模型的一部分。

简单的Sequential介绍:

例子:

import torch.nn as nn
from collections import OrderedDict
model = nn.Sequential(OrderedDict([
                  ('conv1', nn.Conv2d(1,20,5)),
                  ('relu1', nn.ReLU()),
                  ('conv2', nn.Conv2d(20,64,5)),
                  ('relu2', nn.ReLU())
                ]))
# 可以看到,能够在前面写名称
 
print(model)
print(model[2]) # 通过索引获取第几个层
'''运行结果为:
Sequential(
  (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
  (relu1): ReLU()
  (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
  (relu2): ReLU()
)
Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
'''

每一个层都有了自己的名称,但不能够通过名称直接获取层,依然只能通过索引index,即

model[2] 是正确的

model[“conv2”] 是错误的

这其实是由它的定义实现的,看上面的Sequenrial定义可知,只支持index访问


另一种实现的方式:

import torch.nn as nn
from collections import OrderedDict
model = nn.Sequential()
model.add_module("conv1",nn.Conv2d(1,20,5))
model.add_module('relu1', nn.ReLU())
model.add_module('conv2', nn.Conv2d(20,64,5))
model.add_module('relu2', nn.ReLU())
 
print(model)
print(model[2]) # 通过索引获取第几个层

Sequential里面并没有定义add_module()。但实际上,这个方法是定义在它的父类Module里面的,Sequential继承了而已

定义:

def add_module(self, name, module):

# 第一种:

import torch.nn as nn
from collections import OrderedDict
class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.conv_block = nn.Sequential(  # # 定义一个包含卷积、激活函数ReLU和最大池化层的序列
            nn.Conv2d(3, 32, 3, 1, 1),  # 输入通道数为3,输出通道数为32的3x3卷积层
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.dense_block = nn.Sequential(   # 定义一个包含全连接层和激活函数ReLU的序列
            nn.Linear(32 * 3 * 3, 128),
            nn.ReLU(),
            nn.Linear(128, 10)
        )

    # 在这里实现层之间的连接关系,其实就是所谓的前向传播
    def forward(self, x):  # 通过 self 可以访问该类的成员变量和成员方法,包括 conv_block 和 dense_block 这两个成员变量,以及 forward 这个方法
        conv_out = self.conv_block(x)
        res = conv_out.view(conv_out.size(0), -1)  # 将 conv_out 进行展平操作,将其转换为一个二维张量,以便后续输入全连接层进行处理
        out = self.dense_block(res)
        return out
 
model = MyNet()
print(model)

# 第二种: 就是多了个命名

import torch.nn as nn
from collections import OrderedDict
class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.conv_block = nn.Sequential(
            OrderedDict(
                [
                    ("conv1", nn.Conv2d(3, 32, 3, 1, 1)),
                    ("relu1", nn.ReLU()),
                    ("pool", nn.MaxPool2d(2))
                ]
            ))
 
        self.dense_block = nn.Sequential(
            OrderedDict([
                ("dense1", nn.Linear(32 * 3 * 3, 128)),
                ("relu2", nn.ReLU()),
                ("dense2", nn.Linear(128, 10))
            ])
        )
 
    def forward(self, x):
        conv_out = self.conv_block(x)
        res = conv_out.view(conv_out.size(0), -1)
        out = self.dense_block(res)
        return out
 
model = MyNet()
print(model)


# 第三种:就是换成add_module这种方式添加

import torch.nn as nn
from collections import OrderedDict
class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.conv_block=torch.nn.Sequential()
        self.conv_block.add_module("conv1",torch.nn.Conv2d(3, 32, 3, 1, 1))
        self.conv_block.add_module("relu1",torch.nn.ReLU())
        self.conv_block.add_module("pool1",torch.nn.MaxPool2d(2))
 
        self.dense_block = torch.nn.Sequential()
        self.dense_block.add_module("dense1",torch.nn.Linear(32 * 3 * 3, 128))
        self.dense_block.add_module("relu2",torch.nn.ReLU())
        self.dense_block.add_module("dense2",torch.nn.Linear(128, 10))
 
    def forward(self, x):
        conv_out = self.conv_block(x)
        res = conv_out.view(conv_out.size(0), -1)
        out = self.dense_block(res)
        return out
 
model = MyNet()
print(model)

self):
super(MyNet, self).init()
self.conv_block=torch.nn.Sequential()
self.conv_block.add_module(“conv1”,torch.nn.Conv2d(3, 32, 3, 1, 1))
self.conv_block.add_module(“relu1”,torch.nn.ReLU())
self.conv_block.add_module(“pool1”,torch.nn.MaxPool2d(2))

    self.dense_block = torch.nn.Sequential()
    self.dense_block.add_module("dense1",torch.nn.Linear(32 * 3 * 3, 128))
    self.dense_block.add_module("relu2",torch.nn.ReLU())
    self.dense_block.add_module("dense2",torch.nn.Linear(128, 10))

def forward(self, x):
    conv_out = self.conv_block(x)
    res = conv_out.view(conv_out.size(0), -1)
    out = self.dense_block(res)
    return out

model = MyNet()
print(model)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值