深度学习笔记-长期学习更新

一些概念

  • 全连接层

    • 输入和输出通过一种运算直接连接的层
    • 全连接层忽略了空间结构特性,因此不适合用于在方位上找Pattern的任务
    • 理解:https://zhuanlan.zhihu.com/p/33841176
  • 多层感知机

    • 在输出层与输入层之间加入了一个或多个全连接隐藏层。即:含有至少一个隐藏层的由全连接层组成的神经网络
    • 常用的激活函数包括ReLU函数、sigmoid函数和tanh函数
  • 线性回归、softmax回归与logistic回归

    • softmax处理多分类问题,logistic处理二分类问题
    • 线性回归是y=w1x1+w2x2+b的模式,只有一个输出;softmax通过softmax运算符实现多个输出神经元的分类预测。
    • softmax的各分类概率相加为1,用于找概率最大的那个。sigmoid的各分类为0-1之间的值,概率总和不一定为1,用于发现多种可能。
  • 欠拟合与过拟合

  • 隐藏层

    • 每个隐藏层的输出通过激活函数进行变换,实现非线性变换。隐藏层的作用:
      -w947
  • batch概念 & 作用

    • 通常将样本分为多组,每组中样本数量即为batch_size
    • batch太大会训练慢,太小会梯度下降方向性差,但偏大比较好。

梯度下降

本质就是当前点的cost函数对w1,w2,b等各个系数的偏导,从而求得该点的梯度,然后通过梯度乘以学习率,然后进行反向传播,即可实现梯度下降。

例:w := w - a * dw, dw即为损失函数对w的偏导。注意损失函数中的y是要替换成sigmod(z),然后z换成wx+b,从而可以求对w的偏导。

-w898
-w674

1
2
3
4
5
6
7
demo:
for X, y in data_iter:
output = net(X)
l = loss(output, y.view(-1, 1))
optimizer.zero_grad() # 梯度清零,等价于net.zero_grad()
l.backward() # 自动求梯度,结果存在.grid属性中
optimizer.step() # step实现梯度下降

Module构造模型

1
2
3
4
5
6
7
8
9
10
11
12
13
import torch
from torch import nn

class MLP(nn.Module):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Linear(784, 256) # 隐藏层
self.act = nn.ReLU()
self.output = nn.Linear(256, 10) # 输出层

def forward(self, x):
a = self.act(self.hidden(x))
return self.output(a)

这里的模型定义倒是很简单,需要注意的是784*256和256*10的关系。

如下图,784就是x也就是特征的个数,784256为w的数量,也就是要训练的参数的数量。这就好像softmax中的w,是3\3的,而x是1*3的。

因此这里实际上就是:
[1*784] * [784*256] * [256*10] = [1*10]

MLP

softmax的demo

卷积神经网络

强烈推荐: https://github.com/fengdu78/deeplearning_ai_books

卷积层

需要熟悉的概念:

  • 卷基层主要作用是提取图像中的局部特征
  • 卷积(互相关)运算、卷积核
  • 填充(padding)、步幅(stride)
  • 多输入输出通道(多输入通道只需要增加核的通道数,想要多输出通道需要增加核的组数)

含2个输入通道的互相关计算

池化层

需要熟悉的概念:

  • 主要作用是缓解卷积层对位置的过度敏感性,降低数据数量,防止过拟合
  • 输出通道数与输入通道数相同

CNN的反向传播

CNN的参数就是卷积核,因此反向传播就是求cost对卷积核的偏导,然后梯度下降。

LeNet

LeNet模型

模型解读(重要):

这里需要搞懂各种形状的变换,这是核心。理解了这里,看其他几个网络也会轻松很多。
整个模型为:卷积-池化-卷积-池化-全连接
注意数据通道数、维度的变化:首先卷积-池化两层将输入变为6通道,14*14的矩阵,然后再通过一个卷积层变为16通道,10*10的矩阵,注意这里的卷积核是:6通道,16组。

最后全连接层为5*5*16 -> 120, 形状是:
[1,[16,5,5]],然后展开和[[16,5,5],120]相乘,最后结果就是[1,120],这和之前MLP中隐藏层的算法是一样的。

关于CNN中卷积层后为何要跟隐藏层(激活函数的作用):
激活函数的主要作用是提供网络的非线性建模能力。在卷积层中,我们主要采用了卷积的方式来处理,也就是对每个像素点赋予一个权值,这个操作显然就是线性的。但是对于我们样本来说,不一定是线性可分的,为了解决这个问题,我们可以进行线性变化,或者我们引入非线性因素,解决线性模型所不能解决的问题。如果没有激活函数,那么该网络仅能够表达线性映射,此时即便有再多的隐藏层,其整个网络跟单层神经网络也是等价的。因此也可以认为,只有加入了激活函数之后,深度神经网络才具备了分层的非线性映射学习能力。
-w722
不过我还是没懂池化层之后为啥不需要激活。。

使用:
只写一下前向传播吧,conv是前边的一堆卷积池化,然后全连接。注意全连接是256->10的,因此需要feature.view把16*4*4转成256。

1
2
3
4
def forward(self, img):
feature = self.conv(img)
output = self.f_conn(feature.view(img.shape[0], -1)) # feature是256*16*4*4,view后就是256*256,正好conn
return output

AlexNet & VGG

VGG就是很多个VGG block叠在一起,理解上和LeNet没有本质区别。

残差网络:ResNet

非常深层的网络因为深度存在梯度消失和梯度爆炸的问题。因此需要使用跳跃连接,可以将某一层网络的激活迅速传给更深处。

残差网络最重要的是理解残差块,举个例子:
正常的plain block,a[l] -> a[l+2]需要经过这两个线性/激活层,然后才能往后传播。
-w924

而残差块并不需要经过这两层,而是直接通过short cut传递到了后边relu函数,这样就能做到不经过中间层,直接向后传播,也就能实现全局最优解

引用吴恩达的话就是“这些残差块学习恒等函数非常容易,因此可以保证网络性能不受深度影响,甚至提高性能”。
a[l+2]=g(Wa[l+1]+b+a[l])
-w958

GoogLeNet

Inception块原理:
-w732

批量归一化

// TODO

循环神经网络

一定要去看吴恩达的课。。网上那些教程写的就像一坨坨屎

基本原理

https://cuijiahua.com/blog/2018/12/dl-11.html 这篇写的不错。

一共维护三个参数VUW,V是输出层的参数,W是将状态传递到下一次运算的参数,U是下一次和Xt运算的参数。

如何将字符序列输入网络

one_hot,其实就是将一串n个字符的输入表示成一个n维矩阵,矩阵中只有当前那个词是1,其他都是0

基于时间的反向传播

还就是logistic回归的那个cost,但是具体怎么计算的还没搞懂。。

LSTM

关于LSTM的记忆细胞为什么能解决梯度消失问题:
https://www.jianshu.com/p/95d5c461924c
不过为什么之前的信息能这样保存我还没理解

最近写的Webshell直接用上了双向循环LSTM,效果还不错。RNN是几分类,输出的最后一维就是几。

有关输出的问题:
LSTM的输出格式是output, (h_n, c_n),output是三维的,格式为(token_len, batch_size, hidden_size*(bidirectional?1:2))。
time step数量等于token_len,output保存了最后一层的每个time step的输出h,如果是双向LSTM,每个time step的输出h=[h正向, h逆向]
https://zhuanlan.zhihu.com/p/39191116

使用:
input_size是embedding的维度,hidden_size是隐藏单元数量,num_layers是RNN层数,bidirectional True表示双向RNN。

1
2
3
4
self.encoder = nn.LSTM(input_size=embedding_dim,
hidden_size=num_hiddens,
num_layers=num_layers,
bidirectional=True)

word embedding

one hot的各个词向量之间内积为0,没法表示两个词之间的关系(比如近义词),因此提出词嵌入。

核心思路是给词的表示加一个维度,这个维度表示词的一些特征的数量,用embedding_dim表示。比如下图:
性别、年龄等特征种,与其相关的词的这一属性的值就会相近,这样就能找到相近的关系。
-w953

因此,pytorch中使用embedding只需要两个参数:词的属性数量(维度)和词的数量。

1
2
3
4
5
self.embedding = nn.Embedding(token_size, embedding_dim)

# inputs的形状是(批量大小, 词数),因为LSTM需要将序列长度(seq_len)作为第一维,
# 所以将输入转置后再提取词特征,输出形状为(词数, 批量大小, 词向量维度)
embeddings = self.embedding(inputs.permute(1, 0))

pytorch常用操作

tensor切片: https://blog.csdn.net/weicao1990/article/details/93599947

Proudly powered by Hexo and Theme by Hacker
© 2021 LFY