Coggle の 30 日間の ML チェックイン タスク 2: リンゴ病データの読み込みとデータ拡張
タスク 2: リンゴ病データの読み込みとデータ拡張
- 難易度/スコア: 中/2
パンチ内容:
- 出場者名:アップルドクター
- 竣工日:2023.6.9
- タスクの完了ステータス:
- 使用プログラミング言語:Python、Pytorch
- 実装された機能:
- OpenCV または PIL を使用してデータセットをロードする
- torchvision または OpenCV を使用した画像分類タスクのデータ拡張
背景紹介
このチェックイン タスクは、Coggle 30 日間の ML の 2 番目のタスクであり、リンゴ病データの読み込みとデータ拡張を完了する必要があります。データ読み込みフェーズでは、出場者は提供された画像データを読み取って処理するコードを記述する必要があります。データ強化ステージでは、出場者は回転、スケーリング、反転、明るさ調整などのさまざまな画像処理技術や方法を使用して、データセットの多様性と量を強化できます。
ミッション名 | 難易度・スコア |
---|---|
タスク 1: 2 つのコンテストの質問のデータ視覚化 | 低い/1 |
タスク 2: リンゴ病データの読み込みとデータ拡張 | 中/2 |
タスク 3: リンゴ病モデルのトレーニングと予測 | 中/2 |
タスク 4: リンゴ病モデルの最適化と多重トレーニング | 高/3 |
タスク 5: 建物検出データのロードとデータ拡張 | 高/2 |
タスク 6: 建物検出モデルのトレーニングと予測 | 中/2 |
タスク 7: 建物検出モデルの最適化とマルチフォールド トレーニング | 高/3 |
データセットの準備
まずサインアップしてデータセットをダウンロードします。練習試合のアドレスは次のとおりです。
カスタムデータセット
まず、PyTorch を例として使用すると、カスタム データセットが必要になります。これを行うために、 という名前のクラスを定義しますAppleDataset
。
# 定义Apple数据集的类
class AppleDataset(Dataset):
def __init__(self, img_path, transform=None):
"""
构造函数,初始化数据集的路径和数据增强操作
Args:
- img_path: list类型,存储数据集中图像的路径
- transform: torchvision.transforms类型,数据增强操作
"""
self.img_path = img_path
self.transform = transform
def __getitem__(self, index):
"""
获取一个样本
Args:
- index: 数据集中的索引
Returns:
- img: Tensor类型,经过处理后的图像
- label: Tensor类型,标签
"""
img = Image.open(self.img_path[index])
if self.transform is not None:
img = self.transform(img)
# 将类别名转换为数字标签
class_name = self.img_path[index].split('/')[-2]
if class_name in ['d1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9']:
label = ['d1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9'].index(class_name)
else:
label = -1
return img, torch.from_numpy(np.array(label))
def __len__(self):
"""
获取数据集的大小
Returns:
- size: int类型,数据集的大小
"""
return len(self.img_path)
次に、このカスタム データセット クラスを使用してデータをロードできます。
np.random.shuffle(train_path)
train_data = AppleDataset(train_path,)
valid_data = AppleDataset(val_path,)
print("类别: {}".format(classes_name))
print("训练集: {}".format(len(train_data)))
トレーニング セットには約 10,000 枚の写真があることがわかります。この情報は最初のチェックインで言及されています。
类别: ['d1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9']
训练集: 10211
データの拡張と視覚化
次に、データの拡張と視覚化を実行しましょう。
import matplotlib.pyplot as plt
import torchvision.transforms.functional as TF
# 定义一系列的图像增强操作
transformations = [
transforms.Resize((224, 224)), # 将图像大小调整为224*224
transforms.RandomHorizontalFlip(), # 以0.5的概率对图像进行水平翻转
transforms.RandomVerticalFlip(), # 以0.5的概率对图像进行垂直翻转
transforms.GaussianBlur(kernel_size=3), # 对图像进行高斯模糊,卷积核大小为3
transforms.ColorJitter(brightness=0.9), # 调整图像的亮度,亮度因子的范围为[0.1, 1.9]
transforms.ColorJitter(contrast=0.9), # 调整图像的对比度,对比度因子的范围为[0.1, 1.9]
transforms.ColorJitter(saturation=0.9), # 调整图像的饱和度,饱和度因子的范围为[0.1, 1.9]
]
# 定义每个转换操作的标题
transformations_title = ['Resize',
'RandomHorizontalFlip',
'RandomVerticalFlip',
'RandomGaussianBlur',
'ColorJitter(brightness)',
'ColorJitter(contrast)',
'ColorJitter(saturation)',
]
num_images = 5
# 可视化训练集的图像转换结果
fig, axes = plt.subplots(nrows=1, ncols=num_images, figsize=(12, 2))
# 显示原始图像
for i in range(num_images):
img, label = train_data[i]
ax = axes[i]
ax.imshow(img)
ax.set_title(f"Original d{
label+1}")
ax.axis('off')
plt.show()
# 显示每个转换操作的结果
for i, transform in enumerate(transformations):
# 可视化训练集的图像转换结果
fig, axes = plt.subplots(nrows=1, ncols=num_images, figsize=(12, 2))
for j in range(num_images):
img, label = train_data[j]
ax = axes[j]
transformed_img = transform(img)
ax.imshow(transformed_img)
ax.set_title(f"{
transformations_title[i]}")
ax.axis('off')
plt.tight_layout()
plt.show()
上記のコードを通じて、一連のデータ拡張操作を定義し、視覚化しました。さまざまなデータ拡張操作の下で、イメージが変化したことがわかります。
コードでは、次のデータ拡張操作を使用しました。
- 画像のサイズ変更: 画像のサイズを 224x224 ピクセルに変更する
transforms.Resize((224, 224))
ために。 - ランダム水平反転: 0.5 の確率
transforms.RandomHorizontalFlip()
で。 - ランダム垂直反転: 0.5 の確率
transforms.RandomVerticalFlip()
で。 - ガウスぼかし: 画像
transforms.GaussianBlur(kernel_size=3)
に。コンボリューション カーネル サイズは 3 です。 - 明るさの調整: 画像の明るさを
transforms.ColorJitter(brightness=0.9)
調整する。明るさ係数の範囲は [0.1、1.9] です。 - コントラストの調整: 画像のコントラスト
transforms.ColorJitter(contrast=0.9)
を調整する。コントラスト係数の範囲は [0.1、1.9] です。 - 彩度の調整: 画像の彩度
transforms.ColorJitter(saturation=0.9)
を調整する。彩度係数の範囲は [0.1、1.9] です。
以上の操作により、データ補正を行う際に画像に様々な変化を与えることができます。
データのロード + データの拡張
データ拡張操作をデータセットに適用するコードは次のとおりです。
# 定义图像预处理的参数
image_mean = [0.4940, 0.4187, 0.3855]
image_std = [0.2048, 0.1941, 0.1932]
# 定义训练集的数据增强操作
transform_train = transforms.Compose([
transforms.Resize((224,224)), # 将图像大小调整为224*224
transforms.RandomHorizontalFlip(), # 以0.5的概率对图像进行水平翻转
transforms.RandomVerticalFlip(), # 以0.5的概率对图像进行垂直翻转
transforms.RandomApply([transforms.GaussianBlur(kernel_size=3)], p=0.1), # 以0.1的概率对图像进行高斯模糊,卷积核大小为3
transforms.RandomApply([transforms.ColorJitter(brightness=0.9)],p=0.5), # 以0.5的概率调整图像的亮度,亮度因子的范围为[0.1, 1.9]
transforms.RandomApply([transforms.ColorJitter(contrast=0.9)],p=0.5), # 以0.5的概率调整图像的对比度,对比度因子的范围为[0.1, 1.9]
transforms.RandomApply([transforms.ColorJitter(saturation=0.9),],p=0.5), # 以0.5的概率调整图像的饱和度,饱和度因子的范围为[0.1, 1.9]
transforms.ToTensor(), # 将图像转换成张量
transforms.Normalize(image_mean, image_std), # 对图像进行标准化处理
])
# 定义验证集的数据预处理操作
transform_valid = transforms.Compose([
transforms.Resize((224,224)), # 将图像大小调整为224*224
transforms.ToTensor(), # 将图像转换成张量
transforms.Normalize(image_mean, image_std), # 对图像进行标准化处理
])
上記のコードでは、トレーニング セットと検証セットのデータ拡張操作を定義します。transform_train
トレーニング セットのデータ拡張操作であり、画像のサイズ変更、水平反転、垂直反転、ガウスぼかし、明るさ調整、コントラスト調整、彩度調整などの操作が含まれます。transform_valid
検証セットのデータ前処理操作であり、画像のサイズ変更が含まれます。
次に、データ拡張操作後のイメージを視覚化できます。
# 可视化训练集
fig, axes = plt.subplots(nrows=2, ncols=5, figsize=(10, 4))
for i in range(10):
img, label = train_data[i]
ax = axes[i // 5, i % 5]
ax.imshow(img.permute(1, 2, 0))
ax.set_title(classes_name[label.item()])
ax.axis('off')
plt.tight_layout()
plt.show()
上記のコードはデータ拡張後のトレーニングセットの画像を表示しますが、標準化するので非常に奇妙に見えます
何が行われたかを確認するには、非正規化を行います。
def denormalize(img, mean, std):
mean = torch.tensor(mean).reshape(3, 1, 1)
std = torch.tensor(std).reshape(3, 1, 1)
return img * std + mean
# 可视化训练集
fig, axes = plt.subplots(nrows=2, ncols=5, figsize=(10, 4))
for i in range(10):
img, label = train_data[i]
ax = axes[i // 5, i % 5]
ax.imshow( denormalize(img, image_mean, image_std).permute(1, 2, 0))
ax.set_title(classes_name[label.item()])
ax.axis('off')
plt.tight_layout()
plt.show()
上記のコードは、非正規化されたトレーニング セットの画像を表示して、どのようなデータ拡張が行われたかを確認します。
混合データの拡張
次に、Mixup データ拡張メソッドを実装します。
まず、ベータ分布を定義するために使用されるパラメータとしてとをMixup
受け入れるクラスを定義します。このクラスには、Mixup 操作を実行するメソッドがあります。画像データとラベルを指定すると、このメソッドはブレンドされた画像、2 つのラベル、およびブレンド係数を返します。alpha
beta
Mixup
__call__
x
y
mixed_image
y1
y2
lambd
# 定义Mixup类
class Mixup:
def __init__(self, alpha=1.5, beta=1.5):
"""
构造函数,初始化Mixup的参数
Args:
- alpha: float类型,beta分布的参数alpha
- beta: float类型,beta分布的参数beta
Returns:
- None
"""
self.alpha = alpha
self.beta = beta
def __call__(self, x, y):
"""
实现Mixup的操作
Args:
- x: Tensor类型,图像数据
- y: Tensor类型,标签
Returns:
- mixed_image: Tensor类型,混合后的图像数据
- y1: Tensor类型,标签1
- y2: Tensor类型,标签2
- lambd: Tensor类型,混合系数
"""
image, label = x, y
batch_size = image.size(0)
# 生成混合系数
lambd = torch.Tensor([random.betavariate(self.alpha, self.beta)]).to(image.device)
# 生成随机索引
index = torch.randperm(batch_size).to(image.device)
# 进行Mixup操作
mixed_image = lambd * image + (1 - lambd) * image[index, :]
# 生成对应的标签
y1, y2 = label, label[index]
return mixed_image, y1, y2, lambd
# 初始化Mixup的参数
mixup = Mixup(alpha=1.5, beta=1.5)
次に、トレーニング セットからデータのバッチを取得し、Mixup データ拡張を適用します。
# 使用PyTorch的DataLoader加载训练集数据
train_loader = torch.utils.data.DataLoader(
train_data, batch_size=8, shuffle=True, num_workers=0, pin_memory = True)
# 获取一个batch的数据
images, labels = next(iter(train_loader))
# 进行数据混合
mixed_image, y1, y2, lambd = mixup(images,labels)
次に、ブレンドされた画像を非正規化し、結果を視覚化します。画像が実際には 2 つの画像をブレンドしたものであることがわかります。
# 反标准化混合图像
denorm_mixed_images = denormalize(mixed_image, image_mean, image_std)
# 创建图像网格
num_images = len(denorm_mixed_images)
fig, axes = plt.subplots(nrows=2, ncols=num_images//2, figsize=(12, 6))
# 显示混合图像
for i, ax in enumerate(axes.flatten()):
mixed_img = TF.to_pil_image(denorm_mixed_images[i])
ax.imshow(mixed_img)
ax.set_title(f"Mixed Image {
i+1}")
ax.axis('off')
plt.tight_layout()
plt.show()
最後に、Mixup データを強化した後は、それに応じて損失関数も調整する必要があることに注意してください。以下は、トレーニング バッチに Mixup を適用する方法を示すサンプル テンプレートです。
# 在每个训练批次中应用Mixup
inputs, labels = data # 获取训练数据及其标签
inputs, labels_a, labels_b, lam = mixup(inputs, labels)
# 将数据和标签输入模型进行训练
outputs = model(inputs)
loss = lam * criterion(outputs, labels_a) + (1 - lam) * criterion(outputs, labels_b)
optimizer.zero_grad()
loss.backward()
optimizer.step()
上記のコードでは、inputs
はトレーニング データ、 はlabels
対応するラベルです。mixup
この関数を呼び出すことで、入力データに対して Mixup 操作を実行して混合入力データを生成し、mixed_inputs
同時に対応するラベルを生成します。トレーニング プロセスでは、混合データと、損失関数を計算します。損失関数は重み付け計算に。このようにして、トレーニング中に Mixup データ拡張を適用し、混合画像のトレーニングに合わせて損失関数を調整できます。labels_a
labels_b
mixed_inputs
lam
ミックスアップ データ拡張の中心となるアイデアは、特定の比率に従って 2 つのサンプルを線形補間し、新しいサンプルを生成し、同じ比率に従って対応するラベルを補間することです。このデータ拡張方法により、モデルの堅牢性と一般化が向上し、過剰適合の防止に役立ちます。