이번장에서는 AI 딥러닝 중 하나인 Classification(분류화) 알고리즘중에 하나인 EfficientNet에 대해 알아볼것이다.

EfficientNet을 일일이 구현하기 너무 어려우므로 lukemelas님이 구현한 EfficientNet-pytoroch 라이브러리를 사용해서 Classification을 진행할 것이다.
먼저 라이브러리를 설치하려면
# pip install efficientnet_pytorch
위와 같이 설치하면 설치가 완료 된다.
사용법은
from efficientnet_pytorch import EfficientNet
model = EfficientNet.from_pretrained('efficientnet-b0')
위와 같이 사용하면 된다.
efficientnet이 굉장히 강력한 이유는 아래와 같이 비교표를 보면 쉽게 알수있다.

현재 V2까지 나왔지만 코드는 V1으로 진행할것이다. v2를 구현하는건 추후 장에서 하도록 하고
V2에 대해 설명만 하고 넘어가면 현재 가장 강력한 알고리즘중에 하나인데 아래와 같이 여러가지 알고리즘과 비교한 표와 이미 트레인된 학습모델들을 받아 볼수있다.
참고하시기 바란다.



S모델 다운로드 링크: https://storage.googleapis.com/cloud-tpu-checkpoints/efficientnet/v2/efficientnetv2-s.tgz
S모델 세부사항:









그리고 버전1과 동일한 스케일과 프로세싱한 버젼2의 Smaller모델들도 제공한다.









위에 것을 보면서 시간대비 어떻게 자신에게 맞는지 선택해서 사용하면 된다.
우선 V1에서 미리 트레인된 데이터는 선언할때 바로 가져오므로 아래와 같이 V1의 0~7단계의 모델을 선택해서 불러오면 된다.
model=EfficientNet.from_pretrained('efficientnet-b0',num_classes=numc)
여기서 num_Classes에 들어갈건 분류할 클래스의 갯수이다.
그 다음 train_dataset과 valid_dataset을 정규화 시킨다.
train_dataset = datasets.ImageFolder(
data_path,
transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.RandomRotation(30),
transforms.RandomGrayscale(p=0.1),
transforms.RandomHorizontalFlip(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
]))
vaild_dataset = datasets.ImageFolder(
data_path,
transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
]))
여기서 크기를 동일하게 (224,224)로 했는데 이건 모델 사이즈에 따라서 변경해도 된다 그다음 랜덤 로테이션도 되게 하고 그레이스케일도 넣고 수평반전 등등을 넣어서 학습할 데이터셋을 만들고 valid데이터셋은 그냥 리사이즈만 시킨다.
그다음 데이터셋을 학습할 데이터셋 같은 경우 20퍼센트정도 테스트 데이터셋으로 나누고
train_idx, vaild_idx = train_test_split(list(range(len(train_dataset))), test_size=0.2, random_state=random_seed)
데이터셋을 만든다.
datasets = {}
datasets['train'] = Subset(train_dataset, train_idx)
datasets['valid'] = Subset(vaild_dataset, vaild_idx)
그 다음 데이터 로더로 데이터들을 메모리에 로딩시켜놓는다.
dataloaders, batch_num = {}, {}
dataloaders['train'] = torch.utils.data.DataLoader(datasets['train'],
batch_size=batch_size, shuffle=True,
num_workers=4)
dataloaders['valid'] = torch.utils.data.DataLoader(datasets['valid'],
batch_size=batch_size, shuffle=False,
num_workers=4)
그 다음 모델을 하드웨어가 쿠다를 사용한다면 쿠다를 사용해서 로딩한다. 쿠다가 없으면 그냥 CPU연산 사용
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # set gpu
model = model.to(device)
그 다음 Pytorch에서 제공하는 다중 분류를 위한 대표적인 손실 함수 crossentropyloss()함수를 사용 선언하고
criterion = nn.CrossEntropyLoss()
딥러닝에서 제일 많이 사용되는 optimizer인 Adam을 사용하기 위해 선언해준다.이때 같이 스케쥴러까지 세팅한다.
optimizer_ft = optim.Adam(model.parameters(), lr=0.001)
scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
잠깐 손실함수와 최적화에 대해 집고 넘어가자면,
딥러닝이 학습할 시 최대한 틀리지 않는 방향으로 학습을 해나가는데 이때 얼마나 틀리는지 알게하는 함수가 손실함수(Criterion)이다. 그리고 이러한 손실함수의 최소값을 찾아가는게 학습목표인데 최소값을 찾아가는 방법이
최적화(Optimization)이다.
이때 가장 많이 쓰는 최적화 알고리즘이 Adam이라는 알고리즘인데 이건. 최적화 중에서도
Momentum과 RMSProp 두가지를 섞어 쓴 알고리즘으로, 진행하던 속도에 관성을 주고 최근 경로의 곡면의 변화량에 따른 적응적 학습률을 가진 알고리즘이다.
이 Adam알고리즘의 장점은 bounded step size로 기울기 값과 기울기 제곱값의 지수이동평균을 활용해서 step 변화량을 조절하므로서, 초기 경로의 평향 문제가 있는 RMSProp의 단점을 보정하면서, Momentum 방식과 유사하게 계속 계산해온 기울기의 지수 평균을 이용한다.
이제 선언한 것을 이용해서 아래와 같이 학습을 실행하면 된다.
def train_model(model, criterion, optimizer, scheduler, num_epochs=epoch):
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
train_loss, train_acc, valid_loss, valid_acc = [], [], [], []
losscount=0
past_acc=0.0
for epoch in range(num_epochs):
#print('Epoch {}/{}'.format(epoch, num_epochs))
if losscount>2:
break
# Each epoch has a training and validation phase
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
running_loss, running_corrects, num_cnt = 0.0, 0, 0
#print(phase)
# Iterate over data.
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# zero the parameter gradients
optimizer.zero_grad()
# forward
# track history if only in train
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
# backward + optimize only if in training phase
if phase == 'train':
loss.backward()
optimizer.step()
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
num_cnt += len(labels)
if phase == 'train':
scheduler.step()
epoch_loss = float(running_loss / num_cnt)
epoch_acc = float((running_corrects.double() / num_cnt).cpu()*100)
if phase == 'train':
train_loss.append(epoch_loss)
train_acc.append(epoch_acc)
else:
valid_loss.append(epoch_loss)
valid_acc.append(epoch_acc)
# deep copy the model
if phase == 'valid' and epoch_acc > best_acc:
best_idx = epoch
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
model.load_state_dict(best_model_wts)
base_dir = f'{data_path}'
if not os.path.exists(base_dir):
os.makedirs(base_dir)
saved_name=f'{base_dir}/best-savedmodel-{str(epoch).zfill(4)}.pt'
torch.save(model.state_dict(), saved_name)
print('best model saved - %d / %.1f'%(best_idx, best_acc))
for path in sorted(glob(f'{base_dir}/best-savedmodel-*.pt'))[:-5]:
os.remove(path)
losscount=0
elif phase=='valid':
losscount+=1
break
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
print('Best valid Acc: %d - %.1f' %(best_idx, best_acc))
# load best model weights
print('model saved')
이제 학습이 완료가 되면 학습완료된 모델을 로딩하고
model = EfficientNet.from_pretrained('efficientnet-{}'.format(env),num_classes=numc)
model.load_state_dict(torch.load(savedfile))
이미지를 로딩한다음 아까 학습할때 했는 크기로 리사이즈 한다음
test_transforms = transforms.Compose([transforms.Resize(224), transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),])
img=cv2.imread("읽을파일")
input=input_transform(img)
def input_transform(image):
img_ids = Image.fromarray(image)
image_tensor = test_transforms(img_ids)
image_tensor = image_tensor.unsqueeze_(0)
input = Variable(image_tensor)
input = input.to(device)
return input
테스트를 실행해보면 된다.
result=predict_image(input)
def predict_image(input):
output = model(input)
preds = torch.topk(output,k=numc).indices.squeeze(0).tolist()
result='Result:'
for t,idx in enumerate(preds):
prob=torch.softmax(output,dim=1)[0,idx].item()
result=result+'{:<25} ({:.2f}%)'.format(idx, prob*100)+":"
return result
그러면 끝.
'Python 프로그래밍' 카테고리의 다른 글
파이썬 프로그래밍 Json / XML 제어 하기 (0) | 2023.01.04 |
---|---|
opencv 파이썬 프로그래밍 영상처리 (0) | 2022.12.31 |
텐서플로우 파이썬 object detection 나만의 이미지 (1) | 2022.12.28 |
파이썬 YOLO 텐서플로우 학습하기 (0) | 2022.12.11 |