machine-learning
퍼셉트론
수색…
퍼셉트론이란 정확히 무엇입니까?
그 핵심에서 퍼셉트론 모델은 바이너리 분류를 위한 가장 간단한 감독 학습 알고리즘 중 하나입니다. 이것은 선형 분류 자의 한 유형으로, 일련의 가중치와 특징 벡터를 결합한 선형 예측 함수를 기반으로 예측을 만드는 분류 알고리즘입니다. 생각할 수있는보다 직관적 인 방법은 단 하나의 뉴런이 있는 신경망 과 같습니다.
그것이 작동하는 방식은 매우 간단합니다. 입력 값 x 의 벡터를 얻습니다. x 는 각 요소가 데이터 집합의 한 특징입니다.
예 :
대상이 자전거인지 또는 차인지를 분류하고 싶다고합시다. 이 예제에서는 2 개의 피쳐를 선택한다고 가정 해 보겠습니다. 객체의 높이와 너비입니다. 이 경우 x = [x1, x2] 여기서 x1 은 높이이고 x2 는 너비입니다.
그런 다음 입력 벡터 x 를 얻은 다음 해당 벡터의 각 요소에 가중치를 곱하려고합니다. 보통 무게의 가치가 높을수록 기능이 더 중요합니다. 예를 들어 우리가 특징 x3으로 색상 을 사용했고 빨간색 자전거와 빨간 차가 있다면 퍼셉트론은 색상이 최종 예측에 영향을 미치지 않도록 매우 가벼운 무게를 설정합니다.
좋아, 그래서 우리는 2 개의 벡터 x 와 w를 곱해서 벡터를 얻었습니다. 이제 우리는이 벡터의 원소들을 더할 필요가 있습니다. 이 작업을 수행하는 현명한 방법 대신 T는 전치를 의미합니다 우리가 어디의 빔 형성하여 X를 곱할 수 승으로 간단한 곱셈 X이다. 벡터의 회전 된 버전으로 벡터의 전치 를 상상할 수 있습니다. 자세한 정보 는 Wikipedia 페이지를 참조하십시오 . 본질적으로 벡터 w 의 전치를 취함으로써 1xN 대신에 Nx1 벡터를 얻습니다. 따라서 우리의 입력 벡터에 1xN 크기의 Nx1 웨이트 벡터를 곱하면 x1 * w1 + x2 * w2 + ... + xn * wn 과 같은 1x1 벡터 (또는 단순히 단일 값)를 얻을 수 있습니다. 그렇게함으로써 우리는 지금 우리의 예측을 갖게됩니다. 그러나 마지막으로 한 가지가 있습니다. 이 예측은 새 샘플을 분류 할 수있는 간단한 1 또는 -1이 아닐 것입니다. 그래서 우리가 할 수있는 것은 간단하게 다음과 같이 말하면됩니다 : 우리의 예측이 0보다 크면 샘플은 클래스 1에 속한다고 말하고 그렇지 않으면 예측이 0보다 작 으면 샘플이 클래스 -1에 속한다고 말합니다. 이를 계단 함수 라고 합니다 .
그러나 올바른 예측을하기 위해 어떻게 올바른 가중치를 얻습니까? 다시 말해, 퍼셉트론 모델을 어떻게 훈련 시킬 수 있습니까?
퍼셉트론의 경우에 우리 모델을 훈련 시키는데 멋진 수학 방정식이 필요하지 않습니다. 우리의 가중치는 다음 방정식으로 조정할 수 있습니다.
Δw = η * (y- 예측) * x (i)
여기서 x (i) 는 우리의 특징입니다 (예를 들어, 가중치 1의 경우 x1, w2의 경우 x2 ... 등).
또한 학습 속도 인 eta 라는 변수가 있음을 알 수 있습니다. 학습 속도를 우리가 가중치의 변화를 얼마나 크게하기를 원하는지 상상할 수 있습니다. 학습 속도가 빠르면 학습 알고리즘이 빠릅니다. 너무 높은 η 값은 각 신기원에서 오류의 양을 증가시킬 수 있으며 모델이 실제로 나쁜 예측을하고 결코 수렴하지 않게합니다. 학습 률이 너무 낮 으면 모델이 수렴하는 데 너무 많은 시간이 걸릴 수 있습니다. (일반적으로 perceptron 모델의 eta 를 설정하는 데 좋은 값은 0.1이지만 대소 문자가 다를 수 있음).
마지막으로 여러분 중 일부는 첫 번째 입력이 상수 (1)이고 w0을 곱한 것을 알았을 것입니다. 그래서 정확히 무엇입니까? 좋은 예측을 얻으려면 편향성을 추가해야합니다. 그리고 그것은 바로 그 상수입니다.
바이어스 항의 가중치를 수정하기 위해 다른 가중치와 동일한 방정식을 사용하지만,이 경우 입력을 상수로 곱하지 않습니다 (입력 값이 상수 1이므로 더 이상 필요하지 않습니다).
Δw = η * (y- 예측)
그래서 그것은 기본적으로 간단한 퍼셉트론 모델이 어떻게 작동하는지입니다! 가중치를 훈련하면 새로운 데이터를 제공하고 예측을 할 수 있습니다.
노트:
퍼셉트론 모델은 중요한 단점이 있습니다! 데이터가 선형으로 분리 가능 하지 않은 경우 수렴되지 않습니다 (완벽한 가중치를 찾습니다). 이는 직선으로 특성 공간에서 2 개의 클래스를 분리 할 수 있음을 의미합니다. 그래서 피치를 피하려면 고정 된 수의 반복을 추가하여 완벽하게 조정되지 않는 가중치 조정에 모델이 걸리지 않도록하는 것이 좋습니다.
Perceptron 모델을 C ++로 구현하기
이 예제에서는 C ++로 퍼셉트론 모델을 구현하여 작동 원리를보다 잘 이해할 수 있습니다.
먼저 우리가하고 싶은 간단한 알고리즘을 적어 두는 것이 좋습니다.
연산:
- 가중치에 대한 벡터를 만들고 0으로 초기화하십시오 (바이어스 항을 추가하는 것을 잊지 마십시오)
- 0 에러 또는 낮은 에러 카운트가 생길 때까지 가중치를 조정하십시오.
- 보이지 않는 데이터에 대해 예측하십시오.
슈퍼 간단한 알고리즘을 작성한 후에 우리가 필요로하는 함수 중 일부를 작성해 보겠습니다.
- net의 입력을 계산하는 함수가 필요할 것입니다 (ei x * wT 는 입력 시간에 가중치를 곱합니다)
- 1 또는 -1의 예측을 얻을 수있는 단계 함수
- 그리고 가중치에 이상적인 값을 찾는 함수.
그래서 더 이상 걱정하지 말고 바로 들어 가자.
퍼셉트론 클래스를 작성하여 간단하게 시작합시다.
class perceptron
{
public:
private:
};
이제 우리가 필요로하는 기능을 추가합시다.
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
private:
};
함수 fit 이 vector <float>의 벡터를 인수로 취하는 방식에 주목하십시오. 이는 우리 교육 데이터 세트가 입력 행렬이기 때문입니다. 본질적으로 우리는 그 행렬이 두 개의 벡터들 x 이 다른 행들 위에 겹쳐져 있고 그 행렬의 각 열이 하나의 피쳐라는 것을 상상할 수 있습니다.
마지막으로 클래스에 필요한 값을 추가합시다. 벡터 W 가 가중치를 유지하는 것과 같이, 훈련 데이터 세트에 대해 수행 할 패스 수를 나타내는 에포크 의 수입니다. 그리고이 값을 다이얼링하여 교육 절차를 더 빠르게하기 위해 각 체중 업데이트를 늘릴 학습 속도 인 일정한 η ( η) 가 너무 높으면 이상적인 결과를 얻기 위해 전화를 걸 수 있습니다 (대부분의 애플리케이션에서 perceptron의 I는 0.1의 η 값을 제안한다).
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
private:
float m_eta;
int m_epochs;
vector < float > m_w;
};
이제 우리 수업이 시작되었습니다. 이제 각각의 함수를 작성할 차례입니다.
우리는 생성자 ( perceptron (float eta, int epochs); )에서 시작합니다.
perceptron::perceptron(float eta, int epochs)
{
m_epochs = epochs; // We set the private variable m_epochs to the user selected value
m_eta = eta; // We do the same thing for eta
}
우리가하는 일이 매우 간단하다는 것을 알 수 있습니다. 이제 다른 간단한 함수로 넘어 갑시다. 예측 함수 ( int 예측 (벡터 X); ). 모든 예측 함수는 netInput 이 0보다 크고 -1 otherwhise 인 경우 net 입력을 가져 와서 1의 값을 반환한다는 것을 기억하십시오.
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
우리의 삶을 편하게하기 위해 if 문을 사용했다는 것을 알아 두십시오. 다음은 인라인 if 문이 작동하는 방식입니다.
조건? if_true : else
여태까지는 그런대로 잘됐다. netInput 함수 ( float netInput (vector X); ) 구현으로 넘어 갑시다 .
netInput은 다음을 수행합니다. 입력 벡터에 가중치 벡터의 전치를 곱합니다.
x * wT
즉, 입력 벡터 x 의 각 요소에 가중치 벡터 w 의 해당 요소를 곱한 다음 합계를 취하여 편차를 더합니다.
(x1 * w1 + x2 * w2 + ... + xn * wn) + bias
바이어스 = 1 * w0
float perceptron::netInput(vector<float> X)
{
// Sum(Vector of weights * Input vector) + bias
float probabilities = m_w[0]; // In this example I am adding the perceptron first
for (int i = 0; i < X.size(); i++)
{
probabilities += X[i] * m_w[i + 1]; // Notice that for the weights I am counting
// from the 2nd element since w0 is the bias and I already added it first.
}
return probabilities;
}
이제 우리가 할 일은 꽤 많이 끝났습니다. 가중치를 수정하는 fit 함수를 작성하는 것입니다.
void perceptron::fit(vector< vector<float> > X, vector<float> y)
{
for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term
{
m_w.push_back(0); // Setting each weight to 0 and making the size of the vector
// The same as the number of features (X[0].size()) + 1 for the bias term
}
for (int i = 0; i < m_epochs; i++) // Iterating through each epoch
{
for (int j = 0; j < X.size(); j++) // Iterating though each vector in our training Matrix
{
float update = m_eta * (y[j] - predict(X[j])); //we calculate the change for the weights
for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; } // we update each weight by the update * the training sample
m_w[0] = update; // We update the Bias term and setting it equal to the update
}
}
}
그래서 그것은 본질적으로 그것입니다. 3 개의 함수만으로 우리는 예상 할 수있는 작업 인식 클래스를 갖게되었습니다!
코드를 복사하여 붙여 넣기를 시도해보십시오. 다음은 전체 클래스입니다 (각 에포크의 오류 벡터 및 오류 인쇄뿐만 아니라 가중치 가져 오기 / 내보내기 옵션 추가와 같은 몇 가지 추가 기능을 추가했습니다.)
다음은 코드입니다.
클래스 헤더 :
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
void printErrors();
void exportWeights(string filename);
void importWeights(string filename);
void printWeights();
private:
float m_eta;
int m_epochs;
vector < float > m_w;
vector < float > m_errors;
};
함수가있는 클래스 .cpp 파일 :
perceptron::perceptron(float eta, int epochs)
{
m_epochs = epochs;
m_eta = eta;
}
void perceptron::fit(vector< vector<float> > X, vector<float> y)
{
for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term
{
m_w.push_back(0);
}
for (int i = 0; i < m_epochs; i++)
{
int errors = 0;
for (int j = 0; j < X.size(); j++)
{
float update = m_eta * (y[j] - predict(X[j]));
for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; }
m_w[0] = update;
errors += update != 0 ? 1 : 0;
}
m_errors.push_back(errors);
}
}
float perceptron::netInput(vector<float> X)
{
// Sum(Vector of weights * Input vector) + bias
float probabilities = m_w[0];
for (int i = 0; i < X.size(); i++)
{
probabilities += X[i] * m_w[i + 1];
}
return probabilities;
}
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
void perceptron::printErrors()
{
printVector(m_errors);
}
void perceptron::exportWeights(string filename)
{
ofstream outFile;
outFile.open(filename);
for (int i = 0; i < m_w.size(); i++)
{
outFile << m_w[i] << endl;
}
outFile.close();
}
void perceptron::importWeights(string filename)
{
ifstream inFile;
inFile.open(filename);
for (int i = 0; i < m_w.size(); i++)
{
inFile >> m_w[i];
}
}
void perceptron::printWeights()
{
cout << "weights: ";
for (int i = 0; i < m_w.size(); i++)
{
cout << m_w[i] << " ";
}
cout << endl;
}
또한 예제를 시도하려면 여기에 제가 만든 예제가 있습니다.
main.cpp :
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <string>
#include <math.h>
#include "MachineLearning.h"
using namespace std;
using namespace MachineLearning;
vector< vector<float> > getIrisX();
vector<float> getIrisy();
int main()
{
vector< vector<float> > X = getIrisX();
vector<float> y = getIrisy();
vector<float> test1;
test1.push_back(5.0);
test1.push_back(3.3);
test1.push_back(1.4);
test1.push_back(0.2);
vector<float> test2;
test2.push_back(6.0);
test2.push_back(2.2);
test2.push_back(5.0);
test2.push_back(1.5);
//printVector(X);
//for (int i = 0; i < y.size(); i++){ cout << y[i] << " "; }cout << endl;
perceptron clf(0.1, 14);
clf.fit(X, y);
clf.printErrors();
cout << "Now Predicting: 5.0,3.3,1.4,0.2(CorrectClass=-1,Iris-setosa) -> " << clf.predict(test1) << endl;
cout << "Now Predicting: 6.0,2.2,5.0,1.5(CorrectClass=1,Iris-virginica) -> " << clf.predict(test2) << endl;
system("PAUSE");
return 0;
}
vector<float> getIrisy()
{
vector<float> y;
ifstream inFile;
inFile.open("y.data");
string sampleClass;
for (int i = 0; i < 100; i++)
{
inFile >> sampleClass;
if (sampleClass == "Iris-setosa")
{
y.push_back(-1);
}
else
{
y.push_back(1);
}
}
return y;
}
vector< vector<float> > getIrisX()
{
ifstream af;
ifstream bf;
ifstream cf;
ifstream df;
af.open("a.data");
bf.open("b.data");
cf.open("c.data");
df.open("d.data");
vector< vector<float> > X;
for (int i = 0; i < 100; i++)
{
char scrap;
int scrapN;
af >> scrapN;
bf >> scrapN;
cf >> scrapN;
df >> scrapN;
af >> scrap;
bf >> scrap;
cf >> scrap;
df >> scrap;
float a, b, c, d;
af >> a;
bf >> b;
cf >> c;
df >> d;
X.push_back(vector < float > {a, b, c, d});
}
af.close();
bf.close();
cf.close();
df.close();
return X;
}
홍채 데이터 세트를 가져 오는 방법은 실제로 이상적이지는 않지만 나는 효과가있는 것을 원했습니다.
이 자료가 도움이 되셨기를 바랍니다.
바이어스 란 무엇입니까?
바이어스 란 무엇입니까?
퍼셉트론은 입력 (실수) 벡터 x 를 출력 값 f (x) (이진 값)에 매핑하는 함수로 볼 수 있습니다.
여기서 w 는 실수 가중치의 벡터이고 b 는 우리의 바이어스 값입니다. 바이어스는 결정 경계를 원점 (0,0) 에서 벗어나 모든 입력 값에 의존하지 않는 값입니다.
공간적으로 바이어스를 생각할 때, 바이어스는 결정 경계의 위치 (방향이 아님)를 변경합니다. 우리는 바이어스에 의해 이동 된 동일한 곡선의 예를 아래에서 볼 수 있습니다 :