华为开源自研AI框架昇思MindSpore应用实践:RNN实现情感分类

news2024/11/25 20:46:41

目录

  • 一、环境准备
    • 1.进入ModelArts官网
    • 2.使用CodeLab体验Notebook实例
  • 二、数据准备
    • 1.数据下载模块
    • 2.加载IMDB数据集
    • 2.加载预训练词向量
  • 三、数据集预处理
  • 四、模型构建
    • 1.Embedding
    • 2.RNN(循环神经网络)
    • 3.Dense
    • 4.损失函数与优化器
    • 5.训练逻辑
    • 6.评估指标和逻辑
  • 五、模型训练与保存
  • 六、模型加载与测试
  • 七、自定义输入测试

本教程是通过示例代码说明情感分类是自然语言处理中的经典任务,是典型的分类问题。使用MindSpore实现一个基于RNN网络的情感分类模型,实现如下的效果:

输入: This film is terrible
正确标签: Negative
预测标签: Negative

输入: This film is great
正确标签: Positive
预测标签: Positive

如果你对MindSpore感兴趣,可以关注昇思MindSpore社区

在这里插入图片描述

一、环境准备

1.进入ModelArts官网

云平台帮助用户快速创建和部署模型,管理全周期AI工作流,选择下面的云平台以开始使用昇思MindSpore,可以在昇思教程中进入ModelArts官网

在这里插入图片描述

选择下方CodeLab立即体验

在这里插入图片描述
等待环境搭建完成
在这里插入图片描述

2.使用CodeLab体验Notebook实例

下载NoteBook样例代码.ipynb为样例代码

在这里插入图片描述

选择ModelArts Upload Files上传.ipynb文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

选择Kernel环境

在这里插入图片描述

进入昇思MindSpore官网,点击上方的安装

在这里插入图片描述

获取安装命令

在这里插入图片描述

回到Notebook中,在第一块代码前加入三块命令
在这里插入图片描述

pip install --upgrade pip
conda install mindspore-gpu=1.9.0 cudatoolkit=10.1 -c mindspore -c conda-forge
pip install mindvision

依次运行即可

在这里插入图片描述

在这里插入图片描述

二、数据准备

本节使用情感分类的经典数据集IMDB影评数据集,数据集包含Positive和Negative两类,下面为其样例:

ReviewLabel
“Quitting” may be as much about exiting a pre-ordained identity as about drug withdrawal. As a rural guy coming to Beijing, class and success must have struck this young artist face on as an appeal to separate from his roots and far surpass his peasant parents’ acting success. Troubles arise, however, when the new man is too new, when it demands too big a departure from family, history, nature, and personal identity. The ensuing splits, and confusion between the imaginary and the real and the dissonance between the ordinary and the heroic are the stuff of a gut check on the one hand or a complete escape from self on the other.Negative
This movie is amazing because the fact that the real people portray themselves and their real life experience and do such a good job it’s like they’re almost living the past over again. Jia Hongsheng plays himself an actor who quit everything except music and drugs struggling with depression and searching for the meaning of life while being angry at everyone especially the people who care for him most…Positive

此外,需要使用预训练词向量对自然语言单词进行编码,以获取文本的语义特征,本节选取Glove词向量作为Embedding。

1.数据下载模块

为了方便数据集和预训练词向量的下载,首先设计数据下载模块,实现可视化下载流程,并保存至指定路径。数据下载模块使用requests库进行http请求,并通过tqdm库对下载百分比进行可视化。此外针对下载安全性,使用IO的方式下载临时文件,而后保存至指定的路径并返回。

tqdmrequests库需手动安装,命令如下:pip install tqdm requests

在这里插入图片描述


import os
import shutil
import requests
import tempfile
from tqdm import tqdm
from typing import IO
from pathlib import Path

# 指定保存路径为 `home_path/.mindspore_examples`
cache_dir = Path.home() / '.mindspore_examples'

def http_get(url: str, temp_file: IO):
    """使用requests库下载数据,并使用tqdm库进行流程可视化"""
    req = requests.get(url, stream=True)
    content_length = req.headers.get('Content-Length')
    total = int(content_length) if content_length is not None else None
    progress = tqdm(unit='B', total=total)
    for chunk in req.iter_content(chunk_size=1024):
        if chunk:
            progress.update(len(chunk))
            temp_file.write(chunk)
    progress.close()

def download(file_name: str, url: str):
    """下载数据并存为指定名称"""
    if not os.path.exists(cache_dir):
        os.makedirs(cache_dir)
    cache_path = os.path.join(cache_dir, file_name)
    cache_exist = os.path.exists(cache_path)
    if not cache_exist:
        with tempfile.NamedTemporaryFile() as temp_file:
            http_get(url, temp_file)
            temp_file.flush()
            temp_file.seek(0)
            with open(cache_path, 'wb') as cache_file:
                shutil.copyfileobj(temp_file, cache_file)
    return cache_path

在这里插入图片描述

完成数据下载模块后,下载IMDB数据集进行测试(此处使用华为云的镜像用于提升下载速度)。下载过程及保存的路径如下:

在这里插入图片描述

2.加载IMDB数据集

下载好的IMDB数据集为tar.gz文件,我们使用Python的tarfile库对其进行读取,并将所有数据和标签分别进行存放。原始的IMDB数据集解压目录如下:

├── aclImdb
│   ├── imdbEr.txt
│   ├── imdb.vocab
│   ├── README
│   ├── test
│   └── train
│         ├── neg
│         ├── pos
...

数据集已分割为train和test两部分,且每部分包含neg和pos两个分类的文件夹,因此需分别train和test进行读取并处理数据和标签。


import re
import six
import string
import tarfile

class IMDBData():
    """IMDB数据集加载器

    加载IMDB数据集并处理为一个Python迭代对象。

    """
    label_map = {
        "pos": 1,
        "neg": 0
    }
    def __init__(self, path, mode="train"):
        self.mode = mode
        self.path = path
        self.docs, self.labels = [], []

        self._load("pos")
        self._load("neg")

    def _load(self, label):
        pattern = re.compile(r"aclImdb/{}/{}/.*\.txt$".format(self.mode, label))
        # 将数据加载至内存
        with tarfile.open(self.path) as tarf:
            tf = tarf.next()
            while tf is not None:
                if bool(pattern.match(tf.name)):
                    # 对文本进行分词、去除标点和特殊字符、小写处理
                    self.docs.append(str(tarf.extractfile(tf).read().rstrip(six.b("\n\r"))
                                         .translate(None, six.b(string.punctuation)).lower()).split())
                    self.labels.append([self.label_map[label]])
                tf = tarf.next()

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

    def __len__(self):
        return len(self.docs)

在这里插入图片描述
完成IMDB数据加载器后,加载训练数据集进行测试,输出数据集数量:

在这里插入图片描述

将IMDB数据集加载至内存并构造为迭代对象后,可以使用mindspore.dataset提供的Generatordataset接口加载数据集迭代对象,并进行下一步的数据处理,下面封装一个函数将train和test分别使用Generatordataset进行加载,并指定数据集中文本和标签的column_name分别为textlabel:


import mindspore.dataset as ds

def load_imdb(imdb_path):
    imdb_train = ds.GeneratorDataset(IMDBData(imdb_path, "train"), column_names=["text", "label"], shuffle=True)
    imdb_test = ds.GeneratorDataset(IMDBData(imdb_path, "test"), column_names=["text", "label"], shuffle=False)
    return imdb_train, imdb_test

在这里插入图片描述

加载IMDB数据集,可以看到imdb_train是一个GeneratorDataset对象。


imdb_train, imdb_test = load_imdb(imdb_path)
imdb_train

在这里插入图片描述

2.加载预训练词向量

预训练词向量是对输入单词的数值化表示,通过nn.Embedding层,采用查表的方式,输入单词对应词表中的index,获得对应的表达向量。 因此进行模型构造前,需要将Embedding层所需的词向量和词表进行构造。这里我们使用Glove(Global Vectors for Word Representation)这种经典的预训练词向量, 其数据格式如下:

WordVector
the0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862 -0.00066023 …
,0.013441 0.23682 -0.16899 0.40951 0.63812 0.47709 -0.42852 -0.55641 -0.364 …

我们直接使用第一列的单词作为词表,使用dataset.text.Vocab将其按顺序加载;同时读取每一行的Vector并转为numpy.array,用于nn.Embedding加载权重使用。具体实现如下:


import zipfile
import numpy as np

def load_glove(glove_path):
    glove_100d_path = os.path.join(cache_dir, 'glove.6B.100d.txt')
    if not os.path.exists(glove_100d_path):
        glove_zip = zipfile.ZipFile(glove_path)
        glove_zip.extractall(cache_dir)

    embeddings = []
    tokens = []
    with open(glove_100d_path, encoding='utf-8') as gf:
        for glove in gf:
            word, embedding = glove.split(maxsplit=1)
            tokens.append(word)
            embeddings.append(np.fromstring(embedding, dtype=np.float32, sep=' '))
    # 添加 <unk>, <pad> 两个特殊占位符对应的embedding
    embeddings.append(np.random.rand(100))
    embeddings.append(np.zeros((100,), np.float32))

    vocab = ds.text.Vocab.from_list(tokens, special_tokens=["<unk>", "<pad>"], special_first=False)
    embeddings = np.array(embeddings).astype(np.float32)
    return vocab, embeddings

在这里插入图片描述

由于数据集中可能存在词表没有覆盖的单词,因此需要加入<unk>标记符;同时由于输入长度的不一致,在打包为一个batch时需要将短的文本进行填充,因此需要加入<pad>标记符。完成后的词表长度为原词表长度+2。

下面下载Glove词向量,并加载生成词表和词向量权重矩阵。


glove_path = download('glove.6B.zip', 'https://mindspore-website.obs.myhuaweicloud.com/notebook/datasets/glove.6B.zip')
vocab, embeddings = load_glove(glove_path)
len(vocab.vocab())

在这里插入图片描述

使用词表将the转换为index id,并查询词向量矩阵对应的词向量:


idx = vocab.tokens_to_ids('the')
embedding = embeddings[idx]
idx, embedding

在这里插入图片描述

三、数据集预处理

通过加载器加载的IMDB数据集进行了分词处理,但不满足构造训练数据的需要,因此要对其进行额外的预处理。其中包含的预处理如下:

  • 通过Vocab将所有的Token处理为index id。
  • 将文本序列统一长度,不足的使用<pad>补齐,超出的进行截断。

这里我们使用mindspore.dataset中提供的接口进行预处理操作。这里使用到的接口均为MindSpore的高性能数据引擎设计,每个接口对应操作视作数据流水线的一部分,详情请参考MindSpore数据引擎。 首先针对token到index id的查表操作,使用text.Lookup接口,将前文构造的词表加载,并指定unknown_token。其次为文本序列统一长度操作,使用PadEnd接口,此接口定义最大长度和补齐值(pad_value),这里我们取最大长度为500,填充值对应词表中<pad>的index id。

除了对数据集中text进行预处理外,由于后续模型训练的需要,要将label数据转为float32格式。


import mindspore as ms

lookup_op = ds.text.Lookup(vocab, unknown_token='<unk>')
pad_op = ds.transforms.PadEnd([500], pad_value=vocab.tokens_to_ids('<pad>'))
type_cast_op = ds.transforms.TypeCast(ms.float32)

在这里插入图片描述

完成预处理操作后,需将其加入到数据集处理流水线中,使用map接口对指定的column添加操作。



import mindspore as ms

lookup_op = ds.text.Lookup(vocab, unknown_token='<unk>')
pad_op = ds.transforms.PadEnd([500], pad_value=vocab.tokens_to_ids('<pad>'))
type_cast_op = ds.transforms.TypeCast(ms.float32)


在这里插入图片描述

由于IMDB数据集本身不包含验证集,我们手动将其分割为训练和验证两部分,比例取0.7, 0.3。


imdb_train, imdb_valid = imdb_train.split([0.7, 0.3])

在这里插入图片描述

最后指定数据集的batch大小,通过batch接口指定,并设置是否丢弃无法被batch size整除的剩余数据。

调用数据集的mapsplitbatch为数据集处理流水线增加对应操作,返回值为新的Dataset类型。现在仅定义流水线操作,在执行时开始执行数据处理流水线,获取最终处理好的数据并送入模型进行训练。


imdb_train = imdb_train.batch(64, drop_remainder=True)
imdb_valid = imdb_valid.batch(64, drop_remainder=True)

在这里插入图片描述

四、模型构建

完成数据集的处理后,我们设计用于情感分类的模型结构。首先需要将输入文本(即序列化后的index id列表)通过查表转为向量化表示,此时需要使用nn.Embedding层加载Glove词向量;然后使用RNN循环神经网络做特征提取;最后将RNN连接至一个全连接层,即nn.Dense,将特征转化为与分类数量相同的size,用于后续进行模型优化训练。整体模型结构如下:


nn.Embedding -> nn.RNN -> nn.Dense

这里我们使用能够一定程度规避RNN梯度消失问题的变种LSTM(Long short term memory)做特征提取层。下面对模型进行详解:

1.Embedding

Embedding层又可称为EmbeddingLookup层,其作用是使用index id对权重矩阵对应id的向量进行查找,当输入为一个由index id组成的序列时,则查找并返回一个相同长度的矩阵,例如:


embedding = nn.Embedding(1000, 100) # 词表大小(index的取值范围)为1000,表示向量的size为100
input shape: (1, 16)                # 序列长度为16
output shape:(1, 16, 100)

这里我们使用前文处理好的Glove词向量矩阵,设置nn.Embeddingembedding_table为预训练词向量矩阵。对应的vocab_size为词表大小400002,embedding_size为选用的glove.6B.100d向量大小,即100。

2.RNN(循环神经网络)

这里是引用
在这里插入图片描述

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

3.Dense

在经过LSTM编码获取句子特征后,将其送入一个全连接层,即nn.Dense,将特征维度变换为二分类所需的维度1,经过Dense层后的输出即为模型预测结果。

在Dense层后进行了sigmoid运算,将预测值归一至[0,1]区间,用于后续和BCELoss(BinaryCrossEntropyLoss)计算二分类交叉熵损失使用。


import math
import mindspore as ms
import mindspore.nn as nn
import mindspore.numpy as mnp
import mindspore.ops as ops
from mindspore.common.initializer import Uniform, HeUniform

class RNN(nn.Cell):
    def __init__(self, embeddings, hidden_dim, output_dim, n_layers,
                 bidirectional, dropout, pad_idx):
        super().__init__()
        vocab_size, embedding_dim = embeddings.shape
        self.embedding = nn.Embedding(vocab_size, embedding_dim, embedding_table=ms.Tensor(embeddings), padding_idx=pad_idx)
        self.rnn = nn.LSTM(embedding_dim,
                           hidden_dim,
                           num_layers=n_layers,
                           bidirectional=bidirectional,
                           dropout=dropout,
                           batch_first=True)
        weight_init = HeUniform(math.sqrt(5))
        bias_init = Uniform(1 / math.sqrt(hidden_dim * 2))
        self.fc = nn.Dense(hidden_dim * 2, output_dim, weight_init=weight_init, bias_init=bias_init)
        self.dropout = nn.Dropout(1 - dropout)
        self.sigmoid = ops.Sigmoid()

    def construct(self, inputs):
        embedded = self.dropout(self.embedding(inputs))
        _, (hidden, _) = self.rnn(embedded)
        hidden = self.dropout(mnp.concatenate((hidden[-2, :, :], hidden[-1, :, :]), axis=1))
        output = self.fc(hidden)
        return self.sigmoid(output)

在这里插入图片描述

4.损失函数与优化器

完成模型主体构建后,首先根据指定的参数实例化网络;然后选择损失函数和优化器,并将其使用nn.TrainOneStepCell进行封装。针对本节情感分类问题的特性,即预测Positive或Negative的二分类问题,我们选择nn.BCELoss(二分类交叉熵损失函数),这里也可以选择nn.BCEWithLogitsLoss, 其包含sigmoid运算,即:

BCEWithLogitsLoss = Sigmoid + BCELoss

这里使用BECLoss需要设置reduction参数为均值。而后使用nn.WithLossCell将其与实例化网络对象进行关联。

选择合适的损失函数后,选择Adam优化器,并将二者传入TrainOneStepCell中。

MindSpore的设计理念为整图计算与优化,因此将Loss
function和Optimizer均视为计算图的一部分,所以构造TrainOneStepCell作为Wrapper使用。


hidden_size = 256
output_size = 1
num_layers = 2
bidirectional = True
dropout = 0.5
lr = 0.001
pad_idx = vocab.tokens_to_ids('<pad>')

net = RNN(embeddings, hidden_size, output_size, num_layers, bidirectional, dropout, pad_idx)
loss = nn.BCELoss(reduction='mean')
net_with_loss = nn.WithLossCell(net, loss)
optimizer = nn.Adam(net.trainable_params(), learning_rate=lr)
train_one_step = nn.TrainOneStepCell(net_with_loss, optimizer)

在这里插入图片描述

5.训练逻辑

在完成模型构建,进行训练逻辑的设计。一般训练逻辑分为一下步骤:

  1. 读取一个Batch的数据;
  2. 送入网络,进行正向计算和反向传播,更新权重;
  3. 返回loss。

下面按照此逻辑,使用tqdm库,设计训练一个epoch的函数,用于训练过程和loss的可视化。


def train_one_epoch(model, train_dataset, epoch=0):
    model.set_train()
    total = train_dataset.get_dataset_size()
    loss_total = 0
    step_total = 0
    with tqdm(total=total) as t:
        t.set_description('Epoch %i' % epoch)
        for i in train_dataset.create_tuple_iterator():
            loss = model(*i)
            loss_total += loss.asnumpy()
            step_total += 1
            t.set_postfix(loss=loss_total/step_total)
            t.update(1)

在这里插入图片描述

6.评估指标和逻辑

训练逻辑完成后,需要对模型进行评估。即使用模型的预测结果和测试集的正确标签进行对比,求出预测的准确率。由于IMDB的情感分类为二分类问题,对预测值直接进行四舍五入即可获得分类标签(0或1),然后判断是否与正确标签相等即可。下面为二分类准确率计算函数实现:


def binary_accuracy(preds, y):
    """
    计算每个batch的准确率
    """

    # 对预测值进行四舍五入
    rounded_preds = np.around(preds)
    correct = (rounded_preds == y).astype(np.float32)
    acc = correct.sum() / len(correct)
    return acc

在这里插入图片描述

有了准确率计算函数后,类似于训练逻辑,对评估逻辑进行设计, 分别为以下步骤:

  1. 读取一个Batch的数据;
  2. 送入网络,进行正向计算,获得预测结果;
  3. 计算准确率。

同训练逻辑一样,使用tqdm进行loss和过程的可视化。此外返回评估loss至供保存模型时作为模型优劣的判断依据。

在进行evaluate时,使用的模型是不包含损失函数和优化器的网络主体;
在进行evaluate前,需要通过model.set_train(False)将模型置为评估状态,此时Dropout不生效。


def evaluate(model, test_dataset, criterion, epoch=0):
    total = test_dataset.get_dataset_size()
    epoch_loss = 0
    epoch_acc = 0
    step_total = 0
    model.set_train(False)

    with tqdm(total=total) as t:
        t.set_description('Epoch %i' % epoch)
        for i in test_dataset.create_tuple_iterator():
            predictions = model(i[0])
            loss = criterion(predictions, i[1])
            epoch_loss += loss.asnumpy()

            acc = binary_accuracy(predictions.asnumpy(), i[1].asnumpy())
            epoch_acc += acc

            step_total += 1
            t.set_postfix(loss=epoch_loss/step_total, acc=epoch_acc/step_total)
            t.update(1)

    return epoch_loss / total

在这里插入图片描述

五、模型训练与保存

前序完成了模型构建和训练、评估逻辑的设计,下面进行模型训练。这里我们设置训练轮数为5轮。同时维护一个用于保存最优模型的变量best_valid_loss,根据每一轮评估的loss值,取loss值最小的轮次,将模型进行保存。

MindSpore默认采用静态图模式(即Define and Run)进行训练,第一个step会进行计算图编译操作,较为耗时,但整体训练效率更高,若需要进行单步调试或使用动态图模式,可使用如下代码进行设置:


import mindspore as ms
ms.set_context(mode=ms.PYNATIVE_MODE)

在这里插入图片描述


num_epochs = 5
best_valid_loss = float('inf')
ckpt_file_name = os.path.join(cache_dir, 'sentiment-analysis.ckpt')

for epoch in range(num_epochs):
    train_one_epoch(train_one_step, imdb_train, epoch)
    valid_loss = evaluate(net, imdb_valid, loss, epoch)

    if valid_loss < best_valid_loss:
        best_valid_loss = valid_loss
        ms.save_checkpoint(net, ckpt_file_name)

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

六、模型加载与测试

模型训练完成后,一般需要对模型进行测试或部署上线,此时需要加载已保存的最优模型(即checkpoint),供后续测试使用。这里我们直接使用MindSpore提供的Checkpoint加载和网络权重加载接口:1.将保存的模型Checkpoint加载到内存中,2.将Checkpoint加载至模型。

load_param_into_net接口会返回模型中没有和Checkpoint匹配的权重名,正确匹配时返回空列表。


param_dict = ms.load_checkpoint(ckpt_file_name)
ms.load_param_into_net(net, param_dict)

在这里插入图片描述

对测试集打batch,然后使用evaluate方法进行评估,得到模型在测试集上的效果。


imdb_test = imdb_test.batch(64)
evaluate(net, imdb_test, loss)

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

七、自定义输入测试

最后我们设计一个预测函数,实现开头描述的效果,输入一句评价,获得评价的情感分类。具体包含以下步骤:

  1. 将输入句子进行分词;
  2. 使用词表获取对应的index id序列;
  3. index id序列转为Tensor;
  4. 送入模型获得预测结果;
  5. 打印输出预测结果。

具体实现如下:


score_map = {
    1: "Positive",
    0: "Negative"
}

def predict_sentiment(model, vocab, sentence):
    model.set_train(False)
    tokenized = sentence.lower().split()
    indexed = vocab.tokens_to_ids(tokenized)
    tensor = ms.Tensor(indexed, ms.int32)
    tensor = tensor.expand_dims(0)
    prediction = model(tensor)
    return score_map[int(np.round(prediction.asnumpy()))]

在这里插入图片描述


predict_sentiment(net, vocab, "This film is great")

在这里插入图片描述

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

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

相关文章

电脑重装系统后卡顿怎么办?教你快速解决电脑卡顿问题

​Win10电脑卡顿怎么办&#xff1f;许多用户在使用电脑的过程中发现&#xff0c;随着使用时间的增加&#xff0c;电脑会越来越卡顿。有些小伙伴就会选择重装电脑系统&#xff0c;那么我们在重装电脑之后要进行什么操作才能让电脑不卡顿呢&#xff1f; 操作方法&#xff1a; 优化…

java学生成绩管理系统源码swing(GUI) MySQL带开发教程永久学习

今天给大家演示一款由Java swing即GUI和mysql数据库实现的&#xff0c;学生成绩管理系统&#xff0c;系统采用了MVC的设计模式&#xff0c;结构层次非常清晰&#xff0c;此外&#xff0c;该项目有手把手的开发教程&#xff0c;适合刚入门Java的学生学习&#xff0c;下面我们来看…

Pr:导出设置

◆ ◆ ◆导出设置&#xff08;媒体文件&#xff09;Export Settings&#xff08;Media File&#xff09;基本设置文件名File Name指定导出的文件名。位置Location可以点击蓝色字更改导出的文件的存放位置。预设Preset选择导出预设。匹配源 Match Source预设会将大多数设置与源…

[附源码]Python计算机毕业设计高校贫困生信息管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

Mysql 查询获取 为数字的 字符串

先看示例数据: test_value 字段 为 VARVCHAR 类型 数据样例&#xff1a; 包含 纯数字&#xff0c; 带小数点的数字&#xff0c; 字符串 获取里面的纯数字 &#xff1a;使用正则匹配 函数 REGEXP &#xff0c;返回 1代表不匹配&#xff0c; 返回 0 代表匹配 包含小数点 [^0-…

两步开启研发团队专属ChatOps|极狐GitLab ChatOps 的设计与实践

本文来自&#xff1a; 彭亮 极狐(GitLab) 高级产品经理 郭旭东 极狐(GitLab) 资深创新架构师 舒文斌 极狐(GitLab) 高级网站可靠性工程师 最近几天&#xff0c;ChatGPT 真是杀疯了 &#xff01; 相信大家的朋友圈&#xff0c;已经被调戏、询问或探讨 ChatGPT 的贴子刷屏。 看到…

虹科案例 | 风电机组的预测性维护应该如何进行?

虹科预测性维护方案 在风能领域的应用 虹科案例 01 应用背景 风能是最重要的清洁能源之一&#xff0c;大力发展风电等清洁能源是实现国家可持续发展战略的必然选择。发展风电、光伏等新能源的高效运维技术已成为当前电力系统面临的重要问题之一。在风电机组单机容量较大、机组…

在Azure上设置存储账户

目录 &#xff08;一&#xff09;前言 &#xff08;二&#xff09;正文 1. 搜索存储账户类型资源 2. 开始创建新存储账户 &#xff08;1&#xff09;基本信息 &#xff08;2&#xff09;高级选项 &#xff08;3&#xff09;网络配置 &#xff08;4&#xff09;数据保护…

怎么看电脑是32位还是64位?2个方法,快速查看

熟悉计算机操作系统的朋友应该知道&#xff0c;电脑系统分为32位和64位。不同系统位数的兼容软件也会有所不同。怎么看电脑是32位还是64位&#xff1f;这里小编分享2个方法&#xff0c;快速查看自己的电脑系统位数。 方法一&#xff1a;电脑属性查看法 很多小伙伴不知道怎么看…

特殊符号——双引号和单引号

特殊符号——双引号和单引号一.通常理解二.一般使用三.特殊使用四.为何计算机需要字符一.通常理解 在c语言中&#xff0c;我们通常认为双引号保存的是字符串&#xff0c;单引号里保存的是字符。这里也没什么好说的&#xff0c;说一说它们的细微的一些地方 二.一般使用 接下来我…

图为科技与深圳人工智能产业协会联合发布边缘计算机概念

2022年12月13日由图为信息科技&#xff08;深圳&#xff09;有限公司联合深圳市人工智能产业协会举办的“边缘计算机发布会”在深圳市龙岗区大运AI小镇举行。 随着5&#xff27;、物联网、人工智能等技术的规模应用和持续进步&#xff0c;边缘计算市场进入蓬勃发展期。我国在《…

罗克韦尔(AB)PLC远程维护连接不上网关怎么办?

对很多使用罗克韦尔&#xff08;AB&#xff09;PLC的工厂来说&#xff0c;PLC具备成熟系统和稳定性能等特点&#xff0c;可以适应厂内设备的控制指令&#xff0c;需要细心保养&#xff0c;认真维护。随着无线通信技术和物联网技术的发展&#xff0c;PLC的数据上云进行云端监控和…

过两年 JVM 可能就要被它替代了

今天说一说 GraalVM。 GraalVM 是 Oracle 大力发展和想要推广的新一代 JVM &#xff0c;目前很多框架都已经渐渐支持 GraalVM 了&#xff0c;比如我们在用的 Spring 也已经推出了对 GraalVM 兼容的工具包了。 既然说的这么厉害&#xff0c;那么它到底是何方神圣呢。 GraalVM…

java零基础入门-Scanner类

目录 1.概念 2.常用api 3.next()方法 4.nextLine()方法 5.next()与nextLine()区别 6.实例 1.概念 针对java5版本诞生&#xff0c;在jdk之前版本这次的版本是添加了java.util.Scanner类&#xff1b;其类是一个用于扫描输入文本的工具集。它不仅提供了可结合正则表达式和从输…

基于云原生的集群自愈系统 Flink Cluster Inspector

作者: 舟柒、楼台 1. 业务背景与挑战 1.1 实时计算集群现状 关于热点机器处理一直是阿里云 Flink 集群运维的一大痛点&#xff0c;不管在日常还是大促都已经是比较严重的问题&#xff0c;同时这也是分布式系统的老大难问题。而在今年整个阿里云成本控制的背景下&#xff0c;…

Flink 1.16:Hive SQL 如何平迁到 Flink SQL

摘要&#xff1a;本文整理自 Apache Flink PMC&Committer 伍翀&#xff08;云邪&#xff09;在 9 月 24 日 Apache Flink Meetup 的演讲。主要内容包括&#xff1a;Hive SQL 迁移的动机Hive SQL 迁移的挑战Hive SQL 迁移的实践Hive SQL 迁移的演示未来规划Tips&#xff1a;…

班级网页制作 HTML个人网页设计 我的班级网站设计与实现 大学生简单班级静态HTML网页设计作品 DIV布局班级网页模板代码 DW学生校园网站制作成品下载

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

【数据库数据恢复】SQL server数据库被加密怎么恢复数据?

SQL server数据库故障&#xff1a; SQL server数据库和备份文件被加密&#xff0c;无法使用。数据库MDF、LDF、log日志文件名字被修改。 SQL server数据库数据恢复过程&#xff1a; 1、首先对故障数据库所涉及到的硬盘进行镜像备份&#xff0c;避免对原始数据造成二次破坏&…

python大作业高分项目--射击闯关游戏

项目功能&#xff1a; 地图编辑器&#xff1a;可以实现玩家自己定义每一关卡的样式和难易程度 运行界面&#xff1a;实现了玩家的移动&#xff0c;跳跃&#xff0c;发射子弹&#xff0c;投掷手雷&#xff0c;以及敌人的AL&#xff08;移动&#xff0c;发射子弹&#xff0c;扔…

Word处理控件Aspose.Words功能演示:在 Python 中将 HTML 转换为 PNG、JPEG、BMP、GIF 或 TIFF 图像

Aspose API支持流行文件格式处理&#xff0c;并允许将各类文档导出或转换为固定布局文件格式和最常用的图像/多媒体格式。 HTML &#xff08;超文本标记语言&#xff09;是所有浏览器都支持的主要网页文件格式。它经常用于将数据和信息显示为网页。在某些情况下&#xff0c;我们…