PyTorchプロジェクトの応用例(三)共通の画像分類モデルによる画像分類(コードと操作方法付)
背景:画像データから画像をロードし、ラベルに基づいてトレーニングする必要があります.簡単にフォルダに画像を直接入れてラベルとトレーニングデータを生成し、モデルをトレーニングします.実画像から訓練されたモデルへの転換.
コードアドレス(直接実行可能):githubアドレス:https://github.com/Xingxiangrui/image_classification_with_pytorch
copy 4のコードを直接使用することもできます.
目次
一、小サンプルの運行とデバッグ
1.1データセット
1.2ラベル形式
1.3最小データセット運転
1.4可能性のあるエラーおよび解決策(見ざるを得ないものはない)
二、大サンプル量データセットの生成
2.1画像フォーマット
2.2ラベル形式
2.3バッチ生成データとラベル
画像名読み出し
シーヶンス乱れ
リストを2つのリストに分割
画像の読み出しと書き込み
ラベルの生成
三、訓練と検証
3.1データのロード
3.2データロード関数
3.3モデルトレーニングと検証
3.4モデルのトレーニングと保存
四、コード
一、小サンプルの運行とデバッグ
まず小サンプルでプログラムを実行し、プログラムが正しく実行されることを保証し、大サンプルで実験する.コードは最後を参照してください.
1.1データセット
コードにデータセットをロードする方法は次のとおりです.
1.2ラベル形式
場所data/Txtfile/フォルダの下
2つのファイルtxtとval.txt
フォルダ内の各行は、*****121のようなファイルのパスである.jpg(真ん中がtabキー)0(ラベル)
すなわち、画像名tabキーラベル
注意ラベルは0から、ラベルは1からしないでください.そうしないと、エラーが発生します.
1.3最小データセット運転
直接dataフォルダに2つのファイルを入れます.jpg ,2.jpg
サブフォルダdata/Txtfileの2つのファイルtrain.txt, val.txt
どちらのファイルも
直接実行、ルートディレクトリ、python customData_train.py、正常に動作します.
1.4可能性のあるエラーおよび解決策(見ざるを得ないものはない)
pythonおよびtorchバージョンの問題によるエラー:
解決:2つの関数の名前を直接推奨される名前に置き換えます.
解決:ラベルは0から、1からではなく、踊らないほうがいいです.
解決:プログラム内の文を変更する
#原文:train_loss+=loss.data[0]#修正後:train_loss+=loss.item()
二、大サンプル量データセットの生成
2.1画像フォーマット
フォルダ名data/画像の保存
Data/TxtFileはtrainを保存する.txtとval.txt
2.2ラベル形式
train.txtにはトレーニングセットのピクチャ名とラベルが格納され、val.txtには検証セットの名前とラベルが格納されます.
ファイルのフォーマットは行ごとにデータ、ファイル名です.jpg(tabキー)ラベル番号
例:
2.3バッチ生成データとラベル
大量のデータはpython実操(二)を参照してデータセットを作成することができる:label変更とバッチ化ピクチャ処理
画像名読み出し
注意、rangeは1から始まるので、後ろは-1にします.
シーヶンス乱れ
参照先:https://blog.csdn.net/amy_wumanfang/article/details/64483340
https://blog.csdn.net/matrix_google/article/details/72803741
直接
例:
リストを2つのリストに分割
トレーニングセットと検証セットに分解し、それぞれ1/4と3/4
画像の読み出しと書き込み
画像はsrc_に保存されますimgでは、画像の名前を変更してsaveで書き込みます.
ラベルの生成
作成ファイル:aは追加書き込みを示します
各行に「」を付ける必要がある
三、訓練と検証
3.1データのロード
txtファイルの各行に直接基づいてデータとラベルをロードし、トレーニングを行うことができます.
3.2データロード関数
データによる関数のロード
3.3モデルトレーニングと検証
lossの定義
3.4モデルのトレーニングと保存
四、コード
githubアドレス:https://github.com/Xingxiangrui/image_classification_with_pytorch
コードアドレス(直接実行可能):githubアドレス:https://github.com/Xingxiangrui/image_classification_with_pytorch
copy 4のコードを直接使用することもできます.
目次
一、小サンプルの運行とデバッグ
1.1データセット
1.2ラベル形式
1.3最小データセット運転
1.4可能性のあるエラーおよび解決策(見ざるを得ないものはない)
二、大サンプル量データセットの生成
2.1画像フォーマット
2.2ラベル形式
2.3バッチ生成データとラベル
画像名読み出し
シーヶンス乱れ
リストを2つのリストに分割
画像の読み出しと書き込み
ラベルの生成
三、訓練と検証
3.1データのロード
3.2データロード関数
3.3モデルトレーニングと検証
3.4モデルのトレーニングと保存
四、コード
一、小サンプルの運行とデバッグ
まず小サンプルでプログラムを実行し、プログラムが正しく実行されることを保証し、大サンプルで実験する.コードは最後を参照してください.
1.1データセット
コードにデータセットをロードする方法は次のとおりです.
print("Load dataset......")
image_datasets = {x: customData(img_path='data/',
txt_path=('data/TxtFile/' + x + '.txt'),
data_transforms=data_transforms,
dataset=x) for x in ['train', 'val']}
1.2ラベル形式
場所data/Txtfile/フォルダの下
2つのファイルtxtとval.txt
フォルダ内の各行は、*****121のようなファイルのパスである.jpg(真ん中がtabキー)0(ラベル)
すなわち、画像名tabキーラベル
注意ラベルは0から、ラベルは1からしないでください.そうしないと、エラーが発生します.
1.3最小データセット運転
直接dataフォルダに2つのファイルを入れます.jpg ,2.jpg
サブフォルダdata/Txtfileの2つのファイルtrain.txt, val.txt
どちらのファイルも
1.jpg 0
2.jpg 1
直接実行、ルートディレクトリ、python customData_train.py、正常に動作します.
1.4可能性のあるエラーおよび解決策(見ざるを得ないものはない)
pythonおよびtorchバージョンの問題によるエラー:
/home/xingxiangrui/env/lib/python3.6/site-packages/torchvision/transforms/transforms.py:563: UserWarning: The use of the transforms.RandomSizedCrop transform is deprecated, please use transforms.RandomResizedCrop instead.
"please use transforms.RandomResizedCrop instead.")
/home/xingxiangrui/env/lib/python3.6/site-packages/torchvision/transforms/transforms.py:188: UserWarning: The use of the transforms.Scale transform is deprecated, please use transforms.Resize instead.
"please use transforms.Resize instead.")
解決:2つの関数の名前を直接推奨される名前に置き換えます.
RuntimeError: cuda runtime error (59) : device-side assert triggered at /home/lychee/mycode/pytorch/aten/src/THC/generic/THCTensorMath.cu:24
解決:ラベルは0から、1からではなく、踊らないほうがいいです.
return loss.data[0]
IndexError: invalid index of a 0-dim tensor. Use tensor.item() to convert a 0-dim tensor to a Python
解決:プログラム内の文を変更する
#原文:train_loss+=loss.data[0]#修正後:train_loss+=loss.item()
二、大サンプル量データセットの生成
2.1画像フォーマット
print("Load dataset......")
image_datasets = {x: customData(img_path='data/',
txt_path=('data/TxtFile/' + x + '.txt'),
data_transforms=data_transforms,
dataset=x) for x in ['train', 'val']}
フォルダ名data/画像の保存
Data/TxtFileはtrainを保存する.txtとval.txt
2.2ラベル形式
train.txtにはトレーニングセットのピクチャ名とラベルが格納され、val.txtには検証セットの名前とラベルが格納されます.
ファイルのフォーマットは行ごとにデータ、ファイル名です.jpg(tabキー)ラベル番号
class customData(Dataset):
def __init__(self, img_path, txt_path, dataset = '', data_transforms=None, loader = default_loader):
with open(txt_path) as input_file:
lines = input_file.readlines()
self.img_name = [os.path.join(img_path, line.strip().split('\t')[0]) for line in lines]
self.img_label = [int(line.strip().split('\t')[-1]) for line in lines]
self.data_transforms = data_transforms
self.dataset = dataset
self.loader = loader
例:
1.jpg 0
2.jpg 1
2.3バッチ生成データとラベル
大量のデータはpython実操(二)を参照してデータセットを作成することができる:label変更とバッチ化ピクチャ処理
画像名読み出し
source_image_list = os.listdir(source_image_dir)
for idx in range(len(source_image_list)):
if '.png' in source_image_list[idx-1]:
continue
elif '.jpg' in source_image_list[idx-1]:
continue
else:
del source_image_list[idx]
注意、rangeは1から始まるので、後ろは-1にします.
シーヶンス乱れ
参照先:https://blog.csdn.net/amy_wumanfang/article/details/64483340
https://blog.csdn.net/matrix_google/article/details/72803741
直接
random.shuffle(list), list
で便利です.例:
# -*- coding: utf-8 -*-
import random
# list , list
list = range(10)
print list
random.shuffle(list)
print " : ", list
リストを2つのリストに分割
トレーニングセットと検証セットに分解し、それぞれ1/4と3/4
# train list and val list
source_train_list=[]
source_val_list=[]
for idx in range(len(source_image_list)):
if idx
画像の読み出しと書き込み
画像はsrc_に保存されますimgでは、画像の名前を変更してsaveで書き込みます.
# read dource images and rename
path_source_img = os.path.join(source_image_dir, source_image_name)
src_img = Image.open(path_source_img)
full_image_name=prefix+"_train_"+source_image_name
print(full_image_name)
# save renamed image to the target dir
target_image_path=os.path.join(target_image_dir, full_image_name)
src_img.save(target_image_path)
ラベルの生成
作成ファイル:aは追加書き込みを示します
# create label_file or write label file
txt_file_train_name="train.txt"
txt_file_val_name="val.txt"
txt_file_train_path=os.path.join(txt_file_dir, txt_file_train_name)
txt_file_val_path=os.path.join(txt_file_dir, txt_file_val_name)
train_txt_file= open(txt_file_train_path,"a")
val_txt_file= open(txt_file_val_path,"a")
各行に「」を付ける必要がある
# write image names and labels
line_strings= full_image_name+"\t"+str(class_label)+"
"
train_txt_file.write(line_strings)
三、訓練と検証
3.1データのロード
txtファイルの各行に直接基づいてデータとラベルをロードし、トレーニングを行うことができます.
data_transforms = {
'train': transforms.Compose([
#transforms.RandomSizedCrop(224),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
#transforms.Scale(256),
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
use_gpu = torch.cuda.is_available()
batch_size = 32
num_class = 3
print("batch size:",batch_size,"num_classes:",num_class)
print("Load dataset......")
# image_datasets = {x: customData(img_path='sin_poly_defect_data/',
# txt_path=('sin_poly_defect_data/TxtFile/general_train.txt'),
# data_transforms=data_transforms,
# dataset=x) for x in ['train', 'total_val']}
image_datasets={}
image_datasets['train'] = customData(img_path='sin_poly_defect_data/',
txt_path=('sin_poly_defect_data/TxtFile/general_train.txt'),
data_transforms=data_transforms,
dataset='train')
image_datasets['val'] = customData(img_path='sin_poly_defect_data/',
txt_path=('sin_poly_defect_data/TxtFile/real_poly_defect.txt'),
data_transforms=data_transforms,
dataset='val')
# train_data=image_datasets.pop('general_train')
# image_datasets['train']=train_data
# val_data=image_datasets.pop('total_val')
# image_datasets['val']=val_data
# wrap your data and label into Tensor
print("wrap data into Tensor......")
dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],
batch_size=batch_size,
shuffle=True) for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
print("total dataset size:",dataset_sizes)
3.2データロード関数
データによる関数のロード
def default_loader(path):
try:
img = Image.open(path)
return img.convert('RGB')
except:
print("Cannot read image: {}".format(path))
# define your Dataset. Assume each line in your .txt file is [name/tab/label], for example:0001.jpg 1
class customData(Dataset):
def __init__(self, img_path, txt_path, dataset = '', data_transforms=None, loader = default_loader):
with open(txt_path) as input_file:
lines = input_file.readlines()
self.img_name = [os.path.join(img_path, line.strip().split('\t')[0]) for line in lines]
self.img_label = [int(line.strip().split('\t')[-1]) for line in lines]
self.data_transforms = data_transforms
self.dataset = dataset
self.loader = loader
def __len__(self):
return len(self.img_name)
def __getitem__(self, item):
img_name = self.img_name[item]
label = self.img_label[item]
img = self.loader(img_name)
if self.data_transforms is not None:
try:
img = self.data_transforms[self.dataset](img)
except:
print("Cannot transform image: {}".format(img_name))
return img, label
3.3モデルトレーニングと検証
lossの定義
print("Define loss function and optimizer......")
# define cost function
criterion = nn.CrossEntropyLoss()
# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.005, momentum=0.9)
# Decay LR by a factor of 0.2 every 5 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=5, gamma=0.2)
# multi-GPU
model_ft = torch.nn.DataParallel(model_ft, device_ids=[0])
3.4モデルのトレーニングと保存
# train model
print("start train_model......")
model_ft = train_model(model=model_ft,
criterion=criterion,
optimizer=optimizer_ft,
scheduler=exp_lr_scheduler,
num_epochs=15,
use_gpu=use_gpu)
# save best model
print("save model......")
torch.save(model_ft,"output/resnet_on_PV_best_total_val.pkl")
四、コード
githubアドレス:https://github.com/Xingxiangrui/image_classification_with_pytorch
# -*- coding: utf-8 -*
"""
Created by Xingxiangrui on 2019.5.9
This code is to :
1. copy image from source_image_dir to the target_image_dir
2. And generate .txt file for further training
in which each line is : image_name.jpg (tab) image_label (from 0)
such as:
image_01.jpg 0
iamge_02.jpg 1
...
image_02.jpg 0
"""
# import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import os
import random
# variables need to be change
source_image_dir="/Users/Desktop/used/SuZhouRuiTu_dataset/single-poly-defect/poly_OK"
target_image_dir="/Users/Desktop/used/SuZhouRuiTu_dataset/data_for_resnet_classification"
txt_file_dir="/Users/Desktop/used/SuZhouRuiTu_dataset/data_for_resnet_classification/TxtFile"
prefix="poly_OK"
class_label=1
# label 0: single_OK ; label_1: poly_OK ; label 2: poly_defect
print("Program Start......")
print("-"*20)
print("-"*20)
print("-"*20)
# load image list in the source dir
source_image_list = os.listdir(source_image_dir)
for idx in range(len(source_image_list)):
if '.png' in source_image_list[idx-1]:
continue
elif '.jpg' in source_image_list[idx-1]:
continue
else:
del source_image_list[idx-1]
# shuffle image list
print("initial list:")
print source_image_list
random.shuffle(source_image_list)
print("shuffled list:")
print source_image_list
# train list and val list
source_train_list=[]
source_val_list=[]
for idx in range(len(source_image_list)):
if idx
# -*- coding: utf-8 -*
"""
created by xingxiangrui on 2019.5.9
This is the pytorch code for iamge classification
python 3.6 and torch 0.4.1 is ok
dataset mode:
folder data in which is jpg images
folder data/TxtFile/ in which is train.txt and val.txt
in train.txt each line :
image_name.jpg (tab) image_label (from 0)
such as:
image_01.jpg 0
iamge_02.jpg 1
...
image_02.jpg 0
"""
from __future__ import print_function, division
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.autograd import Variable
from torchvision import models, transforms
import time
import os
from torch.utils.data import Dataset
from PIL import Image
# use PIL Image to read image
def default_loader(path):
try:
img = Image.open(path)
return img.convert('RGB')
except:
print("Cannot read image: {}".format(path))
# define your Dataset. Assume each line in your .txt file is [name/tab/label], for example:0001.jpg 1
class customData(Dataset):
def __init__(self, img_path, txt_path, dataset = '', data_transforms=None, loader = default_loader):
with open(txt_path) as input_file:
lines = input_file.readlines()
self.img_name = [os.path.join(img_path, line.strip().split('\t')[0]) for line in lines]
self.img_label = [int(line.strip().split('\t')[-1]) for line in lines]
self.data_transforms = data_transforms
self.dataset = dataset
self.loader = loader
def __len__(self):
return len(self.img_name)
def __getitem__(self, item):
img_name = self.img_name[item]
label = self.img_label[item]
img = self.loader(img_name)
if self.data_transforms is not None:
try:
img = self.data_transforms[self.dataset](img)
except:
print("Cannot transform image: {}".format(img_name))
return img, label
def train_model(model, criterion, optimizer, scheduler, num_epochs, use_gpu):
since = time.time()
best_model_wts = model.state_dict()
best_acc = 0.0
for epoch in range(num_epochs):
begin_time = time.time()
print('Epoch {}/{}'.format(epoch, num_epochs - 1))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['train', 'val']:
count_batch = 0
if phase == 'train':
scheduler.step()
model.train(True) # Set model to training mode
else:
model.train(False) # Set model to evaluate mode
running_loss = 0.0
running_corrects = 0.0
# Iterate over data.
for data in dataloders[phase]:
count_batch += 1
# get the inputs
inputs, labels = data
# wrap them in Variable
if use_gpu:
inputs = Variable(inputs.cuda())
labels = Variable(labels.cuda())
else:
inputs, labels = Variable(inputs), Variable(labels)
# zero the parameter gradients
optimizer.zero_grad()
# forward
outputs = model(inputs)
_, preds = torch.max(outputs.data, 1)
loss = criterion(outputs, labels)
# backward + optimize only if in training phase
if phase == 'train':
loss.backward()
optimizer.step()
# statistics
running_loss += loss.item()
running_corrects += torch.sum(preds == labels.data).to(torch.float32)
# print result every 10 batch
if count_batch%10 == 0:
batch_loss = running_loss / (batch_size*count_batch)
batch_acc = running_corrects / (batch_size*count_batch)
print('{} Epoch [{}] Batch [{}] Loss: {:.4f} Acc: {:.4f} Time: {:.4f}s'. \
format(phase, epoch, count_batch, batch_loss, batch_acc, time.time()-begin_time))
begin_time = time.time()
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects / dataset_sizes[phase]
print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# save model
if phase == 'train':
if not os.path.exists('output'):
os.makedirs('output')
torch.save(model, 'output/resnet_on_PV_epoch{}.pkl'.format(epoch))
# deep copy the model
if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = model.state_dict()
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
# load best model weights
model.load_state_dict(best_model_wts)
return model
if __name__ == '__main__':
print("Program start","-"*10)
print("Init data transforms......")
data_transforms = {
'train': transforms.Compose([
#transforms.RandomSizedCrop(224),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
#transforms.Scale(256),
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
use_gpu = torch.cuda.is_available()
batch_size = 32
num_class = 3
print("batch size:",batch_size,"num_classes:",num_class)
print("Load dataset......")
# image_datasets = {x: customData(img_path='sin_poly_defect_data/',
# txt_path=('sin_poly_defect_data/TxtFile/general_train.txt'),
# data_transforms=data_transforms,
# dataset=x) for x in ['train', 'total_val']}
image_datasets={}
image_datasets['train'] = customData(img_path='sin_poly_defect_data/',
txt_path=('sin_poly_defect_data/TxtFile/general_train.txt'),
data_transforms=data_transforms,
dataset='train')
image_datasets['val'] = customData(img_path='sin_poly_defect_data/',
txt_path=('sin_poly_defect_data/TxtFile/real_poly_defect.txt'),
data_transforms=data_transforms,
dataset='val')
# train_data=image_datasets.pop('general_train')
# image_datasets['train']=train_data
# val_data=image_datasets.pop('total_val')
# image_datasets['val']=val_data
# wrap your data and label into Tensor
print("wrap data into Tensor......")
dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],
batch_size=batch_size,
shuffle=True) for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
print("total dataset size:",dataset_sizes)
# get model and replace the original fc layer with your fc layer
print("get resnet model and replace last fc layer...")
model_ft = models.resnet50(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, num_class)
# if use gpu
print("Use gpu:",use_gpu)
if use_gpu:
model_ft = model_ft.cuda()
print("Define loss function and optimizer......")
# define cost function
criterion = nn.CrossEntropyLoss()
# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.005, momentum=0.9)
# Decay LR by a factor of 0.2 every 5 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=5, gamma=0.2)
# multi-GPU
model_ft = torch.nn.DataParallel(model_ft, device_ids=[0])
# train model
print("start train_model......")
model_ft = train_model(model=model_ft,
criterion=criterion,
optimizer=optimizer_ft,
scheduler=exp_lr_scheduler,
num_epochs=15,
use_gpu=use_gpu)
# save best model
print("save model......")
torch.save(model_ft,"output/resnet_on_PV_best_total_val.pkl")