2025-04-22 李沐深度学习5 —— 线性回归

文章目录

  • 1 案例介绍
    • 1.1 应用场景:美国房价预测
    • 1.2 核心假设
    • 1.3 线性回归与神经网络的关系
    • 1.4 平方损失(L2 Loss)
    • 1.5 训练模型:最小化损失
  • 2 基础优化算法
    • 2.1 梯度下降
    • 2.2 小批量随机梯度下降(Mini-batch SGD)
  • 3 实战:线性回归的从零实现
    • 3.1 生成数据集
    • 3.2 读取数据集
    • 3.3 初始化模型参数
    • 3.4 定义模型
    • 3.5 定义损失函数
    • 3.6 优化算法
    • 3.7 训练
  • 4 实战:线性回归的简易实现
    • 4.1 实现
    • 4.2 练习

硬件配置:

  • Windows 11
  • Intel®Core™i7-12700H
  • NVIDIA GeForce RTX 3070 Ti Laptop GPU

软件环境:

  • Pycharm 2025.1
  • Python 3.12.9
  • Pytorch 2.6.0+cu124
image-20250422103816056

1 案例介绍

1.1 应用场景:美国房价预测

​ 在美国买房时,买家需根据房屋信息(如卧室数量、卫生间数量、面积等)预测合理的成交价。

  • 输入数据:房屋特征(如 X1=卧室数X2=卫生间数X3=面积)。
  • 输出目标:预测成交价 Y
  • 实际挑战:卖家的标价和网站估价(如Redfin)仅为参考,最终需通过竞价决定成交价,因此准确预测至关重要。

1.2 核心假设

  • 房价由关键特征的加权和决定:
    Y = W 1 X 1 + W 2 X 2 + W 3 X 3 + b Y=W_1X_1+W_2X_2+W_3X_3+b Y=W1X1+W2X2+W3X3+b

    • W1, W2, W3:权重(反映各特征对价格的影响)。
    • b:偏差项(基础价格,如地段附加值)。
image-20250421222439982
  • 一般化形式(N 维输入):
    Y = W 1 X 1 + W 2 X 2 + ⋯ + W N X N + b Y=W_1X_1+W_2X_2+\cdots+W_NX_N+b Y=W1X1+W2X2++WNXN+b

    • 向量表示:Y = W^T X + bW为权重向量,X为特征向量)。
image-20250421222518416

1.3 线性回归与神经网络的关系

​ 单层神经网络:线性回归可视为最简单的神经网络。

image-20250421222558963
  • 结构:输入层(特征)→ 输出层(预测值),无隐藏层。
  • 权重 W 对应神经元的连接强度,b 对应激活阈值。
  • 类比生物神经元:输入信号加权求和后,若超过阈值则输出信号。
image-20250421222621559

1.4 平方损失(L2 Loss)

L = 1 2 ( Y − Y ^ ) 2 L=\frac{1}{2}(Y-\hat{Y})^2 L=21(YY^)2

  • Y:真实成交价,Ŷ:模型预测价。

  • 作用:量化预测误差,误差越小模型越准。

  • 为什么用1/2?

    求导时简化计算(导数变为 Y - Ŷ

image-20250421222721461

1.5 训练模型:最小化损失

  1. 训练数据:收集历史成交记录(如过去 6 个月的房屋数据)。
    • 数据矩阵 X(每行一个样本,每列一个特征),向量 Y(真实价格)。
image-20250421223015866
  1. 损失函数(全体数据):
    • 目标:找到 Wb 使 L(W, b) 最小。

L ( W , b ) = 1 2 N ∑ i = 1 N ( Y i − Y ^ i ) 2 L(W,b)=\frac1{2N}\sum_{i=1}^N(Y_i-\hat{Y}_i)^2 L(W,b)=2N1i=1N(YiY^i)2

image-20250421223105614
  1. 求解方法:

    • 闭式解(显示解):仅线性回归等简单模型存在。
      W ∗ = ( X T X ) − 1 X T Y W^*=(X^TX)^{-1}X^TY W=(XTX)1XTY

      • 通过矩阵运算直接计算最优权重。
    • 凸函数性质:损失函数是“碗形”,仅有一个全局最小值。

image-20250421223333847

2 基础优化算法

​ 线性回归有显示解(闭式解),但大多数机器学习模型(如神经网络)无法直接求解,需通过迭代优化逼近最优解。

核心目标是找到模型参数(如权重 W 和偏差 b),使损失函数(如平方误差)最小化。

2.1 梯度下降

基本思想

  • 初始化:随机选择参数初始值 W₀

  • 迭代更新:沿损失函数下降最快的方向(负梯度)逐步调整参数:
    W t = W t − 1 − η ⋅ ∇ L ( W t − 1 ) W_t=W_{t-1}-\eta\cdot\nabla L(W_{t-1}) Wt=Wt1ηL(Wt1)

    • η:学习率(步长),控制更新幅度。
    • ∇L:损失函数对参数的梯度(偏导数向量)。
image-20250421223818242

直观理解

  • 梯度方向:函数值上升最快的方向,负梯度即下降最快方向。
  • 学习率的作用:
    • 太小:收敛慢,需大量计算(如蜗牛爬坡)。
    • 太大:可能跳过最优解,甚至发散(如迈步过大跌入山谷)。

示例

  • 假设损失函数是“碗形”(凸函数),初始点 W₀ 在碗边缘。
  • 每次迭代沿最陡方向(负梯度)移动,逐步接近碗底(最小值)。
image-20250421223842433

2.2 小批量随机梯度下降(Mini-batch SGD)

动机

  • 传统梯度下降:每次计算需遍历全部样本(计算代价高)。
  • 随机梯度下降(SGD):每次随机选一个样本计算梯度(噪声大,不稳定)。
  • 折中方案:小批量(batch_size = B)随机采样,平衡效率和稳定性。
image-20250421224042141

批量大小(batch_size)的选择

  • 太小(如 B=1):
    • 无法利用 GPU 并行计算,训练波动大。
  • 太大(如 B=全数据集):
    • 内存不足,且可能包含冗余样本(如相似数据)。
  • 经验值:常用 3264128(需根据硬件和数据调整)。

3 实战:线性回归的从零实现

​ 首先导入相关包。

%matplotlib inline
import random
import torch
from d2l import torch as d2l

​ d2l 包下载链接:https://github.com/d2l-ai/d2l-zh?tab=readme-ov-file。

​ 只要将 d2l 文件夹放在项目中即可。d2l 导入了 numpy,pandas,matplotlib 这些常用包,自己手动安装即可。

image-20250421230239763

3.1 生成数据集

​ 为了简单起见,我们将根据带有噪声的线性模型构造一个人造数据集,任务是使用这个有限样本的数据集来恢复这个模型的参数。
​ 生成一个包含1000个样本的数据集,每个样本包含从标准正态分布中采样的 2 个特征。我们的合成数据集是一个矩阵 X ∈ R 1000 × 2 \mathbf{X}\in \mathbb{R}^{1000 \times 2} XR1000×2。使用线性模型参数 w = [ 2 , − 3.4 ] ⊤ \mathbf{w} = [2, -3.4]^\top w=[2,3.4] b = 4.2 b = 4.2 b=4.2 和噪声项 ϵ \epsilon ϵ 生成数据集及其标签( ϵ \epsilon ϵ 可以视为模型预测和标签时的潜在观测误差):
y = X w + b + ϵ \mathbf{y}= \mathbf{X} \mathbf{w} + b + \mathbf\epsilon y=Xw+b+ϵ
​ 在这里我们认为标准假设成立,即 ϵ \epsilon ϵ 服从均值为 0 的正态分布。为了简化问题,我们将标准差设为 0.01。

def synthetic_data(w, b, num_examples):  #@save# type: (Tensor, float, int) -> tuple[Tensor, Tensor]"""通过噪声生成y=Xw+b的数据集"""X = torch.normal(0, 1, size=(num_examples, len(w)))y = torch.matmul(X, w) + by += torch.normal(0, 0.01, y.shape)return X, y.reshape((-1, 1))true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
features.shape, labels.shape
image-20250421230627339

​ 通过生成第二个特征 features[:, 1]labels 的散点图, 可以直观观察到两者之间的线性关系。

d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)
d2l.plt.show()
image-20250421230729350

运行 d2l.plt.show() 时报错:

OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized. OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program. That is dangerous, since it can degrade performance or cause incorrect results. The best thing to do is to ensure that only a single OpenMP runtime is linked into the process, e.g. by avoiding static linking of the OpenMP runtime in any library. As an unsafe, unsupported, undocumented workaround you can set the environment variable KMP_DUPLICATE_LIB_OK=TRUE to allow the program to continue to execute, but that may cause crashes or silently produce incorrect results. For more information, please see http://www.intel.com/software/products/support/.

​ 这个错误是由于 OpenMP 运行时库冲突 导致的,libiomp5md.dll 被多次加载。PyTorch 和某些科学计算库(如 NumPy、Scipy)可能各自链接了不同版本的 OpenMP 运行时库。当多个副本被加载时,会导致冲突,出现 OMP: Error #15。常见于 Windows 系统上运行 PyTorch 或 NumPy。

解决方法

  • 方法 1(推荐):设置环境变量 KMP_DUPLICATE_LIB_OK=TRUE

    在代码 最开头 添加:

    import os
    os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"  # 允许重复加载 OpenMP 库(临时解决方案)
    
  • 方法 2:更新或重新安装 PyTorch 和 NumPy

    冲突可能是由于版本不匹配导致的,尝试:

    pip install --upgrade torch numpy
    

3.2 读取数据集

​ 定义一个data_iter函数, 该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size的小批量。 每个小批量包含一组特征和标签。

def data_iter(batch_size, features, labels):# type: (int, Tensor, Tensor) -> Iterable[tuple[Tensor, Tensor]]num_examples = len(features)indices = list(range(num_examples))# 随机打乱样本顺序以实现无偏采样random.shuffle(indices)# 按批次大小遍历整个数据集for i in range(0, num_examples, batch_size):# 获取当前批次的索引范围,处理最后一个批次可能不足的情况batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)])# 生成当前批次的特征和标签张量yield features[batch_indices], labels[batch_indices]

3.3 初始化模型参数

​ 在我们开始用小批量随机梯度下降优化我们的模型参数之前, 我们需要先有一些参数。

​ 在下面的代码中,我们通过从均值为 0、标准差为 0.01 的正态分布中采样随机数来初始化权重, 并将偏置初始化为 0。

w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
w, b
image-20250421231028318

3.4 定义模型

​ 计算输入特征 X \mathbf{X} X 和模型权重 w \mathbf{w} w 的矩阵-向量乘法后加上偏置 b b b

​ 注意,上面的 X w \mathbf{Xw} Xw 是一个向量,而 b b b 是一个标量。回想一下广播机制:当我们用一个向量加一个标量时,标量会被加到向量的每个分量上。

def linreg(X, w, b):  #@save# type: (Tensor, Tensor, Tensor) -> Tensor"""线性回归模型"""return torch.matmul(X, w) + b

3.5 定义损失函数

​ 使用平方损失函数。在实现中,我们需要将真实值y的形状转换为和预测值y_hat的形状相同。

def squared_loss(y_hat, y):  #@save# type: (Tensor, Tensor) -> Tensor"""均方损失"""return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

3.6 优化算法

​ 在每一步中,使用从数据集中随机抽取的一个小批量,然后根据参数计算损失的梯度。接下来,朝着减少损失的方向更新我们的参数。

​ 下面的函数实现小批量随机梯度下降更新。该函数接受模型参数集合、学习速率和批量大小作为输入。每 一步更新的大小由学习速率lr决定。因为我们计算的损失是一个批量样本的总和,所以我们用批量大小(batch_size) 来规范化步长,这样步长大小就不会取决于我们对批量大小的选择。

def sgd(params, lr, batch_size):  #@save# type: (Iterable[Tensor], float, int) -> None"""小批量随机梯度下降"""with torch.no_grad():for param in params:param -= lr * param.grad / batch_sizeparam.grad.zero_()

3.7 训练

​ 在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。计算完损失后,我们开始反向传播,存储每个参数的梯度。最后,我们调用优化算法sgd来更新模型参数。

​ 概括一下,我们将执行以下循环:

  • 初始化参数
  • 重复以下训练,直到完成
    • 计算梯度 g ← ∂ ( w , b ) 1 ∣ B ∣ ∑ i ∈ B l ( x ( i ) , y ( i ) , w , b ) \mathbf{g} \leftarrow \partial_{(\mathbf{w},b)} \frac{1}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} l(\mathbf{x}^{(i)}, y^{(i)}, \mathbf{w}, b) g(w,b)B1iBl(x(i),y(i),w,b)
    • 更新参数 ( w , b ) ← ( w , b ) − η g (\mathbf{w}, b) \leftarrow (\mathbf{w}, b) - \eta \mathbf{g} (w,b)(w,b)ηg

​ 在每个迭代周期(epoch)中,使用data_iter函数遍历整个数据集,并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。

​ 这里的迭代周期个数num_epochs和学习率lr都是超参数,分别设为 3 和 0.03。设置超参数很棘手,需要通过反复试验进行调整。

lr = 0.03  # 学习率
num_epochs = 3  # 迭代次数
batch_size = 10  # 批量大小
net = linreg
loss = squared_lossfor epoch in range(num_epochs):for X, y in data_iter(batch_size, features, labels):l = loss(net(X, w, b), y)  # X和y的小批量损失# 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,# 并以此计算关于[w, b]的梯度l.sum().backward()sgd([w, b], lr, batch_size)  # 使用参数的梯度更新参数# print('w:', w, 'b:', b)with torch.no_grad():train_l = loss(net(features, w, b), labels)print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
image-20250421231556090

​ 上述训练将 1000 个数据分为 100 批次,每个批次大小为 10。我们认为每个批次的 w 和 b 与总体一致。

​ 因此,每一次迭代中,训练 100 批次,一共迭代 3 次,即训练了 300 批次。

​ 通过比较真实参数和通过训练学到的参数来评估训练的成功程度。事实上,真实参数和通过训练学到的参数确实非常接近。

print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')
image-20250421231854328

​ 绘制图像比较真实数据(黄色直线)与拟合结果(红色虚线)。

d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)  # 绘制数据点
d2l.plt.plot(d2l.np.arange(-2, 3), d2l.np.arange(-2, 3) * true_w[1].detach().numpy() + true_b, color='yellow')  # 绘制真实直线
d2l.plt.plot(d2l.np.arange(-2, 3), d2l.np.arange(-2, 3) * w[1, :].detach().numpy() + b.detach().numpy(), color='red', linestyle='--')  # 绘制拟合直线
d2l.plt.show(), w, b
image-20250421231904985

4 实战:线性回归的简易实现

4.1 实现

​ 与上章类似,我们首先生成数据集。

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2ltrue_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)

​ 我们可以调用框架中现有的 API 来读取数据。 我们将featureslabels作为 API 的参数传递,并通过数据迭代器指定batch_size。 此外,布尔值is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据。

def load_array(data_arrays, batch_size, is_train=True):  #@save# type: (tuple[Tensor, Tensor], int, bool) -> data.DataLoader"""构造一个PyTorch数据迭代器"""dataset = data.TensorDataset(*data_arrays)return data.DataLoader(dataset, batch_size, shuffle=is_train)  # 随机选取 batch_size 大小的数据batch_size = 10
data_iter = load_array((features, labels), batch_size)

​ 使用data_iter的方式与上章中使用data_iter函数的方式相同。为了验证是否正常工作,让我们读取并打印第一个小批量样本。 这里我们使用iter构造 Python 迭代器,并使用next从迭代器中获取第一项。

next(iter(data_iter))
image-20250422104034310

​ 对于标准深度学习模型,我们可以使用框架的预定义好的层。

​ 首先定义一个模型变量net,它是一个Sequential类的实例。Sequential类将多个层串联在一起。当给定输入数据时,Sequential实例将数据传入到第一层,然后将第一层的输出作为第二层的输入,以此类推。在下面的例子中,我们的模型只包含一个层,因此实际上不需要Sequential。 但是由于以后几乎所有的模型都是多层的,在这里使用Sequential会让你熟悉“标准的流水线”。

​ 这一单层被称为全连接层(fully-connected layer), 因为它的每一个输入都通过矩阵-向量乘法得到它的每个输出。

# nn是神经网络的缩写
from torch import nnnet = nn.Sequential(nn.Linear(2, 1))

​ 在使用net之前,我们需要初始化模型参数。通过net[0]选择网络中的第一个图层, 然后使用weight.databias.data方法访问参数。 我们还可以使用替换方法normal_fill_来重写参数值。

net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
image-20250422104352926

​ 计算均方误差使用的是MSELoss类,也称为平方 L2 范数。 默认情况下,它返回所有样本损失的平均值。

​ 小批量随机梯度下降算法是一种优化神经网络的标准工具, PyTorch在optim模块中实现了该算法的许多变种。 当我们实例化一个SGD实例时,我们要指定优化的参数 (可通过net.parameters()从我们的模型中获得)以及优化算法所需的超参数字典。 小批量随机梯度下降只需要设置lr值,这里设置为 0.03。

loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

​ 在每个迭代周期里,我们将完整遍历一次数据集(train_data), 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量,我们会进行以下步骤:

  • 通过调用net(X)生成预测并计算损失l(前向传播)。
  • 通过进行反向传播来计算梯度。
  • 通过调用优化器来更新模型参数。

​ 为了更好的衡量训练效果,我们计算每个迭代周期后的损失,并打印它来监控训练过程。

num_epochs = 3
for epoch in range(num_epochs):for X, y in data_iter:l = loss(net(X), y)trainer.zero_grad()l.backward()# print(net[0].weight.grad)trainer.step()l = loss(net(features), labels)print(f'epoch {epoch + 1}, loss {l:f}')
image-20250422104554553

​ 下面我们比较生成数据集的真实参数和通过有限数据训练获得的模型参数。 要访问参数,我们首先从net访问所需的层,然后读取该层的权重和偏置。 正如在从零开始实现中一样,我们估计得到的参数与生成数据的真实参数非常接近。

w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)
image-20250422104629490

4.2 练习

  1. 如果我们用 nn.MSELoss(reduction=‘sum’) 替换 nn.MSELoss(),为了使代码的行为相同,需要怎么更改学习速率?为什么?

    答:这样替换的结果是会使得梯度值放大为原来的 num_example 倍,原有的学习率显得过大,使得其出现了振荡,即步长过长导致。应该把学习率除以 batch_size,因为默认参数是 'mean',换成 'sum' 需要除以批量数。一般会采用默认,因为这样学习率可以跟 batch_size 解耦。

  2. 如何访问线性回归的梯度?

    答:使用 net[0].weight.grad

    num_epochs = 3
    for epoch in range(num_epochs):for X, y in data_iter:l = loss(net(X), y)trainer.zero_grad()l.backward()print(net[0].weight.grad)trainer.step()l = loss(net(features), labels)print(f'epoch {epoch + 1}, loss {l:f}')
    
    image-20250422105844750

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

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

相关文章

你的大模型服务如何压测:首 Token 延迟、并发与 QPS

写在前面 大型语言模型(LLM)API,特别是遵循 OpenAI 规范的接口(无论是 OpenAI 官方、Azure OpenAI,还是 DeepSeek、Moonshot 等众多兼容服务),已成为驱动下一代 AI 应用的核心引擎。然而,随着应用规模的扩大和用户量的增长,仅仅关注模型的功能是不够的,API 的性能表…

数字化转型避坑指南:中钧科技如何用“四个锚点”破解转型深水区

数字化转型浪潮下,企业常陷入四大典型陷阱:跟风式投入、数据沼泽化、流程伪在线、安全裸奔化。中钧科技旗下产品以“经营帮”平台为核心,通过针对性方案帮助企业绕开深坑。 陷阱一:盲目跟风,为数字化而数字化 许…

时分复用、频分复用和码分复用简要比较分析

时分复用(TDM)、频分复用(FDM)和码分复用(CDM)是经典的多路复用技术,它们通过不同的方式共享信道资源。以下是两者的详细比较及其优缺点: 1. 原理对比 时分复用(TDM&…

MCP认证难题破解:常见技术难题实战分析与解决方案

MCP认证难题破解:常见技术难题实战分析与解决方案 一、引言:MCP认证——智能协作领域的“技术试金石” MCP(Multi-agent Communication Protocol)认证作为多智能体系统领域的权威认证,旨在考察考生对MCP协议设计、智能体协作架构、分布式系统优化等核心技术的掌握程度。…

最新iOS性能测试方法与教程

一、工具instrument介绍 使用Xcode的instrument进行测试,instrument自带了很多性能方面的测试工具,如图所示: 二、常见性能测试内容 不管是安卓还是iOS的性能测试,常见的性能测试都要包含这五个方面: 1、内存&#xff…

Vue el-checkbox 虚拟滚动解决多选框全选卡顿问题 - 高性能处理大数据量选项列表

一、背景 在我们开发项目中,经常会遇到需要展示大量选项的多选框场景,比如权限配置、数据筛选等。当选项数量达到几百甚至上千条时,传统的渲染方式全选时会非常卡顿,导致性能问题。本篇文章,记录我使用通过虚拟滚动实现…

JWT的token泄露要如何应对

文章目录 前言✅ 一、预防措施(防泄露)🚨 二、应急响应机制(发现已泄露)🔒 1. **启用 Token 黑名单机制**🔁 2. **启用 Refresh Token 机制 旋转令牌**📍 3. **强制下线机制**&…

24.中医知识问答删除历史对话功能前端代码实现

前端实现对话删除功能的完整指南 功能概述 前篇文章介绍了删除历史对话的后端开发,本篇将介绍如何在前端实现一个完整的对话删除功能,包括用户确认、API调用、状态管理和错误处理等关键环节。 功能拆解 1. 用户确认机制 javascript const confirmDe…

如何在 Python 项目中引入 Rust 函数

目录 1. 初始化 Python 项目2. 添加 Rust 开发工具3. 初始化 Rust 项目4. 开发模式构建5. 验证模块是否成功安装6. 测试 Rust 函数总结 (封面pid: 129416070) Python 是一门非常流行的编程语言,具有易于使用和开发的特点。然而,随着项目需求的增长和性能…

Java基础系列-HashMap源码解析2-AVL树

文章目录 AVL树左旋右旋左旋右旋的4种情况LL 型RR 型LR 型RL 型 实际插入时怎么判断是那种类型?插入时注意事项删除节点 AVL树 为避免BST树退化成链表的极端情况, AVL 树应运而生。 平衡因子取值(-1,0,1)…

新书速览|Hadoop与Spark大数据全景解析(视频教学版)

《Hadoop与Spark大数据全景解析:视频教学版》 01 本书内容 《Hadoop与Spark大数据全景解析:视频教学版》结合作者多年在大数据领域的开发实践经验,采用“理论实战”的形式,以大量实例全面介绍Hadoop和Spark的基础知识及其高级应用。作者将丰富的教学经…

TapData × 梦加速计划 | 与 AI 共舞,TapData 携 AI Ready 实时数据平台亮相加速营,企业数据基础设施现代化

在实时跃动的数据节拍中,TapData 与 AI 共舞,踏出智能未来的新一步。 4月10日,由前海产业发展集团、深圳市前海梦工场、斑马星球科创加速平台等联合发起的「梦加速计划下一位独角兽营」正式启航。 本次加速营以“打造下一位独角兽企业”为目…

[密码学基础]密码学常用名词深度解析:从基础概念到实战应用

密码学常用名词深度解析:从基础概念到实战应用 密码学是信息安全的基石,但其专业术语常令人望而生畏。本文系统梳理密码学领域的核心名词,结合技术原理、实际应用与攻击场景,帮助开发者快速构建密码学知识框架。文中代码示例基于…

GD32H7单片机使用segger_rtt,rtt-viewer看不到输出的问题,怎样解决?

jlink版本目前是792,但估计只要能支持h7的jlink版本应该都可以。 将segger/JLink_V792n中,samples文件夹、RTT中四个文件拷贝出来放在单片机目录中 在任意代码部分引用segger_rtt.h,再调用函数 即可使用rtt打印功能,在rtt-viewe…

快速生成安卓证书并打包生成安卓apk(保姆教程)

一.生成安卓证书 目前市面上生成可以快速生成安卓证书的网站有很多个人推荐香蕉云编以下是网站链接 香蕉云编-app打包上架工具类平台 1.进入网站如下图 2.点击生成签名证书 3.点击立即创建证书 4.点击创建安卓证书 5.按照指引完成创建 6.点击下载就可使用 二.打包安卓apk …

前端面试场景题

目录 1.项目第一次加载太慢优化 / vue 首屏加载过慢如何优化 2.说说了解的es6-es10的东西有哪些 ES6(ES2015)之后,JavaScript 新增了许多实用的数组和对象方法,下面为你详细介绍: 3.常见前端安全性问题 XSS&#…

Spring JDBC 的开发步骤(注解方式)

Spring JDBC 的开发步骤主要包括以下关键环节&#xff0c;结合代码示例说明如下&#xff1a; 1. 添加依赖 在 pom.xml 中引入 Spring JDBC 和数据库驱动依赖&#xff08;以 HikariCP 连接池和 MySQL 为例&#xff09;&#xff1a; <!-- Spring JDBC --> <dependency…

Java面试:探索Spring Boot与微服务的深度挑战

场景&#xff1a;互联网大厂Java求职者面试 在一个阳光明媚的下午&#xff0c;赵大宝来到了知名互联网大厂的面试现场。他面临的是一个严肃的面试官&#xff0c;准备对他的技术能力进行全面考核。 第一轮提问&#xff1a;基础知识与Spring Boot应用 面试官&#xff1a;赵先生…

Spring Boot中的监视器:Actuator的原理、功能与应用

在 Spring Boot 应用中&#xff0c;监视器通常指 Spring Boot Actuator&#xff0c;一个内置的生产就绪工具&#xff0c;用于监控和管理运行中的应用。Actuator 提供了一系列 RESTful 端点&#xff0c;暴露应用的运行时信息&#xff0c;如健康状态、性能指标、日志配置和环境变…

GitHub创建远程仓库

使用GitHub创建远程仓库&#xff1a;从零开始实现代码托管与协作 前言 在当今软件开发领域&#xff0c;版本控制系统已成为开发者必备的核心工具。作为分布式版本控制系统的代表&#xff0c;Git凭借其强大的分支管理和高效的协作能力&#xff0c;已成为行业标准。而GitHub作为…