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, GRUIMDb 데이터 학습
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))