AlexNet结构 及 pytorch、tensorflow、keras、paddle实现ImageNet识别
环境
python3.6, keras2.2.4, tensorflow-gpu 1.12.0
代码
# -*- coding: utf-8 -*-
# @Time : 2020/1/21 11:18
# @Author : Zhao HL
# @File : alexnet-keras.py
import keras
from keras.utils import Sequence
from keras.layers import *
from keras.models import *
from keras.optimizers import *
from keras.callbacks import *
import numpy as np
import pandas as pd
from PIL import Image
from my_utils import draw_loss_acc,dataInfo_show,dataset_divide
# region parameters
# region paths
Data_path = "./data/my_imagenet"
Data_csv_path = "./data/my_imagenet.csv"
Model_path = 'model/'
Model_file_tf = "model/alexnet_tf.ckpt"
Model_file_keras = "model/alexnet_keras.h5"
Model_file_torch = "model/alexnet_torch.pth"
Model_file_paddle = "model/alexnet_paddle.model"
# endregion
# region image parameter
Img_size = 227
Img_chs = 3
Label_size = 1
Label_class = {'n02091244': 'Ibizan hound',
'n02114548': 'white wolf',
'n02138441': 'meerkat',
'n03584254': 'iPod',
'n03075370': 'combination lock',
'n09256479': 'coral reef',
'n03980874': 'poncho',
'n02174001': 'rhinoceros beetle',
'n03770439': 'miniskirt',
'n03773504': 'missile'}
Labels_nums = len(Label_class)
# endregion
# region net parameter
Conv1_kernel_size = 11
Conv1_chs = 96
Conv2_kernel_size = 5
Conv2_chs = 256
Conv3_kernel_size = 3
Conv3_chs = 384
Conv4_kernel_size = 3
Conv4_chs = 384
Conv5_kernel_size = 3
Conv5_chs = 256
Flatten_size = 6 * 6 * 256
Fc1_size = 4096
Fc2_size = 4096
Fc3_size = Labels_nums
# endregion
# region hpyerparameter
Learning_rate = 1e-3
Batch_size = 64
Buffer_size = 256
Infer_size = 1
Epochs = 10
Train_num = 700
Train_batch_num = Train_num // Batch_size
Val_num = 100
Val_batch_num = Val_num // Batch_size
Test_num = 200
Test_batch_num = Test_num // Batch_size
# endregion
# endregion
class MyDataset(Sequence):
def __init__(self, root_path, batch_size=1, files_list=None):
self.root_path = root_path
self.batch_size = batch_size
self.files_list = files_list if files_list else os.listdir(root_path)
np.random.shuffle(self.files_list)
self.batch_size = batch_size
self.size = len(files_list)
self.indexes = np.arange(self.size)
def __len__(self):
return self.size
def shape(self):
batch_num,batch_size = self.size // self.batch_size, self.batch_size
return (batch_num,batch_size)
def __getitem__(self, batch_index):
if batch_index >= self.size // self.batch_size:
batch_index = batch_index % (self.size // self.batch_size)
images, labels = [], []
start_index = batch_index * self.batch_size
end_index = (batch_index + 1) * self.batch_size
for index in range(start_index, end_index):
label_str = self.files_list[index][:9]
label = list(Label_class.keys()).index(label_str)
img = Image.open(os.path.join(self.root_path, self.files_list[index]))
img, label = self.transform(img, label)
images.append(img)
labels.append(label)
images = np.array(images)
labels = np.array(labels)
if batch_index == self.size // self.batch_size - 1:
np.random.shuffle(self.files_list)
return images, labels
# def on_epoch_end(self):
# np.random.shuffle(self.indexes)
def transform(self, image, label):
def Normalize(image, means, stds):
for band in range(len(means)):
image[:, :, band] = image[:, :, band] / 255.0
image[:, :, band] = (image[:, :, band] - means[band]) / stds[band]
return image
def ToOnehot(labels):
labels = np.eye(Labels_nums)[labels].reshape(Labels_nums)
return labels
pass
image = image.resize((Img_size, Img_size), Image.ANTIALIAS)
image = Normalize(np.array(image).astype(np.float), [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
label = ToOnehot(label)
return image, label
class AlexNet:
def __init__(self, structShow=False):
self.structShow = structShow
def get_alexNet(self):
input = Input(shape=(Img_size, Img_size, Img_chs))
conv1 = Conv2D(Conv1_chs, kernel_size=Conv1_kernel_size, padding='VALID', activation='relu', strides=4,
kernel_initializer=keras.initializers.TruncatedNormal(stddev=0.1))(input)
pool1 = MaxPooling2D(pool_size=3, strides=2, padding='VALID')(conv1)
conv2 = Conv2D(Conv2_chs, kernel_size=Conv2_kernel_size, padding='SAME', activation='relu',
kernel_initializer=keras.initializers.TruncatedNormal(stddev=0.1))(pool1)
pool2 = MaxPooling2D(pool_size=3, strides=2, padding='VALID')(conv2)
conv3 = Conv2D(Conv3_chs, kernel_size=Conv3_kernel_size, padding='SAME', activation='relu',
kernel_initializer=keras.initializers.TruncatedNormal(stddev=0.1))(pool2)
conv4 = Conv2D(Conv4_chs, kernel_size=Conv4_kernel_size, padding='SAME', activation='relu',
kernel_initializer=keras.initializers.TruncatedNormal(stddev=0.1))(conv3)
conv5 = Conv2D(Conv5_chs, kernel_size=Conv5_kernel_size, padding='SAME', activation='relu',
kernel_initializer=keras.initializers.TruncatedNormal(stddev=0.1))(conv4)
pool3 = MaxPooling2D(pool_size=3, strides=2, padding='VALID')(conv5)
flat = Flatten()(pool3)
fc1 = Dense(Fc1_size, activation='relu')(flat)
fc2 = Dense(Fc2_size, activation='relu')(fc1)
fc3 = Dense(Fc3_size, activation='softmax')(fc2)
model = Model(inputs=input, outputs=fc3)
model.compile(optimizer=Adam(lr=Learning_rate), loss='categorical_crossentropy', metrics=['accuracy'])
if self.structShow:
model.summary()
return model
def train():
df = pd.read_csv(Data_csv_path, header=0, index_col=0)
train_list = df[df['split'] == 'train']['filename'].tolist()
val_list = df[df['split'] == 'val']['filename'].tolist()
train_dataset = MyDataset(Data_path, batch_size=Batch_size, files_list=train_list)
val_dataset = MyDataset(Data_path, batch_size=Batch_size, files_list=val_list)
net = AlexNet(structShow=True)
model = net.get_alexNet()
# if os.path.exists(Model_file_keras):
# model = load_model(Model_file_keras)
# else:
# model = net.get_alexNet()
model_checkpoint = ModelCheckpoint(Model_file_keras, monitor='val_loss', save_best_only=True)
history = model.fit_generator(train_dataset,
steps_per_epoch=train_dataset.shape()[0],
epochs=Epochs,
use_multiprocessing=True,
validation_data=val_dataset,
validation_steps=val_dataset.shape()[0],
shuffle=True,
callbacks=[model_checkpoint]
)
train_losses = history.history['loss']
train_accs = history.history['acc']
val_losses = history.history['val_loss']
val_accs = history.history['val_acc']
draw_loss_acc(train_losses, train_accs, 'train')
draw_loss_acc(val_losses, val_accs, 'val')
print('best loss %.4f at epoch %d \n' % (max(val_losses), int(np.argmin(np.array(val_losses)))))
if __name__ == '__main__':
pass
# dataInfo_show(r'E:\_Python\01_deeplearning\03_AlexNet\data\my_imagenet',
# r'E:\_Python\01_deeplearning\03_AlexNet\data\my_imagenet.csv',
# r'E:\_Python\01_deeplearning\03_AlexNet\data\synset_words.txt')
# dataset_divide(r'E:\_Python\01_deeplearning\03_AlexNet\data\my_imagenet.csv')
train()
my_utils.py
# -*- coding: utf-8 -*-
# @Time : 2020/1/21 11:39
# @Author : Zhao HL
# @File : my_utils.py
import sys,os,random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image
def process_show(num, nums, train_acc, train_loss, prefix='', suffix=''):
rate = num / nums
ratenum = int(round(rate, 2) * 100)
bar = '\r%s batch %3d/%d:train accuracy %.4f, train loss %00.4f [%s%s]%.1f%% %s; ' % (
prefix, num, nums, train_acc, train_loss, '#' * (ratenum//2), '_' * (50 - ratenum//2), ratenum, suffix)
sys.stdout.write(bar)
sys.stdout.flush()
if num >= nums:
print()
def dataInfo_show(data_path,csv_pth,cls_dic_path,shapesShow=True,classesShow=True):
cls_dict = get_cls_dic(cls_dic_path)
if classesShow:
print('\n'+'*'*50)
df = pd.read_csv(csv_pth)
labels = df['label'].unique()
label_cls = {label:cls_dict[label] for label in labels}
print(label_cls)
cls_count = df['label'].value_counts()
cls_count = {cls_dict[k]:v for k,v in cls_count.items()}
for k,v in cls_count.items():
print(k,v)
if shapesShow:
print('\n'+'*'*50)
shapes = []
for filename in os.listdir(data_path):
img = Image.open(os.path.join(data_path, filename))
img = np.array(img)
shapes.append(img.shape)
shapes = pd.Series(shapes)
print(shapes.value_counts())
def get_cls_dic(cls_dic_path):
# 读取类标签字典,只取第一个逗号前的信息
cls_df = pd.read_csv(cls_dic_path)
cls_df['cls'] = cls_df['info'].apply(lambda x:x[:9]).tolist()
cls_df['label'] = cls_df['info'].apply(lambda x: x[10:]).tolist()
cls_df = cls_df.drop(columns=['info','other'])
cls_dict = cls_df.set_index('cls').T.to_dict('list')
cls_dict = {k:v[0] for k,v in cls_dict.items()}
return cls_dict
def dataset_divide(csv_pth):
cls_df = pd.read_csv(csv_pth, header=0,index_col=0)
cls_df.insert(2,'split',None)
filenames = list(cls_df['filename'])
random.shuffle(filenames)
train_num,train_val_num = int(len(filenames)*0.7),int(len(filenames)*0.8)
train_names = filenames[:train_num]
val_names = filenames[train_num:train_val_num]
test_names = filenames[train_val_num:]
cls_df.loc[cls_df['filename'].isin(train_names),'split'] = 'train'
cls_df.loc[cls_df['filename'].isin(val_names), 'split'] = 'val'
cls_df.loc[cls_df['filename'].isin(test_names), 'split'] = 'test'
cls_df.to_csv(csv_pth)
def draw_loss_acc(loss,acc,type='',save_path=None):
assert len(acc) == len(loss)
x = [epoch for epoch in range(len(acc))]
plt.subplot(2, 1, 1)
plt.plot(x, acc, 'o-')
plt.title(type+' accuracy vs. epoches')
plt.ylabel('accuracy')
plt.subplot(2, 1, 2)
plt.plot(x, loss, '.-')
plt.xlabel(type+' loss vs. epoches')
plt.ylabel('loss')
plt.show()
if save_path:
plt.savefig(os.path.join(save_path,type+"_acc_loss.png"))
if __name__ == '__main__':
pass