pytorch(续周报(1))

文章目录

  • 2.1 张量
    • 2.1.1 简介
    • 2.1.2 创建tensor
    • 2.1.3 张量的操作
    • 2.1.4 广播机制
  • 2.2 自动求导
    • Autograd简介
    • 2.2.1 梯度
  • 2.3 并行计算简介
    • 2.3.1 为什么要做并行计算
    • 2.3.2 为什么需要CUDA
    • 2.3.3 常见的并行的方法:
      • 网络结构分布到不同的设备中(Network partitioning)
      • 同一层的任务分布到不同数据中(Layer-wise partitioning)
      • 不同的数据分布到不同的设备中,执行相同的任务(Data parallelism)
    • 2.3.4 使用CUDA加速训练

2.1 张量

概述:

  • 张量的简介
  • PyTorch如何创建张量
  • PyTorch中张量的操作
  • PyTorch中张量的广播机制

2.1.1 简介

几何代数中定义的张量是基于向量和矩阵的推广,比如我们可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量。

张量维度代表含义
0维张量代表的是标量(数字)
1维张量代表的是向量
2维张量代表的是矩阵
3维张量时间序列数据 股价 文本数据 单张彩色图片(RGB)

张量是现代机器学习的基础。它的核心是一个数据容器,多数情况下,它包含数字,有时候它也包含字符串,但这种情况比较少。因此可以把它想象成一个数字的水桶。

这里有一些存储在各种类型张量的公用数据集类型:

  • 3维 = 时间序列
  • 4维 = 图像
  • 5维 = 视频

例子:一个图像可以用三个字段表示:

(width, height, channel) = 3D

但是,在机器学习工作中,我们经常要处理不止一张图片或一篇文档——我们要处理一个集合。我们可能有10,000张郁金香的图片,这意味着,我们将用到4D张量:

(batch_size, width, height, channel) = 4D

2.1.2 创建tensor

  1. 随机初始化矩阵
    我们可以通过torch.rand()的方法,构造一个随机初始化的矩阵:

import torch
x = torch.rand(4, 3) 
print(x)
tensor([[0.7569, 0.4281, 0.4722],
        [0.9513, 0.5168, 0.1659],
        [0.4493, 0.2846, 0.4363],
        [0.5043, 0.9637, 0.1469]])
  1. 全0矩阵的构建
    我们可以通过torch.zeros()构造一个矩阵全为 0,并且通过dtype设置数据类型为 long。除此以外,我们还可以通过torch.zero_()和torch.zeros_like()将现有矩阵转换为全0矩阵.
import torch
x = torch.zeros(4, 3, dtype=torch.long)
print(x)
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])
  1. 张量的构建
    我们可以通过torch.tensor()直接使用数据,构造一个张量:
import torch
x = torch.tensor([5.5, 3]) 
print(x)
tensor([5.5000, 3.0000])
  1. 基于已经存在的 tensor,创建一个 tensor :
x = x.new_ones(4, 3, dtype=torch.double) 
# 创建一个新的全1矩阵tensor,返回的tensor默认具有相同的torch.dtype和torch.device
# 也可以像之前的写法 x = torch.ones(4, 3, dtype=torch.double)
print(x)
x = torch.randn_like(x, dtype=torch.float)
# 重置数据类型
print(x)
# 结果会有一样的size
# 获取它的维度信息
print(x.size())
print(x.shape)
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
tensor([[ 2.7311, -0.0720,  0.2497],
        [-2.3141,  0.0666, -0.5934],
        [ 1.5253,  1.0336,  1.3859],
        [ 1.3806, -0.6965, -1.2255]])
torch.Size([4, 3])
torch.Size([4, 3])

返回的torch.Size其实是一个tuple,⽀持所有tuple的操作。我们可以使用索引操作取得张量的长、宽等数据维度。

  1. 常见的构造Tensor的方法:
函数功能
Tensor(sizes)基础构造函数
tensor(data)类似于np.array
ones(sizes)全1
zeros(sizes)全0
eye(sizes)对角为1,其余为0
arange(s,e,step)从s到e,步长为step
linspace(s,e,steps)从s到e,均匀分成step份
rand/randn(sizes)rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布
normal(mean,std)正态分布(均值为mean,标准差是std)
randperm(m)随机排列

2.1.3 张量的操作

在接下来的内容中,我们将介绍几种常见的张量的操作方法:

  1. 加法操作:
import torch
# 方式1
y = torch.rand(4, 3) 
print(x + y)

# 方式2
print(torch.add(x, y))

# 方式3 in-place,原值修改
y.add_(x) 
print(y)
tensor([[ 2.8977,  0.6581,  0.5856],
        [-1.3604,  0.1656, -0.0823],
        [ 2.1387,  1.7959,  1.5275],
        [ 2.2427, -0.3100, -0.4826]])
tensor([[ 2.8977,  0.6581,  0.5856],
        [-1.3604,  0.1656, -0.0823],
        [ 2.1387,  1.7959,  1.5275],
        [ 2.2427, -0.3100, -0.4826]])
tensor([[ 2.8977,  0.6581,  0.5856],
        [-1.3604,  0.1656, -0.0823],
        [ 2.1387,  1.7959,  1.5275],
        [ 2.2427, -0.3100, -0.4826]])

  1. 索引操作:(类似于numpy)

需要注意的是:索引出来的结果与原数据共享内存,修改一个,另一个会跟着修改。如果不想修改,可以考虑使用copy()等方法

import torch
x = torch.rand(4,3)
# 取第二列
print(x[:, 1]) 
tensor([-0.0720,  0.0666,  1.0336, -0.6965])
y = x[0,:]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了了
tensor([3.7311, 0.9280, 1.2497])
tensor([3.7311, 0.9280, 1.2497])
  1. 维度变换
    张量的维度变换常见的方法有torch.view()torch.reshape(),下面我们将介绍torch.view()
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1是指这一维的维数由其他维度决定
print(x.size(), y.size(), z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

注: torch.view() 返回的新tensor与源tensor共享内存(其实是同一个tensor),更改其中的一个,另外一个也会跟着改变。(顾名思义,view()仅仅是改变了对这个张量的观察角度)

x += 1
print(x)
print(y) # 也加了了1
tensor([[ 1.3019,  0.3762,  1.2397,  1.3998],
        [ 0.6891,  1.3651,  1.1891, -0.6744],
        [ 0.3490,  1.8377,  1.6456,  0.8403],
        [-0.8259,  2.5454,  1.2474,  0.7884]])
tensor([ 1.3019,  0.3762,  1.2397,  1.3998,  0.6891,  1.3651,  1.1891, -0.6744,
         0.3490,  1.8377,  1.6456,  0.8403, -0.8259,  2.5454,  1.2474,  0.7884])
  1. 取值操作
    如果我们有一个元素 tensor ,我们可以使用 .item() 来获得这个 value,而不获得其他性质:
import torch
x = torch.randn(1) 
print(type(x)) 
print(type(x.item()))
<class 'torch.Tensor'>
<class 'float'>

PyTorch中的 Tensor 支持超过一百种操作,包括转置、索引、切片、数学运算、线性代数、随机数等等,具体使用方法可参考官方文档。

2.1.4 广播机制

当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。

x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])

由于x和y分别是1行2列和3行1列的矩阵,如果要计算x+y,那么x中第一行的2个元素被广播 (复制)到了第二行和第三行,⽽y中第⼀列的3个元素被广播(复制)到了第二列。如此,就可以对2个3行2列的矩阵按元素相加。

2.2 自动求导

PyTorch 中,所有神经网络的核心是 autograd 包。autograd包为张量上的所有操作提供了自动求导机制。它是一个在运行时定义 ( define-by-run )的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。

  • autograd的求导机制
  • 梯度的反向传播

Autograd简介

torch.Tensor 是这个包的核心类。如果设置它的属性 .requires_gradTrue,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用 .backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。

注意:在 y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的Tensor。

要阻止一个张量被跟踪历史,可以调用.detach()方法将其与计算历史分离,并阻止它未来的计算记录被跟踪。为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad(): 中。在评估模型时特别有用,因为模型可能具有 requires_grad = True 的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算。

还有一个类对于autograd的实现非常重要:FunctionTensor Function 互相连接生成了一个无环图 (acyclic graph),它编码了完整的计算历史。每个张量都有一个.grad_fn属性,该属性引用了创建 Tensor 自身的Function(除非这个张量是用户手动创建的,即这个张量的grad_fnNone )。

from __future__ import print_function
import torch
x = torch.randn(3,3,requires_grad=True)
print(x.grad_fn)
None

如果需要计算导数,可以在 Tensor 上调用 .backward()。如果 Tensor 是一个标量(即它包含一个元素的数据),则不需要为 backward() 指定任何参数,但是如果它有更多的元素,则需要指定一个gradient参数,该参数是形状匹配的张量。

创建一个张量并设置requires_grad=True用来追踪其计算历史

x = torch.ones(2, 2, requires_grad=True)
print(x)
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

对这个张量做一次运算:

y = x**2
print(y)
tensor([[1., 1.],
        [1., 1.]], grad_fn=<PowBackward0>)

y是计算的结果,所以它有grad_fn属性。

print(y.grad_fn)
<PowBackward0 object at 0x000001CB45988C70>

对 y 进行更多操作

z = y * y * 3
out = z.mean()

print(z, out)
tensor([[3., 3.],
        [3., 3.]], grad_fn=<MulBackward0>) tensor(3., grad_fn=<MeanBackward0>)

.requires_grad_(...) 原地改变了现有张量的requires_grad标志。如果没有指定的话,默认输入的这个标志是 False

a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
False
True
<SumBackward0 object at 0x000001CB4A19FB50>

2.2.1 梯度

现在开始进行反向传播,因为 out 是一个标量,因此out.backward() out.backward(torch.tensor(1.)) 等价。

out.backward()

输出导数 d(out)/dx

print(x.grad)
tensor([[3., 3.],
        [3., 3.]])

数学上,若有向量函数 y ⃗ = f ( x ⃗ ) \vec{y}=f(\vec{x}) y =f(x ),那么 y ⃗ \vec{y} y 关于 x ⃗ \vec{x} x 的梯度就是一个雅可比矩阵:
J = ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n ) J=\left(\begin{array}{ccc}\frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}\end{array}\right) J= x1y1x1ymxny1xnym
torch.autograd 这个包就是用来计算一些雅可比矩阵的乘积的。例如,如果 v v v 是一个标量函数 l = g ( y ⃗ ) l = g(\vec{y}) l=g(y ) 的梯度:
v = ( ∂ l ∂ y 1 ⋯ ∂ l ∂ y m ) v=\left(\begin{array}{lll}\frac{\partial l}{\partial y_{1}} & \cdots & \frac{\partial l}{\partial y_{m}}\end{array}\right) v=(y1lyml)
由链式法则,我们可以得到:

v J = ( ∂ l ∂ y 1 ⋯ ∂ l ∂ y m ) ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n ) = ( ∂ l ∂ x 1 ⋯ ∂ l ∂ x n ) v J=\left(\begin{array}{lll}\frac{\partial l}{\partial y_{1}} & \cdots & \frac{\partial l}{\partial y_{m}}\end{array}\right)\left(\begin{array}{ccc}\frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}\end{array}\right)=\left(\begin{array}{lll}\frac{\partial l}{\partial x_{1}} & \cdots & \frac{\partial l}{\partial x_{n}}\end{array}\right) vJ=(y1lyml) x1y1x1ymxny1xnym =(x1lxnl)

注意:grad在反向传播过程中是累加的(accumulated),这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零。

# 再来反向传播⼀一次,注意grad是累加的
out2 = x.sum()
out2.backward()
print(x.grad)

out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)
tensor([[4., 4.],
        [4., 4.]])
tensor([[1., 1.],
        [1., 1.]])

现在我们来看一个雅可比向量积的例子:

x = torch.randn(3, requires_grad=True)
print(x)

y = x * 2
i = 0
while y.data.norm() < 1000:
    y = y * 2
    i = i + 1
print(y)
print(i)
tensor([-0.9332,  1.9616,  0.1739], requires_grad=True)
tensor([-477.7843, 1004.3264,   89.0424], grad_fn=<MulBackward0>)
8

在这种情况下,y 不再是标量。torch.autograd 不能直接计算完整的雅可比矩阵,但是如果我们只想要雅可比向量积,只需将这个向量作为参数传给 backward:

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])

也可以通过将代码块包装在 with torch.no_grad(): 中,来阻止 autograd 跟踪设置了.requires_grad=True的张量的历史记录。

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)
True
True
False

如果我们想要修改 tensor 的数值,但是又不希望被 autograd 记录(即不会影响反向传播), 那么我们可以对 tensor.data 进行操作。

x = torch.ones(1,requires_grad=True)

print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外

y = 2 * x
x.data *= 100 # 只改变了值,不会记录在计算图,所以不会影响梯度传播

y.backward()
print(x) # 更改data的值也会影响tensor的值 
print(x.grad)
tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])

2.3 并行计算简介

在利用PyTorch做深度学习的过程中,可能会遇到数据量较大无法在单块GPU上完成,或者需要提升计算速度的场景,这时就需要用到并行计算。

  • 并行计算的简介
  • CUDA简介
  • 并行计算的三种实现方式
  • 使用CUDA加速训练

2.3.1 为什么要做并行计算

深度学习的发展离不开算力的发展,GPU的出现让我们的模型可以训练的更快,更好。所以,如何充分利用GPU的性能来提高我们模型学习的效果,这一技能是我们必须要学习的。这一节,我们主要讲的就是PyTorch的并行计算。PyTorch可以在编写完模型之后,让多个GPU来参与训练,减少训练时间。

2.3.2 为什么需要CUDA

CUDA是我们使用GPU的提供商——NVIDIA提供的GPU并行计算框架。对于GPU本身的编程,使用的是CUDA语言来实现的。但是,在我们使用PyTorch编写深度学习代码时,使用的CUDA又是另一个意思。在PyTorch使用 CUDA表示要开始要求我们的模型或者数据开始使用GPU了。

在编写程序中,当我们使用了 .cuda() 时,其功能是让我们的模型或者数据从CPU迁移到GPU(0)当中,通过GPU开始计算。

注:

  1. 我们使用GPU时使用的是.cuda()而不是使用.gpu()。这是因为当前GPU的编程接口采用CUDA,但是市面上的GPU并不是都支持CUDA,只有部分NVIDIA的GPU才支持,AMD的GPU编程接口采用的是OpenCL,在现阶段PyTorch并不支持。
  2. 数据在GPU和CPU之间进行传递时会比较耗时,我们应当尽量避免数据的切换。
  3. GPU运算很快,但是在使用简单的操作时,我们应该尽量使用CPU去完成。
  4. 当我们的服务器上有多个GPU,我们应该指明我们使用的GPU是哪一块,如果我们不设置的话,tensor.cuda()方法会默认将tensor保存到第一块GPU上,等价于tensor.cuda(0),这将会导致爆出out of memory的错误。我们可以通过以下两种方式继续设置。
    1.  #设置在文件最开始部分
      import os
      os.environ["CUDA_VISIBLE_DEVICE"] = "2" # 设置默认的显卡
      
    2.  CUDA_VISBLE_DEVICE=0,1 python train.py # 使用0,1两块GPU
      

2.3.3 常见的并行的方法:

网络结构分布到不同的设备中(Network partitioning)

在刚开始做模型并行的时候,这个方案使用的比较多。其中主要的思路是,将一个模型的各个部分拆分,然后将不同的部分放入到GPU来做不同任务的计算。其架构如下:

在这里插入图片描述

这里遇到的问题就是,不同模型组件在不同的GPU上时,GPU之间的传输就很重要,对于GPU之间的通信是一个考验。但是GPU的通信在这种密集任务中很难办到,所以这个方式慢慢淡出了视野。

同一层的任务分布到不同数据中(Layer-wise partitioning)

第二种方式就是,同一层的模型做一个拆分,让不同的GPU去训练同一层模型的部分任务。其架构如下:

在这里插入图片描述

这样可以保证在不同组件之间传输的问题,但是在我们需要大量的训练,同步任务加重的情况下,会出现和第一种方式一样的问题。

不同的数据分布到不同的设备中,执行相同的任务(Data parallelism)

第三种方式有点不一样,它的逻辑是,我不再拆分模型,我训练的时候模型都是一整个模型。但是我将输入的数据拆分。所谓的拆分数据就是,同一个模型在不同GPU中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出的数据做一个汇总,然后再反传。其架构如下:

在这里插入图片描述

这种方式可以解决之前模式遇到的通讯问题。现在的主流方式是数据并行的方式(Data parallelism)

2.3.4 使用CUDA加速训练

在PyTorch框架下,CUDA的使用变得非常简单,我们只需要显式的将数据和模型通过.cuda()方法转移到GPU上就可加速我们的训练,在此处我们仅讨论单卡的情况下,后续我们会介绍多卡训练的使用方法。

model = Net()
model.cuda() # 模型显示转移到CUDA上

for image,label in dataloader:
    # 图像和标签显示转移到CUDA上
    image = image.cuda() 
    label = label.cuda()

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

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

相关文章

【Linux多线程】详解线程控制、线程分离

线程互斥与同步 &#x1f478; 理解线程&#x1f934;pthead_t&#x1f977;关于线程&#x1f9b8;‍♀️线程控制POSIX线程库线程ID及进程地址空间布局 &#x1f9b8;线程分离__thread关键字&#x1f9b8;‍♂️pthread_detach函数&#x1f9b9;‍♀️pthread_exit函数&#x…

RNN架构解析——传统RNN模型

目录 传统RNN的内部结构图使用RNN优点和缺点 传统RNN的内部结构图 使用RNN rnnnn.RNN(5,6,1) #第一个参数是输入张量x的维度&#xff0c;第二个是隐藏层维度&#xff0c;第三层是隐藏层的层数 input1torch.randn(1,3,5) #第一个是输入序列的长度&#xff0c;第二个是批次的样本…

网络层IP协议的基本原理 数据链路层ARP协议 域名解析以及一些重要技术

目录 1 网络层IP协议协议头格式网段划分DHCPCIDR&#xff1a;基于子网掩码的划分方式特殊的IP号IP地址的数量限制私有IP地址和公网IP地址路由路由表 2 数据链路层 — 局域网的转发问题以太网认识以太网以太网帧格式局域网通信原理 MTUMTU对IP协议的影响MTU对UDP协议的影响MTU对…

自动化测试——APP测试

一、环境配置 1、安装jdk 配置环境变量 2、Android SDK 环境安装 3、Appium Server安装 4、模拟器安装 5、安装appium-python-client Python第三方库 二、APP自动化测试原理 三、Desired Capabilites——APPium自动化配置项 1、设置参数 2、操作系统 3、选择版本 4、设备名称…

CAN转EtherNet/IP网关can协议破解服务

JM-EIP-CAN 是自主研发的一款 ETHERNET/IP 从站功能的通讯网关。该产品主要功能是将各种 CAN 总线和 ETHERNET/IP 网络连接起来。 本网关连接到 ETHERNET/IP 总线中做为从站使用&#xff0c;连接到 CAN 总线中根据节点号进行读写。 技术参数 ETHERNET/IP 技术参数 网关做为 …

选择器jQuery

诚信是你价格不菲的鞋子&#xff0c;踏遍千山万水&#xff0c;质量也应永恒不变。 jQuery选择器大全总结&#xff1a; jQuery选择器是一种用于在HTML文档中选择元素的强大工具。下面是一些常用的jQuery选择器的总结&#xff1a; 基本选择器&#xff1a; 元素选择器&#xff1a…

HarmonyOS/OpenHarmony元服务开发-卡片使用动效能力

ArkTS卡片开放了使用动画效果的能力&#xff0c;支持显式动画、属性动画、组件内转场能力。需要注意的是&#xff0c;ArkTS卡片使用动画效果时具有以下限制&#xff1a; 以下示例代码实现了按钮旋转的动画效果&#xff1a; Entry Component struct AttrAnimationExample { St…

生命在于学习——APP渗透学习笔记

一、app渗透篇 1、Android 简介 自从 Android 被谷歌收购&#xff08;2005 年&#xff09;&#xff0c;谷歌已经完成了整个开发&#xff0c;在过去的 9 年里&#xff0c;尤其是在安全方面&#xff0c;有很多变化。 现在&#xff0c;它是世界上最广泛使用的智能手机平台&#…

PHP使用Redis实战实录4:单例模式和面向过程操作redis的语法

PHP使用Redis实战实录系列 PHP使用Redis实战实录1&#xff1a;宝塔环境搭建、6379端口配置、Redis服务启动失败解决方案PHP使用Redis实战实录2&#xff1a;Redis扩展方法和PHP连接Redis的多种方案PHP使用Redis实战实录3&#xff1a;数据类型比较、大小限制和性能扩展PHP使用Re…

IT技术面试必备:如何做好IT类技术面试?

博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;&#x1f3fb; 《java 面试题大全》 &#x1f369;惟余辈才疏学浅&#xff0c;临摹之作或有不妥之处&#xff0c;还请读者海涵指正。☕&#x1f36d; 《MYSQL从入门到精通》数据库是开发者必会基础之…

tinkerCAD案例:25. 量角器 - 测量角度

tinkerCAD案例&#xff1a;25. 量角器 - 测量角度 原文 Now we’re going to make a protractor! A Protractor is one of the most basic, but essential, tools for making measurements. It is, then, surprising that the modern protractor is barely over 200 years ol…

神经网络简单介绍

人工神经网络(artififial neural network) 简称神经网络&#xff0c;它是一种模仿生物神经网络结构和功能的非线性数学模型。 神经网络通过输入层接受原始特征信息&#xff0c;再通过隐藏层进行特征信息的加工和提取&#xff0c;最后通过输出层输出结果。 根据需要神经网络可以…

【机器学习】Linear Regression

Model Representation 1、问题描述2、表示说明3、数据绘图4、模型函数5、预测总结附录 1、问题描述 一套 1000 平方英尺 (sqft) 的房屋售价为300,000美元&#xff0c;一套 2000 平方英尺的房屋售价为500,000美元。这两点将构成我们的数据或训练集。面积单位为 1000 平方英尺&a…

数据可视化 - 动态柱状图

基础柱状图 通过Bar构建基础柱状图 from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 使用Bar构建基础柱状图 bar Bar() # 添加X轴 bar.add_xaxis(["中国", "美国", "英国"]) # 添加Y轴 # 设置数值标签在右侧 b…

乌班图22.04安装wireguard实现异地组网

1. 前言&#xff1a; wireguard是新型的异地组网工具&#xff0c;在此之前&#xff0c;又已经被抛弃的pptp&#xff0c;l2tp&#xff0c;有配置复杂的openvpn&#xff0c;wireguard被linux作者linus赞叹优雅&#xff0c;于linux 5.6合并至linux内核主线。 2. 安装过程&#…

【1.3】Java微服务:Spring Cloud版本说明

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…

【Java面试丨消息中间件】Kafka

一、kafka是如何保证消息不丢失 1. 介绍 使用kafka在消息的收发过程都有可能会出现消息丢失 &#xff08;1&#xff09;生产者发送消息到broker丢失 &#xff08;2&#xff09;消息在broker中存储丢失 &#xff08;3&#xff09;消费者从broker接收消息丢失 2. 生产者发送消…

Day47 算法记录|动态规划14子序列

子序列 1143. 最长公共子序列1035.不相交的线53. 最大子数组和 1143. 最长公共子序列 这道题和718. 最长重复子数组的区别&#xff1a;这道题的子序列可以不连续 这个视频讲解的很好 class Solution {public int longestCommonSubsequence(String text1, String text2) {char…

[Linux]线程基本知识

概念 进程 一个正在执行的程序&#xff0c;它是资源分配的最小单位 进程中的事情需要按照一定的顺序逐个进行 进程出现了很多弊端: 一是由于进程是资源拥有者&#xff0c;创建、撤消与切换存在较大的时空开销&#xff0c;因此需要引入轻型进程&#xff1b; 二是由于对称多…

高德地图JS API升级到2.0版本

项目上反馈高德地图底图信息更新不及时&#xff0c;不利于进行点位规划。经研究发现高德地图JS API 1.4.15版本相对于2.0版本&#xff0c;确实地图切片上的标注信息较少。通过工单的形式询问高德的技术工程师认识到1.4.15版本数据更新有延迟&#xff0c;1.4.15版本地图的数据以…