深度学习基础知识-感知机+神经网络的学习

参考书籍:(找不到资源可以后台私信我)
《深度学习入门:基于Python的理论与实现 (斋藤康毅)》
《Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition (Aurelien Geron [Géron, Aurélien])》


机器学习和深度学习的区别:
在这里插入图片描述

神经网络的构造

Perceptron(感知机)

感知机就是一种接收多种输入信号,输出一个信号的原件。输入信号被送往神经元时,会被分别乘以固定的权重,神经元会计算传送来的信号的总和,只有当这个总和超过某个界限值时,才会输出1,此时被称为“神经元被激活”,这个界限值称为阈值。(可以把阈值挪到等式的左边,那只需要比较总和减阈值与0的关系)

感知机的实现就是TLU(Threshold Logic Unit),如下图所示。其中X和W都是向量,Z其实计算的就是加权和。再经过step函数就得到了输出。
在这里插入图片描述
常用的step function有两种:
在这里插入图片描述
设置不同的权重和阈值,我们可以用感知机表示与门、与非门、或门(此处不再证明)。下图中直线就可以是一个或门,很好地把(0,0)和(1,0)、(0,1)、(1,1)分开了。
在这里插入图片描述
但是,单个感知机无法表示异或门,因为异或需要用曲线来分类。也就是说,单层感知机只能表示线性空间。
在这里插入图片描述
使用多层感知机即可表示异或:
在这里插入图片描述
如果像下图一样,每个神经元都接收前一层的每个输出,那就是全连接层(fully connected layer / dense layer)。
在这里插入图片描述
输出的计算公式为:
在这里插入图片描述
其中b是bias vector,每个神经元都有一个bias。Φ是激活函数,如果神经元是TLU,那么Φ就是step function。其他的激活函数还有sigmoid、ReLU、softmax等。用上sigmoid就是神经网络了

Multilayer Perceptron

在这里插入图片描述
跟前面的单层perceptron的区别就是加了隐藏层。其中靠近输入层的也叫lower layers,靠近输出层的也叫upper layers。除了输出层都有bias神经元,每一层也都是全连接的。上图也是feedforward neural network(FNN)。

激活函数

神经网络的激活函数必须使用非线性函数。因为如果使用线性函数,那么加深神经网络的层数是没有意义(只是改了权重/参数)。

输出层所用的激活函数,要根据求解问题的性质决定。一般来说,回归问题可以使用恒等函数(直接输出,不作任何处理),二分类问题可以用sigmoid函数,多元分类问题可以使用softmax函数(只是训练阶段,在推理阶段,一般会省略掉sofmax)。

  • sigmoid函数:
    在这里插入图片描述

  • hyperbolic tangent function:这里h就是sigmoid函数
    tanh(z) = 2h(2x) - 1

  • ReLU(Rectified Linear Unit)函数:
    在这里插入图片描述
    在这里插入图片描述

  • softplus函数:(比ReLU更柔和一点)
    在这里插入图片描述

  • softmax函数:
    在这里插入图片描述
    由于指数增长是很恐怖的,所以为了防止溢出,如下图所示修改这个函数,并且将 C’ 改成 -max(x)
    在这里插入图片描述
    python实现:

def step_func(X):
    return np.array(X > 0, dtype=int)

def sigmoid_func(X):
    return 1 / (1 + np.exp(-X))
    
def relu(X):
    return np.maximum(0, X)

def softmax(X):
    c = np.max(X)
    exp_X = np.exp(X - c)
    sum_exp_X = np.sum(exp_X)
    y = exp_X / sum_exp_X
    return y

输出层的神经元数量需要根据问题决定。对于分类问题,输出层的神经元数量一般设为类别的数量。比如使用mnist训练手写数字分类器,那可以给输出层设置10个神经元,每个神经元对应一个数字。

输入数据的集合称为批(batch)。因为计算机一般会为批处理做优化,所以以batch为单位进行推理会比较快。

神经网络的学习

损失函数(loss function)

损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的神经网络对监督数据在多大程度上不拟合。在神经网络的学习/训练中,寻找最优参数(权重W和偏置B)时,要寻找使损失函数的值尽可能小的参数,此时需要计算参数的导数,然后以导数为指引,逐步更新参数的值。

可以用作损失函数的有:

参考:https://zhuanlan.zhihu.com/p/532850353
在这里插入图片描述
均方误差(mean squared error)/ L2 Loss
在这里插入图片描述

torch.nn.MSELoss(reduction='mean')

或者自己实现:

def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)

RMSE
在这里插入图片描述
MSE比MAE收敛更快,假设的是模型的误差服从标准高斯分布(均值0标准差1)

平均绝对误差(mean absolute error)/ L1 Loss
在这里插入图片描述

torch.nn.L1Loss(reduction='mean')

MAE比MSE更不容易受到异常值影响,假设的是误差服从拉普拉斯分布(μ=0 b=1)

Huber Loss
在这里插入图片描述
在这里插入图片描述
结合了MSE和MAE的优点,下降速度接近MSE,缺点是需要设置δ。

torch.nn.HuberLoss(reduction='mean')

交叉熵误差(cross entropy error
其中y是one-hot表示,所以只需要计算正确预测的情况。比如正确标签的索引是2,神经网络的输出是0.6,那么 E = -ln0.6
在这里插入图片描述

def cross_entropy_error(y, t):
    delta = 1e-7
    # 加一个delta是为了避免log(0)的情况
    return -np.sum(t * np.log(y + delta))

如果扩展到计算一批的误差,则是
在这里插入图片描述
mini-batch学习:从训练数据中选出一批数据(mini-batch),然后对每个mini-batch进行学习。只要计算随机选出的这批数据的损失函数,就可以近似得到所有训练数据的损失。

那么,mini-batch的交叉熵误差这样计算:

def cross_entropy_error_1hot_batch(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    delta = 1e-7
    return -np.sum(t * np.log(y + delta)) / batch_size

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    delta = 1e-7
    return -np.sum(np.log(y[np.arrange(batch_size), t] + delta)) / batch_size

数值微分(Numerical differentiation)

前面说了,在计算神经网络的参数的时候,需要计算参数的导数。计算导数时,实际计算的是近似值。如下图所示,当h足够小的时候可以认为近似值足够接近真值。
在这里插入图片描述
数值微分指的就是用数值方法近似求解导数的过程。如果以x为中心,计算左右两边的差分,就是中心差分:(如果是 x+h 与 x
之间就是前向差分)
在这里插入图片描述
如果是基于数学式的推导求导数就称为解析性求导(analytic differentiation)。比如y=x^2的导数y’=2x。解析性求导得到的导数是不含误差的真实导数。

偏导数是在有多个变量的情况下,对某一个变量进行求导。比如
在这里插入图片描述
它的偏微分是:
在这里插入图片描述
求法就是将其他变量看作常数,只对当前变量做求导。

如果把所有变量的偏导数合在一起变成向量,就称为梯度(gradient)。梯度指示的方向是各点处的函数值减小最多的方向,但并不保证梯度所指的方向就是函数的最小值。

梯度法:从某个位置沿梯度方向前进一段,再重新求梯度,再继续按新梯度方向前进,以此逐渐减小函数值。寻找最小值的梯度法称为梯度下降法(gradient descent method),反之称为梯度上升法(gradient ascent method)。

梯度法想要寻找梯度为0的点,但是梯度为0处不一定是最小值。比如函数的极小值就是局部最小值,而鞍点(saddle point,指从某个方向看是极大值,从另一个方向看是极小值的点)也不是最小值。而且,如果函数很复杂且比较扁平,那么学习可能会进入一个平坦区域(“学习高原”),此时将无法前进。
在这里插入图片描述

def numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x) # 生成和x形状相同的数组
    for idx in range(x.size):
        tmp_val = x[idx]
        # f(x+h)的计算
        x[idx] = tmp_val + h
        fxh1 = f(x)
        # f(x-h)的计算
        x[idx] = tmp_val - h
        fxh2 = f(x)
        # 计算导数
        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val # 还原值
    return grad

def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

学习率是超参数。权重和偏置可以通过训练获取,但学习率需要人工设定。

总结:神经网络的学习过程

神经网络存在合适的权重和偏置,调整它们以便拟合训练数据,这一过程称为“学习”。学习分为4个步骤:

  1. mini-batch
    从训练数据中随机选出一部分数据称为mini-batch。后续的目标是减小mini-batch的损失函数的值。
  2. 计算梯度
    求出各个权重参数的梯度。
  3. 更新参数
    将权重参数沿着梯度方向进行微小更新。
  4. 重复前三个步骤

一个epoch表示学习中所有训练数据都被使用过一次时的更新次数。比如有1w个训练数据,每个mini-batch是100个,那么就要做100次随机梯度下降,所以epoch=100。实际操作时会先将所有训练数据随机打乱,然后按指定的batch size,按顺序生成mini-batch。

下面是示意代码。没有跑,因为部分函数需要修改。

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size,
                 weight_init_std=0.01):
        self.params = {}
        # 生成服从正态分布的数据,(r, c)
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

    def sigmoid_func(self, X):
        return 1 / (1 + np.exp(-X))

    def softmax(self, X):
        c = np.max(X)
        exp_X = np.exp(X - c)
        sum_exp_X = np.sum(exp_X)
        y = exp_X / sum_exp_X
        return y

    def cross_entropy_error(self, y, t):
        if y.ndim == 1:
            t = t.reshape(1, t.size)
            y = y.reshape(1, y.size)
        batch_size = y.shape[0]
        delta = 1e-7
        return -np.sum(np.log(y[np.arrange(batch_size), t] + delta)) / batch_size

    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        a1 = np.dot(x, W1) + b1
        z1 = self.sigmoid_func(a1)
        a2 = np.dot(z1, W2) + b2
        y = self.softmax(a2)
        return y

    def loss(self, x, t):
        y = self.predict(x)
        return self.cross_entropy_error(y, t)

    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        acc = np.sum(y == t) / float(x.shape[0])
        return acc

    def numerical_gradient(self, f, x):
        h = 1e-4  # 0.0001
        grad = np.zeros_like(x)  # 生成和x形状相同的数组
        for idx in range(x.size):
            tmp_val = x[idx]
            # f(x+h)的计算
            x[idx] = tmp_val + h
            fxh1 = f(x)
            # f(x-h)的计算
            x[idx] = tmp_val - h
            fxh2 = f(x)
            # 计算导数
            grad[idx] = (fxh1 - fxh2) / (2 * h)
            x[idx] = tmp_val  # 还原值
        return grad

    def gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        grads = {}
        grads['W1'] = self.numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = self.numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = self.numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = self.numerical_gradient(loss_W, self.params['b2'])
        return grads

X_train, y_train, X_test, y_test = get_data()
train_size = X_train.shape[0]
batch_size = 100
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
# hyperparameters
iters_num = 10000
learning_rate = 0.1
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
for i in range(iters_num):
    # get mini-batch
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = X_train[batch_mask]
    y_batch = y_train[batch_mask]
    # calc gradient
    grad = network.numerical_gradient(x_batch, y_batch)
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
    loss = network.loss(x_batch, y_batch)
    train_loss_list.append(loss)
    # 计算每个epoch的识别精度
    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(X_train, y_train)
        test_acc = network.accuracy(X_test, y_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度学习基础PDF是一份介绍深度学习基本概念和原理的电子书。这本书内容丰富,旨在帮助读者了解深度学习基础知识和技术。 这本PDF首先介绍了神经网络的基本概念和结构。它详细讲解了多层感知机、卷积神经网络和循环神经网络等常见的神经网络模型。通过图文并茂的方式,读者可以深入了解神经网络的工作原理和设计思路。 进一步,这本书介绍了深度学习中常用的优化算法。它详细解释了梯度下降法、随机梯度下降法和自适应学习率算法等。读者可以学习这些算法的原理和应用,掌握如何有效地训练神经网络模型。 此外,这本书还讲解了常用的深度学习框架和工具。它介绍了TensorFlow、PyTorch和Keras等流行的深度学习框架,以及它们的特点和用法。这对于读者来说非常实用,可以帮助他们快速上手并开展自己的深度学习项目。 最后,这本PDF还提供了一些深度学习应用的案例研究。通过这些实例,读者可以看到深度学习在图像识别、自然语言处理和推荐系统等领域的应用。这些案例研究不仅丰富了读者的知识,还能激发他们将深度学习技术应用到自己感兴趣的领域中。 总之,深度学习基础PDF是一本内容详尽、图文并茂的电子书,为读者提供了学习深度学习的基本知识和技术所需的基础。无论是初学者还是有一定经验的深度学习从业者,都可以从中受益。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值