위의 그림 속 신경망은 3층으로 구성되어있지만 가중치를 갖는 층이 2개이기 때문에 2층 신경망 이라고 한다.
y=0 (b+w1x1+w2x2<=0) y=1 (b+w1x1+w2x2>0)
편향(bias)은 하나의 뉴런으로 입력된 모든 값을 다 더한 다음에(가중합이라고 합니다) 이 값에 더 해주는 상수입니다. 이 값은 하나의 뉴런에서 활성화 함수를 거쳐 최종적으로 출력되는 값을 조절하는 역할을 함
활성화 함수(activateion function) : 입력 신호의 총합을 출력 신호로 변환하는 함수. 변환된 신호를 다음 뉴런에 전달한다. 입력 신호의 총합이 활성화를 일으키는지를 정하는 역할을 한다.
a = b+w1x1+w2x2 #가중치가 달린 입력 신호와 편향의 총합 y=h(a) #a를 함수 h()에 넣어 y를 출력
3-2 활성화함수
시그모이드 함수 (sigmoid function)
신경망에서는 활성화 함수로 시그모이드 함수를 이용하여 신호를 변환하고 그 변환된 신호를 다음 뉴런에 전달한다.
시그모이드 함수 구현하기 브로드캐스트 기능: 넘파이 배열과 스칼라값의 연산을 넘파이 배열의 원소 각각과 스칼라값의 연산으로 바꿔 수행한다.
import numpy as np
import matplotlib.pylab as plt
def sigmoid(x):
return 1/(1+np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)
#브로드캐스트
#넘파이 배열과 스칼라값의 연산을 넘파이 배열의 원소 각각과 스칼라값의 연산으로 바꿔 수행
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()
계단함수 (step function)
def step_function(x):
return np.array(x>0, dtype=np.int)
##numpy 배열을 인수로 넣을 수 있게 하는 방법
#x = np.array([-1.0, 1.0, 2.0])
#y = x>0
#y를 출력하면 0보다 큰 x값은 True로, 0보다 작거나 같은 값은 False로 나온다.
#booleaan값을 int형으로 변환시키면 True는 0, False는 1이다.
x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()
딥러닝에서 어떤 모델을 사용하든 모델을 분석하는 과정을 train code를 사용하거나 test code를 사용하는 와중에 값을 확인할 때, 일부 vison 모델에서는 결과값을 opencv로 확인하고 싶을 때의 과정을 정리했다.
여기서 사용한 모델은 Yolact모델이다. (Yolact 모델 정리는 추후 backbone정리가 마무리가 되면 진행할 예정.. fpn과정의 연산이 모듈형태로 foward연산이 자동으로 실행돼서 연산과정을 확인할 수 없어서 시간이 조금 걸릴것으로 예상됨)
여기서는 mask가 씌워지는 결과는 각각 확인하고 싶었다.
뭔가 마스크라는 변수에 15개(object)의 텐서가 들어가 있다 현재 이 연산은 Tensor형태로 gpu에서 연산중이니 opencv에서 확인하기 위해서는 변환하는 과정이 있어야 한다. gpu -> cpu(메모리에 값을 복사) -> byte() float형태의 값을 integer값으로 변환해줘야 opencv에서 사용가능 -> numpy (tensor값을 numpy로 변환해야 opencv에서 확인가능)
# 실제 코드
(masks[0]* 255).byte().cpu().numpy()
cv2.imshow("test1",(masks[0]* 255).byte().cpu().numpy())
cv2.waitKey(0)
변환결과
변과결과 확인
마스킹 형태가 잘 나온걸 확인할 수 있다.
p.s train이나 test중간의 값을 확인하기 하다가 보면 tensor값의 경우 torch.Size([4, 3, 32, 32]) 이런식으로 channel값이 바뀌어 있는 경우가 있는데 이 경우에는 opencv 형식으로 변환해줘야 한다.
# torch.Size([4, 3, 32, 32]) 일 때 train_t = np.transpose(train, (0, 2, 3, 1)) train_t.shape
기능 맵이라고하는 활성화 맵은 입력 이미지 또는 다른 기능 맵과 같은 입력에 필터를 적용한 결과를 캡처합니다.
특정 입력 이미지에 대한 특성 맵을 시각화하는 아이디어는 특성 맵에서 감지되거나 보존되는 입력 특성을 이해하는 것입니다. 입력에 가까운 기능 맵은 작거나 세분화 된 세부 사항을 감지하는 반면 모델 출력에 가까운 기능 맵은보다 일반적인 기능을 캡처합니다. (1pixel이 의미하는 바가 layer를 거치기 전에는 부리의 일부분 깃털의 일부분이라면 layer가 진행되면 진행될수록 부리, 깃털, 날개, 몸톰, 새, 이미지천체 한 픽셀에 담기는 데이터 정보가 점점 커져간다. 이것 때문에 피라미드 구조가 나오게 됨)
기능 맵의 시각화를 탐색하려면 활성화를 만드는 데 사용할 수있는 VGG16 모델에 대한 입력이 필요합니다. 간단한 새 사진을 사용합니다. 특히, Chris Heald가 촬영 한 Robin 은 허용 라이센스에 따라 릴리스되었습니다.
사진을 다운로드하고 파일 이름이 ' bird.jpg '인 현재 작업 디렉토리에 배치합니다
STEP1. - 먼저 이미지를 VGG16에서 사용하는 input size로 가져옵니다
데이터 불러오기 -> 데이터 전처리 -> 모델 train&val -> 모델 test -> inference(service) [학습에서는 데이터의 dependency가 강력하기 때문에 데이터의 일관성이 굉장이 중요함. 본 이미지 데이터 분석은 나중에 이미지 프로젝트 진행시 이미지 데이터를 분석을 하기 위한 초석으로 보면 될 듯 싶다.
import cv2
from tensorflow.keras.models import Model
import numpy as np
from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
#load the image with the required shape
img = cv2.imread('bird.jpg',cv2.COLOR_BGR2RGB)
img = cv2.resize(img,(224,224))
print(img.__class__)
print(img.shape)
STEP2. - 데이터 차원 확장 및 전처리
데이터 차원확장은 이번에 사용하는 데이터가 하나이기 때문에 따로 차원확장을 진행해줬다. [ N, H, W, C], [ N, C, H, W] C,H,W의 순서는 opencv냐 아니냐에 달라질 수는 있으나 (tensorflow, pytorch의 차이도 존재) 기본적으로 4차원으로 들어가야한다.
# load the model
model = VGG16()
# summarize featu
model = Model(inputs=model.inputs, outputs=model.layers[1].output)
STEP4. - 예측하기
feature_maps = model.predict(img)
STEP5. - 결과확인
# plot all 64 maps in an 8x8 squares
square = 8
ix = 1
for _ in range(square):
for _ in range(square):
# specify subplot and turn of axis
ax = pyplot.subplot(square, square, ix)
ax.set_xticks([])
ax.set_yticks([])
# plot filter channel in grayscale
pyplot.imshow(feature_maps[0, :, :, ix-1], cmap='gray')
ix += 1
# show the figure
pyplot.show()
각 레이어에 대한 이미지 feature값들도 확인해보자
input에서 output으로 나오는 각각의 layer의 이미지들을 출력값으로 뽑은 이미지들이다.
# visualize feature maps output from each block in the vgg model
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import Model
from matplotlib import pyplot
from numpy import expand_dims
# load the model
model = VGG16()
# redefine model to output right after the first hidden layer
ixs = [2, 5, 9, 13, 17]
outputs = [model.layers[i].output for i in ixs]
model = Model(inputs=model.inputs, outputs=outputs)
# load the image with the required shape
img = load_img('bird.jpg', target_size=(224, 224))
# convert the image to an array
img = img_to_array(img)
# expand dimensions so that it represents a single 'sample'
img = expand_dims(img, axis=0)
# prepare the image (e.g. scale pixel values for the vgg)
img = preprocess_input(img)
# get feature map for first hidden layer
feature_maps = model.predict(img)
# plot the output from each block
square = 8
for fmap in feature_maps:
# plot all 64 maps in an 8x8 squares
ix = 1
for _ in range(square):
for _ in range(square):
# specify subplot and turn of axis
ax = pyplot.subplot(square, square, ix)
ax.set_xticks([])
ax.set_yticks([])
# plot filter channel in grayscale
pyplot.imshow(fmap[0, :, :, ix-1], cmap='gray')
ix += 1
# show the figure
pyplot.show()
This tutorial is divided into four parts; they are:
Visualizing Convolutional Layers
Pre-fit VGG Model
How to Visualize Filters
How to Visualize Feature Maps
환경 변수
tensorflow = 2.4.0 kereas = 2.4.3
1. Visualizing Convolutional Layers
신경망 모델은 일반적으로 불투명하다고합니다. 이것은 특정 결정이나 예측을 한 이유를 설명하는 데 부족하다는 것을 의미합니다.
컨볼 루션 신경망은 이미지 데이터와 함께 작동하도록 설계되었으며 그 구조와 기능은 다른 유형의 신경망보다 이해하기 어려운 측면이 있습니다.
특히, 모델은 작은 선형 필터와 활성화 맵 또는보다 일반적으로 기능 맵이라는 필터를 적용한 결과로 구성됩니다.
필터와 기능 맵을 모두 시각화 할 수 있습니다.
예를 들어, 라인 감지기와 같은 작은 필터를 설계하고 이해할 수 있습니다. 학습 된 컨볼 루션 신경망 내에서 필터를 시각화하면 모델 작동 방식에 대한 통찰력을 얻을 수 있습니다.
입력 이미지에 필터를 적용하고 이전 계층에서 출력 한 기능 맵에 생성 된 기능 맵은 모델의 특정 입력 지점에서 모델이 갖는 내부 표현에 대한 통찰력을 제공 할 수 있습니다.
이 튜토리얼에서는 컨볼 루션 신경망을 시각화하는 두 가지 접근 방식을 모두 살펴볼 것입니다.
2. Pre-fit VGG Model
시각화 해볼 모델은 VGG16입니다. keras에서 불러오기도 쉽고 사용하기도 쉬운데 성능이 좋기 때문입니다.
# load vgg model
from keras.applications.vgg16 import VGG16
# load the model
model = VGG16()
# summarize the model
model.summary()
# load vgg model
from keras.applications.vgg16 import VGG16
# load the model
model = VGG16()
# summarize the model
model.summary()
신경망 용어에서 학습 된 필터는 단순히 가중치이지만 필터의 특수한 2 차원 구조로 인해 가중치 값은 서로 공간적 관계를 가지며 각 필터를 2 차원 이미지로 플로팅하는 것은 의미가 있습니다
첫 번째 단계는 모델의 필터를 검토하여 작업해야하는 사항을 확인하는 것입니다.
이전 섹션에서 인쇄 된 모델 요약은 각 레이어의 출력 모양 (예 : 결과 피쳐 맵의 모양)을 요약합니다. 네트워크에서 필터 (가중치)의 모양에 대한 아이디어는 제공하지 않으며 레이어 당 총 가중치 수만 제공합니다.
model.layers 속성을 통해 모델의 모든 계층에 액세스 할 수 있습니다 .
각 레이어에는 layer.name 속성이 있습니다. 여기서 컨볼 루션 레이어에는 block # _conv # 와 같은 명명 컨볼 루션이 있습니다. 여기서 ' # '는 정수입니다. 따라서 각 레이어의 이름을 확인하고 ' conv ' 문자열이 포함되지 않은 레이어는 건너 뛸 수 있습니다.
# summarize filter shapes
for layer in model.layers:
# check for convolutional layer
if 'conv' not in layer.name:
continue
각 컨벌루션 계층에는 두 세트의 가중치가 있습니다.
하나는 필터 블록이고 다른 하나는 바이어스 값 블록입니다. layer.get_weights () 함수 를 통해 액세스 할 수 있습니다. 이러한 가중치를 검색 한 다음 그 모양을 요약 할 수 있습니다.
# get filter weights
filters, biases = layer.get_weights()
print(layer.name, filters.shape)
전체 코드 입니다.
# summarize filters in each convolutional layer
from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
# load the model
model = VGG16()
# summarize filter shapes
for layer in model.layers:
# check for convolutional layer
if 'conv' not in layer.name:
continue
# get filter weights
filters, biases = layer.get_weights()
print(layer.name, filters.shape)
모든 컨벌루션 레이어는 작고 해석하기 쉬운 3x3 필터를 사용한다는 것을 알 수 있습니다.
컨벌루션 신경망의 구조적 문제는 필터의 깊이가 필터에 대한 입력 깊이 (예 : 채널 수)와 일치해야한다는 것입니다.
빨강, 녹색 및 파랑에 대해 3 개의 채널이있는 입력 이미지의 경우 각 필터의 깊이가 3임을 알 수 있습니다 (여기서는 채널-마지막 형식으로 작업 함). 하나의 필터를 각 채널에 대해 하나씩 세 개의 이미지가있는 플롯으로 시각화하거나 세 개를 모두 단일 색상 이미지로 압축하거나 첫 번째 채널을보고 다른 채널이 동일하게 보일 것이라고 가정 할 수도 있습니다. 문제는 시각화하고 싶은 63 개의 다른 필터가 있다는 것입니다.
다음과 같이 첫 번째 레이어에서 필터를 검색 할 수 있습니다.
# retrieve weights from the second hidden layer
filters, biases = model.layers[1].get_weights()
가중치 값은 0.0을 중심으로하는 작은 양수 및 음수 값일 수 있습니다.
값을 쉽게 시각화 할 수 있도록 0-1 범위로 정규화 할 수 있습니다.(정규화에 대한 자세한 이야기는 다른 페이지에서 자세히 다루도록 하겠습니다.)
# normalize filter values to 0-1 so we can visualize them
f_min, f_max = filters.min(), filters.max()
filters = (filters - f_min) / (f_max - f_min)
이제 블록의 64 개 중 처음 6 개 필터를 열거하고 각 필터의 3 개 채널을 각각 플로팅 할 수 있습니다.
matplotlib 라이브러리를 사용하고 각 필터를 새로운 서브 플롯 행으로 플로팅하고 각 필터 채널 또는 깊이를 새 열로 플로팅합니다.
# plot first few filters
n_filters, ix = 6, 1
for i in range(n_filters):
# get the filter
f = filters[:, :, :, i]
# plot each channel separately
for j in range(3):
# specify subplot and turn of axis
ax = pyplot.subplot(n_filters, 3, ix)
ax.set_xticks([])
ax.set_yticks([])
# plot filter channel in grayscale
pyplot.imshow(f[:, :, j], cmap='gray')
ix += 1
# show the figure
pyplot.show()
아래는 전체 코드입니다
# cannot easily visualize filters lower down
from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
# load the model
model = VGG16()
# retrieve weights from the second hidden layer
filters, biases = model.layers[1].get_weights()
# normalize filter values to 0-1 so we can visualize them
f_min, f_max = filters.min(), filters.max()
filters = (filters - f_min) / (f_max - f_min)
# plot first few filters
n_filters, ix = 6, 1
for i in range(n_filters):
# get the filter
f = filters[:, :, :, i]
# plot each channel separately
for j in range(3):
# specify subplot and turn of axis
ax = pyplot.subplot(n_filters, 3, ix)
ax.set_xticks([])
ax.set_yticks([])
# plot filter channel in grayscale
pyplot.imshow(f[:, :, j], cmap='gray')
ix += 1
# show the figure
pyplot.show()
예제를 실행하면 각 필터에 대해 한 행, 각 채널에 대해 한 열에 대해 18개의 이미지가 출력된다.
어떤 경우에는 필터가 채널(첫 번째 행)에서 동일하고 다른 경우(마지막 행)필터가 다르다는 것을 알 수 있습니다.
어두운 사각형은 weight 부분이 작은 부분이고 밝은 사각형은 큰 weight를 나타내는데 이 직관을 활용하면 첫 번째 행의 필터가 왼쪽 상단의 빛에서 오른쪽 하단의 어두운 곳으로의 그라디언트를 감지하는다는 것을 알 수 있습니다.
시각화가 있지만 첫 번째 컨볼 루션 레이어의 64 개 필터 중 처음 6 개만 볼 수 있습니다. 64 개의 모든 필터를 하나의 이미지로 시각화하는 것이 가능합니다.
두 번째 컨벌루션 레이어에서 필터를 살펴 보려면 다시 64 개의 필터가 있지만 각 필터에는 입력 특성 맵과 일치하는 64 개의 채널이 있음을 알 수 있습니다. 64 개 필터 모두에 대해 한 행에있는 모든 64 개 채널을 보려면 (64x64) 4,096 개의 서브 플롯이 필요하므로 세부 정보를 확인하기 어려울 수 있습니다.