自然语言处理应用(二):自然语言推断

自然语言推断

自然语言推断(Natural Language Inference)是指通过对自然语言文本进行逻辑推理和推断,判断两个句子之间的关系,通常包括三种关系:蕴含(entailment)、矛盾(contradiction)和中性(neutral)。

在自然语言推断任务中,通常给出一个前提(premise)和一个假设(hypothesis),需要根据前提和假设之间的关系来判断前提是否蕴含、矛盾或中性地支持假设。例如:

前提:狗在玩球。
假设:有一只动物正在玩耍。

在这个例子中,前提和假设之间存在蕴含关系,因为前提表明狗正在玩球,而假设中提到有一只动物正在玩耍,这两个句子的意思是相同的。

自然语言推断是自然语言处理和人工智能领域中一个重要的任务,对于理解和处理自然语言具有重要意义。它在很多应用中都有广泛的应用,例如问答系统、机器翻译、信息检索等。

为了解决自然语言推断问题,研究者们通常使用机器学习和深度学习方法,构建模型来自动进行推断。这些模型会通过学习大规模的标注数据集,使其具备推断能力,并能够泛化到未见过的句子对上。

常见的自然语言推断模型包括基于逻辑回归、支持向量机(SVM)、决策树等传统机器学习方法,以及基于神经网络的模型,如循环神经网络(RNN)、长短时记忆网络(LSTM)、Transformer等。

文章内容来自李沐大神的《动手学深度学习》并加以我的理解,感兴趣可以去https://zh-v2.d2l.ai/查看完整书籍


文章目录

  • 自然语言推断
  • 自然语言处理
  • 斯坦福自然语言推断(SNLI)数据集
    • 读取数据集
    • 定义用于加载数据集的类
    • 整合方法
  • 使用注意力机制
    • 模型
      • 注意
      • 比较
      • 聚合
      • 整合代码
    • 训练和评估模型
      • 读取数据集
      • 创建模型
      • 训练和评估模型
      • 使用模型


自然语言处理

自然语言推断(natural language inference)主要研究 假设(hypothesis)是否可以从前提(premise)中推断出来, 其中两者都是文本序列。 换言之,自然语言推断决定了一对文本序列之间的逻辑关系。这类关系通常分为三种类型:

  1. 蕴涵(entailment):假设可以从前提中推断出来。

  2. 矛盾(contradiction):假设的否定可以从前提中推断出来。

  3. 中性(neutral):所有其他情况。

自然语言推断也被称为识别文本蕴涵任务。 例如,下面的一个文本对将被贴上“蕴涵”的标签,因为假设中的“表白”可以从前提中的“拥抱”中推断出来。

前提:两个女人拥抱在一起。
假设:两个女人在示爱。

下面是一个“矛盾”的例子,因为“运行编码示例”表示“不睡觉”,而不是“睡觉”。

前提:一名男子正在运行Dive Into Deep Learning的编码示例。
假设:该男子正在睡觉。

第三个例子显示了一种“中性”关系,因为“正在为我们表演”这一事实无法推断出“出名”或“不出名”。

前提:音乐家们正在为我们表演。
假设:音乐家很有名。

自然语言推断一直是理解自然语言的中心话题。它有着广泛的应用,从信息检索到开放领域的问答。为了研究这个问题,我们将首先研究一个流行的自然语言推断基准数据集。

斯坦福自然语言推断(SNLI)数据集

斯坦福自然语言推断语料库(Stanford Natural Language Inference,SNLI)是由500000多个带标签的英语句子对组成的集合 (Bowman et al., 2015)。我们在路径…/data/snli_1.0中下载并存储提取的SNLI数据集。

import os
import re
import torch
from torch import nn
from d2l import torch as d2l#@save
d2l.DATA_HUB['SNLI'] = ('https://nlp.stanford.edu/projects/snli/snli_1.0.zip','9fcde07509c7e87ec61c640c1b2753d9041758e4')data_dir = d2l.download_extract('SNLI')

读取数据集

原始的SNLI数据集包含的信息比我们在实验中真正需要的信息丰富得多。因此,我们定义函数read_snli以仅提取数据集的一部分,然后返回前提、假设及其标签的列表。

#@save
def read_snli(data_dir, is_train):"""将SNLI数据集解析为前提、假设和标签"""def extract_text(s):# 删除我们不会使用的信息s = re.sub('\\(', '', s)s = re.sub('\\)', '', s)# 用一个空格替换两个或多个连续的空格s = re.sub('\\s{2,}', ' ', s)return s.strip()label_set = {'entailment': 0, 'contradiction': 1, 'neutral': 2}file_name = os.path.join(data_dir, 'snli_1.0_train.txt'if is_train else 'snli_1.0_test.txt')with open(file_name, 'r') as f:rows = [row.split('\t') for row in f.readlines()[1:]]premises = [extract_text(row[1]) for row in rows if row[0] in label_set]hypotheses = [extract_text(row[2]) for row in rows if row[0] \in label_set]labels = [label_set[row[0]] for row in rows if row[0] in label_set]return premises, hypotheses, labels

现在让我们打印前3对前提和假设,以及它们的标签(“0”“1”和“2”分别对应于“蕴涵”“矛盾”和“中性”)
在这里插入图片描述
训练集约有550000对,测试集约有10000对。下面显示了训练集和测试集中的三个标签“蕴涵”“矛盾”和“中性”是平衡的。
在这里插入图片描述

定义用于加载数据集的类

下面我们来定义一个用于加载SNLI数据集的类。类构造函数中的变量num_steps指定文本序列的长度,使得每个小批量序列将具有相同的形状。换句话说,在较长序列中的前num_steps个标记之后的标记被截断,而特殊标记“”将被附加到较短的序列后,直到它们的长度变为num_steps。通过实现__getitem__功能,我们可以任意访问带有索引idx的前提、假设和标签。

#@save
class SNLIDataset(torch.utils.data.Dataset):"""用于加载SNLI数据集的自定义数据集"""def __init__(self, dataset, num_steps, vocab=None):self.num_steps = num_stepsall_premise_tokens = d2l.tokenize(dataset[0])all_hypothesis_tokens = d2l.tokenize(dataset[1])if vocab is None:self.vocab = d2l.Vocab(all_premise_tokens + \all_hypothesis_tokens, min_freq=5, reserved_tokens=['<pad>'])else:self.vocab = vocabself.premises = self._pad(all_premise_tokens)self.hypotheses = self._pad(all_hypothesis_tokens)self.labels = torch.tensor(dataset[2])print('read ' + str(len(self.premises)) + ' examples')def _pad(self, lines):return torch.tensor([d2l.truncate_pad(self.vocab[line], self.num_steps, self.vocab['<pad>'])for line in lines])def __getitem__(self, idx):return (self.premises[idx], self.hypotheses[idx]), self.labels[idx]def __len__(self):return len(self.premises)

这段代码定义了一个名为"SNLIDataset"的自定义数据集类,用于加载SNLI数据集。

构造函数__init__(self, dataset, num_steps, vocab=None)接受三个参数:

  • dataset:SNLI数据集,包含了前提、假设和标签的数据。
  • num_steps:每个样本的固定长度,用于填充或截断序列。
  • vocab:词汇表对象,用于构建词汇表。如果为None,则根据数据集自动构建。

在构造函数中,首先对前提和假设句子进行分词处理,得到所有前提和假设句子的token列表。然后根据是否提供了词汇表对象,初始化了self.vocab属性,该属性是一个词汇表对象。

接下来,调用了self._pad(all_premise_tokens)self._pad(all_hypothesis_tokens)方法,对前提和假设句子进行填充操作,将其转换为固定长度的序列,并用<pad>进行填充。

最后,将标签转换为torch.tensor对象,并存储在self.labels属性中。同时打印读取的样本数量。

_pad(self, lines)是一个辅助方法,用于将序列进行填充操作。它接受一个列表lines,其中每个元素是一个句子的token列表。对于每个句子,首先使用词汇表将其转换为对应的索引序列,然后使用d2l.truncate_pad方法将序列截断或填充为固定长度num_steps。最后将所有处理后的句子序列转换为一个torch.tensor对象。

__getitem__(self, idx)方法用于获取指定索引的样本。它返回一个元组,包含前提句子、假设句子和对应的标签。

__len__(self)方法返回数据集的样本数量,即前提和假设句子的数量。

整合方法

现在,我们可以调用read_snli函数和SNLIDataset类来下载SNLI数据集,并返回训练集和测试集的DataLoader实例,以及训练集的词表。值得注意的是,我们必须使用从训练集构造的词表作为测试集的词表。因此,在训练集中训练的模型将不知道来自测试集的任何新词元。

#@save
def load_data_snli(batch_size, num_steps=50):"""下载SNLI数据集并返回数据迭代器和词表"""num_workers = d2l.get_dataloader_workers()data_dir = d2l.download_extract('SNLI')train_data = read_snli(data_dir, True)test_data = read_snli(data_dir, False)train_set = SNLIDataset(train_data, num_steps)test_set = SNLIDataset(test_data, num_steps, train_set.vocab)train_iter = torch.utils.data.DataLoader(train_set, batch_size,shuffle=True,num_workers=num_workers)test_iter = torch.utils.data.DataLoader(test_set, batch_size,shuffle=False,num_workers=num_workers)return train_iter, test_iter, train_set.vocab

在这里,我们将批量大小设置为128时,将序列长度设置为50,并调用load_data_snli函数来获取数据迭代器和词表。然后我们打印词表大小。

train_iter, test_iter, vocab = load_data_snli(128, 50)
len(vocab)

在这里插入图片描述
现在我们打印第一个小批量的形状。与情感分析相反,我们有分别代表前提和假设的两个输入X[0]和X[1]。

使用注意力机制

鉴于许多模型都是基于复杂而深度的架构,Parikh等人提出用注意力机制解决自然语言推断问题,并称之为“可分解注意力模型” (Parikh et al., 2016)。这使得模型没有循环层或卷积层,在SNLI数据集上以更少的参数实现了当时的最佳结果。本节将描述并实现这种基于注意力的自然语言推断方法(使用MLP)
在这里插入图片描述

模型

与保留前提和假设中词元的顺序相比,我们可以将一个文本序列中的词元与另一个文本序列中的每个词元对齐,然后比较和聚合这些信息,以预测前提和假设之间的逻辑关系。与机器翻译中源句和目标句之间的词元对齐类似,前提和假设之间的词元对齐可以通过注意力机制灵活地完成。
在这里插入图片描述
上图描述了使用注意力机制的自然语言推断方法。从高层次上讲,它由三个联合训练的步骤组成:对齐、比较和汇总。我们将在下面一步一步地对它们进行说明。

注意

第一步是将一个文本序列中的词元与另一个序列中的每个词元对齐。假设前提是“我确实需要睡眠”,假设是“我累了”。由于语义上的相似性,我们不妨将假设中的“我”与前提中的“我”对齐,将假设中的“累”与前提中的“睡眠”对齐。同样,我们可能希望将前提中的“我”与假设中的“我”对齐,将前提中的“需要”和“睡眠”与假设中的“累”对齐。请注意,这种对齐是使用加权平均的“软”对齐,其中理想情况下较大的权重与要对齐的词元相关联。为了便于演示, 上图以“硬”对齐的方式显示了这种对齐方式。

现在,我们更详细地描述使用注意力机制的软对齐。用 A = ( a 1 , . . . , a m ) A=(a_1,...,a_m) A=(a1,...,am) B = ( b 1 , . . . , b n ) B=(b_1,...,b_n) B=(b1,...,bn)表示前提和假设,其词元数量分别为 m m m n n n,其中 a i , b j ∈ R d a_i,b_j \in R^d ai,bjRd i = 1 , . . . , m , j = 1 , . . . , n i=1,...,m,j=1,...,n i=1,...,m,j=1,...,n)是 d d d维的词向量。对于软对齐,我们将注意力权重 e i j ∈ R e_{ij}\in R eijR计算为:
e i j = f ( a i ) ⊺ f ( b j ) e_{ij}=f(a_i)^\intercal f(b_j) eij=f(ai)f(bj)
其中函数 f f f是在下面的mlp函数中定义的多层感知机。输出维度 f f f由mlp的num_hiddens参数指定。

def mlp(num_inputs, num_hiddens, flatten):net = []net.append(nn.Dropout(0.2))net.append(nn.Linear(num_inputs, num_hiddens))net.append(nn.ReLU())if flatten:net.append(nn.Flatten(start_dim=1))net.append(nn.Dropout(0.2))net.append(nn.Linear(num_hiddens, num_hiddens))net.append(nn.ReLU())if flatten:net.append(nn.Flatten(start_dim=1))return nn.Sequential(*net)

对上式中的注意力权重进行规范化,我们计算假设中所有词元向量的加权平均值,以获得假设的表示,该假设与前提中索引 i i i的词元进行软对齐:
β i = ∑ j = 1 n e x p ( e i j ) ∑ k = 1 n e x p ( e i k ) b j \beta_i=\sum_{j=1}^{n}\frac{exp(e_{ij})}{\sum_{k=1}^{n}exp(e_{ik})}b_j βi=j=1nk=1nexp(eik)exp(eij)bj
同样,我们计算假设中索引为 j j j的每个词元与前提词元的软对齐:
α i = ∑ i = 1 m e x p ( e i j ) ∑ k = 1 n e x p ( e k j ) a i \alpha_i=\sum_{i=1}^{m}\frac{exp(e_{ij})}{\sum_{k=1}^{n}exp(e_{kj})}a_i αi=i=1mk=1nexp(ekj)exp(eij)ai
下面,我们定义Attend类来计算假设(beta)与输入前提A的软对齐以及前提(alpha)与输入假设B的软对齐。

class Attend(nn.Module):def __init__(self, num_inputs, num_hiddens, **kwargs):super(Attend, self).__init__(**kwargs)self.f = mlp(num_inputs, num_hiddens, flatten=False)def forward(self, A, B):# A/B的形状:(批量大小,序列A/B的词元数,embed_size)# f_A/f_B的形状:(批量大小,序列A/B的词元数,num_hiddens)f_A = self.f(A)f_B = self.f(B)# e的形状:(批量大小,序列A的词元数,序列B的词元数)e = torch.bmm(f_A, f_B.permute(0, 2, 1))# beta的形状:(批量大小,序列A的词元数,embed_size),# 意味着序列B被软对齐到序列A的每个词元(beta的第1个维度)beta = torch.bmm(F.softmax(e, dim=-1), B)# beta的形状:(批量大小,序列B的词元数,embed_size),# 意味着序列A被软对齐到序列B的每个词元(alpha的第1个维度)alpha = torch.bmm(F.softmax(e.permute(0, 2, 1), dim=-1), A)return beta, alpha

比较

在下一步中,我们将一个序列中的词元与与该词元软对齐的另一个序列进行比较。请注意,在软对齐中,一个序列中的所有词元(尽管可能具有不同的注意力权重)将与另一个序列中的词元进行比较。

在比较步骤中,我们将来自一个序列的词元的连结(运算符 [ . , . ] [.,.] [.,.])和来自另一序列的对齐的词元送入函数 g g g(一个多层感知机):
v A , i = g ( [ α i , β i ] ) , i = 1 , . . . , m v B , j = g ( [ β j , α j ] ) , j = 1 , . . . , n v_{A,i}=g([\alpha_i,\beta_i]),i=1,...,m \\ v_{B,j}=g([\beta_j,\alpha_j]),j=1,...,n vA,i=g([αi,βi]),i=1,...,mvB,j=g([βj,αj]),j=1,...,n
v A , i v_{A,i} vA,i是指,所有假设中的词元与前提中词元 i i i软对齐,再与词元 i i i的比较;而 v B , j v_{B,j} vB,j是指,所有前提中的词元与假设中词元 j j j软对齐,再与词元 j j j的比较。下面的Compare个类定义了比较步骤。

class Compare(nn.Module):def __init__(self, num_inputs, num_hiddens, **kwargs):super(Compare, self).__init__(**kwargs)self.g = mlp(num_inputs, num_hiddens, flatten=False)def forward(self, A, B, beta, alpha):V_A = self.g(torch.cat([A, beta], dim=2))V_B = self.g(torch.cat([B, alpha], dim=2))return V_A, V_B

聚合

现在我们有两组比较向量 v A , i v_{A,i} vA,i i = 1 , . . . , m i=1,...,m i=1,...,m)和 v B , j v_{B,j} vB,j j = 1 , . . . , n j=1,...,n j=1,...,n)。在最后一步中,我们将聚合这些信息以推断逻辑关系。我们首先求和这两组比较向量:
v A = ∑ i = 1 m v A , i , v B = ∑ j = 1 n v B , j v_A=\sum_{i=1}^{m}v_{A,i},v_B=\sum_{j=1}^{n}v_{B,j} vA=i=1mvA,i,vB=j=1nvB,j
接下来,我们将两个求和结果的连结提供给函数 h h h(一个多层感知机),以获得逻辑关系的分类结果:
y = h ( [ v A , v B ] ) y=h([v_A,v_B]) y=h([vA,vB])
聚合步骤在以下Aggregate类中定义。

class Aggregate(nn.Module):def __init__(self, num_inputs, num_hiddens, num_outputs, **kwargs):super(Aggregate, self).__init__(**kwargs)self.h = mlp(num_inputs, num_hiddens, flatten=True)self.linear = nn.Linear(num_hiddens, num_outputs)def forward(self, V_A, V_B):# 对两组比较向量分别求和V_A = V_A.sum(dim=1)V_B = V_B.sum(dim=1)# 将两个求和结果的连结送到多层感知机中Y_hat = self.linear(self.h(torch.cat([V_A, V_B], dim=1)))return Y_hat

整合代码

通过将注意步骤、比较步骤和聚合步骤组合在一起,我们定义了可分解注意力模型来联合训练这三个步骤。

class DecomposableAttention(nn.Module):def __init__(self, vocab, embed_size, num_hiddens, num_inputs_attend=100,num_inputs_compare=200, num_inputs_agg=400, **kwargs):super(DecomposableAttention, self).__init__(**kwargs)self.embedding = nn.Embedding(len(vocab), embed_size)self.attend = Attend(num_inputs_attend, num_hiddens)self.compare = Compare(num_inputs_compare, num_hiddens)# 有3种可能的输出:蕴涵、矛盾和中性self.aggregate = Aggregate(num_inputs_agg, num_hiddens, num_outputs=3)def forward(self, X):premises, hypotheses = XA = self.embedding(premises)B = self.embedding(hypotheses)beta, alpha = self.attend(A, B)V_A, V_B = self.compare(A, B, beta, alpha)Y_hat = self.aggregate(V_A, V_B)return Y_hat

训练和评估模型

现在,我们将在SNLI数据集上对定义好的可分解注意力模型进行训练和评估。我们从读取数据集开始。

读取数据集

批量大小和序列长度分别设置为 256 256 256 50 50 50

batch_size, num_steps = 256, 50
train_iter, test_iter, vocab = d2l.load_data_snli(batch_size, num_steps)

创建模型

我们使用预训练好的100维GloVe嵌入来表示输入词元。我们将向量 a i a_i ai b j b_j bj中的维数预定义为100。函数 f f f和函数 g g g的输出维度被设置为200.然后我们创建一个模型实例,初始化它的参数,并加载GloVe嵌入来初始化输入词元的向量。

embed_size, num_hiddens, devices = 100, 200, d2l.try_all_gpus()
net = DecomposableAttention(vocab, embed_size, num_hiddens)
glove_embedding = d2l.TokenEmbedding('glove.6b.100d')
embeds = glove_embedding[vocab.idx_to_token]
net.embedding.weight.data.copy_(embeds);

训练和评估模型

我们定义了一个split_batch_multi_inputs函数以小批量接受多个输入,如前提和假设。

lr, num_epochs = 0.001, 4
trainer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss(reduction="none")
d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,devices)

在这里插入图片描述

使用模型

最后,定义预测函数,输出一对前提和假设之间的逻辑关系。

#@save
def predict_snli(net, vocab, premise, hypothesis):"""预测前提和假设之间的逻辑关系"""net.eval()premise = torch.tensor(vocab[premise], device=d2l.try_gpu())hypothesis = torch.tensor(vocab[hypothesis], device=d2l.try_gpu())label = torch.argmax(net([premise.reshape((1, -1)),hypothesis.reshape((1, -1))]), dim=1)return 'entailment' if label == 0 else 'contradiction' if label == 1 \else 'neutral'

我们可以使用训练好的模型来获得对示例句子的自然语言推断结果。

predict_snli(net, vocab, ['he', 'is', 'good', '.'], ['he', 'is', 'bad', '.'])

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

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

相关文章

工商银行潍坊分行党建RPA机器人项目解析

01 案例背景&#xff1a;银行业掀起引入RPA加速实现数字化转型的浪潮 近年来&#xff0c;金融科技的蓬勃发展极大促进了银行的业务创新&#xff0c;新技术、新业态层出不穷。随着银行业务和科技的融合逐步落实&#xff0c;银行业务正朝着线上化、智能化转变。科技赋能的转型范…

如何在 Excel 中求平方根

需要在 Excel 中求一个数字的平方根吗&#xff1f;使用几个内置的 Excel 函数和公式可以轻松计算平方根。在本分步指南中&#xff0c;您将学习在 Excel 中计算平方根的 5 种不同方法&#xff0c;包括使用 SQRT 函数、POWER 函数、指数公式、VBA 代码和 Power Query。跟随教程&a…

华为云云耀云服务器L实例评测|基于L实例使用Docker部署MySQL服务并连接MySQL—phpMyAdmin管理工具

文章目录 一、云耀云服务器产品优势1、智能不卡顿2、价优随心用3、上手更简单4、管理更省心 二、远程连接云耀云服务器L实例三、安装Docker、docker-compse1、docker安装2、docker-compose安装 四、方法① 使用Docker安装部署MySQL服务五、方法② 使用docker-compse安装部署MyS…

Maven常见面试题总结

Maven简介 Maven 是一个项目管理和整合工具。Maven 包含了一个项目对象模型 (Project Object Model)&#xff0c;一组标准集合&#xff0c;一个项目生命周期管理系统(Project Lifecycle Management System)&#xff0c;一个依赖管理系统(Dependency Management System)&#x…

C语言天花板——指针(初阶)

&#x1f320;&#x1f320;&#x1f320; 大家在刚刚接触C语言的时候就肯定听说过&#xff0c;指针的重要性以及难度等级&#xff0c;以至于经常“谈虎色变”&#xff0c;但是今天我来带大家走进指针的奇妙世界。&#x1f387;&#x1f387;&#x1f387; 一、什么是指针&…

WebGL 正确处理对象前后的关系——隐藏面消除(深度测试)/ 深度冲突

目录 前言 验证WebGL处理对象前后关系的规则——后绘制的图形覆盖先绘制的图形 隐藏面消除&#xff08;深度测试&#xff09; 开启隐藏面消除功能&#xff0c;需要遵循以下两步&#xff1a; 1.开启隐藏面消除功能。 gl.enable&#xff08;&#xff09;函数规范 2.在绘制…

2023常用的原型设计软件推荐

美观易操作的产品原型可以帮助团队构建积极的用户体验&#xff0c;帮助团队理解产品交互逻辑。 因此&#xff0c;可互动、易修改的产品原型设计对产品的点击率和回访率具有重要意义。 选择专业的产品原型设计工具&#xff0c;可以为团队和企业带来高效的产品设计体验。本文选…

ddtrace 系列篇之 dd-trace-java 项目编译

dd-trace-java 是 Datadog 开源的 java APM 框架&#xff0c;本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要&#xff1a;jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常&#xf…

Linux JAVA环境的搭建tomcat的部署(含多实例)

tomcat tomcat是Apache软件基金会项目中的一个核心项目由 Apache、Sun 和其他一些公司及个人共同开发而成。tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器. tomcat的组成 tomcat用于支持Java Servlet和JSP。它是一个重要的We…

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单AdaptiveTextSelectionToolba样式UI效果

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单样式UI效果 在开发过程中&#xff0c;需要长按TextField输入框cut、copy设置为中文“复制、粘贴”&#xff0c;我首先查看了TextField中的源码&#xff0c;看到了ToolbarOptions、AdaptiveTextSelectionToo…

AI与医疗保健:革命性技术如何拯救生命

文章目录 引言AI的应用领域1. 影像识别2. 疾病诊断3. 药物研发4. 个性化治疗 AI技术1. 机器学习2. 深度学习3. 自然语言处理4. 基因组学 实际案例1. Google Health的深度学习模型2. IBM Watson for Oncology3. PathAI的病理学分析 道德和隐私考虑结论 &#x1f389;欢迎来到AIG…

实验4 交换机端口隔离(access模式)

交换机端口隔离&#xff08;access模式&#xff09; 实验目的实验拓扑实验步骤&#xff08;1&#xff09;在未划分vlan前&#xff0c;配置pc1、pc2的地址&#xff0c;如图所示&#xff08;2&#xff09;测试两台pc机的连通性&#xff08;3&#xff09;创建vlan&#xff0c;并验…

按键点亮led灯

原理图: K0这个按键按下时&#xff0c;开发板D1这个灯亮&#xff0c;松开&#xff0c;灯灭 代码如下: #include "stm32f4xx.h" void LED_Init(void) {//1.定义一个GPIO外设的结构体变量 GPIO_InitTypeDef GPIO_InitStructure;//RCC_AHB1PeriphClockCmd(RCC_AHB1Pe…

Linux底层基础知识

一.汇编&#xff0c;C语言&#xff0c;C&#xff0c;JAVA之间的关系 汇编&#xff0c;C语言&#xff0c;C可以通过不同的编译器&#xff0c;编译成机器码。而java只能由Java虚拟机识别。Java虚拟机可以看成一个操作系统&#xff0c;Java虚拟机是由汇编&#xff0c;C&#xff0c…

分享一下微信商城如何添加新客有礼活动

一、新客有礼活动的优势 新客有礼活动是一种非常有效的营销策略&#xff0c;通过向新用户提供优惠和礼品&#xff0c;可以吸引更多的用户关注和购买。以下是一些新客有礼活动的优势&#xff1a; 吸引新用户&#xff1a;新客有礼活动可以吸引更多的新用户关注和购买&#xff0c…

12306 抢票小助手: 完整易用的抢票解决方案 | 开源日报 0917

testerSunshine/12306 Stars: 31.4k License: MIT 12306 购票小助手是一个使用 Python 编写的项目&#xff0c;主要功能包括自动打码、自动登录、准点预售和捡漏、智能候补以及邮件通知等。该项目具有以下核心优势&#xff1a; 支持多个版本的 Python提供验证码本地识别功能可…

docker四种网络模式

文章目录 一.为什么要了解docker网络二.docker 网络理论三.docker的四类网络模式3.1 bridge模式3.2 host模式3.3 container模式3.4 none模式 四.bridge模式下容器的通信4.1 防火墙开启状态4.2 防火墙关闭状态 一.为什么要了解docker网络 当你开始大规模使用Docker时&#xff0…

Springboot部署服务器项目上线

第一步&#xff0c;项目打包&#xff0c;有两种方式 第一种、直接在项目根目录打开终端&#xff0c;输入以下语句即可。如下图&#xff1a; mvn clean package -DskipTests 第二种、在右侧点击 Maven选项&#xff0c;选择鼠标左键双击package选项即可。如下图&#xff1a; 两…

CocosCreator3.8研究笔记(十七)CocosCreator UI组件(一)

CocosCreator 中&#xff0c;用户界面 User-interface&#xff08;UI&#xff09;组件和2d渲染对象的区别在于2D 渲染对象一般只负责将2D 对象渲染出来&#xff0c;而 UI 则更多的承担着用户交互的能力。 常用的 UI 控件可通过添加节点的方式来创建。 在 层级管理器 中点击左上…

算法宝典1——Java版本(此系列持续更新,这篇文章有20道)(有题目的跳转链接)(此份宝典包含了链表、栈、队列、二叉树的算法题)

注&#xff1a;由于字数的限制&#xff0c;我打算把算法宝典做成一个系列&#xff0c;一篇文章就20题&#xff01;&#xff01;&#xff01; 目录 一、链表的算法题&#xff08;目前10道&#xff09; 1. 移除链表元素&#xff08;力扣&#xff1b;思路&#xff1a;前后指针&…