0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【python】PyTorchのCNNで漢字画像を分類!!

Posted at

PyTorchのCNNを使って漢字の画像を分類します。

1.漢字画像を生成する。

kanji.py
from PIL import Image, ImageDraw, ImageFont
import os

# 漢字リスト
kanji_list = ["", "", "", "", ""]  # 必要な漢字をリストに追加
output_dir = "kanji_images"  # 画像を保存するディレクトリ

# フォント設定(フォントパスを適切に設定してください)
font_paths = [
    "C:/Windows/Fonts/msmincho.ttc",  # 明朝体(Windows用)
    "C:/Windows/Fonts/meiryo.ttc"
]

# 画像生成用のパラメータ
image_size = (64, 64)  # 画像サイズ(ピクセル)
font_size = 48  # フォントサイズ

# 出力ディレクトリの作成
os.makedirs(output_dir, exist_ok=True)

for kanji in kanji_list:
    kanji_dir = os.path.join(output_dir, kanji)
    os.makedirs(kanji_dir, exist_ok=True)
    
    for font_path in font_paths:
        try:
            font = ImageFont.truetype(font_path, font_size)
            for i in range(10):  # 同じ漢字を10種類生成
                img = Image.new("L", image_size, color=255)  # グレースケール画像(背景白)
                draw = ImageDraw.Draw(img)
                
                # 漢字を画像の中央に描画
                text_bbox = draw.textbbox((0, 0), kanji, font=font)  # テキストのバウンディングボックスを取得
                text_width = text_bbox[2] - text_bbox[0]
                text_height = text_bbox[3] - text_bbox[1]
                text_position = (
                    (image_size[0] - text_width) // 2,
                    (image_size[1] - text_height) // 2
                )
                draw.text(text_position, kanji, fill=0, font=font)  # 黒で描画
                
                # 画像の保存
                img_path = os.path.join(kanji_dir, f"{kanji}_{i}.png")
                img.save(img_path)
        except Exception as e:
            print(f"フォントの読み込みに失敗しました: {font_path} エラー: {e}")

print(f"漢字画像が生成されました。'{output_dir}'ディレクトリを確認してください。")

2.生成された漢字フォルダを data/train、data/valに振り分けておく。
3.CNNを使って漢字の画像を分類する。

pytorch_cnn.py
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt

# デバイスの設定
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# データ変換
transform = transforms.Compose([
    transforms.Grayscale(num_output_channels=1),  # 1チャネル(グレースケール画像)
    transforms.Resize((64, 64)),                 # 画像サイズを統一
    transforms.ToTensor(),                       # テンソル化
    transforms.Normalize((0.5,), (0.5,))         # 正規化
])

# データセットの読み込み
train_dataset = datasets.ImageFolder(root="data/train", transform=transform)
val_dataset = datasets.ImageFolder(root="data/val", transform=transform)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)

# モデルの定義
class KanjiCNN(nn.Module):
    def __init__(self, num_classes):
        super(KanjiCNN, self).__init__()
        self.conv_layers = nn.Sequential(
            nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),  # 畳み込み層1
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),  # プーリング層1
            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), # 畳み込み層2
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)   # プーリング層2
        )
        self.fc_layers = nn.Sequential(
            nn.Flatten(),
            nn.Linear(64 * 16 * 16, 128),  # 全結合層1
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(128, num_classes)    # 全結合層2
        )

    def forward(self, x):
        x = self.conv_layers(x)
        x = self.fc_layers(x)
        return x

# モデルの初期化
num_classes = len(train_dataset.classes)  # クラス数
model = KanjiCNN(num_classes).to(device)

# 損失関数と最適化アルゴリズム
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 学習関数
def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10):
    for epoch in range(num_epochs):
        model.train()
        train_loss = 0.0
        for images, labels in train_loader:
            images, labels = images.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item()
        
        # 検証
        model.eval()
        val_loss = 0.0
        correct = 0
        total = 0
        with torch.no_grad():
            for images, labels in val_loader:
                images, labels = images.to(device), labels.to(device)
                outputs = model(images)
                loss = criterion(outputs, labels)
                val_loss += loss.item()
                _, predicted = torch.max(outputs, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()

        # 結果の出力
        print(f"Epoch [{epoch+1}/{num_epochs}], "
              f"Train Loss: {train_loss/len(train_loader):.4f}, "
              f"Val Loss: {val_loss/len(val_loader):.4f}, "
              f"Accuracy: {100 * correct / total:.2f}%")

# 学習の実行
train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10)

4.実行結果

Epoch [1/10], Train Loss: 1.8352, Val Loss: 1.1979, Accuracy: 40.00%
Epoch [2/10], Train Loss: 1.4003, Val Loss: 0.9445, Accuracy: 80.00%
Epoch [3/10], Train Loss: 0.9725, Val Loss: 0.5208, Accuracy: 100.00%
Epoch [4/10], Train Loss: 0.5777, Val Loss: 0.1786, Accuracy: 100.00%
Epoch [5/10], Train Loss: 0.2621, Val Loss: 0.0478, Accuracy: 100.00%
Epoch [6/10], Train Loss: 0.1093, Val Loss: 0.0238, Accuracy: 100.00%
Epoch [7/10], Train Loss: 0.0564, Val Loss: 0.0038, Accuracy: 100.00%
Epoch [8/10], Train Loss: 0.0512, Val Loss: 0.0009, Accuracy: 100.00%
Epoch [9/10], Train Loss: 0.0394, Val Loss: 0.0003, Accuracy: 100.00%
Epoch [10/10], Train Loss: 0.0143, Val Loss: 0.0005, Accuracy: 100.00%
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?