深度学习-线性回归+基础优化算法

目录

  • 线性模型
  • 衡量预估质量
  • 训练数据
  • 参数学习
    • 训练损失
    • 最小化损失来学习参数
    • 显式解
  • 总结
  • 基础优化
    • 梯度下降
      • 选择学习率
    • 小批量随机梯度下降
      • 选择批量大小
  • 总结
  • 线性回归的从零开始实现
    • 实现一个函数读取小批量效果展示
      • 这里可视化看一下
    • 线性回归从零开始实现
    • 线性回归的简洁实现效果展示
    • 线性回归的简洁实现
  • 问题总结

线性模型

在这里插入图片描述
线性模型可以看做是单层神经网络

在这里插入图片描述




衡量预估质量

在这里插入图片描述




训练数据

在这里插入图片描述

参数学习

训练损失

在这里插入图片描述
这里的b应该加粗,原先b是标量然后通过广播机制变为一列,即向量b。

最小化损失来学习参数

在这里插入图片描述

显式解

加入一列全一的特征,加入X中。即:
在这里插入图片描述
将偏差加入权重。即:
在这里插入图片描述


损失函数:

在这里插入图片描述


示范过程:

在这里插入图片描述
在这里插入图片描述

因为是线性模型:所以损失是凸函数,所以最优解满足
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述




总结

1、线性回归是对n维输入的加权,外加偏差。
2、使用平方损失来衡量预测值和真实值的差异。
3、线性回归有显示解。
4、线性回归可以看做是单层神经网络。



基础优化

梯度下降

当一个模型没有显式解的时候

在这里插入图片描述

选择学习率

在这里插入图片描述




小批量随机梯度下降

在这里插入图片描述

选择批量大小

在这里插入图片描述




总结

在这里插入图片描述




线性回归的从零开始实现

我们将从零开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度下降优化器。
在这里插入图片描述
在这里插入图片描述

import torch
def synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声。"""X = torch.normal(0, 1, (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)
print('features:', features[0], '\nlabel:', labels[0])

正态分布函数:normal()
1、normal(0,1,(num_examples,len(w)))表示均值为0,方差为1的随机数,它的大小是说有num_examples个样本,列数是w的长度

2、矩阵乘法:matmul()

3、y.reshape((-1, 1)中的-1表示维度的大小自动计算,第二个维度是1表示新数组将有一个列。
例如:

import torch
y = torch.tensor([1, 2, 3, 4, 5])
print(y.reshape((-1, 1)))

结果:
在这里插入图片描述

在这个例子中,-1被自动替换为5,因为y有5个元素,并且你想要一个只有一列的二维数组。所以,根据另一个维度(这里是1)自动计算这个维度的大小。

4、features是特征,features中的每一行都包含一个二维数据样本,labels中的每一行包含一维标签值(一个标量)

在这里插入图片描述

在这里插入图片描述

import torch
from d2l import torch as d2l
import matplotlib.pyplot as pltdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声。"""X = torch.normal(0, 1, (num_examples, len(w)))#方差为0,均值为1,num_examples个样本,列数是w的长度y = torch.matmul(X, w) + b #这里的y是一个行向量y += torch.normal(0, 0.01, y.shape) #意思是给 y 加上一个符合正态分布的随机噪声。torch.normal(0, 0.01, y.shape) 生成一个与 y 形状相同的张量,#其中的元素是从均值为 0、标准差为 0.01 的正态分布中随机抽取的。#然后,这个随机生成的张量会被加到 y 上。return X, y.reshape((-1, 1)) #这里的y目的是转换为列向量true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)d2l.set_figsize() #用于设置Matplotlib图像的大小,可以接受两个参数宽度和高度
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1) #detach()分离出数值,不再含有梯度
plt.show()

d2l.plt.scatter(): 使用 scatter 函数绘制散点图。
第一个参数是x轴的数据(即 features 的第二列)。
第二个参数是y轴的数据(即 labels)。
第三个参数1: 这是散点的大小。在这里,所有散点的大小都被设置为1。

features[:, 1].detach().numpy():
features[:, 1]:从 features 数组中选择所有行的第二列
.detach(): features 是一个PyTorch张量,.detach() 方法用于创建一个新的张量,从当前计算图中分离出来,这样它就不会计算梯度。这对于绘图来说通常是必要的,因为我们不需要对绘图数据进行反向传播。
.numpy(): 将PyTorch张量转换为NumPy数组,因为 matplotlib 通常与NumPy数组一起使用。

结果:
在这里插入图片描述




实现一个函数读取小批量效果展示

import random
import torchdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声。"""X = torch.normal(0, 1, (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)def data_iter(batch_size, features, labels):num_examples = len(features) #多个样本indices = list(range(num_examples)) #从0到n-1# 这些样本是随机读取的,没有特定的顺序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]#yield相当于返回一个可迭代对象batch_size = 10
for X, y in data_iter(batch_size, features, labels):print(X, '\n', y)break

indices 是一个从0到 num_examples-1 的整数列表,代表所有样本的索引。

i:min(i + batch_size, num_examples) 是一个切片操作,用于从 indices 中选择一部分索引。从 i 开始,选取到 i + batch_size 或者 num_examples(取两者中较小的一个)结束。是为了确保在最后一个批次中不会超出索引范围。例如,如果总共有1000个样本,批大小为100,当 i 为900时,i + batch_size 会超出索引范围,因此 min(i + batch_size, num_examples) 会确保只选取到最后一个索引。

将上面通过切片操作得到的索引列表转换为一个PyTorch张量

data_iter 函数是一个数据迭代器,它接收批大小 batch_size、特征 features 和标签 labels 作为输入。它首先计算样本数量 num_examples,并创建一个从0到 num_examples-1 的索引列表。然后,它打乱索引列表的顺序,以便在每次迭代时随机选择样本。最后,它使用这些随机索引从特征和标签中抽取小批量数据,并使用 yield 语句返回这些数据。yield 使得这个函数成为一个生成器,每次调用时返回一批数据。设置批大小为10,并使用 data_iter 函数迭代数据和标签。在循环中,每次迭代都会打印出一个小批量的特征 X 和标签 y。由于循环后面有一个 break 语句,所以只会打印出第一批数据。

结果:
在这里插入图片描述

这里可视化看一下

import random
import torch
from d2l import torch as d2l
import matplotlib.pyplot as pltdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声。"""X = torch.normal(0, 1, (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)def data_iter(batch_size, features, labels):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]batch_size = 10
for X, y in data_iter(batch_size, features, labels):print(X, '\n', y)break# 获取一个批次的数据
X_batch, y_batch = next(data_iter(batch_size, features, labels))# 绘制批次数据的散点图
d2l.plt.scatter(X_batch[:, 0].numpy(), y_batch.numpy())
d2l.plt.show()

在这里插入图片描述
在这里插入图片描述




线性回归从零开始实现

import random
import torchdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声。"""X = torch.normal(0, 1, (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)def data_iter(batch_size, features, labels):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]batch_size = 10# 定义初始化模型参数,需要w,b进行更新,所以才将requires_grad设置为True
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
#size=(2, 1)生成的张量 w 是一个形状为 2x1 的二维张量,即它有 2 行和 1 列。
b = torch.zeros(1, requires_grad=True)
#这里的 1 意味着 b 是一个一维张量,它只有一个元素,并且这个元素的值为 0。
#在 PyTorch 中,一维张量通常可以看作是一个向量。
#因此,b 是一个只包含一个元素(值为 0)的向量。# 定义模型
def linreg(X, w, b):"""线性回归模型。"""return torch.matmul(X, w) + b# 定义损失函数,其中y_hat是预测值y是真实值
def squared_loss(y_hat, y):"""均方损失。均方误差公式"""return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2# 定义优化算法
def sgd(params, lr, batch_size):"""小批量随机梯度下降。"""with torch.no_grad():#不需要计算梯度,使用 torch.no_grad() 可以减少内存消耗,并提高运行速度。for param in params:#其中param可能是w也可能是bparam -= lr * param.grad / batch_sizeparam.grad.zero_()lr = 0.03
num_epochs = 3 #意思是把整个数据扫三遍
net = linreg #定义的模型
loss = squared_loss#均方损失
for epoch in range(num_epochs): #每一次对数据扫一遍for X, y in data_iter(batch_size, features, labels):l = loss(net(X, w, b), y)  #一个长为批量大小的损失# 因为’1‘形状是(’batch_size‘,1),而不是一个标量。'1'中的所有元素被加到# 并以此计算关于['w','b']的梯度l.sum().backward()sgd([w, b], lr, batch_size)  # 使用参数的梯度更新with torch.no_grad():train_l = loss(net(features, w, b), labels)print(f'epoch{epoch + 1},loss{float(train_l.mean()):f}')#:f确保train_l.mean()的结果以浮点数形式被格式化并嵌入到字符串中
print(f'w的估计误差:{true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b - b}')

在这里插入图片描述
说明 param -= lr * param.grad / batch_size中param.grad / batch_size的含义。是用来计算平均梯度的。
示例:

import torchX = torch.tensor([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0]])
w = torch.tensor([[1.0], [2.0]], dtype=torch.float32, requires_grad=True)
b = torch.tensor([0.0], requires_grad=True)
y = torch.tensor([[0.0], [1.0], [2.0]])y_hat = torch.matmul(X, w) + b
l = (y_hat - y)**2 / 2
l.sum().backward()print(w.grad)
print(b.grad)

运行结果:

tensor([[46.],[67.]])
tensor([21.])

计算过程:
在这里插入图片描述
计算损失函数时,对它调用.backward()会将自动求导计算的梯度累积存在param.grad中。当一个批次包含batch_size个样本时,并且每个样本都贡献一个梯度给模型参数。那么调用backward()后,paramgrad中存储的就是这些梯度的和。这就是为什么在更新参数时,需要将param.grad除以batch_size。这样做可以得到一个平均梯度。
这样,w.grad / batch_size和b.grad / batch_size相当于在batch_size中取平均值。
然后这整句公式的含义:是进行梯度下降
在这里插入图片描述




学习率不能太高也不能太低。
当学习率很低时

#当lr = 0.03改为0.001时
lr = 0.001

跑完三次后损失还是很大
在这里插入图片描述

多跑几遍看看

#num_epochs由3改为10
num_epochs = 10

在这里插入图片描述
跑完十次后损失还是很大
学习率很高时

#lr 从0.03改为10时
lr = 10

在这里插入图片描述
这种情况是求导的时候会除0或者是无限的值,然后超出了浮点类型的计算范围。




线性回归的简洁实现效果展示

import torch
from torch.utils import data
from d2l import torch as d2ldef load_array(data_arrays, batch_size, is_train=True):"""构造一个PyTorch数据迭代器。"""#在PyTorch中,data.TensorDataset是一个用于包装数据张量(tensors)的数据集类。#*data_arrays 是一个解包操作,它将data_arrays这个元组(或列表)中的每个元素作为单独的参数传递给TensorDataset。#data_arrays是一个包含特征张量features和标签张量labels的元组,那么*data_arrays的效果等同于直接传递这两个张量作为参数dataset = data.TensorDataset(*data_arrays)return data.DataLoader(dataset, batch_size, shuffle=is_train) #每一次随机从中挑选batch_size个样本,并随机打乱顺序true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
batch_size = 10
data_iter = load_array((features, labels),batch_size)
print(next(iter(data_iter)))#iter() 函数用于获取一个迭代器对象。next() 函数用于获取迭代器对象的下一个元素。

结果:
在这里插入图片描述




# ’nn‘ 是神经网络的缩写
from torch import nn
#使用框架预定义好的层
net = nn.Sequential(nn.Linear(2, 1))#输入的维度是2,输出的维度是1
#这意味着这个线性层接受一个形状为[batch_size, 2]的张量作为输入,并输出一个形状为[batch_size, 1]的张量。#初始化模型参数
print(net[0].weight.data.normal_(0, 0.01))#net 是一个 nn.Sequential 的实例,它包含了一个 nn.Linear 层。
#.weight表示该层的权重参数。对于 nn.Linear(2, 1),这个权重参数是一个形状为 [2, 1] 的二维张量。
#.data:这是访问张量底层数据的方式。在这里,我们仅用它来初始化权重。
#normal_(0, 0.01):它会将张量的值替换为从均值为0、标准差为0.01的正态分布中抽取的随机值。这里的下划线 _ 表示这是一个原地操作,它会直接修改调用它的张量,而不是返回一个新的张量。
print(net[0].bias.data.fill_(0))#.bias表示该层的偏置参数。对于nn.Linear(2, 1),这个偏置参数是一个形状为[1]的一维张量。
#fill_(0):它会将张量的所有值设置为给定的标量值,这里是0。

结果:在这里插入图片描述

net = nn.Sequential(nn.Linear(2, 1))的使用示例:

import torch  
import torch.nn as nn  # 定义网络模型  
model = nn.Sequential(nn.Linear(2, 1))  # 创建一个输入张量,形状为 [batch_size, 2]  
input_tensor = torch.randn(3, 2)  # 这里batch_size是3  # 通过网络模型传递输入张量  
output_tensor = model(input_tensor)  # 输出张量的形状将是 [batch_size, 1]  
print(output_tensor.shape)  # 输出: torch.Size([3, 1])



线性回归的简洁实现

# ’nn‘ 是神经网络的缩写
import torch.optim
from torch import nn
from torch.utils import data
from d2l import torch as d2ldef load_array(data_arrays, batch_size, is_train=True):"""构造一个PyTorch数据迭代器。"""#在PyTorch中,data.TensorDataset是一个用于包装数据张量(tensors)的数据集类。#*data_arrays 是一个解包操作,它将data_arrays这个元组(或列表)中的每个元素作为单独的参数传递给TensorDataset。#data_arrays是一个包含特征张量features和标签张量labels的元组,那么*data_arrays的效果等同于直接传递这两个张量作为参数dataset = data.TensorDataset(*data_arrays)return data.DataLoader(dataset, batch_size, shuffle=is_train) #每一次随机从中挑选batch_size个样本,并随机打乱顺序true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
batch_size = 10
data_iter = load_array((features, labels),batch_size)#使用框架预定义好的层
net = nn.Sequential(nn.Linear(2, 1))#输入的维度是2,输出的维度是1
#这意味着这个线性层接受一个形状为[batch_size, 2]的张量作为输入,并输出一个形状为[batch_size, 1]的张量。#初始化模型参数
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)#计算均方误差使用的是MSELoss类,也称为平方范数
loss = nn.MSELoss()
#实例化SGD实例,torch.optim.SGD 是一个用于实现随机梯度下降(Stochastic Gradient Descent, SGD)优化算法的类。
trainer = torch.optim.SGD(net.parameters(), lr=0.03)#net.parameters():拿出所有的参数(即权重w和偏置b)。#训练过程代码和从零开始实现类似
num_epochs = 3
for epoch in range(num_epochs):for X, y in data_iter:l = loss(net(X), y)#这里net自带了模型参数,不需要w和b弄进去了trainer.zero_grad()#trainer优化器梯度清零l.backward()#这里不需要求和,因为pytorch自动求和了trainer.step()#进行模型的更新和从零开始的sgd函数类似l = loss(net(features), labels)print(f'epoch {epoch + 1}, loss {l:f}')

结果:在这里插入图片描述




问题总结

1、为啥使用平方损失而不是绝对差值呢
区别不大,但绝对差值是个不可导的函数

2、损失为什么要求平均?
求不求平均本质上没有关系,不求平均梯度的数值有点大,如果使用梯度下降的话,那么不除以n的话,就把学习率除以n。除以n的好处是说:不管批量和样本多大我的梯度都差不多,调学习率好调。

3、线性回归损失函数是不是通常都是MSE(均方损失误差)
是的

4、不管是gd(梯度下降)还是sgd(随机梯度下降)怎么找到合适的学习率?有什么好的方法吗?
两个办法
找到一个对学习率不那么敏感的算法,比如adam。
通过合理的参数的初始化

5、针对batchsize大小的数据集进行网络训练的时候,网络中每个参数更新时的减去的梯度是batchsize中每个样本对应参数梯度求和后取得平均值吗?
是的

6、detach()是什么作用?
告诉不要算梯度了

7、如果样本大小不是批量数的整数倍,那需要随机剔除多余的样本吗?
假设有100个样本,批量大小为60
第一次60,那么剩下40怎么办?
1、普遍做法是拿到一个小的样本,长为40的批量样本
2、把不完整的批量大小扔掉
3、从下一个里面补20个

8、本质上我们为什么要用SGD(随机梯度下降),是因为大部分的实际loss(损失函数)太复杂,推导不出导数为0的解么?只能逐个batch去逼近?
是的

9、l.backward()这里是调用pytorch自定义的back propogation(梯度反向传播)吗?
是的

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

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

相关文章

静态住宅IP代理VS动态住宅IP代理,该如何选择?

在网络安全和数据采集领域,代理服务已经成为一个必不可少的工具。在IP代理服务中,静态住宅代理和动态住宅代理是两种常见的代理类型。今天就为大家详细介绍静态住宅代理与动态住宅代理的差异。 首先我们来看什么是静态住宅IP,这种IP地址可以被…

硅酸盐玻璃反应离子刻蚀在光学微系统的应用前景

引言 微光学元件和复杂光学微系统需要超精密制造工艺。最大容许粗糙度由所用波长λ的分数定义,例如λ或更好,而元件的整体尺寸和形状可以容易地达到毫米或厘米范围。在RIE过程中,材料传输是通过离子和反应气体与等离子体反应器表面的物理和化…

Spring Boot项目中的ASCII艺术字

佛祖保佑: ${spring-boot.formatted-version} ———————————————————————————————————————————————————————————————————— // _ooOoo_ …

分享爱,分享精彩瞬间,分享5款实用软件

分享爱,分享时光,分享精彩瞬间,大家好,我是互联网的搬运工,今天继续给大家带来几款好用的软件。 1. 数据分析——Chartistic ​ Chartistic是一款功能强大的数据分析可视化工具,它提供了丰富的图表类型和…

C语言操作符和关键字

文章目录 操作符单目操作符sizeof(类型)强制类型转换 关系操作符、逻辑操作符、条件操作符逗号表达式 常见关键字typedefstaticstatic修饰局部变量static修饰全局变量static修饰函数 register寄存器关键词define定义常量和宏 操作符 单目操作符 C语言中…

R-Tree原理及实现代码

目录 一.引言 二.R-Tree的基本原理 插入操作 查询操作 删除操作 平衡操作 三. 节点分裂 线性分裂 二次分裂 增量分裂 四.查询 范围查询 最近邻查询 五.最新研究进展 六.C语言实现示例 七. 实际案例分析 八.总结 一.引言 在计算机科学领域,R-Tree是…

基于 Spring Boot 博客系统开发(一)

基于 Spring Boot 博客系统开发(一) 本系统是简易的个人博客系统开发,为了更加熟练地掌握SprIng Boot 框架及相关技术的使用。🤓🤓🤓 基于 Spring Boot 博客系统开发(二)&#x1f4…

聊聊.NET Core处理全局异常有那些方法

简述 处理全局异常的方法有IExceptionFilter(异常处理),使用中间件异常处理,使用框架自带异常中间件等。考点 考察对异常处理方式的熟悉程度和广度,以及对中间件、过滤器熟练程度。 下面分别具体介绍三种处理异常的…

Spring Cloud学习笔记(Feigh):简介,实战简单样例

这是本人学习的总结,主要学习资料如下 - 马士兵教育 1、Netflix Feign简介2、Open Feign的简单样例2.1、dependency2.2、代码样例 1、Netflix Feign简介 Netfilx Feign是用来帮助发送远程服务的,它让开发者觉得调用远程服务就像是调用本地方法一样&…

计算机系列之进程调度、死锁、存储管理、设备管理、文件管理

11、进程调度-死锁-存储管理-固定分页分段 1、进程调度 进程调度方式是指当有更高优先级的进程到来时如何分配CPU。分为可剥夺和不可剥夺两种,可剥夺指当有更高优先级进程到来时,强行将正在运行进程的CPU分配给高优先级进程;不可剥夺是指高…

分享一些常用的内外网文件传输工具

内外网隔离后的文件传输是网络安全领域中一个常见而又重要的问题。随着信息技术的快速发展,网络安全问题日益凸显,内外网隔离成为了许多企业和组织保护内部信息安全的重要手段。然而,内外网隔离后如何有效地进行文件传输,成为了摆…

专利视角下的量子竞赛:《2024全球专利格局白皮书》

2024年1月,欧洲量子产业联盟(QuIC)发布了题为《全球量子技术专利格局描述》的综合白皮书。 该文件以透明的视角展示了当今的知识产权格局,包括知识产权持有人的地理分布。该文件由 QuIC 知识产权(IP)与贸易…

3DTiles特性与内容解析

一篇19年整理的比较老的笔记了。更多精彩内容尽在数字孪生平台。 瓦片种类 3DTiles瓦片有多种类型: b3dm(Batched 3D Model,批量3D模型) b3dm瓦片存储了多个个体,b3dm中的glb代表的实际对象应该具有相同的种类但是可能数据内容不同。b3dm…

ABAP开发:SAPscript表单设计及打印简介

在SAP ERP系统应用中,通常利用Forms表单来定制诸如发票、支票及标签之类的特殊文档的打印格式。这些Forms用来描述文档页面中的信息结构,比如地址抬头、item行、页脚等等,Forms设计就是要确定这些文档的输出格式。 利用SAPscript工具进行Form…

html+css 选择器优先级

1.基本选择器优先级 id>class>tagname(标签选择器)>*(通配符选择器) <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>基本选择器的优先级</title><style type"text/css"…

ShaderLab的混合命令

文章目录 示例原理混合因子混合操作参考 示例 Pass {Tags{"LightMode" "ForwardBase"}// 关闭深度写入ZWrite Off// 设置Pass的混合模式&#xff0c;SrcAlpha: 片元着色器产生的颜色的混合因子// OneMinusSrcAlpha 已经存在于颜色缓冲中的颜色的混合因子…

vue实现左右两栏布局宽度可拖拽

项目里需要左右两栏布局根据内容多少可以用户自己拖拽宽度的需求 找了文章参考了下&#xff0c;但都没有实现我要的效果&#xff0c;所以结合调整了一下&#xff0c;记录一下我自己用到的效果 参考文章放下面了&#xff0c;感谢两位大佬 vue拖拽 html实现拖拽 最终效果实现…

STM32 cubemx hal库huart串口接收不到第一帧数据或数据全为0的问题

存在问题的stm32工程是使用cubemx搭建stm32串口dma通讯的工程. 问题是&#xff1a; 每次上电后&#xff0c;串口接收第一帧数据全部都为0&#xff0c;第二帧及以后接收的数据都是正确。 原因是&#xff1a; 以下2行代码&#xff0c;放在void HAL_UART_MspInit(UART_HandleT…

easyExcel - 带图片导出

目录 前言一、情景介绍二、问题分析三、代码实现1. 单图片导出2. 多图片导出3. 多图片导出&#xff08;优化&#xff09; 前言 Java-easyExcel入门教程&#xff1a;https://blog.csdn.net/xhmico/article/details/134714025 之前有介绍过如何使用 easyExcel&#xff0c;以及写…

适用于芯片行业的开发及管理工具:版本控制、持续集成、代码分析及项目管理工具介绍

3月28日-29日&#xff0c;2024国际集成电路展览会暨研讨会&#xff08;IIC Shanghai&#xff09;在上海成功举行。此次盛会汇聚了集成电路产业的众多领军企业&#xff0c;共同探寻和把握集成电路产业的发展脉络。 龙智携芯片研发及管理解决方案亮相展会&#xff0c;展示如何通…