{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 11wk-1: 추천시스템 (2) – Embedding 레이어, 사용자정의 네트워크,\n", "\n", "NN-based 추천시스템, A1-A2\n", "\n", "최규빈 \n", "2024-05-13\n", "\n", "\n", "\n", "# 1. 강의영상\n", "\n", "\n", "\n", "# 2. Imports" ], "id": "1acbfcb5-3fea-41b1-964e-c59a0cdaeda2" }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [] }, "outputs": [], "source": [ "import torch\n", "import pandas as pd\n", "import matplotlib.pyplot as plt" ], "id": "4dab14d4-fa0a-4be1-a9eb-3f25a4ed1150" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. `torch.nn.Embedding`\n", "\n", "## A. 임베딩레이어\n", "\n", "`-` 모티브: `torch.nn.functional.one_hot` + `torch.nn.Linear` 를 매번\n", "쓰는건 너무 귀찮지 않어?" ], "id": "d48cde5f-12cd-43b6-b1ce-4f55237755a7" }, { "cell_type": "code", "execution_count": 5, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "#x = ['옥순','영숙','하니','옥순','영숙']\n", "x = torch.tensor([0,1,2,0,1])\n", "E = torch.nn.functional.one_hot(x).float()\n", "linr = torch.nn.Linear(3,1,bias=False) \n", "lf = linr(E)\n", "lf" ], "id": "27b3df8e-5758-445d-93df-711714b18602" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 코드를 뜯어보면.." ], "id": "4c464812-5d77-4af7-a8ab-781f1f392cbc" }, { "cell_type": "code", "execution_count": 11, "metadata": { "tags": [] }, "outputs": [], "source": [ "linr.weight" ], "id": "f92bf6f0-bbe0-45ed-9666-6a59fd20e4e7" }, { "cell_type": "code", "execution_count": 13, "metadata": { "tags": [] }, "outputs": [], "source": [ "E @ linr.weight.T" ], "id": "ff51b9a0-5849-4d9a-83cd-87a511bd3c19" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- ${\\boldsymbol x}= \\begin{bmatrix} 0 \\\\ 1 \\\\ 2 \\\\ 0 \\\\ 1 \\end{bmatrix} \\Longrightarrow {\\bf E}= \\begin{bmatrix} 1 & 0 & 0 \\\\ 0 & 1 & 0 \\\\ 0 & 0 & 1 \\\\ 1 & 0 & 0 \\\\ 0 & 1 & 0 \\end{bmatrix}$\n", "\n", "- $\\text{linr}({\\bf E})= \\begin{bmatrix} 1 & 0 & 0 \\\\ 0 & 1 & 0 \\\\ 0 & 0 & 1 \\\\ 1 & 0 & 0 \\\\ 0 & 1 & 0 \\end{bmatrix}\\begin{bmatrix} -0.2002 \\\\ -0.4890 \\\\ 0.2081 \\end{bmatrix} = \\begin{bmatrix} -0.2002 \\\\ -0.4890 \\\\ 0.2081 \\\\ -0.2002 \\\\ -0.4890 \\end{bmatrix}$\n", "\n", "`-` `torch.nn.functional.one_hot` + `torch.nn.Linear` 를 함께처리해주는\n", "레이어 `torch.nn.Embedding` 존재" ], "id": "fbd1c8dc-ba05-4373-a883-4988cec7994e" }, { "cell_type": "code", "execution_count": 20, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "ebdd = torch.nn.Embedding(3,1) \n", "ebdd.weight.data = linr.weight.data.T\n", "ebdd(x)" ], "id": "5e993dff-ace1-46f3-b70c-3e93445bc014" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $\\text{ebdd}({\\boldsymbol x})= \\text{linr}\\big(\\text{onehot}({\\boldsymbol x})\\big) = \\begin{bmatrix} 1 & 0 & 0 \\\\ 0 & 1 & 0 \\\\ 0 & 0 & 1 \\\\ 1 & 0 & 0 \\\\ 0 & 1 & 0 \\end{bmatrix}\\begin{bmatrix} -0.2002 \\\\ -0.4890 \\\\ 0.2081 \\end{bmatrix} = \\begin{bmatrix} -0.2002 \\\\ -0.4890 \\\\ 0.2081 \\\\ -0.2002 \\\\ -0.4890 \\end{bmatrix}$\n", "\n", "- 우리가 이전에 구현했던 코드 “onehot + linr” 와 “ebdd”는 정확하게\n", " 동일한 동작을 수행함.\n", "\n", "`-` 결론: 아래의 두개의 코드는 같다.\n", "\n", "``` python\n", "X = torch.tensor([0,1,2,0,1])\n", "\n", "## 코드1 \n", "linr = torch.nn.Linear(3,1) \n", "linr(torch.nn.functional.one_hot(X))\n", "\n", "## 코드2 \n", "ebdd = torch.nn.Embedding(3,1)\n", "ebdd(X) \n", "```\n", "\n", "`# 의문`: 그냥 원핫인코딩없이 바로 선형변환하면 안되나? (= 꼭\n", "임베딩레이어를 써야하나?)" ], "id": "ad13473b-f2c9-4d68-91dd-c435f024024f" }, { "cell_type": "code", "execution_count": 23, "metadata": { "tags": [] }, "outputs": [], "source": [ "x = torch.tensor([0,1,2,0,1])\n", "X = x.reshape(-1,1).float()\n", "x,X" ], "id": "80425748-2575-4418-9ec1-12c35afa9af3" }, { "cell_type": "code", "execution_count": 25, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "l1 = torch.nn.Linear(1,1)\n", "l1(X)" ], "id": "6f23c789-ea69-4e87-b697-85f7f113dcf5" }, { "cell_type": "code", "execution_count": 26, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "ebdd = torch.nn.Embedding(3,1) \n", "ebdd(x)" ], "id": "d61e3940-a2d7-49a0-841d-acb9a2f542cc" }, { "cell_type": "markdown", "metadata": {}, "source": [ "결과적으로 0,1,2 를 다른숫자들로 맵핑한건 비슷해보이는데?\n", "\n", "`-` 수식의 차이: 비슷해보이지만 계산방식이 조금 다름" ], "id": "ac5c5654-ba26-4d22-a036-8aa4c622829d" }, { "cell_type": "code", "execution_count": 27, "metadata": { "tags": [] }, "outputs": [], "source": [ "l1.weight, l1.bias" ], "id": "e556b75f-55e0-4b56-b551-a60a30b12c9b" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $l_1({\\bf X}) = \\begin{bmatrix} 0 \\\\ 1 \\\\ 2 \\\\ 0 \\\\ 1 \\end{bmatrix} \\times (-0.3467) + (-0.8470)=\\begin{bmatrix} -0.8470 \\\\ -1.1937 \\\\ -1.5404 \\\\ -0.8470 \\\\ -1.1937 \\end{bmatrix}$\n", "\n", "- $\\text{ebdd}({\\boldsymbol x})= \\text{linr}\\big(\\text{onehot}({\\boldsymbol x})\\big) = \\begin{bmatrix} 1 & 0 & 0 \\\\ 0 & 1 & 0 \\\\ 0 & 0 & 1 \\\\ 1 & 0 & 0 \\\\ 0 & 1 & 0 \\end{bmatrix}\\begin{bmatrix} -0.8178 \\\\ -0.7052 \\\\ -0.5843 \\end{bmatrix} = \\begin{bmatrix} -0.8178 \\\\ -0.7052 \\\\ -0.5843 \\\\ -0.8178 \\\\ -0.7052 \\end{bmatrix}$\n", "\n", "`-` 데이터를 읽으며 해석: 사실상 0,1,2에 대한 의미는\n", "“옥순”,“영숙”,“하니” 같은 자료였고, 임베딩의 결과는\n", "“옥순”,“영숙”,“하니”가 가지는 어떠한 특징이었음 (예를들면 매력같은).\n", "데이터를 상상하며 위의 결과를 다시 해석해보자.\n", "\n", "**옥순이 가지는 어떠한 특징 (-0.8470 혹은 -0.8178) 을 바꾸고 싶다면?**\n", "\n", "- `ebdd`의 경우: `ebdd.weigth`에 있는 -0.8178 이라는 숫자를 조정하면\n", " 된다. 이 조정은 옥순의 특징만 바꾸며 영숙과 하니의 특징은 바꾸지\n", " 않는다. (개별조정이 쉬움)\n", "- `linr`의 경우: `linr.weight`에 있는 -0.3467 혹은 `linr.bias`에 있는\n", " -0.8470 을 조정하면 되는데, 이를 조정하면 옥순의 특징을 바꿈과\n", " 동시에 영숙/하니의 특징까지 같이 바뀌게 된다. (개별조정이 어려움)\n", "\n", "**만약에 출연자가 1000명이라면??**\n", "\n", "- `linr`의 경우: 1000명의 특징을 단 2개의 파라메터로 조정해야한다.\n", " (그리고 한명의 특징을 바꾸면 999명의 특징이 같이 바뀐다, 개별조정은\n", " 애초에 가능하지 않음.)\n", "- `ebdd`의 경우: 1000개의 특징을 조정할 수 있는 1000개의 파라메터를\n", " 확보할 수 있게 된다.\n", "\n", "`-` 결론: ebdd가 더 파라메터 미세조정을 통하여 특징을 학습하기 용이하다.\n", "(독립적으로 특징값을 줄 수 있으니까!)\n", "\n", "> 만약에 문자열이 “최우수(A)”, “우수(B)”, “보통(C)”, “미흡(D)”,\n", "> “매우미흡(F)” 이었다면 특징을 뽑아낼때 linr 가 더 적절했겠죠?\n", "\n", "## B. MF-based 추천시스템 재설계\n", "\n", "아래의 자료를 활용하여 추천시스템을 설계하고자한다." ], "id": "c8b65b87-eb5f-4792-b41b-b9fc8139bcdd" }, { "cell_type": "code", "execution_count": 115, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_view = pd.read_csv('https://raw.githubusercontent.com/guebin/DL2024/main/posts/solo.csv',index_col=0)\n", "df_view" ], "id": "32312f78-6890-4878-b22c-372df4797dd7" }, { "cell_type": "code", "execution_count": 116, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_train = df_view.stack().reset_index().set_axis(['W','M','y'],axis=1)\n", "w = {'옥순(IN)':0, '영자(IN)':1, '정숙(IS)':2, '영숙(IS)':3, '순자(EN)':4, '현숙(EN)':5, '서연(ES)':6, '보람(ES)':7, '하니(I)':8}\n", "m = {'영식(IN)':0, '영철(IN)':1, '영호(IS)':2, '광수(IS)':3, '상철(EN)':4, '영수(EN)':5, '규빈(ES)':6, '다호(ES)':7}\n", "X1 = torch.tensor(df_train['W'].map(w)) # length-n int vector \n", "X2 = torch.tensor(df_train['M'].map(m)) # length-n int vector \n", "y = torch.tensor(df_train['y']).float().reshape(-1,1) # (n,1) float vector" ], "id": "1a5017f3-f863-483a-a894-c63f960aa739" }, { "cell_type": "markdown", "metadata": {}, "source": [ "임베딩레이어를 활용하여 MF-based 추천시스템을 설계하라.\n", "\n", "(풀이)" ], "id": "35ccbe21-d4ae-4df4-9cc8-ad2967b6aee3" }, { "cell_type": "code", "execution_count": 30, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "ebdd1 = torch.nn.Embedding(9,2)\n", "b1 = torch.nn.Embedding(9,1)\n", "ebdd2 = torch.nn.Embedding(8,2)\n", "b2 = torch.nn.Embedding(8,1)\n", "sig = torch.nn.Sigmoid()\n", "loss_fn = torch.nn.MSELoss()\n", "params = list(ebdd1.parameters())+list(b1.parameters())+list(ebdd2.parameters())+list(b2.parameters()) \n", "optimizr = torch.optim.Adam(params, lr=0.1) \n", "#--#\n", "for epoc in range(100):\n", " # 1\n", " W_feature = ebdd1(X1)\n", " W_bias = b1(X1)\n", " M_feature = ebdd2(X2)\n", " M_bias = b2(X2)\n", " score = (W_feature * M_feature).sum(axis=1).reshape(-1,1) + W_bias + M_bias\n", " yhat = sig(score)*5 \n", " # 2 \n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "14cc7f8f-0075-41f5-9365-23d9ccce6443" }, { "cell_type": "code", "execution_count": 32, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.concat([yhat,y],axis=1)[::4]" ], "id": "a1df7f97-f3b1-4e55-aaf2-9485c11f0f32" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. 사용자정의 네트워크\n", "\n", "## A. 사용자정의 네트워크 사용법\n", "\n", "`# 예비학습1`: `net(x)`와 사실 `net.forward(x)`는 같다." ], "id": "888786f4-b7d8-44a6-a719-3af8670f70f5" }, { "cell_type": "code", "execution_count": 33, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = torch.nn.Sequential(\n", " torch.nn.Linear(1,1),\n", " torch.nn.Sigmoid()\n", ")" ], "id": "dd1a7b1c-38e3-4d6e-bbc4-718f59683558" }, { "cell_type": "code", "execution_count": 34, "metadata": { "tags": [] }, "outputs": [], "source": [ "X = torch.randn(5,1)\n", "X" ], "id": "5f9803b2-90bc-4a61-88df-3808d8e71ec3" }, { "cell_type": "code", "execution_count": 35, "metadata": { "tags": [] }, "outputs": [], "source": [ "net(X)" ], "id": "593af51e-60a3-4f62-a92a-483b90dfedd5" }, { "cell_type": "code", "execution_count": 36, "metadata": { "tags": [] }, "outputs": [], "source": [ "net.forward(X)" ], "id": "453cc4cb-f63a-4e35-8b79-0fdc23471a0a" }, { "cell_type": "markdown", "metadata": {}, "source": [ "그래서 `net.forward`를 재정의하면 `net(x)`의 기능을 재정의 할 수 있다." ], "id": "144a71e6-17e4-4ffd-a0d0-7cf323c3eb8e" }, { "cell_type": "code", "execution_count": 38, "metadata": { "tags": [] }, "outputs": [], "source": [ "net.forward = lambda x: '메롱'" ], "id": "d3e7a61c-ee75-4aec-97c7-4752297a7ca9" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `lambda x: '메롱'` 은 입력이 x 출력이 ’메롱’인 함수를 의미 (즉\n", " 입력값에 상관없이 항상 ’메롱’을 출력하는 함수)\n", "- `net.forward = lambda x:1` 이라고 새롭게 선언하였므로 앞으론\n", " `net.forward(x)`, `net(x)` 도 입력값에 상관없이 항상 ’메롱’을\n", " 출력하게 될것임" ], "id": "8da0f856-f6e0-4044-9e2e-ce552b1829ad" }, { "cell_type": "code", "execution_count": 39, "metadata": { "tags": [] }, "outputs": [], "source": [ "net.forward(X)" ], "id": "da78a850-7eac-446f-ad53-760939555332" }, { "cell_type": "code", "execution_count": 41, "metadata": { "tags": [] }, "outputs": [], "source": [ "net(X)" ], "id": "f5e60aa4-0ddb-4cbb-9cc5-25f5ddd1d1d9" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`#`\n", "\n", "`# 예비학습2`: `torch.nn.Module`을 상속받아서 네트워크를 만들면 (=\n", "“`class XXX(torch.nn.Module):`” 와 같은 방식으로 클래스를 선언하면)\n", "약속된 아키텍처를 가진 네트워크를 찍어내는 함수를 만들 수 있다.\n", "\n", "(예시1)" ], "id": "342dc283-4f52-4cbb-b67f-6d093dc52f99" }, { "cell_type": "code", "execution_count": 44, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Mynet1(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.l1 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " self.a1 = torch.nn.Sigmoid()\n", " self.l2 = torch.nn.Linear(in_features=1,out_features=1,bias=False)\n", " def forward(self,x):\n", " yhat = self.l2(self.a1(self.l1(x)))\n", " return yhat" ], "id": "982c2476-cedc-4719-9564-81cfbcacb7d1" }, { "cell_type": "markdown", "metadata": {}, "source": [ "이제\n", "\n", "``` python\n", "net = Mynet1()\n", "```\n", "\n", "는 아래와 같은 효과를 가진다.\n", "\n", "``` python\n", "net = torch.nn.Sequential(\n", " torch.nn.Linear(in_features=1,out_features=1,bias=True),\n", " torch.nn.Sigmoid(),\n", " torch.nn.Linear(in_features=1,out_features=1,bias=False)\n", ")\n", "```\n", "\n", "(예시2)" ], "id": "1e3dfa44-a8db-477f-b00b-4993b3782b9d" }, { "cell_type": "code", "execution_count": 45, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Mynet2(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.l1 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " self.a1 = torch.nn.ReLU()\n", " self.l2 = torch.nn.Linear(in_features=1,out_features=1,bias=False)\n", " def forward(self,x):\n", " yhat = self.l2(self.a1(self.l1(x)))\n", " return yhat" ], "id": "f7e575f5-5738-4dac-a2a8-1e1c9b63eab0" }, { "cell_type": "markdown", "metadata": {}, "source": [ "이제\n", "\n", "``` python\n", "net = Mynet2()\n", "```\n", "\n", "는 아래와 같은 효과를 가진다.\n", "\n", "``` python\n", "net = torch.nn.Sequential(\n", " torch.nn.Linear(in_features=1,out_features=1,bias=True),\n", " torch.nn.RuLU(),\n", " torch.nn.Linear(in_features=1,out_features=1,bias=False)\n", ")\n", "```\n", "\n", "***클래스에 대한 이해가 부족한 학생을 위한 암기방법***\n", "\n", "**step1:** 아래와 코드를 복사하여 틀을 만든다. (이건 무조건 고정임, XXXX\n", "자리는 원하는 이름을 넣는다)\n", "\n", "``` python\n", "class XXXX(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " ## 우리가 yhat을 구할때 사용할 레이어를 정의 \n", " \n", " ## 정의 끝\n", " def forward(self,X):\n", " ## yhat을 어떻게 구할것인지 정의 \n", " \n", " ## 정의 끝\n", " return yhat\n", "```\n", "\n", "- `forward`의 입력: `X`는 `net(X)`에 사용하는 `X`임\n", "- `forward`의 출력: `yhat`은 `net.forward(X)` 함수의 리턴값임\n", "- 사실, `X`/`yhat`은 다른 변수로 써도 무방하나 (예를들면\n", " `input`/`output` 이라든지, `netin`/`netout` 이라든지) 설명의 편의상\n", " `X`와 `yhat`을 고정한다.\n", "\n", "**step2:** `def __init__(self):`에 yhat을 구하기 위해 필요한 재료를\n", "레이어를 정의하고 이름을 붙인다. 이름은 항상 `self.xxx` 와 같은 식으로\n", "정의한다.\n", "\n", "``` python\n", "class XXXX(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " ## 우리가 yhat을 구할때 사용할 레이어를 정의 \n", " self.xxx1 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " self.xxx2 = torch.nn.Sigmoid()\n", " self.xxx3 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " ## 정의 끝\n", " def forward(self,X):\n", " ## yhat을 어떻게 구할것인지 정의 \n", " \n", " ## 정의 끝\n", " return yhat\n", "```\n", "\n", "**step3:** `def forward:`에 “X –\\> yhat” 으로 가는 과정을 묘사한 코드를\n", "작성하고 yhat을 리턴하도록 한다.\n", "\n", "``` python\n", "class XXXX(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " ## 우리가 yhat을 구할때 사용할 레이어를 정의 \n", " self.xxx1 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " self.xxx2 = torch.nn.Sigmoid()\n", " self.xxx3 = torch.nn.Linear(in_features=1,out_features=1,bias=True)\n", " ## 정의 끝\n", " def forward(self,X):\n", " ## yhat을 어떻게 구할것인지 정의 \n", " u = self.xxx1(X) \n", " v = self.xxx2(u)\n", " yhat = self.xxx3(v) \n", " ## 정의 끝\n", " return yhat\n", "```\n", "\n", "`#`\n", "\n", "`# 실습`: 사용자정의 네트워크를 사용하여 아래의 자료를 학습해보자." ], "id": "d4e2a953-8867-4358-ab28-3447772401a8" }, { "cell_type": "code", "execution_count": 46, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "x,_ = torch.randn(100).sort()\n", "x = x.reshape(-1,1)\n", "ϵ = torch.randn(100).reshape(-1,1)*0.5\n", "y = 2.5+ 4*x + ϵ" ], "id": "1c4cdc0a-f1b7-42c3-9035-f071ca50b756" }, { "cell_type": "code", "execution_count": 47, "metadata": { "tags": [] }, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "image/png": "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\n3pwNAAAAAElFTkSuQmCC\n" } } ], "source": [ "plt.plot(x,y,'o')" ], "id": "915f53b7-86c9-4a07-9862-d6dd5520c647" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(풀이)" ], "id": "e208dce2-e4e2-4935-a95f-9edd0158b750" }, { "cell_type": "code", "execution_count": 48, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Net(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " ## 우리가 yhat을 구할때 사용할 레어어를 정의\n", " self.linr = torch.nn.Linear(1,1)\n", " ## 정의 끝\n", " def forward(self,X):\n", " ## yhat을 어떻게 구할것인지 정의 \n", " yhat = self.linr(X)\n", " ## 정의 끝\n", " return yhat" ], "id": "363609bd-a671-4df9-b043-2b3b439f809f" }, { "cell_type": "code", "execution_count": 49, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = Net()" ], "id": "59a9a864-5f30-44eb-98ff-a45b1e498965" }, { "cell_type": "code", "execution_count": 50, "metadata": { "tags": [] }, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "image/png": "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\n" } } ], "source": [ "plt.plot(x,y,'o')\n", "plt.plot(x,net(x).data,'--') # 최초의 직선" ], "id": "5240d6c3-183c-4496-bec1-44403a1ae6fb" }, { "cell_type": "code", "execution_count": 51, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = Net()\n", "loss_fn = torch.nn.MSELoss()\n", "optimizr = torch.optim.SGD(net.parameters(),lr=0.1)\n", "for epoc in range(30):\n", " # 1\n", " yhat = net(x)\n", " # 2 \n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "f716d2d3-d17d-49df-bce0-bfa77c220043" }, { "cell_type": "code", "execution_count": 52, "metadata": { "tags": [] }, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "image/png": "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\nlsSs8TmqIyIiItLGYq6gWW52OqOy7KqsKiIiEgFiLoiAe5hmaL+u4W6GiIhIzIupoRkRERGJLAoi\nIiIiEjYKIiIiIhI2CiIiIiISNgoiIiIiEjYKIiIiIhI2CiIiIiISNgoiIiIiEjYKIiIiIhI2EV1Z\n1TRNAEpLS8PcEhEREQmU53vb8z3uT0QHkbKyMgAyMjLC3BIREREJVllZGTabze81hhlIXAkTl8vF\n9u3bSUlJwTBic1O60tJSMjIy2LZtG6mpqeFuTtTR7zd09LsNLf1+Q0u/35YxTZOysjJ69uyJxeJ/\nFkhE94hYLBZ69eoV7mZEhNTUVP3HEEL6/YaOfrehpd9vaOn323xN9YR4aLKqiIiIhI2CiIiIiISN\ngkiES0xMZNq0aSQmJoa7KVFJv9/Q0e82tPT7DS39fttORE9WFRERkeimHhEREREJGwURERERCRsF\nEREREQkbBREREREJGwWRdmLLli1cffXVZGZm0qFDB/r168e0adOoqqoKd9OixgMPPMCwYcPo2LEj\nnTt3Dndz2r2ZM2eSmZlJUlISAwcO5NNPPw13k6LCsmXLGDt2LD179sQwDN56661wNylqTJ8+neOP\nP56UlBS6d+/Oeeedx7fffhvuZkU9BZF24ptvvsHlcjFnzhy+/vprnnjiCWbPns1dd90V7qZFjaqq\nKi688EImTZoU7qa0e6+++iq33HILd999N59//jknnXQSY8aMYevWreFuWrtXXl7OMcccw4wZM8Ld\nlKizdOlSbrjhBlavXs3ixYupqalh9OjRlJeXh7tpUU3Ld9uxRx99lFmzZvH999+HuylR5cUXX+SW\nW25hz5494W5Ku3XCCSeQk5PDrFmzas8deeSRnHfeeUyfPj2MLYsuhmHw5ptvct5554W7KVFp586d\ndO/enaVLl3LyySeHuzlRSz0i7ZjD4SAtLS3czRCpp6qqis8++4zRo0fXOz969GhWrlwZplaJBM/h\ncADo79kQUxBppzZv3sxTTz3FxIkTw90UkXp27dqF0+mkR48e9c736NGD4uLiMLVKJDimaTJ58mRO\nPPFEsrOzw92cqKYgEmb33nsvhmH4/fm///u/evds376d3NxcLrzwQq655powtbx9aM7vV1qHYRj1\njk3TbHROJFLdeOONfPnll8ybNy/cTYl6ceFuQKy78cYbufjii/1e07dv39o/b9++nREjRjB06FCe\neeaZELeu/Qv29yst161bN6xWa6Pejx07djTqJRGJRDfddBPz589n2bJl9OrVK9zNiXoKImHWrVs3\nunXrFtC1P/30EyNGjGDgwIG88MILWCzq0GpKML9faR0JCQkMHDiQxYsXM27cuNrzixcv5txzzw1j\ny0T8M02Tm266iTfffJNPPvmEzMzMcDcpJiiItBPbt2/n1FNPpXfv3jz22GPs3Lmz9jO73R7GlkWP\nrVu3UlJSwtatW3E6naxbtw6AQw89lE6dOoW3ce3M5MmTufzyyxk0aFBt793WrVs1p6kV7N27l02b\nNtUeFxYWsm7dOtLS0ujdu3cYW9b+3XDDDbz88su8/fbbpKSk1Pbq2Ww2OnToEObWRTFT2oUXXnjB\nBLz+SOu44oorvP5+P/7443A3rV16+umnzT59+pgJCQlmTk6OuXTp0nA3KSp8/PHHXv89veKKK8Ld\ntHbP19+xL7zwQribFtVUR0RERETCRpMMREREJGwURERERCRsFEREREQkbBREREREJGwURERERCRs\nFEREREQkbBREREREJGwURERERCRsFEREREQkbBREREREJGwURERERCRsFEREREQkbP4fLQo2JJ96\nLWAAAAAASUVORK5CYII=\n" } } ], "source": [ "plt.plot(x,y,'o')\n", "plt.plot(x,net(x).data,'--')" ], "id": "bf3b1d7c-4536-4fbe-a43a-6a715778f45f" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`#`\n", "\n", "## B. MF-based 추천시스템 재설계\n", "\n", "아래의 자료를 활용하여 추천시스템을 설계하고자한다." ], "id": "d43150c0-8268-40b6-b038-7078b985ccad" }, { "cell_type": "code", "execution_count": 84, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_view = pd.read_csv('https://raw.githubusercontent.com/guebin/DL2024/main/posts/solo.csv',index_col=0)\n", "df_view" ], "id": "23143b68-f0fb-4392-84c3-51c18749603e" }, { "cell_type": "code", "execution_count": 85, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_train = df_view.stack().reset_index().set_axis(['W','M','y'],axis=1)\n", "w = {'옥순(IN)':0, '영자(IN)':1, '정숙(IS)':2, '영숙(IS)':3, '순자(EN)':4, '현숙(EN)':5, '서연(ES)':6, '보람(ES)':7, '하니(I)':8}\n", "m = {'영식(IN)':0, '영철(IN)':1, '영호(IS)':2, '광수(IS)':3, '상철(EN)':4, '영수(EN)':5, '규빈(ES)':6, '다호(ES)':7}\n", "X1 = torch.tensor(df_train['W'].map(w)) # length-n int vector \n", "X2 = torch.tensor(df_train['M'].map(m)) # length-n int vector \n", "y = torch.tensor(df_train['y']).float().reshape(-1,1) # (n,1) float vector" ], "id": "c8453f26-93a6-4b60-9ed5-73cdf85a01d1" }, { "cell_type": "markdown", "metadata": {}, "source": [ "사용자정의 네트워크를 이용하여 MF-based 추천시스템을 설계하라.\n", "\n", "(풀이1) – `net(X1,X2)`" ], "id": "9797a3b8-2dc4-4174-8532-16b86f159fd3" }, { "cell_type": "code", "execution_count": 86, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Net(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " #--#\n", " self.ebdd1 = torch.nn.Embedding(9,2)\n", " self.ebdd2 = torch.nn.Embedding(8,2)\n", " self.b1 = torch.nn.Embedding(9,1)\n", " self.b2 = torch.nn.Embedding(8,1)\n", " self.sig = torch.nn.Sigmoid()\n", " def forward(self,X1,X2):\n", " W_feature = self.ebdd1(X1)\n", " W_bias = self.b1(X1)\n", " M_feature = self.ebdd2(X2)\n", " M_bias = self.b2(X2)\n", " score = (W_feature * M_feature).sum(axis=1).reshape(-1,1) + W_bias + M_bias \n", " yhat = sig(score) * 5 \n", " return yhat" ], "id": "38c3ae91-f198-418f-9fd3-a81fb754d8fc" }, { "cell_type": "code", "execution_count": 87, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = Net()\n", "loss_fn = torch.nn.MSELoss()\n", "optimizr = torch.optim.Adam(net.parameters(),lr=0.1) # 이게 편해요!!\n", "#--# \n", "for epoc in range(100):\n", " # 1\n", " yhat = net(X1,X2) \n", " # 2\n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "f4a763d2-4645-432e-807f-96ee1d44cc9a" }, { "cell_type": "code", "execution_count": 88, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.concat([yhat.data,y],axis=1)[::5]" ], "id": "13574fdd-37d1-42cb-8623-cf7c2da1df1c" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(풀이2) – `net(X)`" ], "id": "5167a888-9e99-47c1-baa2-8dd2d5402725" }, { "cell_type": "code", "execution_count": 89, "metadata": { "tags": [] }, "outputs": [], "source": [ "X = torch.stack([X1,X2],axis=1)\n", "X[:5]" ], "id": "a1d5df19-0796-446e-a285-9df9a336f12c" }, { "cell_type": "code", "execution_count": 90, "metadata": { "tags": [] }, "outputs": [], "source": [ "X[:,0], X[:,1]" ], "id": "030d6434-a850-4a63-86f7-33c43dfe6016" }, { "cell_type": "code", "execution_count": 91, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Net(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " #--#\n", " self.ebdd1 = torch.nn.Embedding(9,2)\n", " self.ebdd2 = torch.nn.Embedding(8,2)\n", " self.b1 = torch.nn.Embedding(9,1)\n", " self.b2 = torch.nn.Embedding(8,1)\n", " self.sig = torch.nn.Sigmoid()\n", " def forward(self,X):\n", " X1,X2 = X[:,0],X[:,1]\n", " W_feature = self.ebdd1(X1)\n", " W_bias = self.b1(X1)\n", " M_feature = self.ebdd2(X2)\n", " M_bias = self.b2(X2)\n", " score = (W_feature * M_feature).sum(axis=1).reshape(-1,1) + W_bias + M_bias \n", " yhat = sig(score) * 5 \n", " return yhat" ], "id": "74dbc47f-1236-4030-b6f9-44814dee2696" }, { "cell_type": "code", "execution_count": 92, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = Net()\n", "loss_fn = torch.nn.MSELoss()\n", "optimizr = torch.optim.Adam(net.parameters(),lr=0.1) # 이게 편해요!!\n", "#--# \n", "for epoc in range(100):\n", " # 1\n", " yhat = net(X) \n", " # 2\n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "0ecbec60-fc8a-433c-a6ce-3ba5a5b64d79" }, { "cell_type": "code", "execution_count": 93, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.concat([yhat.data,y],axis=1)[::5]" ], "id": "5527bfd7-36de-48bd-9258-c33f01547d50" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 5. NN-based 추천시스템\n", "\n", "## A. NN-based 방식\n", "\n", "아래의 자료를 활용하여 추천시스템을 설계하고자한다." ], "id": "30beeb2f-4396-4634-a23e-85b1432cfa36" }, { "cell_type": "code", "execution_count": 2, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_view = pd.read_csv('https://raw.githubusercontent.com/guebin/DL2024/main/posts/solo.csv',index_col=0)\n", "df_view" ], "id": "1351ee6f-0b65-4f43-94d2-00afabfc4601" }, { "cell_type": "code", "execution_count": 3, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_train = df_view.stack().reset_index().set_axis(['W','M','y'],axis=1)\n", "w = {'옥순(IN)':0, '영자(IN)':1, '정숙(IS)':2, '영숙(IS)':3, '순자(EN)':4, '현숙(EN)':5, '서연(ES)':6, '보람(ES)':7, '하니(I)':8}\n", "m = {'영식(IN)':0, '영철(IN)':1, '영호(IS)':2, '광수(IS)':3, '상철(EN)':4, '영수(EN)':5, '규빈(ES)':6, '다호(ES)':7}\n", "X1 = torch.tensor(df_train['W'].map(w)) # length-n int vector \n", "X2 = torch.tensor(df_train['M'].map(m)) # length-n int vector \n", "y = torch.tensor(df_train['y']).float().reshape(-1,1) # (n,1) float vector" ], "id": "2d522a56-bcf5-45f0-8c10-342e14a7002f" }, { "cell_type": "markdown", "metadata": {}, "source": [ "NN-based 추천시스템을 설계하라.\n", "\n", "(풀이1) – 실패" ], "id": "1610c9f1-acbc-4a63-90dc-f4f30b202d75" }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Net(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " #--#\n", " self.ebdd1 = torch.nn.Embedding(9,2)\n", " self.ebdd2 = torch.nn.Embedding(8,2)\n", " self.b1 = torch.nn.Embedding(9,1)\n", " self.b2 = torch.nn.Embedding(8,1)\n", " self.mlp = torch.nn.Sequential(\n", " torch.nn.Linear(6,1),\n", " torch.nn.Sigmoid()\n", " ) \n", " def forward(self,X1,X2):\n", " W_feature = self.ebdd1(X1)\n", " M_feature = self.ebdd2(X2)\n", " W_bias = self.b1(X1)\n", " M_bias = self.b2(X2)\n", " Z = torch.concat([W_feature,M_feature,W_bias,M_bias],axis=1)\n", " yhat = self.mlp(Z) * 5 \n", " return yhat" ], "id": "7103a280-dcc4-4d00-950e-fcac841f4312" }, { "cell_type": "code", "execution_count": 9, "metadata": { "tags": [] }, "outputs": [], "source": [ "net = Net()\n", "loss_fn = torch.nn.MSELoss()\n", "optimizr = torch.optim.Adam(net.parameters(),lr=0.1) # 이게 편해요!!\n", "#--# \n", "for epoc in range(1000):\n", " # 1\n", " yhat = net(X1,X2) \n", " # 2\n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "db750148-e75a-49da-885a-73c1ecf1ea34" }, { "cell_type": "code", "execution_count": 10, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.concat([yhat.data,y],axis=1)[::5]" ], "id": "b3361aa2-94cc-4367-87ab-3564afea76a4" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 못하겠네?\n", "\n", "(풀이2) – 에라 모르겠다 깊은신경망.." ], "id": "1c500b18-6280-45a2-86b6-f58676254768" }, { "cell_type": "code", "execution_count": 11, "metadata": { "tags": [] }, "outputs": [], "source": [ "class Net(torch.nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " #--#\n", " self.ebdd1 = torch.nn.Embedding(9,2)\n", " self.ebdd2 = torch.nn.Embedding(8,2)\n", " self.b1 = torch.nn.Embedding(9,1)\n", " self.b2 = torch.nn.Embedding(8,1)\n", " self.mlp = torch.nn.Sequential(\n", " torch.nn.Linear(6,15),\n", " torch.nn.ReLU(),\n", " torch.nn.Linear(15,15),\n", " torch.nn.ReLU(),\n", " torch.nn.Linear(15,1),\n", " torch.nn.Sigmoid()\n", " ) \n", " def forward(self,X1,X2):\n", " W_feature = self.ebdd1(X1)\n", " M_feature = self.ebdd2(X2)\n", " W_bias = self.b1(X1)\n", " M_bias = self.b2(X2)\n", " Z = torch.concat([W_feature,M_feature,W_bias,M_bias],axis=1)\n", " yhat = self.mlp(Z) * 5 \n", " return yhat" ], "id": "eb7b4c62-25c9-43b5-9c23-81023c731113" }, { "cell_type": "code", "execution_count": 12, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.manual_seed(43052)\n", "net = Net()\n", "loss_fn = torch.nn.MSELoss()\n", "optimizr = torch.optim.Adam(net.parameters(),lr=0.1) # 이게 편해요!!\n", "#--# \n", "for epoc in range(1000):\n", " # 1\n", " yhat = net(X1,X2) \n", " # 2\n", " loss = loss_fn(yhat,y)\n", " # 3 \n", " loss.backward()\n", " # 4 \n", " optimizr.step()\n", " optimizr.zero_grad()" ], "id": "920d811c-844a-4e91-855a-ae8886407c7b" }, { "cell_type": "code", "execution_count": 13, "metadata": { "tags": [] }, "outputs": [], "source": [ "torch.concat([yhat.data,y],axis=1)[::5]" ], "id": "594c1a90-9ec1-47c6-ab15-fd8f6b050caf" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 잘 맞추긴했는데 불안함" ], "id": "24b69df2-807c-421d-be71-38126a340596" }, { "cell_type": "code", "execution_count": 16, "metadata": { "tags": [] }, "outputs": [], "source": [ "df_view" ], "id": "1f0b7bb1-f025-4b90-8fb6-49070ed70cc6" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(옥순-영식), (영자-다호), (하니-영호) 를 예측해보자." ], "id": "3cfb6d50-9a2d-4b0f-8e90-9841e6e1e4d7" }, { "cell_type": "code", "execution_count": 19, "metadata": { "tags": [] }, "outputs": [], "source": [ "XX1 = torch.tensor([0,1,8])\n", "XX2 = torch.tensor([1,7,2])" ], "id": "bb83cd8a-6911-4b4d-a491-ac1f0dbceeba" }, { "cell_type": "code", "execution_count": 20, "metadata": { "tags": [] }, "outputs": [], "source": [ "net(XX1,XX2)" ], "id": "9e2ca08f-479d-4b43-91ce-eb1b0f8b47dd" }, { "cell_type": "markdown", "metadata": {}, "source": [ "그럴싸함.. (오버피팅 아닌듯)\n", "\n", "## B. NCF (He et al. 2017)\n", "\n", "![](https://github.com/guebin/DL2024/blob/main/posts/NCF.png?raw=true)\n", "\n", "# A1. 자잘한 용어 정리 ($\\star$)\n", "\n", "## A. 지도학습\n", "\n", "`-` 우리가 수업에서 다루는 데이터는 주로 아래와 같은 느낌이다.\n", "\n", "1. 데이터는 $(X,y)$의 형태로 정리되어 있다.\n", "\n", "2. $y$는 우리가 관심이 있는 변수이다. 즉 우리는 $y$를 적절하게 추정하는\n", " 것에 관심이 있다.\n", "\n", "3. $X$는 $y$를 추정하기 위해 필요한 정보이다.\n", "\n", "| $X$ = 설명변수 = 독립변수 | $y$ = 반응변수 = 종속변수 | 비고 | 순서 | 예시 |\n", "|:-------------:|:-------------:|:-------------:|:-------------:|:-------------:|\n", "| 이미지 | 카테고리 | 합성곱신경망 | 상관없음 | 개/고양이 이미지 구분 |\n", "| 유저,아이템 | 평점 | 추천시스템 | 상관없음 | 넷플릭스 영화추천 |\n", "| 과거~오늘까지의주가 | 내일주가 | 순환신경망 | 순서상관있음 | 주가예측 |\n", "| 처음 $m$개의 단어(혹은 문장) | 이후 1개의 단어(혹은 문장) | 순환신경망 | 순서상관있음 | 챗봇, 텍스트생성 |\n", "| 처음 $m$개의 단어(혹은 문장) | 카테고리 | 순환신경망 | 순서상관있음 | 영화리뷰 텍스트 감정분류 |\n", "\n", "`-` 이러한 문제상황, 즉 $(X,y)$가 주어졌을때 $X \\to y$를 추정하는 문제를\n", "supervised learning 이라한다.\n", "\n", "## B. 모델이란?\n", "\n", "> 모델이란 단어는 제 발작버튼이었어요..\n", "\n", "`-` 통계학에서 모델은 y와 x의 관계를 의미하며 오차항의 설계를 포함하는\n", "개념이다. 이는 통계학이 “데이터 = 정보 + 오차”의 관점을 유지하기\n", "때문이다. 따라서 통계학에서 모델링이란\n", "\n", "$$y_i = net(x_i) + \\epsilon_i$$\n", "\n", "에서 (1) 적절한 함수 $net$를 선택하는 일 (2) 적절한 오차항 $\\epsilon_i$\n", "을 설계하는일 모두를 포함한다.\n", "\n", "`-` 딥러닝 혹은 머신러닝에서 모델은 단순히\n", "\n", "$$y_i \\approx net(x_i)$$\n", "\n", "를 의미하는 경우가 많다. 즉 “model=net”라고 생각해도 무방하다. 이 경우\n", "“모델링”이란 단순히 적절한 $net$을 설계하는 것만을 의미할 경우가 많다.\n", "\n", "`-` 그래서 생긴일\n", "\n", "- 통계학교재 특: 분류문제와 회귀문제를 엄밀하게 구분하지 않는다. 사실\n", " 오차항만 다를뿐이지 크게보면 같은 회귀모형이라는 관점이다. 그래서\n", " 일반화선형모형(GLM)이라는 용어를 쓴다.\n", "- 머신러닝/딥러닝교재 특: 회귀문제와 분류문제를 구분해서 설명한다.\n", " (표도 만듦) 이는 오차항에 대한 기술을 모호하게 하여 생기는 현상이다.\n", "\n", "## C. 학습이란?\n", "\n", "`-` 학습이란 주어진 자료 $(X,y)$를 잘 분석하여 $X$에서 $y$로 가는 어떠한\n", "“규칙” 혹은 “원리”를 찾는 것이다.\n", "\n", "- 학습이란 주어진 자료 $(X,y)$를 잘 분석하여 $X$에서 $y$로 가는 어떠한\n", " “맵핑”을 찾는 것이다.\n", "- 학습이란 주어진 자료 $(X,y)$를 잘 분석하여 $X$에서 $y$로 가는 어떠한\n", " “함수”을 찾는 것이다. 즉 $y\\approx f(X)$가 되도록 만드는 $f$를 잘\n", " 찾는 것이다. (이 경우 “함수를 추정한다”라고 표현)\n", "- 학습이란 주어진 자료 $(X,y)$를 잘 분석하여 $X$에서 $y$로 가는 어떠한\n", " “모델” 혹은 “모형”을 찾는 것이다. 즉 $y\\approx model(X)$가 되도록\n", " 만드는 $model$을 잘 찾는 것이다. (이 경우 “모형을 학습시킨다”라고\n", " 표현)\n", "- **학습이란 주어진 자료 $(X,y)$를 잘 분석하여 $X$에서 $y$로 가는\n", " 어떠한 “네트워크”을 찾는 것이다. 즉 $y\\approx net(X)$가 되도록\n", " 만드는 $net$을 잘 찾는 것이다. (이 경우 “네트워크를 학습시킨다”라고\n", " 표현)**\n", "\n", "`-` prediction이란 학습과정에서 찾은 “규칙” 혹은 “원리”를 $X$에 적용하여\n", "$\\hat{y}$을 구하는 과정이다. 학습과정에서 찾은 규칙 혹은 원리는\n", "$f$,$model$,$net$ 으로 생각가능한데 이에 따르면 아래가 성립한다.\n", "\n", "- $\\hat{y} = f(X)$\n", "- $\\hat{y} = model(X)$\n", "- $\\hat{y} = net(X)$\n", "\n", "## D. $\\hat{y}$를 부르는 다양한 이름\n", "\n", "`-` $\\hat{y}$는 $X$가 주어진 자료에 있는 값인지 아니면 새로운 값 인지에\n", "따라 지칭하는 이름이 미묘하게 다르다.\n", "\n", "1. $X \\in data$: $\\hat{y}=net(X)$ 는 predicted value, fitted value 라고\n", " 부른다.\n", "\n", "2. $X \\notin data$: $\\hat{y}=net(X)$ 는 predicted value, predicted\n", " value with new data 라고 부른다.\n", "\n", "## E. 다양한 코드들\n", "\n", "`-` 파이썬 코드..\n", "\n", "``` python\n", "#Python\n", "predictor.fit(X,y) # autogluon 에서 \"학습\"을 의미하는 과정\n", "model.fit(X,y) # sklearn 에서 \"학습\"을 의미하는 과정\n", "learner.learn() # fastai 에서 \"학습\"을 의미하는 과정\n", "learner.fine_tune(1) # fastai 에서 \"부분학습\"을 의미하는 과정\n", "learner.predict(cat1) # fastai 에서 \"예측\"을 의미하는 과정 \n", "model.fit(x, y, batch_size=32, epochs=10) # keras에서 \"학습\"을 의미하는 과정\n", "model.predict(test_img) # keras에서 \"예측\"을 의미하는 과정 \n", "```\n", "\n", "`-` R 코드..\n", "\n", "``` r\n", "# R\n", "ols <- lm(y~x) # 선형회귀분석에서 학습을 의미하는 함수\n", "ols$fitted.values # 선형회귀분석에서 yhat을 출력 \n", "predict(ols, newdata=test) # 선형회귀분석에서 test에 대한 예측값을 출력하는 함수\n", "ols$coef # 선형회귀분석에서 weight를 확인하는 방법\n", "```\n", "\n", "# A2. 참고자료들\n", "\n", "`-` 케라스/텐서플로우: \n", "\n", "`-` 상속:\n", "\n", "\n", "`-` sklearn/autogluon: \n", "\n", "`-` 리눅스관련: – 자료 부실함..\n", "강의영상 없는것 많음..\n", "\n", "`-` 클래스기본: – `10wk-2` ~ `15wk-1`\n", "\n", "He, Xiangnan, Lizi Liao, Hanwang Zhang, Liqiang Nie, Xia Hu, and\n", "Tat-Seng Chua. 2017. “Neural Collaborative Filtering.” In *Proceedings\n", "of the 26th International Conference on World Wide Web*, 173–82." ], "id": "159445b3-4119-4585-9411-3649ad824b4d" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 3 (ipykernel)", "language": "python" }, "language_info": { "name": "python", "codemirror_mode": { "name": "ipython", "version": "3" }, "file_extension": ".py", "mimetype": "text/x-python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } } }