动手学深度学习9 多层感知机+代码实现

多层感知机+代码实现

  • 1. 感知机
  • 2. 多层感知机
    • 单隐藏层
    • 三个激活函数
    • 多隐藏层
  • 3. 代码实现
    • 从零开始实现
    • 简洁实现
    • 注意
  • 4. QA

1. 感知机

视频:https://www.bilibili.com/video/BV1hh411U7gn/?spm_id_from=autoNext&vd_source=eb04c9a33e87ceba9c9a2e5f09752ef8
书:https://zh-v2.d2l.ai/chapter_multilayer-perceptrons/mlp.html
课件:https://courses.d2l.ai/zh-v2/assets/pdfs/part-0_12.pdf

感知机:两分类任务,只有一个元素输出,如下,w和x做内积后加上b再过sigma函数,其值大于0输出1,值小于等于0输出0【也可以输出-1】
在这里插入图片描述
回归输出一个实数,不经过sigma处理
softmax回归不只输出一个元素,输出所有类别的值,可以做多分类的问题。
在这里插入图片描述
预测值大于0应该是正类,预测是小于等于0应该是负类,当预测正确的时候,真实值y乘以预测值<w,x>+b是正值大于0,当预测失败的时候,真实值y乘以预测值<w,x>+b是负值小于等于0,对每一个样本都做这样的判断,直到所有样本都分类正确。
损失函数取一个最大值【对应if条件】,当预测正确,用值取负和0比大小,取0,当预测失败,负的预测值是正的,最大值取负的预测值,损失函数增加。
在这里插入图片描述
猫狗类别划分,根据每一个类别是否划分正确,更新权重。
在这里插入图片描述
做两个假设,数据区域半径r,余量 ρ,存在一个分截面,使得分截面对所有分类都是正确的,而且有一定余量 ρ(≥0)。
r平方是数据的大小,ρ是数据是不是很好,两个分类是否能很好分开。
在这里插入图片描述

在任意二维坐标系内,无法找出一个线性分割面能将下图的点分割开,无法做分类。多层感知机能解决这个问题。
在这里插入图片描述
在这里插入图片描述

2. 多层感知机

第一步学习蓝色的线,第二步学习黄色的线,【复合两个函数】对两个结果做异或操作得出结果。
在这里插入图片描述

单隐藏层

输入输出层大小是由数据决定的,数据有多大,数据有多少类。隐藏层大小是可以自行设置的。
在这里插入图片描述
隐藏层:
权重:假设隐藏层大小m,输入是n维向量,则隐藏层的权重是m*n大小的矩阵
偏移:有多少个隐藏层就有多少个标量偏移
输出层:单分类输出,则权重m维向量,偏移只有一个
在这里插入图片描述

sigma函数不能是线性的,否则等价于单层的感知机。
在这里插入图片描述

三个激活函数

在这里插入图片描述
为什么有个-2?
在这里插入图片描述
上面两个激活函数都是感知机sigmoid函数的soft–柔软版本。
在这里插入图片描述

在cpu上计算指数函数比较贵,计算一次指数计算等于计算几百次乘法运算的花销。所以常用ReLU激活函数【计算简单】。

softmax做的事情:把所有输出单元拉到0-1之间,且所有分类的值等于1,表示为概率的形式。
多类分类感知机和softmax回归没有本质区别:没加隐藏层就是softmax回归,加了隐藏层就是多层感知机,名称上的变化。
在这里插入图片描述

和前面单分类的区别,就是在输出层,因为有k个输出,所以输出层权重w2是m*k的,偏移也是k维向量。
同时对输出要做一次softmax。
在这里插入图片描述

多隐藏层

上一层隐藏层的输入是下一层隐藏层的输出。
在这里插入图片描述
激活函数不能少,少了层数会减一,主要是为了避免层数的塌陷,最后一层输出层不需要激活函数。

超参数有两个:有几个隐藏层,每个隐藏层是多大。
配置好每一层隐藏层都有哪些东西、长什么样子【技术经验】。

根据输入数据复杂度的多少【维度高低】,考虑模型【大小和复杂度】。两个选择:

  1. 模型做的不深,但是每一层都很大
  2. 每一层不大,但是模型比较深

假设输入数据是128维【高】,输出是5类【低】,把高维数据压缩到低维。机器学习本质上是做压缩,把图片或者其他信息压缩成某一个类。
压缩的三个做法:

  1. 逐层慢慢压缩
  2. 第一层隐藏层可以比输入层稍微大一点,先扩张再压缩
  3. cnn–先压缩再扩张的模型,避免overfitting。
    在这里插入图片描述

3. 代码实现

从零开始实现

import torch
from torch import nn
from d2l import torch as d2l
from IPython import display

# 分类精度--判断预测的类别是否是正确的
def accuracy(y_hat, y):
    """计算预测正确的数量"""
    # 如果预测值是二维矩阵,而且每一行列数大于1
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        # 每一行元素预测值最大的下标存到y_hat中 argmax返回的是索引下标--获取概率最高类别的索引
        y_hat = y_hat.argmax(axis=1)
    # print(y_hat.dtype, y_hat.type(torch.float).dtype)
    # y_hat.type(y.dtype) 设置元素数值类型和y保持一致
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())  # 预测类型成功的个数
# print(accuracy(y_hat, y)/len(y))  # 预测成功率

def evaluate_accuracy(net, data_iter):
    """计算在指定数据集上模型的精度"""
    if isinstance(net, torch.nn.Module):
        net.eval()  # 将模型设置为评估模式
        # net.eval() 作用1. 网络结构如果有Batch Normalization 和 Dropout 层的,做模型评测必须加上这个命令以防止报错
        # 作用2: 关闭梯度计算
    # Accumulator 累加器 不断迭代数据X y 不断累加评测结果
    # Accumulator 初始化传入数值2 表示有数组有两个变量,第一个位置存正确测试数,第二个位置存样本总数,根据批次遍历依次累加
    metric = Accumulator(2) # 正确预测数、预测总数
    with torch.no_grad():
        for X, y in data_iter: # 迭代一次 一次批量
            # metric.add(该批次的预测类别正确的样本数,批次的总样本数)
            # y.numel() pytorch中用于返回张量的元素总个数
            metric.add(accuracy(net(X), y), y.numel())

    # 返回值=分类正确样本数/样本总数=精度
    return metric[0] / metric[1]

class Accumulator:
    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n

    def add(self, *args):
        # print(self.data, args)
        self.data = [a + float(b) for a,b in zip(self.data, args)]
        # print(self.data, args)
    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]

class Animator:
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None, ylim=None,
                 xscale='linear', yscale='linear', fmts=('-', 'm--', 'g--', 'r:'),
                 nrows=1, nclos=1, figsize=(3.5, 2.5)):

        # 增量的绘制多条线
        if legend is None:
            legend = []
        d2l.use_svg_display()
        self.fig, self.axes = d2l.plt.subplots(nrows, nclos, figsize=figsize)
        if nrows * nclos == 1:
            self.axes = [self.axes, ]
        # 使用lamda函数捕获参数
        self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts

    def add(self, x, y):
        # 向图表中添加多个数据点
        if not hasattr(y, "__len__"):
            y = [y]
        n = len(y)
        print('n------',n)
        if not hasattr(x, "__len__"):
            x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a,b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
        self.axes[0].cla()
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt)
        self.config_axes()
        display.display(self.fig)
        display.clear_output(wait=True)

def trian_epoch_ch3(net, train_iter, loss, updater):
    """训练模型一个迭代周期(定义见第三章)"""
    # 如果模型是用nn模组定义的
    if isinstance(net, torch.nn.Module):
        net.train()  # 将模型设置为训练模式 告诉pytorch要计算梯度
    # 训练损失总和、训练准确度总和、样本数
    metric = Accumulator(3)  # 三个参数需要累加的迭代器
    for X, y in train_iter:
        # 计算梯度并更新参数
        y_hat = net(X)
        l = loss(y_hat, y) # 计算损失函数
        # 如果优化器是pytorch内置的优化器
        # 下面两个加的结果有什么区别
        # print(float(l)*len(y), accuracy(y_hat,y), y.size().numel(),
        #       float(l.sum()), accuracy(y_hat, y), y.numel())
        if isinstance(updater, torch.optim.Optimizer):
            # 使用pytorch内置的优化器和损失函数
            updater.zero_grad() # 1.梯度先置零
            l.mean().backward() # 2.计算梯度
            updater.step()      # 3.调用step参数进行一次更新
            # metric.add(float(l)*len(y), accuracy(y_hat,y), y.size().numel())
            # 报错 ValueError: only one element tensors can be converted to Python scalars
        else:
            # 使用定制的优化器和损失函数
            # 自己实现的l是一个向量
            l.sum().backward()
            updater(X.shape[0])
            # metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
        metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
    # 返回训练损失和训练精度
    # 损失累加/总样本数  训练正确的/总样本数
    return metric[0] / metric[2], metric[1] / metric[2]

# 开启训练
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):
    """训练模型"""
    animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3,0.9],
                        legend=['train-loss', 'train-acc', 'test-acc'])
    for epoch in range(num_epochs):
        train_metrics = trian_epoch_ch3(net, train_iter, loss, updater)
        test_acc = evaluate_accuracy(net, test_iter)
        animator.add(epoch+1, train_metrics+(test_acc,))
    train_loss, train_acc = train_metrics
    print(train_loss)
    assert train_loss < 0.5, train_loss
    assert train_acc <= 1 and train_acc > 0.7, train_acc
    assert test_acc <= 1 and test_acc > 0.7, test_acc



batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

num_inputs, num_outputs, num_hiddens = 784, 10, 256
# 权重初始化 随机  全部设置0或1 试试有什么区别
W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True)*0.01) # *0.01?  # 
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True)*0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

# 为什么随机  可以设置为0 1 试试
# W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True)) # *0.01?  行数 列数 梯度
# b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
# W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True))
# b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2]

# torch.zeros_like(X) 函数  返回的变量类型及格式都与X一致,但是元素值是0
def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X, a)  # torch.max(a, X)

# 矩阵乘法 @符号简写
def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X @ W1 + b1)
    # O = H@W2 + b2
    return (H @ W2 + b2)

loss = nn.CrossEntropyLoss(reduction='none')
# loss = nn.CrossEntropyLoss(reduction='sum')
num_epochs, lr = 10, 0.01
updater = torch.optim.SGD(params, lr)
train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
# d2l.predict_ch3(net, test_iter)

# 损失下降了 但是精度没有提高?

# 深度学习的好处,模型变化很大,但是从代码实现的角度,只是改了一点点【模型结构的代码】

简洁实现

import torch
from torch import nn
from d2l import torch as d2l
from IPython import display

# 分类精度--判断预测的类别是否是正确的
def accuracy(y_hat, y):
    """计算预测正确的数量"""
    # 如果预测值是二维矩阵,而且每一行列数大于1
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        # 每一行元素预测值最大的下标存到y_hat中 argmax返回的是索引下标--获取概率最高类别的索引
        y_hat = y_hat.argmax(axis=1)
    # print(y_hat.dtype, y_hat.type(torch.float).dtype)
    # y_hat.type(y.dtype) 设置元素数值类型和y保持一致
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())  # 预测类型成功的个数
# print(accuracy(y_hat, y)/len(y))  # 预测成功率

def evaluate_accuracy(net, data_iter):
    """计算在指定数据集上模型的精度"""
    if isinstance(net, torch.nn.Module):
        net.eval()  # 将模型设置为评估模式
        # net.eval() 作用1. 网络结构如果有Batch Normalization 和 Dropout 层的,做模型评测必须加上这个命令以防止报错
        # 作用2: 关闭梯度计算
    # Accumulator 累加器 不断迭代数据X y 不断累加评测结果
    # Accumulator 初始化传入数值2 表示有数组有两个变量,第一个位置存正确测试数,第二个位置存样本总数,根据批次遍历依次累加
    metric = Accumulator(2) # 正确预测数、预测总数
    with torch.no_grad():
        for X, y in data_iter: # 迭代一次 一次批量
            # metric.add(该批次的预测类别正确的样本数,批次的总样本数)
            # y.numel() pytorch中用于返回张量的元素总个数
            metric.add(accuracy(net(X), y), y.numel())

    # 返回值=分类正确样本数/样本总数=精度
    return metric[0] / metric[1]

class Accumulator:
    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n

    def add(self, *args):
        # print(self.data, args)
        self.data = [a + float(b) for a,b in zip(self.data, args)]
        # print(self.data, args)
    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]

class Animator:
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None, ylim=None,
                 xscale='linear', yscale='linear', fmts=('-', 'm--', 'g--', 'r:'),
                 nrows=1, nclos=1, figsize=(3.5, 2.5)):

        # 增量的绘制多条线
        if legend is None:
            legend = []
        d2l.use_svg_display()
        self.fig, self.axes = d2l.plt.subplots(nrows, nclos, figsize=figsize)
        if nrows * nclos == 1:
            self.axes = [self.axes, ]
        # 使用lamda函数捕获参数
        self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts

    def add(self, x, y):
        # 向图表中添加多个数据点
        if not hasattr(y, "__len__"):
            y = [y]
        n = len(y)
        print('n------',n)
        if not hasattr(x, "__len__"):
            x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a,b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
        self.axes[0].cla()
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt)
        self.config_axes()
        display.display(self.fig)
        display.clear_output(wait=True)

def trian_epoch_ch3(net, train_iter, loss, updater):
    """训练模型一个迭代周期(定义见第三章)"""
    # 如果模型是用nn模组定义的
    if isinstance(net, torch.nn.Module):
        net.train()  # 将模型设置为训练模式 告诉pytorch要计算梯度
    # 训练损失总和、训练准确度总和、样本数
    metric = Accumulator(3)  # 三个参数需要累加的迭代器
    for X, y in train_iter:
        # 计算梯度并更新参数
        y_hat = net(X)
        l = loss(y_hat, y) # 计算损失函数
        # 如果优化器是pytorch内置的优化器
        # 下面两个加的结果有什么区别
        # print(float(l)*len(y), accuracy(y_hat,y), y.size().numel(),
        #       float(l.sum()), accuracy(y_hat, y), y.numel())
        if isinstance(updater, torch.optim.Optimizer):
            # 使用pytorch内置的优化器和损失函数
            updater.zero_grad() # 1.梯度先置零
            l.mean().backward() # 2.计算梯度
            updater.step()      # 3.调用step参数进行一次更新
            # metric.add(float(l)*len(y), accuracy(y_hat,y), y.size().numel())
            # 报错 ValueError: only one element tensors can be converted to Python scalars
        else:
            # 使用定制的优化器和损失函数
            # 自己实现的l是一个向量
            l.sum().backward()
            updater(X.shape[0])
            # metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
        metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
    # 返回训练损失和训练精度
    # 损失累加/总样本数  训练正确的/总样本数
    return metric[0] / metric[2], metric[1] / metric[2]

# 开启训练
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):
    """训练模型"""
    animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3,0.9],
                        legend=['train-loss', 'train-acc', 'test-acc'])
    for epoch in range(num_epochs):
        train_metrics = trian_epoch_ch3(net, train_iter, loss, updater)
        test_acc = evaluate_accuracy(net, test_iter)
        animator.add(epoch+1, train_metrics+(test_acc,))
    train_loss, train_acc = train_metrics
    print(train_loss)
    assert train_loss < 0.5, train_loss
    assert train_acc <= 1 and train_acc > 0.7, train_acc
    assert test_acc <= 1 and test_acc > 0.7, test_acc



net = nn.Sequential(nn.Flatten(),
          nn.Linear(784, 256),
          nn.ReLU(),
          nn.Linear(256, 10))
    
def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights)

loss = nn.CrossEntropyLoss(reduction='none')
batch_size, num_epochs, lr = 256, 10, 0.01
updater = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

# d2l.predict_ch3(net, test_iter)

# 损失下降了 但是精度没有提高?
# 深度学习的好处,模型变化很大,但是从代码实现的角度,只是改了一点点【模型结构的代码】

注意

  1. d2l包需要是0.17.5版本及以上,否则没有trian_ch3函数
  2. 代码运行loss过大无法显示在动画图片中,可以试试加大epoch或【】者loss模式修改为reduction=‘none’【 none 损失较大没有显示 mean 损失较小没有显示 sum 训练精度降低 奇怪?】
  3. 深度学习的好处,模型变化很大【MLP cnn等多模型】,但是从代码实现的角度,只是改了一点点【模型结构的代码】 所以用MLP–多层感知机 Multi layer Perceptron比较多,而SVM–支持向量机Support Vector Machine用的比较少【因为要改很多东西】

reduction=none w10.01 , w20.01
在这里插入图片描述

reduction=mean
在这里插入图片描述

在这里插入图片描述
reduction=none w10.01 , w20.01 epoch=30
在这里插入图片描述
reduction=none 代码的简洁实现
在这里插入图片描述

4. QA

  1. 一层网络,一般是说带权【每个箭头都是权重加偏移】的网络层, 也包含激活函数。一般定义输入层就不算一层了。【一层:权重加激活函数是怎么做计算的】【也可以输入层加权重加激活函数算一层,那么最后一层输出层就不算一层了,怎么看都可以。】只有两层w–所以只有两层网络。
    在这里插入图片描述

  2. 机器学习是统计在计算机应用的一个分支。收敛定理是统计学习的知识,一般数据区域r无法测量无法统计,找不到数据分布的区域。可以假设。

  3. SVM 用起来简单 MLP【Multilayer Perceptron 多层感知机】和其他nn网络模型调整简单,SVM调用所有的都要变比较麻烦。【多层感知机在svm之前】

  4. 多层感知机解决了XOR问题,SVM取代了感知机。多层感知机没有流行原因:1.得选超参数–多个隐藏层,每个隐藏层多大。不好收敛(有lr才好收敛)–svm对超参数不敏感。2.svm优化更容易求解,不做sgd。3.假设两个模型实际效果差不多,svm用起来更简单,数学性更好-可解释性。

  5. 为什么增加神经元隐藏层的层数而不是神经元的个数。神经元万有近似性质?
    深度学习【好训练 每一层都学一点简单的东西,更深容易找到一个比较好的解】 or 宽度学习【不好训练,容易overfit过拟合,每个神经元都是一个并行的关系】 优化函数解决不了太宽的问题。

  6. 神经元和卷积核有什么关系?感知机和卷积核的关系【卷积是怎么从感知机演变的。】

  7. 激活函数本质:引入非线性,把线性函数改成非线性函数。relu是分段线性函数不是线性函数。区别:不同激活函数在远点对梯度的影响不同。

  8. 不同激活函数对性能影响较小-差不多。远不如选择隐藏层神经元大小等超参数重要,可以直接用relu,本质上没有太多区别。

  9. 模型的深度更好训练,性能更好一些,没有最优的说法,可以多试一下。从简单开始,慢慢把模型变复杂,加深加宽都可以。
    搞个for训练多试一下,找感觉、直觉。

  10. 训练完参数是固定的,不是动态的【不要有动态性】。同一个数据经过同一个模型做预测,预测结果应该是一致的。 但是模型要有泛化性–鲁棒性Robustness【专门领域:“鲁棒性机器学习”(Robust Machine Learning)或"对抗性机器学习"(Adversarial Machine Learning)医疗无人车等领域稳定性都要很好】,输入数据多种多样,各种信息干扰,但是输出应该是稳定正确的。

  11. 在设置隐藏层的时候,会先认为评估特征的数量,在设置层数和单元数吗?
    可以先猜想是多少,再人为的拿数据–验证集来遛一遛,看看训练或测试的效果,再调参。

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

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

相关文章

如何修改Notes Domino中的默认通讯端口

大家好&#xff0c;才是真的好。 不知道有多少人知道&#xff0c;Notes客户机和Domino服务器之间默认的通讯协议叫做NRPC&#xff0c;很多人就直接称之为Notes协议&#xff0c;Notes和Domino服务器之间的数据通信&#xff0c;都是采用安全的NRPC协议&#xff0c;采用的端口默认…

EMQX 4.0和EMQX 5.0集群架构实现1亿MQTT连接哪些改进

EMQX 5.0水平扩展能力得到了指数级提升&#xff0c;能够更可靠地承载更大规模的物联网设备连接量。 在EMQX5.0正式发布前的性能测试中&#xff0c;我们通过一个23节点的EMQX集群&#xff0c;全球首个达成了1亿MQTT连接每秒100万消息吞吐&#xff0c;这也使得EMQX 5.0成为目前为…

echarts实践总结(常用一):柱状图(特点:渐变色、点击缩放、左右滑动、悬浮展示样式)

目录 第一章 echarts基本使用 第二章 echarts实践——柱状图 效果展示 第一章 echarts基本使用 Echarts常用配置项(详细入门)_echarts配置项手册-CSDN博客 第二章 echarts实践——柱状图 最近接到这么一个需求&#xff0c;需要画页面&#xff0c;然后有这么几个echarts的图需…

25双体系Java学习之StringBuffer和StringBuilder

StringBuffer和StringBuilder ★小贴士 String str new String("welcome to "); str "here"; 字符串的拼接过程实际上是通过建立一个StringBuffer&#xff0c;然后调用StringBuffer的append方法&#xff0c;最后再将StringBuffer转为字符串&#xff0c…

【网络安全】0xhacked CTF 大赛题解出炉啦!

此次 0xhacked CTF 比赛&#xff0c;ChainSecLabs 取得了第四名的成绩。让我们来看看比赛题目的题解吧。&#xff08;题目代码仓库在文末哦~&#xff09; BabyOtter 这是应该说是一个算法题&#xff0c;很明显需要溢出&#xff0c;因为精度问题&#xff0c;uint256(-1)/0x1…

代码随想录算法训练营第二十四天|● 理论基础 ● 77. 组合(JS写法)

回溯理论基础 回溯法解决的问题都可以抽象为树形结构&#xff0c;因为回溯法解决的都是在集合中递归查找子集&#xff0c;集合的大小就构成了树的宽度&#xff0c;递归的深度&#xff0c;都构成的树的深度。递归就要有终止条件&#xff0c;所以必然是一棵高度有限的树&#xff…

仰卧起坐计数,YOLOV8POSE

仰卧起坐计数&#xff0c;YOLOV8POSE 通过计算膝盖、腰部、肩部的夹角&#xff0c;计算仰卧起坐的次数

springboot278基于JavaWeb的鲜牛奶订购系统的设计与实现

鲜牛奶订购系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统鲜牛奶订购信息管理难度大&…

Python使用 k 均值对遥感图像进行语义分割

本篇文章介绍K-means语义分割来估计 2000 年至 2023 年咸海水面的变化 让我们先看一下本教程中将使用的数据。这是同一地区的两张 RGB 图像,间隔 23 年,但很明显地表特性和大气条件(云、气溶胶等)不同。这就是为什么我决定训练两个独立的 k-Means 模型,每个图像一个。 首…

水下蓝牙耳机哪个牌子好?推荐四款高人气力作游泳耳机

在这个充满活力的时代&#xff0c;人们对于生活的追求早已不仅仅局限于日常的琐碎&#xff0c;更多的是对健康、对自我挑战的向往。运动&#xff0c;成为了现代人生活中不可或缺的一部分。而游泳&#xff0c;作为一项既能锻炼全身&#xff0c;又能享受水中美妙的运动&#xff0…

广州地铁线路规划

使用python实现后端功能&#xff0c;由于地铁图需要进行展示&#xff0c;svg图需要花费比较多的时间&#xff0c;这里使用了 MetroFlow 库构建的地铁地图编辑器&#xff0c;可以在画布上构建矢量图&#xff0c;实现站点路线的创建。 用法&#xff1a; 打包好后完整目录&#x…

CornerStone之读取txt文件点数据

1. 页面标签 页面中目前只提供一个按钮来进行输入文件 <input click"importZeroOne" type"file" />2. 函数定义 在输入文件之后&#xff0c;执行importZeroOne函数&#xff0c;获得输入的文件&#xff0c;进行以下处理 const importZeroOne((eve…

windows 11访问Debian10上的共享目录

步骤 要在Windows 11上访问Debian 10.0.0的共享目录&#xff0c;可以通过以下步骤来实现&#xff1a; 1. 设置Samba服务&#xff1a;在Debian系统上&#xff0c;需要安装并配置Samba服务&#xff0c;以便能够实现文件夹共享。Samba是一个允许Linux/Unix服务器与Windows操作系…

【数据结构与算法】(15):归并排序的递归和非递归方式

&#x1f921;博客主页&#xff1a;Code_文晓 &#x1f970;本文专栏&#xff1a;数据结构与算法 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多数据结构与算法点击专栏链接查看&…

二、C#选择排序算法

简介 选择排序算法的基本思想是每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;然后&#xff0c;再从剩余未排序元素中继续寻找最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序序列…

【ArcGISProSDK】获取扩展模块许可到期时间

结果 以下是获取的3D分析模块的许可到期时间 代码 var licenseExpirationDate ArcGIS.Core.Licensing.LicenseInformation.GetExpirationDate(LicenseCodes.Analyst3D); 扩展模块 MemberDescriptionAnalyst3D3D AnalystAviationAirportsAviation and AirportsBusinessAnal…

绿色再生·安卓4G智能远程操作巡视机器人小车

一、前言 1.1 项目介绍 【1】项目功能介绍 随着物联网技术与移动通信技术的快速发展&#xff0c;远程遥控设备在日常生活及工业应用中的普及度日益提高。无论是家用扫地机器人实现自主导航清扫&#xff0c;还是目前抖音平台上展示的实景互动小车等创新应用&#xff0c;都体现…

ICBatlas数据库-转录组免疫检查点阻断疗法数据

ICBatlas: A Comprehensive Resource for Depicting Immune Checkpoint Blockade Therapy Characteristics from Transcriptome Profiles 介绍&#xff1a;在线ICBatlas (hust.edu.cn) 检查点阻断 &#xff08;ICB&#xff09; 疗法为多种癌症类型提供了显着的临床益处。目前…

6语言交易所/多语言交易所php源码/微盘PHP源码

6语言交易所PHP源码&#xff0c;简单测试了一下&#xff0c;功能基本都是正常的。 由于是在本地测试的运行环境的问题&#xff0c;K线接口有点问题&#xff0c;应该在正式环境下是OK的。 源码下载地址&#xff1a;6语言交易所/多语言交易所php源码/微盘PHP源码.zip 程序截图…

【安装教程】安装cudnn

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 安装cudnn 前言一、下载和自己cuda匹配的cudnn二、安装cudnn 前言 首先我是已经安装了cuda&#xff0c;但是因为没有安装cudnn在跑程序的时候出现了一些问题&#xff0c;因此…