LLM学习笔记(16)序列标注任务(准备数据阶段)

序列标注任务

目标:为文本中的每一个 token 分配一个标签,因此 Transformers 库也将其称为 token 分类任务。常见的序列标注任务有命名实体识别 NER (Named Entity Recognition) 和词性标注 POS (Part-Of-Speech tagging)。

1. 命名实体识别(NER - Named Entity Recognition)

  • 定义:命名实体识别是识别文本中具有特定意义的命名实体,例如人名、地名、组织名、日期、货币等。它的目标是为文本中的词汇标记实体类别,例如将“北京”标记为地名,将“特斯拉”标记为公司名称等。
  • 目的:NER 可以帮助从文本中抽取有价值的信息,如提取商业报告中的公司名称、识别社交媒体上的人物提及等。
  • 标签举例:在文本中,“张三”可以被标记为 PERSON(人名),而“北京”可以被标记为 LOCATION(地点)。

2. 词性标注(POS - Part-of-Speech Tagging)

  • 定义:词性标注是为文本中的每个词分配其词性标签,例如名词、动词、形容词、副词等。词性标注帮助我们了解每个词在句子中的功能和语法角色。
  • 目的:词性标注对于句法分析和构建语言的句法树非常重要,它帮助理解句子的结构和语法关系。
  • 标签举例:在句子中,“猫”可以被标记为 N(名词),而“跑”可以被标记为 V(动词)。

BERT 是一种基于 Transformer 架构的模型,广泛应用于各类自然语言处理任务。下面我们以 NER 为例,运用 Transformers 库手工构建一个基于 BERT 的模型来完成任务。

准备数据

我们选择 1998 年人民日报语料库作为数据集,该语料库标注了大量的语言学信息,可以同时用于分词、NER 等任务。这里我们直接使用处理好的 NER 语料 china-people-daily-ner-corpus.tar.gz。

该语料已经划分好了三类文件example.train(训练集)、example.dev(验证集)和 example.test(测试集),包含 20864 / 2318 / 4636 个句子。语料采用 IOB2 格式进行标注,一行对应一个字:

  • IOB2 格式
    • B-XXX:表示某一类实体的开始
    • I-XXX:表示某一类实体的中间
    • O:表示非实体(即该词不属于任何实体类别)。
  • 具体实体类别包括:
    • PER:人物
    • LOC:地点
    • ORG:组织
  • 例如,“B-LOC”和“I-LOC”分别表示地点实体的开始和中间。

因此共有 7 种标签:

  • “O”:非实体;
  • “B-PER/I-PER”:人物实体的起始/中间;
  • “B-LOC/I-LOC”:地点实体的起始/中间;
  • “B-ORG/I-ORG”:组织实体的起始/中间。

构建数据集

首先编写继承自 Dataset 类的自定义数据集用于组织样本和标签。数据集中句子之间采用空行分隔,因此我们首先通过 '\n\n' 切分出句子,然后按行读取句子中每一个字和对应的标签,如果标签以 B 或者 I 开头,就表示出现了实体。

这段代码展示了如何编写一个自定义的 PyTorch Dataset 类,用于将1998 年《人民日报》语料库中的数据加载进来,并为命名实体识别(NER)任务准备数据样本和标签。这段代码主要负责读取原始数据文件,进行预处理,以便后续的模型训练。下面我来逐步解释这段代码的具体作用。

类别集合初始化

categories = set()

创建了一个集合 categories,用于存储数据集中所有的命名实体类别。例如,如果数据中有 "LOC"(地点)、"PER"(人名)等标签,这些类别将会被存储在 categories 中。

定义自定义数据集类 PeopleDaily

class PeopleDaily(Dataset):
    def __init__(self, data_file):
        self.data = self.load_data(data_file)

  • 类定义:定义了一个继承自 Dataset 的自定义数据集类 PeopleDaily
  • __init__ 方法:初始化函数,用于加载数据文件,并调用 load_data 方法对数据进行处理。

load_data 方法:加载和处理数据

def load_data(self, data_file):
    Data = {}
    with open(data_file, 'rt', encoding='utf-8') as f:
        for idx, line in enumerate(f.read().split('\n\n')):
            if not line:
                break
            sentence, labels = '', []
            for i, item in enumerate(line.split('\n')):
                char, tag = item.split(' ')
                sentence += char
                if tag.startswith('B'):
                    labels.append([i, i, char, tag[2:]])  # Remove the B- or I-
                    categories.add(tag[2:])
                elif tag.startswith('I'):
                    labels[-1][1] = i
                    labels[-1][2] += char
            Data[idx] = {
                'sentence': sentence,
                'labels': labels
            }
    return Data

  • 文件读取with open(data_file, 'rt', encoding='utf-8') as f 打开数据文件,并逐行读取内容。
    • open() 函数

      • open() 是 Python 中用于打开文件的函数。
      • 语法格式为:open(file, mode, encoding),它返回一个文件对象,用于对文件进行读、写或其他操作。
    • data_file

      • 这是一个变量,表示要打开的文件路径,可以是相对路径或者绝对路径。例如,data_file = "example.train" 代表需要打开名为 example.train 的文件。
    • 'rt' 参数

      • r:表示以**只读模式(read)**打开文件,这意味着文件只能读取,不能写入。
      • t:表示以**文本模式(text)打开文件,默认情况下,文件会以字符串形式读取。如果换成 'rb',则是以二进制模式(binary)**打开文件。
      • 组合在一起,'rt' 表示以文本模式打开文件进行只读
    • encoding='utf-8'

      • encoding 指定了文件的字符编码格式
      • 'utf-8' 是一种常用的字符编码,确保程序能够正确处理包含非 ASCII 字符的文本(例如中文、特殊符号等)。它确保打开文件时不会因为编码问题而产生错误。
    • with 语句

      • with open(...) as f: 是 Python 的一种上下文管理方式。
      • 使用 with 语句可以确保文件在使用完后自动关闭,避免因忘记关闭文件而导致的内存泄漏或文件锁问题。
      • f 是一个文件对象,通过 f 可以对文件内容进行读取、写入等操作。with 语句结束后,文件会被自动关闭。
  • 分隔句子f.read().split('\n\n') 通过两个换行符将文本划分为句子,即每个句子之间由两个换行符分隔。
    • f.read(size=-1)
      • f.read() 是 Python 中用于从文件对象(例如 f)中读取内容的方法。
      • f 是通过 open() 打开的文件对象,这个对象允许你读取、写入文件的内容。
      • size 表示要读取的字符数。如果 size 没有指定(或者为 -1),则 f.read()读取文件的全部内容
    • str.split(separator, maxsplit)
      • .split() 是 Python 中用于分割字符串的方法。
      • str 是要分割的字符串,在这里是通过 f.read() 得到的文件内容。
      • 参数:

        • separator(分隔符,默认值为 None
          • 用于指定字符串的分隔符。如果指定了分隔符,例如 \n\n,则 .split() 会在每次遇到该分隔符时将字符串切分为不同部分。
          • f.read().split('\n\n') 中,\n\n 作为分隔符表示文件中的双换行符。这意味着,文件的内容会按段落来分割,每个段落之间有两个换行符。
        • maxsplit(可选)
          • maxsplit 用于控制最大分割次数,默认值为 -1,表示没有限制。
          • 例如,s.split(separator, 2) 只会在前两个分隔符处进行分割。
    • f.read().split('\n\n') 的组合用法
      • f.read():读取文件的全部内容,返回一个 字符串,例如整个文件中的所有文字。
      • .split('\n\n'):对文件内容进行分割,使用双换行符 \n\n 作为分隔符。这将文件内容按段落进行分割,将每个段落作为一个列表中的元素。
  • 遍历句子for idx, line in enumerate(f.read().split('\n\n')) 用于对段落进行划分,将文件的内容按双换行符进行分割,得到一个段落的列表,然后逐个段落进行处理。for后面的idx 是句子的索引,line 是当前句子内容。
    • enumerate() 是 Python 中的一个内置函数,用于在遍历可迭代对象时同时获取每个元素的索引元素本身
    • enumerate(iterable, start=0)
      • iterable:任何可迭代对象(如列表、字符串等)。
      • start:可选参数,表示索引开始的数字,默认为 0
    • enumerate(f.read().split('\n\n'))
      • f.read().split('\n\n') 返回一个列表,每个元素是一个段落。
      • enumerate() 将这个列表的每个元素配对上一个索引(从 0 开始)。
    • f.read().split('\n\n')

      • 读取文件的所有内容,并按双换行符分割为段落。
      • 返回一个列表,列表的每个元素是一个段落(即用两个换行符分隔的部分)。
    • enumerate(f.read().split('\n\n'))

      • enumerate() 为分割后的每个段落加上一个索引,形成索引与段落内容的配对
      • 返回一个 迭代器,可以在遍历中使用,格式为 (index, element),其中 index 是段落的索引,element 是具体的段落内容。
  • 处理句子内容:for i, item in enumerate(line.split('\n')) 用于对句子或行进行划分,将当前段落(line)按单换行符进行分割,得到一个句子的列表,然后逐个句子进行处理。
    • 初始化 sentencelabels,用于存储句子文本和标签。
    • 遍历句子中的每一行(每一行代表一个字符和对应的标注),line.split('\n') 将句子内容分为多个字符。
    • char, tag = item.split(' ') 依照空格' '将字符和标注进行分割,将分割结果分别赋值给 char 和 tag 两个变量。
      • 举个例子,假设 item 是一个字符串 "今 B-LOC"

        • item.split(' ') 的结果是一个列表:['今', 'B-LOC']
        • 列表的第一个元素是字符 '今',第二个元素是标注信息 'B-LOC',也就会得到char = '今',tag = 'B-LOC'。
    • 构建句子文本sentence += char 将当前字符追加到句子中。
    • 处理标签
      • 如果标签以 B 开头(表示命名实体的开始),则将 [i, i, char, tag[2:]] 加入 labels 列表,这表示标注实体的起始位置和类别名称。
      • 如果标签以 I 开头(表示命名实体的中间部分),则更新上一个标签的结束位置 labels[-1][1] = i,并将字符追加到实体中。
    • sentencelabels 存储在 Data 字典中,以 idx 作为键。
  • 根据标签进行解析、存储

    • if tag.startswith('B'):
          labels.append([i, i, char, tag[2:]])  # Remove the B- or I-
          categories.add(tag[2:])
      elif tag.startswith('I'):
          labels[-1][1] = i
          labels[-1][2] += char
      • tag 字符串,代表当前字符的标注信息(比如 B-LOC 表示地名实体的开始,I-LOC 表示地名实体的中间部分)。
      • char 是当前的字符
      • i 是字符在句子中的索引。
    • 代码通过处理这些信息来构建标注的列表 labels
    • if tag.startswith('B'):

      • tag.startswith('B') 是一个 字符串方法,用于检查字符串 tag 是否以 'B' 开头。
      • 功能
        • 在命名实体标注(NER)中,B- 通常表示一个实体的开始(如 B-LOC 表示地名的开始)。
        • 这一行的意思是,如果当前的标注是以 'B' 开头的,则说明这是一个新实体的开始,需要对这个实体进行记录。
    • labels.append([i, i, char, tag[2:]])

      • labels.append([...])

        • labels 是一个列表,存储所有的实体标注信息。
        • append() 方法用于在列表 labels 的末尾添加一个新的元素。
      • [i, i, char, tag[2:]]

        • 这里是添加的列表元素,它包含四个部分:
          • i:当前字符的索引,表示实体的起始位置
          • i:这里的第二个 i 也是当前字符的索引,用于表示实体的结束位置。在实体的开始时,开始位置和结束位置是相同的,后续字符会逐步更新结束位置。
          • char:当前的字符,表示实体的初始字符。
          • tag[2:]:截取标注字符串 tag 的从第 2 个字符到末尾的部分。
            • tag[2:] 的作用是移除 'B-''I-',只保留类别本身。例如,如果 tag'B-LOC',那么 tag[2:] 就是 'LOC',表示这个实体的类别为地名
      • 功能

        • 将一个新实体的起始信息添加到 labels 列表中,这包括实体的起始和结束索引、字符本身以及实体类别。
    • categories.add(tag[2:])

      • categories
        • categories 是一个 集合(set),用于存储所有的实体类别。
      • categories.add(tag[2:])
        • add() 方法用于向集合 categories 中添加新的元素。
        • tag[2:]:这里的作用与上面一样,是从 tag 中移除 'B-''I-',只保留类别部分。例如 'LOC''PER' 等。
      • 功能
        • 将当前实体类别添加到 categories 集合中。这确保每个类别只会出现一次,因为集合中的元素是唯一的。
    • elif tag.startswith('I'):

      • elifelse if 的缩写,用于表示在前一个条件不满足时,检查当前条件是否为真。
      • tag.startswith('I')
        • 检查 tag 是否以 'I' 开头。
        • 在命名实体标注中,I- 通常表示一个实体的中间部分,说明这个字符属于前面某个已经开始的实体的一部分。
      • 功能
        • 如果当前标注是以 'I' 开头,说明这是之前标记的实体的延续,需要更新这个实体的结束位置。
    • labels[-1][1] = i

      • labels[-1]
        • -1 表示列表的最后一个元素。labels[-1] 获取列表中的最后一个标注
      • labels[-1][1] = i
        • labels[-1][1]:获取最后一个标注中的第二个值,表示当前实体的结束位置
        • = i:将结束位置更新为当前字符的索引 i
      • 功能
        • 更新当前实体的结束位置,将结束索引从初始位置更新为当前字符的位置。这样可以标识出整个实体的范围。
    • labels[-1][2] += char

      • labels[-1][2]
        • 获取列表 labels 中最后一个标注的第三个值,表示实体当前已累积的字符。
      • labels[-1][2] += char
        • += char 表示将当前字符追加到之前的实体字符后面。例如,如果之前字符是 '北',当前字符是 '京',那么结果会变为 '北京'
      • 功能
        • 将当前字符追加到现有的实体字符串中,以构建出完整的实体内容。
      • 例子
        • 假设我们处理的标注信息是:
          • 今 B-LOC
            天 I-LOC
            天 O
            气 O
            好 O
        • 流程

          • 对于第一个字符 '今',标注为 'B-LOC'

            • if tag.startswith('B') 为真,表示这是一个新的实体。
            • labels.append([i, i, char, tag[2:]]) 添加一个新实体:[0, 0, '今', 'LOC']
            • categories.add(tag[2:])'LOC' 加入类别集合。
          • 对于第二个字符 '天',标注为 'I-LOC'

            • elif tag.startswith('I') 为真,表示这是之前实体的延续。
            • labels[-1][1] = i 更新结束位置为 1,变为 [0, 1, '今', 'LOC']
            • labels[-1][2] += char 将字符 '天' 追加到已有的字符,变为 [0, 1, '今天', 'LOC']
          • 对于后面的字符 '天''气''好',它们标注为 'O',表示非实体,代码不会处理这些字符的标注。

    • Data[idx] = { 'sentence': sentence, 'labels': labels }

      • 这里的 Data[idx] 表示为字典 Data 添加一个新的键值对,其中:

      • idx 是段落的索引(通常从 0 开始),作为字典的 。每个段落有唯一的索引值 idx
      • {'sentence': sentence, 'labels': labels} 是字典的 ,包含两个部分:
        • 'sentence': sentencesentence 是段落的完整内容,表示该段落的句子字符串。
        • 'labels': labelslabels 是与 sentence 对应的标注信息,包含关于每个实体的起始位置、结束位置、字符、类别等。
      • 例子
        • 假设文件内容包含以下段落:
        • 段落1:
          今 B-LOC
          天 I-LOC
          天 O
          气 O
          好 O

          段落2:
          上 B-LOC
          海 I-LOC
          真 O
          美 O
          丽 O

        • 在代码执行过程中:

        • 第一个段落被处理后,生成的 sentencelabels 分别是:

          • sentence = "今天天气好"
          • labels = [[0, 1, '今天', 'LOC']]:表示从索引 01 的字符 '今天' 是一个地名(LOC)。
        • 第二个段落被处理后,生成的 sentencelabels 分别是:

          • sentence = "上海真美丽"
          • labels = [[0, 1, '上海', 'LOC']]:表示从索引 01 的字符 '上海' 是一个地名(LOC)。
        • 最后,Data 字典可能会变成以下结构:

        • Data = {
              0: {
                  'sentence': '今天天气好',
                  'labels': [[0, 1, '今天', 'LOC']]
              },
              1: {
                  'sentence': '上海真美丽',
                  'labels': [[0, 1, '上海', 'LOC']]
              }
          }

__len__ 方法:返回数据集长度

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

返回数据集的样本数量,用于在训练过程中获取数据集的长度。

__getitem__ 方法:获取指定索引的数据样本

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

根据给定的索引 idx,返回相应的数据样本,通常包括一个句子及其对应的标签。

构建数据集部分的总结

对于这一段代码,我的理解就是,它其实是首先根据两次空行'\n\n'来划分段落,然后再根据一次空行'\n'来划分句子,接着再根据空格' '来划分字符和标签,最后通过判断标签来进行提取,将得到的结果输出为需要的字和标签的集合。我这样理解正确吗?

代码处理的步骤大致如下:

  1. 按段落划分:首先按两个换行符 \n\n 将文本划分成不同的段落。
  2. 按句子划分:然后按换行符 \n 将每个段落划分成多个句子。
  3. 按空格划分字符和标签:接着,按空格将每一行分割为字符和标签。
  4. 提取字和标签:根据标签(如 B-LOC, O 等)来处理每个字符,构建句子和标注。
  5. 存储数据:最后,保存每个段落的句子和标注信息到 Data 字典中。

最终输出的 Data 字典包含了所有段落的句子和对应的标注,通常用于命名实体识别(NER)等任务。

数据预处理

id2label = {0:'O'}
for c in list(sorted(categories)):
    id2label[len(id2label)] = f"B-{c}"
    id2label[len(id2label)] = f"I-{c}"
label2id = {v: k for k, v in id2label.items()}

print(id2label)
print(label2id)

建立标签映射字典

为了能够让模型理解和处理数据,需要将每个实体标签转换为数值形式,这样模型可以接收并进行训练。这里我们使用两个字典:

  • id2label:将ID映射到标签。
  • label2id:将标签映射到ID。

代码分析

id2label = {0: 'O'}

  • id2label 是一个字典,用于将ID映射到标签。
  • 初始化 id2label,将ID 0 对应的标签设置为 'O',表示非实体'O' 通常用于表示这个词或字符不是任何命名实体的一部分。

for c in list(sorted(categories)):
    id2label[len(id2label)] = f"B-{c}"
    id2label[len(id2label)] = f"I-{c}"

  • for c in list(sorted(categories)):

    • 遍历所有在 categories 集合中的标签类别(例如 LOC, ORG, PER 等)。
    • categories 是之前通过遍历数据集构建的集合,包含所有的命名实体类别。
    • 使用 sorted(categories) 是为了确保标签按照字母顺序排列,这样生成的标签ID是一致的,不会因为集合的无序性导致标签ID不一致。
  • id2label[len(id2label)] = f"B-{c}"

    • len(id2label):获取当前 id2label 的长度,作为新标签的ID。
    • f"B-{c}":这是f-string格式化字符串,用于生成 'B-LOC', 'B-ORG', 'B-PER' 等标签。
    • B-{c}:其中 'B' 表示这个实体是命名实体的开始部分,{c} 是实体的类别名称(如 LOC, ORG, PER)。
    • 然后将生成的标签加入 id2label,使得新的ID映射到相应的标签。
    • 使用类似的方式添加 'I-LOC', 'I-ORG', 'I-PER' 等标签。

      • I 表示这个实体是命名实体的中间部分或连续部分。
      • f"B-{c}" 中,{c} 被大括号框起来的原因是因为它是 f-string(格式化字符串)的语法,用来插入变量或表达式的值。
        • B- 是一个固定的字符串部分,表示命名实体的开始标签(例如,表示地点的实体 LOC,组织的实体 ORG 等)。
        • {c} 是一个变量插入部分,c 是循环中的当前类别(比如 'LOC', 'ORG', 'PER' 等)。

最终 id2label 的结果

在遍历完所有的实体类别后,id2label 字典最终可能看起来像这样:

{0: 'O', 1: 'B-LOC', 2: 'I-LOC', 3: 'B-ORG', 4: 'I-ORG', 5: 'B-PER', 6: 'I-PER'}

  • ID 0 对应 'O',表示非实体。
  • ID 1 对应 'B-LOC',表示地名的开始部分。
  • ID 2 对应 'I-LOC',表示地名的中间部分。
  • 依次类推...

建立反向映射字典 label2id

label2id = {v: k for k, v in id2label.items()}

  • label2id 是一个反向映射字典,用于将标签映射回ID。
  • {v: k for k, v in id2label.items()} 是一个字典推导式,用于反转 id2label 的键值对。
    • id2label.items() 返回 id2label 中的所有键值对。
    • v: k for k, v in id2label.items() 将每个键值对中的键(ID)和值(标签)进行交换。
  • 生成的 label2id 字典会看起来像这样:

{'O': 0, 'B-LOC': 1, 'I-LOC': 2, 'B-ORG': 3, 'I-ORG': 4, 'B-PER': 5, 'I-PER': 6}

这样就可以通过标签找到对应的ID。例如,'B-LOC' 对应的ID是 1

print 打印结果

print(id2label)
print(label2id)

这两行代码是用于查看生成的 id2labellabel2id 字典的内容,以确认标签和ID的映射关系是否正确。

输出结果为:

{0: 'O', 1: 'B-LOC', 2: 'I-LOC', 3: 'B-ORG', 4: 'I-ORG', 5: 'B-PER', 6: 'I-PER'}
{'O': 0, 'B-LOC': 1, 'I-LOC': 2, 'B-ORG': 3, 'I-ORG': 4, 'B-PER': 5, 'I-PER': 6}

这些输出展示了标签和ID之间的双向映射关系,方便在模型训练和推理时进行转换。

作用和用途

  • 标签转换为数值形式:神经网络模型只能接受数值输入,因此需要将标签(例如 'B-LOC''I-PER')转换为数值ID。这就是 label2id 的用途。
  • 预测结果转换回标签形式:在模型进行推理之后,预测的输出是数值ID,需要将这些ID转换回可理解的标签。这就是 id2label 的用途。

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

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

相关文章

json+Tomact项目报错怎么办?

在响应请求的时候,如果http响应没有指定响应数据的content-type,浏览器就不知道按照什么格式解析响应体的数据,因为浏览器只知道怎样解析http的行和头,再从头里获取响应体的字节长度和类型,按照你给的长度去截流&#…

极限激光雷达点云数据集

https://arxiv.org/pdf/2307.07607v5 ‎ - AirLab 他们的数据集里面有这么多极限场景 点云数据转换 他们的激光用的velodyne,录制的格式是【velodyne_msgs/VelodyneScan】 需要把【velodyne_msgs/VelodyneScan】转化成【sensor_msgs/PointCloud2】 我编译https://github.co…

信奥常考点:二叉树的构建(已知中序和 前序或后序 的情况下)

一、题目引入 这是来自CCF-GESP C七级认证 2024年9月的题目。 我们在此不解题,只把树画出来。 CCF-GESP 编程能力认证 C 七级 2024年9月份详细解析-CSDN博客 二、解题过程 我们可以根据先序遍历得出根节点是A,然后我们得到了A的左子树[B D](橙…

电容的概念和基本参数

电容基本概念 电容最简单的结构可由两个相互靠近的导体平面中间夹一层绝缘介质组成,当在电容两个极板间加上电压时,电容就会储存电荷,所以电容是一个充放电荷的电子元器件。电容量是电容储存电荷多少的一个量值,平板电容的电容量…

【js逆向专题】13.jsvmp补环境篇一

目录 一.了解jsvmp技术1. js虚拟机保护方案2.jsvmp实现原理3. 模拟jsvmp执行过程 二.环境检测1. 什么是环境检测2.案例讲解 三. 项目实战1. 案例11.逆向目标2. 项目分析1.补第一个referrer2. 调试技巧13. 调试技巧24. 补充sign5. 补 length6. 参数长短补充 3. 逆向结果 2. 案例…

高质量翻译在美国推广移动应用中的重要性

美国的移动应用市场是世界上竞争最激烈、利润最高的市场之一,为开发者提供了接触数百万潜在用户的机会。然而,进入这个市场需要的不仅仅是创新技术或令人信服的想法;它要求与目标受众进行有效地沟通和文化契合。在这个过程中,高质…

[Redis#17] 主从复制 | 拓扑结构 | 复制原理 | 数据同步 | psync

目录 主从模式 主从复制作用 建立主从复制 主节点信息 从节点信息 断开主从复制关系 主从拓扑结构 主从复制原理 1. 复制过程 2. 数据同步(PSYNC) 3. 三种复制方式 一、全量复制 二、部分复制 三、实时复制 四、主从复制模式存在的问题 在…

【Unity高级】如何动态调整物体透明度

本文介绍了如何设置及动态调整物体的透明度。 一、手动设置的方法 我们先来看下如何手动设置物体的透明度。 物体的透明与否是通过材质来设置的。只有我们把具有透明度的材质指给物体的渲染器(Render),物体就被设置成相应的透明度了。 看一…

相机动态/在线标定

图1 图2 基本原理 【原理1】平行线在射影变换后会交于一点。如图所示,A为相机光心,蓝色矩形框为归一化平面,O为平面中心。地面四条黄色直线为平行且等距的车道线。HI交其中两条车道线于H、I, 过G作HI的平行线GM交车道线于M。HI、GM在归一化平面上的投影分别为JK、PN,二者会…

通俗易懂理解:网络安全恶意节点的检测与哨兵节点的激活【论文+代码】

以下资料参考来自本文末尾的参考资料与代码: 在网络安全中,恶意节点检测和哨兵节点激活是确保网络稳定性、可靠性和安全性的关键技术,尤其是在分布式系统、物联网 (IoT)、区块链网络等环境中。下面将详细介绍这两个概念及其应用。 一、恶意…

python作业

1.D 2.B 3.D 4.C 5.B 6.D 7.D 8.B 9.D 10. A 11.D 12.C 13.√ 14.√ 16.√ 17.√ 18.None 19.([1,3],[2]) 20. 列表思维导图

Redis(上)

Redis 基础 什么是 Redis? Redis (REmote DIctionary Server)是一个基于 C 语言开发的开源 NoSQL 数据库(BSD 许可)。与传统数据库不同的是,Redis 的数据是保存在内存中的(内存数据库&#xf…

LabVIEW气缸摩擦力测试系统

基于LabVIEW的气缸摩擦力测试系统实现了气缸在不同工作状态下摩擦力的快速、准确测试。系统由硬件平台和软件两大部分组成,具有高自动化、精确测量和用户友好等特点,可广泛应用于精密机械和自动化领域。 ​ 项目背景: 气缸作为舵机关键部件…

CentOS7.X 安装RustDesk自建服务器实现远程桌面控制

参照文章CentOS安装RustDesk自建服务器中间总有几个位置出错,经实践做个记录防止遗忘 一 环境&工具准备 1.1 阿里云轻量服务器、Centos7系统、目前最高1.1.11版本rustdesk-server-linux-amd64.zip 1.2 阿里云轻量服务器–安全组–开放端口:TCP(21…

工具篇:IDEA VFS 损害启动报错 com.intellij.util.io.CorruptedException 处理

文章目录 前言一、 idea 的 VFS是什么?二、解决方式:2.1 退出Idea 然后重新打开:2.2 手动清除Idea 缓存,让Idea 重新建立缓存:2.2.1 打开 Invalidate Caches / Restart 对话框:2.2.2 勾选要清除的缓存: 总结…

2.linux中调度kettle

一.准备转换,等会在linux中用 1.添加excel输入组件,并添加对应的文件 2.添加列拆分为多行组件 3.添加文本文件输出组件 4.保存转换 二.linux安装java 1.把jdk-8u144-linux-x64.tar.gz上传到linux的/lx目录下 2. 解压jdk包,然后配置环境变量…

第四节、电机定角度转动【51单片机-TB6600驱动器-步进电机教程】

摘要:本节介绍用电机转动角度计算步骤,从而控制步进电机转角 一、 计算过程 1.1 驱动器接收一个脉冲后,步进电机转动一步,根据驱动器设置的细分值 计算一个脉冲对应电机转动的角度step_x s t e p x s t e p X … … ① step_{x…

如何终身使用 100% 免费的服务器

作为开发人员,我们需要在云服务上运行和托管后端。有许多 BaaS(后端即服务)可用,但它们有一些限制。 如果我说我已经免费使用基于 Linux 的服务器超过 4-5 年了,那会怎样?是的,你没听错。我正在使用这台安装了 Ubuntu 20、24 GB RAM、4 个 CPU 和 200 GB 存储空间的 Lin…

【计算机组成原理】期末复习题库

5.主存储器和CPU之间增加cache的目的是 。 A.解决CPU和主存之间的速度匹配问题 B.扩大主存储器的容量 C.扩大CPU中通用寄存器的数量 D.既扩大主存容量又扩大CPU中通用寄存器的数量 在计算机系统中,CPU的速…

SAP中Smartforms 翻译越南语

点击打印预览 打印预览中确实是越南语 转出成PDF 成了乱码 SPAD中查询LP01其实是简体中文 换成LP02试试 显示看上去正常的 SPAD中的LP02 SU3可以设置自己的默认打印参数 查查Smartforms中的字体样式 是宋体,看上去不用为了越南文刻意改字体样式成TIMES 看这篇文章…