비트교육센터/AI

[비트교육센터][AI] AI 4일차 Pytorch, 다중분류

달의요정루나 2023. 8. 4. 01:13

1. Pytorch

1. 파이토치와 텐서플로우의 차이점

- numpy 와 비슷하지만 Ai 에서 tensor 는 3차원 이상을 의미한다
- numpy와의 차이점이라면 tensor는 기울기를 구해주는 식을 자체적으로 가지고 있다.

2. 예제

[1] csv 파일 넣기

ThoraricSurgery3.csv
0.02MB

- 작업하는 경로에 해당 csv 파일을 입력한다.

[2] 정확도 계산

1) 모듈 임포트, gpu 사용여부

import torch
import numpy as np
#파이토치를 사용하기 위해 torch 모듈을 임포트한다.
device = ('cuda' if torch.cuda.is_available() else 'cpu')
#pytorch 는 gpu를 사용할지 cpu를 사용할지 코드 상에서 구분 할 수 있다.
torch.cuda.is_available()
#해당 식이 True 값이 나오면 gpu를 사용하는 것이고 false 값이 나오면 cpu로 동작한다.

--> 결과

False

2) csv 파일로드, 넘파일 배열 변환

data_set = np.loadtxt('data/ThoraricSurgery3.csv',delimiter=',')
#폐암 관련 데이터를 가진 csv 파일을 넘파이 배열로 로드한다.
data_set = torch.from_numpy(data_set)
#그 다음 넘파이 배열인 data_set을 파이토치 텐서로 변환한다.
data_set.shape
#data_set의 형태를 출력한다.

--> 결과

torch.Size([470, 17])

- 샘플은 470개, 각 샘플은 17개(16개의 feature, 1개의 target)의 값으로 구성되었다.

3) 입력변수(X), 목표변수(y) 추출

X = data_set[:, :-1]
# 데이터셋의 모든 샘플에 대해 마지막 열을 제외한 특성으로 이루어진 행렬이다.
y = data_set[:, -1]
# 데이터셋의 모든 샘플에 대해 마지막 열의 값들로 이루어진 벡터이다.
X.shape
# 형태를 알아본다.

--> 결과

torch.Size([470, 16])

- 샘플은 470개, 각 샘플은 16개(15개의 feature, 1개의 target)의 값으로 구성되었다.

y.shape
# 형태를 알아본다.

--> 결과

torch.Size([470])

- 총 470개의 샘플이 있다.

4) 인공신경망 모델 Surgery 구현

import torch.nn as nn

class Surgery(nn.Module):

	#init은 모델의 구조를 정의하는 생성자이다.
    #nn.Module클래스를 상성받아 생성자를 만들고 필요한 레이어를 초기화한다.
    def __init__(self):
        super(Surgery, self).__init__()
        self.hidden_linear = nn.Linear(16,30)
        #입력층과 은닉층 사이의 완전연결계층을 정의한다.
        #입력 값은 16개고 은닉층의 출력값은 30개이다.
        self.hidden_activation = nn.ReLU()
        #출력값을 넣을 활성화 함수로 ReLU를 정의한다.
        self.output_linear = nn.Linear(30,1)
        #은닉층과 출력층 사이의 완전연결계층을 정의한다.
        #은닉층의 입력값은 30개이고 출력값 1개이다.
        self.output_activation = nn.Sigmoid()
        #출력값을 넣을 활성화 함수로 Sigmoid를 정의한다.
   
   	#순전파 함수를 정의한다.
    def forward(self, x):
        x = self.hidden_linear(x)
        #입력데이터 x를 입력층의 완전연결계층을 통과시킨다.
        x = self.hidden_activation(x)
        #입력층을 거친결과 ReLU활성화 함수를 적용한다.
        x = self.output_linear(x)
        #은닉층을 거친결과를 출력층의 완전연결계층을 통과시킨다.
        x = self.output_activation(x)
        #출력층을 거친결과에 Sigmoid활성화 함수를 적용한다.
        #Sigmoid함수를 사용시 이 모델이 이진분류를 수행하기 때문이다.
        return x
    
    #예측값을 출력하는 함수이다.
    def predict(self, x):
        pred = self.forward(x)
        #순전파 함수를 호출해 예측값을 얻는다.
        if pred >= 0.5:
            return 1
        else:
            return 0
        #시그모이드 함수로 나오기 때문에
        #예측값이 0.5보다 높으면 1로 보고, 낮으면 0으로 본다.
model = Surgery().to(device)
# Surgery 클래스를 호출하고 to(device)를 통해 cpu로 클래스를 이동시킨다.
model
# model은 cpu에 올려진 인공신경망 모델이다. cpu에 데이터를 입력하고 예측값을 얻을 수 있다.

--> 결과

Surgery(
  (hidden_linear): Linear(in_features=16, out_features=30, bias=True)
  (hidden_activation): ReLU()
  (output_linear): Linear(in_features=30, out_features=1, bias=True)
  (output_activation): Sigmoid()
)

5) 모델 파리미터 반환

param_gen = model.named_parameters()#모델 파라미터를 반환하는 파이썬 제너레이터이다.
param_gen

- 파이썬 제너레이터: iterator를 생성해주는 함수이다.

--> 결과

<generator object Module.named_parameters at 0x0000016A7602D3C0>

6) iterator

next(param_gen)

- next 함수: iterator 값을 출력한다.

--> 결과

('hidden_linear.weight',
 Parameter containing:
 tensor([[ 0.1411, -0.1960,  0.0544, -0.2382, -0.1926, -0.1387,  0.0303, -0.0380,
           0.0116,  0.1834, -0.1816,  0.0169, -0.0408,  0.0976, -0.0479, -0.0467],
         [ 0.0624, -0.1650, -0.0720, -0.1275,  0.0218,  0.2495,  0.1344, -0.0174,
          -0.0051, -0.0460,  0.1676, -0.1328,  0.2260,  0.0975, -0.1880, -0.2194],
         [-0.1642, -0.2300, -0.0594,  0.0662, -0.0571, -0.1797, -0.1625, -0.2354,
          -0.0297,  0.1347,  0.2023,  0.2073,  0.1286, -0.0399, -0.0580,  0.0309],
         ...
         [ 0.0060, -0.1857,  0.1219,  0.1489, -0.1304, -0.1230,  0.2015,  0.0654,
          -0.0031,  0.0406, -0.0504,  0.1818, -0.1568, -0.0601,  0.0579,  0.0206],
         [ 0.1764,  0.1386, -0.0704,  0.0582,  0.0819, -0.1159, -0.0941, -0.2153,
           0.1791,  0.0131,  0.1028,  0.1817,  0.0769,  0.0251, -0.1384,  0.2231],
         [ 0.0381,  0.0496,  0.1430, -0.1061,  0.2194, -0.1305, -0.2474, -0.0537,
          -0.0032, -0.1205, -0.0312,  0.0541,  0.1344, -0.1372, -0.0045, -0.0635],
         [-0.0398, -0.0350, -0.2257,  0.1289,  0.1225,  0.1153,  0.1657,  0.1972,
          -0.2316,  0.1868, -0.1217,  0.1155, -0.0609, -0.0621, -0.0736, -0.1184]],
        requires_grad=True))

7) 파라미터의 개수 계산

#주어진 모델의 파라미터 수와 각 파라미터의 크기를 출력하는 함수이다.
def count_parameters(model):
    total_param = 0 #파라미터를 저장할 변수이다.
    for name, param in model.named_parameters():#모델의 이름과 파라미터를 가져온다.
        if param.requires_grad: #파라미터가 학습 가능 경우에만 파라미터의 크기를 출력하고 계산한다.
            num_param = np.prod(param.size())#파라미터의 크기를 가져온다.
            if param.dim() > 1: #파라미터의 차원이 1보다 큰경우
                print(name, ':', ' x '.join(str(x) for x in list(param.size())[::-1]), '=', num_param)
                #파라미터의 크기를 x로 연결해 출력한다.
            else: #파라미터 차원이 1인 경우
                print(name, ':', num_param) #단일 숫자를 출력한다.
                print('-' * 40)
            total_param += num_param #파라미터의 크기를 변수에 저장하고 total_param에 더해준다.
    print('total:', total_param)
count_parameters(model) #파리미터의 개수 계산

--> 결과

hidden_linear.weight : 16 x 30 = 480
hidden_linear.bias : 30
----------------------------------------
output_linear.weight : 30 x 1 = 30
output_linear.bias : 1
----------------------------------------
total: 541

- 480+30+30+1=541

8) 손실값 출력

import torch.optim as optim
#파이토치에서 제공하는 최적화 알고리즘(Adam, RMSprop 등)을 제공하는 라이브러리다.
from torch.utils.data import DataLoader, TensorDataset
#파이토치에서 제공하는 데이터로딩(TensorDataset)과 미니배치(DataLoader) 처리를 위한 클래스이다.
ds = TensorDataset(X,y)
#입력데이터 X와 라벨 y를 TensorDataset으로 묶어준다.
dataloader = DataLoader(ds, batch_size=10)
#TensorDataset을 사용해 데이터를 미니배치로 로드하는 DataLoader를 생성한다.
optimizer = optim.Adam(model.parameters())
#Adam 최적화 알고리즘을 사용해 모델의 파라미터를 최적화하는 옵티마이저를 정의한다.

n_epochs = 10

for epoch in range(n_epochs):
    for data, label in dataloader:
        out = model(data.type(torch.FloatTensor).to(device))
        #순전파
        loss = nn.BCELoss()(out, label.type(torch.FloatTensor).unsqueeze(1).to(device))
        #calculate loss
        #BCELoss는 예측값과 타겟값 사이의 교차 엔트로피(무질서도)를 계산해 손실값을 얻는다.
        #unsqueeze: 차원을 늘려준다.
        
        optimizer.zero_grad() #기울기 초기화
        loss.backward() #개별 파라미터 기울기 계산
        optimizer.step() #개별 파라미터 갱신
        #loss와 step은 한세트이다.
        
    print("Epoch: %d, Loss: %.4f"%(epoch, float(loss)))
    #각 에포크 마다 현 에포크 번호와 손실 값을 출력한다.
    #에포크: 전체 데이터 셋에 대해 학 번 학습이 아루어지는 단위

--> 결과

Epoch: 0, Loss: 0.3074
Epoch: 1, Loss: 0.3037
Epoch: 2, Loss: 0.3024
Epoch: 3, Loss: 0.3008
Epoch: 4, Loss: 0.2986
Epoch: 5, Loss: 0.2963
Epoch: 6, Loss: 0.2940
Epoch: 7, Loss: 0.2918
Epoch: 8, Loss: 0.2895
Epoch: 9, Loss: 0.2873

9) 정확도 계산

train_loader = DataLoader(ds)

correct = 0 #모델이 예측한 총 데이터수
total = 0 #전체데이터수

with torch.no_grad():
    for data, label in train_loader: #DataLader에서 data와 label을 가져온다.
        data = data.type(torch.FloatTensor)
        #데이터를 실수형으로 변환한다.(파이토치는 기본적으로 실수형이어야 한다.)
        
        predicted = model.predict(data.to(device))
        #model.predict()메소드로 순전파 메소드를 호출해 예측값을 구한다.
        
        target = int(label[0])
        #라벨을 정수형으로 변환해 target 변수를 저장한다.
        
        total +=1
        correct += 1 if(predicted == target) else 0 
        #예측값과 실제라벨이 비교해 맞을시 correct증가
        
print('Accuracy: %.4f'%(correct / total))#정확도 계산

--> 결과

Accuracy: 0.8511

 

2. tensorflow로 피마 인디언 데이터 분석하기

pima-indians-diabetes3.csv
0.02MB

- 피마 인디언 데이터를 작업 경로로 가지고 온다.

- 교제 143

1. 라이브러리 선언하기

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

2. csv파일 읽기

df = pd.read_csv('data/pima-indians-diabetes3.csv')
df.head(10)

--> 결과

3. 칼럼 값 개수 계산하기

df['diabetes'].value_counts()
#diabetes 칼럼의 개수를 계산한다, 0이 몇개이고 1이 몇개인지 알수있다.

--> 결과

0    500
1    268
Name: diabetes, dtype: int64

----------

df.info()
#데이터 프레임 정보를 요약한다.

--> 결과

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 9 columns):
 #   Column     Non-Null Count  Dtype  
---  ------     --------------  -----  
 0   pregnant   768 non-null    int64  
 1   plasma     768 non-null    int64  
 2   pressure   768 non-null    int64  
 3   thickness  768 non-null    int64  
 4   insulin    768 non-null    int64  
 5   bmi        768 non-null    float64
 6   pedigree   768 non-null    float64
 7   age        768 non-null    int64  
 8   diabetes   768 non-null    int64  
dtypes: float64(2), int64(7)
memory usage: 54.1 KB

4. 데이터프레임 요약하기

df.describe()

5. 데이터 프레임 상관관계

df.corr()

--> 결과

6. 그래프 출력하기

colormap = plt.cm.gist_heat   #그래프의 색상 구성을 정합니다.
plt.figure(figsize=(12,12))   #그래프의 크기를 정합니다.

# 그래프의 속성을 결정합니다. vmax의 값을 0.5로 지정해 0.5에 가까울수록 밝은색으로 표시되게 합니다.
sns.heatmap(df.corr(),linewidths=0.1,vmax=0.5, cmap=colormap, linecolor='white', annot=True)
plt.show()

--> 결과

7. 히스토그램 그리기(plasma 값 분포 확인)

plt.hist(x=[df.plasma[df.diabetes==0], df.plasma[df.diabetes==1]], bins=30, histtype='barstacked', label=['normal','diabetes'])
# diabetes칼럼이 0,1일때 plasma열을 선택한다.
# 히스토그램 구간(bin) 개수를 30으로 설정한다.
# batstacked를 설정해 두 히스토그램을 쌓아서 표시한다.
# normal, diabetes로 범례를 지정한다.
plt.legend()
plt.show()

--> 결과

8. 히스토그램 그리기(bmi 값 분포 확인)

plt.hist(x=[df.bmi[df.diabetes==0], df.bmi[df.diabetes==1]], bins=30, histtype='barstacked', label=['normal','diabetes'])
plt.legend()
plt.show()

--> 결과

9. 딥러닝 모델 생성

X = df.iloc[:,:-1]
#입력데이터, 모든행과 마지막 열을 제외한 모든열을 선택해 데이터 저장
y = df.iloc[:,-1]
#타겟변수, 모든행과 미자막 열만 선택한다.
from tensorflow.keras import models, layers

model = models.Sequential()
#딥러닝 모델 선정,Sequential은 순차적으로 층을 쌓는 방식으로 모델을 만든다.
model.add(layers.Dense(12,input_dim=8, activation='relu'))
model.add(layers.Dense(8,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

- 이전 출력값이 다음에서는 입력으로 들어간다.

dense_3
    W = input(8) * output(12) = 96
    B = 12
    W + B = 108
dense_4
    W = input(12) * output(8) = 96
    B = 8
    W + B = 104
dense_5
    W = input(8) * output(1) = 8
    B = 1
    W + B = 9

total = 108 + 104 + 9 = 221

print(model.summary())

--> 결과

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 12)                108       
                                                                 
 dense_1 (Dense)             (None, 8)                 104       
                                                                 
 dense_2 (Dense)             (None, 1)                 9         
                                                                 
=================================================================
Total params: 221
Trainable params: 221
Non-trainable params: 0
_________________________________________________________________
None

10. 모델학습

model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
#model.compile: 케라스에서 모델을 컴파일하는 메소드이다.

#loss: 손실함수, 모델이 학습하는 동안 최소화하려는 오차정의, 
#binary_crossentropy는 이진분류에서 사용되는 손실함수이다.
#true/false 처럼 2개의 클래스를 분류할 수 있는 모델로 예측값은 0과 1사이의 확률값이다.

#optimizer: 모델이 손실함수를 최소화하는 방향으로 가중치 조정, adam 방법을 이용

#metrics: 모델의 평가지표 지정, 학습과정에서 모델의 성능 평가
#accuracy는 정확도를 계산한다.
h = model.fit(X,y,epochs=100,batch_size=5)

#model.compile로 모델 학습과정 설정후 model.fit으로 모델을 학습시킨다.
#X: 입력데이터, 모델에 입력할 특징데이터
#y: 타겟데이터, 모델이 학습할 정답(label)데이터
#epochs: 학습과정에서 데이터를 몇번 반복해 학습할지 결정
#batch_size: 한번에 처리할 샘플 데이터의 개수 지정

--> 결과

Epoch 1/100
154/154 [==============================] - 1s 1ms/step - loss: 3.0909 - accuracy: 0.5065
Epoch 2/100
154/154 [==============================] - 0s 1ms/step - loss: 1.1490 - accuracy: 0.5547
Epoch 3/100
154/154 [==============================] - 0s 1ms/step - loss: 0.9783 - accuracy: 0.5612
Epoch 4/100
154/154 [==============================] - 0s 1ms/step - loss: 0.9023 - accuracy: 0.5755
Epoch 5/100
154/154 [==============================] - 0s 1ms/step - loss: 0.7558 - accuracy: 0.6211

...

Epoch 96/100
154/154 [==============================] - 0s 991us/step - loss: 0.5098 - accuracy: 0.7526
Epoch 97/100
154/154 [==============================] - 0s 1ms/step - loss: 0.5069 - accuracy: 0.7578
Epoch 98/100
154/154 [==============================] - 0s 1ms/step - loss: 0.5014 - accuracy: 0.7604
Epoch 99/100
154/154 [==============================] - 0s 2ms/step - loss: 0.4951 - accuracy: 0.7591
Epoch 100/100
154/154 [==============================] - 0s 3ms/step - loss: 0.5211 - accuracy: 0.7552

2. torch로 피마 인디언 데이터 분석하기

1. 라이브러리 선언, Pima 클래스 생성하기

import torch
import numpy as np
# 파이토치와 numpy를 임포트한다.

import torch.nn as nn
# 파이토치 신경망 모듈을 임포트한다.

import torch.optim as optim
#최적화 알고리즘을 제공하는 optim을 임포트한다.

from torch.utils.data import DataLoader, TensorDataset
#dataloader와 tensordataset을 임포트한다.
device = ('cuda' if torch.cuda.is_available() else 'cpu')
#현재 cpu를 사용하는지 gpu를 사용하는지를 알려준다.
data_set = np.loadtxt('data/pima-indians-diabetes3.csv', delimiter=',',skiprows=1)
#numpy에서는 첫줄을 빼야한다.
#그래서 csv파일을 로드할때 skiprows=1을 선언해야한다.

data_set = torch.from_numpy(data_set)
#numpy배열은 data_set을 텐서로 변환한다.

X = data_set[:, :-1]
#입력데이터 X를 정의한다.

y = data_set[:, -1]
#타겟데이터 y를 정의한다.
#인공신경망 모벨 Pima를 생성한다.
class Pima(nn.Module):
    def __init__(self):
        super(Pima, self).__init__()
        self.hidden_linear1 = nn.Linear(8,12)
        self.hidden_activation1 = nn.ReLU()
        self.hidden_linear2 = nn.Linear(12,8)
        self.hidden_activation2 = nn.ReLU()
        self.output_linear = nn.Linear(8,1)
        self.output_activation = nn.Sigmoid()
    
    def forward(self, x):
        x = self.hidden_linear1(x)
        x = self.hidden_activation1(x)
        x = self.hidden_linear2(x)
        x = self.hidden_activation2(x)
        x = self.output_linear(x)
        x = self.output_activation(x)
        
        return x
    
    def predict(self, x):
        pred = self.forward(x)
        if pred >=0.5:
            return 1
        else:
            return 0
model = Pima().to(device)
model

--> 결과

Pima(
  (hidden_linear1): Linear(in_features=8, out_features=12, bias=True)
  (hidden_activation1): ReLU()
  (hidden_linear2): Linear(in_features=12, out_features=8, bias=True)
  (hidden_activation2): ReLU()
  (output_linear): Linear(in_features=8, out_features=1, bias=True)
  (output_activation): Sigmoid()
)

2. 파리미터 개수

def count_parameters(model):
    total_param = 0
    for name, param in model.named_parameters():
        if param.requires_grad:
            num_param = np.prod(param.size())
            if param.dim() > 1:
                print(name, ':', ' x '.join(str(x) for x in list(param.size())[::-1]), '=', num_param)
            else:
                print(name, ':', num_param)
                print('-' * 40)
            total_param += num_param
    print('total:', total_param)
count_parameters(model)

--> 결과

hidden_linear1.weight : 8 x 12 = 96
hidden_linear1.bias : 12
----------------------------------------
hidden_linear2.weight : 12 x 8 = 96
hidden_linear2.bias : 8
----------------------------------------
output_linear.weight : 8 x 1 = 8
output_linear.bias : 1
----------------------------------------
total: 221

3. 손실값 출력

ds = TensorDataset(X,y)
dataloader = DataLoader(ds, batch_size=5)
optimizer = optim.Adam(model.parameters())

loss_fn = nn.BCELoss()

n_epochs = 100

for epoch in range(n_epochs):
    for data, label in dataloader:
        out = model(data.type(torch.FloatTensor).to(device)) #forward propagation
        loss = loss_fn(out, label.type(torch.FloatTensor).unsqueeze(1).to(device))#calculate loss 
        #unsqieeze: 차원을 늘려준다.
        
        optimizer.zero_grad()
        loss.backward() #개별 파라미터 기울기 계산
        optimizer.step() #개별 파라미터 갱신
        #loss와 step은 한세트이다.
        
    print("Epoch: %d, Loss: %.4f"%(epoch, float(loss)))

--> 결과

Epoch: 0, Loss: 0.4012
Epoch: 1, Loss: 0.3935
Epoch: 2, Loss: 0.3919
Epoch: 3, Loss: 0.4002
Epoch: 4, Loss: 0.3951
Epoch: 5, Loss: 0.3883

...

Epoch: 94, Loss: 0.3457
Epoch: 95, Loss: 0.3511
Epoch: 96, Loss: 0.3468
Epoch: 97, Loss: 0.3399
Epoch: 98, Loss: 0.3403
Epoch: 99, Loss: 0.3370

4. 정확도 출력

train_loader = DataLoader(ds)

correct = 0
total = 0

with torch.no_grad():
    for data, label in train_loader:
        data = data.type(torch.FloatTensor)
        predicted = model.predict(data.to(device))
        target = int(label[0])
        total +=1
        correct += 1 if(predicted == target) else 0
        
print('Accuracy: %.4f'%(correct / total))

--> 결과

Accuracy: 0.7773

3. 다중 분류 문제

iris3.csv
0.00MB

- 꽃 데이터를 작업하는 경로에 넣어준다.

1. csv파일 로드하기

import pandas as pd
df = pd.read_csv('./data/iris3.csv')
df.head()

--> 결과

2. 요약정보 출력

df.info()

--> 결과

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   sepal_length  150 non-null    float64
 1   sepal_width   150 non-null    float64
 2   petal_length  150 non-null    float64
 3   petal_width   150 non-null    float64
 4   species       150 non-null    object 
dtypes: float64(4), object(1)
memory usage: 6.0+ KB

3. 데이터프레임 시각화

import seaborn as sns
import matplotlib.pyplot as plt

# 그래프로 확인해 봅시다.
sns.pairplot(df, hue='species');
#seaborn 라이브러리로 df의 각 변수들 같의 관계를 시각화한다.
#species는 열에 따라 데이터포인트들을 색상으로 구분해 그래프에 표시한다.
plt.show()

--> 결과

4. 출력, 타겟변수 선언하기

X=df.iloc[:,:-1]
y=df.iloc[:,-1]
print(y[:10]) #정수여야 함

--> 결과

0    Iris-setosa
1    Iris-setosa
2    Iris-setosa
3    Iris-setosa
4    Iris-setosa
5    Iris-setosa
6    Iris-setosa
7    Iris-setosa
8    Iris-setosa
9    Iris-setosa
Name: species, dtype: object

5. 원-핫 인코딩

y=pd.get_dummies(y)
#원-핫 인코딩으로 범주형 변수를 처리하기 위해 사용된다.
# 단어 집합의 크기를 벡터의 차원으로 하고, 
# 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 
# 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식이다.
print(y[:10])

--> 결과

   Iris-setosa  Iris-versicolor  Iris-virginica
0            1                0               0
1            1                0               0
2            1                0               0
3            1                0               0
4            1                0               0
5            1                0               0
6            1                0               0
7            1                0               0
8            1                0               0
9            1                0               0

- y의 Iris-setosa, Iris-versicolor, Iris-virginica 중 어느 값인지 나타낸다.

- 예를들어, y의 값이 Iris-setosa이면 1이고 나머지는 0으로 표시된다.

print(y[-10:])

--> 결과

     Iris-setosa  Iris-versicolor  Iris-virginica
140            0                0               1
141            0                0               1
142            0                0               1
143            0                0               1
144            0                0               1
145            0                0               1
146            0                0               1
147            0                0               1
148            0                0               1
149            0                0               1

6. 파라미터 계산

from tensorflow.keras import models, layers

model = models.Sequential()
model.add(layers.Dense(12,input_dim=4, activation='relu'))
model.add(layers.Dense(8,activation='relu'))
model.add(layers.Dense(3,activation='softmax'))
print(model.summary())

--> 결과

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 12)                60        
                                                                 
 dense_1 (Dense)             (None, 8)                 104       
                                                                 
 dense_2 (Dense)             (None, 3)                 27        
                                                                 
=================================================================
Total params: 191
Trainable params: 191
Non-trainable params: 0
_________________________________________________________________
None

7. 모델학습

model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#model.compile로 모델을 컴파일한다.

#categorical_crossentropy는 다중 클래스 분류 문제에서 사용되는 손실함수로 
#신경망의 출력과 실제 타겟 데이터 사이의 차이를 계산하여 손실을 구하는데 사용된다.

#최적화는 adam을 사용하고 accuracy를 선언해 모델의 평가기준을 정확도로 한다.

h = model.fit(X,y,epochs=30,batch_size=5)
#X입력데이터와 y의 타겟데이터로 전체데이터를 30번 반복학습하고
#한번에 5개의 샘플을 사용해 가중치를 갱신한다.

--> 결과

Epoch 1/30
30/30 [==============================] - 1s 1ms/step - loss: 1.5971 - accuracy: 0.3333
Epoch 2/30
30/30 [==============================] - 0s 1ms/step - loss: 1.2213 - accuracy: 0.6067
Epoch 3/30
30/30 [==============================] - 0s 1ms/step - loss: 1.0170 - accuracy: 0.6667
Epoch 4/30
30/30 [==============================] - 0s 1ms/step - loss: 0.8723 - accuracy: 0.6667

...

Epoch 27/30
30/30 [==============================] - 0s 1ms/step - loss: 0.3443 - accuracy: 0.9400
Epoch 28/30
30/30 [==============================] - 0s 1ms/step - loss: 0.3259 - accuracy: 0.9533
Epoch 29/30
30/30 [==============================] - 0s 1ms/step - loss: 0.3150 - accuracy: 0.9533
Epoch 30/30
30/30 [==============================] - 0s 1ms/step - loss: 0.2902 - accuracy: 0.9533

4. 다중 분류 문제(파이토치)

1. 라이브러리 선언, csv로드하기

import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
device = ('cuda' if torch.cuda.is_available() else 'cpu')
import pandas as pd
df = pd.read_csv('./data/iris3.csv')
df.tail()

--> 결과

2. 입력과 타겟변수 선언하기

X=df.iloc[:,:-1]
y=df.iloc[:,-1]
X.info()

--> 결과

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 4 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   sepal_length  150 non-null    float64
 1   sepal_width   150 non-null    float64
 2   petal_length  150 non-null    float64
 3   petal_width   150 non-null    float64
dtypes: float64(4)
memory usage: 4.8 KB

3. numpy타입으로 텐서 타입으로 바꾸기

X=torch.from_numpy(X.values)
print(type(X))

--> 결과

<class 'torch.Tensor'>

4. 원-핫 인코딩 수행하기

y = pd.get_dummies(y)
y = torch.from_numpy(y.values)
print(type(y))

--> 결과

<class 'torch.Tensor'>

5. 데이터 출력하기

print(y[:10]) #iris-setosa일때는 1로 되고 다른 꽃들은 0으로 된다.

--> 결과

tensor([[1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0],
        [1, 0, 0]], dtype=torch.uint8)

6. 인공신경망 Iris 만들기

class Iris(nn.Module):
    def __init__(self):
        super(Iris, self).__init__()
        self.hidden_linear1 = nn.Linear(4,12)
        self.hidden_activation1 = nn.ReLU()
        self.hidden_linear2 = nn.Linear(12,8)
        self.hidden_activation2 = nn.ReLU()
        self.output_linear = nn.Linear(8,3)
    
    def forward(self, x):
        x = self.hidden_linear1(x)
        x = self.hidden_activation1(x)
        x = self.hidden_linear2(x)
        x = self.hidden_activation2(x)
        x = self.output_linear(x)
        
        return x
model = Iris().to(device)
model

--> 결과

Iris(
  (hidden_linear1): Linear(in_features=4, out_features=12, bias=True)
  (hidden_activation1): ReLU()
  (hidden_linear2): Linear(in_features=12, out_features=8, bias=True)
  (hidden_activation2): ReLU()
  (output_linear): Linear(in_features=8, out_features=3, bias=True)
)

7. 파라미터 개수 세기

def count_parameters(model):
    total_param = 0
    for name, param in model.named_parameters():
        if param.requires_grad:
            num_param = np.prod(param.size())
            if param.dim() > 1:
                print(name, ':', ' x '.join(str(x) for x in list(param.size())[::-1]), '=', num_param)
            else:
                print(name, ':', num_param)
                print('-' * 40)
            total_param += num_param
    print('total:', total_param)
count_parameters(model)

--> 결과

hidden_linear1.weight : 4 x 12 = 48
hidden_linear1.bias : 12
----------------------------------------
hidden_linear2.weight : 12 x 8 = 96
hidden_linear2.bias : 8
----------------------------------------
output_linear.weight : 8 x 3 = 24
output_linear.bias : 3
----------------------------------------
total: 191

8. 손실값 출력하기

ds = TensorDataset(X,y)
dataloader = DataLoader(ds, batch_size=5)
optimizer = optim.Adam(model.parameters())

loss_fn = nn.CrossEntropyLoss()

n_epochs = 30

for epoch in range(n_epochs):
    for data, label in dataloader:
        out = model(data.type(torch.FloatTensor).to(device)) #forward propagation
        loss = loss_fn(out, label.type(torch.FloatTensor).to(device))#calculate loss 
        #unsqieeze: 차원을 늘려준다.
        
        optimizer.zero_grad()
        loss.backward() #개별 파라미터 기울기 계산
        optimizer.step() #개별 파라미터 갱신
        #loss와 step은 한세트이다.
        
    print("Epoch: %d, Loss: %.4f"%(epoch, float(loss)))

--> 결과

Epoch: 0, Loss: 0.5206
Epoch: 1, Loss: 0.6155
Epoch: 2, Loss: 0.6569
Epoch: 3, Loss: 0.6708
Epoch: 4, Loss: 0.6322

...

Epoch: 25, Loss: 0.5210
Epoch: 26, Loss: 0.5210
Epoch: 27, Loss: 0.5215
Epoch: 28, Loss: 0.5206
Epoch: 29, Loss: 0.5196

9. 정확도 구하기

test_loader = DataLoader(ds, batch_size=5)
correct = 0
flag = True

with torch.no_grad():
    for data, label in test_loader:
        output = model(data.type(torch.FloatTensor).to(device))
        pred = output.max(1)[1] #output을 1번째 차원으로 max하여 그 index 추출
        target = label.max(1)[1]#label을 1번째 차원으로 max하여 그 index 추출
        if flag :
            print("output",output)
            print("output.max(0)",output.max(0))#output에서 열 기준으로 최대값을 추출한다.
            print("output.max(1)",output.max(1))#output에서 행 기준으로 최대값을 추출한다.
            print('-'*30)
            print("label.max(0)",label.max(0))#label에서 열 기준으로 최대값을 추출한다.
            print("label.max(1)",label.max(1))#label에서 행 기준으로 최대값을 추출한다.
            flag = False
        correct += pred.eq(target.to(device)).sum().item()
        #[0,0,0,0,0]과 [0,0,0,0,0]이런식으로 반환시 0끼리 같으면 1을 반환하고 틀리면 0을 반환한다. 즉, 전부다 맞을 경우 5를 반환한다.
        
print('\nTest set: Accuracy: {}/{} ({:f})\n'.format(correct, len(test_loader.dataset), correct / len(test_loader.dataset)))
#correct은 일치한 횟수, len쪽은 전체 횟수, /쪽은 정확도이다.
        
print("Accuracy: %f" % (correct / len(test_loader.dataset)))

--> 결과

output tensor([[ 0.8066,  0.1407, -0.7902],
        [ 0.7740,  0.1257, -0.7562],
        [ 0.7592,  0.1189, -0.7407],
        [ 0.7436,  0.1118, -0.7245],
        [ 0.7985,  0.1370, -0.7818]])
output.max(0) torch.return_types.max(
values=tensor([ 0.8066,  0.1407, -0.7245]),
indices=tensor([0, 0, 3]))
output.max(1) torch.return_types.max(
values=tensor([0.8066, 0.7740, 0.7592, 0.7436, 0.7985]),
indices=tensor([0, 0, 0, 0, 0]))
------------------------------
label.max(0) torch.return_types.max(
values=tensor([1, 0, 0], dtype=torch.uint8),
indices=tensor([0, 0, 0]))
label.max(1) torch.return_types.max(
values=tensor([1, 1, 1, 1, 1], dtype=torch.uint8),
indices=tensor([0, 0, 0, 0, 0]))

Test set: Accuracy: 120/150 (0.800000)

Accuracy: 0.800000

- 3일차는 내용을 좀더 손보고 올리겠습니다!