2 분 소요

Layer = Block 딥러닝은 결국 블록 반복의 연속이다. like resnet, transformer

torch.nn.Module

딥러닝을 구성하는 layer의 base class input,output, forward, backward 정의 학습대상이 되는 parameter 정의

nn.Parameter

학습 weight 값들 정의 Tensor 객체의 상속 객체 nn.Module 내에 attribute 될 때는, required_grad = True 로 지정되어 학습 대상이 되어야함

parameter 지정 (사실 linear같은 함수 쓰면 알아서 생성되기 때문에 따로 만들 일은 거의 없다)

class MyLiner(nn.Module):

	def __init__(self, in_features, out_features, bias=True):

		super().__init__()
	
		self.in_features = in_features
	
		self.out_features = out_features
		#parameter 지정 (크기 유의)
		self.weights = nn.Parameter(
			torch.randn(in_features, out_features))
	
		self.bias = nn.Parameter(torch.randn(out_features))
	
	  
	
	def forward(self, x : Tensor):

		return x @ self.weights + self.bias

입력값 생성, layer 지난 결과 보기

x = torch.randn(5,7)

layer = MyLiner(7, 12)

layer(x).shape

# torch.Size([5, 12])

layer의 Parameter 보기

for value in layer.parameters():

print(value)

** Tensor 로 하면 prarameters()로 했을 때 값이 안 뜸

backward

layer에 있는 parameter미분 수행 forward 결과값(예측치) , 실제 간의 차이 -> loss 에 대해 미분수행 해당 값으로 parameter 업데이트

criterion = torch.nn.MSELoss()

optimizer = torch.optim.SGD(model.parameters(), lr=learningRate)

for epoch in range(epochs):
	# Converting inputs and labels to Variable
	
	if torch.cuda.is_available():
	
		inputs = Variable(torch.from_numpy(x_train).cuda())
		
		labels = Variable(torch.from_numpy(y_train).cuda())
		
	else:
	
		inputs = Variable(torch.from_numpy(x_train))
		
		labels = Variable(torch.from_numpy(y_train))

  

	# Clear gradient buffers because we don't want any gradient from previous epoch to carry forward, dont want to cummulate gradients
	
	optimizer.zero_grad()
	
	  
	
	# get output from the model, given the inputs
	
	outputs = model(inputs)
	
	  
	
	# get loss for the predicted output
	
	loss = criterion(outputs, labels)
	
	print(loss)
	
	# get gradients w.r.t to parameters
	
	loss.backward()
	
	  
	
	# update parameters
	
	optimizer.step()

  

	print('epoch {}, loss {}'.format(epoch, loss.item()))

여기선 한번에 다 넣지만 보통은 DataLoader를 통해 잘라서 넣는다.

Backward from the scratch (수기 backward)

실제 backward는 Module 단계에서 직접 지정가능 Module에서 backward와 optimizer 오버라이팅 사용자가 직접 미분 수식 써야함(순서 알고 ㅇㅇ)

데이터 불러오는 환경

## configure root folder on your gdrive
data_dir = "./data"

## custom transformer to flatten the image tensors
class ReshapeTransform:
    def __init__(self, new_size):
        self.new_size = new_size

    def __call__(self, img):
        result = torch.reshape(img, self.new_size)
        return result

## transformations used to standardize and normalize the datasets
# 트랜스폼을 통해 데이터를 원래 형태에서 맞는 형태(텐서)로 바꿔줌
data_transforms = {
    'train': transforms.Compose([
        transforms.Resize(224),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        ReshapeTransform((-1,)) # flattens the data
    ]),
    'val': transforms.Compose([
        transforms.Resize(224),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        ReshapeTransform((-1,)) # flattens the data
    ]),
}

## load the correspoding folders
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) 
				  for x in ['train', 'val']}

## load the entire dataset; we are not using minibatches here
train_dataset = torch.utils.data.DataLoader(image_datasets['train'],
                                            batch_size=len(image_datasets['train']),
                                            shuffle=True)
test_dataset = torch.utils.data.DataLoader(image_datasets['val'],
                                           batch_size=len(image_datasets['val']),
                                           shuffle=True)

데이터 불러오기

## load the entire dataset
x, y = next(iter(train_dataset))

## print one example
dim = x.shape[1]
print("Dimension of image:", x.shape, "\n", 
      "Dimension of labels", y.shape)

plt.imshow(x[160].reshape(1, 3, 224, 224).squeeze().T.numpy())

logistic regression 실행

class LR(nn.Module):
    def __init__(self, dim, lr=torch.scalar_tensor(0.01)):
        super(LR, self).__init__()
        # intialize parameters 초기값 설정
        self.w = torch.zeros(dim, 1, dtype=torch.float).to(device)
        self.b = torch.scalar_tensor(0).to(device)
        self.grads = {"dw": torch.zeros(dim, 1, dtype=torch.float).to(device),
                      "db": torch.scalar_tensor(0).to(device)}
        self.lr = lr.to(device)

    def forward(self, x):
        ## compute forward
        z = torch.mm(self.w.T, x) + self.b
        a = self.sigmoid(z)
        return a

    def sigmoid(self, z):
        return 1/(1 + torch.exp(-z))

    def backward(self, x, yhat, y):
        ## compute backward
        self.grads["dw"] = (1/x.shape[1]) * torch.mm(x, (yhat - y).T)
        self.grads["db"] = (1/x.shape[1]) * torch.sum(yhat - y)
    
    def optimize(self):
        ## optimization step
        self.w = self.w - self.lr * self.grads["dw"]
        self.b = self.b - self.lr * self.grads["db"]

## utility functions
def loss(yhat, y):
    m = y.size()[1]
    return -(1/m)* torch.sum(y*torch.log(yhat) + (1 - y)* torch.log(1-yhat))

def predict(yhat, y):
    y_prediction = torch.zeros(1, y.size()[1])
    for i in range(yhat.size()[1]):
        if yhat[0, i] <= 0.5:
            y_prediction[0, i] = 0
        else:
            y_prediction[0, i] = 1
    return 100 - torch.mean(torch.abs(y_prediction - y)) * 100

카테고리:

업데이트:

댓글남기기