感知机-李沐

目录

1.感知机

2.多层感知机

3.代码实现

3.1多层感知机的从0开始实现

3.2多层感知机的简洁实现


 

1.感知机

感知机其实就是2分类的问题

        (1)yi是个标号(+1,-1),小于0表感知机把分类样本预测错了,因为如果是大于0的,意味着要分类成一个正类,假设yi是+1的,那么乘积就是一个大于等于0的数,若乘积小于0说明yi是-1,表示分类分错了。(yi为真实标号,为预测标号)。

        (2)如果分类分错了,就对w和b作一次更新,

(标号乘以样本作权重更新,偏差等于偏差+标号)。由感知机的损失公式:

,可以看出yixi是损失对w求偏导得出的,而yi是损失对偏差b求偏导得出的。

        (3)重复(1),(2)直到所有的类都分类正确。

        (4)等价于使用批量大小为1的梯度下降,含义是每次拿一个样本算梯度然后更新,没有用随机梯度下降是因为感知机最原始的模型就是,感知机一遍一遍的扫数据没有说要随机去弄。感知机的损失函数等于。max()其实就对应了感知机训练过程的if语句,因为如果分类正确的话,这一项是大于0的,前面再加个符号整个第二项的参数就为负,所以max()取的是0,损失函数为0,梯度是常数就不再更新参数了。就对应上面的if语句不成立,如果分类错误就要进入if语句更新参数。

理解一下收敛:r看作是数据的大小,也就是说当r很大时,数据的收敛就会变慢,还有个因素就是,表示数据是不是很好,很好的意思是是否能把两个点真的分的特别开(也是余量较大的含义),分得很开的话很快就收敛了,如果分隔面特别小,那么找到这个面就会花很多时间。

感知机不能拟合xor(异或)函数,如上图紫色是坐标轴,当x和y同号时,同红点表示,当x和y异号时用绿点表示,蓝色是分割线,始终不能把红点和绿点分开。感知机只能产生线性分隔面。

2.多层感知机

解释一下:蓝色分隔面就是把x分成了正和负,黄色分割线就是把y分成了正和负,根据1,2,3,4个点的位置,整理成表格。同号得正,异号得负。对这四个点作分类的问题就可以看作右下角的流程图,把每个点分别经过两个感知机就能得到正确的结果,就是组合几个函数,一层感知机就变成了多层感知机。这就是多层感知机做的事情。

输出就是有多少类了,我们能做的就是设置隐藏层有多大。

输入是一个n维的向量,假设隐藏层的大小是m,权重就是m*n的矩阵,偏移就是有多少个隐藏层就有多少个标量偏移,长为m的向量。因为是单分类的问题所以只输出一个,那么输出层就是一个长为m的向量(这里单分类的时候把图中o2,o3去掉来看就明白了),h是一个长为m的向量,作为输入进入到输出层,再经过权重和偏置的运算得到的输出是一个标量。

为什么需要非线性激活函数?

答:因为加入激活函数是线性的,输出层输出的结果仍然是线性的,那么多层感知机就等价于单层的感知机(这也是我们常犯的错误)。

sigmoid函数就是根据x的值投影到(0,1)开区间。分母做的事情就是exp把x变成一个正数,然后1加正数分支1一定是在(0,1)区间里的一个值。

tanh就是根据输入投影到(-1,1)的开区间。

ReLU函数就是把x,0求最大值。x的导数是+1,0的导数是0。

softmax做的事情就是把所有的输入拉到0和1 之间的区域,使得y1+...+yk=1。多分类问题就是在softmax回归里面加了一层隐藏层。

与单分类问题不同的是输出层的输出变成了K个,因为输出要有k个单元。所以w2就是(m*k)的矩阵,偏移是一个长为k的向量。因此输出o就变成了一个向量,不再是标量了。

记住激活函数不能少,少了就等于这层没有作用,相当于隐藏层的层数减1。输出不需要激活函数。超参数的配置很重要。比如,输入的数据很复杂的情况下,第一个选择就是用单隐藏层,把m1设的大一点,输入为维度128,隐藏层做64,128,256都行。第二个选择是把模型做的深一点,增加m2,m3。相对于单隐藏层的m1很大,做深的话,m1就不要太大,m2,m3大小递减。比如128到64到32到8依次递减。但是第一个隐藏层稍微胖一点也没关系,比如128的输入先做到256再慢慢缩回去,比如图上4个输入,5个隐藏层。要慢慢压缩,不然损失的信息太多最后难以还原。

3.代码实现

3.1多层感知机的从0开始实现

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
#批量大小等于256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

"""初始化模型参数"""
num_inputs, num_outputs, num_hiddens = 784, 10, 256
#假设输入784(28*28的图片),输出是10,输入输出不可改,隐藏层是256

W1 = nn.Parameter(torch.randn(
    num_inputs, num_hiddens, requires_grad=True) * 0.01)
#nn.Parameter声明是torch的一个参数(不加也没关系),第一个隐藏层是行数784,列数256,
#因为要更新所以需要梯度,torch.randn()返回返回一个包含了从标准正态分布中抽取的一组
#随机数的张量乘0.01我的理解:randn是正态(0,1)分布,乘0.01使得分布为正态(0,0.1)分布,
#数据方差更小,把方差变为了0.01
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
#偏差就是隐藏层的个数,是一个向量,偏差设成0
W2 = nn.Parameter(torch.randn(
    num_hiddens, num_outputs, requires_grad=True) * 0.01)
#第二个隐藏层的输入就是256(前一个隐藏层的输出),输出是10,需要梯度。
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
#偏置是10,因为要分10类

params = [W1, b1, W2, b2]

"""激活函数"""
def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X, a)
#zeros_like函数使得数据类型和形状都和X一样但是值为0
#torch.zeros_like() 是 PyTorch 中的一个函数,它返回一个与给定输入张量形状和数据类型
#相同,但所有元素都被设置为零的新张量。torch.zeros_like(input, dtype=None, layout=None,
# device=None, requires_grad=False)



"""实现模型"""
def net(X):
    X = X.reshape((-1, num_inputs))
    #使X变成一个2维的矩阵,因为输入是784,-1代表计算得出的batchsize256
    H = relu(X@W1 + b1)  # 这里“@”代表矩阵乘法
    #根据理论公式转不转置取决于x是怎么创建的,因为这里的x是256*784大小,而w(784*256)
    #所以不用转置
    return (H@W2 + b2)


"""损失函数"""
loss = nn.CrossEntropyLoss(reduction='none')
#损失函数是交叉熵损失,当reduction='none'时,函数会输出一个形状为(batch_size, num_classes) 
#的矩阵,表示每个样本的每个类别的损失。nn.CrossEntropyLoss() 内置了softmax操作,因此input
#只需要是网络输出的logits即可,不需要自己用softmax进行归一化,也不需要保证是正数。


"""训练"""
num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
#经过训练发现现在的损失较之前的只用softmax相比,损失已经降到0.4以下了。精度肉眼看不出来变化


"""预测"""
#在一些测试数据上应用这个模型
d2l.predict_ch3(net, test_iter)

(以上是多层感知机的分类)

(以上是多层感知机的分类预测结果)

(以上是softmax分类结果)

3.2多层感知机的简洁实现

import torch
from torch import nn
from d2l import torch as d2l

"""模型"""
#隐藏层,它包含256个隐藏单元,并使用了ReLU激活函数。
net = nn.Sequential(nn.Flatten(),
                    nn.Linear(784, 256),
                    nn.ReLU(),
                    nn.Linear(256, 10))

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);

"""训练"""
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)




补充一点感知机的损失:

感知机的损失函数只计算被误分类的点,意味着yi与(w.xi+b)是异号的,所以损失L一定大于等于0。(w.xi+b)表征了误分类点到超平面的距离

感知机的目的就是求一个L等于0的超平面,也就是使得损失函数最小的超平面

参考:

torch.zeros_like有什么作用_torch.zero_like-CSDN博客

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值