2014_VGG16_牛津**
图:
网络描述:
VGG16总共有16层,13个卷积层和3个全连接层,第一次经过64个卷积核的两次卷积后,采用一次pooling,第二次经过两次128个卷积核卷积后,再采用pooling,再重复两次三个512个卷积核卷积后,再pooling,最后经过三次全连接。 输入图像尺寸224×224×3,进行第一个卷积之后得到224×224×64的特征图,接着还有一层224×224×64,得到这样2个厚度为64的卷积层,意味着我们用64个过滤器进行了两次卷积。这里采用的都是大小为3×3,步幅为1的过滤器,并且都是采用same卷积。接下来创建一个池化层,池化层将输入图像进行压缩,从224×224×64缩小到112×112×64。然后又是若干个卷积层,使用129个过滤器,以及一些same卷积,112×112×128然后进行池化,可以推导出池化后的结果是这样(56×56×128)。接着再用256个相同的过滤器进行三次卷积操作,然后再池化,然后再卷积三次,再池化。如此进行几轮操作后,将最后得到的7×7×512的特征图进行全连接操作,得到4096个单元,然后进行softmax激活,输出从1000个对象中识别的结果。
特点,优点:
(1)VGGNet探索了卷积神经网络的深度与其性能之间的关系,通过反复堆叠3×3的小型卷积核和2×2的最大池化层,VGGNet成功地构筑了16-19层深的卷积神经网络
(2) VGGNet结构简洁,整个网络都使用了同样大小的卷积核尺寸(3×3)和最大池化尺寸(2×2)
(3) 拥有5段卷积,每段内有2-3个卷积层,每段段尾连接一个最大池化层,用来缩小图片
(4) 使用非常多的3*3卷积串联 ,卷积串联比单独使用一个较大的卷积核,拥有更少的参数量,同时会比单独一个卷积层拥有更多的非线性变换
缺点:
(1)由于用了较多的全连接层(3个),参数量很大。
(2)因为很多的卷积层执行了通道数翻倍,主要缺点是需要训练的特征数量非常巨大。
代码:
keras实现:
class vgg16():
def __init__(self):
self.model = Sequential()
self.mean = [103.93, 116.79, 123.68]
def load_img(self, imgurl):
self.img = cv2.imread(imgurl)
im = cv2.resize(self.img,(224, 224)).astype(np.float32)
im[:,:,0] -= self.mean[0] #RGB三通道图像,对每一个通道减去这个通道的均值,目的是加快网络收敛。
im[:, :, 1] -= self.mean[1]
im[:, :, 2] -= self.mean[2]
im = np.expand_dims(im, axis= 0) #增加batch这一列,[batch, img_height, img_weight, channel]
return im
def model_add(self, filter = None, isConv = False, isMax = False, input_shape = None):
if isConv:
if input_shape:
self.model.add(Convolution2D(filters=filter, kernel_size=(3,3),strides=(1,1)
,padding="same", activation = "relu", input_shape = input_shape))
else:
self.model.add(Convolution2D(filters= filter, kernel_size=(3,3), strides=(1,1)
, padding="same", activation = "relu"))
#这里注意kernel_size = (3,3)
#不同于tf.nn.conv2(kernel_size = [1,3,3,1])
#我的理解是keras是tf的高级融合api,一切都按着简单来考虑
if isMax:
self.model.add(MaxPooling2D(pool_size= (2,2), strides=(2,2), padding="valid"))
def nn(self):
self.model_add(filter=64, isConv= True, input_shape=(224,224,3))
self.model_add(filter=64, isConv= True)
self.model_add(isMax= True)
self.model_add(filter=128, isConv=True)
self.model_add(filter=128, isConv=True)
self.model_add(isMax=True)
self.model_add(filter=256, isConv=True)
self.model_add(filter=256, isConv=True)
self.model_add(filter=256, isConv=True)
self.model_add(isMax=True)
self.model_add(filter=512, isConv=True)
self.model_add(filter=512, isConv=True)
self.model_add(filter=512, isConv=True)
self.model_add(isMax=True)
self.model_add(filter=512, isConv= True)
self.model_add(filter=512, isConv= True)
self.model_add(filter=512, isConv= True)
self.model_add(isMax=True)
self.model.add(Flatten())
self.model.add(Dense(4096, activation= "relu"))
self.model.add(Dense(4096,activation="relu"))
self.model.add(Dense(1000, activation="softmax"))
self.model.load_weights("model/vgg/vgg16_weights_tf_dim_ordering_tf_kernels.h5")
#这里是参数文件的具体位置,我所有工程文件与测试图片“timg.jpg”都在model这个文件夹内。
def pred(self, imgurl):
self.nn()
cls = open("model/vgg/classes.txt") #标签文件
lines = cls.readlines()
cls.close()
img = self.load_img(imgurl= imgurl)
pre = np.argmax(self.model.predict(img))
self.show_img(lines[pre].split(' ', 1)[1])
def show_img(self, text):
cv2.putText(self.img, text, (25,25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255), 1)
cv2.imshow("img", self.img)
cv2.waitKey(0)
cv2.destroyAllWindows()
pytorch实现:
class VGG16(nn.Module):
def __init__(self):
super(VGG16, self).__init__()
self.maxpool1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.maxpool2 = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.maxpool3 = nn.Sequential(
nn.Conv2d(128, 256, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.maxpool4 = nn.Sequential(
nn.Conv2d(256, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.maxpool5= nn.Sequential(
nn.Conv2d(512, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3,stride=1, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.dense = nn.Sequential(
nn.Linear(512 * 5 * 5, 4096),
nn.ReLU(),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Linear(4096, 1000)
)
def forward(self, x):
pool1=self.maxpool1(x)
pool2=self.maxpool2(pool1)
pool3=self.maxpool3(pool2)
pool4=self.maxpool4(pool3)
pool5=self.maxpool5(pool4)
flat = pool5.view(pool5.size(0), -1)
class_ = self.dense(flat)
return class_