深度学习实践(一)基于Transformer英译汉模型

本文目录

  • 前述
  • 一、环境依赖
  • 二、数据准备
    • 1. 数据加载
      • 程序解析
        • word_tokenize()将字符串分割为一个个的单词,并由列表保存。
    • 2. 构建单词表
      • 程序解析
        • (1)将列表里每个子列表的所有单词合并到一个新列表(没有子列表)中。
        • (2)Counter()-- 统计列表(迭代对象)各元素出现次数,并按次数从多到少排序。
        • (3)获取出现频率最高的前 50000 个元素及其个数,返回一个含有多个元组的列表。
        • (4) 将含有多个元组的列表,转为字典。
        • (5) 将字典的元素和索引互换位置。
    • 3. 将英文、中文单词列表转为单词索引列表
      • 程序解析
        • (1)将en句子中的各个单词在字典里的索引,组成一个索引列表。
        • (2)将句子的索引列表按照句子长度进行排序--从短到长。
    • 4. 获取所有语句中的最大长度,如果语句小于该长度则填充。
    • 5. 划分batch
  • 三、模型搭建

前述

基础请查看:Transformer基础查看地址!

一、环境依赖

nltk==3.5
numpy==1.18.5
seaborn==0.11.1
matplotlib==3.3.2
psyco==1.6
zhtools==0.0.5

#torch==1.12.1 安装torch时使用下面的命令
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 -i https://pypi.tuna.tsinghua.edu.cn/simple

代码导入包 :

import copy
import math
import matplotlib.pyplot as plt
import numpy as np
import os
import seaborn as sns
import time
import torch
import torch.nn as nn
import torch.nn.functional as F

from collections import Counter
from langconv import Converter
from nltk import word_tokenize
from torch.autograd import Variable

二、数据准备

  数据集可以去网络上下载,下面的是train.txt文件部分内容,前面为英文,后面为繁体中文,中间以'\t'隔开。其他数据文件也相同。
这里数据集是英文和繁体中文,所以第一步我们需要将繁体中文变为简体中文。
在这里插入图片描述

转换代码如下:

def cht_to_chs(sent):
"""" zh-hans" 是一个语言代码,用于指代中文(汉语)的简体字形式。在国际化和本地化领域,语言代码用于标识特定语言或语言变体。
     在这里,"zh" 表示汉语(中文),"hans" 表示简体字形式。因此,"zh-hans" 表示简体中文。"""
    sent = Converter("zh-hans").convert(sent) 
    sent = sent.encode("utf-8")
    return sent

1. 数据加载

作用:读取数据路径下的完整句子,将每个句子分割为一个一个的单词,并存到子列表中。返回含有子列表的列表,

"""参数参数path 为数据的路径,如下
	train_file= 'nmt/en-cn/train.txt'  # 训练集
	dev_file= "nmt/en-cn/dev.txt"      # 验证集
	load_data(train_file)
"""

def load_data(path):
    """
    读取英文、中文数据
    对每条样本分词并构建包含起始符和终止符的单词列表
    """
    en = []    #定义英文列表
    cn = []    #定义中文列表
    with open(path, mode="r", encoding="utf-8") as f:     #只读的形式打开文件路径,文件描述符为f。
        for line in f.readlines():          #按行读取
            sent_en, sent_cn = line.strip().split("\t")  #以‘\t’进行分割,前面的赋给sent_en,后面的赋给sent_cn 。
            sent_en = sent_en.lower()    #将英文转换为小写。
            sent_cn = cht_to_chs(sent_cn)  #将繁体中文转为简体中文。
            sent_en = ["BOS"] + word_tokenize(sent_en) + ["EOS"]
            # 中文按字符切分
            sent_cn = ["BOS"] + [char for char in sent_cn] + ["EOS"]
            en.append(sent_en)  #将切割好的英文 存入英文列表。包含['BOS', 'i', 'love', 'you', 'EOS']
            cn.append(sent_cn)  #将切割好的中文 存入中文列表。
    return en, cn    #返回两个单词列表
    
"""
输出列表格式如下:
     en = [
					    ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
					    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
		  ]
"""	            

程序解析

word_tokenize()将字符串分割为一个个的单词,并由列表保存。
from nltk import word_tokenize

sent_en="He knows better than to marry her."
print(word_tokenize(sent_en))


# 输出为:['He', 'knows', 'better', 'than', 'to', 'marry', 'her', '.']

2. 构建单词表

"""输入
	sentences= [
				    ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
				    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
	          ]
"""

PAD = 0                             # padding占位符的索引
UNK = 1                             # 未登录词标识符的索引
def build_dict(sentences, max_words=5e4):
     """
     构造分词后的列表数据
     构建单词-索引映射(key为单词,value为id值)
     """
     # 统计数据集中单词词频
     word_count = Counter([word for sent in sentences for word in sent])
    
     # 按词频保留前max_words个单词构建词典
     # 添加UNK和PAD两个单词
     ls = word_count.most_common(int(max_words))
     total_words = len(ls) + 2
     word_dict = {word [0]: index + 2 for index, word in enumerate(ls)}
     word_dict['UNK'] = UNK
     word_dict['PAD'] = PAD
     # 构建id2word映射
     index_dict = {v: k for k, v in word_dict.items()}
     return word_dict, total_words, index_dict

"""
输出:
	word_dict ={'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0}

	index_dict= {2: 'BOS', 3: 'language', 4: 'processing', 5: '.', 6: 'EOS', 7: 'I', 8: 'love', 9: 'natural', 10: 'Natural', 11: 'is', 12: 'fascinating', 1: 'UNK', 0: 'PAD'}
"""

程序解析

(1)将列表里每个子列表的所有单词合并到一个新列表(没有子列表)中。

将sentences里面每句话的每个单词组合形成一个新的列表。

sentences = [
			    ['BOS''I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
			    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
		  ]
		     
word_list = [word for sent in sentences for word in sent]
"""
另一种写法:
			word_list = []
			for sent in sentences:
			    for word in sent:
			        word_list.append(word)
"""
print(word_list )
"""
	输出: ['BOS', 'I', 'love', 'natural', 'language', 'processing', '.', 'EOS', 'BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
"""
(2)Counter()-- 统计列表(迭代对象)各元素出现次数,并按次数从多到少排序。
from collections import Counter
#Python 中的一个内置数据结构
# 定义一个列表
word_list = ['BOS', 'I', 'love', 'natural', 'language', 'processing', '.', 'EOS', 'BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
# 使用 Counter 统计列表中各元素的出现次数
word_count = Counter(word_list)
print(word_count )

"""
	输出: Counter({'BOS': 2, 'language': 2, 'processing': 2, '.': 2, 'EOS': 2, 'I': 1, 'love': 1, 'natural': 1, 'Natural': 1, 'is': 1, 'fascinating': 1})
"""

(3)获取出现频率最高的前 50000 个元素及其个数,返回一个含有多个元组的列表。

如: [ (元素1,频次),(元素2,频次),… ]

from collections import Counter

word_count = Counter({'BOS': 2, 'language': 2, 'processing': 2, '.': 2, 'EOS': 2, 'I': 1, 'love': 1, 'natural': 1, 'Natural': 1, 'is': 1, 'fascinating': 1})

ls = word_count.most_common(int(5e4))#返回列表中频率最高的元素和它们的计数,按照计数从高到低排序。频率最高的前 50000 个元素。
print(ls)
"""
输出:
	[('BOS', 2), ('language', 2), ('processing', 2), ('.', 2), ('EOS', 2), ('I', 1), ('love', 1), ('natural', 1), ('Natural', 1), ('is', 1), ('fascinating', 1)]

"""
(4) 将含有多个元组的列表,转为字典。

如:word_dict ={元素1:索引,元素2,索引…}
enumerate(可迭代元素),返回的第一个值为索引,第二个值为元素。

ls = [('BOS', 2), ('language', 2), ('processing', 2), ('.', 2), ('EOS', 2), ('I', 1), ('love', 1), ('natural', 1), ('Natural', 1), ('is', 1), ('fascinating', 1)]

word_dict = {word [0]: index + 2 for index, word in enumerate(ls)}
# word是('BOS',2), word[0]='BOS' , word[1]=2
#index 是该元组的索引,也就是 0
"""另一种写法:
				word_dict = {}
				for index, word  in enumerate(ls):
				    word_dict[ word[0] ] = index + 2
				print(word_dict)
"""
print(word_dict)  #存放元素及其索引号
"""
	输出: {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12}
"""

word_dict['UNK'] = 1
word_dict['PAD'] = 0
print(word_dict)
"""
	输出:{'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0}
"""
(5) 将字典的元素和索引互换位置。
word_dict= {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0}

index_dict = {v: k for k, v in word_dict.items()}
print(index_dict)

"""
	输出:{2: 'BOS', 3: 'language', 4: 'processing', 5: '.', 6: 'EOS', 7: 'I', 8: 'love', 9: 'natural', 10: 'Natural', 11: 'is', 12: 'fascinating', 1: 'UNK', 0: 'PAD'}
"""

3. 将英文、中文单词列表转为单词索引列表

"""
输入:
 en = [
	        ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
		    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
	  ]
cn= 同上格式相同

en_dict= {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0 }

cn_dict= 同上格式相同
"""

def word2id(en, cn, en_dict, cn_dict, sort=True):
      """
      将英文、中文单词列表转为单词索引列表
      `sort=True`表示以英文语句长度排序,以便按批次填充时,同批次语句填充尽量少
      """
      length = len(en)  #计算长度
      # 单词映射为索引
      out_en_ids = [[en_dict.get(word, UNK) for word in sent] for sent in en]
      out_cn_ids = [[cn_dict.get(word, UNK) for word in sent] for sent in cn]

      # 按照语句长度排序
      def len_argsort(seq):
          """
          传入一系列语句数据(分好词的列表形式),
          按照语句长度排序后,返回排序后原来各语句在数据中的索引下标
          """
          return sorted(range(len(seq)), key=lambda x: len(seq[x]))

      # 按相同顺序对中文、英文样本排序
      if sort:
          # 以英文语句长度排序
          sorted_index = len_argsort(out_en_ids)
          out_en_ids = [out_en_ids[idx] for idx in sorted_index]
          out_cn_ids = [out_cn_ids[idx] for idx in sorted_index]
      return out_en_ids, out_cn_ids

"""
输出:
out_en_ids=	 [ 
				[2, 7, 8, 9, 3, 4, 5, 6],
				[2, 10, 3, 4, 11, 12, 5, 6] 
	       ]
out_cn_ids= 同上格式相同
"""

程序解析

(1)将en句子中的各个单词在字典里的索引,组成一个索引列表。

from nltk import word_tokenize

PAD = 0                             # padding占位符的索引
UNK = 1                             # 未登录词标识符的索引

en = [
	        ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
		    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
	  ]
en_dict= {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0 }

out_en_ids = [[en_dict.get(word, UNK) for word in sent] for sent in en]
"""
另一种写法:
			out_en_ids = []
			for sent in en:
			    # 将句子中的每个单词转换为对应的单词ID
			    # 如果单词不在字典中,则使用UNK表示
			    word_ids = []
			    for word in sent:
			        word_id = en_dict.get(word, UNK)
			        word_ids.append(word_id)
			    out_en_ids.append(word_ids)
"""
print(out_en_ids)
"""
	输出: [ 
				[2, 7, 8, 9, 3, 4, 5, 6],
				[2, 10, 3, 4, 11, 12, 5, 6] 
	       ]
2:en第一个句子的第一个单词'BOS'在en_dict字典的索引值为2.
7:en第一个句子的第二个单词'I'在en_dict字典的索引值为7.
8:en第一个句子的第三个单词'love'在en_dict字典的索引值为8.
......
"""

(2)将句子的索引列表按照句子长度进行排序–从短到长。

作用: 以便后续分batch做padding时,同批次各句子需要padding的长度相近减少padding量。


from nltk import word_tokenize

UNK=1
en = [
    ['BOS', 'I', 'love', 'natural', 'language', 'processing', '.', 'EOS'],
    ['BOS', 'This', 'is', 'a', 'test', 'sentence', '.', 'EOS','I','love'],
    ['BOS',  'test', '.', 'EOS']
]
en_dict = {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'This': 10, 'is': 11, 'a': 12, 'test': 13, 'sentence': 14, 'UNK': 1, 'PAD': 0}

def word2id(en, en_dict, sort=True):

    length = len(en)  # 计算长度
    out_en_ids = [[en_dict.get(word, UNK) for word in sent] for sent in en]
    """
    out_en_ids = [ 
				    [2, 7, 8, 9, 3, 4, 5, 6],
				    [2, 10, 3, 4, 11, 12, 5, 6] 
	             ]
    """
    # 按照语句长度排序
    def len_argsort(seq):
        return sorted(range(len(seq)), key=lambda x: len(seq[x]))
    
    if sort:
        sorted_index = len_argsort(out_en_ids) #获得按句子长度排序后的索引号,如sorted_index =[2, 0, 1]
        out_en_ids = [out_en_ids[idx] for idx in sorted_index] #按照排序后的索引列表的索引,将索引列表排序。
    return out_en_ids

print(word2id(en,en_dict))

"""
sort=False  索引列表按en句子的顺序排列
	out_en_ids=	[[2, 7, 8, 9, 3, 4, 5, 6], [2, 10, 11, 12, 13, 14, 5, 6, 7, 8], [2, 13, 5, 6] ]

sort=True   索引列表按en句子的长度排列,从短到长排列
	out_en_ids=	[[2, 13, 5, 6], [2, 7, 8, 9, 3, 4, 5, 6],  [2, 10, 11, 12, 13, 14, 5, 6, 7, 8] ]
"""

4. 获取所有语句中的最大长度,如果语句小于该长度则填充。

PAD=0

def seq_padding(X, padding=PAD):
    """
    按批次(batch)对数据填充、长度对齐
    """
    # 计算该批次各条样本语句长度
    L = [len(x) for x in X]
    # 获取该批次样本中语句长度最大值
    ML = max(L)
    # 遍历该批次样本,如果语句长度小于最大长度,则用padding填充
    return np.array([
        np.concatenate([x, [padding] * (ML - len(x))]) if len(x) < ML else x for x in X
    ])

"""写法二: """
def seq_padding(X, padding=PAD):
    """
    按批次(batch)对数据填充、长度对齐
    """
    # 计算该批次各条样本语句长度
    Length = [len(x) for x in X]
    # 获取该批次样本中语句长度最大值
    MaxLength = max(Length)
    # 遍历该批次样本,如果语句长度小于最大长度,则用padding填充
    padded_X = []
    for x in X:
        if len(x) < MaxLength:
            padded_seq = np.concatenate([x, [padding] * (ML - len(x))])
        else:
            padded_seq = x
        padded_X.append(padded_seq)
    return np.array(padded_X)

5. 划分batch

"""输入
	sentences= [
				    ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
				    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
	          ]
"""
def split_batch(self, en, cn, batch_size, shuffle=True):
     """
     划分批次
     `shuffle=True`表示对各批次顺序随机打乱
     """
     # 每隔batch_size取一个索引作为后续batch的起始索引
     idx_list = np.arange(0, len(en), batch_size)
     # 起始索引随机打乱
     if shuffle:
         np.random.shuffle(idx_list)
     # 存放所有批次的语句索引
     batch_indexs = []
     for idx in idx_list:
         """
         形如[array([4, 5, 6, 7]), 
              array([0, 1, 2, 3]), 
              array([8, 9, 10, 11]),
              ...]
         """
         # 起始索引最大的批次可能发生越界,要限定其索引
         batch_indexs.append(np.arange(idx, min(idx + batch_size, len(en))))
     # 构建批次列表
     batches = []
     for batch_index in batch_indexs:
         # 按当前批次的样本索引采样
         batch_en = [en[index] for index in batch_index]
         batch_cn = [cn[index] for index in batch_index]
         # 对当前批次中所有语句填充、对齐长度
         # 维度为:batch_size * 当前批次中语句的最大长度
         batch_cn = seq_padding(batch_cn)
         batch_en = seq_padding(batch_en)
         # 将当前批次添加到批次列表
         # Batch类用于实现注意力掩码
         batches.append(Batch(batch_en, batch_cn))
     return batches

三、模型搭建

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

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

相关文章

4.9日总结

1.MySQL概述 1.数据库基本概念&#xff1a;存储数据的仓库&#xff0c;数据是有组织的进行存储 2.数据库管理系统&#xff1a;操纵和管理数据库的大型软件 3.SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;定义了一套操作型数据库统一标准 2.MySQL数据库 关系型数…

单例模式(饿汉模型,懒汉模型)

在着里我们先了解什么是单例模式。 就是某个类在进程中只能有单个实例&#xff0c;这里的单例模式需要一定的编程技巧&#xff0c;做出限制&#xff0c;一旦程序写的有问题&#xff0c;创建了多个实例&#xff0c;编程就会报错。 如果我们学会了单例模式&#xff0c;这种模式…

小程序变更主体流程是怎样的?

小程序迁移变更主体有什么作用&#xff1f;“小程序主体变更”是指小程序账号开发者将其小程序项下业务交由其他开发者承接、运营和服务。主体变更完成后&#xff0c;小程序的运营权限、主体信息将发生变化。小程序迁移变更主体的条件有哪些&#xff1f;1、境外小程序不支持小程…

秋叶Stable diffusion的创世工具安装-带安装包链接

来自B站up秋葉aaaki&#xff0c;近期发布了Stable Diffusion整合包v4.7版本&#xff0c;一键在本地部署Stable Diffusion&#xff01;&#xff01; 适用于零基础想要使用AI绘画的小伙伴~本整合包支持SDXL&#xff0c;预装多种必须模型。无需安装git、python、cuda等任何内容&am…

yolov7的改进工地安全帽佩戴检测系统-协同双注意力机制CDAM2(教程+代码)

研究的背景和意义 随着工业化和城市化的快速发展&#xff0c;建筑工地的安全问题日益凸显。在建筑工地中&#xff0c;工人的安全是至关重要的&#xff0c;而工地安全帽的佩戴是保障工人安全的重要措施之一。然而&#xff0c;由于工地环境复杂多变&#xff0c;工人的佩戴情况往…

【jQuery】jQuery框架

目录 1.jQuery基本用法 1.1选择器 1.2jQuery对象 1.3事件绑定 1.4链式编程 1.5过滤方法 1.6样式操纵 1.6属性操纵 1.7操作value 1.8查找方法 1.9类名操纵 1.10事件进阶 1.11触发事件 1.12window事件绑定 2.节点操作与动画 2.1获取位置 2.2滚动距离 2.3显示/隐…

C语言——调试技巧

1.Debug和Release的介绍 Debug 通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不作任何优化&#xff0c;便于程序员调试程序。Release 称为发布版本&#xff0c;它往往是进行了各种优化&#xff0c;使得程序在代码大小和运行速度上都是最优 的&#xff0c;以便用…

AIGC实战——StyleGAN(Style-Based Generative Adversarial Network)

AIGC实战——StyleGAN 0. 前言1. StyleGAN1.1 映射网络1.2 合成网络1.3 自适应实例归一化层1.4 风格混合1.5 随机变化 2. StyleGAN 生成样本3. StyleGAN23.1 权重调制与解调3.2 路径长度正则化3.3 非渐进式增长 4. StyleGAN2 生成样本小结系列链接 0. 前言 StyleGAN (Style-Ba…

Echarts柱状图多样式实现

样式一 样式二 在这里插入代码片

大语言模型开源数据集

本文目标&#xff1a;汇聚目前大语言模型预训练、微调、RM/RL、评测等全流程所需的常见数据集&#xff0c;方便大家使用&#xff0c;本文持续更新。文章篇幅较长&#xff0c;建议收藏后使用。 一、按语料类型分类 1、维基百科类 No.1 Identifying Machine-Paraphrased Plagia…

【行业认证,实力背书】NISP一级证书,你的信息安全职业通行证!

国家信息安全水平考试(NISP一级) 2024年3月考试成绩发布 通过的学员由中国信息安全测评中心颁发证书 以下是考试通过名单 PART01&#xff1a;什么是国家信息安全水平考试 国家信息安全水平考试&#xff08;NISP&#xff09;认证分为一级和二级&#xff0c;证书由中国信息安全测…

使用 wangeditor 解析富文本并生成目录与代码块复制功能

在 Web 开发中&#xff0c;经常需要使用富文本编辑器来编辑和展示内容。wangeditor 是一个强大的富文本编辑器&#xff0c;提供了丰富的功能和灵活的配置&#xff0c;但是官方并没有提供目录导航和代码块的复制功能&#xff0c;所以我自己搞了一个 <template><div cla…

安卓的认证测试

1 CTS CTS 是 Android 兼容性测试套件&#xff0c;用于验证设备是否符合 Android 平台的兼容性标准。它包含一系列测试用例&#xff0c;涵盖了设备的各个方面&#xff0c;如硬件功能、软件功能、API 的正确实现等。通过 CTS 测试&#xff0c;设备厂商可以确保其设备符合 Andro…

华为S5735S核心交换配置实例

以下脚本实现创建vlan2,3&#xff0c;IP划分&#xff0c;DHCP启用&#xff0c;接口划分&#xff0c;ssh,telnet,http,远程登录启用 默认用户创建admin/admin123提示首次登录需要更改用户密码S5735产品手册更多功能配置&#xff0c;移步官网参考手册配置 sysname test-Hxvlan …

Linux入门攻坚——18、SELinux、Bash脚本编程续

SELinux——Secure Enhanced Linux&#xff08;安全加强的Linux&#xff09;&#xff0c;工作于Linux内核中。 SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源&#xff08;最小权限原则&#xff09;。采用委任式存取控制&#xff0c;是在进行程序、文件等细节权…

如何在Flutter应用中配置ipa Guard进行混淆

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

EDM营销:常见的邮件模板制作方法

在EDM邮件营销中&#xff0c;邮件模板的制作是一个关键步骤&#xff0c;邮件模板的质量直接影响到邮件的打开率、阅读率和转化率。邮件内容可能是简单的文字&#xff0c;只需要进行基本的排版&#xff1b;而有些则涉及文字、图片以及超链接等多种元素&#xff0c;这就需要借助工…

spring02:DI(依赖注入)

spring02&#xff1a;DI&#xff08;依赖注入&#xff09; 文章目录 spring02&#xff1a;DI&#xff08;依赖注入&#xff09;前言&#xff1a;一、构造器注入二、set注入&#xff1a;1. Student类&#xff1a;2. Address类&#xff1a;3. beans.xml&#xff1a;4. MyTest&…

想拥有健康体魄?学会中医气血调理秘籍!

《素问调经论》所述&#xff0c;人的生理机能主要依赖于血与气。这两者构成了我们身体生命的基石&#xff0c;其他所有生理活动都是围绕这一核心进行的。因此&#xff0c;各种健康问题&#xff0c;其根源往往可以追溯到气血的失调。 气虚会表现为畏寒怕冷&#xff0c;头晕耳鸣、…

反射(Reflection) --Java学习笔记

反射 反射就是:加载类&#xff0c;并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等) 反射学什么? 学习获取类的信息、操作它们 反射第一步:加载类&#xff0c;获取类的字节码:Class对象获取类的构造器:Constructor对象获取类的成员变量:Field对象获取类的成…