본 포스팅은 다음 과정을 정리 한 글입니다.
Custom Models, Layers, and Loss Functions with TensorFlow
www.coursera.org/specializations/tensorflow-advanced-techniques
지난 시간 리뷰
2021.04.06 - [Artificial Intelligence/Keras] - [Tensorflow 2][Keras] Week 4 - Implementing ResNet
안녕하세요 이번 시간에는 VGG network를 실제로 구현해보고자 합니다.
들어가기 전에 Python function 중 vars()를 이용하는 법에 대해서 살펴보겠습니다.
이 함수를 통해 for 루프를 돌면서 여러 개의 variables를 한 번에 정의해 보겠습니다. (ex var1, var2, var3)
# Define a small class MyClass
class MyClass:
def __init__(self):
# One class variable 'a' is set to 1
self.var1 = 1
# Create an object of type MyClass()
my_obj = MyClass()
Python class들은 __dict__를 호출할 수 있습니다.
__dict__는 파이썬 dictionary로 객체의 instance variable과 값을 쌍으로 들고 있습니다.
my_obj.__dict__
Out : {'var1': 1}
만약에 vars()를 호출하면서 object를 매개변수로 넣으면, 이 것은 object의 __dict__ 속성을 call 하게 됩니다.
vars(my_obj)
{'var1': 1}
비슷하게 새로운 variable를 더 생성해 봅시다.
# Add a new instance variable and give it a value
my_obj.var2 = 2
# Calls vars() again to see the object's instance variables
vars(my_obj)
Out : {'var1': 1, 'var2': 2}
위와 같이 object에 instance variable을 추가하고 값을 대입할 수 있는 방법이 있고 그 외에 vars()를 통해 object에 instance variable을 추가하는 방법이 있습니다.
# Call vars, passing in the object. Then access the __dict__ dictionary using square brackets
vars(my_obj)['var3'] = 3
# Call vars() to see the object's instance variables
vars(my_obj)
Out : {'var1': 1, 'var2': 2, 'var3': 3}
동일하게 object의 instance variable이 추가되는 것을 알 수 있습니다.
이 것이 왜 필요하냐?!
객체의 instance variable에 액세스 하기 위해 다른 방법이 필요한 이유가 궁금하시죠?
vars()를 사용할 때 이제 변수 var3의 이름을 문자열로 전달할 수 있습니다.
이름이 비슷한 여러 변수(var4, var5, ... var9)를 사용하려고 할 때 편리하게 액세스 할 수 있는 방법이 있습니다.
다음 코드는 var4~var9까지를 0으로 만드는 코드입니다.
# Use a for loop to increment the index 'i'
for i in range(4,10):
# Format a string that is var
vars(my_obj)[f'var{i}'] = 0
# View the object's instance variables!
vars(my_obj)
Out : {'var1': 1, 'var2': 2, 'var3': 3, 'var4': 0, 'var5': 0, 'var6': 0, 'var7': 0, 'var8': 0, 'var9': 0}
파이썬에서 문자열 형식을 지정하는 두 가지 방법에 대해 설명드리겠습니다.
- f-string: f"var{i}"
- .format: "var{}".format(i)
# Format a string using f-string notation
i=1
print(f"var{i}")
# Format a string using .format notation
i=2
print("var{}".format(i))
Out : var1
var2
vars(self)를 사용하여 클래스 정의 내에서 클래스의 변수에 액세스 할 수 있습니다.
# Define a small class MyClass
class MyClass:
def __init__(self):
# Use vars(self) to access the class's dictionary of variables
vars(self)['var1'] = 1
# Create an object of type MyClass()
my_obj = MyClass()
vars(my_obj)
Out : {'var1': 1}
여기까지가 vars에 대한 설명이었습니다. 이제 VGG network를 만들어 봅시다.
# Please uncomment all lines in this cell and replace those marked with `# YOUR CODE HERE`.
# You can select all lines in this code cell with Ctrl+A (Windows/Linux) or Cmd+A (Mac), then press Ctrl+/ (Windows/Linux) or Cmd+/ (Mac) to uncomment.
class Block(tf.keras.Model):
def __init__(self, filters, kernel_size, repetitions, pool_size=2, strides=2):
super(Block, self).__init__()
self.filters = filters
self.kernel_size = kernel_size
self.repetitions = repetitions
# Define a conv2D_0, conv2D_1, etc based on the number of repetitions
for i in range(0, self.repetitions):
# Define a Conv2D layer, specifying filters, kernel_size, activation and padding.
vars(self)[f'conv2D_{i}'] = tf.keras.layers.Conv2D(self.filters, self.kernel_size, activation='relu', padding='same')
# Define the max pool layer that will be added after the Conv2D blocks
self.max_pool = tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size), strides=(strides, strides))
def call(self, inputs):
# access the class's conv2D_0 layer
conv2D_0 = self.conv2D_0
# Connect the conv2D_0 layer to inputs
x = conv2D_0(inputs)
# for the remaining conv2D_i layers from 1 to `repetitions` they will be connected to the previous layer
for i in range(1, self.repetitions):
# access conv2D_i by formatting the integer `i`. (hint: check how these were saved using `vars()` earlier)
conv2D_i = vars(self)[f'conv2D_{i}']
# Use the conv2D_i and connect it to the previous layer
x = conv2D_i(x)
# Finally, add the max_pool layer
max_pool = self.max_pool(x)
return max_pool
# Please uncomment all lines in this cell and replace those marked with `# YOUR CODE HERE`.
# You can select all lines in this code cell with Ctrl+A (Windows/Linux) or Cmd+A (Mac), then press Ctrl+/ (Windows/Linux) or Cmd+/ (Mac) to uncomment.
class MyVGG(tf.keras.Model):
def __init__(self, num_classes):
super(MyVGG, self).__init__()
# Creating blocks of VGG with the following
# (filters, kernel_size, repetitions) configurations
self.block_a = Block(64, 3, 2)
self.block_b = Block(128, 3, 2)
self.block_c = Block(256, 3, 3)
self.block_d = Block(512, 3, 3)
self.block_e = Block(512, 3, 3)
# Classification head
# Define a Flatten layer
self.flatten = tf.keras.layers.Flatten()
# Create a Dense layer with 256 units and ReLU as the activation function
self.fc = tf.keras.layers.Dense(256, activation='relu')
# Finally add the softmax classifier using a Dense layer
self.classifier = tf.keras.layers.Dense(num_classes, activation='softmax')
def call(self, inputs):
# Chain all the layers one after the other
x = self.block_a(inputs)
x = self.block_b(x)
x = self.block_c(x)
x = self.block_d(x)
x = self.block_e(x)
x = self.flatten(x)
x = self.fc(x)
x = self.classifier(x)
return x
dataset = tfds.load('cats_vs_dogs', split=tfds.Split.TRAIN, data_dir='data/')
# Initialize VGG with the number of classes
vgg = MyVGG(num_classes=2)
# Compile with losses and metrics
vgg.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Define preprocessing function
def preprocess(features):
# Resize and normalize
image = tf.image.resize(features['image'], (224, 224))
return tf.cast(image, tf.float32) / 255., features['label']
# Apply transformations to dataset
dataset = dataset.map(preprocess).batch(32)
# Train the custom VGG model
vgg.fit(dataset, epochs=10)
댓글