机器学习鱼书笔记(自用更新)

零、预知识

1.Numpy

使用

  1. 介绍:高效的操作多维数组的函数库。

  2. 安装:(前提已经安装了python)

    pip install numpy
    
  3. 导入

    import numpy as np
    
  4. 创建数组

    Numpy最重要的数据结构是多维数组(ndarray)。通过Numpy,你可以轻松创建数组:

    # 从Python列表创建一维数组
    arr1d = np.array([1, 2, 3, 4, 5])
    >[1, 2, 3, 4, 5]
    
    # 从Python嵌套列表创建二维数组
    arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >[[1, 2, 3],
      [4, 5, 6],
      [7, 8, 9]]
    
    # 创建全零数组
    zeros = np.zeros((3, 4))
    >[[0., 0., 0., 0.],
      [0., 0., 0., 0.],
      [0., 0., 0., 0.]]
    
    # 创建全一数组
    ones = np.ones((2, 3))
    >[[1., 1., 1.],
      [1., 1., 1.]]
    
    # 创建指定范围内的数组
    range_arr = np.arange(0, 10, 2)
    >[0, 2, 4, 6, 8]
    
    # 创建线性间隔的数组
    linspace_arr = np.linspace(0, 1, 5)
    >[0.  , 0.25, 0.5 , 0.75, 1.  ]
    
  5. 数组属性

    Numpy数组有许多属性,你可以通过它们来了解数组的维度、形状和元素类型:

    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    
    print(arr.shape)        # 获取数组的形状 n行m列 输出:(3, 3)
    print(arr.ndim)         # 获取数组的维度 输出:2
    print(arr.size)         # 获取数组的长度 输出:9
    print(arr.dtype)        # 获取数组的元素类型 输出:int64
    
  6. 数组操作

    Numpy提供了许多数组操作函数,使得数组的操作和计算变得简单高效:

    # 数组加法
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([4, 5, 6])
    result = arr1 + arr2
    >[5, 7, 9]
    
    # 数组乘法
    arr = np.array([1, 2, 3])
    result = arr * 2
    >[2, 4, 6]
    
    # 二维数组乘法
    x = np.array([[1, 2], [3, 4]])
    y = np.array([[2, 1], [3, 4]])
    >[[1, 2],   [[2, 1],
      [3, 4]]    [4, 3]]
    >[[2, 2],
      [12, 12]]
    
    # 矩阵乘法 点乘运算
    mat1 = np.array([[1, 2], [3, 4]])
    mat2 = np.array([[5, 6], [7, 8]])
    result = np.dot(mat1, mat2)
    >[[1, 2],     [[5, 6],
      [3, 4]]			 [7, 8]]
    >输出: [[19, 22],
            [43, 50]]
    
    # 数组索引和切片 与python内置数组操作一致
    arr = np.array([1, 2, 3, 4, 5])
    print(arr[0])         # 输出:1
    print(arr[1:4])       # 输出:[2, 3, 4]
    
    # 数组形状变换
    arr = np.array([1, 2, 3, 4, 5, 6])
    reshaped_arr = arr.reshape(2, 3)
    >[[1, 2, 3],
      [4, 5, 6]]
    
  7. 常用数学函数

    Numpy提供了许多常用的数学函数,可以直接应用于数组:

    arr = np.array([1, 2, 3, 4, 5])
    
    print(np.sum(arr))          # 输出:15
    print(np.mean(arr))         # 输出:3.0
    print(np.max(arr))          # 输出:5
    print(np.min(arr))          # 输出:1
    print(np.sin(arr))          # 输出:[0.84147098 0.90929743 0.14112001 -0.7568025  -0.95892427]
    print(np.cos(arr))          # 输出:[0.54030231 -0.41614684 -0.9899925 -0.65364362 0.28366219 0.96017029]
    print(np.power(arr, 2))     # 输出:[1,  4,  9, 16, 25]
    print(np.exp(arr))          # 输出:[2.71828183, 7.3890561, 20.08553692, 54.59815003, 148.4131591 ]
    

广播机制

广播是numpy中一种强大的机制,允许对不同形状的数组进行运算,而不需要显式地进行形状匹配或复制数据。

  1. 广播标量,下图将10当做2x2的矩阵来运算
    请添加图片描述

  2. 数组广播

    请添加图片描述
    通过以上的例子可以看到广播的原则都是低纬度向高纬度看齐,然后补全数据,再进行运算。

2.Matplotlib

Matplotlib是Python中最流行的数据可视化库之一,可以用来绘制图表内容。

安装Matplotlib

在开始之前,确保你已经安装了Python和Matplotlib。如果还没有安装Matplotlib,可以通过以下命令使用pip进行安装:

pip install matplotlib

导入Matplotlib

在使用Matplotlib之前,首先需要导入它。习惯上,我们使用以下方式导入Matplotlib并简写为plt

import matplotlib.pyplot as plt

1. 绘制简单的折线图

折线图是Matplotlib中最简单的图表类型之一,它用于显示数据随着变量的变化而变化的趋势。下面是一个简单的绘制折线图的例子:

# 示例数据
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

# 绘制折线图
plt.plot(x, y)

# 添加标题和标签
plt.title('简单折线图')
plt.xlabel('X轴')
plt.ylabel('Y轴')

# 显示图形
plt.show()

图形绘制如下

请添加图片描述

2.绘制散点图

散点图常用于显示两个变量之间的关系。下面是一个绘制散点图的例子:

# 示例数据
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

# 绘制散点图
plt.scatter(x, y)

# 添加标题和标签
plt.title('简单散点图')
plt.xlabel('X轴')
plt.ylabel('Y轴')

# 显示图形
plt.show()

请添加图片描述

3. 绘制柱状图

柱状图常用于比较不同类别的数据。下面是一个绘制柱状图的例子:

# 示例数据
categories = ['A', 'B', 'C', 'D', 'E']
values = [10, 25, 15, 30, 20]

# 绘制柱状图
plt.bar(categories, values)

# 添加标题和标签
plt.title('简单柱状图')
plt.xlabel('类别')
plt.ylabel('值')

# 显示图形
plt.show()

请添加图片描述

4. 绘制饼图

饼图常用于显示不同类别占总量的比例。下面是一个绘制饼图的例子:

# 示例数据
categories = ['A', 'B', 'C', 'D', 'E']
values = [10, 25, 15, 30, 20]

# 绘制饼图
plt.pie(values, labels=categories, autopct='%1.1f%%')

# 添加标题
plt.title('简单饼图')

# 显示图形
plt.show()

请添加图片描述

5. 自定义图形样式

Matplotlib允许我们自定义图形的样式,包括线条颜色、标记类型、图例等。例如:

x = np.arange(0,6, 0.1)
# 绘制sin图像
y1 = np.sin(x)
# 绘制cos图像
y2 = np.cos(x)

plt.plot(x, y1, label="sin", color='blue')
# 设置图线样式
plt.plot(x, y2, linestyle="--", color='red', label="cos")
plt.xlabel("x")
plt.ylabel("y")
plt.title("sin & cos")
plt.legend()
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9jJZ8AKc-1691499932714)(鱼书笔记.assets/image-20230728194801266.png)]

6.绘制其他图形的方法(总结于chatGPT)

plt.plot() # 绘制折线图。

plt.scatter() # 绘制散点图。

plt.bar() # 绘制柱状图。

plt.barh() # 绘制水平柱状图。

plt.hist() # 绘制直方图。

plt.pie() # 绘制饼图。

plt.boxplot() # 绘制箱线图。

plt.errorbar() # 绘制误差条形图。

plt.contour() # 绘制等高线图。

plt.imshow() # 绘制图像。

plt.polar() # 绘制极坐标图。

plt.stem() # 绘制离散序列的线型图。

plt.fill() 和 plt.fill_between() # 绘制填充图。

plt.stackplot() # 绘制堆叠区域图。

plt.barbs() # 绘制风羽图。

plt.quiver() # 绘制场矢量图。

plt.streamplot() # 绘制流线图。

plt.hexbin() # 绘制六边形二维直方图。

一、感知机

1.感知机原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yayXtuvz-1691499932714)(鱼书笔记.assets/image-20230726224334363.png)]

x1,x2是输入,y是输出,w1,w2是权值,x*w之和超过阀值θ时才会激活y
y = { 0    ( ω 1 x 1 + ω 2 x 2 ≤ θ ) 1    ( ω 1 x 1 + ω 2 x 2 > θ ) y = \begin{cases} 0 \,\,( \omega 1x1 + \omega2x2 \le \theta )\\ 1 \,\,( \omega 1x1 + \omega2x2 > \theta )\\ \end{cases} y={0(ω1x1+ω2x2θ)1(ω1x1+ω2x2>θ)

可将 θ \theta θ 变为-b移到不等式左边,变换为如下表达式。其中 ω 1 \omega1 ω1 ω 2 \omega2 ω2 表示权重(用于控制各个信号的重要性),b表示偏置(用于控制神经元被激活的容易程度)。
y = { 0    ( b + ω 1 x 1 + ω 2 x 2 ≤ 0 ) 1    ( b + ω 1 x 1 + ω 2 x 2 > 0 ) y = \begin{cases} 0 \, \,( b+ \omega 1x1 + \omega2x2 \le 0 )\\ 1 \, \,( b+ \omega 1x1 + \omega2x2 > 0 )\\ \end{cases} y={0(b+ω1x1+ω2x20)1(b+ω1x1+ω2x2>0)

2.简单逻辑电路

与门 AND 代码实现

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

或门 OR 代码实现

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

与非门 NAND 代码实现

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

3.多层感知机的实现

单层的感知机,只能划分线性空间,想要实现异或门仅靠单层感知机无法实现,所以借助多层感知机进行非线性的空间划分可以解决异或门无法实现的问题。如下图所示,通过一个与非门,一个或门,一个与门相互连接实现了异或门的功能

请添加图片描述
请添加图片描述

  1. 第0层的两个神经元接收输入信号,并将信号发送至第1层的神经元。
  2. 第1层的神经元将信号发送至第2层的神经元,第2层的神经元输出y。

异或门 代码实现

def XOR(x1, x2):
  s1 = NAND(x1, x2)
  s2 = OR(x1, x2)
  y = AND(s1, s2)
  return y

二、神经网络

前面设计与或非门的权重值是人工设计的,后续通过学习神经网络,利用已有的数据学习合适的权重作为参数解决上面的权重问题。

请添加图片描述

1.激活函数

请添加图片描述

根据上图的函数转换,我们就能转换为h(x),这就是激活函数

激活函数类型

激活函数分为阶跃函数和sigmoid函数,其中阶跃函数就是当输入值超过某一阀值时就换转变输出。

  1. 阶跃函数

    定义如下
    h ( x ) = { 0    ( x ≤ 0 ) 1    ( x > 0 ) h(x) = \begin{cases} 0 \,\,( x \le 0 )\\ 1 \,\,( x > 0 )\\ \end{cases} h(x)={0(x0)1(x>0)
    代码实现

    import numpy as np
    import matplotlib.pylab as plt
    
    # 定义阶跃函数
    def step_function(x):
        y = x > 0
        return y.astype(int)
    
    X = np.arange(-5.0, 5.0, 0.1)
    Y = step_function(X)
    plt.plot(X, Y)
    plt.ylim(-0.1, 1.1)  # 指定图中绘制的y轴的范围
    plt.show()
    

请添加图片描述

  1. sigmoid函数

    定义如下
    h ( x ) = 1 1 + e x p ( − x ) h(x) = \frac{1}{1 + exp(-x)} h(x)=1+exp(x)1

    代码实现

    # coding: utf-8
    import numpy as np
    import matplotlib.pylab as plt
    
    # sigmoid函数
    def sigmoid(x):
        return 1 / (1 + np.exp(-x))    
    
    X = np.arange(-5.0, 5.0, 0.1)
    Y = sigmoid(X)
    plt.plot(X, Y)
    plt.ylim(-0.1, 1.1)
    plt.show()
    
    

请添加图片描述

两个激活函数对比

请添加图片描述

  • 共同点:有相似的形状、输入小时输出接近(等于)0,输入大时输出接近(等于)1、输出信号都在0到1之间。
  • 不同点:sigmoid函数是光滑的曲线,阶跃函数是跳跃的折线。

ReLU函数

大于0时直接输出x,小于等于0时输出0
h ( x ) = { x    ( x > 0 ) 0    ( x ≤ 0 ) h(x) = \begin{cases} x \,\,( x > 0 )\\ 0 \,\,( x \le 0 )\\ \end{cases} h(x)={x(x>0)0(x0)
代码实现

import numpy as np
import matplotlib.pylab as plt

# 定义reLU函数
def relu(x):
    return np.maximum(0, x)

x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)
plt.plot(x, y)
plt.ylim(-1.0, 5.5)
plt.show()

请添加图片描述

2.神经网络的内积

多维数组的运算

二维数组点乘二维数组的运算法则等同于线性代数中学习的矩阵相乘的结果。

使用二维数组点乘一维数组的运算过程中我发现与想象的不太一致。像如下两个数组进行点乘运算,按照线性代数中所学,b矩阵应该要求为2行1列。但使用np.array进行点乘运算结果没有问题。
请添加图片描述

以下总结了二维点乘一维数组的运算规律

请添加图片描述
请添加图片描述

神经网络的内积

请添加图片描述

实现该神经网络时,要注意X、W、Y的形状,特别是X和W的对应维度的元素个数是否一致。

代码实现

请添加图片描述

3层神经网络的实现

请添加图片描述

其中符号的含义
请添加图片描述

  1. 实现第0层到第一层,在上图x1和x2的基础上加上了b1
    请添加图片描述

    用数学式表示 a 1 a_1 a1 如下
    a 1 ( 1 ) = ω 11 ( 1 ) x 1 + ω 12 ( 1 ) x 2 + b 1 ( 1 ) a^{(1)}_1 = \omega^{(1)}_{11}x_1 + \omega^{(1)}_{12}x2 + b^{(1)}_1 a1(1)=ω11(1)x1+ω12(1)x2+b1(1)
    根据矩阵点乘算法规则,那么可以将第一层的加权表示成下面的数学式
    A ( 1 ) = X W ( 1 ) + B ( 1 ) A^{(1)} = XW^{(1)} + B^{(1)} A(1)=XW(1)+B(1)
    请添加图片描述

    代码实现

    X = np.array([1.0, 0.5])
    W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    B1 = np.array([0.1, 0.2, 0.3])
    A1 = np.dot(X, W1) + B1
    
  2. 实现下图a1到z1激活函数的转变(sigmoid函数)

请添加图片描述

代码实现

Z1 = sigmoid(A1)
print(A1) # [0.3 0.7 1.1]
print(Z1) # [0.57444252 0.66818777 0.75026011]
  1. 同理实现第一层到第二层的传递

请添加图片描述

代码实现

W2 = np.array([[0.1, 0.4],[0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])
print(Z1.shape) # (3,)
print(W2.shape) # (3, 2)
print(B2.shape) # (2,)
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
  1. 第2层到第3层(输出层)也跟上面步骤基本一致,但激活函数不同
    请添加图片描述

    代码实现

    # 定义恒等函数
    def identity_function(x):
        return x
    
    W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
    B3 = np.array([0.1, 0.2])
    A3 = np.dot(Z2, W3) + B3
    Y = identity_function(A3)
    

    这里定义的恒等函数,会将输入按照原样输出,这里用恒等函数是为了和前面第0层到第1层和第1层到第2层的处理流程保持一致

  2. 总体代码实现

    def identity_function(x):
        return x
    
    # 权重和偏置的初始化  
    def init_network():
        network = {}
        network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
        network['b1'] = np.array([0.1, 0.2, 0.3])
        network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
        network['b2'] = np.array([0.1, 0.2])
        network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
        network['b3'] = np.array([0.1, 0.2])
    
        return network
    
    # 将输入信号转换为输出信号的方法
    def forward(network, x):
        W1, W2, W3 = network['W1'], network['W2'], network['W3']
        b1, b2, b3 = network['b1'], network['b2'], network['b3']
    
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        z2 = sigmoid(a2)
        a3 = np.dot(z2, W3) + b3
        y = identity_function(a3)
    
        return y
    
    network = init_network()
    # 定义两个输入x的初值
    x = np.array([1.0, 0.5])
    y = forward(network, x)
    print(y)  # [0.31682708 0.69627909]
    

感知机中神经元流动的是0或1的二元信号,而神经网络中流动的是连续的实数值信号。

神经网络的激活函数必须使用非线性函数。因为使用线性函数的话,加深神经网络的层数将没有意义

一般而言,对于输出层的激活函数,回归问题用恒等函数,分类问题用softmax函数。

3.输出层的设计

1.三种输出函数的类型

  1. 恒等函数,常用在回归问题上

    def identity_function(x):
        return x
    
  2. sigmoid函数,用在二元分类问题上
    h ( x ) = 1 1 + e x p ( − x ) h(x) = \frac{1}{1 + exp(-x)} h(x)=1+exp(x)1

    def sigmoid(x):
        return 1 / (1 + np.exp(-x))    
    
  3. softmax函数,用在多元分类问题上
    y k = e x p ( a k ) ∑ i = 1 n e x p ( a i ) y_k = \frac{exp(a_k)}{\sum_{i=1}^n exp(a_i)} yk=i=1nexp(ai)exp(ak)

    def softmax(a):
        exp_a = np.exp(a)
        sum_exp_a = np.sum(exp_a)
        y = exp_a / sum_exp_a
    
        return y
    

    其中softmax函数表示在各输出之间都有收到输入信号的影响,如图

    请添加图片描述

2.softmax函数溢出改进

之所以要改进softmax函数,是因为计算机所表示的数字是有界限的,比如32位或64位,而 e x e^x ex 可以可以很大,会超过64位所表示数字的最大值,于是对softmax函数进行如下的改进:(1)分子分母同乘以一个常数(2)将常数移到指数函数内部,记为 l o g C logC logC (3)用另一个常数替换 l o g C logC logC(4)实例中常用0减去a数组中的最大值C: $ -C $替换这个 C ′ C' C
请添加图片描述

例子:

请添加图片描述

代码实现改进后的softmax函数

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

3.softmax函数特征

请添加图片描述

我们可以看到输出的y都在0-1之间,且它们的和为1,所以我们可以把他转为概率问题,也就是说输出的越大,他的概率越高,从上图可以看出,输入的a数组元素越大,输出的数组对应元素(即概览)也越大;另外e^x是一个单调递增函数,所以上例中a元素的大小关系和y的大小关系不变,y[2]最大,所以我们在实际上根本不需要softmax函数,直接看a元素就能知道哪个概率最大了(因为softmax需要指数运算,计算量挺大的)

求解机器学习问题的步骤可以分为“学习”和“推理”两个阶段。在学习阶段进行模型的学习,然后,在推理阶段,用学到的模型对未知的数据进行推理(分类)。如前所述,推理阶段一般会省略输出层的softmax函数。在输出层使用softmax函数是因为它和神经网络的学习有关系

4.输出神经元数量

请添加图片描述

由上图可以知道,输出神经元数量由类别数量决定,如输出结果为0-9这10个类别,那么神经元输出则为10个。

4.手写数字识别

三、神经网络的学习

神经网络的学习指的是根据训练数据找出相关权重参数的过程

1.从数据中学习

  1. 数字识别的方案

请添加图片描述

  1. 训练数据和测试数据

    1.训练数据和测试数据:训练数据为监督数据,就是用来训练模型的,而测试数据就是不包含在训练模型内的数据,用来评判训练后模型好坏的数据。

    2.泛化能力:泛化能力其实就是先训练数据训练模型,然后用测试数据进行测试模型,如果测试的成绩好那么他的泛化能力就好。

    3.过拟合:根据训练数据训练出来的模型,他可以很好的处理测试已经训练过的数据,但是对没有测试过的测试数据却无法处理,所以模型和训练数据太过拟合以至于没有很好的泛化能力

2.损失函数

损失函数是用来评判神经网络好坏的一个重要指标,越低越好,一般有2种评判方法均方误差交叉熵误差

one-hot表示法:仅正确标签为1,其余为0

1.均方误差

  • 数学表达式:
    E = 1 2 ∑ k ( y k − t k ) 2 E = \frac{1}{2}\sum_{k}(y_k - t_k)^2 E=21k(yktk)2

    y k y_k yk表示神经网络的输出, t k t_k tk表示监督数据,k表示数据的维数。

  • 代码:

    import numpy as np
    
    def mean_squared_error(y, t):
        return 0.5 * np.sum((y - t) ** 2)
    
  • 实例:

请添加图片描述

2.交叉熵误差

  • 数学表达式:
    E = − ∑ k ( t k l o g e y k ) E = -\sum_{k} (t_klog_ey_k) E=k(tklogeyk)
    其中log表示以e为底的自然对数, y k y_k yk是神经网络的输出, t k t_k tk是正确解标签。并且 t k t_k tk中只有正确解的索引标签为1,其余为0(one-hot表示)

  • 代码实现:

    def corss_entropy_error(y, t):
        # 在Python中,1e-7 是一个表示科学计数法的数值,也称为浮点数。它表示的是数字 1 乘以 10 的负7次方,即 0.0000001。科学计数法用于表示非常大或非常小的数值,以便简化表示和处理。在这种情况下,1e-7 表示一个非常接近零的小数值。
        delta = 1e-7
        # log表示以e为底数的自然对数
        return -np.sum(t * np.log(y + delta))
    

    代码如下代码中加上了一个微小值delta,因为当出现np.log(0)时会变为负无限大的-inf,这样会导致后续计算无法进行。添加微小值可以防止负无限大的发生。

    因为只有t为1时才计算,所以计算量比均方误差小,同时log是个负数的单调递增函数,趋向于0,所以y越大则E的结果越趋向于0,那么其误差结果就越小。

  • 实例:

请添加图片描述

从上图可以看到第一个例子正确时概率高,损失函数的结果低,所以他的神经网络模型好。

3.mini-batch学习

E = − 1 N ∑ n ∑ k ( t n k l o g e ( y n k ) ) E=-\frac{1}{N}\sum_n\sum_k(t_{nk} log_e(y_{nk})) E=N1nk(tnkloge(ynk))

这里,假设数据有N个, t n k t_{nk} tnk表示第n个数据的第k个元素的值( y n k y_{nk} ynk是神经网络的输出, t n k t_{nk} tnk是监督数据)。以上表达式就是将N个数据的损失函数的值取平均值。

# 改良交叉熵误差函数的实现
def cross_entropy_error_improved(y, t):
    # y的维度为1时
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    
    batch_size= y.shape[0]
    # 以下是t为one-hot表示形式的实现
    return -np.sum(t * np.log(y + 1e-7)) / batch_size
    # 以下是标签表示法,np.arange(batch_size)会生成一个0到batch_size-1的数组
    # return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

mini-batch简单说就是采取部分样本计算出的结果近似看为整体的计算结果。

在进行神经网络的学习时,不能将识别精度作为指标。因为如果以识别精度为指标,则参数的导数在绝大多数地方都会变为0。

得益于sigmoid函数的斜率不为0,神经网络的学习才得以正确进行。

3.数值微分

1.导数

导数的定义:表示函数某一点的瞬间变化率,数学表达式如下
d f ( x ) d x = lim ⁡ h → 0 f ( x + h ) − f ( x ) h \frac{df(x)}{dx} = \lim_{h\rightarrow0} \frac{f(x+h) - f(x)}{h} dxdf(x)=h0limhf(x+h)f(x)
考虑代码实现求函数的导数,可以将h设置为非常非常小的值,如 1 0 − 50 10^{-50} 1050,则代码如下:

def numerical_diff(f, x):
  h = 1e-50 # 0.0001
  return (f(x+h) - f(x)) / h

需改进点:

  • 1 0 − 50 10^{-50} 1050在Python中会产生舍入误差(rounding error)。如下运行的结果

    >>> np.float32(1e-50)
    0.0
    

    使用float32类型的浮点数表示 1 0 − 50 10^{-50} 1050则直接变成了0.0,无法正确表示。所以需要改进这个微小值。这里考虑使用 1 0 − 4 10^{-4} 1041e-4

  • f(x+h)-f(x)/h(向前差分)这个误差也很大,因为根据1的改变,h不是一个趋近于0的数,所以误差变大,应该用中心法改成f(x+h)-f(x-h)/2h(中心差分)
    请添加图片描述

改进后代码:

def numerical_diff(f, x):
  h = 1e-4 # 0.0001
  return (f(x+h) - f(x-h)) / (2*h)

注意:这种利用微小差分的导数过程为数值微分,而用数学公式推导的如y=x²导数为y=2x这种交解析性求导,这种叫做真导数

2.一个微分的例子

如:y=0.01x²+0.1x的导数实现

运行结果如下:

请添加图片描述

可以发现改进后的微分代码误差非常小

3.偏导数

一个函数有多个自变量时的导数成为偏导数,表达式 ∂ f ∂ x 0 \frac{\partial f}{\partial x_0} x0f ∂ f ∂ x 1 \frac{\partial f}{\partial x_1} x1f


f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0, x_1) = x_0^2 + x_1^2 f(x0,x1)=x02+x12
使用matplotlib绘制的图像如下

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 创建数据点
x0 = np.linspace(-10, 10, 100)
x1 = np.linspace(-10, 10, 100)
# 使用 np.meshgrid 函数可以将这两个一维数组转换为两个二维数组 x0 和 x1,这将构成我们的网格。
x0, x1 = np.meshgrid(x0, x1)
f = x0**2 + x1**2

# 创建 3D 图像
fig = plt.figure()
# projection='3d' 指定这是一个三维图像
ax = fig.add_subplot(111, projection='3d')

# 绘制曲面
# cmap='viridis' 指定了颜色映射,这里使用了 Viridis 颜色映射
ax.plot_surface(x0, x1, f, cmap='viridis')

# 设置轴标签
ax.set_xlabel('x0')
ax.set_ylabel('x1')
ax.set_zlabel('f(x0, x1)')

# 显示图像
plt.show()

请添加图片描述

偏导数实现:原理其实跟一元导数一样,就是带入一个真值消除一个变量而已

请添加图片描述

4.梯度

由全部变量的偏导数汇总而成的向量( ∂ f ∂ x 0 \frac{\partial f}{\partial x_0} x0f ∂ f ∂ x 1 \frac{\partial f}{\partial x_1} x1f)称为梯度

比如我们求一个函数y=x0²+x1²变量有x0,x1,当我们对他全部变量(这里最多只有2个)进行偏导汇总而成的变量叫梯度。

实现梯度的代码如下

# 实现梯度
def numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)

    for idx in range(x.size):
        tem_val = x[idx]
        # f(x + h) 的计算
        x[idx] = tem_val + h
        fxh1 = f(x)

        # f(x - h) 的计算
        x[idx] = tem_val - h
        fxh2 = f(x)

        grad[idx] = (fxh1 - fxh2) / (2 * h)
        x[idx] = tem_val # 还原倍数
    
    return grad

请添加图片描述

从这个图可以看出,梯度指向函数 f ( x 0 , x 1 ) f(x_0,x_1) f(x0,x1)的最低处(最小值),就像指南针一样,所有的箭头都指向同一点。其次我们发现,离“最低处”越远,箭头越大。梯度指示的方向是各点处的函数值减小最多的方向,这是一个重要的性质

1.梯度法

在梯度法中,函数的取值从当前位置沿着梯度方向前进一段距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此反复,不断地沿梯度方向前进。像这样不断的沿梯度方向前进,逐渐减小函数值的过程就是梯度法,用数学表达式来表示则如下所示

x 0 = x 0 − η ∂ f ∂ x 0 x_0 = x_0 - \eta\frac{\partial f}{\partial x_0} x0=x0ηx0f

x 1 = x 1 − η ∂ f ∂ x 1 x_1 = x_1 - \eta\frac{\partial f}{\partial x_1} x1=x1ηx1f

其中, η \eta η表示更新量,在神经网络的学习中,称为学习率。学习率决定在一次更新中更新的程度。

梯度下降算法代码实现:

# 梯度下降法找最小值
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

用梯度法求函数 f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0, x_1) = x_0^2 + x_1^2 f(x0,x1)=x02+x12的最小值如下

请添加图片描述

最终结果为(-6.11110793e-10 8.14814391e-10),非常接近(0,0)。实际上,真的最小值就是(0, 0)。所以说通过梯度法我们基本得到了正确结果。用图示来表示梯度法的更新过程则如下:

请添加图片描述

学习率 η \eta η不可过大也不可过小,太大时结果会发散成很大的数,太小的话结果几乎没更新就结束了

像学习率这样的参数称为超参数。这是一种和神经网络的参数(权重和偏置)性质不同的参数。相对于神经网络的权重参数是通过训练数据和学习算法自动获得的,学习率这样的超参数则是人工设定的。一般来说,超参数需要尝试多个值,以便找到一种可以使学习顺利进行的设定。

2.神经网络的梯度

我们有2*3的W权重参数,L为损失函数,梯度用 ∂ L ∂ W \frac{\partial L}{\partial W} WL表示,如下所示
W = { ω 11 ω 12 ω 13 ω 21 ω 22 ω 23 } W = \begin{Bmatrix} \omega_{11}&\omega_{12}&\omega_{13}\\ \omega_{21}&\omega_{22}&\omega_{23}\\ \end{Bmatrix} W={ω11ω21ω12ω22ω13ω23}

∂ L ∂ W = { ∂ L ∂ ω 11 ∂ L ∂ ω 12 ∂ L ∂ ω 13 ∂ L ∂ ω 21 ∂ L ∂ ω 22 ∂ L ∂ ω 23 } \frac{\partial L}{\partial W} = \begin{Bmatrix} \frac{\partial L}{\partial \omega_{11}}&\frac{\partial L}{\partial \omega_{12}}&\frac{\partial L}{\partial \omega_{13}}\\ \frac{\partial L}{\partial \omega_{21}}&\frac{\partial L}{\partial \omega_{22}}&\frac{\partial L}{\partial \omega_{23}}\\ \end{Bmatrix} WL={ω11Lω21Lω12Lω22Lω13Lω23L}

∂ L ∂ W \frac{\partial L}{\partial W} WL的元素由各个元素关于W的偏导数构成。比如,第一行第一列的元素 ∂ L ∂ ω 11 \frac{\partial L}{\partial \omega_{11}} ω11L表示当 ω 11 \omega_{11} ω11稍微变化时,损失函数L会发生多大变化。这里的重点是 ∂ L ∂ W \frac{\partial L}{\partial W} WL的形状和W相同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/65028.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

农商行基于分类分级的数据安全管控建设实践

《数据安全法》颁布实施以来&#xff0c;以分类分级为基础&#xff0c;对数据进行差异化管理和防护&#xff0c;成为行业共识。 金融行业作为数据密集的高地&#xff0c;安全是重中之重&#xff0c;而鉴于金融数据种类和内容庞杂&#xff0c;面临规模化用数、普惠用数、跨机构共…

分布式协议与算法——Paxos算法

目录 Paxos算法Basic Paxos算法三种角色如何达成共识&#xff08;协商过程&#xff09;小结&#xff1a; Multi-Paxos算法关于 Multi-Paxos 的思考领导者优化Basic PaxosChubby 的 Multi-Paxos 实现小结 参考 Paxos算法 Paxos论文 Paxos Made Simple 、author&#xff1a;Lesli…

wireshark 安装和使用

wireshark&#xff0c;世界上最受欢迎的网络协议分析器。是一个网络流量分析器&#xff0c;或“嗅探器”&#xff0c;适用于Linux、macOS、*BSD和其他Unix和类Unix操作系统以及Windows。它使用图形用户界面库Qt以及libpcap和npcap作为数据包捕获和过滤库。 wireshark&#xff…

Flamingo

基于已有的图像模型和文本模型构建多模态模型。输入是图像、视频和文本&#xff0c;输出是文本。 Vision encoder来自预训练的NormalizerFree ResNet (NFNet)&#xff0c;之后经过图文对比损失学习。图片经过图像模型的输出是2D grid&#xff0c;视频按1FPS的频率采样后经过图…

【2种方法,jmeter用一个正则提取器提取多个值!】

jmeter中&#xff0c;用json提取器&#xff0c;一次提取多个值&#xff0c;这个很多人都会。但是&#xff0c;用正则提取器一次提取多个&#xff0c;是否可以呢&#xff1f; 肯定&#xff0c;很多人都自信满满的说&#xff0c;可以&#xff01;形如&#xff1a;token":&q…

Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

matlab使用教程(10)—脚本和函数

1.概述 MATLAB 提供了一个强大的编程语言和交互式计算环境。您可以使用此语言在 MATLAB 命令行中一次输入一个命令&#xff0c;也可以向某个文件写入一系列命令&#xff0c;按照执行任何 MATLAB 函数的相同方式来执行这些命令。使用 MATLAB 编辑器或任何其他文件编辑器可以创建…

使用HTTP隧道时如何应对目标网站的反爬虫监测?

在进行网络抓取时&#xff0c;我们常常会遇到目标网站对反爬虫的监测和封禁。为了规避这些风险&#xff0c;使用代理IP成为一种常见的方法。然而&#xff0c;如何应对目标网站的反爬虫监测&#xff0c;既能保证数据的稳定性&#xff0c;又能确保抓取过程的安全性呢&#xff1f;…

Gartner发布《2023年全球RPA魔力象限》:90%RPA厂商,将提供生成式AI自动化

8月3日&#xff0c;全球著名咨询调查机构Gartner发布了《2023年全球RPA魔力象限》&#xff0c;通过产品能力、技术创新、市场影响力等维度&#xff0c;对全球16家卓越RPA厂商进行了深度评估。 弘玑Cyclone&#xff08;Cyclone Robotics&#xff09;、来也&#xff08;Laiye&am…

Visual Studio Code中对打开的脚本格式统一

什么是Language Server Protocol (LSP)? Language Server Protocol&#xff08;语言服务器协议&#xff0c;简称LSP&#xff09;是微软在2016年提出的一套统一的通讯协议方案。LSP定义了一套编辑器或者IDE与语言服务器&#xff08;Language Server&#xff09;之间使用的协议&…

【笔记】移动光猫改桥接

1. 登录后台 移动光猫的超管和密码&#xff08;百度的&#xff09; 账号&#xff1a;CMCCAdmin 密码&#xff1a;aDm8H%MdA 浏览器访问 192.168.1.1 并登录 2. 选择连接 点击“网络”&#xff0c;在“连接名称”下拉框选择 INTENET_R_VID 字样的连接&#xff0c;并截图备…

构建Docker容器监控系统(Cadvisor +InfluxDB+Grafana)

目录 案例概述 Cadvisor InfluxDBGrafana 1.1、 Cadvisor 1.2、InfluxDB 1.3、Grafana 1.4、监控组件架构 1.5、开始部署 安装docker-ce 阿里云镜像加速器 创建自定义网络 创建influxdb容器 案例概述 Docker作为目前十分出色的容器管理技术&#xff0c;得到大量企业…

CTF流量题解http1.pcapng

使用Wireshark工具打开流量文件http1.pcapng&#xff0c;如下图所示。 在过滤检索栏输入http&#xff0c;wireshark自动进行过滤。

2023牛客暑期多校训练营6 A-Tree (kruskal重构树))

文章目录 题目大意题解参考代码 题目大意 ( 0 ≤ a i ≤ 1 ) , ( 1 ≤ c o s t i ≤ 1 0 9 ) (0\leq a_i\leq 1),(1 \leq cost_i\leq 10^9) (0≤ai​≤1),(1≤costi​≤109) 题解 提供一种新的算法&#xff0c;kruskal重构树。 该算法重新构树&#xff0c;按边权排序每一条边…

【OpenCV常用函数:轮廓检测+外接矩形检测】cv2.findContours()+cv2.boundingRect()

文章目录 1、cv2.findContours()2、cv2.boundingRect() 1、cv2.findContours() 对具有黑色背景的二值图像寻找白色区域的轮廓&#xff0c;因此一般都会先经过cvtColor()灰度化和threshold()二值化后的图像作为输入。 cv2.findContous(image, mode, method[, contours[, hiera…

STM32 低功耗学习

STM32 电源系统结构介绍 电源系统&#xff1a;VDDA供电区域、VDD供电区域、1.8V供电区域、后备供电区域。 器件的工作电压&#xff08;VDD&#xff09;2.0~3.6V 为了提高转换精度&#xff0c;给模拟外设独立供电。电压调节器为1.8V供电区域供电&#xff0c;且1.8V供电区域是电…

过滤器,监听器与拦截器的区别

过滤器&#xff0c;监听器与拦截器的区别 ​ 过滤器和监听器不是Spring MVC中的组件&#xff0c;而是Servlet的组件&#xff0c;由Servlet容器来管理。拦截器是Spring MVC中的组件&#xff0c;由Spring容器来管理 ​ Servlet过滤器与Spring MVC 拦截器在Web应用中所处的层次如…

代码随想录算法训练营day60

文章目录 Day60 柱状图中最大的矩形题目思路代码 Day60 柱状图中最大的矩形 84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图…

相关搜索量激增10000%!“芭比周边”产品火爆亚马逊!

据外媒报道&#xff0c;芭比娃娃是今年夏天最热的话题。今年7月份&#xff0c;“芭比娃娃”是亚马逊上搜索最多的词。第二季度&#xff0c;Shopify上的芭比娃娃销量激增了56%。知名玩具制造商美泰&#xff08;Mattel&#xff09;预计&#xff0c;受电影的推动&#xff0c;在未来…

数字员工助力农行安全生产数字化转型应用实践

党的二十大指出&#xff0c;“以数字中国建设助力中国式现代化&#xff0c;加快建设网络强国、数字中国”&#xff0c;2022年1月发布《“十四五”数字经济发展规划》提出&#xff0c;加强类人智能、自然交互与虚拟现实等技术研究。近年来&#xff0c;各大银行纷纷推出自己的数字…