Bert基础(十八)--Bert实战:NER命名实体识别

1、命名实体识别介绍

1.1 简介

命名实体识别(NER)是自然语言处理(NLP)中的一项关键技术,它的目标是从文本中识别出具有特定意义或指代性强的实体,并对这些实体进行分类。这些实体通常包括人名、地名、组织机构名、日期、时间、专有名词等。NER在许多实际应用中都非常重要,如信息提取、文本挖掘、机器翻译、自动摘要等。
NER的任务主要分为两部分:

  1. 实体的边界识别:这部分任务是要确定文本中实体的起始和结束位置,即在文本中准确地定位出实体的边界。
  2. 确定实体的类型:在识别出实体的边界之后,还需要确定每个实体的具体类型,如人名、地名、机构名等。

例如,在处理文本“马云在杭州创建了阿里巴巴”时,NER系统需要识别出“阿里巴巴”是一个组织机构名,“马云”是一个人名,“杭州”是一个地名。

NER的技术实现通常涉及机器学习、深度学习等方法,通过训练模型来识别和分类文本中的实体。随着深度学习技术的发展,NER的准确率和效率有了显著提高,成为NLP领域研究和应用的热点之一。我们今天使用transformers库来实现一下。

1.2 标注方法

序列标注的方法中有多种标注方式:BIO、BIOSE、IOB、BILOU、BMEWO,其中前三种最为常见。

  • BIO:标识实体的开始,中间部分和非实体部分

    • b代表“开始”(表示命名实体的开始,即NE)
    • I代表“内部”(表示该词在NE内部)
    • o代表‘outside’(表示这个单词只是一个NE之外的普通单词)
  • BIOSE:增加S单个实体情况的标注和增加E实体的结束标识

    • b代表“开始”(表示一个NE的开始)
    • I代表“内部”(表示该词在NE内部)
    • o代表‘outside’(表示这个单词只是一个NE之外的普通单词)
    • e代表‘end’(表示这个词是一个NE的结尾)
    • s代表“singleton”(表示单个单词是一个NE)
  • IOB (即IOB-1):三位序列标注法(B-begin,I-inside,O-outside),IOB与BIO字母对应的含义相同,其不同点是IOB中,标签B仅用于两个连续的同类型命名实体的边界区分,不用于命名实体的起始位置,这里举个例子:

    • 词序列:(word)(word)(word)(word)(word)(word)
      IOB标注:(I-loc)(I-loc)(B-loc)(I-loc)(o)(o)
      BIO标注:(B-loc)(I-loc)(B-loc)(I-loc)(o)(o)
      在命名实体识别(NER)中,BIO和IOB都使用B、I、O三种标签来标注实体,但是它们在使用B标签的方式上有所不同。
      在BIO标注方法中,B标签用于表示一个实体的开始,I标签用于表示实体的内部,而O标签用于表示非实体词。每个实体都由一个B标签开始,后面跟着零个或多个I标签。
      IOB标注方法与BIO类似,但是在IOB中,B标签有特殊的用途。它仅用于标记两个连续的同类型命名实体的边界,而不是用于标记一个实体的开始。这意味着,如果一个实体紧接着另一个同类型的实体,那么第二个实体不会以B标签开始,而是以I标签开始。
      在这个例子中,前两个词是同一个实体的组成部分,因此在IOB标注中,它们都以I-loc开始。当遇到一个新的同类型实体时,使用B-loc来标记它们的边界。而在BIO标注中,每个实体的开始都使用B标签。
      总的来说,IOB和BIO的主要区别在于如何处理连续的命名实体。IOB在处理这种情况时更加精细,但是在实际应用中,BIO因为其简单性和直观性而被更广泛地使用。

    • 因为IOB的整体效果不好,所以出现了IOB-2,约定了所有命名实体均以B tag开头。这样IOB-2就与BIO的标注方式等价了。

      • I表示实体内部
      • B表示实体开始
      • O表示实体外部
      • 标记说明
        B-Person人名开始
        I- Person人名中间
        B-Organization组织名开始
        I-Organization组织名中间
        O非命名实体

1.3 评价指标

  • 精准率:度量模型的精确度/准确度。 它是正确识别的正值(真正)与所有识别出的正值之间的比率。 精准率指标显示正确标记的预测实体的数量。
    Precision = #True_Positive / (#True_Positive + #False_Positive)

  • 召回率:度量模型预测实际正类的能力。 这是预测的真正值与实际标记的结果之间的比率。 召回率指标显示正确的预测实体的数量。
    Recall = #True_Positive / (#True_Positive + #False_Negatives)

  • F1 分数:F1 分数是精准率和召回率的函数。 在精准率和召回率之间进行平衡时,需要用到它。
    F1 Score = 2 * Precision * Recall / (Precision + Recall)

举例说明

词组Gold标签Predict标签
B-PERB-PER
I-PERI-PER
OO
B-LOCB-LOC
I-LOCI-LOC
OO
OO
OO
B-ORGB-ORG
I-ORGI-ORG
I-ORGO
I-ORGO

例子中一共有三个实体,

  • 预测了三个实体,预测对了2个,所以精准率= 2 3 \frac{2}{3} 32
  • 样本中实际游3个实体,预测对了2个,召回率= 2 3 \frac{2}{3} 32
  • F1 Score = 2 * Precision * Recall / (Precision + Recall) = 2* 2 3 \frac{2}{3} 32* 2 3 \frac{2}{3} 32/( 2 3 \frac{2}{3} 32+ 2 3 \frac{2}{3} 32) = 2 3 \frac{2}{3} 32

2 实战

基本步骤:

1 加载数据集
2 数据预处理
3 创建模型
4 创建评估函数
5 创建训练器
6 训练模型
7 评估
8 预测

2.1 加载数据集

打开hugging face,
在这里插入图片描述
我们这里使用msra_ner数据集

ner_datasets = load_dataset("msra_ner", cache_dir="./data")
ner_datasets
DatasetDict({train: Dataset({features: ['id', 'tokens', 'ner_tags'],num_rows: 45001})test: Dataset({features: ['id', 'tokens', 'ner_tags'],num_rows: 3443})
})

查看数据

print(ner_datasets["train"][0])
{'id': '0', 'tokens': ['当', '希', '望', '工', '程', '救', '助', '的', '百', '万', '儿', '童', '成', '长', '起', '来', ',', '科', '教', '兴', '国', '蔚', '然', '成', '风', '时', ',', '今', '天', '有', '收', '藏', '价', '值', '的', '书', '你', '没', '买', ',', '明', '日', '就', '叫', '你', '悔', '不', '当', '初', '!'], 'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}

这个数据集的第一条好像没有被标注,我们来看下,这个数据集的标注类型

ner_datasets["train"].features
{'id': Value(dtype='string', id=None),'tokens': Sequence(feature=Value(dtype='string', id=None), length=-1, id=None),'ner_tags': Sequence(feature=ClassLabel(names=['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC'], id=None), length=-1, id=None)}
label_list = ner_datasets["train"].features["ner_tags"].feature.names
label_list
['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC']

这个是IOB-2类型

2.2 数据预处理

tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
tokenizer(ner_datasets["train"][0]["tokens"], is_split_into_words=True) {'input_ids': [101, 2496, 2361, 3307, 2339, 4923, 3131, 1221, 4638, 4636, 674, 1036, 4997, 2768, 7270, 6629, 3341, 8024, 4906, 3136, 1069, 1744, 5917, 4197, 2768, 7599, 3198, 8024, 791, 1921, 3300, 3119, 5966, 817, 966, 4638, 741, 872, 3766, 743, 8024, 3209, 3189, 2218, 1373, 872, 2637, 679, 2496, 1159, 8013, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}  

前面我们查看数据时,看到数据其实已经分词了, 对于已经做好tokenize的数据,要指定is_split_into_words参数为True

# 借助word_ids 实现标签映射
def process_function(examples):tokenized_exmaples = tokenizer(examples["tokens"], max_length=128, truncation=True, is_split_into_words=True)labels = []for i, label in enumerate(examples["ner_tags"]):word_ids = tokenized_exmaples.word_ids(batch_index=i)label_ids = []for word_id in word_ids:if word_id is None:label_ids.append(-100)else:label_ids.append(label[word_id])labels.append(label_ids)tokenized_exmaples["labels"] = labelsreturn tokenized_exmaples

这段代码是一个处理函数,用于对给定的例子进行标记映射。它接受一个包含文本和相应命名实体识别(NER)标签的字典作为输入,并返回一个包含标记化文本和映射标签的字典。以下是该函数的详细解释:

  1. tokenizer:这是一个标记器函数,用于将文本转换为标记。它接受文本、最大长度、截断标志和是否按单词分割的标志作为输入。
  2. tokenized_exmaples = tokenizer(examples["tokens"], max_length=128, truncation=True, is_split_into_words=True):这行代码使用标记器函数对输入文本进行标记化处理,并将结果存储在tokenized_exmaples变量中。最大长度设置为128,如果文本长度超过128,则进行截断。同时,标记器会按单词进行分割。
  3. labels = []:这是一个空列表,用于存储映射后的标签。
  4. for i, label in enumerate(examples["ner_tags"])::这行代码遍历输入字典中的NER标签,并为每个标签分配一个索引i
  5. word_ids = tokenized_exmaples.word_ids(batch_index=i):这行代码获取标记化文本中的单词ID。word_ids是一个列表,其中包含与每个标记对应的单词ID。如果标记是一个子单词,则其单词ID与其前一个标记的单词ID相同;如果标记是一个特殊标记(如CLS或SEP),则其单词ID为None。
  6. label_ids = []:这是一个空列表,用于存储映射后的标签ID。
  7. for word_id in word_ids::这行代码遍历word_ids列表中的每个单词ID。
  8. if word_id is None::这行代码检查单词ID是否为None。如果是,说明当前标记是一个特殊标记,我们将标签ID设置为-100。
  9. else::如果单词ID不是None,说明当前标记是一个单词的一部分。我们将输入标签中的相应标签ID添加到label_ids列表中。
  10. labels.append(label_ids):这行代码将label_ids列表添加到labels列表中。
  11. tokenized_exmaples["labels"] = labels:这行代码将labels列表添加到标记化示例字典中。
  12. return tokenized_exmaples:这行代码返回包含标记化文本和映射标签的字典。

总之,这个处理函数使用标记器对输入文本进行标记化处理,并将输入标签映射到标记化文本上。映射后的标签将用于后续的命名实体识别任务。

tokenized_datasets = ner_datasets.map(process_function, batched=True)
tokenized_datasets
DatasetDict({train: Dataset({features: ['id', 'tokens', 'ner_tags', 'input_ids', 'token_type_ids', 'attention_mask', 'labels'],num_rows: 45001})test: Dataset({features: ['id', 'tokens', 'ner_tags', 'input_ids', 'token_type_ids', 'attention_mask', 'labels'],num_rows: 3443})
})

找一个数据看一下

print(tokenized_datasets["train"][5])
{'id': '5', 'tokens': ['我', '们', '是', '受', '到', '郑', '振', '铎', '先', '生', '、', '阿', '英', '先', '生', '著', '作', '的', '启', '示', ',', '从', '个', '人', '条', '件', '出', '发', ',', '瞄', '准', '现', '代', '出', '版', '史', '研', '究', '的', '空', '白', ',', '重', '点', '集', '藏', '解', '放', '区', '、', '国', '民', '党', '毁', '禁', '出', '版', '物', '。'], 'ner_tags': [0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 0, 0, 0, 0, 0, 0], 'input_ids': [101, 2769, 812, 3221, 1358, 1168, 6948, 2920, 7195, 1044, 4495, 510, 7350, 5739, 1044, 4495, 5865, 868, 4638, 1423, 4850, 8024, 794, 702, 782, 3340, 816, 1139, 1355, 8024, 4730, 1114, 4385, 807, 1139, 4276, 1380, 4777, 4955, 4638, 4958, 4635, 8024, 7028, 4157, 7415, 5966, 6237, 3123, 1277, 510, 1744, 3696, 1054, 3673, 4881, 1139, 4276, 4289, 511, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'labels': [-100, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 0, 0, 0, 0, 0, 0, -100]}

2.3 创建模型

# 对于所有的非二分类任务,切记要指定num_labels,否则就会device错误
model = AutoModelForTokenClassification.from_pretrained("bert-base-chinese", num_labels=len(label_list))

2.4 创建评估函数

seqeval = evaluate.load("seqeval")
seqeval

这里使用seqeval进行计算,我们使用开头那个例子来看一下

词组Gold标签Predict标签
B-PERB-PER
I-PERI-PER
OO
B-LOCB-LOC
I-LOCI-LOC
OO
OO
OO
B-ORGB-ORG
I-ORGI-ORG
I-ORGO
I-ORGO
references = [["B-PER", "I-PER", "O", "B-LOC", "I-LOC", "O", "O", "O", "B-ORG", "I-ORG", "I-ORG", "I-ORG"]]
predictions = [["B-PER", "I-PER", "O", "B-LOC", "I-LOC", "O", "O", "O", "B-ORG", "I-ORG", "O", "O"]]results = seqeval.compute(predictions=predictions, references=references){'LOC': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1},'ORG': {'precision': 0.0, 'recall': 0.0, 'f1': 0.0, 'number': 1},'PER': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1},'overall_precision': 0.6666666666666666,'overall_recall': 0.6666666666666666,'overall_f1': 0.6666666666666666,'overall_accuracy': 0.8333333333333334}

创建评估函数

import numpy as npdef eval_metric(pred):predictions, labels = predpredictions = np.argmax(predictions, axis=-1)# 将id转换为原始的字符串类型的标签true_predictions = [[label_list[p] for p, l in zip(prediction, label) if l != -100]for prediction, label in zip(predictions, labels) ]true_labels = [[label_list[l] for p, l in zip(prediction, label) if l != -100]for prediction, label in zip(predictions, labels) ]result = seqeval.compute(predictions=true_predictions, references=true_labels, mode="strict", scheme="IOB2")return {"f1": result["overall_f1"]}

这段代码定义了一个评估指标函数eval_metric,用于评估序列标注模型在命名实体识别(NER)任务上的性能。函数的输入是一个元组pred,其中包含模型预测的分数和真实的标签。代码使用numpy库来处理数组运算,并使用seqeval库来计算评估指标。
以下是代码的详细解释:

  1. import numpy as np:导入numpy库,用于执行高效的数学运算。
  2. def eval_metric(pred)::定义一个名为eval_metric的函数,它接受一个参数pred,这是一个包含模型预测分数和真实标签的元组。
  3. predictions, labels = pred:将pred元组解包为两个变量predictionslabels,分别存储模型预测的分数和真实的标签。
  4. predictions = np.argmax(predictions, axis=-1):使用numpyargmax函数沿最后一个轴(即类别轴)找到每个样本的最大预测分数的索引,这些索引对应于预测的标签ID。
  5. true_predictions = [...]:这是一个列表推导式,用于将预测的标签ID转换为原始的字符串类型的标签。对于每个预测和标签序列,它遍历它们并创建一个新的列表,其中只包含标签不是-100的元素。label_list[p]用于将标签ID转换为字符串标签。
  6. true_labels = [...]:这是另一个列表推导式,与true_predictions类似,但它用于转换真实的标签ID为字符串标签。
  7. result = seqeval.compute(predictions=true_predictions, references=true_labels, mode="strict", scheme="IOB2"):这行代码使用seqeval库的compute函数来计算评估指标。true_predictions是模型的预测,true_labels是真实的标签。mode参数设置为"strict",表示严格评估模式,scheme参数设置为"IOB2",表示使用IOB2标签格式。
  8. return {"f1": result["overall_f1"]}:函数返回一个字典,其中包含整体的F1分数,这是NER任务中常用的评估指标。
    总之,这个函数用于评估模型在NER任务上的性能,它将模型输出的分数转换为标签,并使用seqeval库来计算F1分数。

2.5 创建训练器

args = TrainingArguments(output_dir="models_for_ner",per_device_train_batch_size=64,per_device_eval_batch_size=128,evaluation_strategy="epoch",save_strategy="epoch",metric_for_best_model="f1",load_best_model_at_end=True,logging_steps=50,num_train_epochs=1,report_to=['tensorboard']
)

为了节省时间我们只训练一遍num_train_epochs=1

2.6 模型训练

trainer = Trainer(model=model,args=args,train_dataset=tokenized_datasets["train"],eval_dataset=tokenized_datasets["test"],compute_metrics=eval_metric,data_collator=DataCollatorForTokenClassification(tokenizer=tokenizer)
)
trainer.train()

在这里插入图片描述
F1达到了0.946

2.7 评估

trainer.evaluate(eval_dataset=tokenized_datasets["test"]){'eval_loss': 0.02092777192592621,'eval_f1': 0.9463030643800956,'eval_runtime': 16.7905,'eval_samples_per_second': 205.056,'eval_steps_per_second': 1.608,'epoch': 1.0}

2.8 预测

# 如果模型是基于GPU训练的,那么推理时要指定device
# 对于NER任务,可以指定aggregation_strategy为simple,得到具体的实体的结果,而不是token的结果
ner_pipe = pipeline("token-classification", model=model, tokenizer=tokenizer, device=0, aggregation_strategy="simple")res = ner_pipe("马云在杭州创建了阿里巴巴")
res[{'entity_group': 'PER','score': 0.9968899,'word': '马 云','start': 0,'end': 2},{'entity_group': 'LOC','score': 0.99767697,'word': '杭 州','start': 3,'end': 5},{'entity_group': 'ORG','score': 0.98138344,'word': '阿 里 巴 巴','start': 8,'end': 12}]

完整代码

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

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

相关文章

极简shell制作

🌎自定义简单shell制作 (ps: 文末有完整代码) 文章目录: 自定义简单shell制作 简单配置Linux文件 自定义Shell编写 命令行解释器       获取输入的命令       字符串分割       子进程进行进程替换 内建命令…

28.Gateway-网关过滤器

GatewayFilter是网关中提供的一种过滤器,可以多进入网关的请求和微服务返回的响应做处理。 GatewayFilter(当前路由过滤器,DefaultFilter) spring中提供了31种不同的路由过滤器工厂。 filters针对部分路由的过滤器。 default-filters针对所有路由的默认…

opencv基础篇 ——(九)图像几何变换

图像几何变换是通过对图像的几何结构进行变换来改变图像的形状、大小、方向或者透视关系。常见的图像几何变换包括缩放、旋转、平移、仿射变换和透视变换等。下面对这些几何变换进行简要介绍: 矩阵的转置(transpose ): 对于图像来…

微服务之SpringCloud AlibabaNacos服务注册和配置中心

一、概述 1.1注册中心原理 在微服务远程调用的过程中,包括两个角色: 服务提供者:提供接口供其它微服务访问,比如item-service 服务消费者:调用其它微服务提供的接口,比如cart-service 在大型微服务项目…

符合医药行业规范的液氮罐运输和存储温度监测解决方案

API原料药、冻干物质和人体样本必须在玻璃相中以尽可能低的温度运输和存储。专门的低温容器——干式液氮罐——可通过液氮(LN2)将温度保持在-196 C。由于温度极低,低温容器的温度数据监测不仅具有挑战性,而且还需要更复杂的过程&a…

Linux下的常用基本指令

基本指令 前言ls 指令语法功能常用选项举例注意要点关于拼接关于 -a关于文件ls与/的联用ls与根目录ls与任意文件夹ls与常用选项与路径 ls -d与ls -ldls与ll pwd命令语法功能常用选项注意要点window与Linux文件路径的区别家目录 cd 指令语法功能举例注意要点cd路径.. .相对路径与…

Cesium116版本安装跑错,注意Node版本

SyntaxError: Unexpected token ?? at Loader.moduleStrategy (internal/modules/esm/translators.js:149:18) 无法解析ES node.js本本过低 nvm use无效NVM踩坑不完全指南,nvm use没有*_nvm use 无效-CSDN博客

决策树模型示例

通过5个条件判定一件事情是否会发生,5个条件对这件事情是否发生的影响力不同,计算每个条件对这件事情发生的影响力多大,写一个决策树模型pytorch程序,最后打印5个条件分别的影响力。 一 决策树模型是一种非参数监督学习方法,主要…

centos7 openresty lua 自适应webp和缩放图片

目录 背景效果图准备安装cwebp等命令,转换文件格式安装ImageMagick,压缩文件下载Lua API 操控ImageMagick的依赖包 代码参考 背景 缩小图片体积,提升加载速度,节省流量。 效果图 参数格式 : ?image_processformat,…

Llama-7b-Chinese本地推理

Llama-7b-Chinese 本地推理 基础环境信息(wsl2安装Ubuntu22.04 miniconda) 使用miniconda搭建环境 (base) :~$ conda create --name Llama-7b-Chinese python3.10 Channels:- defaults Platform: linux-64 Collecting package metadata (repodata.js…

Linux下软硬链接和动静态库制作详解

目录 前言 软硬链接 概念 软链接的创建 硬链接的创建 软硬链接的本质区别 理解软链接 理解硬链接 小结 动静态库 概念 动静态库的制作 静态库的制作 动态库的制作 前言 本文涉及到inode和地址空间等相关概念,不知道的小伙伴可以先阅读以下两篇文章…

智慧校园建设指导

智慧校园是一个庞大的业务系统,他涉及到校园事务的各个方面,包括教务,考务,教工,学工,办公,科研等。因此,建设符合学校业务需求的智慧校园平台,不仅需要做到认真负责外&a…

C语言位运算详解(移位操作符、位操作符)

目录 一、整数在内存中的存储方式 二、移位操作符 1、左移操作符 2、右移操作符 a.逻辑右移 b.算数右移 ps、移位操作符使用警告 三、位操作符 用例代码: a.按位与(&) b.按位或(|) c.按位异或&#xf…

【笔试强训】Day4 --- Fibonacci数列 + 单词搜索 + 杨辉三角

文章目录 1. Fibonacci数列2. 单词搜索3. 杨辉三角 1. Fibonacci数列 【链接】:Fibonacci数列 解题思路:简单模拟题,要最少的步数就是找离N最近的Fibonacci数,即可能情况只有比他小的最大的那个Fibonacci数以及比他大的最小的那…

《软件设计师教程:计算机网络浅了解计算机之间相互运运作的模式》

​ 个人主页:李仙桎 🔥 个人专栏: 《软件设计师》 ⛺️生活的理想,就是为了理想的生活! ​ ⛺️前言:各位铁汁们好啊!!!,今天开始继续学习中级软件设计师考试相关的内容&#xff0…

Java高阶私房菜:JVM垃圾回收机制及算法原理探究

目录 垃圾回收机制 什么是垃圾回收机制 JVM的自动垃圾回收机制 垃圾回收机制的关键知识点 初步了解判断方法-引用计数法 GCRoot和可达性分析算法 什么是可达性分析算法 什么是GC Root 对象回收的关键知识点 标记对象可回收就一定会被回收吗? 可达性分析算…

【免费源码下载】完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城php+uniapp

简介 完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本&am…

52832 不使用micro_lib ,同时使用AC6编译器且使用printf问题

1. 因为我的工程用AC6是因为要跑自己的C 和 TensorFlow lite micro. 所以是C,C混合的工程,但是一直没法打印,所以写一个总结。 基本说明: micro_lib这种情况不要选,因为存在C文件 第一个坑: 第二个坑&…

windows 避免电脑强制息屏

许多打工人的电脑被公司设置了隔一段时间没有操作,就会自动息屏,如何避免这种事发生呢 方案一 自动操作鼠标的软件 如果能自由安装软件,可以下载自动移动鼠标的软件,设置鼠标每隔多长时间做一次什么操作,防止锁屏 方…

LIUNX:系统编程动态库加载(1)

目录 操作系统角度理解 如何加载 怎么管理库 编址 操作系统角度理解 如何加载 首先main想要运行,首先要为main创建task_struct和mm_struct,然后将main的代码和数据加载到内存,将main的代码通过页表映射到mm_struct的正文代码段&#xff0…