#change to 四元数,https://zhuanlan.zhihu.com/p/45404840defmatrix2quaternion(m):#m:array
w =((np.trace(m)+1)**0.5)/2
x =(m[2][1]- m[1][2])/(4* w)
y =(m[0][2]- m[2][0])/(4* w)
z =(m[1][0]- m[0][1])/(4* w)return w,x,y,z
defquaternion2matrix(q):#q:list
w,x,y,z = q
return np.array([[1-2*y*y-2*z*z,2*x*y-2*z*w,2*x*z+2*y*w],[2*x*y+2*z*w,1-2*x*x-2*z*z,2*y*z-2*x*w],[2*x*z-2*y*w,2*y*z+2*x*w,1-2*x*x-2*y*y]])
defm(a):
a = a.split(';')
a =[float(i)for i in a]
A = np.array([[a[0],a[1],a[2]],[a[3],a[4],a[5]],[a[6],a[7],a[8]]])return matrix2quaternion(A)
change_train_labels =1if change_train_labels:
train_labels = pd.read_csv('/kaggle/input/image-matching-challenge-2023/train/train_labels.csv')
train_labels['rotation_matrix_quaternion']=[i for i inmap(m,train_labels['rotation_matrix'])]
train_labels.to_csv('/kaggle/working/my_train_labels.csv')
DEFAULT_PADDING ='SAME'deflayer(op):'''Decorator for composable network layers.'''deflayer_decorated(self,*args,**kwargs):# Automatically set a name if not provided.
name = kwargs.setdefault('name', self.get_unique_name(op.__name__))# Figure out the layer inputs.iflen(self.terminals)==0:raise RuntimeError('No input variables found for layer %s.'% name)eliflen(self.terminals)==1:
layer_input = self.terminals[0]else:
layer_input =list(self.terminals)# Perform the operation and get the output.
layer_output = op(self, layer_input,*args,**kwargs)# Add to layer LUT.
self.layers[name]= layer_output
# This output is now the input for the next layer.
self.feed(layer_output)# Return self for chained calls.return self
return layer_decorated
classNetwork(object):def__init__(self, inputs, trainable=True):# The input nodes for this network
self.inputs = inputs
# The current list of terminal nodes
self.terminals =[]# Mapping from layer names to layers
self.layers =dict(inputs)# If true, the resulting variables are set as trainable
self.trainable = trainable
# Switch variable for dropout
self.use_dropout = tf.placeholder_with_default(tf.constant(1.0),
shape=[],
name='use_dropout')
self.setup()defsetup(self):'''Construct the network. '''raise NotImplementedError('Must be implemented by the subclass.')defload(self, data_path, session, ignore_missing=False):'''Load network weights.
data_path: The path to the numpy-serialized network weights
session: The current TensorFlow session
ignore_missing: If true, serialized weights for missing layers are ignored.
'''
data_dict = np.load(data_path,allow_pickle=True,encoding="latin1").item()for op_name in data_dict:with tf.variable_scope(op_name, reuse=True):for param_name, data in data_dict[op_name].items():try:
var = tf.get_variable(param_name)
session.run(var.assign(data))except ValueError:ifnot ignore_missing:raisedeffeed(self,*args):'''Set the input(s) for the next operation by replacing the terminal nodes.
The arguments can be either layer names or the actual layers.
'''assertlen(args)!=0
self.terminals =[]for fed_layer in args:ifisinstance(fed_layer,str):try:
fed_layer = self.layers[fed_layer]except KeyError:raise KeyError('Unknown layer name fed: %s'% fed_layer)
self.terminals.append(fed_layer)return self
defget_output(self):'''Returns the current network output.'''return self.terminals[-1]defget_unique_name(self, prefix):'''Returns an index-suffixed unique name for the given prefix.
This is used for auto-generating layer names based on the type-prefix.
'''
ident =sum(t.startswith(prefix)for t, _ in self.layers.items())+1return'%s_%d'%(prefix, ident)defmake_var(self, name, shape):'''Creates a new TensorFlow variable.'''return tf.get_variable(name, shape, trainable=self.trainable)defvalidate_padding(self, padding):'''Verifies that the padding is one of the supported ones.'''assert padding in('SAME','VALID')@layerdefconv(self,input,
k_h,
k_w,
c_o,
s_h,
s_w,
name,
relu=True,
padding=DEFAULT_PADDING,
group=1,
biased=True):# Verify that the padding is acceptable
self.validate_padding(padding)# Get the number of channels in the input
c_i =input.get_shape()[-1]# Verify that the grouping parameter is validassert c_i % group ==0assert c_o % group ==0# Convolution for a given input and kernel
convolve =lambda i, k: tf.nn.conv2d(i, k,[1, s_h, s_w,1], padding=padding)with tf.variable_scope(name)as scope:
kernel = self.make_var('weights', shape=[k_h, k_w,int(int(c_i)/ group), c_o])if group ==1:# This is the common-case. Convolve the input without any further complications.
output = convolve(input, kernel)else:# Split the input into groups and then convolve each of them independently
input_groups = tf.split(3, group,input)
kernel_groups = tf.split(3, group, kernel)
output_groups =[convolve(i, k)for i, k inzip(input_groups, kernel_groups)]# Concatenate the groups
output = tf.concat(3, output_groups)# Add the biasesif biased:
biases = self.make_var('biases',[c_o])
output = tf.nn.bias_add(output, biases)if relu:# ReLU non-linearity
output = tf.nn.relu(output, name=scope.name)return output
@layerdefrelu(self,input, name):return tf.nn.relu(input, name=name)@layerdefmax_pool(self,input, k_h, k_w, s_h, s_w, name, padding=DEFAULT_PADDING):
self.validate_padding(padding)return tf.nn.max_pool(input,
ksize=[1, k_h, k_w,1],
strides=[1, s_h, s_w,1],
padding=padding,
name=name)@layerdefavg_pool(self,input, k_h, k_w, s_h, s_w, name, padding=DEFAULT_PADDING):
self.validate_padding(padding)return tf.nn.avg_pool(input,
ksize=[1, k_h, k_w,1],
strides=[1, s_h, s_w,1],
padding=padding,
name=name)@layerdeflrn(self,input, radius, alpha, beta, name, bias=1.0):return tf.nn.local_response_normalization(input,
depth_radius=radius,
alpha=alpha,
beta=beta,
bias=bias,
name=name)@layerdefconcat(self, inputs, axis, name):return tf.concat(values=inputs, axis=axis, name=name)@layerdefadd(self, inputs, name):return tf.add_n(inputs, name=name)@layerdeffc(self,input, num_out, name, relu=True):with tf.variable_scope(name)as scope:
input_shape =input.get_shape()if input_shape.ndims ==4:# The input is spatial. Vectorize it first.
dim =1for d in input_shape[1:].as_list():
dim *= d
feed_in = tf.reshape(input,[-1, dim])else:
feed_in, dim =(input, input_shape[-1].value)
weights = self.make_var('weights', shape=[dim, num_out])
biases = self.make_var('biases',[num_out])
op = tf.nn.relu_layer if relu else tf.nn.xw_plus_b
fc = op(feed_in, weights, biases, name=scope.name)return fc
@layerdefsoftmax(self,input, name):
input_shape =map(lambda v: v.value,input.get_shape())iflen(input_shape)>2:# For certain models (like NiN), the singleton spatial dimensions# need to be explicitly squeezed, since they're not broadcast-able# in TensorFlow's NHWC ordering (unlike Caffe's NCHW).if input_shape[1]==1and input_shape[2]==1:input= tf.squeeze(input, squeeze_dims=[1,2])else:raise ValueError('Rank 2 tensor input expected for softmax!')return tf.nn.softmax(input, name)@layerdefbatch_normalization(self,input, name, scale_offset=True, relu=False):# NOTE: Currently, only inference is supportedwith tf.variable_scope(name)as scope:
shape =[input.get_shape()[-1]]if scale_offset:
scale = self.make_var('scale', shape=shape)
offset = self.make_var('offset', shape=shape)else:
scale, offset =(None,None)
output = tf.nn.batch_normalization(input,
mean=self.make_var('mean', shape=shape),
variance=self.make_var('variance', shape=shape),
offset=offset,
scale=scale,# TODO: This is the default Caffe batch norm eps# Get the actual eps from parameters
variance_epsilon=1e-5,
name=name)if relu:
output = tf.nn.relu(output)return output
@layerdefdropout(self,input, keep_prob, name):
keep =1- self.use_dropout +(self.use_dropout * keep_prob)return tf.nn.dropout(input, keep, name=name)
defpreprocess(images):
images_out =[]#final result#Resize and crop and compute mean!
images_cropped =[]for i in tqdm(range(len(images)):#print(images[i])
X = cv2.imread(images[i])#X = cv2.resize(X, (455, 256))
X = centeredCrop(X,224)
images_cropped.append(X)#compute images mean
N =0
mean = np.zeros((1,3,224,224))for X in tqdm(images_cropped):
X = np.transpose(X,(2,0,1))#print(X.shape)#3,224,224#print(X[0,:,:].shape)#3,224#print(mean[0][0].shape)#224,224
mean[0][0]+= X[0,:,:]
mean[0][1]+= X[1,:,:]
mean[0][2]+= X[2,:,:]
N +=1
mean[0]/= N
#Subtract mean from all imagesfor X in tqdm(images_cropped):
X = np.transpose(X,(2,0,1))
X = X - mean
X = np.squeeze(X)
X = np.transpose(X,(1,2,0))
images_out.append(X)return images_out
如果调试的时候,为了快速验证,可以不处理全部函数,比如len(images)*0+2:
#network.py
DEFAULT_PADDING ='SAME'deflayer(op):'''Decorator for composable network layers.'''deflayer_decorated(self,*args,**kwargs):# Automatically set a name if not provided.
name = kwargs.setdefault('name', self.get_unique_name(op.__name__))# Figure out the layer inputs.iflen(self.terminals)==0:raise RuntimeError('No input variables found for layer %s.'% name)eliflen(self.terminals)==1:
layer_input = self.terminals[0]else:
layer_input =list(self.terminals)# Perform the operation and get the output.
layer_output = op(self, layer_input,*args,**kwargs)# Add to layer LUT.
self.layers[name]= layer_output
# This output is now the input for the next layer.
self.feed(layer_output)# Return self for chained calls.return self
return layer_decorated
classNetwork(object):def__init__(self, inputs, trainable=True):# The input nodes for this network
self.inputs = inputs
# The current list of terminal nodes
self.terminals =[]# Mapping from layer names to layers
self.layers =dict(inputs)# If true, the resulting variables are set as trainable
self.trainable = trainable
# Switch variable for dropout
self.use_dropout = tf.placeholder_with_default(tf.constant(1.0),
shape=[],
name='use_dropout')
self.setup()defsetup(self):'''Construct the network. '''raise NotImplementedError('Must be implemented by the subclass.')defload(self, data_path, session, ignore_missing=False):'''Load network weights.
data_path: The path to the numpy-serialized network weights
session: The current TensorFlow session
ignore_missing: If true, serialized weights for missing layers are ignored.
'''
data_dict = np.load(data_path,allow_pickle=True,encoding="latin1").item()for op_name in data_dict:with tf.variable_scope(op_name, reuse=True):for param_name, data in data_dict[op_name].items():try:
var = tf.get_variable(param_name)
session.run(var.assign(data))except ValueError:ifnot ignore_missing:raisedeffeed(self,*args):'''Set the input(s) for the next operation by replacing the terminal nodes.
The arguments can be either layer names or the actual layers.
'''assertlen(args)!=0
self.terminals =[]for fed_layer in args:ifisinstance(fed_layer,str):try:
fed_layer = self.layers[fed_layer]except KeyError:raise KeyError('Unknown layer name fed: %s'% fed_layer)
self.terminals.append(fed_layer)return self
defget_output(self):'''Returns the current network output.'''return self.terminals[-1]defget_unique_name(self, prefix):'''Returns an index-suffixed unique name for the given prefix.
This is used for auto-generating layer names based on the type-prefix.
'''
ident =sum(t.startswith(prefix)for t, _ in self.layers.items())+1return'%s_%d'%(prefix, ident)defmake_var(self, name, shape):'''Creates a new TensorFlow variable.'''return tf.get_variable(name, shape, trainable=self.trainable)defvalidate_padding(self, padding):'''Verifies that the padding is one of the supported ones.'''assert padding in('SAME','VALID')@layerdefconv(self,input,
k_h,
k_w,
c_o,
s_h,
s_w,
name,
relu=True,
padding=DEFAULT_PADDING,
group=1,
biased=True):# Verify that the padding is acceptable
self.validate_padding(padding)# Get the number of channels in the input
c_i =input.get_shape()[-1]# Verify that the grouping parameter is validassert c_i % group ==0assert c_o % group ==0# Convolution for a given input and kernel
convolve =lambda i, k: tf.nn.conv2d(i, k,[1, s_h, s_w,1], padding=padding)with tf.variable_scope(name)as scope:
kernel = self.make_var('weights', shape=[k_h, k_w,int(int(c_i)/ group), c_o])if group ==1:# This is the common-case. Convolve the input without any further complications.
output = convolve(input, kernel)else:# Split the input into groups and then convolve each of them independently
input_groups = tf.split(3, group,input)
kernel_groups = tf.split(3, group, kernel)
output_groups =[convolve(i, k)for i, k inzip(input_groups, kernel_groups)]# Concatenate the groups
output = tf.concat(3, output_groups)# Add the biasesif biased:
biases = self.make_var('biases',[c_o])
output = tf.nn.bias_add(output, biases)if relu:# ReLU non-linearity
output = tf.nn.relu(output, name=scope.name)return output
@layerdefrelu(self,input, name):return tf.nn.relu(input, name=name)@layerdefmax_pool(self,input, k_h, k_w, s_h, s_w, name, padding=DEFAULT_PADDING):
self.validate_padding(padding)return tf.nn.max_pool(input,
ksize=[1, k_h, k_w,1],
strides=[1, s_h, s_w,1],
padding=padding,
name=name)@layerdefavg_pool(self,input, k_h, k_w, s_h, s_w, name, padding=DEFAULT_PADDING):
self.validate_padding(padding)return tf.nn.avg_pool(input,
ksize=[1, k_h, k_w,1],
strides=[1, s_h, s_w,1],
padding=padding,
name=name)@layerdeflrn(self,input, radius, alpha, beta, name, bias=1.0):return tf.nn.local_response_normalization(input,
depth_radius=radius,
alpha=alpha,
beta=beta,
bias=bias,
name=name)@layerdefconcat(self, inputs, axis, name):return tf.concat(values=inputs, axis=axis, name=name)@layerdefadd(self, inputs, name):return tf.add_n(inputs, name=name)@layerdeffc(self,input, num_out, name, relu=True):with tf.variable_scope(name)as scope:
input_shape =input.get_shape()if input_shape.ndims ==4:# The input is spatial. Vectorize it first.
dim =1for d in input_shape[1:].as_list():
dim *= d
feed_in = tf.reshape(input,[-1, dim])else:
feed_in, dim =(input, input_shape[-1].value)
weights = self.make_var('weights', shape=[dim, num_out])
biases = self.make_var('biases',[num_out])
op = tf.nn.relu_layer if relu else tf.nn.xw_plus_b
fc = op(feed_in, weights, biases, name=scope.name)return fc
@layerdefsoftmax(self,input, name):
input_shape =map(lambda v: v.value,input.get_shape())iflen(input_shape)>2:# For certain models (like NiN), the singleton spatial dimensions# need to be explicitly squeezed, since they're not broadcast-able# in TensorFlow's NHWC ordering (unlike Caffe's NCHW).if input_shape[1]==1and input_shape[2]==1:input= tf.squeeze(input, squeeze_dims=[1,2])else:raise ValueError('Rank 2 tensor input expected for softmax!')return tf.nn.softmax(input, name)@layerdefbatch_normalization(self,input, name, scale_offset=True, relu=False):# NOTE: Currently, only inference is supportedwith tf.variable_scope(name)as scope:
shape =[input.get_shape()[-1]]if scale_offset:
scale = self.make_var('scale', shape=shape)
offset = self.make_var('offset', shape=shape)else:
scale, offset =(None,None)
output = tf.nn.batch_normalization(input,
mean=self.make_var('mean', shape=shape),
variance=self.make_var('variance', shape=shape),
offset=offset,
scale=scale,# TODO: This is the default Caffe batch norm eps# Get the actual eps from parameters
variance_epsilon=1e-5,
name=name)if relu:
output = tf.nn.relu(output)return output
@layerdefdropout(self,input, keep_prob, name):
keep =1- self.use_dropout +(self.use_dropout * keep_prob)return tf.nn.dropout(input, keep, name=name)defcenteredCrop(img, output_side_length):
height, width, depth = img.shape
new_height = output_side_length
new_width = output_side_length
if height > width:
new_height = output_side_length * height / width
else:
new_width = output_side_length * width / height
height_offset =(new_height - output_side_length)/2
width_offset =(new_width - output_side_length)/2
cropped_img = img[height_offset:height_offset + output_side_length,
width_offset:width_offset + output_side_length]return cropped_img
defpreprocess(images):
images_out =[]#final result#Resize and crop and compute mean!
images_cropped =[]for i in tqdm(range(len(images)*0+2)):#print(images[i])
X = cv2.imread(images[i])#X = cv2.resize(X, (455, 256))
X = centeredCrop(X,224)
images_cropped.append(X)#compute images mean
N =0
mean = np.zeros((1,3,224,224))for X in tqdm(images_cropped):
X = np.transpose(X,(2,0,1))#print(X.shape)#3,224,224#print(X[0,:,:].shape)#3,224#print(mean[0][0].shape)#224,224
mean[0][0]+= X[0,:,:]
mean[0][1]+= X[1,:,:]
mean[0][2]+= X[2,:,:]
N +=1
mean[0]/= N
#Subtract mean from all imagesfor X in tqdm(images_cropped):
X = np.transpose(X,(2,0,1))
X = X - mean
X = np.squeeze(X)
X = np.transpose(X,(1,2,0))
images_out.append(X)return images_out
6.数据加载
基本配置设置(my_train_labels是之前文件处理写入的路径)
batch_size =75
max_iterations =30000# Set this path to your dataset directory
my_train_labels ='/kaggle/working/my_train_labels.csv'