Spring Boot(1) | 개발환경 세팅 (Eclipse 등)
java 좋아하는 언어는 아니었지만 이제 java로 웹개발 해야한다… 진짜 이제 친해져야 해 :)
java 좋아하는 언어는 아니었지만 이제 java로 웹개발 해야한다… 진짜 이제 친해져야 해 :)
개념 정리보다는 내가 이해한 것과 궁금한 것 정리
2020 여름 아무것도 몰랐던 내가 웹 외주를 맡은 사건에 대하여…
web에 대해 1도 모른채 지인 분의 웹사이트를 개발하게 되었고 (2020 여름) 그 이후 유지보수도 해주겠다고 했던 것에 … 최근에 다시 코드를 살펴본 결과 유지보수를 위한 컴포넌트화가 안되어 있음은 물론이고 그냥 아주 엉망진창 스파게티 코드의 정석인 것이었다.
난 CNN에서 이해가 안되는 게 너무 많아
합성곱 연산을 통해 이미지의 feature를 extract하고 마지막에 fc 레이어를 통해 분류하는 구조
filter 개수 = output 채널 = feature map 개수 ?????????
filter에 따라 conv 연산 결과로 나오는 feature map이 다 다를텐데 filter는 어떻게, 누가 만드는 건가.
RGB 컬러 이미지에서 채널이 3개이면, 채널마다 각각 다른 필터가 적용되지만 결국 출력 feature map은 하나다. (해당 위치의 값들을 다 더함)
사전 기반이 아니라, 학습 데이터 내 자주 발생하는 패턴을 기반으로 단어의 경계선을 구분
from soynlp.utils import DoublespaceLineCorpus
from soynlp.noun import LRNounExtractor_v2
from soynlp.word import WordExtractor
train_data = DoublespaceLineCorpus("train.txt") # 데이터기반 패턴 학습
### 명사 추출
noun_extractor = LRNounExtractor_v2() # extractor 객체 생성
nouns = noun_extractor.train_extract(train_data) # train_data에서 명사 추출
### 단어 추출
word_extractor = WordExtractor() # extractor 객체 생성
words = word_extractor.train_extract(train_data) # train_data에서 단어 추출
NLP 기본 흐름
줄글 텍스트에서 단어 뽑아내기
1) 특수 문자 제거 hi
와 hi!
를 같은 단어로 처리 2) stopword 제거 is
, the
와 같이 의미보다는 문법적 기능을 가진 단어 제거 노이즈 제거와 같음 3) stemming love
, loved
, loves
가 모두 같은 love
로 처리 되도록 단어의 공통된 형태로 변환 normalize(정규화)와 같음
각 단어를 연속형 벡터로 표현하는 방법
컴퓨터는 텍스트를 어떻게 인식해야할까? 수치형 데이터로 어떻게 mapping 할까?
나무 --> [0.23, 0.44, 0.21 ...]
꽃 --> [0.29, 0.40, 0.8 ...]
이다 --> [0.913, 0.879, ...]
= 문맥을 이용
임베딩 벡터 간 합과 차로 단어의 의미적 특징을 활용할 수 있음
단어 임베딩 벡터 학습 알고리즘
주어진 문맥에서 발생하는 단어를 예측하는 문제를 통해 단어 임베딩 벡터를 학습
특정 단어들이 입력으로 주어졌을 때 계산되는 은닉층의 값이 임베딩 벡터
가 된다
from gensim.models import Word2Vec
# window: 문맥의 범위, 앞뒤 단어 개수
# vector_size: hidden node 개수, 벡터의 차원수
wv_model =Word2Vec( window=2, vector_size=300)
# input으로 쓰이는 단어들을 정수형 id로 변환하여 더욱 빠르게 학습
wv_model.build_vocab(input_data)
wv_model.train(input_data, total_examples=wv_model.corpus_count, epochs=10)
# "sad"와 유사한 단어
similar_sad = wv_model.wv.most_similar("sad")
'''
[('unhappy', 0.947895884513855), ('scared', 0.9425392746925354), ('hopeless', 0.9322786927223206), ('lonely', 0.9289621710777283), ('needy', 0.9200672507286072), ('paranoid', 0.9122549295425415), ('bitchy', 0.9073493480682373), ('angry', 0.9071397185325623), ('depressed', 0.9064767956733704), ('insecure', 0.9049254059791565)]
'''
# 두 단어의 임베딩 벡터 간 유사도
# 코사인 유사도
similar_sad_lonely = wv_model.wv.similarity("sad", "lonely")
'''
0.9289622
'''
BoW란 무엇인가
단어들의 순서는 전혀 고려하지 않고, 단어들의 출현 빈도(
frequency
)에만 집중하는 텍스트 데이터의 수치화 표현 방법
각 단어에 정수 인덱스를 부여하고, for문을 돌면서 카운트되도록 직접 구현할 수도 있지만, scikit-learn에 이미 구현되어 있다.
from sklearn.feature_extraction.text import CountVectorizer
text = ["가을 아침 내겐 정말 커다란 기쁨이야 가을 아침 내겐 정말 커다란 행복이야 응석만 부렸던 내겐",
"이른 아침 작은 새들 노랫소리 들려오면 언제나 그랬듯 아쉽게 잠을 깬다"]
cv = CounterVectorizer() # vectorizer 개체 생성
X = cv.fit_transform(text) # 리스트 안의 문자열이 각각 문서로 취급된다
print(X.shape) # (문서 개수, 전체 문서에서 등장하는 단어 개수)
### (2, 19)
print(X) # (문서 인덱스, 단어 인덱스) count
'''
(0, 0) 2
(0, 10) 2
(0, 4) 3
(0, 16) 2
(0, 17) 2
(0, 2) 1
(0, 18) 1
(0, 12) 1
(0, 7) 1
(1, 10) 1
(1, 13) 1
(1, 14) 1
(1, 8) 1
(1, 5) 1
(1, 6) 1
(1, 11) 1
(1, 1) 1
(1, 9) 1
(1, 15) 1
(1, 3) 1
'''
print(X.toarray())
'''
[[2 0 1 0 3 0 0 1 0 0 2 0 1 0 0 0 2 2 1]
[0 1 0 1 0 1 1 0 1 1 1 1 0 1 1 1 0 0 0]]
'''
print(cv.vocabulary_) # 단어-인덱스 정보
'''
{'가을': 0, '아침': 10, '내겐': 4, '정말': 16, '커다란': 17, '기쁨이야': 2, '행복이야': 18, '응석만': 12, '부렸던': 7, '이른': 13, '작은': 14, '새들': 8, '노랫소리': 5, '들려오면': 6, '언제나': 11, '그랬듯': 1, '아쉽게': 9, '잠을': 15, '깬다': 3}
'''
X.toarray()
의 [0][0]은 첫번째 문장(문서)에서 단어 인덱스가 0인 단어의 등장 빈도수CountVectorizer는 토큰화 + 벡터화 동시에 해준다.
보통 띄어쓰기 기준으로 단어를 끊어 토큰화하고 벡터화하기 때문에, 띄어쓰기로 단어가 나뉘지 않는 한국어에는 적용하기 어렵다.
ex. 사랑을, 사랑이구나, 사랑 -> 모두 다른 단어로 처리됨
아래 두 방법이 사실 똑같긴 한데,
1) CountVecetorizer 객체에 tokenizer
옵션을 konlpy
로 설정하기
from konlpy.tag import Okt
from sklearn.feature_extraction.text import CountVecetorizer
okt = Okt()
cv = CountVecetorizer(tokenizer=lambda x: okt.nouns(x))
2) konlpy
등으로 tokenizing을 먼저 하고, CountVectorizer
의 옵션을 조절하여 vectorizing만 수행
nouns = []
for doc in documents:
nouns.append(okt.nouns(doc))
cv = CountVectorizer(tokenizer=lambda x: x, lowercase=False) # lowercase 인자를 꼭 False로 해야 에러가 안난다.
X = cv.fit_transform(nouns)
2번 방법으로 하면 토큰화된 결과를 한 번 확인할 수 있음
연속된 N개의 단어를 기준으로 텍스트 분석을 수행
상대적으로 자주 발생하는 단어가 더 중요하다는 점을 반영
from sklearn.feature_extraction.text import TfidfVectorizer
# TfidfVectorizer을 불러옵니다. (stop_words 는 영어로 설정)
vectorizer = TfidfVectorizer(stop_words = 'english')
X = vectorizer.fit_transform(df_clean['Review Text'].str.lower())
RNN 모델을 생성하고 학습하기
Recurrent Neural Network
recurrent
하게 학습시키는 구조LSTM
, GRU
IMDb 데이터 학습
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow.keras import layers, Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing.sequence import pad_sequences
def load_data(num_words, max_len):
# imdb 데이터셋을 불러옵니다. 데이터셋에서 단어는 num_words 개를 가져옵니다.
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_words)
# 단어 개수가 다른 문장들을 Padding을 추가하여
# 단어가 가장 많은 문장의 단어 개수로 통일합니다.
X_train = pad_sequences(X_train, maxlen=max_len)
X_test = pad_sequences(X_test, maxlen=max_len)
return X_train, X_test, y_train, y_test
def build_rnn_model(num_words, embedding_len):
model = Sequential()
# TODO: [지시사항 1번] 지시사항에 따라 모델을 완성하세요.
model.add(layers.Embedding(input_dim=num_words, output_dim=embedding_len))
model.add(layers.SimpleRNN(16))
model.add(layers.Dense(1, activation="sigmoid"))
return model
def main(model=None, epochs=5):
# IMDb 데이터셋에서 가져올 단어의 개수
num_words = 6000
# 각 문장이 가질 수 있는 최대 단어 개수
max_len = 130
# 임베딩 된 벡터의 길이
embedding_len = 100
# IMDb 데이터셋을 불러옵니다.
X_train, X_test, y_train, y_test = load_data(num_words, max_len)
if model is None:
model = build_rnn_model(num_words, embedding_len)
# TODO: [지시사항 2번] 모델 학습을 위한 optimizer와 loss 함수를 설정하세요.
optimizer = Adam(learning_rate=0.001)
model.compile(optimizer=optimizer, loss="binary_crossentropy", metrics="accuracy")
# TODO: [지시사항 3번] 모델 학습을 위한 hyperparameter를 설정하세요.
hist = model.fit(X_train, y_train, epochs=epochs, batch_size=100, validation_split=0.2, shuffle=True, verbose=2)
# 모델을 테스트 데이터셋으로 테스트합니다.
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print()
print("테스트 Loss: {:.5f}, 테스트 정확도: {:.3f}%".format(test_loss, test_acc * 100))
return optimizer, hist
if __name__=="__main__":
main()
PIL (pillow) 라이브러리
아래와 같이 pip로 설치할 수 있다.
python3 -m pip install Pillow
from PIL from Image
그래픽 분야의 국룰 예시 이미지 Lenna 사용
img = Image.open("Lena.png")
Pillow의 Image 클래스에 구현된 open
메소드를 이용해 image 불러오기
(matplotlib) 불러온 이미지 시각화
from matplotlib.pyplot import imshow
imshow(img)
이미지 사이즈, 속성 확인하기
# size: 가로x세로 픽셀수, mode: 흑백/컬러
print("Size: {}, Mode: {}".format(img.size, img.mode))
(x1, y1): 잘라내기를 시작할 좌상단 좌표 (x2, y2): 잘라내기를 끝낼 우하단 좌표
img.crop((x1, y1, x2, y2))
imshow(img.crop((x1, y1, x2, y2)))
degree: 반시계 방향으로 회전할 각도
imshow(img.rotate(degree))
imshow(img.rotate(degree, expand=True)) # 이미지 잘리지 않도록 크기 조절
이미지 크기와 비율을 조절할 수 있다.
imshow(img.resize((128, 128))) # 사이즈(픽셀수) 바뀜
imshow(img.resize((128, 256))) # 비율이 바뀜
추가 모듈 import
from PIL import ImageEnhance
enhancer = ImageEnhance.Brightness(img) # 밝기 조절을 수행하는 enhancer 객체 생성
imshow(enhancer.enhance(2)) # 밝기 2배로 조절 (밝아짐)
imshow(enhancer.enhance(0.5)) # 밝기 절반, (어두워짐)
contrast_enhancer = ImageEnhance.Contrast(img)
imshow(contrast_enhancer.enhance(2))
convert
메소드 활용
import matplotlib.pyplot as plt
img_gray = img.convert("L")
print("흑백 사진 모드:", img_gray.mode)
imshow(img_gray, cmap=plt.get_cmap("gray"))
filter
메소드 활용
from PIL import ImageFilter
### 1. sharpening 필터
img_sharpen = img.filter(ImageFilter.SHARPEN)
### 2. blur 필터
img_blur = img.filter(ImageFilter.BLUR)
### 3. 경계선 탐지 필터
img_edge = img.filter(ImageFilter.FIND_EDGES)
### 필터를 여러번 적용해 필터 강도를 높일 수 있다.
img_blur_3 = img.filter(ImageFilter.BLUR)
img_blur_3 = img.filter(ImageFilter.BLUR)
img_blur_3 = img.filter(ImageFilter.BLUR)
copy and paste
### for문 이용
lines = []
with open("sample.txt") as f:
for row in f:
lines.append(f.strip())
### readlines() 이용
lines2 = []
with open("sample2.txt") as f:
lines2 = f.readlines() # 여러 줄 읽기
lines2 = [x.strip() for x in lines2] # 줄바꿈 문자 제거
최대 1, 최소 0이 되도록 선형 정규화
각 feature 별로 (column 별) 최솟값을 빼고 최댓값으로 나누기
for i in range(X.shape[1]): # feature의 개수만큼 반복 = 13
X[:, i] -= np.min(X[:, i]) # 해당 열의 minimum을 일괄적으로 빼기
X[:, i] /= np.max(X[:, i]) # 해당 열의 max 값으로 전체 열을 나누기
return X
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
lrmodel = LinearRegression()
lrmodel.fit(train_x, train_y)
beta_0 = lrmodel.coef_[0] # lrmodel로 구한 직선의 기울기
beta_1 = lrmodel.intercept_ # lrmodel로 구한 직선의 y절편
print("beta_0: %f" % beta_0)
print("beta_1: %f" % beta_1)
print("Loss: %f" % loss(X, Y, beta_0, beta_1))
pred = lrmodel.predict(test_x)
socre = lr_mode.score(test_x, test_y)
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
from sklearn.linear_model import ElasticNet
ridge_reg = Ridge(alpha=10)
lasso_reg = Lasso(alpha=10)
ElasticNet_reg = ElasticNet(alpha=0.001, l1_ratio=0.01)
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
loss = mean_absolute_error(y, y_pred)
import sklearn.decomposition
num_components = 3
pca = sklearn.decomposition.PCA(n_components=num_components)
pca.fit(X)
transform_res = pca.transform(X)
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix
svm = SVC()
svm.fit(train_X, train_y)
pred_y = svm.predict(test_X)
# SVM 분류 결과값을 출력합니다.
print("\nConfusion matrix : \n",confusion_matrix(test_y,pred_y))
print("\nReport : \n",classification_report(test_y,pred_y))
from sklearn.naive_bayes import GaussianNB
model = GaussianNB()
model.fit(train_X, train_y)
predicted = model.predict(test_X)
from sklearn.cluster import KMeans
kmeans = KMeans(init="random", n_clusters=3, random_state=100)
kmeans.fit(irisDF)
from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components=3, random_state=100)
gmm.fit(irisDF)
irisDF['cluster'] = gmm.predict(irisDF)
반복문
def loss(x, y, beta_0, beta_1):
N = len(x)
l = 0 # loss 값
for i in range(N):
l += (y[i] - (beta_0*x[i] + beta_1))**2
return l
numpy 연산
rss = np.sum(np.square(y - y_pred)) # RSS
mse = np.mean(np.square(y - y_pred)) # MSE
def kmeans(X, num_clusters, initial_centroid_indices):
import time
N = len(X)
centroids = X[initial_centroid_indices]
labels = np.zeros(N)
while True:
is_changed = False # 라벨이 바뀌었는지
for i in range(N):
distances = []
for centroid in centroids:
distances.append(distance(X[i], centroid))
if labels[i] != np.argmin(distances):
is_changed = True
labels[i] = np.argmin(distances) # 클러스터 0, 1, 2 중 하나
# print(labels)
### 새 중심점 계산
for k in range(num_clusters):
x = X[labels == k][:, 0]
y = X[labels == k][:, 1]
x = np.mean(x)
y = np.mean(y)
centroids[k] = [x, y]
if not is_changed:
break
return labels
### 유클리드 거리 norm
def distance(x1, x2):
return np.sqrt(np.sum((x1 - x2) ** 2))