<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yugyeong_929.log</title>
        <link>https://velog.io/</link>
        <description>M. Sc in Computer Science and Engineering, Mar 2024 to present / B. Sc in Computer Engineering, Mar 2020 to Feb 2024</description>
        <lastBuildDate>Mon, 24 Feb 2025 18:38:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yugyeong_929.log</title>
            <url>https://velog.velcdn.com/images/yugyeong_929/profile/bec618da-464b-4459-b733-8a9a17f4345e/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yugyeong_929.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yugyeong_929" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[UoT] Introduction to Deep Learning (2)]]></title>
            <link>https://velog.io/@yugyeong_929/UoT-Introduction-to-Deep-Learning-2</link>
            <guid>https://velog.io/@yugyeong_929/UoT-Introduction-to-Deep-Learning-2</guid>
            <pubDate>Mon, 24 Feb 2025 18:38:39 GMT</pubDate>
            <description><![CDATA[<h3 id="week3">Week3</h3>
<h4 id="anns-part2">ANNs Part2</h4>
<ol>
<li>Neural Network Architecture
Architecture: 신경망 내 뉴런과 연결 구조를 설명하는 개념
Multi-Layer Perceptron (MLP):</li>
</ol>
<ul>
<li>Feed-Forward 및 Fully-Connected</li>
<li>Linear Layers + Nonlinear Activations</li>
</ul>
<p>Ex) MLP, CNN, RNN..</p>
<ol start="2">
<li>Neural Network Training</li>
</ol>
<ul>
<li>Training: 데이터에서 모델 가중치 및 파라미터를 효과적으로 학습하는 과정</li>
<li>Loss function: 모델의 예측이 실제 값과 얼마나 차이가 있는지 측정</li>
<li>Optimizer: 모델의 가중치를 조정하여 최적의 출력을 도출<ul>
<li>method: (1) 무작위로 가중치를 선택<pre><code>    (2) 한 번에 하나의 가중치를 변경하여 오류를 줄이는 방향으로 조정
    (3) Gradient Descent 사용</code></pre></li>
</ul>
</li>
</ul>
<p>Gradient Descent</p>
<ul>
<li>1-layer의 경우: 경사 방향을 따라 가중치를 조정하여 최소 손실점으로 이동.</li>
<li>2-layer의 경우: non-convex 표면에서 최적화를 수행해야 함.</li>
</ul>
<p>Critical Points (임계점) 유형</p>
<ul>
<li>극소값(Local Minima)</li>
<li>극대값(Local Maxima)</li>
<li>안장점(Saddle Point)</li>
<li>평탄한 영역(Plateau)</li>
</ul>
<ol start="3">
<li>Auto Differentiation</li>
</ol>
<ul>
<li>뉴럴 네트워크에서 기울기를 직접 계산하는 것은 복잡하고 오류 발생 가능성이 높음.</li>
<li>자동 미분을 지원하는 프레임워크: Pytorch, Tensorflow, Keras, Theano 등</li>
<li>연산 그래프(Computation Graph)를 활용한 미분 계산</li>
</ul>
<ol start="4">
<li>Multi-Class Classification</li>
</ol>
<ul>
<li>숫자 0~9 중 하나를 분류하는 문제</li>
</ul>
<ol start="5">
<li>Hyperparameter Tuning</li>
</ol>
<ul>
<li><p>Hyperparameter:</p>
<ul>
<li>Batch Size</li>
<li>Learning Rate</li>
<li>Size of Network (레이어 개수, 뉴런 개수)</li>
<li>Activation Function</li>
</ul>
</li>
<li><p>Batching</p>
<ul>
<li>한 번의 학습에서 n개의 샘플을 사용하여 평균 손실을 계산</li>
<li>작은 배치 -&gt; 최적호 과정이 불안정</li>
<li>너무 큰 배치 -&gt; 계산 비용이 커짐</li>
</ul>
</li>
<li><p>Learning Rate</p>
<ul>
<li>너무 작으면 학습이 오래 걸림.</li>
<li>너무 크면 발산(unstable)</li>
<li>학습이 진행될수록 학습률을 줄이는 방식 사용</li>
</ul>
</li>
<li><p>최적화 기법</p>
<ul>
<li>SGD</li>
<li>Momentum</li>
<li>RMSProp</li>
<li>Adam (SGD + Momentum + RMSProp)</li>
</ul>
</li>
</ul>
<ol start="6">
<li>Regularization</li>
</ol>
<ul>
<li>L2 정규화(Weight Decay)<ul>
<li>가중치의 크기를 줄여 모델이 복잡해지는 것을 방지</li>
</ul>
</li>
<li>L1 정규화(Lasso)<ul>
<li>가중치를 0으로 만들어 feature selection이 가능</li>
</ul>
</li>
<li>Dropout<ul>
<li>무작위로 뉴런을 비활성화하여 과적합 방지</li>
</ul>
</li>
</ul>
<h3 id="예상-문제">예상 문제</h3>
<ol>
<li>What is ANN?</li>
</ol>
<p>An ANN is a machine learning model inspired by the way neurons in the human brain process information. It consists of interconnected neurons with weights and can learn patterns from data to perform tasks such as predictions, classification, and regression.</p>
<ol start="2">
<li>Describe the key features of multilayer perceptron (MLP).</li>
</ol>
<p>A MLP is a feed-forward neural network consisting of at least three layers (input layer, hidden layer output layer). Neurons in each layer have weights, and non-linearity is introduced through activation functions. MLPs are fully connected an d typically include linear layers followed by non-linear activation functions such as ReLU or sigmoid.</p>
<ol start="3">
<li>Describe the role of loss functions in the learning process of neural networks.</li>
</ol>
<p>A loss function measures the difference between a model&#39;s predictions and the actual values. It is used in optimization algorithms like Gradient Descent to help the model find the optimal weights. Common loss functions include MSE and Cross-Entropy Loss.</p>
<ol start="4">
<li>What is Gradient Descent?</li>
</ol>
<p>Gradient Descent is an optimization algorithm that updates weights in a neural network to minimize the loss function. It computes the gradient of the loss function and adjusts weights accordingly. Common variants include Stochastic Gradient Descent (SGD), Momentum, RMSProp, and Adam.</p>
<ol start="5">
<li>Explain the difference between binary classification and multi-class classification in PyTorch.</li>
</ol>
<p>In binary classification, there is a single output neuron with a Sigmoid activation function, and the loss function used is BCEWithLogitsLoss().
In multi-class classification, the number of output neurons equeals the number of classes, and Softmax activation is applied. The loss function used is CrossEntropyLoss()</p>
<ol start="6">
<li>What is batch size, and explain the problem when it is too large or too small.</li>
</ol>
<p>Batch size refers to the number of samples used in a single optimiztion step.
If too small, training becomes unstable, and the loss function fluctuates frequently.
If too large, computational cost increases, and optimization may slow down.</p>
<ol start="7">
<li>Explain overfitting and how to prevent it.</li>
</ol>
<p>Overfitting occurs when a model is too optimized to the training data and lacks generalization to new data. It can be prevented using Dropout, L1/L2 Regularization, Data Augmenation, and Early Stopping.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UoT] Introduction to Deep Learning (1)]]></title>
            <link>https://velog.io/@yugyeong_929/UoT-Introduction-to-Deep-Learning-1</link>
            <guid>https://velog.io/@yugyeong_929/UoT-Introduction-to-Deep-Learning-1</guid>
            <pubDate>Mon, 24 Feb 2025 02:49:21 GMT</pubDate>
            <description><![CDATA[<h2 id="deep-learning-mid-term-test-요약-및-예상-문제">Deep Learning Mid term test 요약 및 예상 문제</h2>
<h3 id="week1">Week1</h3>
<ul>
<li><p>What is AI?
  AI is the intelligence of machines and the branch of computer science that aims to create it.
  AI is the science and engineering of making intelligent machines, especially intelligent computer programs.
  AI is often used to describe machines that mimic “cognitive” functions that humans associate with the human mind, such as “learning” and “problem solving”.</p>
</li>
<li><p>Unsupervised Learning: This type of learning focuses on finding patterns, regularities or structure in unlabeled data.</p>
</li>
</ul>
<h3 id="week2">Week2</h3>
<ol>
<li><p>ANN의 개요
 Motivation problem
 : 자동차 vs 트럭 분류기 문제를 통해 이미지 분류 개념 설명.
 : 입력(이미지) -&gt; 출력(고정된 범주의 하나로 할당)</p>
<p> 컴퓨터가 보는 방식</p>
<ul>
<li><p>픽셀값 행렬 (0~255 사이의 값)</p>
</li>
<li><p>RGB(컬러) 이미지: 3개의 채널로 구성됨</p>
<p>시각 인식의 어려움</p>
</li>
<li><p>Veiwpoint variation: 카메라 움직임에 따라 픽셀 값이 모두 변함.</p>
</li>
<li><p>Interclass variation: 세부 카테고리로 세분화 가능.</p>
</li>
<li><p>Background Clutter(배경 복잡성), illumination(조명), occlusion(가림) 등 다양한 도전적 과제</p>
</li>
</ul>
</li>
<li><p>머신러닝 기반 이미지 분류 단계
 Step1: 데이터셋 준비
 이미지의 픽셀 값 가져오기: RGB 이미지 -&gt; 각 픽셀의 [R, G, B] 값으로 구성 또는 grayscale 변환 후 1차원 벡터로 변환. 
 Step2: 데이터셋 분할
 Train/Validation/Test</p>
</li>
</ol>
<ol start="3">
<li><p>머신러닝 기초 모델
 Baseline 모델 선택</p>
<ul>
<li>Scikit-learn의 대표적인 머신러닝 모델 활용 가능:
  -&gt; KNN, Logistic Regression, SVM, Random Forests</li>
<li>Logistic Regression 적용
  -&gt; 낮은 성능을 보임
  -&gt; 왜 성능이 낮을까?<pre><code>  : 이미지 데이터의 고차원 특성을 단순 선형 모델로 설명하기 어려움.
  : Feature Engineering 필요</code></pre></li>
</ul>
</li>
<li><p>Feature Engineering</p>
<ul>
<li><p>이미지 데이터를 단순히 픽셀로 표현한 것이 아니라, 자동차의 길이, 너비, 높이, 크기 등 의미 있는 feature 추출 가능.</p>
</li>
<li><p>새로운 feature를 사용하여 logistic regression 적용 -&gt; 성능 향상
문제점: feature를 수동으로 선택해야 함. 적절한 feature를 고르는 것이 어려움. 고차원 데이터에서는 feature가 폭발적으로 증가할 가능성이 있음.</p>
<p>해결책: ANN 활용 -&gt; 머신러닝 모델이 자동으로 의미있는 특징을 학습하도록 유도.</p>
</li>
</ul>
</li>
<li><p>ANN 개념
 : 인공 두뇌를 모방한 모델로, 뉴런의 구조를 기반으로 학습.</p>
<ul>
<li>Artificial Neuron 모델
  : weight와 bias 사용
  : 입력 x에 대해 선형 결합 후 활성화 함수 적용
  : Activation Function을 사용하여 비선형성을 추가</li>
</ul>
</li>
<li><p>Multi-Layer Neural Networks
 기본적인 ANN 구조: Input Layer -&gt; Hidden Layer -&gt; Output Layer</p>
<p> 왜 한 개의 층으로는 부족한가?
 : 단층 신경망 (1-layer ANN) = logistic regression
 비선형 데이터를 제대로 학습할 수 없음.
 단순 선형 변환만 가능.</p>
</li>
<li><p>Activation Functions
 1) Step Function: 미분 불가능하여 사용하기 어려움
 2) Sigmoid
 : 출력범위: (0, 1)
 문제점: 큰 값에서는 기울기가 사라지는 Vanishing Gradient Problem 발생</p>
<p> 3) Other Activation Functions : ReLU, Tanh 등도 자주 사용됨.</p>
</li>
<li><p>Training Neural Networks
 Loss Function</p>
<ul>
<li><p>이진 분류: Binary Cross-Entropy 사용</p>
</li>
<li><p>다중 분류: Softmax + Cross-Entropy 사용</p>
<p>Backpropagation</p>
</li>
<li><p>Chain Rule을 이용하여 loss의 기울기를 계산하고 가중치를 업데이트</p>
</li>
<li><p>최적화 기법: Gradient Descent 적용</p>
</li>
</ul>
</li>
<li><p>모델 성능 개선 전략
 1) 하이퍼파라미터 튜닝</p>
<pre><code> - 은닉층 개수, 뉴런 수, 활성화 함수 선택
 - learning rate, batch size 조정</code></pre><p> 2) Regularization</p>
<pre><code> - 과적합 방지를 위해 drop out, L1/L2 정규화 적용</code></pre><p> 3) Data Augmentation</p>
<pre><code> - 이미지 변형을 통해 데이터 다양성을 확보하여 일반화 성능 향상</code></pre></li>
</ol>
<h3 id="예상문제">예상문제</h3>
<ol>
<li>What are the main challenges in image classification tasks?</li>
</ol>
<p>The main challenges in image classification include:</p>
<ul>
<li>Veiwpoint Variation: The appearance of objects changes with camera angles.</li>
<li>Interclass Variation: Objects within the same class may have different shapes, sizes, or textures.</li>
<li>Background Clutter: Unrelated objects in the background can interfere with classification.</li>
<li>Illumination and Occlusion: Lighting conditions and objects blocking parts of the image affect recognition.</li>
<li>Scalabillity: Large datasets require high computational power for training models.</li>
</ul>
<ol start="2">
<li>Why does logistic regression perform poorly on raw pixel image data?</li>
</ol>
<p>Logistic regression performs poorly on raw pixel data because:</p>
<ul>
<li>Lack of Feature Extraction: It treats all pixels as independent variables without considering spatial relationships.</li>
<li>High Dimensionality: Images contain thousands of features, making linear models ineffective.</li>
<li>Non-linearity: Many real-world classification problems require non-linear decision boundaries.</li>
</ul>
<ol start="3">
<li>What is feature engineering, and what are its limitations?</li>
</ol>
<p>Feature engineering is the process of manually selecting or transforming raw data into meaningful representations for machine learning models.</p>
<p>Limitations:</p>
<ul>
<li>Requires Domain Knowledge: Finding effective features requires expertise.</li>
<li>Time-Consuming: Manually extracting features is labor-intensive.</li>
<li>Curse of Dimensionality: High-dimensional feature representations can degrade model performance.</li>
</ul>
<ol start="4">
<li>What is the problem with using a single-layer neural network?</li>
</ol>
<p>A single-layer neural network cannot model complex decision boundaries fails to classify non-linearly separable data.</p>
<ol start="5">
<li>Why do deep neural networks require non-linear activation functions?</li>
</ol>
<p>Without non-linear activation functions, deep neural networks behave as a single linear transformation, limiting their ability to learn complex patterns. Non-linearity allows the network to model intricate relationships in data.</p>
<ol start="6">
<li>What does &quot;feed-forward&quot; mean in the context of an artificial neural network?</li>
</ol>
<p>Feed-forward in artificial neural networks refers to the process where the input data passes through the network layer by layer without loops or feedback connections. The information moves in one direction—from the input layer to the output layer.</p>
<ol start="7">
<li>What does “fully-connect” mean in the context of an artificial neural network?</li>
</ol>
<p>A fully-connected layer in a neural network means that every neuron in a layer is connected to every neuron in the next layer. This allows the model to learn complex patterns but increases the number of parameters significantly.</p>
<ol start="8">
<li>Why do we need both a training set and a test set?</li>
</ol>
<p>The training set is used to teach the model, while the test set evaluates its performance on unseen data. Without a separate test set, we cannot measure how well the model generalizes to new examples.</p>
<ol start="9">
<li>What is the difference between sigmoid, ReLU, and softmax activation functions?</li>
</ol>
<ul>
<li><p>Sigmoid: Maps values to the range (0,1), often used for binary classification but suffers from vanishing gradients.</p>
</li>
<li><p>ReLU (Rectified Linear Unit): Replaces negative values with zero, reducing the vanishing gradient problem but can suffer from dying neurons.</p>
</li>
<li><p>Softmax: Converts logits into probabilities, ensuring that the sum of all class probabilities equals 1, mainly used for multi-class classification.</p>
</li>
</ul>
<ol start="10">
<li>What is the purpose of the softmax activation? How is it similar to the sigmoid activation? How is it different?</li>
</ol>
<p>The softmax activation function transforms a vector of raw scores (logits) into probabilities that sum to 1. Like the sigmoid function, it maps values to a range between 0 and 1. However, while sigmoid applies to binary classification, softmax is used for multi-class classification by normalizing all outputs across multiple classes.</p>
<ol start="11">
<li>What is the vanishing gradient problem, and how does it affect training?</li>
</ol>
<p>The vanishing gradient problem occurs when gradients become too small during backpropagation, causing earlier layers in deep networks to learn slowly or not at all. This leads to inefficient training and poor convergence.</p>
<ol start="12">
<li>How is an artificial neural network similar to a biological neural network? How are they different?</li>
</ol>
<p>Similarities:</p>
<ul>
<li>Both process information using interconnected units (neurons).</li>
<li>Both rely on weighted connections to determine the strength of signal transmission.</li>
<li>Both can adapt based on learning experience.</li>
</ul>
<p>Differences:</p>
<ul>
<li>Biological neurons transmit signals chemically and electrically, while artificial neurons use mathematical computations.</li>
<li>Artificial neural networks are structured in layers, whereas biological neural networks are highly interconnected and dynamic.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs231n+michigan DL for CV] lecture 2: Image Classification (1)]]></title>
            <link>https://velog.io/@yugyeong_929/cs231nmichigan-DL-for-CV-lecture-2-Image-Classification-1</link>
            <guid>https://velog.io/@yugyeong_929/cs231nmichigan-DL-for-CV-lecture-2-Image-Classification-1</guid>
            <pubDate>Tue, 02 Jul 2024 10:55:10 GMT</pubDate>
            <description><![CDATA[<h1 id="image-classification-a-core-computer-vision-task">Image classification: A core computer vision task</h1>
<h3 id="what-is-image-classification">What is Image Classification?</h3>
<p>이미지 분류는 컴퓨터 비전의 중요한 핵심이다. 예를 들어, 이미지를 입력으로 사용하고 출력으로 레이블 중 하나를 이미지에 할당하는 작업이다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/8151c873-e80e-4dd3-b3fb-d498ddc7d93b/image.png" alt=""></p>
<h1 id="problem-semantic-gap">Problem: Semantic Gap</h1>
<p>인간에게는 간단한 이미지 분류 작업이 컴퓨터에게는 어려운데, 그 이유는 semantic gap 때문이다. 인간은 이미지를 이미지 자체로 인식하고 직관적으로 이해가 가능하지만, 컴퓨터는 모든 것을 숫자로 인식한다. 컴퓨터에서 이미지는 0~255 사이의 pixel과 red, green, blue의 3개의 채널로 이루어진 거대한 숫자 집합에 불과하다. 이렇게 인간과 컴퓨터가 이미지를 바라보는 인식의 차이를 semantic gap (의미론적 차이)라고 한다.</p>
<h1 id="challenges-viewpoint-variation">Challenges: Viewpoint Variation</h1>
<p>컴퓨터가 이미지를 숫자로 인식한다는 점에서 발생하는 다양한 문제들이 있다.
<strong>1. Viewpoint Variation</strong>
카메라를 조금만 움직여도 사진을 구성하는 픽셀 값들이 전부 변한다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/29a02685-cbc4-4996-a6ca-79d1f2d0a6cc/image.png" alt=""></p>
<p><strong>2. Intraclass Variation</strong>
유전적 다양성으로 인해 컴퓨터가 이미지 분류 작업이 어려워진다.
예를 들어서, 같은 고양이이지만 색상, 무늬 등의 생김새가 다를 경우 이미지 분류를 하는데 어려움이 생길 수 있다.</p>
<p><strong>3. Fine-Grained Categories</strong>
2번과 비슷한 맥락일 수 있는데, 예를 들어서 이는 고양이 안에서도 품종별로 세분화 하는 작업을 일컫는다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/0e297726-1d74-4d6a-aa56-32c6bd2c9ec4/image.png" alt=""></p>
<p><strong>4. Background Clutter</strong>
배경으로 인해 식별이 어려운 경우를 말한다. 인식해야할 객체가 배경에 섞일 수도 있기 때문이다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/4244d51b-f6f0-4250-baca-6c726eaeb350/image.png" alt=""></p>
<p><strong>5. Illumination Changes</strong>
장면에서 일어나는 다양한 변화에도 이미지를 잘 분류하려면, 장면의 조명 조건을 변경하면서도 조명 변화에 강인한 분류기가 필요하다. 예를 들어서, 어둠 속에서 사진을 찍을 수도 있고 조명을 켠 채로 찍을 수도 있는 경우를 뜻하는 것이다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/91745ab9-cc87-4d38-9d1b-8cf485f44454/image.png" alt=""></p>
<p><strong>6. Deformation</strong>
고양이처럼 변형이 가능한 물체(살아움직이는..) 종류들은 인식하기 더 어려울 수 있다. 
<img src="https://velog.velcdn.com/images/yugyeong_929/post/f2095637-2c15-4155-8ea4-7f58d42d1ebb/image.png" alt=""></p>
<p><strong>7. Occlusion</strong>
아래 사진들처럼 고양이의 일부밖에 보이지 않는 상황도 있을 수 있는데, 이 경우에도 인식하기 어려울 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/c4fef8dd-33de-4c48-838a-c3174cf70e22/image.png" alt=""></p>
<h1 id="image-classification-building-block-for-other-tasks">Image Classification: Building Block for other tasks!</h1>
<p>많은 문제들이 있음에도 불구하고 Image Classification을 연구하는 이유는 다양한 분야에서 유용하게 쓰이기 때문이다. 일례로, 의학 분야에서는 양성 종양과 악성 종양을 구분하는데 이미지 분류 작업을 사용하기도 한다. 그 밖에도 이미지 분류를 사용하여 아래와 같은 작업들이 가능하다.</p>
<p><strong>1. Object Detection</strong>
이미지를 분류하는 것에서 어떠한 객체에 대해 Bounding Box를 그려주는 Localization 작업까지 수행할 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/add4ce61-d89b-48c8-91f6-c7a2c55d0ad1/image.png" alt=""></p>
<p><strong>2. Image Captioning</strong>
이미지에 캡션을 달아주는 작업으로, 이미지를 보고 어떤 이미지인지 언어로 설명해주는 작업을 말한다. 접근 방식으로는 크게 &#39;Top-Down Approach&#39;와 &#39;Bottom-Up Approach&#39;로 구분된다.</p>
<ul>
<li><p>Top-Down Approach: 이미지를 통째로 시스템에 통과시켜 얻은 요점을 언어로 변환</p>
</li>
<li><blockquote>
<p>현재까지 가장 많이 쓰이고 있는 접근방식이지만, 이미지의 디테일한 부분에 집중하는 것이 상대적으로 어렵다.</p>
</blockquote>
</li>
<li><blockquote>
<p>Recurrent Neural Network (RNN)을 활용한 학습이 가능하며, 이 방식의 성능이 가장 좋다고 평가 받는다.</p>
</blockquote>
</li>
<li><p>Bottom-Up Approach: 이미지를 부분적으로 접근하여 여러 부분들로부터 단어를 도출하고 이를 결합하여 문장을 생성</p>
</li>
<li><blockquote>
<p>이미지의 여러 부분으로부터 하나씩 단어들을 뽑아낸 뒤에 결합하기 때문에 조금 더 디테일한 부분을 반영할 수 있다.</p>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/1430154f-c342-421a-a524-624fbe3f9b6f/image.png" alt=""></p>
<h1 id="attempts-to-image-classification">Attempts to Image Classification</h1>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/59ba6aa1-c7a0-423b-90d8-b4273e391639/image.png" alt="">
이미지 분류를 위해 처음으로 시도된 방법 중 하나는 바로 가장자리 (edge)를 이용하는 것이었다. 가장자리를 추출하여 해당 가장자리의 특성 혹은 패턴을 찾으려고 하는 것이다.</p>
<p>자세히 이야기하면, 가장자리를 따라 outline을 만들어내고, 세 개의 선이 맞닿는 부분을 &#39;corner&#39;라고 정의한다. 고양이, 개 등 객체별 corner 집합의 규칙을 이끌어내 이미지를 구별한다는 것이다. 이 방식에도 문제점이 있는데, <strong>1) Too weak.</strong> 고양이로 예를 들면 무늬, 자세 등에 너무 쉽게 영향을 받고, <strong>2) Low scalability.</strong> 고양이, 개 등 객체별 집합을 모두 정의해야 하므로 확장성이 낮다.</p>
<p>이 문제점들을 해결하기 위해 등장한 것이 &#39;Data-Driven Approach (데이터 중심 접근법)&#39;이다.</p>
<h1 id="machine-learning-data-driven-approach">Machine Learning: Data-Driven Approach</h1>
<ol>
<li>Collect a dataset of images and labels</li>
<li>Use Machine Learning to train a classifier</li>
<li>Evaluate the classifier on new images</li>
</ol>
<h1 id="nearest-neighbor">Nearest Neighbor</h1>
<p>분류를 위한 머신러닝 알고리즘으로, 이를 train function과 predict function 두개의 함수를 구현해야 한다.</p>
<ul>
<li>train function: 모든 training data와 label을 기억한다.</li>
<li>predict function: 입력된 데이터를 training data와 비교함으로써 어떤 label을 가질지 예측한다.</li>
</ul>
<h3 id="distance-metric-to-compare-images">Distance Metric to compare images</h3>
<p>입력된 데이터를 training data와 비교하여 어떤 라벨을 가질지 예측하는 함수가 필요한데, 이에 사용할 수 있는 알고리즘 중 하나인 &#39;L1(Manhattan) distance&#39;에 대해서 알아보자.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/97483d85-6a66-4f06-ae8f-cdd90b0d668a/image.png" alt="">
L1 distance 수식을 살펴보면, test image에서 training image 픽셀 값을 빼서 차이를 구하는 것을 볼 수 있다. 각 픽셀끼리의 차를 구한 뒤 결과 값을 합산하는 방식이다.</p>
<pre><code class="language-python">import numpy as np

class NearestNeibor :
    def __init__(self) :
        pass

    ### Memorize training data
    def train(self , X , y) :
        # X is N x D where each row is an examples. y is label which is 1-dim of size N
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y

    def predict(self , X) :
        # X is N x D where each row is an example we wish to predict label for
        num_test = X.shape(0)
        # let&#39;s make sure that the output type matches the input type
        Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    ### For each test image(loop over all test rows)
    ### Find nearest training image &amp; Return label of nearest image
    for i in xrange(num_test)
            # find the nearest training images to the i&#39;th test image
            # using the L1 distance (sum of absolute value difference)
            distances = np.sum(np.abs(sel.Xtr - X[i,:]) , axis = 1)

            # get the index with smallest distance
            min_index = np.argmin(distances)

            # predict the label of nearest example
            Ypred[i] = self.ytr[min_index]

        return Ypred</code></pre>
<p>코드를 살펴보면 다음을 알 수 있다.</p>
<ul>
<li>predict function 정의부의 반복문에서 self.Xtr(입력받은 train data를 사용하여 학습한 내용)과 X[i, :](test data) 의 거리를 합을 구하는 것을 알 수 있다.</li>
<li>이를 통해, L1 distance가 가장 작은 것이 train data와 test data 사이의 차이가 가장 작다는 의미로, 이 차이의 최솟값을 갖는 라벨을 Ypred(결과)로 출력한다.</li>
</ul>
<h3 id="problems-of-nearest-neighbor">Problems of Nearest Neighbor</h3>
<ul>
<li><p>시간 복잡도
Nearest Neighbor에서 train function은 단순히 train data를 저장하므로 O(1)이다. 하지만, predict function에서 반복문을 통해 모든 test data와 train data의 차이를 구하므로 N개의 데이터가 주어졌을 때의 시간 복잡도는 O(N)이 된다. 이는 데이터가 많아질수록 시간 복잡도가 계속해서 증가한다고 볼 수 있다.</p>
</li>
<li><p>Decision Boundaries
Nearest Neighbor는 &#39;Decision Boundaries&#39;를 만들 때 문제가 발생한다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/43672461-1378-441e-bad6-cb0df76a6f3d/image.png" alt="">
위 이미지에서 각각의 점이 train data이고 점의 색깔은 해당 데이터의 라벨이다. 배경 색은 test data가 주어졌을 때 할당될 라벨이라고 생각하면 된다.</p>
</li>
</ul>
<p>여기서의 문제는</p>
<ul>
<li>가장 가까운 위치의 데이터만을 이용하여 boundary를 만들기 때문에 이상치에 취약하다.</li>
<li>마찬가지로 가까운 위치의 데이터만을 이용하기 때문에 boundary의 경계면이 부드럽지 못하다. 이럴 경우에는 과적합이 일어날 수 있다.</li>
</ul>
<p>여기서 두번째 문제를 해결하여 경계선을 보다 스무스하게 만들기 위해 생각해낸 것이 &#39;k-nearest neighbor&#39;이다. 단 하나의 이웃만을 이용하는 기존 방식에서 나아가, k개의 이웃을 사용하여 가장 많은 득표수를 가진 클래스로 예측하는 방식이다.</p>
<h3 id="k-nearest-neighbor">K-Nearest Neighbor</h3>
<p>아래의 사진을 통해 k의 수에 따라 경계면이 보다 부드럽게 변화한 것을 확인할 수 있다. 하지만, 경계 사이의 분류되지 않은 공백이 생기는 현상이 발생하는데 이 또한 knn이 해결해야 할 문제 중 하나이다. 공백은 추론하거나 임의로 결정하여 채울 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/c8738c33-27bb-42ce-b907-1b51281e5b5e/image.png" alt=""></p>
<h3 id="l2-euclidean-distance">L2 (Euclidean) distance</h3>
<p>L1 distance 외에도 L2 (Euclidean) distance가 있다. 어떤 거리 척도를 사용하느냐에 따라서 boundary의 모양에 차이가 생긴다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/f8cd2e0d-ff19-4c82-8238-121d06529731/image.png" alt=""></p>
<ul>
<li>L1 distance: 각각의 벡터 요소들이 개별적인 의미를 가지고 있을 때 사용하는 거리 척도이다.</li>
<li>L2 distance: 벡터 요소들의 의미를 모르거나, 의미가 별로 없을 때 사용하는 거리 척도이다.</li>
</ul>
<p>실제로 두 거리 척도의 수식을 보면 L1, L2 distance 모두 &#39;거리&#39; 개념이므로 양수가 나와야 한다는 점에서 같지만, 양수를 만들기 위해 사용한 방식이 다른 것을 알 수 있다. L1은 차이에 절댓값을 취하는 방식이라 test data에서 train data를 뺀 값 자체를 보존할 수 있다.</p>
<h3 id="k-nearest-neighbor의-특징-universal-approximation">K-Nearest Neighbor의 특징: Universal Approximation</h3>
<p>kNN은 충분히 많은 데이터가 주어지고 적절한 k값이 선택된다면, 거의 모든 함수 형태를 근사할 수 있다.(이론적으로는 어떤 함수든 근사할 수 있다고 하지만, 이를 위해서는 몇 가지 조건이 필요하다. 예를 들어, 함수가 특정 도메인에서 연속적이어야 하거나, 훈련 데이터 포인트 간의 간격이 일정해야 한다는 가정 등이 필요하다.) 이는 kNN이 데이터 분포의 세부적인 형태까지 포착할 수 있는 이유 중 하나이다. 또한, 선형 모델이 아니기 때문에 비선형적인 데이터를 잘 처리할 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/ae8e14d1-3dba-4059-81f5-7c490c267769/image.png" alt=""></p>
<h3 id="k-nearest-neighbor의-문제점">K-Nearest Neighbor의 문제점</h3>
<p><strong>- 차원의 저주:</strong> 차원이 늘어남에 따라 공간을 균일하게 메우기 위해 필요한 training point의 개수가 기하급수적으로 증가한다. image classification에서 보편적으로 사용하는 데이터셋의 이미지를 분류한다고 생각했을 때, 해당 데이터셋의 이미지 크기는 $32<em>32$이므로 해당 공간을 균일하게 메워 균등한 학습이 이루어지도록 하려면 $2^{32</em>32}$ 만큼의 training point가 필요하게 된다. image classification에서 kNN 알고리즘을 적용하는 것은 사실상 불가능하다는 뜻이다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/9f0fffcf-9f9a-43db-b51b-b337574c6dba/image.png" alt=""></p>
<ul>
<li>** distance metric은 이미지에 적용하기에 부적절하다.**
<img src="https://velog.velcdn.com/images/yugyeong_929/post/157da531-d65b-470b-96e1-4a918da067a6/image.png" alt="">
위 이미지들을 보면 알 수 있는데, 인간의 눈으로 보기에는 다 다른 이미지이지만 L2 distance를 구했을 때의 값은 비슷할 수 있다. 따라서, kNN으로는 분류가 잘 되지 않을 수도 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs226] Lecture 1: Introduction]]></title>
            <link>https://velog.io/@yugyeong_929/cs226-Lecture-1-Introduction</link>
            <guid>https://velog.io/@yugyeong_929/cs226-Lecture-1-Introduction</guid>
            <pubDate>Wed, 26 Jun 2024 14:31:37 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<h3 id="what-is-generative-models">What is Generative Models?</h3>
<p>생성 모델은 주어진 학습 데이터를 학습하여 <strong>학습 데이터의 분포를 따르는 새로운 데이터를 생성</strong>하는 모델이다. 학습 데이터와 유사한 데이터를 생성해야 하기 때문에 학습 데이터와 유사한 샘플을 뽑아야 한다. 따라서, 생성 모델에는 학습 데이터의 분포를 어느 정도 안 상태에서 생성(Explicit)하거나 잘 모르는 상태에서 생성(Implicit)하는 다양한 모델들이 존재한다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/7e592bd9-12f9-4f19-ab2a-14d69529a9e4/image.png" alt="">
강의에서는 Richard Feynman의 인용문을 생성모델에 적용하여 설명했다.
<em>&quot;What I cannot create, I do not understand&quot;</em>
이는 수학적 정리에서 자신이 직접 증명할 수 없다면 그 개념을 충분히 이해하지 못한다는 것을 의미한다.
이를 생성 모델에 적용한다면, &quot;만약 이미지나 텍스트의 의미를 이해할 수 있다면 이를 생성할 수 있다&quot;고 할 수 있다.</p>
<h1 id="generative-modeling-computer-graphics">Generative Modeling: Computer Graphics</h1>
<h3 id="how-to-generate-natural-images-with-a-computer">How to generate natural images with a computer?</h3>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/fc8610a9-bc07-4104-90e8-de79c4a76050/image.png" alt="">
<strong>컴퓨터 그래픽스에서 고차원 신호(이미지) 생성 :</strong> 주어진 High Level Description(물체의 종류, 색상, 위치 등)을 기반으로 이미지를 생성하는 과정이다. 이는 물체가 어떤 모양인지, 색상은 어떤지, 위치는 어디인지와 같은 정보를 바탕으로 이미지를 렌더링하는 것을 포함한다.</p>
<p><strong>생성 모델을 통해 이를 역으로 해석하는 &#39;Inverse Graphics (역 그래픽스)&#39; :</strong> 생성 모델의 철학 중 하나로, 이미지를 생성하는 과정을 역으로 수행하여 이미지를 해석하는 방법이다. 이는 이미지에서 시작하여 그 이미지를 생성한 요소들, 즉 High Level Description을 추론하는 것을 의미한다.</p>
<p><strong>이미지 생성 및 해석에서 컴퓨터 그래픽스와 생성 모델의 차이점</strong></p>
<ul>
<li>컴퓨터 그래픽스는 주로 고수준의 설명을 바탕으로 이미지를 생성하는 반면, 생성 모델은 주어진 데이터를 기반으로 새로운 데이터를 생성하거나 해석함.</li>
<li>생성 모델을 통해 역 그래픽스 접근법을 사용하면, 이미지를 보고 그 이미지를 생성한 요소들을 이해할 수 있다.</li>
</ul>
<h1 id="statistical-generative-models">Statistical Generative Models</h1>
<p>생성 모델은 이미지나 텍스트의 확률 분포로 구성된다. 이때, 통계 모델을 사용하여 데이터와 사전 지식을 결합을 통해 좋은 생성 모델을 구축한다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/e570b84f-0c86-4c7e-9ea6-16da6ef99903/image.png" alt="">
사전 지식으로는 prametric form, loss function, optimization algorithm 등이 될 수 있다.</p>
<p>임의의 이미지 x가 입력으로 주어졌을 때, 이 이미지가 데이터 세트에서 나타날 <strong>확률 $p(x)$를 계산</strong>할 수 있다.</p>
<ul>
<li>임의의 이미지 $x$ 입력</li>
<li>모델이 이 이미지가 학습된 분포에 따라 나타날 확률을 계산</li>
<li><blockquote>
<p>이를 통해, 모델은 입력 이미지 $x$를 스칼라 확률 값 $p(x)$로 매핑한다. 예를 들어, 특정 이미지가 모델의 학습된 분포에 잘 맞는다면 높은 확률 값을 가질 것이다.</p>
</blockquote>
</li>
</ul>
<p><strong>생성 모델을 데이터 시뮬레이터로 사용하여 새로운 데이터를 생성하는 과정</strong>은 데이터를 입력으로 받는 것이 아니라 <strong>출력을 생성하는 방식</strong>이라고 생각하면 된다.</p>
<h3 id="생성-모델을-통해-시뮬레이터를-구축하는-과정">생성 모델을 통해 시뮬레이터를 구축하는 과정</h3>
<ol>
<li>데이터 수집: 생성 모델을 학습시키기 위해 많은 데이터를 수집한다.</li>
<li>모델 학습: 이 데이터 세트를 사용하여 생성 모델을 학습 시킨다. 생성 모델은 데이터 세트의 분포를 학습하고, 각 데이터 포인트가 어떻게 생겼는지에 대한 확률적 이해를 가지게 된다. 이 과정에서 모델은 각 이미지에 대한 다양한 특징들을 학습하게 된다.</li>
</ol>
<p>학습된 확률 분포를 바탕으로 해당 분포에서 샘플링하여 새로운 이미지를 생성할 수 있다고 생각하면 된다.</p>
<h3 id="제어-신호를-사용한-데이터-생성">제어 신호를 사용한 데이터 생성</h3>
<p>제어 신호를 사용하여 생성 모델을 특정한 방식으로 제어할 수 있다. 여기서 제어 신호는 생성 과정에서 원하는 출력을 얻기 위해 입력되는 추가적인 정보를 의미한다. 이는 스케치, 캡션 등이 포함될 수 있다.
(이런 것들을 Conditional Generative Model이라고 생각하면 됨.)</p>
<h1 id="image-generation">Image Generation</h1>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/f49a8a51-d9f8-4dbb-b2d1-1b42c7287af8/image.png" alt="">
생성 모델은 많은 발전을 이루었고, 다양한 분야에서 성공을 거두고 있다. 초기에는 단순한 흑백 이미지 생성이었지만, 점차 고해상도와 더 많은 디테일을 갖춘 현실적인 이미지까지 발전했다.</p>
<p>강의에서는 간략하게 GAN, Diffusion Model, Dalle3 등이 이미지를 생성한 예시들을 보여주며 넘어간다.</p>
<p>GAN과 Diffusion Model에 대해서 간략하게 설명하자면,</p>
<ul>
<li><p><strong>GAN:</strong> generator와 discriminator라는 두 개의 신경망으로 구성되는데, 이 두 신경망이 적대적인 관계로 가짜 데이터 생성하는 생성자와 진짜와 가짜 데이터를 구분하는 판별자가 서로 경쟁을 하며 학습을 한다.</p>
</li>
<li><p><strong>Diffusion Model:</strong> 원본 데이터에 여러 단계에 걸쳐 노이즈를 추가(전향 과정(Forward Process))하고, 모델이 각 단계에서 노이즈가 추가된 데이터를 입력으로 받아, 노이즈를 제거하여 원래 데이터로 복원역향 과정(Reverse Process)하는 방법을 학습한다. 학습된 모델을 사용하여 노이즈가 많은 상태에서 시작하여 점진적으로 노이즈를 제거함으로써 새로운 데이터를 생성한다.</p>
</li>
</ul>
<h1 id="audio-and-speech-generation">Audio and Speech Generation</h1>
<p>음성 생성 모델도 또한 발전했다. WaveNet 모델은 텍스트를 음성으로 변환하는데 매우 효과적이다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/5d6bdb50-141e-4096-b606-771d5c210455/image.png" alt="">
최신 모델은 감정 표현과 억양을 포함하여 더욱 자연스러운 음성을 생성할 수 있다. 강의에서는 Diffusion Text2Speech와 Audio Super Resolution 모델의 음성 생성 예시를 보여준다. (여기서 Audio Super Resolution 모델은 Conditional generative model이다.)</p>
<h1 id="language-generation">Language Generation</h1>
<p>언어 모델도 많은 진전을 이루었다. GPT와 같은 대규모 언어 모델은 다양한 텍스트 생성 작업을 수행할 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/db50b15f-f11f-4fff-bbf0-3a847ddf39cc/image.png" alt="">
GPT는 텍스트를 이해하고, 새로운 텍스트를 생성하는 능력이 매우 뛰어나다.</p>
<ul>
<li>Machine Translation (기계 번역): 기계 번역은 생성 모델을 사용하여 다양한 언어로 텍스트를 변환하는 작업이다.</li>
<li>Code generation (코드 생성 모델): 자연어 설명을 기반으로 코드를 생성할 수 있다.  </li>
</ul>
<h1 id="video-generation">Video Generation</h1>
<p>비디오 생성 모델도 발전하고 있다. 
<img src="https://velog.velcdn.com/images/yugyeong_929/post/6f21cb8a-b32a-468f-ac7c-b519a24485fc/image.png" alt="">
위와 같이 텍스트 설명을 기반으로 짧은 비디오를 생성할 수도 있고 다양한 비디오 클립을 결합하여 하나의 콘텐츠를 생성할 수도 있다. 비디오 생성 모델은 텍스트나 이미지 시드로 제어가 가능하다.</p>
<h1 id="utilization-of-generative-model">Utilization of Generative Model</h1>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/e405d7d4-3176-40c1-aa18-f8e181b299a3/image.png" alt="">
생성 모델은 Decision Making and Robotics (결정 제어 및 로봇 공학 분야에서도 사용된다. 예를 들어, 자율 주행 자동차 등에 사용될 수 있다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/6e6e3a26-d5c4-4e1e-8cae-fb06907c40c3/image.png" alt="">
뿐만 아니라, 화학 및 생명 공학 분야에서도 생성 모델이 중요한 역할을 한다. 예를 들어, 특정 속성을 가진 분자나 단백질을 설계하는 데 사용될 수 있다.</p>
<p>이외에도, 3D 객체 생성, 음악 생성 등 다양한 분야에서도 활용된다.</p>
<h1 id="ethical-issues-in-generative-models">Ethical Issues in Generative Models</h1>
<p>생성 모델은 다양한 분야에서 활용되며 많은 발전을 이루고 있지만, 이에 따른 윤리적인 문제도 인식을 해야 한다. 예를 들어, 딥페이크와 같은 기술들은 다양한 범죄에 악용될 수 있기 때문에 이를 방지하기 위한 논의도 필요하다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/7cfb327b-2ec3-4ed8-ba1a-f41e74051f75/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transformer in Pytorch ]]></title>
            <link>https://velog.io/@yugyeong_929/Transformer-in-Pytorch</link>
            <guid>https://velog.io/@yugyeong_929/Transformer-in-Pytorch</guid>
            <pubDate>Sun, 02 Jun 2024 06:14:46 GMT</pubDate>
            <description><![CDATA[<h2 id="hyperparameter-of-transformer">Hyperparameter of Transformer</h2>
<ul>
<li><p><strong>$d_{model}$(hidden_size)</strong>: 트랜스포머 모델에서 <strong>각 토큰의 임베딩 벡터 차원</strong>을 나타낸다. <strong>즉, 입력과 출력의 벡터 크기이다.</strong> 트랜스포머의 encoder와 decoder에서 정해진 입력과 출력의 크기로 embedding vector의 차원과 동일하며, encoder와 decoder 내에서 값이 전달될 때의 차원 또한 동일하다.</p>
</li>
<li><p><strong>num_layers(num_encoder_layers)</strong>: encoder 또는 decoder에 있는 <strong>layer의 수</strong>이다. (구현한 코드에서는 encoder의 layer 수를 의미함.)</p>
</li>
<li><p><strong>num_heads</strong>: 트랜스포머에서는 attention을 사용할 때, 하나로 진행하는 것보다 여러 개의 attention을 병렬로 진행하고 독립적으로 수행한 결과값을 하나로 합친다. 이때 multi-head attention에서 <strong>병렬로 attention을 수행하는 head의 개수</strong>이다.</p>
</li>
<li><p>$d_{ff}$: 트랜스포머 내부에는 <strong>Feed-Forward Neural Network (FFN)</strong>가 존재한다. <strong>이때의 은닉층 크기를 의미하는 하이퍼 파라미터이다.</strong> 즉, $d_{ff}$ 차원에서 $d_{model}$ 차원으로 임베딩이 진행된다. (이 내용은 아래의 내용을 읽으면서 이해하는 것이 빠르다.) $d_{ff}$는 $d_{model}$(hidden size)의 4배로 설정되는데, 이는 Transformer paper <em>&#39;AttentionIs All You Need&#39;_에서 제안된 기본 구조 때문이다. 각 트랜스포머 레이어의 FFN을 두 개의 선형 변환과 ReLU 활성화 함수로 구성하며, 이때 중간층의 크기($d</em>{ff}$)는 입력 및 출력 크기인 $d_{model}$(hidden size)의 4배로 설정된다. 이 설계 방식은 모델이 더 많은 특징을 학습할 수 있게 하여 성능을 향상시키기 위함이다.</p>
</li>
</ul>
<h2 id="structure-of-transformer">Structure of Transformer</h2>
<p>트랜스포머 모델은 주로 두 가지 주요 구성 요소로 나뉜다:</p>
<ol>
<li><strong>Multi-Head Attention 메커니즘</strong></li>
<li><strong>Feed-Forward Neural Network (FFN)</strong></li>
</ol>
<p>각 트랜스포머 레이어는 위의 두 가지 구성 요소로 구성되어 있다.
이 구성 요소가 작동하는 방식은 아래와 같다.</p>
<h4 id="1-임베딩-및-multi-head-attention">1. 임베딩 및 Multi-Head Attention</h4>
<ul>
<li>입력 시퀀스는 처음에 임베딩 층을 거쳐 <code>hidden_size</code> (또는 <code>d_model</code>) 크기의 벡터로 변환된다.</li>
<li>각 입력 벡터는 포지셔널 인코딩을 더하여 시퀀스 내에서의 위치 정보를 포함한다.</li>
<li>이렇게 임베딩된 벡터들은 Multi-Head Attention 메커니즘에 입력으로 들어간다.</li>
</ul>
<h4 id="2-feed-forward-neural-network-ffn">2. Feed-Forward Neural Network (FFN)</h4>
<p>FFN은 트랜스포머 레이어의 중요한 부분이다. 각 트랜스포머 레이어는 다음과 같은 구조를 가진다:</p>
<p>${FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2$</p>
<p>여기서 <code>W_1</code>과 <code>W_2</code>는 선형 변환을 위한 weight이고, <code>b_1</code>과 <code>b_2</code>는 bias이다.</p>
<h3 id="ffn의-동작-방식">FFN의 동작 방식</h3>
<ol>
<li><p><strong>입력 벡터</strong> ( x ):</p>
<ul>
<li>각 토큰에 대한 임베딩 벡터로, 차원은 <code>hidden_size</code> (또는 <code>d_model</code>)이다.</li>
</ul>
</li>
<li><p><strong>첫 번째 선형 변환 및 활성화 함수</strong>:</p>
<ul>
<li>입력 벡터 ( x )는 첫 번째 선형 변환을 거쳐 <code>d_ff</code> 차원의 은닉층 벡터로 변환된다.</li>
<li>이 변환은 다음과 같다:
$h = \max(0, xW_1 + b_1)$
여기서 <code>W_1</code>의 크기는 <code>(hidden_size, d_ff)</code>이고, <code>h</code>의 크기는 <code>d_ff</code>이다. 활성화 함수로 ReLU가 사용된다.</li>
</ul>
</li>
<li><p><strong>두 번째 선형 변환</strong>:</p>
<ul>
<li>은닉층 벡터 ( h )는 두 번째 선형 변환을 거쳐 다시 <code>hidden_size</code> 차원의 출력 벡터로 변환된다:
$y = hW_2 + b_2$
여기서 <code>W_2</code>의 크기는 <code>(d_ff, hidden_size)</code>이고, <code>y</code>의 크기는 <code>hidden_size</code>이다.</li>
</ul>
</li>
</ol>
<p>따라서, 피드포워드 네트워크는 <code>hidden_size</code> 차원의 입력을 받아 <code>d_ff</code> 차원으로 확장한 후, 다시 <code>hidden_size</code> 차원으로 축소하는 역할을 한다. 이는 다음과 같은 과정을 통해 이뤄진다:</p>
<ul>
<li><code>hidden_size</code> 차원의 입력 벡터 → <code>d_ff</code> 차원의 은닉층 → <code>hidden_size</code> 차원의 출력 벡터</li>
</ul>
<h3 id="예시">예시</h3>
<ul>
<li><p><strong>입력 임베딩 벡터 (hidden_size = 256)</strong>:
$[x_1, x_2, ..., x_{256}]$</p>
</li>
<li><p><strong>FFN의 첫 번째 선형 변환 (hidden_size → d_ff = 1024)</strong>:
$[h_1, h_2, ..., h_{1024}]$
여기서 ( h )는 활성화 함수(ReLU)를 통과한 후의 벡터입니다.</p>
</li>
<li><p><strong>FFN의 두 번째 선형 변환 (d_ff → hidden_size)</strong>:
$[y_1, y_2, ..., y_{256}]$</p>
</li>
</ul>
<p>따라서 <code>d_ff</code>는 피드포워드 신경망의 중간층 크기를 의미하며, 이 중간층은 <code>hidden_size</code>의 4배로 설정되는 것이 일반적이다.</p>
<h3 id="code">Code</h3>
<p>위의 설명을 코드에 반영하면, <code>EncoderLayer</code> 클래스는 다음과 같이 구성된다:</p>
<pre><code class="language-python">class EncoderLayer(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.hidden_size = config.hidden_size

        self.self_attn = MultiHeadAttention(config)
        self.self_attn_layer_norm = nn.LayerNorm(self.hidden_size)

        self.activation_fn = nn.ReLU()

        # 피드포워드 신경망의 첫 번째 선형 변환: hidden_size → d_ff
        self.fc1 = nn.Linear(self.hidden_size, config.d_ff)
        # 피드포워드 신경망의 두 번째 선형 변환: d_ff → hidden_size
        self.fc2 = nn.Linear(config.d_ff, self.hidden_size)
        self.final_layer_norm = nn.LayerNorm(self.hidden_size)

        self.dropout = nn.Dropout(0.1)

    def forward(self, hidden_states, enc_self_mask):
        residual = hidden_states
        hidden_states = self.self_attn(
            query_states=hidden_states,
            key_value_states=hidden_states,
            attention_mask=enc_self_mask
        )
        hidden_states = self.dropout(hidden_states)
        hidden_states = residual + hidden_states
        hidden_states = self.self_attn_layer_norm(hidden_states)

        residual = hidden_states
        hidden_states = self.activation_fn(self.fc1(hidden_states))
        hidden_states = self.dropout(hidden_states)
        hidden_states = self.fc2(hidden_states)
        hidden_states = self.dropout(hidden_states)
        hidden_states = residual + hidden_states
        hidden_states = self.final_layer_norm(hidden_states)

        return hidden_states</code></pre>
<p>이 구조는 트랜스포머 레이어 내의 FFN가 <code>hidden_size</code> 차원의 입력을 받아 <code>d_ff</code> 차원으로 확장한 후, 다시 <code>hidden_size</code> 차원의 출력으로 변환하는 과정을 반영한다. 이를 통해, 모델은 더 많은 특징을 학습할 수 있으며, 성능을 높이는 데 기여한다.</p>
<h2 id="positional-encoding">Positional Encoding</h2>
<p><strong>기존의 다른 방법론들은 각 단어의 임베딩 벡터를 바로 input</strong>으로 받지만, <strong>Transformer에서는 encoder와 decoder에서 임베딩 벡터의 값을 조정하여 input</strong>으로 받는다. 이를 <strong>Positional Encoding</strong>이라고 한다.</p>
<p>Transformer는 단어를 순차적으로 입력받지 않기 때문에, 단어의 위치 정보를 다른 방식으로 알려주어야 한다. <strong>Transformer는 해당 단어의 위치 정보를 임베딩 벡터에 더하여</strong> 모델의 최종적인 입력으로 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/f3cbdecc-3310-480a-9fd5-7920c9131c40/image.png" alt=""></p>
<p>위 그림처럼, 단어들의 임베딩 벡터가 Transformer의 input으로 들어가기 전에 positional encoding 값이 더해진다.</p>
<p>Positional Encoding에는 다양한 종류들이 있지만, 기본적으로 sin, cos 함수를 이용하여 위치 정보를 전달한다.</p>
<p>${PE}<em>{{pos}, 2i}$=$
sin\left(\frac{\text{pos}}{10000^{\frac{2i}{d</em>{\text{model}}}}}\right)
$</p>
<p>${PE}<em>{{pos}, 2i+1}$ = $cos\left(\frac{\text{pos}}{10000^{\frac{2i}{d</em>{\text{model}}}}}\right)
$</p>
<ul>
<li>$pos$: 입력 문장에서 임베딩 벡터의 위치(e.g., I는 &#39;I am a student&#39;의 첫 번째 위치)</li>
<li>$i$: 임베딩 벡터 내 차원의 index</li>
<li>${d}_{model}$: Transformer의 모든 layer의 output 차원을 나타내는 하이퍼 파라미터</li>
</ul>
<p>Positional Encoding 방법을 이용할 경우에는 순서 정보가 보존된다. 예를 들어, 같은 임베딩 벡터(단어)라도 positional encoding 값을 더하게 되면 최종적으로 Transformer의 input 값은 달라진다.</p>
<p>Pytorch code of Positional Encoding</p>
<pre><code class="language-python">import torch
import matplotlib.pyplot as plt
import numpy as np
from torch import nn

class PositionalEncoding(nn.Module):

    def __init__(self, d_model, max_len, device):
        &quot;&quot;&quot;
        sin, cos encoding 구현

        parameter
        - d_model : model의 차원
        - max_len : 최대 seaquence 길이
        - device : cuda or cpu
        &quot;&quot;&quot;

        super(PositionalEncoding, self).__init__() # nn.Module 초기화

        # input matrix(자연어 처리에선 임베딩 벡터)와 같은 size의 tensor 생성
        # 즉, (max_len, d_model) size
        self.encoding = torch.zeros(max_len, d_model, device=device)
        self.encoding.requires_grad = False # encoding의 gradient는 필요 없음. 

        # 위치 indexing용 벡터
        # pos는 max_len의 index를 의미함.
        pos = torch.arange(0, max_len, device =device)
        # 1D : (max_len, ) size -&gt; 2D : (max_len, 1) size -&gt; word의 위치를 반영하기 위해

        pos = pos.float().unsqueeze(dim=1) # int64 -&gt; float32 (없어도 됨.)

        # i는 d_model의 index를 의미한다. _2i : (d_model, ) size
        # 즉, embedding size가 512일 때, i = [0,512]
        _2i = torch.arange(0, d_model, step=2, device=device).float()

        # (max_len, 1) / (d_model/2 ) -&gt; (max_len, d_model/2)
        self.encoding[:, ::2] = torch.sin(pos / (10000 ** (_2i / d_model)))
        self.encoding[:, 1::2] = torch.cos(pos / (10000 ** (_2i / d_model)))


    def forward(self, x):
        # self.encoding
        # [max_len = 512, d_model = 512]

        # batch_size = 128, seq_len = 30
        batch_size, seq_len = x.size() 

        # [seq_len = 30, d_model = 512]
        # [128, 30, 512]의 size를 가지는 token embedding에 더해질 것임.
        # 
        return self.encoding[:seq_len, :]
</code></pre>
<h2 id="attention">Attention</h2>
<p>Transformer에는 3가지의 Attention이 사용된다.</p>
<ol>
<li>Self-Attention of Encoder</li>
<li>Masked Self-Attention of Decoder</li>
<li>Co-Attention Between Encoder and Decoder.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/9d60f458-6e54-4a29-a67c-d1a960415efc/image.png" alt=""></p>
<p>Self-Attention은 Query, Key, Value가 동일한 경우(이 때, Query, Key, Value가 동일하다는 것은 서로 값이 같다는 것이 아닌, 출처 자체가 Encoder에서만 나오거나, Decoder에서만 나오거나 한다는 것)를 말하며, 
Co-Attention은 Query가 Decoder의 Vector, Key, Value가 Encoder의 Vector가 된다.</p>
<h2 id="encoder">Encoder</h2>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/de691338-c8a3-4cdb-9af4-8e3421225e48/image.png" alt=""></p>
<p>Encoder는 하이퍼 파라미터 num_layers에 따라서 해당하는 개수만큼 Encoder layers를 쌓는다. 하나의 lay를 기준으로 봤을 때에는 Self-Attention layer와 Feed-Forward Network layer로 나뉜다.</p>
<h3 id="self-attention-of-encoder">Self-Attention of Encoder</h3>
<p><strong>Self-Attention이란?</strong>
Attention 함수는 주어진 Query에 대해 모든 Key와의 유사도를 각각 구한다. 이 유사도는 weight로 사용하여 Key와 매핑되어 있는 Value와 가중합을 하게 된다.</p>
<ul>
<li><p>기존 Attention:
$Q$ = Query: $t$ 시점의 decoder cell에서의 hidden state
$K$ = Keys: 모든 시점의 encoder cell의 hidden states
$V$ = Values: 모든 시점의 encoder cell의 hidden states</p>
</li>
<li><p>Self-Attention:
$Q$ = Querys: 모든 시점의 decoder cell에서의 hidden states
$K$ = Keys: 모든 시점의 encoder cell의 hidden states
$V$ = Values: 모든 시점의 encoder cell의 hidden states</p>
</li>
</ul>
<p>이처럼 기존 Attention에서 Query $Q$는 decoder cell의 hidden state이고, $K$는 encoder cell의 hidden state이기 때문에 $Q$, $K$는 서로 다른 값을 가진다.</p>
<p>하지만, Self-Attention에서는 $Q$, $K$, $V$가 모두 동일하다.</p>
<ul>
<li>$Q$: input sentence의 모든 단어 벡터들 (input sequence)</li>
<li>$K$: input sentence의 모든 단어 벡터들</li>
<li>$V$: input sentence의 모든 단어 벡터들</li>
</ul>
<p>그렇다면, 왜 input sequence에 대해서 스스로 attention 과정을 거칠까?
<img src="https://velog.velcdn.com/images/yugyeong_929/post/6cdf60d7-0308-4abf-b36c-5025283f14cb/image.png" alt="">
위 이미지의 it은 animal일까, street일까?</p>
<p>Self-Attention은 위처럼 하나의 input sentence 내에서 특정 단어들끼리의 유사도를 구함으로써 위와 같이 it이 어떤 단어인지 파악할 수 있다.</p>
<p>Self-Attention은 encoder의 초기 input인 $d_{model}$ 차원의 sequence를 바로 사용하는 것이 아니라, 더 작은 차원의 $Q$, $K$, $V$ 벡터를 얻는다.
이는 $num$_$heads$에 의해 결정된다.</p>
<p>예를들어, 초기 input sequence의 차원 $d_{model}$ = $512$과 Attention의 $num$<em>$heads$ = $8$을 사용한다면, 각 $Q$, $K$, $V$ 벡터의 차원은 $d_model$ $/$ $num$</em>$heads$ = $512$ / $8$ = $64$가 된다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/436f1491-e4bb-450f-93f6-c395a54ffccf/image.png" alt=""></p>
<p>기존의 $d_{model}$ $512$차원에서 $64$차원으로 줄이기 위해 weight matrix ($512$ X $64$)를 곱해주면 된다.
위와 같은 과정을 거쳐 각 단어는 낮은 차원의 $Q$, $K$, $V$로 변환된다.</p>
<hr>



<h4 id="reference-httpsvelogiosjinutransformer-in-pytorch5-ec9db8ecbd94eb8d94encoder">[reference] <a href="https://velog.io/@sjinu/Transformer-in-Pytorch#5-%EC%9D%B8%EC%BD%94%EB%8D%94encoder">https://velog.io/@sjinu/Transformer-in-Pytorch#5-%EC%9D%B8%EC%BD%94%EB%8D%94encoder</a></h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[[선형대수학] Normal equation]]></title>
            <link>https://velog.io/@yugyeong_929/%EC%84%A0%ED%98%95%EB%8C%80%EC%88%98%ED%95%99-Normal-equation</link>
            <guid>https://velog.io/@yugyeong_929/%EC%84%A0%ED%98%95%EB%8C%80%EC%88%98%ED%95%99-Normal-equation</guid>
            <pubDate>Sat, 27 Jan 2024 05:36:23 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-the-normal-equaton">What is the normal equaton?</h1>
<ul>
<li>정규 방정식(normal equation)은 최소제곱 문제(Least Squares Problem)에서 사용되는 방법으로, 선형 회귀에서 모델 파라미터를 추정하는데 사용되는 주요한 방법입니다. </li>
</ul>
<p>-&gt; 주어진 데이터 포인트들과 모델의 예측 값 사이의 오차를 최소화하여 모델의 파라미터를 추정하는 것이 목표입니다. 
-&gt; 정규 방정식은 최소제곱법(Ordinary Least Squares)을 수학적으로 해결하는 방법 중 하나라고 말할 수 있습니다.</p>
<p>간단하게 정리하자면, <strong>정규 방정식은 다항 방정식을 행렬로 나타내고, 역행렬을 통해 최적의 값을 찾는 방법</strong>이라고 말할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/5292859e-a99e-4d17-af30-9435415e3744/image.png" alt="">
위와 같이 정규 방정식에서 비용 함수는 주로 평균 제곱 오차(Mean Squared Error, MSE)를 사용합니다.
위 수식의 비용 함수에서 제곱을 사용하는 이유는 오차의 크기와 오차의 제곱을 통한 평가 및 최적화를 효과적으로 수행하기 위함입니다. 1/2m을 곱해준 이유는 미분을 편라하게 하기 위한 목적으로 사용됩니다.</p>
<p>최솟값을 찾을 때, 주로 미분을 사용하는데 이처럼 정규 방정식에서도 
a, b에 대한 최솟값을 찾기 위해 각 변수에 대해 편미분을 취해줍니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/49cf6acd-cc00-4574-a615-0c975d4ce5b1/image.png" alt="">
최적의 계수 a, b를 구하기 위해 아래와 같이 역행렬을 이용하여 값을 찾기 위한 식을 정리해볼 수 있습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/f5ffba06-45a3-4072-be8c-84799642ee29/image.png" alt="">
이를 행렬로 나타내면 아래와 같습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/ec8cd8ae-33a8-4858-ab60-0360c9edcbee/image.png" alt="">
식을 간단히 나타내면 아래와 같고, cost값을 최소로 하는 a, b를 구할 수 있습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/36e3d456-2d21-4a2a-8ddb-cc33d6c2f868/image.png" alt=""></p>
<h1 id="선형-회귀linear-regression">선형 회귀(Linear regression)</h1>
<p>정규 방정식이 선형회귀에서 모델 파라미터를 추정하는데 쓰이는 방법이기 때문에 선형 회귀에 대해서도 알아보겠습니다.</p>
<p>먼저, x:[1, 2, 3]이라는 어떠한 입력이 있을 때, 그 예측값이 각각 y:[3, 5, 7]인 것을 아는 상황이라고 가정해보겠습니다.</p>
<p>이때, x=4라면 y가 어떤 값을 가질까요?</p>
<p>우리는 y를 x에 대한 함수로 나타낼 수 있습니다. 쉽게 f(x)=2x+1이라고 유추가 가능합니다. 만약, 데이터의 개수가 매우 많아지고 복잡해진다면 머리로 풀기에는 매우 어려운 문제가 됩니다. 이렇게 어려운 문제는 컴퓨터에게 대신 계산해달라고 할 수 있습니다.</p>
<p>컴퓨터는 문제를 어떻게 풀 수 있을까요?
이러한 문제를 <strong>선형 회귀(Linear regression)</strong>이라고 합니다.
선형 회귀 문제를 풀 수 있게 되면, 새로운 입력이 들어와도 y값을 유추해낼 수 있습니다.</p>
<p>선형회귀는 실제로 다양한 사례에서 매우 많이 관측되고 사용됩니다. 그렇기 때문에 굉장히 실용적인 모델이라고 할 수 있으며, 머신러닝과 통계에서 가장 기본이 되는 알고리즘이라고 할 수 있습니다.</p>
<p>이제, 컴퓨터가 선형 회귀 문제를 풀 수 있도록 해보겠습니다.</p>
<p>가장 먼저, 가설을 세워야 합니다.
가설함수는 H(W, b)=Wx+b라고 할 수 있고, 위 상황에서는 인간은 W는 2, b는 1이라고 유추할 수 있습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/a44d8f40-f361-40de-af49-bb00a140498b/image.png" alt=""></p>
<p>하지만, 컴퓨터는 인간처럼 유추를 할 수 없고 컴퓨터를 인간처럼 학습을 시켜줘야 하는 것 입니다.</p>
<p>다시 말해, 우리의 목표는 W값과 b값이 있을 때, W=2, b=1으로 만드는 것입니다.
컴퓨터는 이를 모르는 상황이기 때문에 가설을 초기화하여, 임의로 W=1, b=0이라고 가정해보겠습니다. 반복적인 연산을 통해서 현재 1인 W와 0인 b를 목표와 가깝게 학습을 시켜야 합니다. 이를 위해서는 현재 가설이 목표와 얼마나 잘못되었는지를 판단하기 위한 척도가 필요합니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/b7261209-11b5-4597-9e0f-38a33706c112/image.png" alt=""></p>
<p>일반적으로, 이를 cost라고 합니다.-&gt;cost(W, b) 
주로 최소제곱법을 이용하여 구합니다.</p>
<p>다시 돌아가서, 가지고 있는 x:[1, 2, 3], y:[3, 5, 7]을 그래프로 나타내보면 이와 같습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/7fb9b7bf-39ad-41c7-8392-cc9787bc6ffe/image.png" alt=""></p>
<p>이때 우리가 임의로 세운 가설인 W=1, b=0을 그래프에 그려보면 이와 같습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/8d5f9aeb-dfde-4880-a5d0-47b8ef888bea/image.png" alt="">
우리의 목표는 원래의 데이터와 가깝게 H(W, b)를 옮겨주는 것입니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/e9f98138-a474-4e96-b5bf-58e6b4558d48/image.png" alt="">
원래의 데이터와 가깝게 옮겨주기 위해서 &#39;얼마나 잘못되었는가&#39;를 판단하기 위해 비용함수를 정의해준 것 입니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/74863568-1855-4247-a090-0ecfa001c1a1/image.png" alt="">
최소제곱법은 원래의 값과 차이나는 정도를 제곱하여 그 값을 더해준 뒤에 데이터의 개수로 나눠주는 것입니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/96869a16-1090-418a-a7b0-a6d32e513839/image.png" alt="">
위 이미지에서의 비용은 현재 29/3로 원래의 값과 많이 차이난다는 것을 알 수 있습니다. 따라서, 현재의 값이 원래의 값에 근사하게 되면 이 비용은 0과 가까워지게 됩니다.</p>
<p>우리는 이 비용 함수를 정의할 수 있는데,
<img src="https://velog.velcdn.com/images/yugyeong_929/post/00af8884-16ff-4397-b3d0-89da80f52379/image.png" alt="">
위 수식처럼 나타낼 수 있습니다.
여기서 Wxi+1은 우리가 설정한 가설 즉, 예측값이라고 할 수 있고 yi는 실제값이라고 할 수 있습니다.</p>
<p>예측값과 실제값의 차이는 항상 양수로 나와야하기 때문에 제곱을 사용하였습니다. 양수로 만들기 위해서는 제곱 외에도 절댓값으로도 나타낼 수 있는데 왜 하필 제곱을 사용했을까요?</p>
<p>이에 대해서는 두가지 이유가 있습니다.</p>
<p>-&gt; 제곱을 이용하면 비용이 더 커지기 때문에 가설이 잘못되었을 때 그에대한 패널티를 더 크게 부여하기 위해서 입니다.
-&gt; 컴퓨터가 절댓값을 계산하기 위해서는 조건문을 이용해야하기 때문에 연산속도가 더 느려질 수도 있기 때문입니다.</p>
<p>그렇다면, 우리는 이 비용을 어떻게 줄여나갈 수 있을까요?
<img src="https://velog.velcdn.com/images/yugyeong_929/post/e2308ce8-fda6-4274-9ec0-33ab068ea3ad/image.png" alt="">
비용을 줄여나가기 위해서 값을 최소화하는 W, b값을 찾아야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/459d4f73-fa00-4da1-91ba-6c36e4c83ea9/image.png" alt="">
W는 식에서 기울기를 나타내는데, 만약 W를 잘못 설정하게 된다면 오차는 기하급수적으로 늘어나게 됩니다.
이를 표현하기 위해서, x축을 W로 y축을 cost로 설정하겠습니다.우리가 궁극적으로 찾고자하는 W의 값 즉, global optimum이 있다고 가정합니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/2c9c2154-7bd2-4ba1-ae10-5b73be924554/image.png" alt="">
W의 값이 global optimum과 멀어지게 되면 비용은 증가하기 때문에 위처럼 이차함수 그래프로 나타낼 수 있습니다. </p>
<p>기울기가 0이 될 때, global optimum이기 때문에
<strong>기울기가 음수라면,</strong> 오른쪽으로 (+) 옮겨가고,
<strong>기울기가 양수라면,</strong> 왼쪽으로 (-) 옮겨가면 됩니다.
옮기는 과정을 반복해서 global optimum을 찾아 나가면 됩니다. 이러한 방법을 &#39;경사하강법(Gradient Descent)라고 합니다.</p>
<p>쉽게 말해, 경사하강법은 cost를 줄이기 위해 반복적으로 기울기를 계산하여 변수의 값을 변경해나가는 과정이라고 할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/459d4f73-fa00-4da1-91ba-6c36e4c83ea9/image.png" alt="">
b값은 위의 그래프에서 y절편을 말하고, W와 마찬가지로 이차함수로 나타낼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/df8472d9-bb32-459b-81b4-e40efced3b55/image.png" alt="">
b도 같은 방식으로 위 이차함수의 기울기를 옮겨가며 최적의 값을 찾을 수 있습니다.
W와 b의 적절한 값을 찾아서 비용을 줄여나가는 과정을 선형회귀 문제를 풀어나가는 과정이라고 할 수 있습니다.</p>
<h1 id="정규방정식-gradient-descent">정규방정식? Gradient Descent?</h1>
<p>정규방정식은 비용 함수를 최소화하기 위해 수학적인 방정식을 사용하는데, 이 방법은 작은 데이터셋에서 효과적이며, 계산적으로 비용이 크지 않은 경우에 사용됩니다. 하지만, 정규방정식은 역행렬이 존재해야 하는 제약이 있습니다.</p>
<p>경사하강법은 비용 함수를 최소화하기 위해서 비용 함수의 미분을 계산하고, 이를 이용하여 모델 파라미터를 업데이트합니다.</p>
<p>reference)
<a href="https://www.youtube.com/watch?v=ve6gtpZV83E">https://www.youtube.com/watch?v=ve6gtpZV83E</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter.1] Introduction and Optimization Problems]]></title>
            <link>https://velog.io/@yugyeong_929/Chapter.01-Introduction-and-Optimization-Problems</link>
            <guid>https://velog.io/@yugyeong_929/Chapter.01-Introduction-and-Optimization-Problems</guid>
            <pubDate>Tue, 21 Nov 2023 08:41:10 GMT</pubDate>
            <description><![CDATA[<h1 id="key-words">key words</h1>
<p>#Computer Model #Optimization Model #Greedy algorithms</p>
<h1 id="knapsack-problem냅색-문제"><strong>knapsack Problem(냅색 문제)</strong></h1>
<p>constraint -&gt; enough to put in a knapsack
: 도둑이 가장 값 비싼 물건을 훔쳐야 하는 <strong>optimization problem</strong></p>
<h2 id="two-variants"><strong>Two variants</strong></h2>
<h3 id="01-knapsack-problem-vs-continuous-or-fractional-knapsack-problem">0/1 knapsack problem vs Continuous or fractional knapsack problem</h3>
<p>0/1 knapsack problem : 현재의 결정이 다음 결정에 영향을 끼침
Continuous or fractional knapsack problem : 연속 문제는 아주 쉬운 문제. Greedy algorithm으로 풀 수 있음.</p>
<h3 id="01-knapsack-problem">0/1 knapsack problem</h3>
<ul>
<li>Each item is represented by a pair, _&lt;value, weight&gt;_.</li>
<li>The knapsack can accomodate items with a total weight of no more than <em>w</em>.</li>
<li>A vector, _L _, of length n, represented the set of available items.
(Each element of the vector is an item.)</li>
<li>A vector, <em>V</em> , of length n, is used to indicate whether or not items are taken.<pre><code>  ex) V[i]=1 이면, i번 째 물건은 가져간 것. V[i]=0이면, i번 째 물건은 가져가지 않은 것.</code></pre></li>
</ul>
<p>이를 수학적으로 표현하면,</p>
<blockquote>
<p><em>Find a V that maximizes</em>
$\sum_{i=0}^{n-1}$ V[i]<em>I[i].value
<em>subject to the constraint that</em>
$\sum_{i=0}^{n-1}$ V[i]</em>I[i].weight &lt;= w</p>
</blockquote>
<h3 id="solution-brute-force-algorithm완전-탐색"><strong>Solution) Brute Force Algorithm(완전 탐색)</strong></h3>
<ol>
<li>Enumerate all possible combinations of items.(멱집합 구하기)</li>
<li>Remove all of the combinations whose total units exceeds the allowed weight.</li>
<li>From the remaining combinations choose anyone whose value is the largest.</li>
</ol>
<p><strong>-&gt; often Not Practical!!!</strong>
이는 모든 경우의 수를 고려하는 알고리즘. 최적의 해를 구할 수 있지만, 벡터의 길이가 길어질 경우, 매우 오래걸리고 복잡함. 이 방법만큼 최적의 해를 찾는 좋은 algorithm은 없지만, 꽤 좋은 algorithm은 존재.</p>
<h3 id="another-solution-is-the-flexible-greedy"><strong>Another Solution is the &quot;Flexible Greedy&quot;</strong></h3>
<p>실습 코드</p>
<pre><code class="language-python">class Food(object):
    def __init__(self, n, v, w):
        self.name = n
        self.value = v
        self.calories = w
    def getValue(self):
        return self.value
    def getCost(self):
        return self.calories
    def density(self):
        return self.getValue()/self.getCost()
    def __str__(self):
        return self.name + &#39;: &lt;&#39; + str(self.value)\
                 + &#39;, &#39; + str(self.calories) + &#39;&gt;&#39;

def buildMenu(names, values, calories):
    &quot;&quot;&quot;names, values, calories lists of same length.
       name a list of strings
       values and calories lists of numbers
       returns list of Foods&quot;&quot;&quot;
    menu = []
    for i in range(len(values)):
        menu.append(Food(names[i], values[i],
                          calories[i]))
    return menu

def greedy(items, maxCost, keyFunction):
    &quot;&quot;&quot;Assumes items a list, maxCost &gt;= 0,
         keyFunction maps elements of items to numbers&quot;&quot;&quot;
    itemsCopy = sorted(items, key = keyFunction,
                       reverse = True)
    result = []
    totalValue, totalCost = 0.0, 0.0
    for i in range(len(itemsCopy)):
        if (totalCost+itemsCopy[i].getCost()) &lt;= maxCost:
            result.append(itemsCopy[i])
            totalCost += itemsCopy[i].getCost()
            totalValue += itemsCopy[i].getValue()
    return (result, totalValue)

def testGreedy(items, constraint, keyFunction):
    taken, val = greedy(items, constraint, keyFunction)
    print(&#39;Total value of items taken =&#39;, val)
    for item in taken:
        print(&#39;   &#39;, item)

def testGreedys(foods, maxUnits):
    print(&#39;Use greedy by value to allocate&#39;, maxUnits,
          &#39;calories&#39;)
    testGreedy(foods, maxUnits, Food.getValue)
    print(&#39;\nUse greedy by cost to allocate&#39;, maxUnits,
          &#39;calories&#39;)
    testGreedy(foods, maxUnits,
               lambda x: 1/Food.getCost(x))
    print(&#39;\nUse greedy by density to allocate&#39;, maxUnits,
          &#39;calories&#39;)
    testGreedy(foods, maxUnits, Food.density)


names = [&#39;wine&#39;, &#39;beer&#39;, &#39;pizza&#39;, &#39;burger&#39;, &#39;fries&#39;,
         &#39;cola&#39;, &#39;apple&#39;, &#39;donut&#39;, &#39;cake&#39;]
values = [89,90,95,100,90,79,50,10]
calories = [123,154,258,354,365,150,95,195]
foods = buildMenu(names, values, calories)
testGreedys(foods, 1000)</code></pre>
<p>코드 내부에서 <strong>sorted</strong>를 사용 -&gt; python에서는 팀 정렬을 사용하는데, 이 정렬의 가장 나쁜 시간 복잡도는 <strong>n <em>log</em> n</strong> (여기서의 n은 물건의 개수를 뜻함.)</p>
<p>최종 시간복잡도 또한 <strong>n <em>log</em> n</strong>이기 때문에, 꽤 효율적인 알고리즘.</p>
<p><strong>+) python 문법 설명</strong>
파이썬 람다(lambda) 표현식</p>
<ul>
<li>익명(=이름이 없는)의 함수를 만들 때 사용</li>
<li>(lambda 식별자 배열 : 원하는 식)</li>
<li>이 파라미터들로 표현된 식을 계산하고 결과를 반환하는 함수를 만듬</li>
<li>def를 쓰는 대신에 인라인 함수로 정의</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI web service project] MBTIgram: 모델링-LinearSVC]]></title>
            <link>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-LinearSVC</link>
            <guid>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-LinearSVC</guid>
            <pubDate>Thu, 24 Aug 2023 14:22:04 GMT</pubDate>
            <description><![CDATA[<p>이번 포스팅은 최종 모델로 선정된 LinearSVC 모델링 과정을 설명해보려고 합니다.
미해결 과제로 남았던 &#39;클래스 불균형&#39;을 SMOTE를 통한 리샘플링으로 해결하였고, TF-IDF Vectorizer과 GridSearchCV, LinearSVC를 이용하여 모델링을 진행했습니다.</p>
<h1 id="smote"><strong>SMOTE</strong></h1>
<p><strong>SMOTE</strong>는 불균형 데이터(imbalanced data) 처리를 위한 샘플링 기법으로, 오버 샘플링에 속합니다.</p>
<pre><code>불균형 데이터를 처리해야만 했던 이유는 무엇일까요?</code></pre><p>불균형 데이터란 정상 범주의 관측치 수와 이상 범주의 관측치 수가 현저히 차이나는 데이터입니다. 만약, 불균형 데이터를 처리하지 않고 그대로 모델에 적용하여 예측을 진행한다면 어떻게 될까요?
예를 들어, 0과 1 두가지 클래스가 존재할 때 데이터 샘플 수의 비율이 99:1이라고 가정해봅시다. 이런 불균형 데이터에 대해 분류 모델을 훈련시킨 후 예측을 하면 모든 데이터를 ‘0’ 이라고 분류한다고 했을 때의 정확도(accuracy)는 99%가 됩니다. 정확도만 보고 모델 성능 평가를 해보면 잘 만들어진 모델같지만 &#39;1&#39;이라는 클래스는 제대로 분류를 해내지 못했으므로 성능이 안좋은 모델이라고 할 수 있습니다.</p>
<p>이러한 이유로, 저는 불균형 데이터를 처리해서 balanced data로 만들어줘야 했습니다.</p>
<pre><code class="language-python">from sklearn.preprocessing import LabelEncoder, OneHotEncoder

# SMOTE를 사용하기 위해서 예측 변수, 설명 변수 모두 인코딩
encoder_X = OneHotEncoder()
encoded_X = encoder_X.fit_transform(data[&#39;posts&#39;].to_numpy().reshape(-1, 1))
encoder_y = LabelEncoder()
encoded_y = encoder_y.fit_transform(data[&#39;type&#39;].to_numpy().reshape(-1, 1))</code></pre>
<p>데이터셋을 SMOTE에 적용시키기 위해서는 숫자로 매핑을 하는 과정이 필요합니다.</p>
<h1 id="encoding">Encoding</h1>
<p>처음에는 One-hot encoding으로 예측 변수, 설명 변수를 모두 인코딩하였는데, 가진 데이터셋의 예측 변수가 16개의 클래스로 이루어져 있기 때문에 벡터의 차원이 커지는 것을 방지하고자 예측변수 인코딩만 Label encoding으로 변경하여 진행했습니다.</p>
<blockquote>
<p>One-hot encoding이란?</p>
</blockquote>
<p>원핫 인코딩은 주어진 범주(category)를 나타내는 변수를 0과 1로 이루어진 이진 벡터로 변환하는 방식입니다. 각 범주에 대해 하나의 새로운 이진 변수를 만들어 해당 범주에 해당하는 위치에 1을, 다른 위치에는 0을 할당합니다. 이를 통해 각 범주 간의 상호 관계가 없다는 것을 나타낼 수 있습니다.</p>
<p>예를 들어, [&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;]와 같은 세 가지 과일 범주가 있을 경우:</p>
<ul>
<li>&#39;사과&#39;는 [1, 0, 0]</li>
<li>&#39;바나나&#39;는 [0, 1, 0]</li>
<li>&#39;오렌지&#39;는 [0, 0, 1]
이런 식으로 변환됩니다. 원핫 인코딩은 주로 범주형 변수가 상대적으로 작을 때 사용되며, 범주의 개수가 많아질수록 벡터의 차원이 커지는 단점이 있습니다.</li>
</ul>
<p>제가 가진 데이터셋으로 생각하면, 16개의 범주이기 때문에 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 이런 식으로 차원이 아주 커지게 되는 거죠.</p>
<blockquote>
<p>Label encoding이란?</p>
</blockquote>
<p>라벨 인코딩은 각 범주에 대해 순차적인 정수 값을 할당하는 방식입니다. 이 방식은 범주 간의 순서나 관계를 전제로 하기 때문에 순서가 중요한 변수에 주로 사용됩니다.</p>
<p>예를 들어, [&#39;저학년&#39;, &#39;중학년&#39;, &#39;고학년&#39;]과 같은 학년 범주가 있을 경우:</p>
<ul>
<li>&#39;저학년&#39;은 1</li>
<li>&#39;중학년&#39;은 2</li>
<li>&#39;고학년&#39;은 3
이런 식으로 변환됩니다.</li>
</ul>
<pre><code class="language-python">unique_array=np.unique(encoded_y)
print(unique_array)</code></pre>
<p>출력값: [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]
이렇게 0~15까지의 정수형으로 16개의 클래스가 제대로 맵핑된 것을 확인할 수 있었습니다.</p>
<h1 id="smote-적용">SMOTE 적용</h1>
<pre><code class="language-python">import sklearn
from imblearn.over_sampling import SMOTE

# SMOTE 적용
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(encoded_X, encoded_y)</code></pre>
<p>뒤에서 사용할 TF-IDF Vectorizer에 적용시키기 위해서 SMOTE를 통해 불균형한 데이터를 처리한 뒤, 인코딩한 데이터들을 디코딩해줘야 합니다.</p>
<pre><code class="language-python"># 인코딩한 변수들을 다시 문자열로 디코딩하는 함수 정의
def text_inverse_transform_X(encoded_data, encoder):
    decoded_data = encoder.inverse_transform(encoded_data)
    return decoded_data

def text_inverse_transform_y(encoded_data, encoder):
    decoded_data = encoder.inverse_transform(encoded_data)
    return decoded_data</code></pre>
<pre><code class="language-python"># 예측 변수, 설명 변수 디코딩
X_data = text_inverse_transform_X(X_resampled, encoder_X)
y_data = text_inverse_transform_y(y_resampled, encoder_y)</code></pre>
<pre><code class="language-python">y_data</code></pre>
<p>다음과 같이 예측변수가 제대로 디코딩 되었는지 확인했습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/e2398119-218d-4e5c-91fe-f659ca01ca88/image.png" alt=""></p>
<pre><code class="language-python">X_data</code></pre>
<p>설명변수 또한 디코딩이 제대로 수행되었습니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/2295e4cb-a15a-4d92-9337-febce0570c84/image.png" alt=""></p>
<pre><code class="language-python">from collections import Counter
Counter(y_data)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/5efc91f1-7e51-44db-ac1d-86234b34de2d/image.png" width="40%">
사진과 같이 y_data의 각 클래스별 샘플 수를 확인해보면, SMOTE가 잘 적용된 것을 볼 수 있습니다.

<h1 id="tf-idf-vectorizer">TF-IDF Vectorizer</h1>
<p><strong>TF-IDF(Term Frequency-Inverse Document Frequency)</strong>는 자연어 처리에서 널리 사용되는 텍스트 피처 추출 방법 중 하나로, 문서 내에서 단어의 중요성을 평가하는 데 도움이 되는 기술입니다.</p>
<pre><code>- TF(Term Frequency) : 특정 단어가 등장하는 횟수
- IDF(Inverse Document Frequency) : 특정 단어가 몇 개의 Document에서 등장하는지의 역수
- TF-IDF = TF*IDF</code></pre><p><strong>TF-IDF를 통해 벡터화를 하는 경우,</strong>
<span style="background-color: rgba(0, 128, 128)">1. 단어의 중요성 강조:</span> TF-IDF는 단어의 빈도와 문서 내에서 얼마나 널리 분포되어 있는지에 기반하여 단어의 중요성을 평가합니다. 단어가 특정 문서에서 높은 빈도로 등장하면서 동시에 다른 문서에서는 드물게 등장할수록 해당 단어는 그 문서의 특징을 잘 나타내는 단어로 간주됩니다.
<span style="background-color: rgba(0, 128, 128)">2. 차원 감소:</span> 텍스트 데이터는 일반적으로 고차원의 특성을 가지며, 이로 인해 차원의 저주(curse of dimensionality)와 관련된 문제가 발생할 수 있습니다. TF-IDF는 단어의 빈도를 기반으로 하지만, IDF(Inverse Document Frequency)의 역할로 인해 빈도가 높지만 모든 문서에 공통적으로 등장하는 단어들의 가중치는 낮아집니다. 따라서 흔한 단어들이 너무 큰 영향을 끼치지 않게 되어 차원을 상당히 감소시킬 수 있습니다.</p>
<pre><code class="language-python"># 변수가 바이트 형식이라면 utf-8로 디코딩
X_decoded = [x.decode(&#39;utf-8&#39;) if isinstance(x, bytes) else x for x in X_data]
y_decoded = [y.decode(&#39;utf-8&#39;) if isinstance(y, bytes) else y for y in y_data]
# data split
X, X_test, y, y_test = train_test_split(X_decoded, y_decoded, test_size=0.2, random_state=1)
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1)</code></pre>
<pre><code class="language-python">from sklearn.feature_extraction.text import TfidfVectorizer
# 벡터화
tfidf = TfidfVectorizer(lowercase=False)


# 문자열로 변환-&gt;X_train를 그대로 tfidfVectorizer로 벡터화하면 에러 발생
X_train_str = [str(x) for x in X_train]

# 훈련 데이터 벡터화
X_train_tfidf = tfidf.fit_transform(X_train_str)</code></pre>
<pre><code class="language-python">clf = LinearSVC()
clf.fit(X_train_tfidf, y_train)
# grid search를 이용해 최적의 하이퍼 파라미터 찾기
cv = GridSearchCV(clf, {&#39;C&#39;: [0.1, 0.2, 0.3, 0.4, 0.5, 1.0]}, scoring = &quot;accuracy&quot;)

text_clf = Pipeline([(&#39;tfidf&#39;,TfidfVectorizer()),(&#39;clf&#39;,cv)])
text_clf.fit(X_train_str, y_train)

C = cv.best_estimator_.C</code></pre>
<pre><code class="language-python">print(&quot;최적의 파라미터 C : &quot;, C)</code></pre>
<p>최적의 파라미터 C :  1.0</p>
<h1 id="모델-학습">모델 학습</h1>
<pre><code class="language-python">#grid search를 통해 찾은 최적의 하이퍼 파라미터 적용
text_clf = Pipeline([(&#39;tfidf&#39;,TfidfVectorizer()),(&#39;clf&#39;,LinearSVC(C=1.0))])
text_clf.fit(X_train_str, y_train)</code></pre>
<pre><code class="language-python">X_valid_str = [str(x) for x in X_valid]  # 타입에러로 인해 문자열로 변환
# valid 데이터의 mbti 예측
pred = text_clf.predict(X_valid_str)
# valid data에서의 정확도
accuracy_score(pred, y_valid)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/08d0ecb6-96d9-439b-8df5-86d0ec87ee90/image.png" width="35%">

<pre><code class="language-python">from sklearn.metrics import classification_report
print(classification_report(y_valid, pred))</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/c3af1c96-9c9f-4463-91a2-d7652149fd8e/image.png" width="60%">

<pre><code class="language-python">X_str = [str(x) for x in X]
X_test_str = [str(x) for x in X_test]
# 모든 설명변수 데이터 X 자연어처리
X_tfidf = tfidf.fit_transform(X_test_str)</code></pre>
<pre><code class="language-python">clf = LinearSVC()
clf.fit(X_tfidf, y_test)</code></pre>
<pre><code class="language-python">svc_clf = Pipeline([(&#39;tfidf&#39;,TfidfVectorizer()),(&#39;clf&#39;,LinearSVC(C=1.0))])
svc_clf.fit(X_str, y) # train/valid data 합쳐서 학습, test data로 예측

pred_svc = svc_clf.predict(X_test_str)</code></pre>
<pre><code class="language-python">accuracy_score(test_pred, y_test)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/f5d3f2e6-e247-4239-97e8-8a2e435c749f/image.png" width="35%">

<pre><code class="language-python">from sklearn.metrics import classification_report
print(classification_report(y_test, test_pred))</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/8eb153c6-db8b-40ab-8c2d-85fe29bb2f9a/image.png" width="60%">
classification report를 보니, 여러 평가 지표를 모두 확인 했을 때 성능이 좋다는 것을 볼 수 있습니다.

<h1 id="모델-저장">모델 저장</h1>
<p>학습이 된 모델을 피클 파일로 저장합니다.</p>
<pre><code class="language-python">import pickle

with open(&#39;saved_model_result&#39;, &#39;wb&#39;) as f:
    pickle.dump(svc_clf, f)</code></pre>
<h1 id="마치며"><strong>마치며..</strong></h1>
<p>MBTIgram 프로젝트를 통해 &#39;텍스트 데이터를 이용한 MBTI 예측 알고리즘&#39;을 개발했습니다. 개발의 모든 단계를 누구의 도움없이 혼자만의 힘으로 해낸게 처음이라 더욱 뿌듯하고 기억에 오래 남을 것 같습니다. 많은 시행착오를 직면한 덕에 더 많은 것을 배울 수 있었습니다. 이번 프로젝트를 통해서 남은 아쉬움과 부족한 점들을 보완하여 더욱 성장할 수 있었으면 좋겠습니다😆</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI web service project] MBTIgram: 모델링-RNN]]></title>
            <link>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-RNN</link>
            <guid>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-RNN</guid>
            <pubDate>Wed, 23 Aug 2023 11:26:04 GMT</pubDate>
            <description><![CDATA[<p>지난 포스팅에서는 XGBoost 모델링 과정을 설명했습니다:) 이번에는 시계열 데이터나 텍스트와 같은 도메인에서 강력한 성능을 발휘하는 <strong>RNN(Recurrent Neural Network) 모델링 과정</strong>에 대해서 다뤄보겠습니다.</p>
<blockquote>
<h1 id="모델링-rnn-recurrent-neural-network">모델링: RNN (Recurrent Neural Network)</h1>
</blockquote>
<pre><code class="language-python">import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
from sklearn.metrics import classification_report</code></pre>
<pre><code class="language-python">data = pd.read_csv(&#39;/content/drive/MyDrive/spp_project/data_result.csv&#39;, index_col=&#39;type&#39;) #type열을 인덱스로 설정.</code></pre>
<pre><code class="language-python">X = data[&#39;posts&#39;] #설명변수
y = data.index #예측변수</code></pre>
<pre><code class="language-python"># Train/test split
X_train, X_test, y_train, y_test = train_test_split(X_padded, y, test_size=0.2, random_state=42)</code></pre>
<pre><code class="language-python"># numpy배열로 변환
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)</code></pre>
<p>모델링은 총 2가지로 학습을 진행했습니다. 2안은 lstm layer를 한 층 더 추가하고 drop out 비율을 늘렸습니다. </p>
<h2 id="모델링-1안">모델링 1안</h2>
<pre><code class="language-python"># 모델 정의
model = Sequential()
model.add(Embedding(input_dim=max_words, output_dim=256, input_length=max_len))
model.add(LSTM(64, dropout=0.2))
model.add(Dense(len(label_to_int), activation=&#39;softmax&#39;))  # Use len(label_to_int) as the number of units

# 모델 컴파일
model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, optimizer=&#39;adam&#39;, metrics=[&#39;accuracy&#39;])

model.summary()

# Early stopping callback 설정
early_stopping = EarlyStopping(monitor=&#39;val_loss&#39;, patience=2, verbose=1)

# Learning rate reduction callback 설정
reduce_lr = ReduceLROnPlateau(monitor=&#39;val_loss&#39;, factor=0.5, patience=1, verbose=1)

# 모델 학습
batch_size = 64
epochs = 20
model.fit(X_train, y_train_int, batch_size=batch_size, epochs=epochs,
          validation_split=0.2, callbacks=[early_stopping, reduce_lr])</code></pre>
<p><strong>early stopping:</strong> 검증 데이터(validation data)의 성능을 모니터링하여 학습을 조기중단 시키는 역할을 합니다. 성능이 개선되지 않을 때 학습을 중단하여 과적합을 방지하거나 학습 시간을 단축할 수 있습니다.</p>
<ul>
<li>monitor: 모니터링할 지표 ex) &#39;val_loss&#39;, &#39;val_accuracy&#39;</li>
<li>patience: 성능이 개선되지 않아도 몇 번까지 기다릴지 지정</li>
<li>verbose: 출력 여부 ex) 0: 출력o, 1: 출력x</li>
<li>resotre_best_weights: 최상의 모델 가중치로 복원할 지 여부</li>
</ul>
<p><strong>ReduceLROnPlateau:</strong> 학습률을 동적으로 조절하는 역할을 합니다. 검증 데이터(validation data)의 성능이 개선되지 않을 때, 학습률을 줄여서 모델이 더 나은 지점으로 수렴하도록 돕습니다.</p>
<ul>
<li>monitor: 모니터링할 지표</li>
<li>factor: 학습률을 줄일 비율(새 학습률 = 현재 학습률*factor)</li>
<li>verbose: 출력 여부</li>
<li>min_lr: 학습률의 하한 값</li>
</ul>
<p>아래의 결과를 보면, early stopping의 patience = 2로 설정했지 때문에 epoch 2개에서 연속으로 val_loss가 증가하면 성능이 개선되지 않는 것으로 학습이 조기 종료 되는 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/30e3e16e-92f4-4dbf-8384-b6a39623e370/image.png" alt=""></p>
<pre><code class="language-python"># 예측
pred_probs = model.predict(X_test)
pred_classes = np.argmax(pred_probs, axis=1)

# classification report 계산 및 출력
report = classification_report(y_test_int, pred_classes, target_names=label_to_int.keys())
print(report)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/25394c7c-ff6e-412d-a257-38d0e62934cb/image.png" width="55%">
classification report를 보면, support(각 클래스에 속한 샘플의 수)가 적은 클래스는 대체적으로 precision, recall, f1-score가 모두 낮은 것을 볼 수 있습니다. 성능을 높이기 위해서는 파라미터 튜닝(모델의 layer 층 개수 조절 등), 클래스 불균형 해결, drop out 비율 조절 등의 방법이 있습니다.

<p>처음으로 고려했던 방법은 <strong>가중치 조정</strong>을 통한 <strong>&#39;클래스 불균형 해결&#39;</strong>이었는데, 오히려 정확도가 심하게 낮아지고 검증 데이터에 대한 성능이 거의 개선되지 않고 학습이 조기 종료되어 다른 방법을 시도했습니다. </p>
<p>코드에는 사용하지 않았지만, 가중치 조정에 대해 궁금하신 분들은 참고 바랍니다.<strong>가중치 조정 방법</strong>은 다음과 같습니다.</p>
<pre><code> 클래스 불균형 문제를 해결하기 위해서는 class_weight 매개변수를 사용하면 됩니다. 
 class_weight는 손실 함수 계산 시 각 클래스에 적용할 가중치를 지정하는 매개변수로, 
 불균형한 클래스에 높은 가중치를 부여하여 모델이 불균형한 데이터를 더 잘 학습할 수 있도록 도와줍니다.</code></pre><pre><code class="language-python"># 필요한 모듈 임포트
from sklearn.utils.class_weight import compute_class_weight

# 클래스 가중치 계산
class_weights = compute_class_weight(class_weight = &quot;balanced&quot;, classes = np.unique(y_train_int), y = y_train_int)
class_weight_dict = {i: w for i, w in enumerate(class_weights)}
.
.
(생략)
.
.
# 매개변수에 class_weight=class_weight_dict 추가
model.fit(X_train, y_train_int, batch_size=batch_size, epochs=epochs,
          validation_split=0.2, callbacks=[early_stopping, reduce_lr], class_weight=class_weight_dict)</code></pre>
<h2 id="모델링-2안">모델링 2안</h2>
<pre><code class="language-python"># Define the model
model = Sequential()
model.add(Embedding(input_dim=max_words, output_dim=256, input_length=max_len))
model.add(LSTM(128, dropout=0.3, return_sequences=True))
model.add(LSTM(128, dropout=0.3))
model.add(Dense(len(label_to_int), activation=&#39;softmax&#39;))  # Use len(label_to_int) as the number of units

# Compile the model
model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, optimizer=&#39;adam&#39;, metrics=[&#39;accuracy&#39;])

# Print model summary
model.summary()

# Early stopping callback
early_stopping = EarlyStopping(monitor=&#39;val_loss&#39;, patience=2, verbose=1)

# Learning rate reduction callback
reduce_lr = ReduceLROnPlateau(monitor=&#39;val_loss&#39;, factor=0.5, patience=1, verbose=1)

# Train the model
batch_size = 64
epochs = 30
model.fit(X_train, y_train_int, batch_size=batch_size, epochs=epochs,
          validation_split=0.2, callbacks=[early_stopping, reduce_lr])</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/8b0b0d5c-41bf-4c94-ac69-4a87b2fa102c/image.png" alt=""></p>
<pre><code class="language-python"># Predict classes
pred_probs = model.predict(X_test)
pred_classes = np.argmax(pred_probs, axis=1)

# Calculate classification report
report = classification_report(y_test_int, pred_classes, target_names=label_to_int.keys())
print(report)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/9c9f3d09-d0eb-41ab-9ec1-051a00a9933a/image.png" width="55%">
2안도 마찬가지로 support(각 클래스에 속한 샘플의 수)가 적은 클래스는 대체적으로 precision, recall, f1-score가 모두 낮은 것을 볼 수 있습니다. 클래스 불균형 해결이 가장 중요할 것 같다는 생각이 들었고, 가중치 조정으로 계속 시도를 해보았지만 해결이 안되었기 때문에 처음에 사용하던 LinearSVC 모델에 데이터 리샘플링을 추가해보기로 결정했습니다.

<h2 id="마치며">마치며..</h2>
<p>딥러닝 모델링 경험이 많지 않아서 더욱 많은 시간을 투자했지만 좋은 결과는 얻지 못했던 것 같습니다. 이번에 딥러닝 모델링을 직접 해보면서 공부해야할 부분이 많다는 것을 느꼈습니다. 다양한 에러와 좋지 않은 성능을 마주하는 등 많은 시행착오를 겪으면서, 배울 수 있었고 부족함을 많이 느꼈습니다. 초반에 짰던 알고리즘부터 최종 결과물까지 비교를 하면 많이 성장한 것 같다는 생각도 들었습니다. 다음 포스팅에서는 처음 짰던 LinearSVC 코드와 최종 모델로 완성된 LinearSVC 코드에 대한 설명을 모두 작성하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AI web service project] MBTIgram: 모델링-XGBoost]]></title>
            <link>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-XGBoost</link>
            <guid>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%AA%A8%EB%8D%B8%EB%A7%81-XGBoost</guid>
            <pubDate>Tue, 22 Aug 2023 07:39:40 GMT</pubDate>
            <description><![CDATA[<p>지난번 포스팅에서 전처리 및 EDA를 수행한 내용을 바탕으로 모델링을 진행했습니다.
3가지 모델을 후보로 실험 및 검증을 진행했습니다. 전처리 및 EDA 과정은 이전 글을 참고 바랍니다.</p>
<h1 id="모델-선정">모델 선정</h1>
<ol>
<li>XGBoost</li>
<li>RNN</li>
<li>LinearSVC</li>
</ol>
<p>세 가지로 후보를 둔 이유는 다음과 같습니다.</p>
<h2 id="xgboost-extreme-gradient-boosting">XGBoost (eXtreme Gradient Boosting)</h2>
<ul>
<li>XGBoost는 부스팅 알고리즘으로 앙상블 기법을 사용하며, 다양한 데이터 유형과 복잡한 패턴에 대해 강력한 성능을 보일 수 있다.</li>
<li><strong>클래스 불균형 문제를 다룰 수 있는 가중치 조정과 샘플링 기법을 제공하여 불균형 데이터셋에도 잘 대응할 수 있다.</strong></li>
<li>Feature Importance를 제공하여 모델의 예측에 어떤 특성이 중요한지를 해석하기 쉽게 도와줍니다.</li>
</ul>
<p>+) XGBoost는 하이퍼 파라미터 튜닝이 중요하기 때문에, 추가적으로 GridSearchCV를 이용하여 최적의 파라미터를 찾고 학습을 진행하였습니다.</p>
<br>

<h2 id="rnn-recurrent-neural-network">RNN (Recurrent Neural Network)</h2>
<ul>
<li>RNN은 장기 의존성을 학습하는데 우수하며, 시계열 데이터나 <strong>텍스트와 같은 도메인에서 강력한 성능을 발휘할 수 있다.</strong></li>
</ul>
<p>+) 클래스 불균형 문제를 해결하기 위해서 불균형한 클래스의 샘플 비율에 따라서 자동으로 가중치 조정을 하는 &#39;compute_class_weight&#39;를 이용하였습니다.</p>
<h2 id="linearsvc-support-vector-machine-with-linear-kernel">LinearSVC (Support Vector Machine with Linear Kernel)</h2>
<p>-LinearSVC는 선형 결정 경계를 통해 클래스를 분리하기 때문에, <strong>비교적 간단하면서도 높은 성능</strong>을 발휘할 수 있다.</p>
<ul>
<li>고차원 데이터에서도 잘 동작하며, 특히 <strong>텍스트 분류와 같은 자연어 처리 작업에서 효과적</strong>일 수 있다.</li>
<li><strong>클래스 불균형 문제에도 상대적으로 덜 민감</strong>할 수 있다.</li>
</ul>
<p>+) LinearSVC도 XGBoost와 마찬가지로 최적의 C값을 찾기 위해서 GridSearchCV를 사용했습니다.</p>
<br>

<blockquote>
<h1 id="모델링-xgboost-extreme-gradient-boosting">모델링: XGBoost (eXtreme Gradient Boosting)</h1>
</blockquote>
<h1 id="전처리">전처리</h1>
<p>XGBoost를 사용하기 위해서 TF-IDF를 통한 벡터화와 label을 숫자로 매핑하기 위해 Label Encoder로 전처리를 한번 더 수행했습니다.</p>
<pre><code class="language-python">posts = data[&#39;posts&#39;] # 설명변수
MBTItype = data[&#39;type&#39;] # 예측변수

# numpy배열로 변환
posts_list = posts.to_numpy()
type_list = MBTItype.to_numpy()</code></pre>
<pre><code class="language-python">type_list</code></pre>
<p>array([&#39;INTJ&#39;, &#39;INTJ&#39;, &#39;INTJ&#39;, ..., &#39;INTP&#39;, &#39;INFP&#39;, &#39;INFP&#39;], dtype=object)</p>
<pre><code class="language-python">posts_list</code></pre>
<p>array([&#39;know tool use interaction people excuse antisocial truly enlighten mastermind know would count pet peeze something time matter people either whether group people mall never see best friend sit outside conversation jsut listen want interject sit formulate say wait inject argument thought find fascinate sit watch people talk people fascinate sit class watch different people find intrigue dad stand look like line safeway watch people home talk people like think military job people ...(생략)</p>
<pre><code class="language-python">import sklearn
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

# posts_list를 모델에 사용할 토큰 개수 행렬로 벡터화
cntizer = CountVectorizer(analyzer=&quot;word&quot;,
                             max_features=1000,
                             max_df=0.7,
                             min_df=0.1)
# analyzer=&quot;word&quot;: 텍스트를 단어 단위로 분석
# max_features=1000: 최대 1000개의 단어 피처를 선택
# max_df=0.7: 문서 빈도가 70% 이상인 단어는 무시
# min_df=0.1: 문서 빈도가 최소 10% 이상

print(&quot;Using CountVectorizer :&quot;)

# posts_list를 토큰 개수 행렬로 변환
X_cnt = cntizer.fit_transform(posts_list)

feature_names = list(enumerate(cntizer.get_feature_names_out()))
print(&quot;10 feature names can be seen below&quot;)
print(feature_names[0:10])



tfizer = TfidfTransformer()

print(&quot;\nUsing Tf-idf :&quot;)

print(&quot;Now the dataset size is as below&quot;)
# 카운트 행렬 X_cnt를 tf-idf 표현으로 변환
X_tfidf =  tfizer.fit_transform(X_cnt).toarray()
print(X_tfidf.shape)
</code></pre>
<p>Using CountVectorizer :
10 feature names can be seen below
[(0, &#39;ability&#39;), (1, &#39;able&#39;), (2, &#39;absolutely&#39;), (3, &#39;accept&#39;), (4, &#39;accurate&#39;), (5, &#39;across&#39;), (6, &#39;act&#39;), (7, &#39;action&#39;), (8, &#39;actual&#39;), (9, &#39;actually&#39;)]</p>
<p>Using Tf-idf :
Now the dataset size is as below
(114742, 672)</p>
<pre><code class="language-python">#counting top 10 words
reverse_dic = {}
for key in cntizer.vocabulary_:
    reverse_dic[cntizer.vocabulary_[key]] = key
top_10 = np.asarray(np.argsort(np.sum(X_cnt, axis=0))[0,-10:][0, ::-1]).flatten()
[reverse_dic[v] for v in top_10]</code></pre>
<p>XGBoost를 사용하기 위해 LabelEncoder를 사용했습니다. XGBoost는 기본적으로 숫자형 데이터를 다루는데 특화되어 있기 때문에 범주형 변수를 사용하려면 이를 숫자로 변환해야 합니다.</p>
<p>제가 사용한 데이터셋은 16개의 범주형 변수가 사용되었기 때문에 이를 0~15의 숫자로 매핑하여 모델이 이해할 수 있는 형태로 변환해주었습니다.</p>
<pre><code class="language-python">#XGBoost를 사용하기 위해 LabelEncoder 사용
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
le.fit(type_list)
type_list = le.transform(type_list)</code></pre>
<pre><code class="language-python">from sklearn.model_selection import train_test_split
X_data = X_tfidf
y_data = type_list

X, X_test, y, y_test = train_test_split(X_data, y_data, test_size=0.2, random_state=1)
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1)</code></pre>
<h1 id="모델-학습">모델 학습</h1>
<pre><code class="language-python">from xgboost import XGBClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import numpy as np


xgb_model = XGBClassifier(n_estimators=100)
params = {&#39;learning_rate&#39;: [0.1, 0.06,  0.02], &#39;max_depth&#39;:[3, 5, 7], &#39;colsample_bytree&#39;:[0.3, 0.5,0.75]} # &#39;n_estimators&#39;: [100, 300, 500],&#39;min_child_weight&#39;:[1,3], // &#39;scale_pos_weight&#39;: [1, 5, 10] 를 작성해도 사용되지 않아 경고가 뜸.

# GridSearchCV 객체 생성
gridcv = GridSearchCV(xgb_model, param_grid=params, cv=3, scoring=&#39;f1_weighted&#39;)

# 파라미터 튜닝 시작
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric=&#39;mlogloss&#39;, eval_set=[(X_valid, y_valid)])

# 튜닝된 파라미터 출력
print(gridcv.best_params_)
print(gridcv.best_score_)</code></pre>
<p>클래스 불균형 문제 해소를 위해서 하이퍼 파라미터 튜닝을 할때, scoring=&#39;f1_weighted&#39;와 같이 설정하여 가중치를 적용한 평균 F1-score를 통해 최적의 하이퍼 파라미터를 구했습니다.</p>
<pre><code>다음과 같이 하이퍼 파라미터 튜닝 결과가 나왔으며, 이를 바탕으로 학습을 진행하였습니다.</code></pre><p>하이퍼 파라미터 튜닝 결과:
<img src="https://velog.velcdn.com/images/yugyeong_929/post/45c8bddf-d201-43e7-b20a-a9e572d0571d/image.png" alt=""></p>
<pre><code class="language-python">from xgboost import XGBClassifier
from sklearn.model_selection import GridSearchCV

# 1차적으로 튜닝된 파라미터를 가지고 객체 생성
xgb_model = XGBClassifier(n_estimators=500, learning_rate=0.1, max_depth=7, min_child_weight=3, colsample_bytree=0.75, reg_alpha=0.03)

# 학습
xgb_model.fit(X, y, early_stopping_rounds=200, eval_metric=&#39;mlogloss&#39;, eval_set=[(X_test, y_test)])</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/ed0f5f57-d8fd-4b58-91b0-a5cd4c090edc/image.png" alt=""></p>
<pre><code class="language-python">from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix, f1_score

xgb_pred = xgb_model.predict(X_test)

accuracy = accuracy_score(y_test, xgb_pred)
precision = precision_score(y_test, xgb_pred, average=&#39;weighted&#39;)
recall = recall_score(y_test, xgb_pred, average=&#39;weighted&#39;)
f1 = f1_score(y_test, xgb_pred, average = &#39;weighted&#39;)

print(accuracy)
print(precision)
print(recall)
print(f1)
print(&#39;정확도 : {:.4f}\n정밀도 : {:.4f}\n재현율 : {:.4f}\nf1-score : {:.4f}&#39;.format(accuracy, precision, recall, f1))</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/089a6b1d-8c4f-42c2-a8c9-cbe36437bc01/image.png" alt=""></p>
<br>

<h1 id="📌-초기-모델링과의-차이점">📌 초기 모델링과의 차이점</h1>
<p> 프로젝트 시작의 목적은 <strong>University of Southern California</strong>에서 주최한 <strong>2023년도 한미 해커톤</strong>을 위한 개발이었기 때문에 시간 부족으로 인해 전처리 및 EDA 작업이 부족했습니다. 클래스 불균형 문제의 심각성을 알고 있었지만, 이를 고려하여 모델링을 진행하기 어려웠습니다.</p>
<p> 프로젝트 초기에 <strong>LinearSVC</strong>를 이용하여 개발했던 알고리즘은 <strong>accuracy만</strong>을 고려하여 모델 성능 평가를 진행했는데 <strong>84%</strong>라는 정확도만 보고 성능이 좋다고 판단했습니다. 이는 <strong>클래스 불균형을 전혀 고려하지 않은 성능 평가</strong>입니다.</p>
 <br>

<p> <span style="background-color: rgba(242,179,188,0.5)"><strong>클래스 불균형 문제가 있을 때, accuracy만을 사용하여 모델 평가를 하면 안되는 이유:</strong></span></p>
<ul>
<li>데이터 불균형으로 인한 왜곡: 클래스 간 샘플 수가 많이 차이나면, 모델이 샘플 수가 많은 클래스를 더 잘 분류하도록 학습되기 쉽다. </li>
<li>이로 인해, 샘플 수가 적은 클래스를 정확하게 예측하지 못할 수 있으며, 데이터 불균형으로 인해 정확도가 높아지는 현상이 발생할 수 있다.</li>
</ul>
<p><span style="background-color: rgba(242,179,188,0.5)"><strong>F1-score를 사용해야 하는 이유:</strong></span></p>
<ul>
<li>데이터 불균형으로 인한 편향을 상쇄하여, 클래스 간 예측 성능을 균형있게 평가한다.</li>
<li>F1-score는 정밀도와 재현율을 모두 고려하기 때문에, 클래스 간 불균형에 민감하게 반응한다. </li>
<li>모델이 작은 클래스의 예측을 얼마나 잘 수행하는지를 보다 정확하게 평가할 수 있다.</li>
</ul>
<p><strong>따라서, 성능 평가에 F1-score 또한 포함하기로 결정하였습니다.</strong></p>
<br>

<h1 id="포스팅을-마치며">포스팅을 마치며..</h1>
<p>결과적으로, 첫 모델은 accuracy는 높지만 f1-score가 아주 낮았기 때문에 현재의 모델도 성능이 좋다고 판단할 수는 없으나 개선이 되었다는 것을 알 수 있었습니다. 모델의 성능이 좋지 않은 이유는 XGBoost와 같은 gradient boosting 알고리즘은 주로 수치형 데이터에 대한 모델링에 뛰어난 성능을 보이지만, 텍스트와 같은 비정형 데이터에는 다소 한계가 있기 때문이라고 생각합니다. 불균형 클래스에 덜 민감하지만, 텍스트 데이터를 사용한 모델링이기 때문에 적합하지 않은 모델이라는 생각이 들었습니다.</p>
<p>그동안 모델링을 할때, 불균형 클래스 문제가 있는 데이터셋을 다뤄본 적이 많이 없었기 때문에 accuracy만을 고려하여 모델 성능 평가를 했습니다. 불균형이 심각한 데이터를 사용하여 모델링을 진행해보면서, 다양한 지표를 활용하여 모델 성능 평가를 해야 한다는 점을 배울 수 있었던 것 같습니다.</p>
<p>부족한 글이지만, 읽어주셔서 감사합니다.☺️</p>
<pre><code>다음 포스팅은 &#39;RNN 모델링과 성능평가&#39;입니다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[AI web service project] MBTIgram: 데이터셋 전처리 및 EDA]]></title>
            <link>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%85%8B-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B0%8F-EDA</link>
            <guid>https://velog.io/@yugyeong_929/AI-web-service-project-MBTIgram-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%85%8B-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B0%8F-EDA</guid>
            <pubDate>Fri, 18 Aug 2023 19:10:12 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개발환경과-데이터셋">1. 개발환경과 데이터셋</h2>
<blockquote>
<p>💻  <strong>개발환경</strong>: Google Colab
✅  <strong>사용 데이터셋</strong>
<strong>(MBTI) Myers-Briggs Personality Type Dataset</strong>
[Link] <a href="https://www.kaggle.com/datasets/datasnaek/mbti-type">https://www.kaggle.com/datasets/datasnaek/mbti-type</a>
mbti_1.csv<br><br><strong>MBTI Personality Types 500 Datase</strong>t
[Link] <a href="https://www.kaggle.com/datasets/zeyadkhalid/mbti-personality-types-500-dataset">https://www.kaggle.com/datasets/zeyadkhalid/mbti-personality-types-500-dataset</a>
MBTI 500.csv</p>
</blockquote>
<p>kaggle에 있는 2개의 MBTI 데이터셋을 사용했습니다.
type, posts 2개의 열을 가진 데이터로, type은 mbti 종류이며 posts는 해당 mbti가 작성한 텍스트 데이터입니다.</p>
<p>❤️저는 colab을 아주 애용하기 때문에 이번 프로젝트도 colab을 사용하여 개발을 진행하였습니다.❤️</p>
<h2 id="2-데이터-전처리">2. 데이터 전처리</h2>
<pre><code class="language-python">from google.colab import drive
drive.mount(&#39;/content/drive&#39;)

import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings(&#39;ignore&#39;)

import seaborn as sns
import matplotlib.pyplot as plt

#데이터셋 로드
data = pd.read_csv(&#39;/content/drive/MyDrive/spp_project/mbti_concat.csv&#39;)</code></pre>
<p>위 코드에서 로드한 데이터셋은 사전에 2개의 데이터셋을 합친 csv 파일입니다.</p>
<pre><code class="language-python">data</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/af68863c-c710-4e9f-bd54-eb3af097886c/image.png" alt=""></p>
<p>데이터셋을 합치면서 생성된 &#39;Unnamed: 0&#39; 컬럼이 보입니다. concat()을 진행하는 과정에서 index가 하나 더 생긴 것 같습니다. 불필요하기 때문에 해당 열 전체를 삭제해줍니다.</p>
<pre><code class="language-python"># 불필요한 열 제거
data = data.drop([&#39;Unnamed: 0&#39;], axis=1)
data</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/a2696ede-9e4e-4c6c-8d40-2fb5bc22427f/image.png" alt="">
해당 열이 삭제된 것을 확인되었으니 본격적인 전처리를 시작하겠습니다.
영어에는 &#39;축약형&#39;이라는 것이 존재하기 때문에 이러한 텍스트를 정제하는 과정을 거쳐야 합니다. 아래의 링크를 참고하여 코드를 작성하였습니다.
<a href="https://stackoverflow.com/questions/19790188/expanding-english-language-contractions-in-python">https://stackoverflow.com/questions/19790188/expanding-english-language-contractions-in-python</a></p>
<pre><code class="language-python"># 전처리 함수에서 사용할 contractions 생성
contractions = {&quot;&#39;cause&quot;: &#39;because&#39;,
 &quot;I&#39;d&quot;: &#39;I would&#39;,
 &quot;I&#39;d&#39;ve&quot;: &#39;I would have&#39;,
 &quot;I&#39;ll&quot;: &#39;I will&#39;,
 &quot;I&#39;ll&#39;ve&quot;: &#39;I will have&#39;,
 &quot;I&#39;m&quot;: &#39;I am&#39;,
 &quot;I&#39;ve&quot;: &#39;I have&#39;,
 &quot;ain&#39;t&quot;: &#39;is not&#39;,
 &quot;aren&#39;t&quot;: &#39;are not&#39;,
 &quot;can&#39;t&quot;: &#39;cannot&#39;,
 &quot;could&#39;ve&quot;: &#39;could have&#39;,
 &quot;couldn&#39;t&quot;: &#39;could not&#39;,
 &quot;didn&#39;t&quot;: &#39;did not&#39;,
 &quot;doesn&#39;t&quot;: &#39;does not&#39;,
 &quot;don&#39;t&quot;: &#39;do not&#39;,
 &quot;hadn&#39;t&quot;: &#39;had not&#39;,
 &quot;hasn&#39;t&quot;: &#39;has not&#39;,
 &quot;haven&#39;t&quot;: &#39;have not&#39;,
 &quot;he&#39;d&quot;: &#39;he would&#39;,
 &quot;he&#39;ll&quot;: &#39;he will&#39;,
 &quot;he&#39;s&quot;: &#39;he is&#39;,
 &quot;here&#39;s&quot;: &#39;here is&#39;,
 &quot;how&#39;d&quot;: &#39;how did&#39;,
 &quot;how&#39;d&#39;y&quot;: &#39;how do you&#39;,
 &quot;how&#39;ll&quot;: &#39;how will&#39;,
 &quot;how&#39;s&quot;: &#39;how is&#39;,
 &quot;i&#39;d&quot;: &#39;i would&#39;,
 &quot;i&#39;d&#39;ve&quot;: &#39;i would have&#39;,
 &quot;i&#39;ll&quot;: &#39;i will&#39;,
 &quot;i&#39;ll&#39;ve&quot;: &#39;i will have&#39;,
 &quot;i&#39;m&quot;: &#39;i am&#39;,
 &quot;i&#39;ve&quot;: &#39;i have&#39;,
 &quot;isn&#39;t&quot;: &#39;is not&#39;,
 &quot;it&#39;d&quot;: &#39;it would&#39;,
 &quot;it&#39;d&#39;ve&quot;: &#39;it would have&#39;,
 &quot;it&#39;ll&quot;: &#39;it will&#39;,
 &quot;it&#39;ll&#39;ve&quot;: &#39;it will have&#39;,
 &quot;it&#39;s&quot;: &#39;it is&#39;,
 &quot;let&#39;s&quot;: &#39;let us&#39;,
 &quot;ma&#39;am&quot;: &#39;madam&#39;,
 &quot;mayn&#39;t&quot;: &#39;may not&#39;,
 &quot;might&#39;ve&quot;: &#39;might have&#39;,
 &quot;mightn&#39;t&quot;: &#39;might not&#39;,
 &quot;mightn&#39;t&#39;ve&quot;: &#39;might not have&#39;,
 &quot;must&#39;ve&quot;: &#39;must have&#39;,
 &quot;mustn&#39;t&quot;: &#39;must not&#39;,
 &quot;mustn&#39;t&#39;ve&quot;: &#39;must not have&#39;,
 &quot;needn&#39;t&quot;: &#39;need not&#39;,
 &quot;needn&#39;t&#39;ve&quot;: &#39;need not have&#39;,
 &quot;o&#39;clock&quot;: &#39;of the clock&#39;,
 &quot;oughtn&#39;t&quot;: &#39;ought not&#39;,
 &quot;oughtn&#39;t&#39;ve&quot;: &#39;ought not have&#39;,
 &quot;sha&#39;n&#39;t&quot;: &#39;shall not&#39;,
 &quot;shan&#39;t&quot;: &#39;shall not&#39;,
 &quot;shan&#39;t&#39;ve&quot;: &#39;shall not have&#39;,
 &quot;she&#39;d&quot;: &#39;she would&#39;,
 &quot;she&#39;d&#39;ve&quot;: &#39;she would have&#39;,
 &quot;she&#39;ll&quot;: &#39;she will&#39;,
 &quot;she&#39;ll&#39;ve&quot;: &#39;she will have&#39;,
 &quot;she&#39;s&quot;: &#39;she is&#39;,
 &quot;should&#39;ve&quot;: &#39;should have&#39;,
 &quot;shouldn&#39;t&quot;: &#39;should not&#39;,
 &quot;shouldn&#39;t&#39;ve&quot;: &#39;should not have&#39;,
 &quot;so&#39;s&quot;: &#39;so as&#39;,
 &quot;so&#39;ve&quot;: &#39;so have&#39;,
 &quot;that&#39;d&quot;: &#39;that would&#39;,
 &quot;that&#39;d&#39;ve&quot;: &#39;that would have&#39;,
 &quot;that&#39;s&quot;: &#39;that is&#39;,
 &quot;there&#39;d&quot;: &#39;there would&#39;,
 &quot;there&#39;d&#39;ve&quot;: &#39;there would have&#39;,
 &quot;there&#39;s&quot;: &#39;there is&#39;,
 &quot;they&#39;d&quot;: &#39;they would&#39;,
 &quot;they&#39;d&#39;ve&quot;: &#39;they would have&#39;,
 &quot;they&#39;ll&quot;: &#39;they will&#39;,
 &quot;they&#39;ll&#39;ve&quot;: &#39;they will have&#39;,
 &quot;they&#39;re&quot;: &#39;they are&#39;,
 &quot;they&#39;ve&quot;: &#39;they have&#39;,
 &quot;this&#39;s&quot;: &#39;this is&#39;,
 &quot;to&#39;ve&quot;: &#39;to have&#39;,
 &quot;wasn&#39;t&quot;: &#39;was not&#39;,
 &quot;we&#39;d&quot;: &#39;we would&#39;,
 &quot;we&#39;d&#39;ve&quot;: &#39;we would have&#39;,
 &quot;we&#39;ll&quot;: &#39;we will&#39;,
 &quot;we&#39;ll&#39;ve&quot;: &#39;we will have&#39;,
 &quot;we&#39;re&quot;: &#39;we are&#39;,
 &quot;we&#39;ve&quot;: &#39;we have&#39;,
 &quot;weren&#39;t&quot;: &#39;were not&#39;,
 &quot;what&#39;ll&quot;: &#39;what will&#39;,
 &quot;what&#39;ll&#39;ve&quot;: &#39;what will have&#39;,
 &quot;what&#39;re&quot;: &#39;what are&#39;,
 &quot;what&#39;s&quot;: &#39;what is&#39;,
 &quot;what&#39;ve&quot;: &#39;what have&#39;,
 &quot;when&#39;s&quot;: &#39;when is&#39;,
 &quot;when&#39;ve&quot;: &#39;when have&#39;,
 &quot;where&#39;d&quot;: &#39;where did&#39;,
 &quot;where&#39;s&quot;: &#39;where is&#39;,
 &quot;where&#39;ve&quot;: &#39;where have&#39;,
 &quot;who&#39;ll&quot;: &#39;who will&#39;,
 &quot;who&#39;ll&#39;ve&quot;: &#39;who will have&#39;,
 &quot;who&#39;s&quot;: &#39;who is&#39;,
 &quot;who&#39;ve&quot;: &#39;who have&#39;,
 &quot;why&#39;s&quot;: &#39;why is&#39;,
 &quot;why&#39;ve&quot;: &#39;why have&#39;,
 &quot;will&#39;ve&quot;: &#39;will have&#39;,
 &quot;won&#39;t&quot;: &#39;will not&#39;,
 &quot;won&#39;t&#39;ve&quot;: &#39;will not have&#39;,
 &quot;would&#39;ve&quot;: &#39;would have&#39;,
 &quot;wouldn&#39;t&quot;: &#39;would not&#39;,
 &quot;wouldn&#39;t&#39;ve&quot;: &#39;would not have&#39;,
 &quot;y&#39;all&quot;: &#39;you all&#39;,
 &quot;y&#39;all&#39;d&quot;: &#39;you all would&#39;,
 &quot;y&#39;all&#39;d&#39;ve&quot;: &#39;you all would have&#39;,
 &quot;y&#39;all&#39;re&quot;: &#39;you all are&#39;,
 &quot;y&#39;all&#39;ve&quot;: &#39;you all have&#39;,
 &quot;you&#39;d&quot;: &#39;you would&#39;,
 &quot;you&#39;d&#39;ve&quot;: &#39;you would have&#39;,
 &quot;you&#39;ll&quot;: &#39;you will&#39;,
 &quot;you&#39;ll&#39;ve&quot;: &#39;you will have&#39;,
 &quot;you&#39;re&quot;: &#39;you are&#39;,
 &quot;you&#39;ve&quot;: &#39;you have&#39;}</code></pre>
<p>데이터셋에서 유의미한 단어 토큰만을 선별하기 위해서 큰 의미가 없는 단어 토큰을 제거하는 과정이 필요합니다. 예를 들어, &#39;I&#39;, &#39;my&#39;, &#39;me&#39;, 조사, 접미사 등과 같은 단어들은 문장에 빈번하게 등장하지만 의미 분석을 하는데는 많은 기여를 하지 않는 경우가 많습니다. 이러한 단어들을 불용어(stopword)라고 하며, nltk에는 불용어들을 패키지 내에서 미리 정의하고 있습니다.</p>
<p>nltk의 불용어를 사용하기위한 모듈을 import해야 하는데, 만약 데이터가 없다는 에러가 발생하면 nltk.download라는 커맨드를 통해서 다운로드가 가능합니다.</p>
<pre><code class="language-python">import nltk
nltk.download(&#39;stopwords&#39;)
from nltk.corpus import stopwords

# NLTK의 불용어
stop_words = set(stopwords.words(&#39;english&#39;))
print(&#39;불용어 개수 :&#39;, len(stop_words))
print(stop_words)</code></pre>
<p>stopwords.words(&quot;english&quot;)는 nltk가 정의한 영어 불용어 리스트를 반환해줍니다. 위의 코드로 불용어의 개수와 불용어를 출력해서 확인할 수 있습니다. 불용어 개수는 179개라는 것을 확인하였습니다.</p>
<pre><code class="language-python">import re
from bs4 import BeautifulSoup

# 전처리 함수
def preprocess_sentence(sentence, remove_stopwords = True):
    sentence = re.sub(r&#39;https?:\/\/.*?[\s+]&#39;, &#39;&#39;, sentence) # Links 제거
    sentence = sentence.lower() # 텍스트 소문자화
    sentence = BeautifulSoup(sentence, &quot;lxml&quot;).text # &lt;br /&gt;, &lt;a href = ...&gt; 등의 html 태그 제거
    sentence = re.sub(r&#39;\([^)]*\)&#39;, &#39;&#39;, sentence) # 괄호로 닫힌 문자열  제거 Ex) my friend(yugyeong) -&gt; my friend
    sentence = re.sub(&#39;&quot;&#39;,&#39;&#39;, sentence) # 쌍따옴표 &quot; 제거
    sentence = &#39; &#39;.join([contractions[t] if t in contractions else t for t in sentence.split(&quot; &quot;)]) # 약어 정규화
    sentence = re.sub(r&quot;&#39;s\b&quot;,&quot;&quot;,sentence) # 소유격 제거. Ex) yugyeong&#39;s -&gt; yugyeong
    sentence = re.sub(&quot;[^a-zA-Z]&quot;, &quot; &quot;, sentence) # 영어 외 문자(숫자, 특수문자 등) 공백으로 변환
    sentence = re.sub(&#39;[m]{2,}&#39;, &#39;mm&#39;, sentence) # m이 3개 이상이면 2개로 변경. Ex) ummmmmmm  -&gt; umm

    pers_types = [&#39;infp&#39; ,&#39;infj&#39;, &#39;intp&#39;, &#39;intj&#39;, &#39;istp&#39;, &#39;isfp&#39;, &#39;isfj&#39;,&#39;istp&#39;, &#39;entp&#39;, &#39;enfp&#39;, &#39;entj&#39;, &#39;enfj&#39;, &#39;estp&#39;, &#39;esfp&#39; ,&#39;esfj&#39; ,&#39;estj&#39;]
    for types in pers_types:
      sentence = sentence.replace(types, &#39;&#39;)

    # 불용어 제거 (Text)
    if remove_stopwords:
        tokens = &#39; &#39;.join(word for word in sentence.split() if not word in stop_words if len(word) &gt; 1)
    # 불용어 미제거 (Summary)
    else:
        tokens = &#39; &#39;.join(word for word in sentence.split() if len(word) &gt; 1)
    return tokens</code></pre>
<p>전처리 함수를 위와 같이 정의해줍니다. 코드에서 볼 수 있는 pers_types는 mbti 종류로 데이터셋 내부에 mbti 종류가 포함되어 있다면 예측 정확도에 영향을 끼칠 수도 있기 때문에 제거를 했습니다.</p>
<pre><code class="language-python"># posts 열 전처리
clean_posts = []
for s in data[&#39;posts&#39;]:
    clean_posts.append(preprocess_sentence(s))
clean_posts[:5]</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/06f146cf-0ea2-4efc-a61e-26aaad208cc8/image.png" alt="">
결과를 보면, 처음 데이터셋을 불러올때 0번째 행에 포함되어 있던 &#39;intj&#39;라는 단어와 같이 mbti 종류와 링크, 특수문자 제거 및 소문자화 등의 과정이 제대로 진행된 것을 확인할 수 있습니다.</p>
<pre><code class="language-python">data[&#39;posts&#39;] = clean_posts</code></pre>
<pre><code class="language-python"># 전처리 진행과정에서 결측치 생성 여부 확인
print(data.isnull().sum())</code></pre>
<h5 id="posts--------0brtype-----0brdtype-int64">posts        0<br>type     0<br>dtype: int64</h5>
<p>결측치가 없는 것을 확인했습니다. 
이제, collections 모듈을 사용하여 전체 posts 열에서 중복이 많은 단어들을 확인하고 word cloud를 이용하여 시각화를 진행하겠습니다.</p>
<pre><code class="language-python">import collections
from collections import Counter

# collections 모듈의 Counter를 사용하여 posts 열에서 중복이 많은 단어 40개 출력
words = list(data[&quot;posts&quot;].apply(lambda x: x.split()))
words = [x for y in words for x in y]
Counter(words).most_common(40)</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/76eee3d6-7529-458f-b640-21c65e933342/image.png" width="30%" height="30">
사진에 모두 담지는 못했지만, 중복이 많은 단어 40개를 출력한 것을 확인했습니다. Counter 생성자에 중복된 데이터가 저장된 배열을 인자로 넘기면 각 원소가 몇 번씩 나오는지 저장된 객체를 얻게 됩니다.

<p>collection 모듈의 Counter를 사용하는 방법은 <a href="https://www.daleseo.com/python-collections-counter/">https://www.daleseo.com/python-collections-counter/</a> 를 참고하시면 됩니다.</p>
<pre><code class="language-python">import wordcloud
from wordcloud import WordCloud, STOPWORDS

wc = wordcloud.WordCloud(width=1200, height=500,
                         collocations=False, background_color=&quot;white&quot;,
                         colormap=&quot;tab20b&quot;).generate(&quot; &quot;.join(words))

plt.figure(figsize=(25,10))
# word cloud 생성
plt.imshow(wc, interpolation=&#39;bilinear&#39;)
_ = plt.axis(&quot;off&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/29127300-ac63-4328-9366-9fa1b52f2848/image.png" alt=""></p>
<pre><code class="language-python">fig, ax = plt.subplots(len(data[&#39;type&#39;].unique()), sharex=True, figsize=(15,len(data[&#39;type&#39;].unique())))
k = 0
for i in data[&#39;type&#39;].unique():
    data_4 = data[data[&#39;type&#39;] == i]
    wordcloud = WordCloud(max_words=1628,relative_scaling=1,normalize_plurals=False).generate(data_4[&#39;posts&#39;].to_string())
    plt.subplot(4,4,k+1)
    plt.imshow(wordcloud, interpolation=&#39;bilinear&#39;)
    plt.title(i)
    ax[k].axis(&quot;off&quot;)
    k+=1</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/5c2952de-3fb9-42d0-a81d-8fbb923370b1/image.png" width="80%" height="30">
<img src="https://velog.velcdn.com/images/yugyeong_929/post/8099a7b4-1b16-4ba5-aef7-22b87e4ee7a3/image.png" width="80%" height="30">
<img src="https://velog.velcdn.com/images/yugyeong_929/post/570c01fa-1144-45d8-b43f-0601c1851dbb/image.png" width="80%" height="30">
<img src="https://velog.velcdn.com/images/yugyeong_929/post/c1df6613-04cf-466b-ae9d-fba56a033f11/image.png" width="80%" height="30">
word cloud를 통해서 각 mbti별로 자주 사용한 단어를 확인할 수 있었습니다.

<h2 id="3-eda">3. EDA</h2>
<p>전처리가 끝났으니, 전처리된 데이터셋으로 <strong>EDA</strong>를 수행합니다.</p>
<pre><code class="language-python">data.head()</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/39ac0490-ce0e-4bb8-b887-88686a1ecf25/image.png" width="50%" height="30">

<pre><code class="language-python">data.info()</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/f81ec450-5737-4c95-a4ae-c80193b7d296/image.png" width="40%" height="30">

<pre><code class="language-python">data.isnull().sum().to_frame().rename(columns={0: &quot;Count of Missing Values&quot;})</code></pre>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/1d1a1410-5c14-48e6-9262-1309f84e6c46/image.png" width="40%" height="30">

<pre><code class="language-python">import seaborn as sns
import matplotlib.pyplot as plt

# 스타일과 색상 설정
sns.set(style=&quot;whitegrid&quot;, palette=&quot;pastel&quot;)

# count plot 생성
plt.figure(figsize=(14, 6))
ax = sns.countplot(data=data, x=&#39;type&#39;, order=sorted(data[&#39;type&#39;].unique()),
                   palette=&quot;pastel&quot;)
ax.set_title(&#39;Distribution of MBTI Types&#39;)
ax.set_xlabel(&#39;MBTI Type&#39;)
ax.set_ylabel(&#39;Count&#39;)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha=&quot;right&quot;)
for p in ax.patches:
    ax.annotate(f&#39;{p.get_height():.0f}&#39;, (p.get_x()+p.get_width()/2, p.get_height()),
                ha=&#39;center&#39;, va=&#39;bottom&#39;, fontsize=12)
plt.tight_layout()

plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/yugyeong_929/post/8ece1478-2cd5-4118-8dfe-8962648de7a3/image.png" alt="">
각 mbti별 데이터 분포를 살펴본 결과 클래스 불균형이 심각한 것을 확인할 수 있었습니다. 모델링을 진행할 때, <strong>클래스 불균형 문제에 잘 대응할 수 있는 모델</strong>을 선정하는 것이 성능 향상에 가장 중요할 것 같다는 생각이 들었습니다.</p>
<pre><code class="language-python">data[&#39;word_count&#39;] = data[&#39;posts&#39;].apply(lambda x: len(x.split()))

plt.figure(figsize=(14, 6))
sns.histplot(data=data, x=&#39;word_count&#39;, bins=30, kde=True)
plt.title(&#39;Distribution of Word Count in Tweets&#39;)
plt.xlabel(&#39;Word Count&#39;)
plt.ylabel(&#39;Frequency&#39;)
plt.show()</code></pre>
<p><br>단어별 개수 분포에 대한 결과입니다.
<img src="https://velog.velcdn.com/images/yugyeong_929/post/50731181-7627-43f8-b175-838605955e62/image.png" alt=""></p>
<pre><code class="language-python">import plotly.express as px

# 색상 설정
color_palette = px.colors.qualitative.Pastel

# 박스 플롯 생성
fig = px.box(data, x=&quot;type&quot;, y=&quot;word_count&quot;, color=&quot;type&quot;,
             title=&quot;Word Count Distribution by MBTI Personality Type&quot;,
             category_orders={&quot;label&quot;: sorted(data[&quot;type&quot;].unique())},
             color_discrete_sequence=color_palette)

# 라벨 이름 설정
fig.update_xaxes(title=&quot;MBTI Personality Type&quot;, showgrid=False,
                 tickfont=dict(size=12, color=&quot;black&quot;))
fig.update_yaxes(title=&quot;Word Count&quot;, showgrid=False,
                 tickfont=dict(size=12, color=&quot;black&quot;))

# 타이틀 설정
fig.update_layout(title_font=dict(size=24, color=&quot;darkblue&quot;))

fig.show()</code></pre>
<p><bt><bt>
mtbi 종류별 단어 개수 분포에 대한 결과입니다.</p>
<p>  <img src="https://velog.velcdn.com/images/yugyeong_929/post/d2e9f99f-3260-4f8e-862b-983fc63bd31f/image.png" alt=""></p>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/c116d490-6d7d-4614-9646-f586169c0a24/image.png" width="30%" height="30">

<p>시각화를 하면서 생성된 word_count 컬럼을 삭제하고  &#39;data_result.csv&#39; 로 저장합니다.
저장한 csv 파일은 모델링에 사용할 최종 데이터셋입니다.</p>
<pre><code class="language-python"># word_count열 제거 후, csv파일로 저장
data = data.drop([&#39;word_count&#39;], axis=1)
data.to_csv(&#39;data_result.csv&#39;)</code></pre>
<br>

<p>프로젝트 처음 작성했던 EDA 코드를 공개합니다..</p>
<pre><code class="language-python">from google.colab import drive
drive.mount(&#39;/content/drive&#39;)

  import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

train = pd.read_csv(&#39;/content/drive/MyDrive/spp_project/MBTI.csv&#39;)

  train.head()

  # 라벨별 개수 확인
  print(f&quot;{len(train[&#39;type&#39;].unique())}개&quot;)

  # 라벨별 비율 확인
  train[&#39;type&#39;].value_counts()

  # 결측치 확인
  train.isnull().sum()

  # 데이터 중복 여부 확인
  train[&#39;posts&#39;].nunique() == len(train[&#39;posts&#39;])

  # MBTI 글자별 빈도수 확인

  # E, I 빈도수 확인
first = []
for i in range(len(train)):
    first.append(train[&#39;type&#39;][i][0])
first = pd.DataFrame(first)
first[0].value_counts()

  # N, S 빈도수 확인
second = []
for i in range(len(train)):
    second.append(train[&#39;type&#39;][i][1])
second = pd.DataFrame(second)
second[0].value_counts()

  # T, F 빈도수 확인
third = []
for i in range(len(train)):
    third.append(train[&#39;type&#39;][i][2])
third = pd.DataFrame(third)
third[0].value_counts()

  # P, J 빈도수 확인
fourth = []
for i in range(len(train)):
    fourth.append(train[&#39;type&#39;][i][3])
fourth = pd.DataFrame(fourth)
fourth[0].value_counts()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ML] 데이터 결측치 처리 방법]]></title>
            <link>https://velog.io/@yugyeong_929/ML-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B2%B0%EC%B8%A1%EC%B9%98-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@yugyeong_929/ML-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B2%B0%EC%B8%A1%EC%B9%98-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 15 Aug 2023 06:39:53 GMT</pubDate>
            <description><![CDATA[<p>정형 데이터를 다루다 보면 null 값을 가진 컬럼들이 존재하는 경우가 많다. </p>
<img src="https://velog.velcdn.com/images/yugyeong_929/post/3617711f-11a9-4965-8fd7-b328c6480e4c/image.png" width="60%" height="30">

<h6 id="공공하수처리-데이터-중-과거수질자료_낙동강csv의-예시">(공공하수처리 데이터 중 과거수질자료_낙동강.csv의 예시)</h6>
<h5 id="분석에-사용할-변수유해남조류-세포수--microcystis--anbaena--oscillatoria--aphanizomenon--수온--지오스민--2mib--ph--microcystin-lr-중에서-지오스민-2mib-microcystin-lr-컬럼이-많은-결측치를-가지기-때문에-처리를-할-필요가-있다br-대부분의-경우-결측치를-제거하고-분석을-진행했는데-낙동강-데이터셋에서-데이터의-개수가-충분하지-않기-때문에-다른-방법을-찾아보게-됐다">분석에 사용할 변수(유해남조류 세포수 / Microcystis / Anbaena / Oscillatoria / Aphanizomenon / 수온 / 지오스민 / 2MIB / PH / Microcystin-LR) 중에서 지오스민, 2MIB, Microcystin-LR 컬럼이 많은 결측치를 가지기 때문에 처리를 할 필요가 있다.<br> 대부분의 경우, 결측치를 제거하고 분석을 진행했는데 낙동강 데이터셋에서 데이터의 개수가 충분하지 않기 때문에 다른 방법을 찾아보게 됐다.</h5>
<p>결측치를 처리하는 방법에는 <span style="background-color: rgba(242,179,188,0.5)">7가지</span>가 있다.</p>
<blockquote>
<p>Data Imputation</p>
</blockquote>
<p><strong>1. 평균값으로 대체(Mean Imputation)</strong></p>
<p>-&gt; 결측치가 존재하는 변수에서 결측치를 제외한 나머지 값들의 평균으로 결측치를 대체하는 방법
장점: 해당 값으로 대체 시 변수의 평균값이 변하지 않는다.</p>
<p><strong>2. 새로운 값으로 대체(Substitution)</strong></p>
<p>-&gt; 해당 데이터 대신 샘플링 되지 않은 다른 데이터에서 값을 가져오는 방법</p>
<p><strong>3. Hot deck imputation</strong></p>
<p>-&gt; 다른 변수에서 비슷한 값을 가지는 데이터 중 하나를 랜덤 샘플링하여 값을 복사해오는 방법
이는 결측값이 존재하는 변수가 가질 수 있는 값의 범위가 한정되어 있을 때 이점을 가짐. 또한, 랜덤하게 가져온 값이기 때문에 어느 정도 변동성을 더해준다는 점에서 표준 오차의 정확도에 어느 정도 기여를 함.</p>
<p><strong>4. Cold deck imputation</strong></p>
<p>-&gt; Hot deck imputation처럼 다른 변수에서 비슷한 값을 가지는 데이터 중에서 하나를 골라서 결측값을 대체하는 방법. 다른 점은 랜덤 샘플링을 하는 것이 아니라 어떠한 규칙하에 하나를 선정하는 것 이다.</p>
<p><strong>5. Regression imputation</strong></p>
<p>-&gt; 결측치가 존재하지 않는 변수를 feature로 삼고, 결측치를 채우고자 하는 변수를 target으로 삼아 regression task를 진행하는 방법
데이터 내의 다른 변수를 기반으로 결측치를 예측하는 것이기 때문에 변수 간 관계를 그대로 보존할 수 있다는 장점을 갖지만, 예측치 간의 variability는 보존할 수 없다는 단점을 가짐.</p>
<p><strong>6. Stochastic regression imputation</strong></p>
<p>-&gt; regression 방법에 random residual value를 더해서 결측치의 최종 예측값으로 대체하는 방법
Regression imputation의 장점을 모두 가지며, random component를 가진다는 장점 또한 있음.</p>
<p><strong>7. Interpolation and extrapolation(보간법, 보외법)</strong></p>
<p>-&gt; 같은 대상으로부터 얻은 다른 관측치로부터 결측치를 추정하는 방법</p>
<h6 id="reference-httpsdaebaq27tistorycom43">[Reference] <a href="https://daebaq27.tistory.com/43">https://daebaq27.tistory.com/43</a></h6>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Data Science] 녹조 발생지역 예측 분석 Project]]></title>
            <link>https://velog.io/@yugyeong_929/Data-Science-%EB%85%B9%EC%A1%B0-%EB%B0%9C%EC%83%9D%EC%A7%80%EC%97%AD-%EC%98%88%EC%B8%A1-%EB%B6%84%EC%84%9D-Project-1</link>
            <guid>https://velog.io/@yugyeong_929/Data-Science-%EB%85%B9%EC%A1%B0-%EB%B0%9C%EC%83%9D%EC%A7%80%EC%97%AD-%EC%98%88%EC%B8%A1-%EB%B6%84%EC%84%9D-Project-1</guid>
            <pubDate>Fri, 11 Aug 2023 12:32:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h4 id="녹조algal-bloom란">녹조(algal bloom)란?</h4>
</blockquote>
<h5 id="강이나-호수에-남조류가-과도하게-성장하여-물의-색깔이-짙은-녹색으로-변하는-현상을-말한다">강이나 호수에 남조류가 과도하게 성장하여 물의 색깔이 짙은 녹색으로 변하는 현상을 말한다.</h5>
<h5 id="이와같이-남조류-과잉-발생이-녹조의-주된-원인이기-때문에-머신러닝과-딥러닝을-통해-유해-남조류-발생-예측을-한다면-녹조-발생지역-예측-분석이-가능할-것-이다">이와같이, 남조류 과잉 발생이 녹조의 주된 원인이기 때문에 머신러닝과 딥러닝을 통해 유해 남조류 발생 예측을 한다면 녹조 발생지역 예측 분석이 가능할 것 이다.</h5>
<h6 id="✅-knn-svm-ann-사용-예정-br✅-data-set-물-환경-정보-시스템-과거수질자료---낙동강-한강-금강-영산강csv">✅ KNN, SVM, ANN 사용 예정 <br>✅ Data Set: 물 환경 정보 시스템 과거수질자료 -&gt; 낙동강, 한강, 금강, 영산강.csv</h6>
<h6 id="📌data-set-컬럼-분류--지점명--채수위치--조사년도--수온--ph--do--투명도--탁도--chi-a--유해남조류-세포수--microcystis--anbaena--oscillatoria--aphanizomenon--지오스민--2mib--microcystin-lrbr📌사용-예정-컬럼-유해남조류-세포수--microcystis--anbaena--oscillatoria--aphanizomenon--수온--지오스민--2mib--ph--microcystin-lr">📌Data Set 컬럼: 분류 / 지점명 / 채수위치 / 조사년도 / 수온 / pH / DO / 투명도 / 탁도 / Chi-a / 유해남조류 세포수 / Microcystis / Anbaena / Oscillatoria / Aphanizomenon / 지오스민 / 2MIB / Microcystin-LR<br>📌사용 예정 컬럼: 유해남조류 세포수 / Microcystis / Anbaena / Oscillatoria / Aphanizomenon / 수온 / 지오스민 / 2MIB / PH / Microcystin-LR</h6>
<br>

<blockquote>
<p>ANN(Artifical Neural Network)이란?</p>
</blockquote>
<h5 id="인공-신경망이라고-불리는-ann은-사람의-신경망-원리와-구조를-모방하여-만든-기계학습-알고리즘이다">인공 신경망이라고 불리는 ANN은 사람의 신경망 원리와 구조를 모방하여 만든 기계학습 알고리즘이다.</h5>
<div align="center">
  <figure align="center">
    <img src="https://velog.velcdn.com/images/yugyeong_929/post/5a93de86-67fa-    49f9-bbb1-0384ee623779/image.png" width="200px" alt="ann"/>
    <figcaption style="text-align:center; font-size:15px; color:#808080">ANN의 구조</figcaption>
  </figure>
</div>   

<h5 id="이는-은닉-계층을-포함하는-인공신경망-기술이며-동작-단계는-다음과-같이-span-style--color-2d3748-background-colorfff5b14-단계span로-이루어져-있다">이는 은닉 계층을 포함하는 인공신경망 기술이며, 동작 단계는 다음과 같이 <span style = "color: #2D3748; background-color=#fff5b1">4 단계</span>로 이루어져 있다.</h5>
<h5 id="1단계-입력-계층에서-입력된-데이터에-대해-가충치-행렬을-곱하여-은닉-계층으로-보냄br2단계-은닉-계층-내부에서-활성화-함수를-통해-데이터-가공br3단계-은닉-계층에서-나온-데이터를-새로운-가중치-행렬을-곱해-출력-계층으로-보냄br4단계-출력을-위한-활성화-함수를-반영하여-결과를-출력">1단계: 입력 계층에서 입력된 데이터에 대해 가충치 행렬을 곱하여 은닉 계층으로 보냄<br>2단계: 은닉 계층 내부에서 활성화 함수를 통해 데이터 가공<br>3단계: 은닉 계층에서 나온 데이터를 새로운 가중치 행렬을 곱해 출력 계층으로 보냄<br>4단계: 출력을 위한 활성화 함수를 반영하여 결과를 출력</h5>
<br>

<p><strong>활성화 함수</strong></p>
<h5 id="1-계단-함수step-function--0보다-작은-수는-0으로-0보다-큰-수는-1로-출력br2-시그모이드-함수sigmoid-function-미세한-변화에-대한-값도-반영하기-위해-사용br3-relu-함수rectified-linear-unit-function-입력이-0을-넘으면-입력-그대로-출력-0-이하일-땐-0을-출력br4-소프트맥스-함수softmax-function-입력받은-값을-01-사이의-값으로-정규화하며-총합이-항상-1이-되는-특성을-가진-함수-n개-이상의-class-확률-분포를-계산할-때-사용">1. 계단 함수(Step Function) : 0보다 작은 수는 0으로, 0보다 큰 수는 1로 출력<br>2. 시그모이드 함수(Sigmoid Function): 미세한 변화에 대한 값도 반영하기 위해 사용<br>3. ReLU 함수(Rectified Linear Unit Function): 입력이 0을 넘으면 입력 그대로 출력, 0 이하일 땐 0을 출력<br>4. 소프트맥스 함수(Softmax Function): 입력받은 값을 0~1 사이의 값으로 정규화하며 총합이 항상 1이 되는 특성을 가진 함수, N개 이상의 class 확률 분포를 계산할 때 사용</h5>
<br>



<h6 id="reference-brkim-sang-hoon2021-prediction-of-cyanobacteria-harmful-algal-blooms-in-reservoir-using-machine-learning-and-deep-learningbrhttpsebbnflowtistorycom119">[Reference] <br>Kim Sang-Hoon(2021), Prediction of cyanobacteria harmful algal blooms in reservoir using machine learning and deep learning<br><a href="https://ebbnflow.tistory.com/119">https://ebbnflow.tistory.com/119</a></h6>
]]></description>
        </item>
    </channel>
</rss>