神经网络的学习 求梯度
import sys, ossys.path.append(os.pardir)
import numpy as npfrom common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient# simpleNet类
class simpleNet:def __init__(self):self.W = np.random.rand(2, 3) # 随机形状为2*3的权重参数def predict(self, x): # 方法一:预测return np.dot(x, self.W) #表示输入 x 与权重 W 之间的点积,这相当于神经网络的前向传播。def loss(self, x, t): # 方法二:求损失函数值 x接受输入数据,t为真实值标签z = self.predict(x)y = softmax(z) # softmax的输出总和=1,可将softmax函数输出的结果称为概率loss = cross_entropy_error(y, t) # 交叉熵损失函数,值越小,表示越接近真实值return lossnet = simpleNet()#生成
print(net.W) #输出权重参数
x = np.array([0.6, 0.9])
p = net.predict(x)
print(p)print(np.argmax(p))#最大的索引值t=np.array([0,0,1])#正确标签为2print(net.loss(x,t))#求损失函数值#求梯度:
def f(W): #f(W)是为参数W可以在求权重函数中使用的兼容参数,类似于将W重构成f(W)?return net.loss(x,t)
dW=numerical_gradient(f,net.W)
print(dW)
common中用到的的function和gradient
import numpy as npdef softmax(x):if x.ndim == 2:x = x.Tx = x - np.max(x, axis=0)y = np.exp(x) / np.sum(np.exp(x), axis=0)return y.T x = x - np.max(x) # 溢出对策return np.exp(x) / np.sum(np.exp(x))def cross_entropy_error(y, t):if y.ndim == 1:t = t.reshape(1, t.size)y = y.reshape(1, y.size)# 监督数据是one-hot-vector的情况下,转换为正确解标签的索引if t.size == y.size:t = t.argmax(axis=1)batch_size = y.shape[0]return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
def numerical_gradient(f, x):h = 1e-4 # 0.0001grad = np.zeros_like(x)it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])while not it.finished:idx = it.multi_indextmp_val = x[idx]x[idx] = float(tmp_val) + hfxh1 = f(x) # f(x+h)x[idx] = tmp_val - h fxh2 = f(x) # f(x-h)grad[idx] = (fxh1 - fxh2) / (2*h)x[idx] = tmp_val # 还原值it.iternext() return grad
代码详解:
第一段:simpleNet
这段代码实现了一个简单的神经网络(simpleNet 类),并展示了如何计算神经网络的预测、损失函数值以及权重的梯度。接下来,我将逐行解释代码的作用和它的核心概念。
1. 导入模块
import sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient
import sys, os: 导入sys和os模块,允许你在程序中操作系统路径、环境变量等。sys.path.append(os.pardir): 将父目录添加到模块搜索路径中,以便可以访问父目录中的模块。os.pardir是上级目录的路径。import numpy as np: 导入 NumPy 库,常用于数组操作和数学计算。from common.functions import softmax, cross_entropy_error: 从common.functions模块中导入softmax和cross_entropy_error函数。softmax将网络的输出转化为概率分布,cross_entropy_error用于计算交叉熵损失。from common.gradient import numerical_gradient: 从common.gradient模块中导入numerical_gradient函数,用于计算梯度。
2. simpleNet 类
class simpleNet:def __init__(self):self.W = np.random.rand(2, 3) # 随机形状为2*3的权重参数
class simpleNet:定义了一个名为simpleNet的类,这个类是简单的神经网络模型。def __init__(self):构造函数初始化模型参数。self.W = np.random.rand(2, 3): 初始化权重W,它是一个 2×32 \times 3 的随机矩阵,表示有 2 个输入和 3 个输出神经元。
3. predict 方法
def predict(self, x): # 方法一:预测return np.dot(x, self.W) # 表示输入 x 与权重 W 之间的点积,这相当于神经网络的前向传播。
def predict(self, x):定义了一个方法predict,用于计算神经网络的输出。return np.dot(x, self.W): 计算输入x和权重矩阵W的点积。点积相当于神经网络的前向传播过程,得出每个神经元的激活值。
4. loss 方法
def loss(self, x, t): # 方法二:求损失函数值 x 接受输入数据,t 为真实标签z = self.predict(x)y = softmax(z) # softmax的输出总和=1,可将 softmax 函数输出的结果称为概率loss = cross_entropy_error(y, t) # 交叉熵损失函数,值越小,表示越接近真实值return loss
def loss(self, x, t):定义了一个计算损失的函数。x是输入数据,t是真实标签。z = self.predict(x): 调用predict方法计算输入x的预测值z。y = softmax(z): 使用softmax函数将输出z转化为概率分布。softmax函数将模型的原始输出转化为每个类别的概率。loss = cross_entropy_error(y, t): 使用交叉熵损失函数计算预测概率y和真实标签t之间的差异。交叉熵损失值越小,表示预测越接近真实值。return loss: 返回损失值。
5. 实例化并测试网络
net = simpleNet() # 生成 simpleNet 类的实例
print(net.W) # 输出权重参数
x = np.array([0.6, 0.9])
p = net.predict(x)
print(p)
print(np.argmax(p)) # 打印最大值的索引
net = simpleNet(): 创建一个simpleNet类的实例,初始化网络的权重。print(net.W): 打印权重W,它是一个 2×32 \times 3 的随机矩阵。x = np.array([0.6, 0.9]): 定义输入数据x,它是一个包含两个元素的数组。p = net.predict(x): 使用predict方法计算输入x的预测结果p。print(p): 打印预测结果p。print(np.argmax(p)): 打印p中最大的值的索引。np.argmax(p)返回数组p中最大元素的索引,通常用于分类任务,表示预测的类别。
6. 计算损失
t = np.array([0, 0, 1]) # 正确标签为2(即第三类)
print(net.loss(x, t)) # 求损失函数值
t = np.array([0, 0, 1]): 定义真实标签t,这里标签为[0, 0, 1],表示类别 2 的独热编码。print(net.loss(x, t)): 计算输入数据x与标签t之间的交叉熵损失,并打印出来。
7. 计算梯度
def f(W): # f(W) 是一个可以在求权重函数中使用的兼容参数,类似于将 W 重构成 f(W)?return net.loss(x, t)dW = numerical_gradient(f, net.W)
print(dW)
def f(W):定义了一个函数f(W),该函数用于计算给定权重W下的损失值。这个函数将net.loss(x, t)封装在其中,并接受W作为参数。dW = numerical_gradient(f, net.W): 使用numerical_gradient函数计算损失函数f(W)对权重W的数值梯度。numerical_gradient会通过数值差分方法计算梯度。print(dW): 打印计算得到的梯度dW,它表示每个权重参数对于损失函数的敏感程度。
总结
这段代码展示了一个简单的神经网络的实现,包括了:
- 网络的初始化(权重的随机生成)。
- 前向传播过程(通过点积和
softmax函数得到预测)。 - 损失函数的计算(使用交叉熵损失)。
- 计算损失对权重的梯度(使用数值梯度)。
通过这些步骤,代码展示了如何用 Python 构建一个简单的神经网络,并计算其梯度,从而为后续的优化(如梯度下降)做好准备。
function:激活函数softmax和求交叉熵误差
这段代码实现了两个常用的函数:softmax 和 cross_entropy_error,它们在神经网络中用于分类任务。接下来我会逐行解释这两个函数的作用和实现细节。
1. Softmax 函数
def softmax(x):if x.ndim == 2:x = x.T # 转置,使得每一列代表一个样本x = x - np.max(x, axis=0) # 减去每列的最大值,避免溢出y = np.exp(x) / np.sum(np.exp(x), axis=0) # 对每列应用 softmaxreturn y.T # 转置回原来的形状x = x - np.max(x) # 溢出对策,减去最大值避免指数溢出return np.exp(x) / np.sum(np.exp(x)) # 计算softmax
解释:
-
softmax 函数将一个向量或者矩阵(代表每个类的分数)转换成概率分布。它常用于神经网络的输出层,将原始的网络输出(称为“logits”)转换为类的概率。
-
if x.ndim == 2::检查输入x的维度。如果x是二维数组(形状为batch_size x class_num),即处理的是多个样本(一个小批量的数据),则执行以下代码:x = x.T:转置矩阵,使得每一列代表一个样本的数据。x = x - np.max(x, axis=0):减去每列的最大值,防止在计算指数时溢出。因为大数的指数值会导致计算中的溢出。y = np.exp(x) / np.sum(np.exp(x), axis=0):对每列的值应用 softmax 函数,得到每个类别的概率。np.exp(x)对每个元素求指数,np.sum(np.exp(x), axis=0)是对每列进行求和。return y.T:最后将矩阵转置回原来的形状。
-
x = x - np.max(x):如果x是一个一维数组(单个样本),则直接减去最大值,避免指数计算时的溢出。 -
return np.exp(x) / np.sum(np.exp(x)):计算 softmax 输出,返回每个类别的概率。
Softmax 特点:
- 输入值经过 softmax 函数后,输出的概率值总和为 1。
- 它将每个输出值转换为一个介于 0 和 1 之间的值,表示该类的预测概率。
2. 交叉熵损失函数(Cross-Entropy Error)
def cross_entropy_error(y, t):if y.ndim == 1:t = t.reshape(1, t.size) # 如果标签是1D,转换为2Dy = y.reshape(1, y.size) # 如果输出是1D,转换为2Dif t.size == y.size:t = t.argmax(axis=1) # 将标签转换为类索引(对于one-hot编码)batch_size = y.shape[0] # 获取批次大小return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size # 计算平均交叉熵损失
解释:
-
if y.ndim == 1::检查y是否是一维数组。如果y是一维数组,表示只有一个样本,接着将标签和预测的y重塑为二维数组,便于处理。 -
if t.size == y.size::检查t和y的尺寸。如果标签t和预测概率y的尺寸相同,则说明标签是 one-hot 编码。例如,标签为[0, 0, 1],表示类别 2。argmax(axis=1)将标签从 one-hot 编码转换为类别索引。即t.argmax(axis=1)变为2。 -
batch_size = y.shape[0]:获取样本的批次大小,即y的第一维的大小。 -
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size:np.arange(batch_size):生成批次大小的数组(从 0 到batch_size-1),表示样本的索引。y[np.arange(batch_size), t]:从预测概率y中选取对应类别t的概率值。t是每个样本的类别索引,y是一个矩阵,y[i, t[i]]会返回样本i在类别t[i]上的预测概率。np.log(y[np.arange(batch_size), t] + 1e-7):对每个样本的预测概率取对数,1e-7是防止概率值为 0,导致对数函数计算出无穷大。np.sum(...)/batch_size:求和并计算平均值,返回批次的平均交叉熵损失。
交叉熵损失:
交叉熵损失函数衡量了预测概率分布与实际标签之间的差异,特别适用于分类问题。它的值越小,表示模型的预测越准确。对于二分类任务和多分类任务,交叉熵是常用的损失函数。
总结:
- Softmax 函数将神经网络的原始输出转化为概率分布,用于分类问题。
- Cross-Entropy Error 计算模型的输出概率与实际标签之间的差异,用于量化模型的预测误差。
这两个函数常常一起使用,尤其是在多类分类任务中,softmax 用于生成分类概率,交叉熵损失用于衡量预测与真实标签的差异。
求函数的梯度值
这段代码实现了 数值梯度 的计算。数值梯度是通过有限差分方法来近似计算梯度的,常用于验证反向传播算法的正确性。接下来我将详细解释这段代码的每一部分。
1. numerical_gradient(f, x) 函数的作用
-
函数输入:
f: 目标函数。它接受一个输入x,并返回该输入对应的损失值。x: 参数x,是我们要计算梯度的输入,通常是模型的参数(如权重和偏置)。
-
函数输出:
grad: 数值梯度,表示目标函数对每个参数x的导数,形状与x相同。
2. 初始化和设置
h = 1e-4 # 设定一个小的值,用于计算有限差分
grad = np.zeros_like(x) # 创建一个与x相同形状的零矩阵,用于存储计算出来的梯度
h = 1e-4: 设定一个很小的值h,用于在计算梯度时做微小的偏移。h是差分方法中的步长,用来近似导数。grad = np.zeros_like(x): 创建一个与x形状相同的零矩阵grad,用来存储计算得到的梯度。
3. 使用 np.nditer 迭代 x
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
np.nditer(x)是 NumPy 中的一个迭代器,用于遍历x中的每一个元素。flags=['multi_index']: 允许获取每个元素的多维索引。op_flags=['readwrite']: 允许对x中的元素进行读取和修改。
4. 计算每个元素的数值梯度
while not it.finished:idx = it.multi_index # 获取当前元素的多维索引tmp_val = x[idx] # 保存当前元素的值x[idx] = float(tmp_val) + h # 将当前元素加上hfxh1 = f(x) # 计算 f(x + h)x[idx] = tmp_val - h # 将当前元素减去hfxh2 = f(x) # 计算 f(x - h)grad[idx] = (fxh1 - fxh2) / (2 * h) # 通过中心差分法计算梯度x[idx] = tmp_val # 还原当前元素的值it.iternext() # 移动到下一个元素
-
while not it.finished:: 这是一个循环,直到迭代器遍历完x中的所有元素。 -
idx = it.multi_index: 获取当前元素的索引。 -
tmp_val = x[idx]: 保存当前元素的原始值,以便在计算后将其还原。 -
x[idx] = float(tmp_val) + h: 将当前元素的值加上h,然后调用目标函数f(x)计算其值fxh1。 -
fxh1 = f(x): 计算函数在x + h处的值。 -
x[idx] = tmp_val - h: 将当前元素的值减去h,然后计算函数f(x)在x - h处的值fxh2。 -
fxh2 = f(x): 计算函数在x - h处的值。 -
grad[idx] = (fxh1 - fxh2) / (2 * h): 使用中心差分法计算梯度。中心差分法通过(f(x+h) - f(x-h)) / (2 * h)近似计算导数。 -
x[idx] = tmp_val: 还原当前元素的值,以便继续计算其他元素的梯度。 -
it.iternext(): 移动到下一个元素,继续计算梯度。
5. 返回结果
return grad
grad是一个与x形状相同的矩阵,包含了x中每个元素的数值梯度。
数值梯度的原理
数值梯度通过有限差分方法来近似计算。对于给定的函数 f(x),某个元素 x_i 的导数可以通过以下公式来近似:

其中:
x + h和x - h分别表示对x_i添加和减去微小偏移量h后的值。(f(x + h) - f(x - h)) / (2h)是使用中心差分法近似计算的梯度。
使用场景
数值梯度主要用于验证反向传播算法的正确性。在训练神经网络时,计算梯度是一个关键步骤。反向传播算法是基于链式法则计算的梯度,而数值梯度可以作为一种“手工”计算梯度的方式,帮助我们检查反向传播是否实现正确。
总结
- 这个
numerical_gradient函数通过对x中每个元素添加和减去一个小的h来计算数值梯度,采用了中心差分法。 - 数值梯度对于调试和验证梯度计算的正确性非常有用,特别是在训练神经网络时。
相关文章:
神经网络的学习 求梯度
import sys, ossys.path.append(os.pardir) import numpy as npfrom common.functions import softmax, cross_entropy_error from common.gradient import numerical_gradient# simpleNet类 class simpleNet:def __init__(self):self.W np.random.rand(2, 3) # 随机形状为2*…...
机器学习数学基础:24.随机事件与概率
一、教程目标 本教程致力于帮助零基础或基础薄弱的学习者,全面掌握概率论与数理统计的基础公式,透彻理解核心概念,熟练学会应用解题技巧,最终能够轻松应对期末或考研考试。 二、适用人群 特别适合那些对概率论与数理统计知识了…...
【NLP 24、模型训练方式】
你的痛苦,我都心疼,想为你解决 —— 25.2.15 一、按学习范式分类 1. 监督学习(Supervised Learning) 核心思想:使用带有标签(已知输入-输出对)的数据训练模型。 常见任务:分类&…...
【鸿蒙】ArkUI-X跨平台问题集锦
系列文章目录 【鸿蒙】ArkUI-X跨平台问题集锦 文章目录 系列文章目录问题集锦1、HSP,HAR模块中 无法引入import bridge from arkui-x.bridge;2、CustomDialog 自定义弹窗中的点击事件在Android 中无任何响应;3、调用 buildRouterMode() 路由跳转页面前,…...
AI向量数据库之LanceDB快速介绍
LanceDB LanceDB 是一个开源的向量搜索数据库,具备持久化存储功能,极大地简化了嵌入向量的检索、过滤和管理。 LanceDB的主要特点 LanceDB 的主要特点包括: 生产级向量搜索:无需管理服务器。 存储、查询和过滤向量、元数据以…...
嵌入式玩具--无人机字幕
day01 01-无人机-组成结构-上 哎,好,各位,那现在呢我们一起来看一下,就是咱们接下来要做的这个小项目啊。呃,当然这个名字有很多啊,就是这种飞行器有管,它叫四旋翼飞行器的,也有叫…...
CentOS7 安装配置FTP服务
CentOS7 安装配置FTP服务 CentOS7 安装配置FTP服务1. FTP简介2. 先行准备2.1 关闭防火墙2.2 关闭 SELinux 3.安装FTP软件包4. 创建 FTP 用户及目录4.1 创建 FTP 目录并设置权限4.2 防止 FTP 用户登录 Linux 终端4.3 创建 FTP 用户组及用户4.4 创建 FTP 可写目录 5. 配置ftp服务…...
几款dxf文件转Gcode的开源软件
以下是一些常用的开源软件,可以将DXF文件转换为Gcode: 1. **Inkscape with Gcode Tools** - **Inkscape** 是一款开源的矢量图形编辑器,支持DXF文件导入。通过安装 **Gcode Tools** 插件,可以将矢量图形转换为Gcode。 - 官网: [Inkscape](https://inkscape.org/) …...
【设计模式】03-理解常见设计模式-行为型模式(专栏完结)
前言 前面我们介绍完创建型模式和创建型模式,这篇介绍最后的行为型模式,也是【设计模式】专栏的最后一篇。 一、概述 行为型模式主要用于处理对象之间的交互和职责分配,以实现更灵活的行为和更好的协作。 二、常见的行为型模式 1、观察者模…...
【计算机网络】传输层数据段格式
在计算机网络中,数据段(Segment) 是传输层协议(如 TCP 或 UDP)使用的数据单元。TCP 和 UDP 的数据段格式有所不同,以下是它们的详细说明: 1. TCP 数据段格式 TCP(传输控制协议&…...
编程题-最大子数组和(中等-重点【贪心、动态规划、分治思想的应用】)
题目: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。 解法一(枚举法-时间复杂度超限): …...
网络将内网服务转换到公网上
当然,以下是根据您提供的描述,对内网端口在公网上转换过程的详细步骤,并附上具体例子进行说明: 内网端口在公网上的转换过程详细步骤 1. 内网服务配置 步骤说明: 在内网中的某台计算机(我们称之为“内网…...
本地通过隧道连接服务器的mysql
前言 服务器上部署了 mysql,本地希望能访问该 mysql,但是又不希望 mysql 直接暴露在公网上 那么可以通过隧道连接 ssh 端口的方式进行连接 从外网看,服务器只开放了一个 ssh 端口,并没有开放 3306 监听端口 设置本地免密登录 …...
跳跃游戏 II - 贪心算法解法
问题描述: 给定一个长度为 n 的 0 索引整数数组 nums,我们从数组的第一个元素 nums[0] 开始。每个元素 nums[i] 表示从索引 i 可以跳跃的最大长度,换句话说,从位置 i,你可以跳到位置 i j,其中 0 < j &…...
2. grafana插件安装并接入zabbix
一、在线安装 如果不指定安装位置,则默认安装位置为/var/lib/grafana/plugins 插件安装完成之后需要重启grafana 命令在上一篇讲到过 //查看相关帮助 [rootlocalhost ~]# grafana-cli plugins --help //从列举中的插件过滤zabbix插件 [rootlocalhost ~]# grafana…...
Linux第107步_Linux之PCF8563实验
使用PCF8563代替内核的RTC,可以降低功耗,提高时间的精度。同时有助于进一步熟悉I2C驱动的编写。 1、了解rtc_time64_to_tm()和rtc_tm_to_time64() 打开“drivers/rtc/lib.c” /* * rtc_time64_to_tm - Converts time64_t to rtc_time. * Convert seco…...
功能说明并准备静态结构
功能说明并准备静态结构 <template><div class"card-container"><!-- 搜索区域 --><div class"search-container"><span class"search-label">车牌号码:</span><el-input clearable placeho…...
pip 与 conda 的故事
pip 换源 pip 官方源 -i https://pypi.python.org/simple pip 清华源 -i https://pypi.tuna.tsinghua.edu.cn/simple pip 阿里源 -i https://mirrors.aliyun.com/pypi/simple PyTorch 安装 pip3 install torch torchvision torchaudio pip3 install torch torchvision torchaud…...
【05】RUST错误处理
文章目录 错误处理panic代码运行 ResutResult中的一些方法介绍传播错误?运算符 错误处理 建议是尽量用Result由调用者自行决定是否恢复,不恢复也可直接在Err中调用panic。代码分支不可能走的分支可panic。 需要panic的情况: 有害状态&#x…...
[免费]SpringBoot公益众筹爱心捐赠系统【论文+源码+SQL脚本】
大家好,我是老师,看到一个不错的SpringBoot公益众筹爱心捐赠系统,分享下哈。 项目介绍 公益捐助平台的发展背景可以追溯到几十年前,当时人们已经开始通过各种渠道进行公益捐助。随着互联网的普及,本文旨在探讨公益事业…...
算法【动态规划中使用观察优化枚举】
动态规划的问题中,已经写出了记忆化搜索的版本,还要写出严格位置依赖的版本,意义在于不仅可以进行空间压缩优化;关键还在于,很多时候通过进一步观察,可以优化枚举,让时间复杂度更好。优化枚举的…...
ML.Net二元分类
ML.Net二元分类 文章目录 ML.Net二元分类前言项目的创建机器学习模型的创建添加模型选择方案训练环境的选择训练数据的添加训练数据的选择训练数据的格式要预测列的选择模型评估模型的使用总结前言 ML.NET是由Microsoft为.NET开发者平台创建的免费、开源、跨平台的机器学习…...
visutal studio 2022使用qcustomplot基础教程
编译 下载,2.1.1版支持到Qt6.4 。 拷贝qcustomplot.h和qcustomplot.cpp到项目源目录(Qt project)。 在msvc中将它俩加入项目中。 使用Qt6.8,需要修改两处代码: L6779 # if QT_VERSION > QT_VERSION_CHECK(5, 2, …...
本地搭建自己的专属客服之OneApi关联Ollama部署的大模型并创建令牌《下》
这里写目录标题 OneApi1、渠道设置2、令牌创建 配置文件修改修改配置文件docker-compose.yml修改config.json到此结束 上文讲了如何本地docker部署fastGtp,相信大家也都已经部署成功了!!! 今天就说说怎么让他们连接在一起 创建你的…...
c#自动更新-源码
软件维护与升级 修复漏洞和缺陷:软件在使用过程中可能会发现各种漏洞和缺陷,自动更新可以及时推送修复程序,增强软件的稳定性和安全性,避免因漏洞被利用而导致数据泄露、系统崩溃等问题。提升性能:通过自动更新&#x…...
SIP中常见的服务器类型
在SIP(Session Initiation Protocol)网络中,除了B2BUA(Back-to-Back User Agent)、路由代理和媒体服务器外,还有其他类型的服务器。以下是所有类型的服务器及其作用、示例和其他相关信息的表格:…...
【C】初阶数据结构4 -- 双向循环链表
之前学习的单链表相比于顺序表来说,就是其头插和头删的时间复杂度很低,仅为O(1) 且无需扩容;但是对于尾插和尾删来说,由于其需要从首节点开始遍历找到尾节点,所以其复杂度为O(n)。那么有没有一种结构是能使得头插和头删…...
小爱音箱控制手机和电视听歌的尝试
最近买了小爱音箱pro,老婆让我扔了,吃灰多年的旧音箱。当然舍不得,比小爱还贵,刚好还有一台红米手机,能插音箱,为了让音箱更加灵活,买了个2元的蓝牙接收模块Type-c供电3.5接口。这就是本次尝试起…...
Kotlin Lambda
Kotlin Lambda 在探索Kotlin Lambda之前,我们先回顾下Java中的Lambda表达式,Java 的 Lambda 表达式是 Java 8 引入的一项强大的功能,它使得函数式编程风格的代码更加简洁和易于理解。Lambda 表达式允许你以一种更简洁的方式表示实现接口&…...
动态库与静态库:深入解析与应用
在软件开发中,库(Library)是预编译的代码集合,用于在多个程序之间共享功能。根据链接方式的不同,库主要分为两种类型:静态库(Static Library) 和 动态库(Dynamic Library…...
