[유튜브] 삼프로TV_경제의신과함께

(8분 40초부터)

김동환, 이진우, 정영진 3명의 이름을 걸고 운영하는 경제 관련 유튜브 채널. 삼프로라는 이름은 그 3명을 지칭한다.

이진우는 ‘손에 잡히는 경제’를 매일 듣는 청취자라서 알고 있었는데, 다른 2명은 잘 몰라서 패스. ‘손에 잡히는 경제’는 다른 경제 라디오 보다 깊이가 느껴져서 계속 듣고 있는데, 이 유튜브 채널도 비슷해서 추천. 3명이서 하다보니 라디오보다 컨텐츠가 좀 더 풍부하고 깊이 있는 듯.

위 영상에 양적완화와 화폐와 채권 금리를 포함하여 중앙은행의 다양한 부양 정책에 대한 개념 설명이 잘 되어있어서 링크.

[유튜브] 구슬쌤

초보자 보다는 영어가 익숙한 사람들에게 도움이 되는 내용 위주의 영어 강의 채널. 내가 볼만한 수준은 아니긴 하지만 전문 강사이기 때문에 내용이나 전달이 좋아서 추천.

개인적으로 흥미로웠던 부분은은 네이티브들이 자주 사용하는 idiom 들이 단어만 봐서는 그 늬앙스를 이해할 수 없는 것들이 많다는 것. ‘Let’s call it a day’ 를 단어의 뜻만으로 ‘오늘은 여기까지만 하자’ 라고 어떻게 이해할 수 있겠는가?

기계에게 이런 것을 어떻게 학습 시킬 수 있을까? 현세대 컴퓨터가 인간의 언어를 이해하는 것이 가능할까?

[20.03.07]

중국, 자율주행차 목표시기 5년 늦췄다

위원회는 이어 2단계로 2035~2050년 사이에 `완전하고 안전하며, 효율적이며 친환경적인' 중국의 표준 스마트카 시스템을 완성한다는 청사진을 밝혔다. 이 역시 애초 2035년에서 2050년으로 늦춰졌다.

중국 정부의 이런 방침은 자율주행차가 시장에 안착하기엔 아직 넘어야 할 벽이 만만치 않음을 보여준다. 중국은 지난해 베이징과 신도시를 잇는 고속도로에 자율주행차 전용차로를 설치하는 구상을 발표하는 등 자율주행차 도입에 박차를 가해왔다. 이 분야의 선두 업체인 IT 대기업 바이두는 2017년 자율주행차 기술 플랫폼 인 아폴로를 공개한 데 이어 중국내 여러 도시에서 자율주행차 시험운행을 해왔다. 2019년 7월 현재 바이두가 13개 도시에서 300대의 자율 주행차로 실시한 도로 시험주행 누적거리는 200만km가 넘었다.

자율주행 구현, 영상처리만으로 어려워

그러나 영상처리만으로는 부족하다. 영상처리로 자율주행차에 줄 수 있는 운행 정보는 한계가 있기 때문이다. 자율주행차의 영상 센서 인식 범위는 최대 200미터가 고작이다. 해당 거리는 시속 100킬로미터 속도로 달리는 자동차가 7초 만에 도달할 수 있는 거리이다. 따라서 자율주행차는 영상처리만으로 도로 환경 대처하기 어렵다. 예를 들어 200미터 이상의 곡선 도로 상황에 대처할 수 없다. (중략)

자율주행차는 얼마큼 연습해야 안전할까? 싱크탱크 연구소 ‘랜드 연구소(RAND Corporation)’가 이에 답을 준다.

랜드 연구소는 미국 교통통계국(Bureau of Transportation Statistics)에서 조사한 2015년의 교통 사망률(1.09%)을 기반으로 110억 마일(약 177.02억 킬로미터)의 주행 시험이 필요한 것으로 분석했다. 이는 시간당 25마일(약 40.23킬로미터)을 달리는 자율주행차 100대가 365일 동안 계속 주행 시험을 하는 것을 기준으로 500년이 걸린다.

삼정KPMG는 2035년에 자율주행차 시대를 예고했다. 그런데 랜드 연구소의 전망은 2500년이 돼야 자율주행차 확산을 기대할 수 있게 한다. 물론, 자율주행차 학습량을 해결할 기술이 존재한다. 자율주행 시뮬레이터가 이에 해당한다. 자율주행 시뮬레이터는 가상 환경에서 자율주행차 시스템이 주행을 학습할 수 있게 하는 기술이다.

알파고가 수 천년 동안 익힐 수 있는 기보를 가상 세계에서 36시간 만에 익힌 것처럼, 자율주행차는 시뮬레이터를 통해 수많은 학습량을 순식간에 익힐 수 있다. 가상세계에는 물리적 제약을 받지 않기 때문에 가능하다. 참고로 작년 7월 웨이모 최고경영자인 존 크라프칙 (John Krafcik) “50억 마일(80.46킬로미터)의 주행 시험을 자율주행 시뮬레이터를 통해서 진행했다”고 밝혔다.

사실 전망이 10년을 넘어서는 수준이면 ‘안 된다’라고 봐도 무방하다. 새로운 돌파구가 나오지 않는 이상 현재의 기술로는 자율주행이 안된다라고 해석하는 게 맞을 듯. 그 새로운 돌파구가 1-2년 내에 나올 수도 있고, 어쩌면 현세대 컴퓨팅 기술로는 아예 도달 불가능한 지점일 수도 있다. 새로운 차원의 컴퓨터가 등장해야 가능할 수 있음.

최초 ‘인체 내’ 크리스퍼 시술

5일 ‘가디언’, ‘NPR’ 등 주요 언론들은 사상 최초의 크리스퍼 유전자가위(Crispr-Cas9) 체내 시술이 지금 미국에서 진행되고 있다고 전했다.

시술 대상은 유전성 희귀질환인 ‘레베르 선천성 흑암시(LCA)’를 앓고 있는 3~17세 환자 18명이다. 이들은 태어나면서부터 시력이 소실되고, 눈 떨림, 완만한 동공반사, 망막이상증 등으로 인해 고통을 겪어왔다. (중략)

성공 여부는 수 주일 안에 알 수 있을 것으로 내다봤다. 실명했던 시력이 회복될 수 있는지 여부는 2~3개월 후가 될 것이라고 말했다.

인공지능 분야는 아직 돌파구를 찾지 못한 상태이지만, 바이오 업계는 돌파구를 이미 찾았고 시험 적용 중인 단계인 듯.

공기로 만드는 단백질…제3의 대체육이 온다

2017년 11월에 설립된 핀란드의 솔라푸드도 공기에서 단백질을 만드는 방법을 개발했다. 수소와 이산화탄소를 미생물에 주면 미생물이 이를 먹이로 삼아 단백질과 탄수화물, 지방을 토해낸다. 수소는 물을 전기분해하는 방식으로 공급하고, 탄소는 공기 중에서 채취한다. ‘솔레인’이라는 이름의 이 단백질의 주된 용도는 빵이나 파스타, 요구르트를 포함해 기존 식품의 단백질 함량을 높이는 것이다. 솔라푸드는 배양육을 만드는 과정에서 동물 세포에 아미노산을 공급하는 데도 유용할 것으로 보고 있다. 

솔라푸드에 따르면 솔레인 단백질은 식물육, 배양육보다 100배나 더 친환경적이다. 1㎏의 소고기를 생산하는 데는 1만5천리터의 물이, 1㎏의 대두를 생산하는 데는 2500리터의 물이 필요하지만, 솔레인 1㎏을 생산하는 데는 10리터의 물만 있으면 된다는 것이다. 솔레인 단백질 함량은 65%다. 솔라푸드는 현재 하루 1㎏의 공기단백질을 시험 생산하고 있다. 2021년 중 시판에 들어갈 계획이다. 유럽우주국과 함께 이 기술을 우주에서도 활용할 수 있는지도 연구하고 있다.

맛만 보증된다면 소나 돼지도 이제 자리(?)를 잃게 되는건가?

동물들도 민주적 의사결정 내린다

사람은 투표를 통해 자신의 의사를 표현하고 사회가 나아가야 할 방향을 결정한다. 그런데 투표는 사람만 하는 게 아니라 동물도 한다는 사실이 여러 연구를 통해 알려져 있다. 동물 세계도 방법의 차이는 있지만 일종의 투표를 통해 무리의 합의를 이끌어 낸다. 과학자들은 동물들의 투표 방법들이 놀라울 정도로 민주적이라는 분석 결과를 내놓고 있다. (중략)

개미들이 선택하는 투표 방식은 미국의 대선후보를 뽑는 ‘코커스(당원대회)’와 유사하다. 코커스는 제한된 수의 정당 간부나 선거인단이 모여 공직선거에 나설 후보자를 선출하는 것을 일컫는다. 특정 후보지를 지지하는 개미가 많아지고 그 수가 새로운 거처를 지을 정도가 되는 순간, 개미들은 새 리더를 뽑아 한 번에 이사를 감행한다. 코커스가 끝난 후 공직선거를 위해 정당이 다시 하나로 뭉치는 것처럼 기존 개미집에 남아있던 개미들도 새로운 거처로 자리를 옮긴다.

재미있는 내용이라 정리. 결국 무리를 이루는 생명체들이 내리는 무리 차원의 의사 결정은 네트워크 자체의 특성이기 때문에 사람이든 동물이든 마찬가지인 것 같다. 외계인도 다를 바 없을 듯.

미토콘드리아가 없는 기생충 발견

연구팀은 이 기생충이 미토콘드리아가 없을 뿐 아니라 아예 미토콘드리아 DNA의 흔적 자체가 없다는 것을 발견했습니다. 이는 미토콘드리아 없이 매우 오랜 시간을 살아왔다는 이야기입니다. 그런데도 생존이 가능한 비결은 철저하게 기생 생활에 적응된 덕분입니다. 본래 숙주의 양분을 훔쳐 살아가는 것은 모든 기생충의 기본이지만, 헨네구야는 매우 기초적인 것 까지 숙주에 의존해 아예 근육이나 신경까지 퇴화했으며 덕분에 매우 작은 에너지로 살아갈 수 있습니다. 크기 역시 작아져 조직에 침투하기도 쉬워지고 적은 에너지로 기생할 수 있게 된 것은 물론입니다. 이들은 숙주가 죽으면 기생충끼리 모여 포자를 만든 후 다른 숙주에 먹혀 새로운 삶을 이어가게 됩니다. 

그렇다고 합니다.

 

[영화] 1917

기생충과 작품상 경쟁을 한 것으로 유명한 1차 대전 배경의 전쟁 영화. <라이언 일병 구하기> 류의 전쟁씬을 기대했다면 그런 장면은 나오지 않으므로 실망할 수 있다. 사실 나는 그래서 실망했다.

전쟁의 참혹함을 그리는 것과 당시 상황에 몰입하게 하는 연출은 훌륭했으나, 이야기가 너무 단순하며 우연에 의해 해결이 되는 상황이 반복되어서 애매한 부분이 많았다 –픽사 스토리 가이드 라인에 의하면 우연에 의해 사건에 개입되는 것은 좋지만 우연에 의해 사건이 해결되는 것은 하지 말아야 한다고 하는데 1917은 그렇지 않은 장면이 종종 등장 함

삶을 이루는 3가지 원칙

40년 가까이 살면서 깨우친 삶을 이루는 3가지 원칙에 대해 생각해 보았는데, 더 할 수도 덜 할 수도 있겠지만 내 나이가 내 삶의 절반 정도에 이르렀다고 생각해 보면 적어도 이 3가지 원칙이 삶의 절반정도는 되지 않을까 싶다.

  1. 다른 누구로도 말고 오직 스스로를 등불로 삼으라 –붓다
  2. 남에게 대접을 받고자 하는 대로 너희도 남을 대접하라 –예수
  3. 공짜를 바라지 마라

제 1 원칙

붓다가 유언으로 남겼다는 저 말은 자기 자신에 대한 것으로 자신의 삶을 살아가는 기준을 말하는 것이다.

세상은 불공평하고 많은 영역이 운에 닿아 있기 때문에 자신이 제어할 수 없는 밖의 것에 관심을 두지 말고, 다른 것과 자신을 비교하지 말고 오로지 스스로의 기준으로 삶을 살아 가야 한다.

삶이란 생각 보다 길기 때문에, 1-2년의 세상 돌아가는 것이나 남의 말에 현혹되지 말고 자신의 기준으로 10-20년을 바라보고 정진하다 보면, 어느 순간 남들은 따라 오기 어려운 경지에 도달하게 될 것이다.

다른 사람의 삶이 아니라 자기 자신의 삶을 살아야 한다.

제 2 원칙

황금률이라고도 하는 이 원칙은 나 자신에 대한 제 1 원칙과 달리 타인과의 관계에 대한 것이며, 호혜성이나 상호성의 원칙과도 맥락이 통한다.

어느 누구도 자신에게 친절하고 잘해주는 사람과 함께 하고 싶어하지, 자신에게 까다로운 사람과 함께 하고 싶어하지는 않는다. 이는 까다로운 사람 스스로도 마찬가지다. 타인에게 친절한 사람은 결국 타인의 협력을 이끌어 내기 좋고 장기적으로 같이 발전하는 관계 구축이 가능하다.

물론 세상에는 무임승차자가 존재하기 때문에 단기적으로 불이익이 발생하겠지만, 그런 사람이 절대 다수는 아니고 세상에는 평판이라는게 존재해서 무임승차자가 영구적으로 존재하기는 어렵다. 그런 사람은 네트워크 내에서 평판이 떨어져서 결국 네트워크 내에서 배제 당하게 된다.

세상은 홀로 살아갈 수는 없고 다른 사람과 협력하며 살아야 하는데, 그 협력을 이끌어 내려면 결국 타인에게 호혜적이어야 한다.

제 3 원칙

공짜라는 표현 때문에 이 원칙을 경제적인 것으로만 이해하면 다소 협소한 이해이다. 이를 에너지라는 개념으로 확장해 보면 이것은 엔트로피에 대한 것이며, 이는 과학계에서 절대 위상을 차지하는 열역학 제 2법칙과 맞닿은 것이다.

세상 일이란 결국 무질서가 증가하는 방향으로 흐르며, 질서를 잡기 위해서는 에너지를 투여해야 한다. 에너지를 쓰지 않고는 질서를 잡을 수가 없다.

공부하지 않고 성적이 좋을 수 없고, 운동하지 않고 좋은 몸을 가질 수는 없다. 극도로 운이 좋은 예외적인 경우를 제외하고 우리는 에너지를 쓰지 않고 무언가를 얻을 수 없다. 인생을 운에 맞길 수는 없지 않은가?

노력 없이 좋은 결과를 기대해서는 안 된다. 무언가를 원한다면 그에 합당한 노력을 해야 한다.

나우 : 시간의 물리학

나우 : 시간의 물리학

실험 물리학자가 쓴 시간에 대한 물리학 이야기. 상대성이론에서 시작해서 엔트로피, 양자역학에 이르기까지 시간에 대한 다양한 물리학자들의 해석을 다루고 있다.

결론부터 말하자면 애석하게도 아직은 시간에 대한 설득력 있는 설명이 없다는 것. 상대성이론에서는 시간에 대한 정의를 회피하고, 엔트로피에 의한 시간 증가도 틀린 부분이 있으며, 양자역학에서는 시간을 거꾸로 가는 입자가 있는 –저자는 디랙의 음의 바다나 파인만의 시간을 거꾸로 가는 입자에 대해 계산이 맞기 때문에 쓰이고 있을 뿐, 향후에 더 합리적인 설명 체계가 등장하면 대체 되리라는 기대를 하고 있다– 등 아직은 시간에 대해 명확히 합의된 내용이 없다는 것.

현재에는 시간에 대한 정의가 모호하기 때문에 그 지점을 넘어서면 각자의 시간에 대한 철학으로 이어지게 된다. –물리학자인 저자는 그 지점에서 과학주의, 물리주의를 비판한다. 괴델이 수학도 불완전함을 증명했는데, 물리학이 완전하지 못하다는 것을 받아들여야 한다는 것

책의 결론은 모호하지만, 시간에 대한 물리학의 관점이 잘 정리되어 있고 나름 서술이 흥미롭게 잘 되어 있기 때문에 관심 있다면 재미있게 읽을만한 책이라 생각 됨.다만 어려운 내용들이 좀 있어서 물리학에 대한 깊이 있는 수준의 이해가 없으면 내용을 따라가기는 어려운 것 같다. –나도 설명이 깊어지는 부분은 건너 뛰면서 읽었음.

관찰자와 행위자

내가 미로 속에서 길을 찾고 있고, 그런 나를 위에서 바라보고 있는 관찰자가 있다고 하자.

그 관찰자 입장에서는 미로 전체와 그 안에서 돌아다니는 내 모습을 한 눈에 보고 있기 때문에, 내가 진행하는 방향으로 가면 어떠한 결과가 벌어질 지 예측이 가능한 상태일 것이다. 하지만 그렇다고 내가 어떤 방향으로 움직일지 자체는 예측할 수 없는데 내가 직진하다가 갑자기 방향을 틀 가능성도 있기 때문이다.

이는 내가 존재하는 위치에 따라 예측이 가능한 것과 그 범위 자체가 달라진다는 특성이 나타나는데 이에 대해서는 지금 글의 주제와 다르므로 차후에 정리해 보겠다. —-이 경우에서 행위자는 자신의 행동은 예측이 가능하지만 자신의 방향을 유지할 경우 발생할 미래 –미로가 이어지는 길– 은 예측 불가, 관찰자는 행위자가 자신의 방향을 유지할 경우 앞으로 벌어질 일에 대해서는 예측 가능하지만, 행위자가 현재 어떤 행동을 결정할 지는 예측 불가

이와 같은 상황에서 내가 현재 진행하는 외길의 끝이 오른쪽으로 이어져 있고 그 길에는 낭떠러지가 있다고 가정하자. 관찰자 입장에서 행위자인 내가 현재 방향을 고수할 경우 저 행위자는 곧 죽겠군 이라는 비관적인 전망을 예측하고 그에 대한 조치를 준비할 수 있다.

하지만 행위자인 내 입장에서 내가 이 미로 속에서 죽음의 경로를 찾는 것 –자살을 하려는 것– 이 목적이 아닌 이상 길을 따라 가다 끝에서 돌았더니 낭떠러지가 나왔다면 ‘어이쿠 여기는 길이 더 없군’ 하고 다시 왔던 길을 되돌아가면 그만이다. 우리는 생(life)에 대한 의지와 더 나아지려는 의지를 갖고 살아가기 때문이다. –간혹 그렇지 않은 사람도 있을 수도 있겠으나 거의 대부분은 그럴 것이다

나라의 경제가 어려워지든 조직의 운명이 어려워지든 우리는 관찰자 입장에서 쉽게 ‘저러다 망하지’ 라는 말을 쉽게 내놓고 나라나 조직이 망하면 이익을 얻을 수 있는 편으로 베팅을 할 수도 있다. 하지만 행위자인 나라와 조직 입장에서는 자신들의 생을 지속하고 더 낫게 하려는 의지를 갖고 있기 때문에, 어떻게든 현재의 좋지 않은 상황을 더 낫게 하는 방향으로 결정하고 행동할 것이다. –물론 나아지려고 한 결정이 스스로를 망칠 수도 있지만

우리는 그 조직 (혹은 개인)이 더 나은 방향으로 움직일 것이라는 것에 대한 믿음을 갖고 그 조직 (혹은 개인)이 그것을 수행할 수 있는 역량을 갖추었는 지에 대한 판단을 올바르게 하는 것이 미래에 대한 예측을 올바르게 하는 것이다. –망할 것이라고 기우제 지내지 말 것이고, 근거 없이 잘 될 것이라는 믿음도 경계 해야 한다

불가항력적인 –천재지변이나 압도적인 힘을 가진 경쟁자에 의한– 것이 아닌 이상, 어찌되었든 역량이 존재한다면 어려움이라는 것은 결국 극복할 수 있는 것이다.

시간은 흐르지 않는다

시간은 흐르지 않는다

양자중력 이론의 선구자라고 인정 받는 저자가 쓴 시간에 대한 책. 이 책의 저자인 카를로 로벨리의 책은 처음 읽었는데, 왜 이 사람의 전작들이 유명했었는지 이해가 되었다. 대중이 이해하기 쉽게 쓴 것을 더해 대단히 문학적인 글을 잘 쓰는 과학자라고 생각 됨. –예전에 칼 세이건이 유명했었지.

내용을 요약하자면 시간이라는 것은 미시세계에는 존재하지 않는 것이고 –현대 과학이 일관성 있게 이야기하는 것은 시간, 공간도 결국 입자– 시간을 인지하는 것은 거시적인 차원에 존재하는 우리가 기억이나 방향 –엔트로피가 증가하는 방향– 등으로 특별하게 인지하는 것일 뿐이라는 내용.

또 중요한 것은 사실 우리의 근본적인 것은 사물(입자)이 아니라 사건이라는 것. 우리가 사물로 인식하는 것은 일정한 시간과 공간 범위 내에 지속되는 사건이라는 것. 사실 양자적 세계에서는 입자는 외부와 상호작용(관측이라고도 하는) 을 통해 붕괴된 것이고 그 전에는 파동의 형태로 존재하는 것이라는 점을 생각해 보면 이 내용이 자연스럽게 이해가 될 텐데 여튼 그런 내용이다.

여기까지 이해하면 대단히 철학적인 단계까지 이어지는데, 그에 대한 대단히 문학적이고 철학적인 감성으로 내용이 쓰여져 있는데 읽으면서 참 대단하다는 생각을 많이 했음.

책 자체의 분량도 많지 않기 떄문에 대중 교양 과학 지식이 갖춰진 상태라면 한 번쯤 읽어 볼 만한 책이라 생각 함

이상엽/ 해석학/ 리만적분

리만적분

  • (사실 리만 적분은 다르부의 적분과 동일하고, 오히려 다르부 적분이 더 간편하기 때문에 일반적으로 다르부 적분을 이용해서 적분을 다루지만 안타깝게도 리만이 더 유명하기 때문에 리만 적분이라고 부른다.)

리만적분의 정의

Def 1. [분할과 세분]

[a, b] 가 유계인 폐구간이고 a = x_{0} < x_{1} < x_{2} < ... < x_{n} = b 일 때 \mathcal{P} = \{ x_{0}, x_{1}, ... , x_{n} \} [a, b] 의 분할이라 한다.

[a, b] 의 분할 \mathcal{P} \mathcal{P}* 에 대하여 \mathcal{P} \subset \mathcal{P}* 이면 \mathcal{P}* \mathcal{P} 의 세분이라 한다.

Def 2. [상합과 하합]

f [a, b] 에서 유계일 때

\mathcal{P} = \{ x_{0}, x_{1}, ... , x_{n} \} 에 대해

\Delta x_{i} = x_{i} - x_{i - 1}

M_{i} = \sup \{ f(x) | x_{i-1} \leq x \leq x_{i} \}

m_{i} = \inf \{ f(x) | x_{i-1} \leq x \leq x_{i} \} 로 나타내자

이때

  1. U(\mathcal{P}, f) = \sum_{i=1}^{n} M_{i} \Delta x_{i}
  2. L(\mathcal{P}, f) = \sum_{i=1}^{n} m_{i} \Delta x_{i}

을 각각 [a, b] 에서 f 의 상합과 하합이라 한다.

  • (M_{i} 는 구간 내에서 가장 큰 사각형의 면적이고 이것들의 합이 상합 (아래 그림의 왼쪽) m_{i} 은 구간 내에서 가장 작은 사각형의 면적이고 이것들의 합이 하합이다. (아래 그림의 오른쪽))
  • (실제 구간의 면적은 상합과 하합 사이의 값이 되고, 그 구간의 간격을 극한으로 보내면 상합과 하합의 면적의 차이를 줄일 수 있고 최종적으로 그 줄어든 값이 면적이 된다.)

Def 3. [상적분과 하적분]

f [a, b] 에서 유계일 때 [a, b] 의 분할 \mathcal{P} 에 대해

  1. \overline{\int_{a}^{b}} f(x) dx = \overline{\int_{a}^{b}} f = inf \{ U(\mathcal{P}, f) \}
  2. \underline{\int_{a}^{b}} f(x) dx = \underline{\int_{a}^{b}} f = sup \{ L(\mathcal{P}, f) \}

을 각각 [a, b] 에서 f 의 상적분과 하적분이라 한다.

  • (구할 수 있는 상합들 중에서 하한이 상적분, 구할 수 있는 하합들 중에서 상한이 하적분이 된다.)

Thm.

다음 명제들이 성립한다.

  1. \mathcal{P}* [a, b] 의 분할 \mathcal{P} 의 세분이면
    • L(\mathcal{P}, f) \leq L(\mathcal{P}*, f) \leq U(\mathcal{P}, f) \leq U(\mathcal{P}, f) 
    • (원래 분할 보다 더 세분화 시킨 것(세분)의 하합과 상합은 원래 분할의 하합과 상합의 사이에 온다.)
  2. [a, b] 의 임의의 두 분할 \mathcal{P}_{1}, \mathcal{P}_{2} 에 대하여 L(\mathcal{P}_{1}, f) \leq U(\mathcal{P}_{2}, f) 이다.
    • (임의의 두 분할에서 한쪽 분할의 상합은 다른쪽 분할의 하합 보다 항상 크다.)
  3. f [a, b] 에서 유계이면
    • \underline{\int_{a}^{b}} f \leq \overline{\int_{a}^{b}} f

Def 4. [리만적분가능성]

f [a, b] 에서 유계일 때

\underline{\int_{a}^{b}} f = \overline{\int_{a}^{b}} f

이면 f [a, b] 에서 리만적분가능하다고 하며

\int_{a}^{b} f(x) dx = \int_{a}^{b} f = \underline{\int_{a}^{b}} f = \overline{\int_{a}^{b}} f

로 표현한다. 또한 [a, b] 에서 유계인 리만적분가능한 함수 f 들의 집합을 \mathfrak{R} [a, b] 로 나타낸다 (f \in \mathfrak{R} [a, b] )

  • (상적분 값과 하적분 값이 같게 되면 리만적분 가능하다고 한다. 둘이 같게 되지 않은 경우도 있음.)
  • (리만적분이 불가능하다고 해서 적분 자체가 안되는 것은 아니다. 다른 적분법을 이용하면 적분이 가능할 수 있음.)

주요 정리

Thm 1. [리만적분 판별법]

f [a, b] 에서 유계일 때 다음이 성립한다. (\mathcal{P} [a, b] 의 분할)

f \in \mathfrak{R} [a, b]

\Leftrightarrow \forall \epsilon > 0, \exists \mathcal{P} s.t. U(\mathcal{P}, f) - L(\mathcal{P}, f) < \epsilon

  • (상합과 하합의 차이가 \epsilon 보다 작아지면 리만적분 가능하다 = 상적분과 하적분의 값이 같다.)

Thm 2. [연속성과 리만적분가능성]

f [a, b] 에서 연속이면 f \in \mathfrak{R} [a, b] 이다.

  • (연속이면 리만적분 가능하다. 연속이라고 미분은 안되는데, 연속이면 적분이 됨)
  • (불연속이어도 리만적분 가능한 경우가 있다)

Thm 3. [적분의 평균값 정리]

f [a, b] 에서 연속이면

\int_{a}^{b} f = f(c)(b-a) c \in (a, b) 가 존재한다.

리만적분의 연산

  • f, g \in \mathfrak{R} [a, b] 이면 다음이 성립한다.
    • \int_{a}^{b} (f \pm g) = \int_{a}^{b} f \pm \int_{a}^{b} g (복부호동순)
  • f \in \mathfrak{R} [a, b] 
    • \Leftrightarrow \forall c \in (a, b), f \in \mathfrak{R}[a, c] \wedge f \in \mathfrak{R}[c, b]
    • with \int_{a}^{b} f = \int_{a}^{c} f  + \int_{c}^{b} f

미적분학의 기본정리

제 1 기본정리

Def. [부정적분]

f \in \mathfrak{R} [a, b] 일 때 x \in [a, b] 에 대하여

F(x) = \int_{a}^{x} f(t) dt

로 정의한 함수 F [a, b] 에서 f 의 부정적분이라 한다.

Thm. [미적분학의 제 1 기본정리]

f \in \mathfrak{R} [a, b] 이면 f [a, b] 에서 f 의 부정적분 F 에 대하여 다음이 성립한다.

  1. F [a, b] 에서 균등연속이다.
  2. f [a, b] 에서 연속이면 F [a, b] 에서 미분가능하고 \forall x \in [a, b], F'(x) = f(x) 이다.
  • (미분과 적분의 연산이 역관계를 갖는다는 의미)
  • (이를 최초로 발견한 사람은 이탈리아 수학자였던 토리첼리. 이를 좀 더 일반화한 사람이 뉴턴의 스승이었던 아이작 배로)

제 2 기본정리

Def. [역도함수]

D 가 구간이고 f, F : D \to \mathbb{R} 가 모든 x \in D 에 대하여 F'(x) = f(x) 이면 F f 의 역도함수라 한다.

Thm. [미적분학의 제 2 기본정리]

f \in \mathfrak{R} [a, b] 이고 F : [a, b] \to \mathbb{R} [a, b] 에서 연속이고 (a, b) 에서 미분가능하다고 하자. 이때 F f 의 역도함수이면 다음이 성립한다.

\int_{a}^{b} f = F(b) - F(a)

따름정리

Thm 1. [치환적분법]

g [a, b] 에서 미분가능하고 g' \in \mathfrak{R} [a, b] 이며 f g([a, b]) 에서 연속이면 다음이 성립한다.

\int_{a}^{b} f(g(t))g'(t) dt = \int_{g(a)}^{g(b)} f(x) dx

Thm 2. [부분적분법]

f, g: [a, b] \to \mathbb{R} [a, b] 에서 연속이고 (a, b) 에서 미분가능하며 f', g' \in \mathfrak{R} [a, b] 이면 다음이 성립한다.

\int_{a}^{b} f' g = \{ f(b)g(b) - f(a)g(a) \} - \int_{a}^{b} f g'

리만적분의 확장

  • (리만적분으로는 면적을 구할 수 없는 경우가 많아서 수학자들이 새로 방법을 정의한 것들이 다른적분 방법들)

특이적분

  • (이상 적분이라고도 함. 적분 구간이 유계인 폐구간이 아니거나 f가 유계가 아닌 경우에도 사용할 수 있는 적분 방법)

Def 1. [(a, b] 또는 [a, b) 의 경우]

  1. f : (a, b] \to \mathbb{R} 가 임의의 c \in (a, b) 에 대하여 f \in \mathfrak{R} [c, b] 이면 (a, b] 에서 f 의 특이적분은 \int_{a}^{b} f = \lim_{c \to a+} \int_{c}^{b} f 로 정의한다.
    • f : [a, b) \to \mathbb{R} 의 경우 \int_{a}^{b} f = \lim_{c \to b-} \int_{a}^{c} f
  2. 1에서 우변의 극한이 존재하면 각 구간에 대해 f 는 특이적분가능하다고 한다.
  3. f : [a, b] - \{ c \} \to \mathbb{R} [a, c) (c, b] 에서 특이적분가능하면 f [a, b] 에서 특이적분가능하다고 하고 \int_{a}^{b} f = \lim_{p \to c-} \int_{a}^{p} f + \lim_{q \to c+} \int_{q}^{b} f 로 정의한다.
  • (폐구간이 아니기 때문에 중간에 폐구간이 되는 점을 잡고 그 점을 개구간으로 향하는 극한을 취함)

Def 2. [[a, \infty) 또는 (-\infty, b] 의 경우]

  1. f : [a, \infty) \to \mathbb{R} a < c 인 임의의 c \in \mathbb{R} 에 대하여 f \in \mathfrak{R} [a, c] 이면 [a, \infty) 에서 f 의 특이적분은 \int_{a}^{\infty} f = \lim_{c \to \infty} \int_{a}^{c} f 로 정의한다.
    • f : (-\infty, b] \to \mathfrak{R} 의 경우 \int_{-\infty}^{b} f = \lim_{c \to -\infty} \int_{c}^{b} f
  2. 1에서 우변의 극한이 존재하면 각 구간에 대해 f 는 특이적분가능하다고 한다.
  3. f 가 적당한 p \in \mathbb{R} 에 대하여 (-\infty, p] [p, \infty) 에서 특이적분가능하면 f \mathbb{R} 에서 특이적분가능하다고 하고 \int_{-\infty}^{\infty} f = \int_{-\infty}^{p} f + \int_{p}^{\infty} f 로 정의한다.
  • (위와 비슷하게 정의. 폐구간 점보다 큰 임의의 점을 잡아서 적분 가능한지 확인하고 그 임의의 점을 무한으로 향하는 극한을 취함)

스틸체스적분

  • (\int f(x) dg(x) 의 꼴로 표현되는 형태로 g(x) 는 증가함수로 정의됨)
  • (g(x) x 가 되면 리만적분의 형태가 되기 때문에 리만적분의 일반화된 버전으로 생각할 수 있다.)
  • (리만적분은 연속이어야 가능하지만, 스틸체스적분은 불연속적인 것에 대해서도 적분이 가능하다. g(x) 를 불연속적인 함수로 잡으면 되기 때문)

Def 1. [스틸체스 상합과 하합]

[a, b] 에서 유계인 함수 f 와 증가함수 \alpha, [a, b] 의 분할 \mathcal{P} = \{ x_{0}, x_{1}, ... , x_{n} \} \Delta \alpha_{i} = \alpha(x_{i}) - \alpha(x_{i-1} 에 대하여

  1. U(\mathcal{P}, f, \alpha) = \sum_{i = 1}^{n} M_{i} \Delta \alpha_{i}
  2. L(\mathcal{P}, f, \alpha) = \sum_{i = 1}^{n} M_{i} \Delta \alpha_{i}

을 각각 \alpha 에 관한 f 의 스틸체스상합, 스틸체스하합이라 한다. (i = 1, 2, ... , n )

Def 2. [스틸체스 상적분과 하적분]

[a, b] 에서 유계인 함수 f 와 증가함수 \alpha, [a, b] 의 분할 \mathcal{P} 에 대하여

  1. \overline{\int_{a}^{b}} f d\alpha = \inf \{ U(\mathcal{P}, f, \alpha) \}
  2. \underline{\int_{a}^{b}} f d\alpha = \sup \{ L(\mathcal{P}, f, \alpha) \}

을 각각 \alpha 에 관한 f 의 스틸체스 상적분과 스틸체스 하적분이라 한다.

Def 3. [스틸체스 적분 가능성]

f [a, b] 에서 유계이고 \alpha [a, b] 에서 증가함수 일 때

\overline{\int_{a}^{b}} f d\alpha = \underline{\int_{a}^{b}} f d\alpha

이면 f [a, b] 에서 \alpha 에 관하여 스틸체스적분가능하다고 하며

\int_{a}^{b} f d\alpha = \overline{\int_{a}^{b}} f d\alpha = \underline{\int_{a}^{b}} f d\alpha

로 표현하고 이를 \alpha 에 관한 f 의 스틸체스적분이라 한다. (f \in \mathfrak{R}_{\alpha} [a, b] )

Thm.

f \in \mathfrak{R} [a, b] 이고 \alpha [a, b] 에서 증가하고 미분가능한 함수이며 \alpha ' \in \mathfrak{R}_{\alpha} [a, b] 이면 f \in \mathfrak{R}_{\alpha} [a, b] 이고 다음이 성립한다.

\int_{a}^{b} f d \alpha = \int_{a}^{b} f(x) \alpha '(x) dx

  • (리만 적분은 스틸체스 적분의 \alpha = x 인 지점이므로 \int_{a}^{b} f(x) x' dx 이 되고 x' = 1 이므로 결과적으로 \int_{a}^{b} f(x) dx 의 꼴이 된다)

머신 러닝 교과서/ 간단한 분류 알고리즘 훈련

인공 뉴런: 초기 머신러닝의 간단한 역사

  • 1943년 워런 맥컬록과 월터 피츠는 처음으로 간소화된 뇌의 뉴런 개념을 발표함. 이를 맥컬록-피츠(MCP) 뉴런이라고 한다.
    • 맥컬록과 피츠는 신경 세포를 이진 출력을 내는 간단한 논리 회로로 표현했다. 수상 돌기에 여러 신호가 도착하면 세포체에 합쳐지고 합쳐진 신호가 특정 임계값을 넘으면 출력 신호가 생성되고 축삭 돌기를 이용해서 전달 됨
  • 몇 년 후 프랑크 로젠블라트는 MCP 뉴런 모델을 기반으로 퍼셉트론 학습 개념을 처음 발표함.
    • 퍼셉트론 규칙에서 로젠블라트는 자동으로 최적의 가중치를 학습하는 알고리즘을 제안함.
    • 이 가중치는 뉴런의 출력 신호를 낼지 말지를 결정하기 위해 입력 특성에 곱하는 계수.
    • 지도 학습과 분류 개념으로 말하면 이 알고리즘으로 샘플이 한 클래스에 속하는지 아닌지를 예측할 수 있다.

인공 뉴런의 수학적 정의

  • 인공 뉴런(artifical neuron) 아이디어를 두 개의 클래스가 있는 이진 분류(binary classification) 작업으로 볼 수 있다.
    • 두 클래스는 간단하게 1(양성)과 -1(음성)으로 나타낸다. 그 다음 입력값 x 와 이에 상응하는 가중치 벡터 w 의 선형 조합으로 결정함수(\phi(z) )를 정의한다.
    • 최종 입력(net input)인 z z = w_{1} + x_{1} + ... + w_{m} x_{m} 이다.

w = \left[ \begin{array}{rrr} w_{1} \\ ... \\ w_{m} \end{array} \right], x = \left[ \begin{array}{rrr} x_{1} \\ ... \\ x_{m} \end{array} \right]

  • 이제 특정 샘플 x^{(i)} 의 최종 입력이 사전에 정의된 임계 값 \theta 보다 크면 클래스 1로 예측하고 그렇지 않으면 클래스 -1로 예측한다.
    • 퍼셉트론 알고리즘에서 결정함수 \phi(\cdot) 는 단위 계단 함수(unit step function)를 변형한 것이다.

\phi(z) = \begin{cases} 1 & z \geq \theta \\ -1 & else \end{cases}

  • 식을 간단하게 만들기 위해 임계 값 \theta 를 식의 왼조긍로 옮겨 w_{0} = -\theta x_{0} = 1 인 0번째 가중치를 정의한다. 이렇게 하면 z 를 좀 더 간단하게 쓸 수 있다.

z = w_{0}x_{0} + w_{1}x_{1} + ...  + w_{m}x_{m} = w^{T}x

  • 결정 함수는 다음과 같다.

\phi(z) = \begin{cases} 1 & z \geq \theta \\ -1 & else \end{cases}

  • 머신 러닝 분야에서 음수 임계 값 또는 가중치 w_{0} = -\theta 를 절편이라고 한다.
  • 그림 2-2는 퍼셉트론 결정함수로 최종 입력 z = w^{T}x 가 이진 출력 (-1 또는 1)으로 압축되는 방법(왼쪽)과 이를 사용하여 선형 분리가 가능한 두 개의 클래스 사이를 구별하는 방법(오른쪽)을 나타낸다.

퍼셉트론 학습 규칙

  • MCP 뉴런과 로젠블라트의 임계 퍼셉트론 모델 이면에 있는 전반적인 아이디어는 뇌의 뉴런 하나가 작동하는 방식을 흉내내려는 환원주의(reductionism) 접근 방식을 사용한 것이다.
    • 즉 출력을 내거나 내지 않는 두 가지 경우만 있다. 따라서 로젠블라트의 초기 퍼셉트론 학습 규칙을 요약하면 다음과 같다.
      1. 가중치를 0 또는 랜덤한 작은 값으로 초기화 한다.
      2. 각 훈련 샘플 x^{(i)} 에서 다음 작업을 한다.
        1. 출력값 \hat{y} 를 계산한다.
        2. 가중치를 업데이트 한다.
  • 여기서 출력 값은 앞서 정의한 단위 계단 함수로 예측한 클래스 레이블이다. 가중치 벡터 w 에 있는 개별 가중치 w_{j} 가 동시에 업데이트 되는 것을 다음과 같이 쓸 수 있다.

w_{j} := w_{j} + \Delta w_{j}

  • 가중치 w_{j} 를 업데이트 하는데 사용되는 \Delta w_{j} 값은 퍼셉트론 학습 규칙에 따라 계산된다.

\Delta w_{j} = \eta (y^{(i)} - \hat{y}^{(i)}) x_{j}^{(i)}

  • 여기서 \eta (eta)는 학습률(learning rate)이다. (일반적으로 0.0에서 1.0 사이의 값)
    • y^{(i)} i 번째 훈련 샘플의 진짜 클래스 레이블이다.
    • \hat{y}^{(i)} 는 예측 클래스 레이블이다.
  • 가중치 벡터의 모든 가중치를 동시에 업데이트 한다는 점이 중요하다. 즉, 모든 가중치 \Delta w_{j} 를 업데이트 하기 전에 \hat{y}^{(i)} 를 다시 계산하지 않는다.
  • 구체적으로 2차원 데이터셋에서는 다음과 같이 업데이트 된다.

\Delta w_{0} = \eta (y^{(i)} - output^{(i)})

\Delta w_{1} = \eta (y^{(i)} - output^{(i)}) x_{1}^{i}

\Delta w_{2} = \eta (y^{(i)} - output^{(i)}) x_{2}^{i}

  • 퍼셉트론 규칙이 어떻게 작동하는지 알아보자.
  • 퍼셉트론이 클래스 레이블을 정확히 예측한 다음의 두 경우는 가중치가 변경되지 않고 그대로 유지된다.

\Delta w_{j} = \eta (1 - 1) x_{j}^{i} = 0

\Delta w_{j} = \eta ((-1) - (-1)) x_{j}^{i} = 0

  • 잘못 예측했을 때는 가중치를 양성 또는 음성 타깃 클래스 방향으로 이동시킨다.

\Delta w_{j} = \eta (1 - (-1)) x_{j}^{i} = \eta(2)x_{j}^{(i)}

\Delta w_{j} = \eta (-1 - 1) x_{j}^{i} = \eta(-2)x_{j}^{(i)}

  • 곱셈 계수인 x_{j}^{(i)} 를 좀 더 잘 이해하기 위해 다른 예를 살펴보겠다.

y^{(i)} = 1, \hat{y}_{j}^(i) = -1, \eta = 1

  •  x_{j}^{(i)} = 0.5 일 때 이 샘플을 -1로 잘못 분류했다고 가정한다.
    • 이때 가중치가 1 만큼 증가되어 다음 번에 이 샘플을 만났을 때 최종 입력 x_{j}^{(i)} \times w_{j}^{(i)} 가 더 큰 양수가 된다.
    • 단위 계단 함수의 임계 값보다 커져 샘플이 +1로 분류될 가능성이 높아질 것이다.

\Delta w_{j}^{(i)} = (1 - (-1)) 0.5 = (2) 0.5 = 1

  • 가중치 업데이트는 x_{j}^{(i)} 값에 비례한다. 예컨대 다른 샘플 x_{j}^{(i)} = 2 를 -1로 잘못 분류했다면 이 샘플을 다음번에 올바르게 분류하기 위해 더 크게 결정 경게를 움직인다.

\Delta w_{j}^{(i)} = (1 - (-1)) 2 = (2) 2 = 4

  • 퍼셉트론은 두 클래스가 선형적으로 구분되고 학습률이 충분히 작을 때만 수렴이 보장된다.
    • 두 클래스를 선형 결정 경계로 나눌 수 없다면 훈련 데이터셋을 반복할 최대 횟수(에포크(epoch))를 지정하고 분류 허용 오차를 지정할 수 있다. 그렇지 않으면 퍼셉트론 가중치 업데이트를 멈추지 않는다.

  • 그림 2-4는 퍼셉트론이 샘플 x_{j}^{(i)} 를 입력으로 받아 가중치 x_{j}^{(i)} 를 연결하여 최종 입력을 계산하는 방법을 보여준다.
    • 그 다음 최종 입력은 임계 함수로 전달되어 샘플의 예측 클래스 레이블인 -1 또는 +1의 이진 출력을 만든다.
    • 학습 단계에서 이 출력을 사용하여 예측 오차를 계산하고 가중치를 업데이트 한다.

파이썬으로 퍼셉트론 학습 알고리즘 구현

객체 지향 퍼셉트론 API

  • 객체 지향 방식을 사용하여 퍼셉트론 인터페이스를 가진 파이썬 클래스를 정의
    • Perceptron 객체를 초기화한 후 fit 메서드로 데이터에서 학습하고, 별도의 predict 메서드로 예측을 만든다.
    • 관례에 따라 초기화 과정에서 생성하지 않고 다른 메서드를 호출하여 만든 속성에는 밑줄(_)을 추가한다. ex) self.w_
import numpy as np

class Perceptron(object):

    """ 퍼셉트론 분류기

    매개변수
   ----------
   eta : float
       학습률 (0.0과 1.0사이)
    n_iter : int
       훈련 데이터셋 반복 횟수
    random_state : int
       가중치 무작위 초기화를 위한 난수 생성기 시드

   속성
   ---------
   w_ : 1d-array
       학습된 가중치
    errors_ : list
       에포크마다 누적된 분류 오류
    """

   def __init__(self, eta=0.01, n_iter=50, random_state=1):
       self.eta = eta
       self.n_iter = n_iter
       self.random_state = random_state

    def fit(self, X, y):
        """ 훈련 데이터 학습

        매개변수
       ----------
       X : {array-like}, shape = [n_samples, n_features]
            n_samples개의 샘플과 n_features개의 특성으로 이루어진 훈련 데이터
       y : array-like, shape = [n_samples]
           타겟 값       

        반환값
       ---------
        self : object
        """

       rgen = np.random.RandomState(self.random_state)
        self.w_ = rgen.normal(loc = 0.0, scale = 0.1, size = 1 + X.Shape[1])
        self.errors_ = []

       for _ in range(self.n_iter):
            errors = 0

           for xi, target in zip(X, y):
               update = self.eta * (target - self.predict(xi))
                self.w_[1:] += update * xi
                self.w_[0] += update
                errors += int(update != 0.0)

            self.errors_.append(errors)

        return self

    def net_input(self, X):
       """ 최종 입력 계산 """
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def predict(self, X):
       """ 단위 계단 함수를 사용하여 클래스 레이블을 반환합니다 """
       return np.where(self.net_input(X) >= 0.0, 1, -1)
  • 이 퍼셉트론 구현을 사용하여 학습률 eta와 에포크 횟수(훈련 데이터를 반복하는 횟수) n_iter로 새로운 Perceptron 객체를 초기화 한다.
    • fit 메서드에서 self.w_ 가중치를 벡터 \mathbb{R}^{m + 1} 로 초기화한다.
    • 여기서 m은 데이터셋에 있는 차원(특성) 개수이다.
    • 벡터의 첫 번째 원소인 절편을 위해 1을 더했다. 즉 이 벡터의 첫 번째 원소 self.w_[0]는 앞서 언급한 절편이다.
  • 이 벡터는 rgen.normal(loc = 0.0, scale = 0.01, size = 1 + X.shape[1])을 사용하여 표준 편차가 0.01인 정규 분포에서 뽑은 랜덤한 작은 수를 담고 있다.
    • 여기서 rgen은 넘파이 난수 생성기로 사용자가 지정한 랜덤 시드(seed)로 이전과 동일한 결과를 재현할 수 있다.
  • 가중치를 0으로 초기화 하지 않는 이유는 가중치가 0이 아니어야 학습률 \eta 가 분류 결과에 영향을 주기 때문이다.
    • 가중치가 0으로 초기화되어 있다면 학습률 파라미터 eta는 가중치 벡터의 방향이 아니라 크기에만 영향을 미친다.
  • fit 메서드는 가중치를 초기화한 후 훈련 세트에 있는 모든 개개의 샘플을 반복 순회하면서 이전 절에서 설명한 퍼셉트론 학습 규칙에 따라 가중치를 업데이트 한다.
    • 클래스 레이블은 predict 메서드에서 예측한다.
    • fit 메서드에서 가중치를 업데이트하기 위해 predict 메서드를 호출하여 클래스 레이블에 대한 예측을 얻는다.
    • predict 메서드는 모델이 학습되고 난 후 새로운 데이터의 클래스 레이블을 예측하는데도 사용할 수 있다.
  • 에포크마다 self.errors_ 리스트에 잘못 분류된 횟수를 기록한다. 나중에 훈련하는 동안 얼마나 퍼셉트론을 잘 수행했는지 분석할 수 있다.

붓꽃 데이터셋에서 퍼셉트론 훈련

  • 앞서 만든 퍼셉트론 구현을 테스트 하기 위해 붓꽃 데이터셋에서 Setosa, Versicolor 두 개의 클래스만 사용한다.
    • 퍼셉트론 알고리즘은 다중 클래스 분류로 확장이 가능한데, 일대다(one-versus-all, OvA) 전략 등을 사용하면 된다.
  • pandas 라이브러리를 사용하여 붓꽃 데이터셋을 DataFrame 형식으로 읽고 꽃받침 길이와 꽃잎 길이를 추출하여 2차원 산점도를 그리면 그림 2-6과 같다.
import matplotlib.pyplot as plt
import numpy as np

# setosa와 versicolor를 선택
y = df.iloc[0:100, 4].values
y = np.where(y == 'Iris-setosa', -1, 1)

# 꽃받침 길이와 꽃잎 길이를 추출
X = df.iloc[0:100, [0,2]].values

# 산점도를 그린다.
plt.scatter(X[:50, 0], X[:50, 1], color='red', marker='o', label='setosa')
plt.scatter(X[50:100, 0], X[50:100, 1], color='blue', marker='x', label='versicolor')
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
plt.show()

  • 이 데이터셋에서 추출한 일부 데이터를 이용하여 퍼셉트론 알고리즘을 훈련하고 에포크 대비 잘못 분류된 오차를 그래프로 그리면 다음과 같다.
ppn = Perceptron(eta=0.1, n_iter=10)
ppn.fit(X, y)
plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of errors')
plt.show()

  • 퍼셉트론은 6번째 에포크 이후에 수렴했고 훈련 샘플을 완벽하게 분류했다.
  • 최종적으로 데이터셋의 결정 경계를 시각화 하면 아래 그림과 같다.
from matplotlib.colors import ListedColormap

def plot_decision_regions(X, y, classifier, resolution=0.02):
    # 마커와 컬러맵을 설정
   markers = ('s', 'x', '0', '^', 'v')
   colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
   cmap = ListedColormap(colors[:len(np.unique(y))])
    # 결정 경계를 그린다.
   x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
   x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
   Z = Z.reshape(xx1.shape)
   plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
   plt.ylim(xx2.min(), xx2.max())
    # 샘플의 산점도를 그린다.
   for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha = 0.8, c = colors[idx], marker = markers[idx], label = cl, edgecolor = 'black')

plot_decision_regions(X, y, classifier=ppn)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc = 'upper left')
plt.show()

적응형 선형 뉴런과 학습의 수렴

  • 이 절에서는 단일층 신경망의 또 다른 종류인 적응형 선형 뉴런(Adaptive Linear Neuron, ADALINE)을 살펴보겠다.
    • 버나드 위드로우와 테드 호프는 프랑크 로젠블라트의 퍼셉트론 알고리즘 이 후 몇 년 지나지 않아 아달린(Adaline)을 발표했는데, 이는 퍼셉트론의 향상된 버전으로 볼 수 있다.
    • 아달린은 연속 함수(continous function)으로 비용 함수를 정의하고 최소화하는 핵심 개념을 보여주기 때문에 흥미롭다.
  • 아달린 규칙(위드로우-호프 규칙이라고도 함)과 로젠블라트 퍼셉트론의 가장 큰 차이점은 가중치를 업데이트 하는데 퍼셉트론처럼 단위 계단 함수 대신 선형 활성화 함수를 사용한다는 것이다.
    • 아달린에서 선형 활성화 함수 \phi(z) 는 최종 입력과 동일한 함수이다.

\phi (w^{T}x) = w^{T} x

  • 선형 활성화 함수가 가중치 학습에 사용되지만 최종 예측을 만드는데 여전히 임계 함수를 사용하는데, 이는 앞서 보았던 단위 계단 함수와 비슷하다.
    • 퍼셉트론과 아달린 알고리즘의 차이는 아래 그림과 같다.

  • 아달린 알고리즘은 진짜 클래스 레이블과 선형 활성화 함수의 실수 출력 값을 비교하여 모델의 오차를 계산하고 가중치를 업데이트 한다.
    • 반면 퍼셉트론은 진짜 클래스 레이블과 예측 클래스 레이블을 비교한다.

경사 하강법으로 비용 함수 최소화

  • 지도 학습 알고리즘의 핵심 구성 요소는 학습 과정 동안 최적화 하기 위해 정의한 목적 함수(object function)이다.
    • 종종 최소화하려는 비용 함수가 목적 함수가 된다.
    • 아달린은 계산된 출력과 진짜 클래스 레이블 사이의 제곱 오차합(Sum of Squared Errors, SSE)으로 가중치를 학습할 비용 함수 J 를 정의한다.

J(w) = {1 \over 2} \sum_{i} (y^{(i)} - \phi(z^{(i)}))^{2}

  • 1/2 항은 그래디언트(gradient)를 간소하게 만들려고 편의상 추가한 것이다.
  • 단위 계단 함수 대신 연속적인 선형 활성화 함수를 사용하는 장점은 비용 함수가 미분 가능해진다는 것이다.
    • 이 비용 함수의 또 다른 장점은 볼록 함수라는 것이다. 간단하지만 강력한 최적화 알고리즘인 경사 하강법(gradient descent)을 적용하여 붓꽃 데이터셋의 샘플을 분류하도록 비용 함수를 최소화하는 가중치를 찾을 수 있다.
  • 아래 그림에서는 경사 하강법 이면에 있는 핵심 아이디어를 지역 또는 전역 최솟값에 도달할 때까지 언덕을 내려오는 것으로 묘사한다.
    • 각 반복에서 경사의 반대 방향으로 진행한다.
    • 진행 크기는 경사의 기울기와 학습률로 결정한다.

  • 경사 하강법을 사용하면 비용 함수 J(w) 의 그래디언트 \nabla J(w) 반대 방향으로 조금씩 가중치를 업데이트 한다.

w := w + \Delta w

  • 가중치 변화량 \Delta w 는 음수의 그래디언트에 학습률 \eta 를 곱한 것으로 정의한다.

\Delta w = - \eta \nabla J(w)

  • 비용 함수의 그래디언트를 계산하려면 각 가중치 w_{j} 에 대한 편도 함수를 계산해야 한다.

{\partial J \over \partial w_{j}} = - \sum_{i} (y^{(i)} - \phi(z^{(i)})) x_{j}^{(i)}

  • 따라서 가중치 w_{j} 의 업데이트 공식을 다음과 같이 쓸 수 있다.

\Delta w_{j} = - \eta {\partial J \over \partial w_{j}} = \eta \sum_{i} (y^{(i)} - \phi(z^{(i)})) x_{j}^{(i)}

  • 모든 가중치가 동시에 업데이트 되기 때문에 아달린 학습 규칙은 다음과 같다.

w := w + \Delta w

  • 아달린 학습 규칙이 퍼셉트론 규칙과 동일하게 보이지만 z^{(i)} = w^{T} x^{(i)} \phi(z^{(i)}) 는 정수 클래스로 레이블이 아니고 실수이다.
    • 또 훈련 세트에 있는 모든 샘플을 기반으로 가중치 업데이트를 계산한다.
    • 이 방식을 배치 경사 하강법(batch gradient descent)라고도 한다.

파이썬으로 아달린 구현

  • 퍼셉트론 규칙과 아달린이 매우 비슷하기 때문에 앞서 정의한 퍼셉트론 구현에서 fit 메서드를 바꾸어 경사 하강법으로 비용 함수가 최소화 되도록 가중치를 업데이트 한다.
import numpy as np

class AdalineGD(object):
   """ 적응형 선형 뉴런 분류기
    매개변수
   ----------
   eta : float
       학습률 (0.0과 1.0사이)
    n_iter : int
       훈련 데이터셋 반복 횟수
    random_state : int
        가중치 무작위 초기화를 위한 난수 생성기 시드

    속성
   ---------
   w_ : 1d-array
       학습된 가중치
    errors_ : list
       에포크마다 누적된 분류 오류
    """

    def __init__(self, eta = 0.01, n_iter = 50, random_state = 1):
       self.eta = eta
       self.n_iter = n_iter
        self.random_state= random_state

    def fit(self, X, y):
       """ 훈련 데이터 학습
        매개변수
       ----------
       X : {array-like}, shape = [n_samples, n_features]
            n_samples개의 샘플과 n_features개의 특성으로 이루어진 훈련 데이터
       y : array-like, shape = [n_samples]
           타겟 값       

        반환값
       ---------
       self : object
        """

       rgen = np.random.RandomState(self.random_state)
        self.w_ = rgen.normal(loc = 0.0, scale = 0.01, size = 1 + X.shape[1])
       self.cost_ = []

       for i in range(self.n_iter):
           net_input = self.net_input(X)
           output = self.activation(net_input)
            errors = (y - output)
           self.w_[1:] += self.eta * X.T.dot(errors)
            self.w_[0] += self.eta * errors.sum()
           cost = (errors**2).sum() / 2.0
           self.cost_.append(cost)       

        return self

   def net_input(self, X):
       """ 최종 입력 계산 """
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def activation(self, X):
       """ 선형 활성화 계산 """
        return X

   def predict(self, X):
       """ 단위 계단 함수를 사용하여 클래스 레이블을 반환합니다 """
       return np.where(self.net_input(X) >= 0.0, 1, -1)
  • 퍼셉트론처럼 개별 훈련 샘플마다 평가한 후 가중치를 업데이트 하지 않고, 전체 훈련 데이터셋을 기반으로 그래디언트를 계산한다.
    • 절편(0번째 가중치)은 self.eta * errors.sum() 이고 가중치 1에서 m까지는 self.eta * X.T.dot(errors)이다.
    • 여기서 X.T.dot(errors)는 특성 행렬과 오차 벡터 간의 행렬-벡터 곰셈이다.
  • 이 코드의 activation 메서드는 단순한 항등 함수(identity function)이기 때문에 아무런 영향을 미치지 않는다.
    • 단일층 신경망을 통해 정보가 어떻게 흘러가는지를 표시하려고 추가했다.
  • 입력 데이터의 특성에서 최종 입력, 활성화, 출력 순으로 진행된다.
    • 다음 장에서는 항등 함수가 아니고 비선형 활성화 함수를 사용하는 로지스틱 회귀 분류기를 다룰 것인데, 로지스틱 회귀 모델은 활성화 함수와 비용 함수만 다르고 아달린과 매우 비슷하다.
fit, ax = plt.subplots(nrows=1, ncols=2, figsize=(10,4))

ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, y)

ax[0].plot(range(1, len(ada1.cost_) + 1), np.log10(ada1.cost_), marker='o')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('log(Sum-squared-error)')
ax[0].set_title('Adaline - Learning rate 0.01')

ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, y)

ax[1].plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Sum-squared-error')
ax[1].set_title('Adaline - Learning rate 0.0001')

plt.show()
  • 출력된 비용 함수 그래프에서 볼 수 있 듯 두 개의 다른 문제가 발생한다.
    • 아래 그림 2-11 왼쪽 그래프는 학습률이 너무 클 때 발생한다.
    • 비용 함수를 최소화 하지 못하고 오차는 에포크마다 점점 더 커진다. 전역 최솟값을 지나쳤기 때문이다.
    • 반면 오른쪽 그래프에서는 비용이 감소하지만 학습률 \eta = 0.0001 은 너무 작기 때문에 알고리즘이 전역 최솟값에 수렴하려면 아주 많은 에포크가 필요하다.

  • 아래 그림 2-12는 비용 함수 J 를 최소화하려고 특정 가중치 값을 바꾸었을 때 어떤 일이 일어나는지 보여준다.
    • 왼쪽 그림은 적절하게 선택한 학습률의 경우로, 비용이 점차 감소하여 전역 최솟값 방향으로 이동한다.
    • 오른쪽 그림은 너무 큰 학습률을 선택하여 전역 최솟값을 지나친다.

특성 스케일을 조정하여 경사 하강법 결과 향상

  • 책에서 살펴볼 머신 러닝 알고리즘들은 최적의 성능을 위해 어떤 식으로든 특성 스케일을 조정하는 것이 필요하다. 이는 3, 4장에서 살펴보겠다.
  • 경사 하강법은 특성 스케일을 조정하여 혜택을 볼 수 있는 많은 알고리즘 중 하나이다. 이 절에서는 표준화(standardization)라고 하는 특성 스케일 방법을 사용하겠다.
    • 데이터에 표준 정규 분포의 성질을 부여하여 경사 하강법 학습이 좀 더 빠르게 수렴되도록 돕는다.
    • 표준화는 각 특성의 평균을 0에 맞추고 특성의 표준 편차를 1로 만든다.
    • 예컨대 j 번째 특성을 표준화 하려면 모든 샘플에서 평균 \mu_{j} 을 빼고 표준 편차 \sigma_{j} 로 나누면 된다.

x'_{j} = {x_{j} - \mu_{j} \over \sigma_{j}}

  • 여기서 x_{j} n 개의 모든 훈련 샘플에서 j 번째 특성 값을 포함한 벡터이다.
    • 표준화 기법을 데이터셋의 각 특성 j 에 적용한다.
    • 표준화가 경사 하강법 학습에 도움이 되는 이유 중 하나는 그림 2-13에 나온 것처럼 더 적은 단계를 거쳐 최적 혹은 좋은 솔루션을 찾기 때문이다.
    • 그림 2-13은 2차원 분류 문제에서 모델의 가중치에 따른 비용 함수의 등고선을 보여준다.

  • 표준화를 적용한 결과는 아래 그림 2-14와 같다.
    • 이 그래프에서 볼 수 있듯이 학습률 \eta = 0.01 을 사용하고 표준화된 특성에서 훈련하니 아달린 모델이 수렴했다.
    • 모든 샘플이 완벽하게 분류되더라도 SSE가 0이 되지는 않는다.
# 표준화
X_std = np.copy(X)
X_std[:,0] = (X[:,0] - X[:,0].mean()) / X[:,0].std()
X_std[:,1] = (X[:,1] - X[:,1].mean()) / X[:,1].std()

ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, y)

plot_decision_regions(X_std, y, classifier=ada)

plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.show()

대규모 머신 러닝과 확률적 경사 하강법

  • 전체 훈련 세트에서 계산한 그래디언트 반대 방향으로 한 걸음씩 진행하여 비용 함수를 최소화 하는 방식을 배치 경사 하강법이라고도 부른다.
    • 수백 만개의 데이터셋이 존재하는 경우 배치 경사 하강법을 사용하면 계산 비용이 매우 많이 든다. 전역 최솟값으로 나아가는 단계마다 매번 전체 훈련 데이터셋을 다시 평가해야 하기 때문이다.
  • 확률적 경사 하강법(stochastic gradient descent)은 배치 경사 하강법의 다른 대안으로 인기가 높다. 이따금 반복 또는 온라인 경사 하강법이라고도 부른다.
    • 다음 첫 번째 수식처럼 모든 샘플 x^{(i)} 에 대하여 누적된 오차의 합을 기반으로 가중치를 업데이트하는 대신 두 번째 수식처럼 각 훈련 샘플에 대해서 조금씩 가중치를 업데이트 한다.

\Delta w = \eta \sum_{i} (y^{(i)} - \phi(z^{(i)})) x^{(i)}

\Delta w = \eta (y^{(i)} - \phi(z^{(i)})) x^{(i)}

  • 확률적 경사 하강법을 경사 하강법의 근사로 생각할 수 있지만 가중치가 더 자주 업데이트 되기 때문에 수렴 속도가 훨씬 빠르다.
    • 그래디언트가 하나의 훈련 샘플을 기반으로 계산되므로 오차의 궤적은 배치 경사 하강법보다 훨씬 어지럽다.
    • 비선형 비용 함수를 다룰 때 얕은 지역 최솟값을 더 쉽게 탈출할 수 있어 장점이 되기도 한다.
    • 확률적 경사 하강법에서 만족스러운 결과를 얻으려면 훈련 샘플 순서를 무작위하게 주입하는 것이 중요하다.
    • 또 순환되지 않도록 에포크마다 훈련 세트를 섞는 것이 좋다.
  • 확률적 경사 하강법의 또 다른 장점은 온라인 학습(online learning)으로 사용할 수 있다는 것이다.
    • 온라인 학습에서 모델은 새로운 훈련 데이터가 도착하는대로 훈련된다. 많은 양의 훈련 데이터가 있을 때도 유용하다.
    • 예컨대 고객 데이터를 처리하는 웹 애플리케이션에서 온라인 학습을 사용해서 시스템은 변화에 즉시 적응할 수 있다.
  • 확률적 경사 하강법으로 소스를 고치면 다음과 같다.
import numpy as np

class AdalineSGD(object):
   """ 적응형 선형 뉴런 분류기
    매개변수
   ----------
   eta : float
       학습률 (0.0과 1.0사이)
    n_iter : int
       훈련 데이터셋 반복 횟수
    random_state : int
        가중치 무작위 초기화를 위한 난수 생성기 시드

    속성
   ---------
   w_ : 1d-array
       학습된 가중치
    errors_ : list
        에포크마다 누적된 분류 오류
    """

    def __init__(self, eta = 0.01, n_iter = 50, shuffle=True, random_state = None):
       self.eta = eta
       self.n_iter = n_iter
       self.w_initialized = False
        self.shuffle = shuffle
        self.random_state= random_state

    def fit(self, X, y):
       """ 훈련 데이터 학습
        매개변수
       ----------
       X : {array-like}, shape = [n_samples, n_features]
            n_samples개의 샘플과 n_features개의 특성으로 이루어진 훈련 데이터
       y : array-like, shape = [n_samples]
           타겟 값       

        반환값
       ---------
        self : object

        """

       self._initialize_weights(X.shape[1])
        self.cost_ = []

       for i in range(self.n_iter):
            if self.shuffle:
               X, y = self._shuffle(X, y)           

            cost = []

           for xi, target in zip(X, y):
                cost.append(self._update_weights(xi, target))

            avg_cost = sum(cost) / len(y)
           self.cost_.append(avg_cost)       

        return self

    def partial_fit(self, X, y):
        """ 가중치를 다시 초기화하지 않고 훈련 데이터를 학습합니다 """
       if not self.w_initialized:
           self.w_initialized_weights(X.shape[1])      

        if y.ravel().shape[0] > 1:
           for xi, target in zip(X, y):
               self._update_weights(xi, target)       
        else:
           self._update_weights(X, y)       

        return self

   def _shuffle(self, X, y):
       """ 훈련 데이터를 섞습니다 """
       r = self.rgen.permutation(len(y))
        return X[r], y[r]

   def _initialize_weights(self, m):
       """ 랜덤한 작은 수로 가중치를 초기화 합니다 """
       self.rgen = np.random.RandomState(self.random_state)
        self.w_ = self.rgen.normal(loc=0.0, scale=0.01, size=1+m)
        self.w_initialized = True

   def _update_weights(self, xi, target):
       """ 아달린 학습 규칙을 적용하여 가중치를 업데이트 합니다 """
        output = self.activation(self.net_input(xi))
        error = (target - output)
       self.w_[1:] += self.eta * xi.dot(error)
        self.w_[0] += self.eta * error
        cost = 0.5 * error ** 2

        return cost

    def net_input(self, X):
       """ 최종 입력 계산 """
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def activation(self, X):
       """ 선형 활성화 계산 """
        return X

   def predict(self, X):
       """ 단위 계단 함수를 사용하여 클래스 레이블을 반환합니다 """
        return np.where(self.net_input(X) >= 0.0, 1, -1)
  • 확률적 경사 하강법을 이용해 분류기를 훈련하고 결과를 그래프로 그리면 아래 그림 2-15와 같다.
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)

plot_decision_regions(X_std, y, classifier=ada)

plt.title('Adaline - Stochastic Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Average Cost')
plt.show()