我正在实现一种称为“改进的双线性填充”的算法。它包括不带FC层的VGG或ResNet。在结果特征图中执行每个向量的外积。然后执行矩阵平方根,元素明智平方根,L2范数,最后将结果馈入softmax层。
以下是论文: https://arxiv.org/abs/1707.06772
我试图以这种方式重新实现它: 我使用了在imagenet上保留的没有FC层的keras VGG 16模型
vgg_16 = keras.applications.vgg16.VGG16(weights='imagenet',include_top=False, input_shape=(224, 224, 3))
vgg_16.layers.pop()
My_Model = Sequential()
for layer in vgg_16.layers:
My_Model.add(layer)
for layer in My_Model.layers:
layer.trainable = False
然后我在每个位置取每个向量,并将乘积做一个矩阵
Batch_Size=16
def BILINEAR_POOLING(Feature_Map):
Height = Feature_Map.shape[1]
Width = Feature_Map.shape[2]
Channel = Feature_Map.shape[3]
Epsilon = (tf.scalar_mul( tf.keras.backend.epsilon(), tf.ones([Batch_Size, Channel, Channel],tf.float32)))
A = tf.zeros([Batch_Size, Channel, Channel],tf.float32)
for i in range (Height):
for j in range (Width):
A = A + tf.matmul(Feature_Map[:,i,j,:],Feature_Map[:,i,j,:], transpose_a=True)
N = tf.cast((Height*Width), tf.float32)
A = tf.add(tf.div(A,N) ,Epsilon)
return A
然后是模糊部分,具有SVD分解和Lyapunov方程的矩阵平方根
#Forward + Backward via SVD
def Sqrt_Root_SVD_Lyapunov(A):
BatchSize = A.shape[0]
Dim = A.shape[1]
#dlda = tf.zeros([BatchSize,Dim,Dim],tf.float32)
sA = tf.zeros([BatchSize,Dim,Dim],tf.float32)
output_list = []
for i in range(BatchSize):
S,U,V = tf.svd(A[i,:,:],compute_uv = True)
S = tf.where(tf.less(S, 1e-10), S, tf.sqrt(S))
SQRT = tf.matmul(U,(tf.matmul(tf.diag(tf.sqrt(S)),V, transpose_b = True)))
output_list.append(SQRT)
#S = tf.matmul(tf.diag(tf.sqrt(S)), (tf.ones([Dim,Dim],Type)))
#IU = tf.transpose(U)
#X = tf.matmul(tf.matmul(-U,(tf.matmul((tf.matmul(dldz,IU)),U)/(S+tf.transpose(S)))),IU)
#dlda [i,:,:] = X
sA= tf.stack(output_list)
return sA
pytorch中的原始代码如下
# Forward + Backward via SVD decomposition
def sqrt_svd_lyap(A, dldz, dtype):
batchSize = A.data.shape[0]
dim = A.data.shape[1]
dlda = torch.zeros(batchSize, dim, dim).type(dtype)
sA = torch.zeros(batchSize, dim, dim).type(dtype)
for i in range(batchSize):
U, S, V = (A[i,:,:].data).svd()
sA[i,:,:] = (U.mm(S.diag().sqrt())).mm(V.t())
S = S.diag().sqrt().mm(torch.ones(dim, dim).type(dtype))
IU = U.t()
X = -U.mm(
((IU.mm(dldz[i,:,:].data)).mm(IU.t()))
/(S+S.t())
).mm(U.t());
dlda[i,:,:] = X
return sA, dlda, compute_error(A, Variable(sA, requires_grad=False))
然后我将这些功能添加到模型中
My_Model.add(Lambda(BILINEAR_POOLING,output_shape=[512,512]))
My_Model.add(Lambda(Sqrt_Root_SVD_Lyapunov,output_shape=[512,512]))
My_Model.add(Lambda(lambda x: tf.sign(x)* tf.sqrt(tf.abs(x))))
My_Model.add(Lambda(lambda x: tf.math.l2_normalize(x,axis=None, epsilon=1e-12, name=None,dim=None)))
My_Model.add(Flatten())
My_Model.add(Dense(7, activation='softmax'))
My_Model.compile(SGD(lr=.001), loss='categorical_crossentropy', metrics=['accuracy'])
My_Model.fit_generator(train_batches, steps_per_epoch=49, validation_data=valid_batches, validation_steps=16,epochs=10,
verbose=1)
问题是它确实给出了很好的结果。而且它停留在30%,所以我认为它并没有结束学习的目的
你能告诉我问题吗?