Python Numpy 实现神经网络自动训练:反向传播与激活函数的应用详解

news2024/10/26 19:00:43

Python Numpy 实现神经网络自动训练:反向传播与激活函数的应用详解

这篇文章介绍了如何使用 Python 的 Numpy 库来实现神经网络的自动训练,重点展示了反向传播算法和激活函数的应用。反向传播是神经网络训练的核心,能够通过计算梯度来优化模型参数,使得预测更加精准。文中详细演示了如何使用 Numpy 进行神经网络的前向预测、反向传播更新、误差计算,并通过引入 ReLU 等激活函数提升模型的非线性拟合能力。最后,通过对比训练前后的结果,展示了加入激活函数后模型性能的显著提升,适合初学者和爱好者学习神经网络的基础原理与应用。

文章目录

  • Python Numpy 实现神经网络自动训练:反向传播与激活函数的应用详解
      • 一 简单介绍反向传播
      • 二 用 Numpy 来做神经网络
        • 没有训练
        • 开始训练
      • 三 加入激活函数
        • 常用激活函数
        • 非线性计算,不加激活函数
        • 非线性计算,加入激活函数
      • 四 完整代码示例
      • 五 源码地址

一 简单介绍反向传播

反向传播(Backpropagation)是训练神经网络的核心算法,用于通过计算损失函数相对于网络各个参数的梯度,逐步优化这些参数,从而使模型的预测结果更加准确。使用梯度反向更新规则做神经网络参数优化调整。
这段代码计算每一层神经层的更新幅度,让神经网络对数据拟合变好,不理解先当工具方法记住。

def backprop(dz, layer, layer_in, learning_rate=0.01):
    """
    进行反向传播,更新当前层的权重和偏置,并计算传递给前一层的梯度。

    参数:
    dz: 当前层输出的梯度(损失函数对激活输出的偏导数)
    layer: 当前层的参数字典,包含权重 "w" 和偏置 "b"
    layer_in: 输入到当前层的激活值
    learning_rate: 学习率,用于控制参数更新的步长,默认值为 0.01

    返回:
    new_dz: 传递给前一层的梯度
    """

    # 计算损失函数对权重的梯度,layer_in.T 是当前层输入的转置,dot(dz) 进行矩阵乘法
    gw = layer_in.T.dot(dz)
    
    # 计算损失函数对偏置的梯度,按列求和,保留维度,求得每个偏置的梯度
    gb = np.sum(dz, axis=0, keepdims=True)
    
    # 计算传递给前一层的梯度,使用当前层的权重转置与 dz 相乘
    new_dz = dz.dot(layer["w"].T)
    
    # 更新当前层的权重:使用学习率乘以权重梯度,然后加到原有的权重上(梯度上升)
    layer["w"] += learning_rate * gw
    
    # 更新当前层的偏置:同样使用学习率乘以偏置梯度,然后加到原有的偏置上
    layer["b"] += learning_rate * gb
    
    # 返回传递给前一层的梯度,以便继续进行反向传播
    return new_dz

二 用 Numpy 来做神经网络

没有训练
def predict(x, l1, l2):
    o1 = x.dot(l1["w"]) + l1["b"]
    o2 = o1.dot(l2["w"]) + l2["b"]
    return [o1, o2]


def predict01():
    # 数据
    x = np.linspace(-1, 1, 10)[:, None]  # shape [10, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[10, 1]) + x  # shape [10, 1]

    # 搭建模型
    l1 = layer(1, 3)
    l2 = layer(3, 1)

    draw_line(x, predict(x, l1, l2)[-1])
    draw_scatter(x, y)

运行结果

在这里插入图片描述

可以看出在没有训练的时候,模型预测的结果与实际 y 值在数量级上存在较大差异。

开始训练
def predict02():
    # 数据
    x = np.linspace(-1, 1, 10)[:, None]  # shape [10, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[10, 1]) + x  # shape [10, 1]
    l1 = layer(1, 3)
    l2 = layer(3, 1)

    # 训练 50 次
    learning_rate = 0.01
    for i in range(50):
        # 前向预测
        o1, o2 = predict(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, o1)
        _ = backprop(dz1, l1, x)

    # 画一个训练后的图,对比上文中有数值问题的线
    draw_line(x, predict(x, l1, l2)[-1])
    draw_scatter(x, y)

运行结果

在这里插入图片描述

三 加入激活函数

常用激活函数
# 激活函数
def relu(x):
    return np.maximum(0, x)


def relu_derivative(x):  # 导数
    return np.where(x > 0, np.ones_like(x), np.zeros_like(x))


def tanh(x):
    return np.tanh(x)


def tanh_derivative(x):  # 导数
    return 1 - np.square(np.tanh(x))


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def sigmoid_derivative(x):  # 导数
    o = sigmoid(x)
    return o * (1 - o)

非线性计算,不加激活函数
def predict03():
    # 非线性计算
    x = np.linspace(-1, 1, 30)[:, None]  # shape [30, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[30, 1]) + x ** 2  # shape [30, 1]

    # draw_scatter(x, y)
    # 搭建模型
    l1 = layer(1, 10)
    l2 = layer(10, 1)

    # 训练 300 次
    learning_rate = 0.01
    for i in range(300):
        # 前向预测
        o1, o2 = predict(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, o1)
        _ = backprop(dz1, l1, x)

    draw_line(x, predict(x, l1, l2)[-1])
    draw_scatter(x, y)

运行结果

在这里插入图片描述

模型训练结果在量级上出现较大差距,欠拟合。

非线性计算,加入激活函数
def predict04():
    # 非线性计算
    x = np.linspace(-1, 1, 30)[:, None]  # shape [30, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[30, 1]) + x ** 2  # shape [30, 1]
    # 搭建模型
    l1 = layer(1, 10)
    l2 = layer(10, 1)
    # 训练 300 次
    learning_rate = 0.01
    for i in range(300):
        # 前向预测
        o1, a1, o2 = predictjihuo(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, a1)
        dz1 *= relu_derivative(o1)  # 这里要添加对应激活函数的反向传播
        _ = backprop(dz1, l1, x)

    draw_line(x, predictjihuo(x, l1, l2)[-1])
    draw_scatter(x, y)

运行结果

在这里插入图片描述

模型成功拟合了这些异常数据点,说明非线性激活函数确实非常有效。

四 完整代码示例

# This is a sample Python script.
from matplotlib import pyplot as plt
import numpy as np


# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
def draw_scatter(x, y):
    # 使用 matplotlib 的 scatter 方法来绘制散点图
    # x.ravel() 和 y.ravel() 将 x 和 y 的二维数组转换为一维数组,适合作为散点图的输入
    plt.scatter(x.ravel(), y.ravel())
    # 显示图表
    plt.show()


def draw_line(x, y):
    idx = np.argsort(x.ravel())
    plt.plot(x.ravel()[idx], y.ravel()[idx])
    # plt.show()


def layer(in_dim, out_dim):
    weights = np.random.normal(loc=0, scale=0.1, size=[in_dim, out_dim])
    bias = np.full([1, out_dim], 0.1)
    return {"w": weights, "b": bias}


# 激活函数
def relu(x):
    return np.maximum(0, x)


def relu_derivative(x):  # 导数
    return np.where(x > 0, np.ones_like(x), np.zeros_like(x))


def tanh(x):
    return np.tanh(x)


def tanh_derivative(x):  # 导数
    return 1 - np.square(np.tanh(x))


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def sigmoid_derivative(x):  # 导数
    o = sigmoid(x)
    return o * (1 - o)


def backprop(dz, layer, layer_in, learning_rate=0.01):
    """
    进行反向传播,更新当前层的权重和偏置,并计算传递给前一层的梯度。

    参数:
    dz: 当前层输出的梯度(损失函数对激活输出的偏导数)
    layer: 当前层的参数字典,包含权重 "w" 和偏置 "b"
    layer_in: 输入到当前层的激活值
    learning_rate: 学习率,用于控制参数更新的步长,默认值为 0.01

    返回:
    new_dz: 传递给前一层的梯度
    """

    # 计算损失函数对权重的梯度,layer_in.T 是当前层输入的转置,dot(dz) 进行矩阵乘法
    gw = layer_in.T.dot(dz)

    # 计算损失函数对偏置的梯度,按列求和,保留维度,求得每个偏置的梯度
    gb = np.sum(dz, axis=0, keepdims=True)

    # 计算传递给前一层的梯度,使用当前层的权重转置与 dz 相乘
    new_dz = dz.dot(layer["w"].T)

    # 更新当前层的权重:使用学习率乘以权重梯度,然后加到原有的权重上(梯度上升)
    layer["w"] += learning_rate * gw

    # 更新当前层的偏置:同样使用学习率乘以偏置梯度,然后加到原有的偏置上
    layer["b"] += learning_rate * gb

    # 返回传递给前一层的梯度,以便继续进行反向传播
    return new_dz


def predictjihuo(x, l1, l2):
    o1 = x.dot(l1["w"]) + l1["b"]
    a1 = relu(o1)  # 这里我添加了一个激活函数
    o2 = a1.dot(l2["w"]) + l2["b"]
    return [o1, a1, o2]


def predict(x, l1, l2):
    """
    预测函数,执行前向传播,计算两层神经网络的输出。

    参数:
    x: 输入数据,形状为 [N, 输入特征数],此处为 [10, 1]。
    l1: 第一层的参数字典,包含权重 "w" 和偏置 "b"。
    l2: 第二层的参数字典,包含权重 "w" 和偏置 "b"。

    返回:
    o1: 第一层的输出结果。
    o2: 第二层的输出结果(最终输出)。
    """
    # 第一层的输出,x.dot(l1["w"]) 是线性组合,+ l1["b"] 加上偏置
    o1 = x.dot(l1["w"]) + l1["b"]

    # 第二层的输出,o1.dot(l2["w"]) 是线性组合,+ l2["b"] 加上偏置
    o2 = o1.dot(l2["w"]) + l2["b"]

    # 返回两层的输出,o1 为第一层的输出,o2 为最终的输出
    return [o1, o2]


def predict01():
    """
    模拟预测和数据绘制函数,包含数据生成、模型搭建、前向预测和绘图。
    """
    # 生成输入数据 x,使用 np.linspace 生成从 -1 到 1 的 10 个均匀分布的点,并reshape为 [10, 1]
    x = np.linspace(-1, 1, 10)[:, None]  # 形状 [10, 1]

    # 生成目标值 y,基于 x 加上高斯噪声,模拟真实数据,形状为 [10, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[10, 1]) + x  # 形状 [10, 1]

    # 搭建神经网络模型
    # 第一层:输入维度为 1,输出维度为 3(即3个神经元)
    l1 = layer(1, 3)

    # 第二层:输入维度为 3,输出维度为 1
    l2 = layer(3, 1)

    # 使用 predict 函数进行前向传播,绘制预测结果
    # 只提取第二层的输出 o2 来绘制预测的线
    draw_line(x, predict(x, l1, l2)[-1])

    # 绘制真实数据点的散点图
    draw_scatter(x, y)


def predict02():
    # 数据
    x = np.linspace(-1, 1, 10)[:, None]  # shape [10, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[10, 1]) + x  # shape [10, 1]
    l1 = layer(1, 3)
    l2 = layer(3, 1)

    # 训练 50 次
    learning_rate = 0.01
    for i in range(50):
        # 前向预测
        o1, o2 = predict(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, o1)
        _ = backprop(dz1, l1, x)

    # 画一个训练后的图,对比上文中有数值问题的线
    draw_line(x, predict(x, l1, l2)[-1])
    draw_scatter(x, y)


def predict03():
    # 非线性计算
    x = np.linspace(-1, 1, 30)[:, None]  # shape [30, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[30, 1]) + x ** 2  # shape [30, 1]

    # draw_scatter(x, y)
    # 搭建模型
    l1 = layer(1, 10)
    l2 = layer(10, 1)

    # 训练 300 次
    learning_rate = 0.01
    for i in range(300):
        # 前向预测
        o1, o2 = predict(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, o1)
        _ = backprop(dz1, l1, x)

    draw_line(x, predict(x, l1, l2)[-1])
    draw_scatter(x, y)


def predict04():
    # 非线性计算
    x = np.linspace(-1, 1, 30)[:, None]  # shape [30, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[30, 1]) + x ** 2  # shape [30, 1]
    # 搭建模型
    l1 = layer(1, 10)
    l2 = layer(10, 1)
    # 训练 300 次
    learning_rate = 0.01
    for i in range(300):
        # 前向预测
        o1, a1, o2 = predictjihuo(x, l1, l2)

        # 误差计算
        if i % 10 == 0:
            average_cost = np.mean(np.square(o2 - y))
            print(average_cost)

        # 反向传播,梯度更新
        dz2 = -2 * (o2 - y)  # 输出误差 (o2 - y)**2 的导数
        dz1 = backprop(dz2, l2, a1)
        dz1 *= relu_derivative(o1)  # 这里要添加对应激活函数的反向传播
        _ = backprop(dz1, l1, x)

    draw_line(x, predictjihuo(x, l1, l2)[-1])
    draw_scatter(x, y)


def print_hi(name):
    # Use a breakpoint in the code line below to debug your script.
    print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.
    # 模型前向预测
    # 数据
    x = np.linspace(-1, 1, 10)[:, None]  # shape [10, 1]
    y = np.random.normal(loc=0, scale=0.2, size=[10, 1]) + x  # shape [10, 1]
    # draw_scatter(x, y)
    # 模型
    l1 = layer(1, 3)
    l2 = layer(3, 1)

    # 计算
    o = x.dot(l1["w"]) + l1["b"]
    print("第一层出来后的 shape:", o.shape)

    o = o.dot(l2["w"]) + l2["b"]
    print("第二层出来后的 shape:", o.shape)

    print("output:", o)
    # draw_scatter(x, o)
    # 简单介绍反向传播
    # predict01()
    # predict02()
    # 加入激活函数
    # 非线性计算,没有激活函数的网络训练,量级上的差距大
    # predict03()
    # 非线性计算,加入激活函数
    predict04()


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    print_hi('神经网络-自动训练')

# See PyCharm help at https://www.jetbrains.com/help/pycharm/

复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。

Hi, 神经网络-自动训练
第一层出来后的 shape: (10, 3)
第二层出来后的 shape: (10, 1)
output: [[0.08015376]
 [0.08221984]
 [0.08428592]
 [0.086352  ]
 [0.08841808]
 [0.09048416]
 [0.09255024]
 [0.09461632]
 [0.0966824 ]
 [0.09874848]]
0.2226335913018929
0.18084056623965614
0.17646520657891238
0.16955062165383475
0.15974897747454914
0.14609449775016456
0.12879398035319886
0.11000871768876343
0.09272999949822598
0.07986100731357502
0.07149628207512877
0.06657668787644673
0.06412748050655417
0.06308965708664192
0.06255298788129363
0.06233764319523034
0.06229224784095634
0.062220235356859256
0.06227320308423159
0.06227607241875045
0.06218961938206315
0.062183519685144004
0.06220136162617964
0.062260925337883535
0.06228186644083771
0.062212564435570314
0.06214763225225857
0.062190709318072676
0.06225667345334308
0.06227302776778138

五 源码地址

代码地址:

国内看 Gitee 之 numpy/神经网络-自动训练.py

国外看 GitHub 之 numpy/神经网络-自动训练.py

引用 莫烦 Python

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unity项目导出安卓工程后,在AndroidStudio打包报错:unityLibrary:BuildIl2CppTask‘.

下面这个是我在unity开发者社区提问后,他们回答得: 解决方案:我这边按照这几个方案检查了下,NDK和JDK都没问题,最后重启电脑才解决的,应该是文件被锁定了,我用的windows系统的。 验证&#xff…

达梦数据守护集群_备库重建(二)

目录 1、概述 1.1 实验场景 1.2 实验环境 2、故障模拟 3、重建方案1 3.1 登录主库、联机备份 3.2 脱机还原备库 3.3 模拟新业务数据 3.4 主库备份归档 3.5 利用归档恢复备库 3.6 启动备库 3.7 验证 4、重建方案2 4.1 登录主库、联机备份 4.2 脱机还原备库 4.3 …

是否有必要考PG认证?

如今PG很火,我在BOSS招聘查了一下,确实很多职位需要PG.那么考个PG认证确实很有必要! 当然这么快给出肯定答案,这公众号是发不出来的.必须有300个字才可以哦! 大家友情支持下,点点广告! 听我来细说 1.2.3 本小仙40有余可以说是80后.我们这代80后什么好事都没捞着,糟糕的事没有…

基于docker 部署redis

1、拉取镜像 docker pull redis:latest如果拉取失败可以尝试下配置镜像源,具体参考如下,目前暂可以使用 Docker切换镜像源-CSDN博客 2、创建配置文件 mkdir /usr/local/redis/conf vim redis.conf bind 0.0.0.0#protected-mode no port 6379 tcp-b…

用更多的钱买电脑而不是手机

如果,我们对自己的定义是知识工作者,那么在工作、学习相关的电子设备投入上,真的别舍不得花钱。 需要留意的是,手机,对于大部分在电脑前工作的人,不是工作设备。在我看来,每年投入到电脑的钱&…

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…

基于C#开发游戏辅助工具的Windows底层相关方法详解

开发游戏辅助工具通常需要深入了解Windows操作系统的底层机制&#xff0c;以及如何与游戏进程进行有效交互。本文将基于C#语言&#xff0c;从Windows底层方法的角度来详细讲解开发游戏辅助工具的相关技术和概念。 一、游戏辅助工具的基本概述 游戏辅助工具&#xff0c;通常被称…

Java应用程序的测试覆盖率之设计与实现(三)-- jacoco cli 客户端

一、背景 上文已把覆盖率数据采集好了,并提供远程连接的tcp地址及端口。 jacoco cli文档jacoco cli jar包jacococli.jar 我下载好了,放在github工程里。 本文主要是介绍如何使用jacoco cli 客户端读取并生成覆盖率报告。 二、使用 1、dump覆盖率统计 java -jar doc/jacoc…

duilib的应用 在双屏异分辨率的显示器上 运行显示不出来

背景&#xff1a;win11&#xff0c;duilib应用&#xff0c;双显示器&#xff0c;两台分辨率相同&#xff0c;分别设置不同的缩放以后&#xff0c;应用运行以后&#xff0c;程序闪一下消失或者程序还在&#xff0c;但是UI显示不出来。 原因 窗口风格设置不合理&#xff0c;所以…

【办公类-57-01】美工室材料报销EXCEL表批量插入截图(图片)

背景需求&#xff1a; 我们班分到美工室&#xff0c;需要准备大量材料&#xff0c;根据原始的报销单EXCLE&#xff0c;里面有商品名称、图片、链接、单位、数量等信息 今天我和搭档一起填写新表&#xff0c;发现手机截图的图片插入EXCEL后非常大&#xff0c; 需要手动调整图片…

alovajs:前后端交互还能这么玩?

嘿&#xff0c;小伙伴们&#xff01;今天我要和大家分享一个超级有趣的发现。最近在折腾项目时&#xff0c;我遇到了一个叫 alovajs 的工具&#xff0c;它居然能帮我们构建 Client-Server 交互层&#xff01;听起来有点高大上&#xff0c;但其实超级实用。一起来探索这个新大陆…

JS+Springboot做一个交互Demo

背景&#xff1a;老大做了一个 SDK&#xff0c;包含字符加解密、文件加解密&#xff0c;要求能从前端访问&#xff0c;并且能演示的 Demo。 思路&#xff1a;html 写页面&#xff0c;js 发送请求&#xff0c;freemarker 做简单的参数交互&#xff0c;JAVA 后端处理。 一、项目依…

element 按钮变形 el-button样式异常

什么都没动&#xff0c;element UI的按钮变形了&#xff0c;莫名其妙&#xff0c;连官网的也变形了&#xff0c;换了其它浏览器又正常&#xff0c; 难道这是element UI的问题&#xff1f;NO&#xff0c;是浏览器的插件影响到了&#xff01;去扩展插件里面一个个关闭扩展&#x…

使用高德API和MapboxGL实现路径规划并语音播报

概述 本文使用高德API实现位置查询和路径规划&#xff0c;使用MapboxGL完成地图交互与界面展示&#xff0c;并使用Web Speech API实现行驶中路线的实时语音播报。 效果 Web Speech API简介 Web Speech API 使你能够将语音数据合并到 Web 应用程序中。Web Speech API 有两个部…

软件测试的重要一环:「性能测试」怎么做?

性能测试是软件测试中的重要一环&#xff0c;今天给大家介绍性能测试及如何使用RunnerGo完成性能测试任务。 性能测试是什么&#xff1f; 一句话概括&#xff1a;不断地通过不同场景的系统表现去探究系统设计与资源消耗之间的平衡&#xff0c;为开发人员提供消除瓶颈所需的诊…

IntelliJ IDEA 设置数据库连接全局共享

前言 在日常的软件开发工作中&#xff0c;我们经常会遇到需要在多个项目之间共享同一个数据库连接的情况。默认情况下&#xff0c;IntelliJ IDEA 中的数据库连接配置是针对每个项目单独存储的。这意味着如果你在一个项目中配置了一个数据库连接&#xff0c;那么在另一个项目中…

从零搭建开源陪诊系统:关键技术栈与架构设计

构建一个开源陪诊系统是一个涉及多种技术的复杂工程。为了让这个系统具备高效、可靠和可扩展的特点&#xff0c;我们需要从架构设计、技术栈选择到代码实现等方面进行全面的考量。本文将从零开始&#xff0c;详细介绍搭建开源陪诊系统的关键技术栈和架构设计&#xff0c;并提供…

C#中的委托、匿名方法、Lambda、Action和Func

委托 委托概述 委托是存有对某个方法的引用的一种引用类型变量。定义方法的类型&#xff0c;可以把一个方法当作另一方法的参数。所有的委托&#xff08;Delegate&#xff09;都派生自 System.Delegate 类。委托声明决定了可由该委托引用的方法。 # 声明委托类型 委托类型声…

汽车免拆诊断案例 | 2019 款奥迪 A6L 车行驶中偶发熄火

故障现象  一辆2019款奥迪A6L车&#xff0c;搭载2.0T发动机&#xff0c;累计行驶里程约为9万km。车主反映&#xff0c;车辆行驶中偶发熄火&#xff0c;故障频率较高。 故障诊断  接车后试车&#xff0c;起动发动机&#xff0c;可以正常起动着机。使用故障检测仪检测&#x…

ELK之路第一步——Elasticsearch集群的搭建以及踩坑记录

elasticSearch集群 前言一、架构二、下载三、虚拟机相关设置3.1 创建es用户3.2 为建es用户赋权sudo3.3 更换es目录所属用户 四、Elasticsearch配置文件修改4.1 修改elasticsearch.yml4.2 修改jvm.options4.3 修改jdk路径 五、启动六、启动报错七、可视化界面cerebro 前言 Elk&…