1. 异或门问题

很多时候,我们的分类问题,就是使用一条之间,讲平面上的点划分为两个部分。

1. 矩阵乘法的已补充:

Tensor进行乘法的过程中,会把一维向量,默认作为列向量进行运算
下面程序的结果:

import torch
X = torch.tensor([[1, 2], [3, 4],[5,6], [7, 8]], dtype=torch.float)
y = torch.tensor([2, 3], dtype=torch.float)
z = torch.tensor([[1], [3]], dtype=torch.float)
print(z.shape)  #  torch.Size([2])
print(y.shape)  # torch.Size([2, 1])
print(X @ y)   # tensor([ 8., 18., 28., 38.])  形状是  torch.Size([4])
print(X @ z)  # tensor([[ 8.],
			        # [18.],
			       #  [28.],
			       #  [38.]])   形状是 4 * 1 二位矩阵。

简单的单层神经网络,我们可以进行线性分类,方便的把内容分为两类或者多类。但是对于异或这种数据,我们是不可能使用简单的线性关系来分离数据的。
在这里插入图片描述
所以,引入多层神经网络,来拟合曲线寻找分类边界,进行分类。多层神经网络,理论上来讲可以拟合/接近任意形状的曲线。
单层神经网络,不能解决异或门的分类问题。但是只要我们增加一层,我们就可以解决这个分类问题。(实际上,我们增加多层,可以处理任意的分类问题)

深层神经网络的不可解释性

数据量越大,神经网络层数越深,效果就会越好。
深度神经网络的核心理解:
在这里插入图片描述

1 输入的神经元的个数,其实就是我们的特征数量。
2 每一层的神经元,其实就是一个矩阵。(一层就是一个矩阵,转换矩阵)
3 神经网络传递的过程,其实相当于把我们的特征分解,再处理,之后根据输出要求,综合形成输出。

在实际工程中,我们实际数据可能有成百上千个特征,所以我们的神经网络的层数和中间特征会很大。中间会有各种各样的参数,他们之间究竟是如何作用生成了我们最后的结果,所以通常情况下,我们可以认为整个神经网络处理的过程是一个"黑箱"。
所以我们很难通过神经网络的传播,来获取特征权重的重要性。

深度探索神经网络

增加神经网络的层数并不会增加神经网络的表达能力
神经网络的表达能力的提升,其实是通过激活函数实现的。(相当于引入非线性因素)

常见的神经网络的激活函数:
sigmoid,ReLU,tanh, softmax等。

从0实现神经网络的正向传播

复习:torch.nn中,包含两个内容,一个function 包含我们所需要的各种激活函数。一个Module,包含我们建立神经网络所需要的各种层。
所以我们建立神经网络的时候,可以直接使用nn来搭建。

import torch
from torch import nn

# 生成 500,2 的矩阵
torch.random.manual_seed(0)
x = torch.randint(0, 10, (500, 20))
y = torch.randint(0, 3, (500, ))
print(x.shape)
print(y.shape)
x = x.float()
y = y.float()

class Net(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(Net, self).__init__()  # 必须写上,因为父类在init方法中的,如果有自定义的内容,就不会执行。所以还是手动调用该__init__()
        self.fc1 = nn.Linear(input_dim, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, output_dim)
        self.relu = nn.ReLU()
        # self.softmax = nn.functional.softmax(dim=1)
        # 通常情况下,最后一层我们不会使用激活函数,因为后面求解梯度时,
        # 最后一层会自动求解,但是这里为了方便,还是加上了

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)
        x = nn.functional.softmax(x, dim=1)
        return x

input_dim = x.shape[-1]  # 通常输入特征是x的最后一个维度,这里我们直接获取
print(input_dim)
output_dim = len(y.unique())
print(output_dim)

# 分类
model = Net(input_dim, output_dim)
# 会自动执行forward函数
model(x)
# 查看数据
n1 = model.fc1.weight.data
n1_b = model.fc1.bias.data
print(n1)
print(n1_b)
print(n1.shape)
print(n1_b.shape)

我们直接使用nn模块提供的 Module和 function,像是搭积木一样,搭建我们自己的神经网络。
这个三层的神经网络,其实就是输入了我们的数据x(500, 20)。
进入第一层网络,(其实就是一个矩阵w1,x与w1进行运算,得到第一层的输出h1)
h1进入第二层网络(其实就是与矩阵 w2进行运算,得到输出h2)
继续进入第三层网路,得到输出。
所有的神经网络的前向传播过程,其实都是这种类似的过程。

详细解析流程:
每一层的权重的形状如下:
输入的形状是 (500, 20)
在这里插入图片描述
计算过程如下:
output = input @ weight.T + bias

对于我们继承的nn.Module中,一些重要的参数

print(model.training) # True 是否训练
print(model.cpu())  # 把模型放在CPU上
print(model.cuda()) # 把模型放在GPU上(要有GPU)

params = model.parameters()
for item in params:
    print(item)
    
# 也可以查看具体的参数和名称
for name, param in model.named_parameters():
    print(name, param)

这些参数相对来说比较重要,但是即便不会也不用担心,我们开发过程中,会经常用到一些函数,比如 model.parameters(),和model.training 完全不用死记硬背。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐