Bert のパワーのおかげで、そのテキスト分類は非常に良い結果を達成しました. 敵対的トレーニングを通じてモデルの堅牢性を向上させることは、非常に意味のある研究方向です. 以下では、実際のコード戦闘を通じて説明します. Bert テキスト分類フィールドにおける敵対的トレーニングアプリケーション。
目次
1. Bert テキスト分類により input_ids に妨害が加えられる
3. Bert はテキスト分類を実装し、FGSM を使用して埋め込みに妨害を加えます。
4. Bert テキスト分類は埋め込みに摂動を追加し、サンプルに対する防御を考慮します
1. Bert テキスト分類により input_ids に妨害が加えられる
Python は、BERT テキスト分類に基づいて敵対的学習を実装します。PyTorch と Transformers ライブラリを使用して BERT モデルに基づいたテキスト分類を実装し、トレーニング中に敵対的学習を適用してモデルの堅牢性を向上できます。
まず、必要なライブラリをインストールする必要があります。
pip install torch transformers -i https://pypi.tuna.tsinghua.edu.cn/simple
次に、BERT ベースのテキスト分類モデルを実装するコードを作成しましょう。
import torch
import torch.nn as nn
from transformers import BertModel, BertTokenizer
class BertForTextClassification(nn.Module):
def __init__(self, bert_model_path, num_classes):
super().__init__()
self.bert_model = BertModel.from_pretrained(bert_model_path)
self.dropout = nn.Dropout(0.1)
self.classifier = nn.Linear(self.bert_model.config.hidden_size, num_classes)
def forward(self, input_ids, attention_mask):
outputs = self.bert_model(input_ids, attention_mask=attention_mask)
pooled_output = outputs[1]
pooled_output = self.dropout(pooled_output)
logits = self.classifier(pooled_output)
return logits
このモデルは、事前トレーニングされた BERT モデルを特徴抽出器として使用し、分類用の線形レイヤーを追加します。オーバーフィッティングを減らすためにドロップアウトも使用します。
次に、トレーニング関数と評価関数を定義する必要があります。
def train(model, train_dataloader, optimizer, criterion, epsilon):
model.train()
total_loss, total_correct = 0., 0.
for batch in train_dataloader:
batch = tuple(t.to(device) for t in batch)
input_ids, attention_mask, labels = batch
# adversarial training
if epsilon:
delta = torch.zeros_like(input_ids).uniform_(-epsilon, epsilon)
delta = delta.to(device)
output = model(input_ids + delta, attention_mask=attention_mask)
else:
output = model(input_ids, attention_mask=attention_mask)
loss = criterion(output, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
_, predicted = torch.max(output.data, 1)
total_correct += (predicted == labels).sum().item()
return total_loss / len(train_dataloader), total_correct / len(train_dataloader.dataset)
def evaluate(model, test_dataloader):
model.eval()
total_loss, total_correct = 0., 0.
with torch.no_grad():
for batch in test_dataloader:
batch = tuple(t.to(device) for t in batch)
input_ids, attention_mask, labels = batch
output = model(input_ids, attention_mask=attention_mask)
loss = criterion(output, labels)
total_loss += loss.item()
_, predicted = torch.max(output.data, 1)
total_correct += (predicted == labels).sum().item()
return total_loss / len(test_dataloader), total_correct / len(test_dataloader.dataset)
上記の関数の 関数はtrain
、モデルをトレーニングし、敵対的トレーニングをサポートするために使用されます。epsilon
パラメータは、敵対的な例のサイズを制御します。0 の場合はepsilon
標準のトレーニング方法が使用され、epsilon
0 より大きい場合は、敵対的なサンプルを取得するために各サンプルに小さな摂動が追加されます。evaluate
テストデータに対するモデルのパフォーマンスを評価する関数。
最後に、データセットをロードしてモデルのトレーニングを開始する main 関数を作成できます。
def load_data():
# your code to load dataset here
pass
if __name__ == '__main__':
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
bert_model_path = 'bert-base-uncased'
num_classes = 2
epsilon = 0.0 # set to non-zero value for adversarial training
# load data
train_dataloader, test_dataloader = load_data()
# create model, optimizer, loss function
model = BertForTextClassification(bert_model_path, num_classes)
model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=5e-5)
criterion = nn.CrossEntropyLoss()
# train and evaluate the model
for epoch in range(10):
train_loss, train_acc = train(model, train_dataloader, optimizer, criterion, epsilon=epsilon)
test_loss, test_acc = evaluate(model, test_dataloader)
print(f"Epoch {epoch+1} - Train Loss: {train_loss:.4f} - Train Acc: {train_acc:.4f} - Test Loss: {test_loss:.4f} - Test Acc: {test_acc:.4f}")
必要なデータセットをロードして処理するには、上記のコードの 関数load_data
をユーザーが実装する必要があります。この例では、バイナリ分類タスクを含む、Google ベースの BERT テキスト分類データセットを使用します。
2. Bert テキスト分類により埋め込みに乱れが生じる
Python は、埋め込みに摂動を追加するために、バート テキスト分類に基づいて敵対的学習を実装します。PyTorch と Transformers ライブラリによって実装された例に基づいて、この例では、トレーニングに敵対的サンプルを使用して、モデルの堅牢性を向上させます。
この例では、FGSM を使用して埋め込みベクトルを摂動させ、敵対的なテキスト サンプルを生成します。FGSM はシンプルだが効果的な敵対的攻撃手法であり、その基本的な考え方は、勾配計算を使用してモデルに摂動を与え、誤った予測結果を生成できるようにすることです。
サンプルコードは次のとおりです。
import torch
import torch.nn.functional as F
from transformers import BertForSequenceClassification, BertTokenizer
# 加载BERT模型和Tokenizer
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# 定义对抗性扰动函数
def fgsm_attack(embeddings, gradient, epsilon):
# 计算扰动的符号
sign_gradient = gradient.sign()
# 计算embedding的对抗性扰动
perturbed_embeddings = embeddings + epsilon*sign_gradient
# 将扰动后的embedding截断在[-1, 1]之间
perturbed_embeddings = torch.clamp(perturbed_embeddings, min=-1, max=1)
return perturbed_embeddings
# 训练模型
def train(model, optimizer, train_loader, epsilon):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
data = data.to(device)
target = target.to(device)
# 对输入的embedding添加对抗性扰动
embeddings = model.bert.embeddings.word_embeddings(data)
embeddings.requires_grad = True
output = model(inputs_embeds=embeddings, attention_mask=(data>0).to(data.device))
loss = F.cross_entropy(output.logits, target)
loss.backward()
# 生成对抗性样本
gradient = embeddings.grad.data
perturbed_embeddings = fgsm_attack(embeddings.data, gradient, epsilon)
# 重新计算模型输出
adv_logits = model(inputs_embeds=perturbed_embeddings, attention_mask=(data>0).to(data.device)).logits
# 计算对抗性训练损失
adv_loss = F.cross_entropy(adv_logits, target)
total_loss = loss + adv_loss
total_loss.backward()
optimizer.step()
# 测试模型
def test(model, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data = data.to(device)
target = target.to(device)
output = model(data, attention_mask=(data>0).to(data.device))
test_loss += F.cross_entropy(output.logits, target, reduction='sum').item()
pred = output.logits.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
print('Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)'.format(
test_loss, correct, len(test_loader.dataset), accuracy))
# 加载数据
def load_data():
# 加载数据集
# TODO: 根据您的数据集实现此函数
pass
# 定义超参数
batch_size = 32
learning_rate = 5e-5
epochs = 10
epsilon = 0.1
# 加载数据
train_loader, test_loader = load_data()
# 将模型和数据加载到GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
# 定义优化器
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 训练模型
for epoch in range(epochs):
print("Epoch:", epoch+1)
train(model, optimizer, train_loader, epsilon)
test(model, test_loader)
load_data
独自のデータセットを実装し、必要に応じてハイパーパラメータを調整するには、置換 関数が必要です。また、このコードを使用するには、PyTorch および Transformers (Hugging Face チームの自然言語処理ライブラリ) ライブラリを使用する必要があります。
3. Bert はテキスト分類を実装し、FGSM を使用して埋め込みに妨害を加えます。
Python は、中国語テキスト分類の精度を向上させるために埋め込みに追加された摂動を使用するバート中国語テキスト分類に基づいた敵対的学習を実装します。
PyTorch の事前トレーニング済み Bert モデルを使用した中国語テキスト分類と、モデルの堅牢性を向上させるための敵対的な例によるトレーニング。
敵対的学習は主に次の 3 つのステップに分かれます。
- 敵対的サンプルの生成: FGSM アルゴリズムを使用してテキストの埋め込みを撹乱し、敵対的テキスト サンプルを生成します。
- 敵対的損失を計算する: 敵対的サンプルと通常のサンプルを使用して、損失関数を分類および計算します。
- モデル パラメーターの更新: 敵対的サンプルと通常のサンプルの損失値に応じてモデル パラメーターを更新します。
load_data
以下は完全な実装コードです。独自のデータセットに従って関数内のコードを変更するだけで済みます 。
import torch
import torch.nn as nn
from transformers import BertTokenizer, BertModel
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 加载预训练Bert模型和tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertModel.from_pretrained('bert-base-chinese').to(device)
# 分类模型
class BertClassifier(nn.Module):
def __init__(self, num_classes):
super(BertClassifier, self).__init__()
self.bert = BertModel.from_pretrained('bert-base-chinese')
self.fc = nn.Linear(768, num_classes)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
pooled_output = outputs[1]
out = self.fc(pooled_output)
return out
# 定义对抗扰动攻击函数
def fgsm_attack(embeds, grad, epsilon=0.3):
sign_grad = grad.sign()
perturb = epsilon * sign_grad
perturb_embeds = embeds + perturb
return perturb_embeds
# 加载数据集
def load_data(file_path):
# 在此处实现加载数据集的代码
return train_data, valid_data, test_data
# 训练模型
def train_model(model, criterion, optimizer, scheduler, train_data, valid_data, num_epochs=10):
best_acc = 0.0
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
correct = 0
total = 0
for data in train_data:
texts, labels = data.text, data.label
input_ids = []
attention_masks = []
for text in texts:
encoded_dict = tokenizer.encode_plus(
text, # 文本数据
add_special_tokens = True, # 添加 '[CLS]' 和 '[SEP]'
max_length = 128, # 设置最大长度
pad_to_max_length = True, # 使用padding
return_attention_mask = True, # 返回attention mask
return_tensors = 'pt', # 返回PyTorch张量格式的输出
)
input_ids.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])
# 将列表转换为张量形式
input_ids = torch.cat(input_ids, dim=0).to(device)
attention_masks = torch.cat(attention_masks, dim=0).to(device)
labels = labels.to(device)
optimizer.zero_grad()
# 对抗性样本训练
input_ids.requires_grad_()
attention_masks.requires_grad_()
output = model(input_ids, attention_masks)
loss = criterion(output, labels)
loss.backward()
grad = input_ids.grad.data
perturb_input_ids = fgsm_attack(input_ids, grad, epsilon=0.3)
perturb_output = model(perturb_input_ids, attention_masks)
perturb_loss = criterion(perturb_output, labels)
adv_loss = 0.5 * loss + 0.5 * perturb_loss
_, predicted = torch.max(output.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
adv_loss.backward()
optimizer.step()
running_loss += adv_loss.item()
scheduler.step()
# 在验证集上计算准确率
model.eval()
valid_loss = 0.0
valid_correct = 0
valid_total = 0
with torch.no_grad():
for data in valid_data:
texts, labels = data.text, data.label
input_ids = []
attention_masks = []
for text in texts:
encoded_dict = tokenizer.encode_plus(
text, # 文本数据
add_special_tokens = True, # 添加 '[CLS]' 和 '[SEP]'
max_length = 128, # 设置最大长度
pad_to_max_length = True, # 使用padding
return_attention_mask = True, # 返回attention mask
return_tensors = 'pt', # 返回PyTorch张量格式的输出
)
input_ids.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])
# 将列表转换为张量形式
input_ids = torch.cat(input_ids, dim=0).to(device)
attention_masks = torch.cat(attention_masks, dim=0).to(device)
labels = labels.to(device)
output = model(input_ids, attention_masks)
loss = criterion(output, labels)
valid_loss += loss.item()
_, predicted = torch.max(output.data, 1)
valid_total += labels.size(0)
valid_correct += (predicted == labels).sum().item()
epoch_loss = running_loss / len(train_data)
epoch_acc = correct / total
valid_loss = valid_loss / len(valid_data)
valid_acc = valid_correct / valid_total
print('Epoch [{}/{}], train_loss: {:.4f}, train_acc: {:.4f}, valid_loss: {:.4f}, valid_acc: {:.4f}'.format(epoch+1, num_epochs, epoch_loss, epoch_acc, valid_loss, valid_acc))
if valid_acc > best_acc:
best_acc = valid_acc
return model
# 加载数据
train_data, valid_data, test_data = load_data('./data/train.csv')
# 设置超参数
num_classes = 2
learning_rate = 2e-5
num_epochs = 10
batch_size = 32
# 构造Bert分类器模型
classifier = BertClassifier(num_classes).to(device)
# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(params=classifier.parameters(), lr=learning_rate)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=2, gamma=0.1)
# 训练模型
trained_model = train_model(classifier, criterion, optimizer, scheduler, train_data, valid_data, num_epochs=num_epochs)
# 在测试集上进行测试
test_loss = 0.0
test_correct = 0
test_total = 0
with torch.no_grad():
for data in test_data:
texts, labels = data.text, data.label
input_ids = []
attention_masks = []
for text in texts:
encoded_dict = tokenizer.encode_plus(
text, # 文本数据
add_special_tokens = True, # 添加 '[CLS]' 和 '[SEP]'
max_length = 128, # 设置最大长度
pad_to_max_length = True, # 使用padding
return_attention_mask = True, # 返回attention mask
return_tensors = 'pt', # 返回PyTorch张量格式的输出
)
input_ids.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])
# 将列表转换为张量形式
input_ids = torch.cat(input_ids, dim=0).to(device)
attention_masks = torch.cat(attention_masks, dim=0).to(device)
labels = labels.to(device)
output = trained_model(input_ids, attention_masks)
loss = criterion(output, labels)
test_loss += loss.item()
_, predicted = torch.max(output.data, 1)
test_total += labels.size(0)
test_correct += (predicted == labels).sum().item()
test_loss = test_loss / len(test_data)
test_acc = test_correct / test_total
print('Test_loss: {:.4f}, Test_acc: {:.4f}'.format(test_loss, test_acc))
この例では、通常のサンプルに対する攻撃のみを考慮していることに注意してください。実際のアプリケーションでは、敵対的な例に対する防御も考慮する必要があります。敵対的防御方法について詳しく知りたい場合は、敵対的防御 GitHub - Trusted-AI/adversarial-robustness-toolbox: Adversarial Robustness Toolbox (ART) - 機械学習セキュリティのための Python ライブラリ - 回避、ポイズニング、抽出、推論 - を確認してください。赤チームと青チーム
4. Bert テキスト分類は埋め込みに摂動を追加し、サンプルに対する防御を考慮します
Python は、埋め込みに摂動を追加し、中国語テキスト分類の精度を向上させ、敵対的サンプルの防御を考慮するバート中国語テキスト分類に基づいた敵対的学習を実装します。
import random
import jieba
import torch
import torch.nn as nn
from transformers import BertTokenizer, BertModel
from torch.utils.data import Dataset, DataLoader
from torch.optim import Adam
from torch.nn.utils.rnn import pad_sequence
from torch.utils.tensorboard import SummaryWriter
# 设定随机种子
random.seed(42)
torch.manual_seed(42)
# BERT模型和tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
bert_model = BertModel.from_pretrained('bert-base-chinese')
# 自定义的中文文本分类器
class TextClassifier(nn.Module):
def __init__(self, bert_model, num_classes):
super(TextClassifier, self).__init__()
self.bert = bert_model
self.fc = nn.Linear(768, num_classes)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
pooled_output = outputs[1]
logits = self.fc(pooled_output)
return logits
# 加载数据集函数
def load_data(file_path):
data = []
with open(file_path, encoding='utf-8') as f:
for line in f:
text, label = line.strip().split('\t')
label = int(label)
seg_list = jieba.cut(text)
text = ' '.join(seg_list)
data.append((text, label))
return data
# 构建dataset和dataloader
class TextDataset(Dataset):
def __init__(self, data, tokenizer):
self.sentences = [item[0] for item in data]
self.labels = [item[1] for item in data]
self.tokenizer = tokenizer
def __len__(self):
return len(self.sentences)
def __getitem__(self, index):
sentence = self.sentences[index]
label = self.labels[index]
encoded_dict = self.tokenizer.encode_plus(
sentence, # 输入文本
add_special_tokens = True, # 添加 '[CLS]' 和 '[SEP]'
max_length = 32, # 填充 & 截断长度
pad_to_max_length = True,
return_attention_mask = True, # 返回 attention mask
return_tensors = 'pt', # 返回 pytorch tensor
)
input_ids = encoded_dict['input_ids'][0]
attention_mask = encoded_dict['attention_mask'][0]
return input_ids, attention_mask, label
def collate_fn(batch):
# 按输入文本长度排序,pad_sequence所需要的batch需要排序后的
batch.sort(key=lambda x: len(x[0]), reverse=True)
input_ids, attention_masks, labels = zip(*batch)
input_ids = pad_sequence(input_ids, batch_first=True)
attention_masks = pad_sequence(attention_masks, batch_first=True)
return input_ids, attention_masks, torch.tensor(labels)
def train(model, train_loader, optimizer, criterion, num_epochs):
writer = SummaryWriter()
global_step = 0
for epoch in range(num_epochs):
total_loss = 0
for i, (input_ids, attention_mask, labels) in enumerate(train_loader):
print(input_ids.shape)
optimizer.zero_grad()
logits = model(input_ids, attention_mask)
loss = criterion(logits, labels)
total_loss += loss.item()
loss.backward()
# 对embedding向量进行扰动
epsilon = 0.5
step_size = 0.05
perturbation = torch.zeros_like(input_ids).uniform_(-epsilon, epsilon)
perturbation.requires_grad_()
logits_perturbed = model(input_ids+perturbation, attention_mask)
loss_perturbed = criterion(logits_perturbed, labels)
loss_perturbed.backward()
perturbation = step_size * perturbation.grad
with torch.no_grad():
input_ids = input_ids+perturbation
input_ids.clamp_(0, tokenizer.vocab_size-1)
optimizer.step()
global_step += 1
if global_step % 10 == 0:
writer.add_scalar('training_loss', loss.item(), global_step)
avg_loss = total_loss / len(train_loader)
print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch + 1, num_epochs, avg_loss))
writer.close()
def test(model, test_loader):
total = 0
correct = 0
with torch.no_grad():
for input_ids, attention_mask, labels in test_loader:
logits = model(input_ids, attention_mask)
predicted = torch.argmax(logits, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = correct / total
print('Accuracy on test set: {:.4f}'.format(accuracy))
def main():
train_data = load_data('train.txt')
test_data = load_data('test.txt')
train_dataset = TextDataset(train_data, tokenizer)
test_dataset = TextDataset(test_data, tokenizer)
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True, collate_fn=collate_fn)
test_loader = DataLoader(test_dataset, batch_size=128, shuffle=False, collate_fn=collate_fn)
num_classes = 10
model = TextClassifier(bert_model, num_classes)
optimizer = Adam(model.parameters(), lr=2e-5)
criterion = nn.CrossEntropyLoss()
num_epochs = 3
train(model, train_loader, optimizer, criterion, num_epochs)
test(model, test_loader)
if __name__ == '__main__':
main()
この例では、敵対的摂動を追加するために FGSM メソッドが使用されています。トレーニング プロセス中、各バッチの各サンプルで、埋め込みベクトルを変更しないままにする摂動を作成するために使用します。次のステップで勾配が更新されるときは、逆にしますperturbation.requires_grad_()
。伝播では、モデルの損失だけでなく摂動の損失も考慮され、次にperturbation = step_size * perturbation.grad
更新摂動が利用され、最後に、input_ids.clamp_(0, tokenizer.vocab_size-1)
生成された敵対的な例がまだ有効なテキスト入力データであるという保証が使用されます。敵対的な例の防御に関しては、一般的な防御手法にはモデル融合、データ増幅、その他の手法が含まれます。
5. 敵対的なサンプルから防御する方法
敵対的な例から防御する方法は数多くありますが、一般的に使用されるいくつかの方法を次に示します。
敵対的トレーニング: 敵対的トレーニングは、トレーニング プロセス中にトレーニング データに敵対的サンプルを追加することでモデルの堅牢性を強化します。具体的には、敵対的トレーニングには、敵対的サンプルの生成と、トレーニング用の敵対的サンプルの使用という 2 つのステップが含まれます。敵対的な例を生成するときは、FGSM や PGD などの方法を使用できます。敵対的な例を使用してトレーニングする場合、敵対的な例と元の例を混合し、混合した例を使用してモデルをトレーニングします。これにより、敵対的な例からの攻撃に対してモデルをより堅牢にすることができます。
モデル圧縮: モデル圧縮は、モデルの複雑さを軽減することでモデルの堅牢性を強化します。具体的には、モデル圧縮は、モデル プルーニングと量子化という 2 つのステップで構成されます。モデルを枝刈りするとき、いくつかの冗長なニューロンまたはレイヤーを削除することで、モデルの複雑さを軽減できます。量子化するときに、モデル内の浮動小数点パラメータを整数パラメータに変換できるため、モデルの記憶領域と計算の複雑さが軽減されます。これにより、モデルがよりシンプルになり、敵対的な例からの攻撃に耐えられるようになります。
ランダム化防御: ランダム化防御は、モデルにランダム性を導入することでモデルの堅牢性を強化することです。具体的には、ランダム化防御は、入力ランダム化とモデルランダム化の 2 つのステップで構成されます。入力のランダム化では、ノイズ、摂動、回転などを追加するなど、入力データに対してランダム化を行うことができます。モデルをランダム化する場合、畳み込み層でのランダム畳み込みカーネルの使用、全結合層でのランダム接続などを使用するなど、モデルにランダム性を導入できます。これにより、モデルの攻撃がより困難になり、敵対的な例の攻撃に抵抗できるようになります。
モデル アンサンブル: モデル アンサンブルは、複数のモデルを組み合わせることでモデルの堅牢性を強化します。具体的には、モデル アンサンブルは、複数のモデルのトレーニングと複数のモデルの結合の 2 つのステップで構成されます。複数のモデルをトレーニングする場合、異なる初期化、異なるハイパーパラメーター、または異なるトレーニング データを使用して複数のモデルをトレーニングできます。複数のモデルを組み合わせる場合は、投票、加重平均、モデル融合などの方法を使用して複数のモデルを組み合わせることができます。これにより、敵対的な例からの攻撃に対してモデルがより堅牢になります。
これらの方法を使用すると、敵対的なサンプルを防御し、モデルの全体的なパフォーマンスを向上させることができます。ただし、各方法には長所と短所があり、特定の選択は、特定のアプリケーション シナリオと要件に従って比較検討する必要があることに注意してください。