深度学习 精选笔记(4)线性神经网络-交叉熵回归与Softmax 回归

学习参考:

  • 动手学深度学习2.0
  • Deep-Learning-with-TensorFlow-book
  • pytorchlightning

①如有冒犯、请联系侵删。
②已写完的笔记文章会不定时一直修订修改(删、改、增),以达到集多方教程的精华于一文的目的。
③非常推荐上面(学习参考)的前两个教程,在网上是开源免费的,写的很棒,不管是开始学还是复习巩固都很不错的。

深度学习回顾,专栏内容来源多个书籍笔记、在线笔记、以及自己的感想、想法,佛系更新。争取内容全面而不失重点。完结时间到了也会一直更新下去,已写完的笔记文章会不定时一直修订修改(删、改、增),以达到集多方教程的精华于一文的目的。所有文章涉及的教程都会写在开头、一起学习一起进步。

一、交叉熵回归

交叉熵回归(Cross-Entropy Regression):交叉熵是一种用于衡量两个概率分布之间差异的指标,在机器学习中常用于分类问题的损失函数。交叉熵回归通常用于二分类问题,其中模型输出的是一个概率值,表示样本属于某一类的概率,损失函数是交叉熵损失函数。交叉熵损失函数可以表示为:
在这里插入图片描述

二、Softmax 回归

Softmax 回归:Softmax 回归是一种多分类模型,用于将模型的输出转化为多个类别的概率分布。在 Softmax 回归中,模型的最后一层是一个 Softmax 函数,将模型的输出转化为每个类别的概率,使得所有类别的概率之和为 1。
在这里插入图片描述

交叉熵回归通常用于二分类问题,而 Softmax 回归用于多分类问题。此外,Softmax 回归中的 Softmax 函数将模型输出转化为概率分布,而交叉熵回归中的损失函数用于衡量二分类模型输出与真实标签的差异。

1.分类问题

分类任务是机器学习和统计学中常见的一类任务,其目标是将数据集中的样本划分到预定义的类别或标签中。分类任务通常涉及预测离散的输出值,即将样本分为不同的类别。例如,将电子邮件分为“垃圾邮件”和“非垃圾邮件”、将图片识别为“猫”、“狗”或“鸟”等。

分类问题是指解决这类分类任务的问题。分类问题的关键在于构建一个分类模型,该模型可以根据输入的特征将样本正确地分配到各个类别中。常用的分类算法包括逻辑回归、支持向量机(SVM)、决策树、随机森林、K近邻(K-NN)等。

一种表示分类数据的简单方法:独热编码(one-hot encoding)。 独热编码是一个向量,它的分量和类别一样多。 类别对应的分量设置为1,其他所有分量设置为0。 从一个图像分类问题开始,假设每个图像属于类别“猫”“鸡”和“狗”中的一个、每次输入是一个 2×2 的灰度图像、每个图像对应四个特征𝑥1,𝑥2,𝑥3,𝑥4。标签 𝑦将是一个三维向量, 其中 (1,0,0) 对应于“猫”、 (0,1,0) 对应于“鸡”、 (0,0,1) 对应于“狗”。
在这里插入图片描述

2.网络结构

为了估计所有可能类别的条件概率,需要一个有多个输出的模型,每个类别对应一个输出。 为了解决线性模型的分类问题,需要和输出一样多的仿射函数(affine function)。 每个输出对应于它自己的仿射函数。

在识别猫、鸡、狗的任务中,为每个输入计算三个未规范化的预测(logit):𝑜1、𝑜2和𝑜3:
在这里插入图片描述
与线性回归一样,softmax回归也是一个单层神经网络。 由于计算每个输出 𝑜1 、 𝑜2 和 𝑜3取决于 所有输入 𝑥1 、 𝑥2 、 𝑥3 和 𝑥4 , 所以softmax回归的输出层也是全连接层。
在这里插入图片描述
通过向量形式表达为𝐨=𝐖𝐱+𝐛, 这是一种更适合数学和编写代码的形式。 由此,已经将所有权重放到一个3×4矩阵中。 对于给定数据样本的特征𝐱, 输出是由权重与输入特征进行矩阵-向量乘法再加上偏置𝐛得到的。

3.softmax运算

将优化参数以最大化观测数据的概率。 为了得到预测结果,将设置一个阈值,如选择具有最大概率的标签。

softmax函数能够将未规范化的预测变换为非负数并且总和为1,同时让模型保持 可导的性质。 为了完成这一目标,我们首先对每个未规范化的预测求幂,这样可以确保输出非负。 为了确保最终输出的概率值总和为1,我们再让每个求幂后的结果除以它们的总和。如下式:
在这里插入图片描述
因此, 𝐲̂ 可以视为一个正确的概率分布。 softmax运算不会改变未规范化的预测 𝐨之间的大小次序,只会确定分配给每个类别的概率。 因此,在预测过程中,仍然可以用下式来选择最有可能的类别。

在这里插入图片描述
尽管softmax是一个非线性函数,但softmax回归的输出仍然由输入特征的仿射变换决定。 因此,softmax回归是一个线性模型(linear model)。

4.小批量样本的矢量化

为了提高计算效率并且充分利用GPU,通常会对小批量样本的数据执行矢量计算。 softmax回归的矢量计算表达式为:
在这里插入图片描述
相对于一次处理一个样本, 小批量样本的矢量化加快了 𝐗和𝐖的矩阵-向量乘法。 由于 𝐗中的每一行代表一个数据样本, 那么softmax运算可以按行(rowwise)执行: 对于 𝐎 的每一行,先对所有项进行幂运算,然后通过求和对它们进行标准化。

5.损失函数

需要一个损失函数来度量预测的效果。 将使用最大似然估计,这与在线性回归中相同。

(1)对数似然

softmax函数给出了一个向量 𝐲̂ , 可以将其视为“对给定任意输入 𝐱的每个类的条件概率”。 例如, 𝑦̂ 1 = 𝑃(𝑦=猫∣𝐱)。 假设整个数据集 {𝐗,𝐘}具有 𝑛个样本, 其中索引 𝑖的样本由特征向量 𝐱(𝑖)和独热标签向量 𝐲(𝑖)组成。 可以将估计值与实际值进行比较:
在这里插入图片描述
根据最大似然估计,最大化 𝑃(𝐘∣𝐗) ,相当于最小化负对数似然:
在这里插入图片描述
其中,对于任何标签 𝐲和模型预测 𝐲̂ ,损失函数为:
在这里插入图片描述
上述损失函数 通常被称为交叉熵损失公式(cross-entropy loss)

(2)softmax及其导数

由于softmax和相关的损失函数很常见, 因此需要更好地理解它的计算方式。将𝐲̂ =softmax(𝐨) 代入交叉熵损失公式中,得到:
在这里插入图片描述
考虑相对于任何未规范化的预测 𝑜𝑗 的导数,得到:
在这里插入图片描述
上述最终导数表示,导数是softmax模型分配的概率与实际发生的情况(由独热标签向量表示)之间的差异。

(3)交叉熵损失

定义损失 𝑙, 它是所有标签分布的预期损失值。 此损失称为交叉熵损失(cross-entropy loss),它是分类问题最常用的损失之一。
在这里插入图片描述

用一个概率向量表示来阐述整个结果的分布情况,如 (0.1,0.2,0.7), 而不是仅包含二元项的向量 (0,0,1) ,,即观察到的不仅仅是一个结果。

6.模型预测和评估

在训练softmax回归模型后,给出任何样本特征,便可以预测每个输出类别的概率。 通常使用预测概率最高的类别作为输出类别。 如果预测与实际类别(标签)一致,则预测是正确的。最后使用精度(accuracy)来评估模型的性能。 精度等于正确预测数与预测总数之间的比率。

三、Fashion-MNIST图片分类数据集

1.加载数据集

通过框架中的内置函数将Fashion-MNIST数据集下载并读取到内存中。Fashion-MNIST由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像 和测试数据集(test dataset)中的1000张图像组成。 因此,训练集和测试集分别包含60000和10000张图像。 测试数据集不会用于训练,只用于评估模型性能。

每个输入图像的高度和宽度均为28像素。 数据集由灰度图像组成,其通道数为1。 为了简洁起见、将高度 ℎ 像素、宽度 𝑤像素图像的形状记为 ℎ×𝑤或( ℎ , 𝑤 )。

%matplotlib inline
import tensorflow as tf
from d2l import tensorflow as d2l

d2l.use_svg_display()

#执行之后会启动下载数据集到本地,不建议开飞机再运行此代码下载、亲测会丢包导致数据不完整而报错。
mnist_train, mnist_test = tf.keras.datasets.fashion_mnist.load_data()

如果下载失败(通常是这个文件t10k-images-idx3-ubyte.gz失败),也可以直接访问 Fashion-MNIST 数据集的官方网站或者仓库:Fashion-MNIST.

  • 下载数据集文件夹。

  • 将这四个文件放置在您项目的数据集目录中,例如 ~/.keras/datasets/fashion-mnist/。

下载失败的话删除~/.keras/datasets/fashion-mnist/文件夹重新运行直到成功为止。

Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
29515/29515 [==============================] - 0s 1us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26421880/26421880 [==============================] - 6s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
5148/5148 [==============================] - 0s 0s/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4422102/4422102 [==============================] - 1s 0us/step

Fashion-MNIST中包含的10个类别,分别为t-shirt(T恤)、trouser(裤子)、pullover(套衫)、dress(连衣裙)、coat(外套)、sandal(凉鞋)、shirt(衬衫)、sneaker(运动鞋)、bag(包)和ankle boot(短靴)。 以下函数用于在数字标签索引及其文本名称之间进行转换。

def get_fashion_mnist_labels(labels):  #@save
    """返回Fashion-MNIST数据集的文本标签"""
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
#创建一个函数来可视化这些样本
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):  #@save
    """绘制图像列表"""
    figsize = (num_cols * scale, num_rows * scale)
    _, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
    axes = axes.flatten()
    for i, (ax, img) in enumerate(zip(axes, imgs)):
        ax.imshow(img.numpy())
        ax.axes.get_xaxis().set_visible(False)
        ax.axes.get_yaxis().set_visible(False)
        if titles:
            ax.set_title(titles[i])
    return axes

查看数据:

X = tf.constant(mnist_train[0][:10])
y = tf.constant(mnist_train[1][:10])
show_images(X, 2, 5, titles=get_fashion_mnist_labels(y));

在这里插入图片描述

2.读取小批量数据

为了在读取训练集和测试集时更容易,使用内置的数据迭代器,而不是从零开始创建。在每次迭代中,数据迭代器每次都会读取一小批量数据,大小为batch_size。 通过内置数据迭代器,可以随机打乱了所有样本,从而无偏见地读取小批量。

batch_size = 256
train_iter = tf.data.Dataset.from_tensor_slices(
    mnist_train).batch(batch_size).shuffle(len(mnist_train[0]))

数据迭代器是获得更高性能的关键组件。依靠实现良好的数据迭代器,利用高性能计算来避免减慢训练过程。

3.整合组件

def load_data_fashion_mnist(batch_size, resize=None):   #@save
    """下载Fashion-MNIST数据集,然后将其加载到内存中"""
    mnist_train, mnist_test = tf.keras.datasets.fashion_mnist.load_data()
    # 将所有数字除以255,使所有像素值介于0和1之间,在最后添加一个批处理维度,
    # 并将标签转换为int32。
    process = lambda X, y: (tf.expand_dims(X, axis=3) / 255,
                            tf.cast(y, dtype='int32'))
    resize_fn = lambda X, y: (
        tf.image.resize_with_pad(X, resize, resize) if resize else X, y)
    return (
        tf.data.Dataset.from_tensor_slices(process(*mnist_train)).batch(
            batch_size).shuffle(len(mnist_train[0])).map(resize_fn),
        tf.data.Dataset.from_tensor_slices(process(*mnist_test)).batch(
            batch_size).map(resize_fn))

通过指定resize参数来测试load_data_fashion_mnist函数的图像大小调整功能。

train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
    print(X.shape, X.dtype, y.shape, y.dtype)
    break

四、从0实现softmax回归

1.加载数据集

引入Fashion-MNIST数据集, 并设置数据迭代器的批量大小为256。

import tensorflow as tf
from IPython import display
from d2l import tensorflow as d2l


batch_size = 256
# load_data_fashion_mnist函数已封装在d2l模块里面可以直接调用。也可以调用上面的。
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

2.初始化模型参数

输出与类别一样多。 (因为数据集有10个类别,所以网络输出维度为10)。 因此,权重将构成一个 784×10 的矩阵, 偏置将构成一个 1×10 的行向量。 与线性回归一样,将使用正态分布初始化权重W,偏置初始化为0。

num_inputs = 784
num_outputs = 10

W = tf.Variable(tf.random.normal(shape=(num_inputs, num_outputs),
                                 mean=0, stddev=0.01))
b = tf.Variable(tf.zeros(num_outputs))

3.定义softmax操作

实现softmax由三个步骤组成:

  • 对每个项求幂(使用exp);
  • 对每一行求和(小批量中每个样本是一行),得到每个样本的规范化常数;
  • 将每一行除以其规范化常数,确保结果的和为1。
def softmax(X):
    X_exp = tf.exp(X)
    partition = tf.reduce_sum(X_exp, 1, keepdims=True)
    return X_exp / partition  # 这里应用了广播机制

对于任何随机输入,将每个元素变成一个非负数。 此外,依据概率原理,每行总和为1。

4.定义模型

定义softmax操作后,可以实现softmax回归模型。 下面的代码定义了输入如何通过网络映射到输出。 注意,将数据传递到模型之前,使用reshape函数将每张原始图像展平为向量。

def net(X):
    return softmax(tf.matmul(tf.reshape(X, (-1, W.shape[0])), W) + b)

5.交叉熵损失函数

实现交叉熵损失函数

def cross_entropy(y_hat, y):
    return -tf.math.log(tf.boolean_mask(
        y_hat, tf.one_hot(y, depth=y_hat.shape[-1])))


6.分类精度

当预测与标签分类y一致时,即是正确的。 分类精度即正确预测数量与总预测数量之比。 虽然直接优化精度可能很困难(因为精度的计算不可导), 但精度通常是最关心的性能衡量标准,在训练分类器时几乎总会关注它。

def accuracy(y_hat, y):  #@save
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = tf.argmax(y_hat, axis=1)
    cmp = tf.cast(y_hat, y.dtype) == y
    return float(tf.reduce_sum(tf.cast(cmp, y.dtype)))

同样,对于任意数据迭代器data_iter可访问的数据集, 可以评估在任意模型net的精度。

def evaluate_accuracy(net, data_iter):  #@save
    """计算在指定数据集上模型的精度"""
    metric = Accumulator(2)  # 正确预测数、预测总数
    for X, y in data_iter:
        metric.add(accuracy(net(X), y), d2l.size(y))
    return metric[0] / metric[1]

定义一个实用程序类Accumulator,用于对多个变量进行累加。 在上面的evaluate_accuracy函数中, 在Accumulator实例中创建了2个变量, 分别用于存储正确预测的数量和预测的总数量。 当遍历数据集时,两者都将随着时间的推移而累加。

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

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

    def reset(self):
        self.data = [0.0] * len(self.data)

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

7.训练模型

定义一个函数来训练一个迭代周期。 请注意,updater是更新模型参数的常用函数,它接受批量大小作为参数。 它可以是d2l.sgd函数,也可以是框架的内置优化函数。

def train_epoch_ch3(net, train_iter, loss, updater):  #@save
    """训练模型一个迭代周期(定义见第3章)"""
    # 训练损失总和、训练准确度总和、样本数
    metric = Accumulator(3)
    for X, y in train_iter:
        # 计算梯度并更新参数
        with tf.GradientTape() as tape:
            y_hat = net(X)
            # Keras内置的损失接受的是(标签,预测),这不同于用户在本书中的实现。
            # 本书的实现接受(预测,标签),例如我们上面实现的“交叉熵”
            if isinstance(loss, tf.keras.losses.Loss):
                l = loss(y, y_hat)
            else:
                l = loss(y_hat, y)
        if isinstance(updater, tf.keras.optimizers.Optimizer):
            params = net.trainable_variables
            grads = tape.gradient(l, params)
            updater.apply_gradients(zip(grads, params))
        else:
            updater(X.shape[0], tape.gradient(l, updater.params))
        # Keras的loss默认返回一个批量的平均损失
        l_sum = l * float(tf.size(y)) if isinstance(
            loss, tf.keras.losses.Loss) else tf.reduce_sum(l)
        metric.add(l_sum, accuracy(y_hat, y), tf.size(y))
    # 返回训练损失和训练精度
    return metric[0] / metric[2], metric[1] / metric[2]

训练函数实现之前,定义一个在动画中绘制数据的实用程序类Animator, 它能够简化本书其余部分的代码。

class Animator:  #@save
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
                 ylim=None, xscale='linear', yscale='linear',
                 fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
                 figsize=(3.5, 2.5)):
        # 增量地绘制多条线
        if legend is None:
            legend = []
        d2l.use_svg_display()
        self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使用lambda函数捕获参数
        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)
        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)

实现一个训练函数, 它会在train_iter访问到的训练数据集上训练一个模型net。 该训练函数将会运行多个迭代周期(由num_epochs指定)。 在每个迭代周期结束时,利用test_iter访问到的测试数据集对模型进行评估。

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save
    """训练模型(定义见第3章)"""
    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 = train_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
    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

作为一个从零开始的实现,使用定义的 小批量随机梯度下降来优化模型的损失函数,设置学习率为0.1。

class Updater():  #@save
    """用小批量随机梯度下降法更新参数"""
    def __init__(self, params, lr):
        self.params = params
        self.lr = lr

    def __call__(self, batch_size, grads):
        d2l.sgd(self.params, grads, self.lr, batch_size)

updater = Updater([W, b], lr=0.1)

之前定义的小批量随机梯度下降如下,已经封装在d2l模块中了:

def sgd(params, grads, lr, batch_size):  #@save
    """小批量随机梯度下降"""
    for param, grad in zip(params, grads):
        param.assign_sub(lr*grad/batch_size)

训练模型50个迭代周期。 请注意,迭代周期(num_epochs)和学习率(lr)都是可调节的超参数。 通过更改它们的值,可以提高模型的分类精度。

num_epochs = 50
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)

在这里插入图片描述

8.预测

模型已经准备好对图像进行分类预测。 给定一系列图像,将比较它们的实际标签(文本输出的第一行)和模型预测(文本输出的第二行)。

def predict_ch3(net, test_iter, n=6):  #@save
    """预测标签(定义见第3章)"""
    for X, y in test_iter:
        break
    trues = d2l.get_fashion_mnist_labels(y)
    preds = d2l.get_fashion_mnist_labels(tf.argmax(net(X), axis=1))
    titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
    d2l.show_images(
        tf.reshape(X[0:n], (n, 28, 28)), 1, n, titles=titles[0:n])

predict_ch3(net, test_iter)

在这里插入图片描述

五、简洁实现softmax回归

softmax回归的输出层是一个全连接层,只需在Sequential中添加一个带有10个输出的全连接层。

import tensorflow as tf
from d2l import tensorflow as d2l

#加载数据集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

# 初始化模型参数,仍然以均值0和标准差0.01随机初始化权重。
net = tf.keras.models.Sequential()
net.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
weight_initializer = tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.01)
net.add(tf.keras.layers.Dense(10, kernel_initializer=weight_initializer))

# 交叉熵损失函数,在交叉熵损失函数中传递未规范化的预测,并同时计算softmax及其对数。
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

# 使用学习率为0.1的小批量随机梯度下降作为优化算法
trainer = tf.keras.optimizers.SGD(learning_rate=0.1)

# 调用之前定义的训练函数训练模型
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

这里为什么是d2l.train_ch3函数来训练而不是类似tf内置的model.fit()呢?因为train_ch3函数里面已经封装好了训练过程和可视化功能。利用Animator类来可视化训练进度。
在这里插入图片描述
预测:

d2l.predict_ch3(net, test_iter)

在这里插入图片描述

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

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

相关文章

为什么网站页面没有被百度搜索收录?是网站被攻击了?

例如&#xff0c;为什么网站页面没有被百度搜索收录&#xff1f; 网站是否受到攻击&#xff1f; 网站索引量和网站流量之间有关系吗&#xff1f; 您在运行网站或小程序时是否有过这样的疑问&#xff1f; 下面我将为大家详细解答这些问题。 1.PC/H5站点相关 1、为什么新网站页面…

蓝桥杯Learning

Part 1 递归和递推 1. 简单斐波那契数列 n int(input())st [0]*(47) # 注意这个地方&#xff0c;需要将数组空间设置的大一些&#xff0c;否则会数组越界 st[1] 0 st[2] 1 # 这个方法相当于是递推&#xff0c;即先求解一个大问题的若干个小问题 def dfs(u):if u 1:print(…

Linux如何查看端口是否占用

在Linux中&#xff0c;有多种方法可以用来检查端口是否被占用。以下是一些常用的命令&#xff1a; netstat&#xff1a;这是一个非常通用的命令&#xff0c;可以用来查看所有端口的使用情况。如果你想查找特定的端口是否被占用&#xff0c;可以使用netstat命令配合grep。例如&…

pytest教程-13-conftest.py文件

上一小节我们学习了fixture的作用域&#xff0c;本小节我们学习一下pytest conftest.py文件的使用方法。 conftest.py文件的作用 conftest.py文件是pytest框架中的一个特殊文件&#xff0c;用于定义共享的设置、夹具(fixture)和钩子函数&#xff08;hook&#xff09;。 在py…

Java学习-简单算法与正则表达式

1.排序算法 a.冒泡排序&#xff1a; 每轮找出当前最大值&#xff0c;冒到前面&#xff0c;循环长度减一次&#xff0c;每轮从1个比较到长度减i个 b.选择排序&#xff1a; 每一轮选择每一个位置的数组元素和后面的元素比较&#xff0c;从第i1个比较到最后一个 选择排序的优化&am…

Netty的InboundHandler 和OutboundHandler

一、InboundHandler 和OutboundHandler的区别 在Netty中&#xff0c;"inbound"表示来自外部来源&#xff08;如网络连接&#xff09;的数据&#xff0c;而"outbound"则表示从应用程序发送到外部目标&#xff08;如网络连接或其他服务&#xff09;的数据。…

2、事件机制、DOM操作、jquery对尺寸操作、jquery添加和删除

一、事件机制 1、事件源.事件类型(事件处理程序) $(this)中的this不能加引号 $(#box).click(function () {$(this).css(background-color,blue)//点击颜色变为蓝色 })2、事件源.on/bind(事件类型&#xff0c;事件处理程序) $("#box").on(dbclick,function () {$(…

MySQL:错误ERROR 1045 (28000)详解

1.问题说明 有时候我们登录Mysql输入密码的时候&#xff0c;会出现这种情况&#xff1a; mysql -u root -p Enter Password > ‘密码’ 错误&#xff1a;ERROR 1045 (28000): Access denied for user ‘root’‘localhost’ (using password: YES) 或者&#xff1a;错误…

CTFHUB--文件包含漏洞--RCE

文件包含漏洞 文件包含漏洞也是一种注入型漏洞&#xff0c;其本质就是输入一段用户能够控制的脚本或者代码&#xff0c;并让服务端执行。有时候由于网站功能需求&#xff0c;会让前端用户选择要包含的文件&#xff0c;而开发人员又没有对要包含的文件进行安全考虑&#xff0c;…

修改centos7的dns解决docker拉取镜像超时问题

近期在一台centos7的服务器上部署系统&#xff0c;拉取docker镜像时总是超时&#xff0c;如图所示。网上有教程说&#xff0c;可以修改操纵系统的dns地址&#xff0c;试了一下&#xff0c;果然搞定。 打开dns配置文件 sudo vi /etc/resolv.conf发觉里面的地址设为114.114.114…

Unity铰链四杆机构设计和运动仿真

一、效果图 设定好各边长度和转速后&#xff0c;点击【设置并启动】&#xff0c;自动生成一个机构模型&#xff0c;并按照原理进行运转 二、铰链四杆机构介绍 机架&#xff1a;A和D是固定位置&#xff0c;叫做机架。 曲柄&#xff1a;B点绕A点旋转&#xff0c;构成曲柄。 连…

什么是VR数字文化遗产保护|元宇宙文旅

VR数字文化遗产保护是指利用虚拟现实&#xff08;VR&#xff09;技术来保护和传承文化遗产。在数字化时代&#xff0c;许多珍贵的文化遗产面临着自然衰退、人为破坏或其他因素造成的威胁。通过应用VR技术&#xff0c;可以以全新的方式记录、保存和展示文化遗产&#xff0c;从而…

sqlserver 改变decimal 精度

遇到需要修改精度的业务场景: 可能是数据库存的精度和小数位太多,需要减少: 比较全能的CAST转换: CAST(你的字段 AS DECIMAL(38,10)) ↓ CAST(你的字段 AS DECIMAL(38,2)) 在 SQL Server 中&#xff0c;decimal 数据类型通常使用两个参数来定义其精度和小数位数。这两个…

MySQL进阶:视图存储过程存储函数触发器

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;MySQL进阶&#xff1a;大厂高频面试——各类SQL语句性能调优经验 &#x1f4da;订阅专栏&#xff1a;MySQL进阶 希望文章对你们有…

leetcode 3.1

leetcode hot 100 双指针1.三数之和2.接雨水 多维动态规划1.最长公共子序列 双指针 1.三数之和 三数之和 排序 双指针的方法&#xff0c;固定一个数nums[i], 用两数和找target - nums[i] 的数需要注意两点: 1.需要去掉重复数字 while (l < r && nums[l] nums[…

【Numpy】成功解决AttributeError: ‘Tuple‘ object has no attribute ‘shape‘

【Numpy】成功解决AttributeError: ‘Tuple’ object has no attribute ‘shape’ &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&…

Java+SpringBoot+Vue:招生宣传的全栈解决方案

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

linux系统Jenkins工具配置webhook自动部署

Jenkins工具webhook自动部署 webhook自动部署webhook的意义操作流程jenkins页面操作gitlab页面操作 webhook自动部署 webhook的意义 自动化部署&#xff1a;Webhook 可以在代码提交、合并请求或其他特定事件发生时自动触发 Jenkins 构建和部署任务&#xff0c;从而实现自动化…

【Spring Boot 源码学习】BootstrapRegistry 初始化器实现

《Spring Boot 源码学习系列》 BootstrapRegistry 初始化器实现 一、引言二、往期内容三、主要内容3.1 BootstrapRegistry3.2 BootstrapRegistryInitializer3.3 BootstrapRegistry 初始化器实现3.3.1 定义 DemoBootstrapper3.3.2 添加 DemoBootstrapper 四、总结 一、引言 前面…

[机缘参悟-160] :人的感知系统是及其有限的,从电磁波的频谱、声波的声谱,看人类只看感知到物质世界的一小部分,无法感知到全部真相

目录 一、人自身是如何感知物质世界的&#xff1f; 1.1 五官 1.2 关于视觉、光、电磁波 1.2.1 视觉系统 1.2.2 感光细胞 ​编辑 1.2.3 光波与人眼的光波范围 1.2.4 电磁波 1.2.5 通过科学仪器和技术可以拓展人对电磁波的感知 1.2.6 太阳光的光谱 1.2.6 光不仅仅用于…