class PGDAdversary(nn.Module):
    """Module implementing the PGD adversarial attack on a given model."""
    def __init__(self, model, x_batch, max_epsilon):
        """
        :param model: Model under attack.
        :param x_batch: Batch of inputs to attack.
        :param max_epsilon: Maximum norm of the L_\infinity attack.
        """
        super(PGDAdversary, self).__init__()
        self.batch_size, self.input_size = x_batch.shape
        # print("Shape of input to attack:", self.batch_size, self.input_size)
        self.model = model
        self.x_batch = Parameter(x_batch, requires_grad=False)
        self.x_batch.requires_grad = False
        self.max_epsilon_norm = max_epsilon
        # The model is NOT trainable.
        for p in model.parameters():
            p.requires_grad = False
        # The epsilon is the attack.
        # Notice that we have one epsilon per input, _and_ per batch element.
        # Of course, we fine tune the epsilon of the attack to each individual batch element.
        # So the batches are NOT batches of learning; we learn individually the epsilon for
        # each batch member, and we use batches purely to speed up the computation.
        self.epsilon = Parameter(torch.Tensor(self.batch_size,
                                              self.input_size),
                                 requires_grad=True)
        self.epsilon.retain_grad()
        # print("Epsilon shape", self.epsilon.shape)
        # For each element of self.epsilon, we compute the min and max value of its range.
        # These are given by the [0, 1] constraints on range of x + epsilon, and by the
        # max_epsilon_norm constraint on epsilon.
        self.min_epsilon = Parameter(torch.clamp(x_batch, 0., max_epsilon),
                                     requires_grad=False)
        self.max_epsilon = Parameter(torch.clamp(1. - x_batch, 0, max_epsilon),
                                     requires_grad=False)
        # We initialize epsilon.
        self.epsilon.data.uniform_(-max_epsilon, +max_epsilon)
        # And we clip it to its range.
        self.clip_epsilon_to_range()

    def clip_epsilon_to_range(self):
        """Clips epsilon to its predetermined range."""
        self.epsilon.data = torch.max(self.epsilon, self.min_epsilon)
        self.epsilon.data = torch.min(self.epsilon, self.max_epsilon)

    def forward(self):
        # print("Trying with:", torch.max(torch.abs(self.epsilon)))
        x_adversarial = torch.clamp(self.x_batch + self.epsilon, 0., 1.)
        return self.model.forward(x_adversarial)
Exemple #2
0
class GCU(Module):
	def __init__(self, batch = 16, h=64, w=64, d=2048, V=32,outfeatures=256):
		super(GCU, self).__init__()
		
		
		self.ht = h
		self.wdth= w
		self.d = d
		self.no_of_vert = V
		self.outfeatures = outfeatures
		self.batch = batch
		self.W = Parameter(torch.cuda.FloatTensor(d,V))
		self.W.requires_grad = True
		self.W.retain_grad()
		self.variance = Parameter(torch.cuda.FloatTensor(d,V))
		self.variance.requires_grad = True
		self.variance.retain_grad()
		self.weight = Parameter(torch.cuda.FloatTensor(d, outfeatures))
		self.weight.requires_grad = True
		torch.nn.init.xavier_uniform(self.weight)
		torch.nn.init.xavier_uniform(self.W)
		torch.nn.init.xavier_uniform(self.variance)


		self.iden = torch.eye(self.d).cuda(1)
		self.iden = torch.cat((self.iden, self.iden))
		for i in range(int(np.log2(V))):
			self.iden = torch.cat((self.iden,self.iden), dim=1)

		
		
		self.count = 0
		
		
		

	def init_param(self,x):
		vari = x.clone()
		x.detach()
		c = np.reshape(vari.detach().numpy(), (self.ht*self.wdth, self.d))
		kmeans = KMeans(n_clusters=self.no_of_vert, random_state=0).fit(c)
		W = Parameter(torch.t(torch.tensor(np.array(kmeans.cluster_centers_).astype('float32'))))
		# print("Printing W\n", self.W)
		lab = kmeans.labels_
		c_s = np.square(c)
		sig1 = np.zeros((self.d, self.no_of_vert))
		sig2 = np.zeros((self.d, self.no_of_vert))
		count = np.array([0 for i in range(self.no_of_vert)])
		for i in range(len(lab)):
			sig1[:,lab[i]] += np.transpose(c[i])
			sig2[:,lab[i]] += np.transpose(c_s[i])
			count[lab[i]] += 1

		sig2 = sig2/count
		sig1 = sig1/count

		sig1 = np.square(sig1)

		variance = Parameter(torch.tensor((sig2 - sig1 + 1e-6	).astype('float32')))

		return W, variance
		# print("Printing variance\n", self.variance)


	def GraphProject(self,X):

		Adj = torch.cuda.FloatTensor(self.batch, self.no_of_vert,self.no_of_vert)
		Adj = Adj.cuda(1)
		Z = torch.cuda.FloatTensor(self.batch,self.d,self.no_of_vert)
		Z = Z.cuda(1)
		Q = torch.cuda.FloatTensor(self.batch, self.ht*self.wdth,self.no_of_vert)

		Q = Q.cuda(1)
		#print("Hello",Z.get_device(), Q.get_device())
		for i in range(self.no_of_vert):
			q1 = self.W[:,i]
			# print(q1)
			q = X - q1[None,None,None,:]
			# print("after subracting", q)
			# print("variance", self.variance[:,i])
			q = q/self.variance[:,i]
			
			q = torch.reshape(q,(self.batch, self.ht*self.wdth, self.d))

			q = q**2
			# print("after dividing", q)
			q = torch.sum(q, dim=2)
			# print("Prinitng\n", q)
			# q = torch.exp(-q*0.5)
			Q[:,:,i] = q
			# print("Prinitng q\n", self.Q[:,i])
		# print(torch.max(self.Q, 1)[0])
		Q -= torch.min(Q, 2)[0][:,:,None]
		Q = torch.exp(-Q*0.5)
		norm = torch.sum(Q, dim=2)
		# print(norm.shape)
		Q = torch.div(Q,norm[:,:,None])

		# print("Printing Q\n",self.Q)

		

		#print("the pixel-to-vertex assignment matrix Done")
		for i in range(self.no_of_vert):
			z1 = self.W[:,i]
			q = X - z1[None,None,None,:]
			z = q/self.variance[:,i]
			z = torch.reshape(z,(self.batch, self.ht*self.wdth, self.d))
			
			z = torch.mul(z,Q[:,:,i][:,:,None])

			z = torch.sum(z,dim=1)

			n = torch.sum(Q[:,:,i],dim=1)
			#print(z.shape, n.shape)
			if torch.equal(z,torch.cuda.FloatTensor(z.shape).fill_(0).cuda(1)) and torch.equal(n,torch.cuda.FloatTensor(n.shape).fill_(0).cuda(1)):
				z = torch.ones(z.shape)
			else:
				z = z/n[:,None]
			Z[:,:,i] = z

		norm = Z**2

		norm = torch.sum(norm, dim=1)
		# print("norm size",norm.shape)
		# print("Z \n",self.Z)
		Z = torch.div(Z,norm[:,None])

		#print("the vertex features Z Done", torch.transpose(Z,1,2).shape, Z.shape)
		#torch.cuda.synchronize()
		Adj = torch.matmul(torch.transpose(Z,1,2), Z)
		#print("the adjacency matrix A Done")

		return (Q, Z, Adj)

	def GraphProject_optim(self, X):

		Adj = torch.cuda.FloatTensor(self.batch, self.no_of_vert,self.no_of_vert)
		Adj = Adj.cuda(1)
		Z = torch.cuda.FloatTensor(self.batch,self.d,self.no_of_vert)
		Z = Z.cuda(1)
		Q = torch.cuda.FloatTensor(self.batch, self.ht*self.wdth,self.no_of_vert)

		Q = Q.cuda(1)
		X = torch.reshape(X,(self.batch, self.ht*self.wdth, self.d))
		zero = torch.cuda.FloatTensor(X.shape).fill_(0).cuda(1) 
		new = torch.cat((zero, X), dim=2)
		#print("Shapes", new.shape, zero.shape, X.shape)
		extend = torch.matmul(new, self.iden)
		#print(extend.shape)

		W = torch.reshape(self.W, (self.d*self.no_of_vert,))
		q = extend - W[None,None,:]
		variance = torch.reshape(self.variance, (self.d*self.no_of_vert,))
		q1 = q/variance[None, None, :]
		q = q1**2
		q = torch.reshape(q, (self.batch, self.ht*self.wdth, self.d , self.no_of_vert))
		q = torch.sum(q, dim=2)
		q = torch.reshape(q, (self.batch, self.ht*self.wdth, self.no_of_vert))
		Q = q

		Q -= torch.min(Q, 2)[0][:,:,None]
		Q = torch.exp(-Q*0.5)
		norm = torch.sum(Q, dim=2)
		# print(norm.shape)
		Q = torch.div(Q,norm[:,:,None])

		#print(Q.shape)

		z = torch.reshape(q1, (self.batch,  self.d , self.ht*self.wdth , self.no_of_vert))
		z = torch.mul(z,Q)
		z = torch.sum(z, dim=2)
		#print("MIN",torch.min(torch.abs(z)), z.shape)
		z = torch.add(z, 10e-8)/torch.add(torch.sum(Q,dim=1), 10e-8)

		norm = z**2
		norm = torch.sum(norm, dim=1)
		# print("norm size",norm.shape)
		# print("Z \n",self.Z)
		Z = torch.div(Z,norm)

		#print("the vertex features Z Done")
		Adj = torch.matmul(torch.transpose(Z,1,2), Z)

		return (Q, Z, Adj)



	def GraphReproject(self, Z_o,Q):
		X_new = torch.matmul(Z_o,Q)
		return torch.reshape(X_new, (self.batch, self.outfeatures, self.ht, self.wdth))

	def forward(self, X):
		X = torch.reshape(X,(self.batch, self.ht, self.wdth, self.d)).float()
		# if self.count == 0:
		# 	with torch.no_grad():
		# 		self.W, self.variance = self.init_param(X)
		# 	self.count += 1
		
		
		
		Q, Z, Adj = self.GraphProject_optim(X)
		# print("Prinitng Z\n",self.Z)
		#print("Hello1", self.weight.get_device())
		out = torch.matmul(torch.transpose(Z,1,2), self.weight)
		out = torch.matmul(Adj, out)
		Z_o = F.relu(out)

		out = self.GraphReproject(Q, Z_o)
		#out = out.view(self.batch, self.outfeatures, self.ht, self.wdth) #usample requires 4Dtensor
		#print("Prinitng Z", Z.shape)
		
		return out