IPv6: IPv4 의 주소 개수 한계로 등장한 주소 체계, 현재는 전부 IPv6를 사용하는데 IPv4로 설정하면 자동으로 변환을 수행. 128비트 주소 체계로 16비트씩 8개의 영역으로 구분을 하고 각 16비트는 16진수 4자리로 표현하고 중복되는 부분을 생략할 수 있도록 설계
GTSRB\Final_Training\Images 디렉토리 안에 디렉토리 별로 이미지가 ppm 확장자로 분류되어 있다.
- ppm: 무손실 압축 이미지 파일 형식
- image 크기: 32 x 32
- 신경망 구조를 만들 때 선택 사항
2차원 컨볼루션에서 필터 개수 와 커널 크기
Max Pool 에서의 커널 크기
Fully Connected 계층(Dense)에서의 유닛 개수
계층 별 배치 크기, 최적화 알고리즘, 학습률, 할성화 함수, epoch 수 등
- 이미지 전처리
이미지 크기를 32*32로 수정
43개의 레이블을 생성: 디렉토리 이름이 레이블
표지판의 경우 구분해야 할 것은 색상이 아니라 모양: 이미지를 흑백으로 변경
데이터를 다룰 때 목적을 먼저 생각하고 작업을 시작해야 한다. (도메인)
- 필요한 패키지 와 상수 선언
클래스 개수와 이미지의 크기를 변수에 저장
이 두개의 절대로 변하지 않을 값
변하지 않는 값을 장할 변수의 이름은 모두 대문자로 작성하는 것이 좋다.
SNAKE 표기법이라고 한다.
N_CLASSES = 43
RESIZED_IMAGE = (32, 32)
# 모듈
import matplotlib.pyplot as plt
#디렉토리를 핸들링 할 때 사용하는 모듈
import glob
from skimage.color import rgb2lab
from skimage.transform import resize
import numpy as np
from collections import namedtuple
from sklearn.model_selection import train_test_split
- 이미지 전처리를 위한 함수
이름이 있는 튜플 생성 - 다른 언어에서는 튜플을 이런 형태로 만든다.
튜플의 원래 목적은 변경할 수 없는 하나의 행(record, row)을 표현하기 위한 것
인덱스가 아니라 이름으로 구별하는 것이 타당
Dataset = namedtuple('Dataset', ['X', 'y'])
# 포맷 변경해주는 함수
def to_tf_format(imgs):
return np.stack([img[:, :, np.newaxis] for img in imgs], axis=0).astype(np.float32)
- 이미지 디렉토리에 있는 모든 이미지들에 라벨링을 하기 위한 작업 - 이미지의 크기 변경도 여기서 수행
def read_dataset_ppm(rootpath, n_labels, resize_to):
#이미지 데이터 와 라벨을 저장할 list
images = []
labels = []
for c in range(n_labels):
#루트경로/00001/ 형태로 이미지 경로를 생성
full_path = rootpath + "/" + format(c, '05d') + "/"
#각 이미지 디렉토리를 순회하면서 확장자가 ppm 인 파일의 경로를 가지고
for img_name in glob.glob(full_path + "*.ppm"):
#이미지 읽어오기
img = plt.imread(img_name).astype(np.float32)
#이미지를 정규화
img = rgb2lab(img / 255.0)[:, :,0]
#이미지 크기를 조정
if resize_to:
img = resize(img, resize_to, mode='reflect')
#라벨 생성
#43개 짜리 배열을 만들어서 자신의 인덱스에 해당하는 값에만 1을 대입
#원핫 인코딩 된 라벨
label = np.zeros((n_labels, ), dtype=np.float32)
label[c] = 1.0
images.append(img.astype(np.float32))
labels.append(label)
return Dataset(X = to_tf_format(images).astype(np.float32), y = np.matrix(labels).astype(np.float32))
#모델 만들기
model = keras.Sequential()
#입력 층을 합성곱 층을 사용
model.add(keras.layers.Conv2D(32, kernel_size=3, activation="relu",
padding='same', input_shape=(28, 28, 1)))
model.add(keras.layers.MaxPooling2D(2))
model.add(keras.layers.Conv2D(64, kernel_size=3, activation="relu",
padding='same'))
model.add(keras.layers.MaxPooling2D(2))
#데이터를 1차원으로 만들어주는 층
model.add(keras.layers.Flatten())
#Dense 는 1차원의 데이터만 사용
model.add(keras.layers.Dense(100, activation="relu"))
#드랍 아웃 적용
model.add(keras.layers.Dropout(0.4))
model.add(keras.layers.Dense(10, activation="softmax"))
# 모델 확인
model.summary()
4. 모델 컴파일 (훈련)
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
#체크 포인트
checkpoint_cb = keras.callbacks.ModelCheckpoint("best-cnn-model.keras")
#2번의 epoch 동안 점수가 좋아지지 않으면 조기 종료
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2,
restore_best_weights=True)
history = model.fit(train_scaled, train_target, epochs=20,
validation_data=(val_scaled, val_target),
callbacks=[checkpoint_cb, early_stopping_cb])
4. 모델 평가
model.evaluate(val_scaled, val_target)
아래 합성곱 층으로 내려갈 때 뉴런의 개수를 늘렸는데 중간에 MaxPooling2D(Dropout을 적용해도 동일) 을 적용했기 때문에 실제 파라미터의 개수가 줄어들어 사용되므로 늘린 티가 나지 않음
tmp_coloumns = [pop.columns.get_level_values(0)[n] + \
pop.columns.get_level_values(1)[n]
for n in range(0,len(pop.columns.get_level_values(0)))]
pop.columns = tmp_coloumns
pop.head()
plt.figure(figsize=(8, 11))
# 지역 이름 표시
for idx, row in draw_korea_raw_stacked.iterrows():
# 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시
# (중구, 서구)
if len(row['ID'].split())==2:
dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
elif row['ID'][:2]=='고성':
dispname = '고성'
else:
dispname = row['ID']
# 시도 경계 그리기
for path in BORDER_LINES:
ys, xs = zip(*path)
plt.plot(xs, ys, c='black', lw=1.5)
#y축의 위아래 변경
plt.gca().invert_yaxis()
#plt.gca().set_aspect(1)
#축과 라벨 제거
plt.axis('off')
#자동 레이아웃 설정
plt.tight_layout()
plt.show()
# draw_korea_raw_stacked와 pop의 도시이름 일치시키기
#draw_korea_raw_stacked 와 pop 의 도시이름 비교
print(set(draw_korea_raw_stacked['ID'].unique()) - set(pop['ID'].unique()))
print(set(pop['ID'].unique()) - set(draw_korea_raw_stacked['ID'].unique()))
#일치하지 않는 데이터 삭제
tmp_list = list(set(pop['ID'].unique()) - set(draw_korea_raw_stacked['ID'].unique()))
for tmp in tmp_list:
pop = pop.drop(pop[pop['ID']==tmp].index)
print(set(pop['ID'].unique()) - set(draw_korea_raw_stacked['ID'].unique()))
def drawKorea(targetData, blockedMap, cmapname):
gamma = 0.75
#인구수 데이터의 크고 낮음을 분류하기 위한 값 만들기
whitelabelmin = (max(blockedMap[targetData]) -
min(blockedMap[targetData]))*0.25 + \
min(blockedMap[targetData])
#컬럼이름을 대입하기
datalabel = targetData
#최대값과 최소값 구하기
vmin = min(blockedMap[targetData])
vmax = max(blockedMap[targetData])
#x 와 y를 가지고 피봇 테이블 만들기
mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData)
#데이터가 존재하는 것 골라내기
masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)
#그래프 영역 크기 만들기
plt.figure(figsize=(9, 11))
#색상 설정
plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname,
edgecolor='#aaaaaa', linewidth=0.5)
# 지역 이름 표시
for idx, row in blockedMap.iterrows():
# 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시
#(중구, 서구)
if len(row['ID'].split())==2:
dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
elif row['ID'][:2]=='고성':
dispname = '고성'
else:
dispname = row['ID']
# 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시
if len(dispname.splitlines()[-1]) >= 3:
fontsize, linespacing = 10.0, 1.1
else:
fontsize, linespacing = 11, 1.
#글자색상 만들기
annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
#텍스트 출력하기
plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold',
fontsize=fontsize, ha='center', va='center', color=annocolor,
linespacing=linespacing)
# 시도 경계 그리기
for path in BORDER_LINES:
ys, xs = zip(*path)
plt.plot(xs, ys, c='black', lw=2)
plt.gca().invert_yaxis()
plt.axis('off')
cb = plt.colorbar(shrink=.1, aspect=10)
cb.set_label(datalabel)
plt.tight_layout()
plt.show()
# 인구수 합계로 Catrogram 그리기
drawKorea('인구수합계', pop, 'Blues')
#소멸위기지역으로 Cartogram 그리기
pop['소멸위기지역'] = [1 if con else 0 for con in pop['소멸위기지역']]
drawKorea('소멸위기지역', pop, 'Reds')