diff --git a/wyk/09_neurozoo.ipynb b/wyk/09_neurozoo.ipynb new file mode 100644 index 0000000..6d8aa72 --- /dev/null +++ b/wyk/09_neurozoo.ipynb @@ -0,0 +1,1526 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Neurozoo\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Funkcja sigmoidalna\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Funkcja sigmoidalna zamienia dowolną wartość („sygnał”) w wartość z przedziału $(0,1)$, czyli wartość, która może być interperetowana jako prawdopodobieństwo.\n", + "\n", + "$$\\sigma(x) = \\frac{1}{1 + e^{-x}}$$\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.6457)" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "\n", + "def sigmoid(x):\n", + " return 1 / (1 + torch.exp(-x))\n", + "\n", + "sigmoid(torch.tensor(0.6))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'sigmoid.png'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEGCAYAAABo25JHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Z1A+gAAAACXBIWXMAAAsTAAALEwEAmpwYAAAhNUlEQVR4nO3deXyV5Z3+8c83+04gCVsIqyAguwHcWm2tDijuti5YFW39aWvHWtuqHaszdanLtFNn1PKjFpda12opVQpq6zYubMoWQiCGJWHLRvY9554/EpkMBgTMk+cs1/v1Oq/knOdJvI7Gcz3rfZtzDhERiVxRfgcQERF/qQhERCKcikBEJMKpCEREIpyKQEQkwsX4HeBIZWZmuuHDh/sdQ0QkpKxevbrcOZfV3bKQK4Lhw4ezatUqv2OIiIQUM9t+sGU6NCQiEuFUBCIiEU5FICIS4VQEIiIRzrMiMLOFZlZqZhsOstzM7D/NrNDM1pnZNK+yiIjIwXm5R/AkMOsQy2cDozsf1wG/9TCLiIgchGdF4Jx7F6g8xCrnAU+7Dh8B6WY2yKs8IiLSPT/vI8gGirs8L+l8bfeBK5rZdXTsNTB06NBeCSci0hucczS3BahpaqWuqY265rb9Xxta2qlvaaOhuePr8cP68pXR3d4T9qX4WQTWzWvdTo7gnFsALADIzc3VBAoiEpQCAce+hhbK61qoqG+moq6FfQ0tVNa3UNXQyr6Gjq/VjR2PmsZWapvaaGkPHNbvv+G0UWFXBCVATpfnQ4BdPmURETmkptZ2dlY1squqkd3VTeyuamJPTROlNU3srW2itKaZivoW2gPdb6umJcSQnhRH36RY0hJjGdI3kT6JHd+nJsSQmhBLWkIMyXExpCTEkBIfQ3J8DMlx0STFx5AYG010VHfbz1+en0WwGLjRzJ4HZgLVzrnPHRYSEekt1Y2tbC2vp6isjm0VDeyoqGd7ZQPFlY2U1zV/bv2M5DgGpCUwIC2e8YPSyEqNJyslnoyUeDJS4shMiadfchzpibHERAfv1fqeFYGZPQecBmSaWQlwFxAL4JybDywBzgIKgQZgnldZRES6qmlqpWBPLZt217B5bx1bSmspLK2jvK5l/zpRBoP6JDIsI4nTx/Ynu28iQ/omMjg9kcF9EumfFk9CbLSP76LneFYEzrnLvmC5A77v1T9fRAQ6tvLXlVSxrqSaDTurWb+zmpJ9jfuXpybEMLp/Cl8f259j+qcwIjOFEZnJDO2XRFxM8G7F96SQG31URORgnHNsr2hgxdZKVm6r5JPiKgpL6/YvH5aRxOScdC6fOZRxA9MYOyiVgWkJmHlz7D1UqAhEJKTtqmrkvwvL+aCwnA8+raC0tuNYft+kWKYN7cv5UwYzJacvE4f0oU9irM9pg5OKQERCSmt7gJXbKnm7oIy3NpWypXOLPzMljhNHZXLCyH7MGN6PY/qnRPyW/uFSEYhI0GtqbeftgjJez9vD3zeVUt3YSmy0MXNEBpdMz+GU0ZkcOyBVH/xHSUUgIkGptT3Af28pZ/HaXbyet4f6lnb6JMZy+rj+nDl+IKeMziQlXh9hPUH/FkUkqBTsqeWlVcUsWrOT8roW0hJimDNpMOdMHszMkf2IDeLr8UOVikBEfNfU2s5r63bzh4+2s6a4ipgo4/Rx/bn4+BxOHZMVMZdx+kVFICK+2VPdxFMfbuP5FTvY19DKyKxk7jh7HBdMzSYjJd7veBFDRSAivW7TnhoWvFvEX9fuoj3gOHP8QK48cRgnjsrQCV8fqAhEpNds2FnNf/1jC8vy9pIUF83cmcO49pQR5PRL8jtaRFMRiIjnCvbU8tCyAt7M30tqQgw3nT6aeScPJz0pzu9ogopARDxUsq+BX7+xmT9/spOUuBh+dMYYrj55OGkJusM3mKgIRKTHNbS08dhbn7LgvSIAvvuVkdxw6ij6JmsPIBipCESkxzjnWLx2F79csok9NU2cP2UwP5k1luz0RL+jySGoCESkR2yvqOeORRt4b0s5k4b04dG5Uzl+WD+/Y8lhUBGIyJfS1h5gwXtFPPzmFuKio7j7/AnMnTGUKI+mVZSepyIQkaNWWFrLLS+uZW1JNbMnDORfzz2OAWkJfseSI6QiEJEjFgg4Fr6/lQeXFZAcF81jc6dx1sRBfseSo6QiEJEjUlrbxC0vruW9LeV8Y9wAfnnhRLJSNRxEKFMRiMhhe3dzGT96cQ21TW3cd8FELpuRoyEhwoCKQES+UCDgePjvW3j471sYMyCFP37nBI4dmOp3LOkhKgIROaTqxlZufmEN/9hUykXThnDP+RNIjIv2O5b0IBWBiBzUlr21fOfpVezc18jd5x3HFScM06GgMKQiEJFuvbeljO898zHxsdE8f90J5A7XzWHhSkUgIp/zzEfbuWtxHqP7p/D7q6driIgwpyIQkf2cczywtID573zKacdm8V+XTSVVI4WGPRWBiAAdQ0Xc9sp6/rS6hMtnDuUX5x5HjCaKjwgqAhGhsaWdG5/9mL9vKuWm00fzw2+M1knhCKIiEIlw9c1tXPPkSlZsq+Tu8yfw7ROG+R1JepmKQCSC1TS1Mu+JlawpruI3l0zhvCnZfkcSH6gIRCJUdUMrVz6xgryd1Txy2VRma9C4iOXpmSAzm2VmBWZWaGa3dbO8j5n91czWmlmemc3zMo+IdKhpauXKhcvJ31XDb684XiUQ4TwrAjOLBh4FZgPjgcvMbPwBq30f2OicmwycBvzKzDSpqYiH6pvbmPfESvJ21fDY3GmcMX6A35HEZ17uEcwACp1zRc65FuB54LwD1nFAqnVcnpACVAJtHmYSiWhNre1856lVfLJjH/952VS+oRIQvC2CbKC4y/OSzte6egQYB+wC1gM3OecCB/4iM7vOzFaZ2aqysjKv8oqEtdb2ADc8s5qPtlbw629N0UQysp+XRdDdRcjugOf/BKwBBgNTgEfMLO1zP+TcAudcrnMuNysrq6dzioS9QMBx65/W8VZBGfeeP5Hzp+rqIPlfXhZBCZDT5fkQOrb8u5oHvOI6FAJbgbEeZhKJSPcv3cQrn+zkljPGcPnMoX7HkSDjZRGsBEab2YjOE8CXAosPWGcHcDqAmQ0AjgWKPMwkEnF+924RC94t4qoTh3Hj14/xO44EIc/uI3DOtZnZjcAyIBpY6JzLM7PrO5fPB+4GnjSz9XQcSrrVOVfuVSaRSLNk/W7uXZLP2RMHcdc5x2nYCOmWpzeUOeeWAEsOeG1+l+93AWd6mUEkUn28Yx83v7CG44f15VffmkxUlEpAuqehBUXCUHFlA999ahUD0hJY8O3jSYjV1JJycCoCkTBT29TKNU+upC3geGLedDJS4v2OJEFOYw2JhJFAwHHzC2soKq/nD9fMYFRWit+RJARoj0AkjPz6jc28mV/Kz88ex0nHZPodR0KEikAkTLy6bhePvFXIJbk5XHXScL/jSAhREYiEgYI9tfzkpXUcP6wvvzhfl4nKkVERiIS42qZWbnhmNcnxMfx27jTiY3SFkBwZnSwWCWHOOX7y0jq2Vzbw7Hdm0j8twe9IEoK0RyASwn73XhFL8/Zw26yxzByZ4XccCVEqApEQtXp7JQ8sLWD2hIF85ysj/I4jIUxFIBKC9tW38INnPyE7PZEHLp6kk8PypegcgUiIcc7xkz+tpayumZdvOIm0hFi/I0mI0x6BSIhZ+P423swv5fbZ45g0JN3vOBIGVAQiIWTDzmru/1s+3xg3gHknD/c7joQJFYFIiGhsaeefn/+EfslxPKTzAtKDdI5AJETc89pGisrq+eN3ZtI3Oc7vOBJGtEcgEgJez9vDH5fv4LqvjuRkDSYnPUxFIBLkSmubuPXldRw3OI1bzhzjdxwJQyoCkSDmnOP2l9fT0NLOw5dO0ThC4gkVgUgQe3FVMX/fVMqts8ZyTP9Uv+NImFIRiASp4soGfvHXjZw4MoOrNb+AeEhFIBKEAgHHLS+tJcqMf//WZKKidKmoeEdFIBKEnvhgGyu2VnLnOePJTk/0O46EORWBSJDZWl7PQ8s2cfrY/lx8/BC/40gEUBGIBJFAwPHTP60lLjqK+y6cqLuHpVeoCESCyFMfbmPltn3cec5xDNBsY9JLVAQiQWJ7RT0PLN3E147N4qJp2X7HkQiiIhAJAs45bnt5PbFROiQkvU9FIBIEXlhZzIdFFdx+1jgG9dFVQtK7VAQiPttb08S9S/I5YWQ/Lp2e43cciUAqAhEfOee4Y9EGWtoC3H/hJN04Jr7wtAjMbJaZFZhZoZnddpB1TjOzNWaWZ2bveJlHJNj8bcMe3ti4l1vOHMPwzGS/40iE8mxiGjOLBh4FzgBKgJVmttg5t7HLOunAY8As59wOM+vvVR6RYFPd2Mpdi/OYkJ3GNSeP8DuORDAv9whmAIXOuSLnXAvwPHDeAetcDrzinNsB4Jwr9TCPSFB5YOkmKuqauf/CScRE6yit+MfLv75soLjL85LO17oaA/Q1s7fNbLWZXdndLzKz68xslZmtKisr8yiuSO9Zua2SZ5fv4NpTRjAhu4/fcSTCeVkE3Z31cgc8jwGOB84G/gn4uZl9bgom59wC51yucy43Kyur55OK9KLmtnZuf2U92emJ3HyGZhwT/3k5eX0J0PVauCHArm7WKXfO1QP1ZvYuMBnY7GEuEV/9/3eKKCyt44l500mK8/J/QZHD4+UewUpgtJmNMLM44FJg8QHr/AX4ipnFmFkSMBPI9zCTiK+2ltfzyFuFzJk0iK8dq2sjJDh4tjninGszsxuBZUA0sNA5l2dm13cun++cyzezpcA6IAA87pzb4FUmET913DOwnvjoKO6cM97vOCL7ebpf6pxbAiw54LX5Bzx/CHjIyxwiweAva3bxfmEFd58/gf4aWVSCiK5ZE+kFVQ0t3PPaRqbkpDN3xlC/44j8HzpTJdILHlhawL6GVp6+ZqKGkZCgoz0CEY+t3r6P51bsYN5Jwxk/OM3vOCKfoyIQ8VBbe4A7Fm1gYFoCP9Q9AxKkVAQiHnryg23k767hrnPGkxKvI7ESnFQEIh7ZXd3If7yxmdOOzWLWhIF+xxE5KBWBiEfufnUjbQHHL86doKknJaipCEQ88HZBKUvW7+HGrx3D0Iwkv+OIHJKKQKSHNbW2c9fiPEZkJnPdqSP9jiPyhXT2SqSHzX/nU7ZXNPDMtTOJj4n2O47IF9IegUgP2lZez2Nvf8o5kwdzyuhMv+OIHBYVgUgPcc5x1+I84qKjuOPscX7HETlsKgKRHrIsbw/vbC7j5jPGMECDykkI+cIiMLMbzaxvb4QRCVX1zW382183MnZgKledOMzvOCJH5HD2CAYCK83sRTObZbogWuRz/vMfW9hd3cS9F0zQRPQScr7wL9Y5dwcwGvg9cDWwxczuM7NRHmcTCQmb99by+/e28q3cIRw/rJ/fcUSO2GFtujjnHLCn89EG9AX+ZGYPephNJOg55/j5og0kx8dw66yxfscROSpfeB+Bmf0zcBVQDjwO/MQ512pmUcAW4KfeRhQJXovW7GT51kruu2AiGSnxfscROSqHc0NZJnChc2571xedcwEzm+NNLJHgV93Qyr2v5TM5J51Lp+f4HUfkqH1hETjn7jzEsvyejSMSOv799QIq61t4ct4MzTomIU2XN4gchXUlVTyzfDtXnjicCdl9/I4j8qWoCESOUHvAcceiDWQkx/OjMzXrmIQ+FYHIEXp2+XbWlVTz8znjSEuI9TuOyJemIhA5AqW1TTy4rICTj8ng3MmD/Y4j0iNUBCJH4L7X8mluDXD3eZp1TMKHikDkMH1QWM6iNbu4/rRRjMxK8TuOSI9REYgchua2du74ywaGZSTxvdM0uoqEF81QJnIY5r9dRFFZPU9fM4OEWM06JuFFewQiX6CorI5H3y7knMmD+eqYLL/jiPQ4FYHIITjXcc9AfEwUP5+jWcckPKkIRA5h0ZqdfPBpBT+dNZb+qZp1TMKTp0XQOZFNgZkVmtlth1hvupm1m9nFXuYRORL76lu459V8puSkM3fGUL/jiHjGs5PFZhYNPAqcAZTQMcvZYufcxm7WewBY5lUWkaNx35J8qhpb+cMFEzWonIQ1L/cIZgCFzrki51wL8DxwXjfr/QB4GSj1MIvIEfmgsJyXVpdw3VdHMn5wmt9xRDzlZRFkA8Vdnpd0vrafmWUDFwDzD/WLzOw6M1tlZqvKysp6PKhIV02t7fzsz+sZlpHETaeP9juOiOe8LILu9qXdAc9/A9zqnGs/1C9yzi1wzuU653KzsnT5nnjrkX8Usq2igXvPn6h7BiQieHlDWQnQddqmIcCuA9bJBZ7vHLMlEzjLzNqcc4s8zCVyUPm7a5j/zqdcODWbU0Zn+h1HpFd4WQQrgdFmNgLYCVwKXN51BefciM++N7MngVdVAuKXtvYAt768jj6Jsfx8zni/44j0Gs+KwDnXZmY30nE1UDSw0DmXZ2bXdy4/5HkBkd72xPvbWFdSzX9dNpW+yXF+xxHpNZ6ONeScWwIsOeC1bgvAOXe1l1lEDmVbeT2/eqOAb4wbwJxJg/yOI9KrdGexRDznHLe/sp7YqCjuOV/zDEjkURFIxPvj8h18WFTB7WeNY2AfDSMhkUdFIBGtuLKBXy7J55RjMrlsRs4X/4BIGFIRSMRyznHbK+sAuP+iiTokJBFLRSAR67kVxbxfWMHPzh7HkL5JfscR8Y2KQCJScWUD9y3J56RRGVyukUUlwqkIJOIEAo4fv7QWgAcumqRDQhLxVAQScRa+v5XlWyu585zx5PTTISERFYFElC17a3lwWceNY988fojfcUSCgopAIkZre4CbX1xDSnwMv7xQVwmJfMbTISZEgslv3tzMhp01zL9iGlmp8X7HEQka2iOQiLC8qILH3v6Ub+UOYdYEjSUk0pWKQMJedUMrN7+whmH9krjrnOP8jiMSdHRoSMKac46fLVpPaW0zL99wEsnx+pMXOZD2CCSsvbS6hNfW7ebmM8YwOSfd7zgiQUlFIGFry95a7vzLBk4cmcH1p47yO45I0FIRSFhqbGnnxmc/ITkuhocvnUJ0lC4VFTkYHTCVsPSLV/Mo2FvLU9fMoH+a5hgQORTtEUjYWfTJTp5bUcwNp43i1DFZfscRCXoqAgkrBXtquf2V9Uwf3pcfnTHG7zgiIUFFIGGjpqmV659ZTUpCDI9ePo3YaP15ixwOnSOQsOCc4ycvrWVHZQPPffcEnRcQOQLaZJKw8Nt3PmVZ3l5unz2WGSP6+R1HJKSoCCTk/T1/Lw8tK2DOpEFce8oIv+OIhBwVgYS0wtJabnp+DeMHpfHQxZM1tLTIUVARSMiqbmjlu0+vJiE2igVX5pIYF+13JJGQpJPFEpJa2wN879nVlOxr4NnvnkB2eqLfkURClopAQo5zjjv+vIH3Cyt46OJJTB+uk8MiX4YODUnI+e07n/LCqmJ+8PVj+GZujt9xREKeikBCyqvrdvHg0gLOnTxYdw6L9BAVgYSM9wvLufmFNcwY3o8HL56kK4REeoinRWBms8yswMwKzey2bpbPNbN1nY8PzGyyl3kkdK0vqea6p1cxMjOF312ZS0KsrhAS6SmeFYGZRQOPArOB8cBlZjb+gNW2Aqc65yYBdwMLvMojoWtreT1XP7GC9KQ4nr52Bn2SYv2OJBJWvNwjmAEUOueKnHMtwPPAeV1XcM594Jzb1/n0I2CIh3kkBJXsa+CKx5cTcI6nr53BAI0hJNLjvCyCbKC4y/OSztcO5lrgb90tMLPrzGyVma0qKyvrwYgSzPZUNzH38eXUNLXyh2tnMiorxe9IImHJyyLo7kye63ZFs6/RUQS3drfcObfAOZfrnMvNytJEI5GgvK6ZuY9/RHltM09dM4MJ2X38jiQStry8oawE6HqR9xBg14Ermdkk4HFgtnOuwsM8EiLKajtKYGdVI0/Nm8G0oX39jiQS1rzcI1gJjDazEWYWB1wKLO66gpkNBV4Bvu2c2+xhFgkRe6qbuGTBhxRXNrLwqunMHJnhdySRsOfZHoFzrs3MbgSWAdHAQudcnpld37l8PnAnkAE81nlNeJtzLterTBLcdlY1cvnv/vdwkOYVEOkd5ly3h+2DVm5urlu1apXfMaSHFZbWcdXCFdQ0tfLUNTocJNLTzGz1wTa0Neic+G5NcRXznlhBdJTx3HdP0IlhkV6mIhBfvbu5jOufWU1GShx/uGYmwzOT/Y4kEnFUBOKb51bs4I5FGxgzIJWn5k3XhPMiPlERSK9rDzgeWLqJBe8WceqYLB65fCqpCRo2QsQvKgLpVbVNrfzoxbW8sXEvV544jDvnjCcmWoPgivhJRSC9prC0jv/3h1Vsq2jgX88Zz9Unj/A7koigIpBesnTDHn780lriY6J45tqZnDhKN4qJBAsVgXiqua2d+/+2iSfe38bknHTmXzGNQX000bxIMFERiGeKyur4wXOfkLerhnknD+e22WOJj9GEMiLBRkUgPc45x3MrirnntY3ExUTxuytzOWP8AL9jichBqAikR+2pbuLWl9fxzuYyTj4mg4cunszgdB0KEglmKgLpEYGA48VVxdy3JJ/WdscvzjuOK2YOIypKE8yLBDsVgXxphaW1/OyVDazYVsmMEf144KJJjNBQESIhQ0UgR62uuY1H/lHIwv/eSmJcNA9eNIlv5g6hc0hxEQkRKgI5YoGA45VPdvLA0k2U1TZz0bQh3H7WWDJT4v2OJiJHQUUgh805x9uby3hwaQH5u2uYnJPOgm8fz1TNHSAS0lQEclhWbqvkV68X8FFRJTn9EvnNJVM4d/JgnQwWCQMqAjmkj4oqePjNLXxYVEFmShz/es54Lp85jLgYDRQnEi5UBPI57QHHGxv3sODdIj7eUUVWajx3nD2OuTOHkRinO4NFwo2KQParbmzl5dUlPPXhNrZXNDC0XxL/du5xXDI9h4RYFYBIuFIRRDjnHOtKqnluxQ4WrdlJU2uAaUPTuW3WWM48biDROgcgEvZUBBGqrLaZv6zZyYuritm8t47E2GgumJrN3JnDNHm8SIRREUSQ6oZWluXtYfHaXXzwaTkBB1Ny0rn3ggnMmTSYPomaLlIkEqkIwtzemiZe37iX1/P28OGnFbQFHEP7JfG9047hvCmDGT0g1e+IIuIzFUGYaW0PsLa4ircLyniroJS8XTUAjMhM5tqvjGD2hEFMHtJHw0CIyH4qghDX1h4gf3cty7dW8MGnFSwvqqC+pZ3oKOP4oX356axjOX3sAMYMSNGHv4h0S0UQYqoaWlhTXMUnO6r4eMc+PtlRRV1zG9Cx1X/BtGxOHpXJSaMy6ZOkY/4i8sVUBEHKOUdZbTP5e2rZuKuGDTurWb+zmh2VDQBEGYwZkMr5UwczY0QGM4b3Y2CfBJ9Ti0goUhH4LBBw7K5pYmtZPUXldWzZW8fmvbVsKa2jsr5l/3pD+iYyMbsPl0zPYerQdCYNSSclXv/5ROTL0yeJx5xz1DS2sbOqkZ1VjZTsa6C4spEdlQ3sqKxnR2UDTa2B/eunJsQwZkAqZ44fwNiBqYwdlMbYgamkJ8X5+C5EJJypCI5SIOCoamyloq6Z8roWyuqaKa9tprS2mdKaJvbWNrG7uondVU00trb/n59NiI1iWL9khmUk89XRWYzMSmFEZjIjs5Lpnxqvk7oi0qs8LQIzmwU8DEQDjzvn7j9guXUuPwtoAK52zn3sZabPOOdobgtQ39xGfXM7tc2t1DW1UdvURm1zKzWNbdQ0tlLd2EpVYytVDa1UNbSwr6GFqoZW9jW0EHCf/72x0Ub/1AQGpMVz7IBUThvTn8HpCQzqk8iQvolk900kIzlOH/YiEjQ8KwIziwYeBc4ASoCVZrbYObexy2qzgdGdj5nAbzu/9ri3Ckq559WNNLS0dz7aaG3v5pP8AElx0aQnxpKWGEvfpDiO7TxMk5EcR7/OR2ZKPP1T48lMiSc9KVYf8iISUrzcI5gBFDrnigDM7HngPKBrEZwHPO2cc8BHZpZuZoOcc7t7OkyfxFjGDkojOS6apLgYkuKiSY6PISU+Zv/X1ISOr2mJsaQlxJCaEKtx90Uk7HlZBNlAcZfnJXx+a7+7dbKB/1MEZnYdcB3A0KFDjyrMtKF9mXa5plQUETmQl5u73R0fOfBYzOGsg3NugXMu1zmXm5WV1SPhRESkg5dFUALkdHk+BNh1FOuIiIiHvCyClcBoMxthZnHApcDiA9ZZDFxpHU4Aqr04PyAiIgfn2TkC51ybmd0ILKPj8tGFzrk8M7u+c/l8YAkdl44W0nH56Dyv8oiISPc8vY/AObeEjg/7rq/N7/K9A77vZQYRETk0XRspIhLhVAQiIhFORSAiEuGs4zB96DCzMmC73zmOQiZQ7neIXqb3HP4i7f1C6L7nYc65bm/ECrkiCFVmtso5l+t3jt6k9xz+Iu39Qni+Zx0aEhGJcCoCEZEIpyLoPQv8DuADvefwF2nvF8LwPescgYhIhNMegYhIhFMRiIhEOBWBD8zsx2bmzCzT7yxeMrOHzGyTma0zsz+bWbrfmbxiZrPMrMDMCs3sNr/zeM3McszsLTPLN7M8M7vJ70y9xcyizewTM3vV7yw9RUXQy8wsh455nHf4naUXvAFMcM5NAjYDt/ucxxNd5ueeDYwHLjOz8f6m8lwbcItzbhxwAvD9CHjPn7kJyPc7RE9SEfS+/wB+SjczsYUb59zrzrm2zqcf0THxUDjaPz+3c64F+Gx+7rDlnNvtnPu48/taOj4Ys/1N5T0zGwKcDTzud5aepCLoRWZ2LrDTObfW7yw+uAb4m98hPHKwubcjgpkNB6YCy32O0ht+Q8eGXMDnHD3K0/kIIpGZvQkM7GbRvwA/A87s3UTeOtT7dc79pXOdf6HjUMIfezNbLzqsubfDkZmlAC8DP3TO1fidx0tmNgcodc6tNrPTfI7To1QEPcw5943uXjezicAIYK2ZQcdhko/NbIZzbk8vRuxRB3u/nzGzq4A5wOkufG9aici5t80slo4S+KNz7hW/8/SCk4FzzewsIAFIM7NnnHNX+JzrS9MNZT4xs21ArnMuFEcxPCxmNgv4NXCqc67M7zxeMbMYOk6Gnw7spGO+7sudc3m+BvOQdWzNPAVUOud+6HOcXte5R/Bj59wcn6P0CJ0jEC89AqQCb5jZGjOb/0U/EIo6T4h/Nj93PvBiOJdAp5OBbwNf7/xvu6ZzS1lCkPYIREQinPYIREQinIpARCTCqQhERCKcikBEJMKpCEREIpyKQEQkwqkIREQinIpA5Esys+mdcy4kmFly5/j8E/zOJXK4dEOZSA8ws3voGH8mEShxzv3S50gih01FINIDzCyOjjGGmoCTnHPtPkcSOWw6NCTSM/oBKXSMrZTgcxaRI6I9ApEeYGaL6ZiZbAQwyDl3o8+RRA6b5iMQ+ZLM7EqgzTn3bOf8xR+Y2dedc//wO5vI4dAegYhIhNM5AhGRCKciEBGJcCoCEZEIpyIQEYlwKgIRkQinIhARiXAqAhGRCPc/OnN4AJzLYKEAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "import torch\n", + "\n", + "x = torch.linspace(-5,5,100)\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.plot(x, sigmoid(x))\n", + "fname = 'sigmoid.png'\n", + "plt.savefig(fname)\n", + "fname" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[file:# Out[32]:\n", + "\n", + " 'sigmoid.png'\n", + "\n", + "![img](./obipy-resources/Tb0Of9.png)]]\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### PyTorch\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Funkcja `torch.sigmoid` po prostu stosuje sigmoidę do każdego elementu tensora (*element-wise*).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.6457, 0.7311, 0.0067])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "\n", + "torch.sigmoid(torch.tensor([0.6, 1.0, -5.0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Istnieje również `torch.nn.Sigmoid`, które może być używane jako warstwa.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.5000, 0.4502, 0.5987])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "s = nn.Sigmoid()\n", + "s(torch.tensor([0.0, -0.2, 0.4]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Implementacja w Pytorchu\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.5000, 0.6225, 0.5744])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "import torch\n", + "\n", + "class MySigmoid(nn.Module):\n", + " def __init__(self):\n", + " super(MySigmoid, self).__init__()\n", + "\n", + " def forward(self, x):\n", + " return 1 / (1 + torch.exp(-x))\n", + "\n", + "s = MySigmoid()\n", + "s(torch.tensor([0.0, 0.5, 0.3]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Wagi\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Funkcja sigmoidalna nie ma żadnych wyuczalnych wag.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### **Pytanie**: Czy można rozszerzyć funkcję sigmoidalną o jakieś wyuczalne wagi?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Regresja liniowa\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Softmax\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "W klasyfikacji wieloklasowej należy zwrócić musimy zwrócić rozkład\n", + "prawdopodobieństwa po wszystkich klasach, w przeciwieństwie do\n", + "klasyfikacji binarnej, gdzie wystarczy zwrócić jedną liczbę —\n", + "prawdopodobieństwo pozytywnej klasy ($p$; prawdopodobieństwo drugiej\n", + "klasy to po prostu $1-p$).\n", + "\n", + "A zatem na potrzeby klasyfikacji wieloklasowej potrzeba wektorowego\n", + "odpowiednika funkcji sigmoidalnej, to jest funkcji, która zamienia\n", + "nieznormalizowany wektor $\\vec{z} = [z_1,\\dots,z_k]$ (pochodzący np. z\n", + "poprzedzającej warstwy liniowej) na rozkład prawdopobieństwa.\n", + "Potrzebujemy zatem funkcji $s: \\mathcal{R}^k \\rightarrow [0,1]^k$\n", + "\n", + "spełniającej następujące warunki:\n", + "\n", + "- $s(z_i) = s_i(z) \\in [0,1]$\n", + "- $\\Sigma_i s(z_i) = 1$\n", + "- $z_i > z_j \\Rightarrow s(z_i) > s(z_j)$\n", + "\n", + "Można by podać takie (**błędne**!) rozwiązanie:\n", + "\n", + "$$s(z_i) = \\frac{z_i}{\\Sigma_{j=1}^k z_j}$$\n", + "\n", + "To rozwiązanie zadziała błędnie dla liczb ujemnych, trzeba najpierw\n", + "użyć funkcji monotonicznej, która przekształaca $\\mathcal{R}$ na $\\mathcal{R^+}$.\n", + "Naturalna funkcja tego rodzaju to funkcja wykładnicza $\\exp{x} = e^x$.\n", + "Tym sposobem dochodzimy do funkcji softmax:\n", + "\n", + "$$s(z_i) = \\frac{e^{z_i}}{\\Sigma_{j=1}^k e^{z_j}}$$\n", + "\n", + "Mianownik ułamka w definicji funkcji softmax nazywamy czasami czynnikiem normalizacyjnym:\n", + "$Z(\\vec{z}) = \\Sigma_{j=1}^k e^{z_j}$, wtedy:\n", + "\n", + "$$s(z_i) = \\frac{e^{z_i}}{Z(\\vec{z})}$$\n", + "\n", + "Definicja w PyTorchu:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.1182, 0.0022, 0.0059, 0.8737])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "\n", + "def softmax(z):\n", + " z_plus = torch.exp(z)\n", + " return z_plus / torch.sum(z_plus)\n", + "\n", + "softmax(torch.tensor([3., -1., 0., 5.]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![img](./softmax.png \"Softmax\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Soft vs hard\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dlaczego *softmax*? Czasami używa się funkcji **hardmax**, która np.\n", + "wektora $[3, -1, 0, 5]$ zwróciłaby $[0, 0, 0, 5]$ — to jest po prostu\n", + "wektorowa wersja funkcji zwracającej maksimum. Istnieje też funkcja\n", + "hard\\*arg\\*max, która zwraca wektor *one-hot* — z jedną jedynką na\n", + "pozycji dla największej wartości (zamiast podania największej\n", + "wartości), np. wartość hardargmax dla $[3, -1, 0, 5]$ zwróciłaby $[0,\n", + "0, 0, 1]$.\n", + "\n", + "Zauważmy, że powszechnie przyjęta nazwa *softmax* jest właściwie\n", + "błędna, funkcja ta powinna nazywać się *softargmax*, jako że w\n", + "„miękki” sposób identyfikuje największą wartość przez wartość zbliżoną\n", + "do 1 (na pozostałych pozycjach wektora nie będzie 0).\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### **Pytanie**: Jak można zdefiniować funkcję *softmax* w ścisłym tego słowa znaczeniu („miękki” odpowiednik hardmax, nie hardargmax)?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### PyTorch\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Funkcja `torch.nn.functional.softmax` normalizuje wartości dla całego tensora:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":3: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " nn.functional.softmax(torch.tensor([0.6, 1.0, -5.0]))\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor([0.4007, 0.5978, 0.0015])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "nn.functional.softmax(torch.tensor([0.6, 1.0, -5.0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "… zobaczmy, jak ta funkcja zachowuje się dla macierzy:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":3: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " nn.functional.softmax(torch.tensor([[0.6, 1.0], [-2.0, 3.5]]))\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor([[0.4013, 0.5987],\n", + " [0.0041, 0.9959]])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "nn.functional.softmax(torch.tensor([[0.6, 1.0], [-2.0, 3.5]]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Za pomocą (zalecanego zresztą) argumentu `dim` możemy określić wymiar, wzdłuż którego dokonujemy normalizacji:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0.9309, 0.0759],\n", + " [0.0691, 0.9241]])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "nn.functional.softmax(torch.tensor([[0.6, 1.0], [-2.0, 3.5]]), dim=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Istnieje również `torch.nn.Softmax`, które może być używane jako warstwa.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.3021, 0.2473, 0.4506])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "s = nn.Softmax(dim=0)\n", + "s(torch.tensor([0.0, -0.2, 0.4]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Implementacja w Pytorchu\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.5000, 0.6225, 0.5744])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "import torch\n", + "\n", + "class MySoftmax(nn.Module):\n", + " def __init__(self):\n", + " super(MySoftmax, self).__init__()\n", + "\n", + " def forward(self, x):\n", + " ex = torch.exp(x)\n", + " return ex / torch.sum(ex)\n", + "\n", + "s = MySigmoid()\n", + "s(torch.tensor([0.0, 0.5, 0.3]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###### **Pytanie**: Tak naprawdę wyżej zdefiniowana klasa `MySoftmax` nie zachowuje się identycznie jak `nn.Softmax`. Na czym polega różnica?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Przypadek szczególny\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sigmoida jest przypadkiem szczególnym funkcji softmax:\n", + "\n", + "$$\\sigma(x) = \\frac{1}{1 + e^{-x}} = \\frac{e^x}{e^x + 1} = \\frac{e^x}{e^x + e^0} = s([x, 0])_1$$\n", + "\n", + "Ogólniej: softmax na dwuelementowych wektorach daje przesuniętą sigmoidę (przy ustaleniu jednej z wartości).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'softmax3.png'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "import torch\n", + "import torch.nn as nn\n", + "\n", + "x = torch.linspace(-5,5,100)\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "a = torch.Tensor(x.size()[0]).fill_(2.)\n", + "m = torch.stack([x, a])\n", + "plt.plot(x, nn.functional.softmax(m, dim=0)[0])\n", + "fname = 'softmax3.png'\n", + "plt.savefig(fname)\n", + "fname" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[file:# Out[19]:\n", + "\n", + " 'softmax3.png'\n", + "\n", + "![img](./obipy-resources/gjBA7K.png)]]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'softmax3d.png'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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c+TeU4iiyOeff86ll15KamoqGo2G008/ndNPP53o6OhZs96+1olLex0aGpJz6Z6mk7qD3W6npKRkr6bXJGLn5+ePs9ZWq3VGxjSJosijjz5KcXExr7/++l6ppnN97ssuu4ywsDD+9a9/zcZTzJF7JvCPf/yDY489loKCAhobG1m9ejVvv/02SqWS0047jZUrV85YkEsUxXE55T1xIV2LZlQqlZxLn+gFWK1WSktL95pCKXgm9kRMHNMUEhIiV5dNdQQRRZEnn3ySL7/8klWrVu2V+ndXfPvttxx22GHj6gLuueceTj755Jl6ijlyzxZEUaStrU0musVi4bTTTmPFihUkJyfvFtFno05cwujoqJxikwQoIiMjUSqVezVvDuPbRH05X08c0xQQECD3pru626Io8txzz/HBBx/w9ttv75UKxX2AOXLvDYiiSGdnJ2vWrGHNmjUMDg5yyimnsHLlSq/nYe2NOnEJZrMZg8FAR0cHQ0NDREVFkZqauleqs3aX2BMxsZxXo9EQEBCAVqvliy++YPXq1axdu3bWesz3A8yRe1+gq6uLd955hzVr1tDV1cVJJ53EihUrPBaCSKN2goOD91oUXlIonTdvHjabDYPBgNlsJjw8nOjo6N2qLJsOkrTVnhLbHUZGRiguLubWW2+ls7OTW265hQsuuGBWI/77GHPk3tfo6+uTxSdaWlo4/vjjOeOMM2QBB6vVKvea761AlieFUpvNRk9PD52dnRiNRrmneybG+ErEdlWImWmsWbOGp59+mueff54vvvgCrVbLRRddNCvPtR9gjtz7EwYGBuSe9NraWg455BA2bNjA888/T2Zm5l7Zg7cKpe4EKKKioqado+UOvb291NTUkJ+fP2vEfu+993j00Ufl1OVsYP369dx0003Y7Xauvvpqfv/738/K83iJOXLvr6iqquLUU08lMzOT1tZWjjrqKFasWMHSpUv3O4VST8McvMmlS1JMs0ns9evX889//pP333/fbbvtTMBut5ORkcEnn3xCQkICRUVFvPbaazNZK+4rfnoCiT8XVFRU8Prrr7N06VJGR0f5+OOPeeGFF7jppps47LDDWLFiBcuXL5+xogvXum1fGzIUCgVhYWGyuIE03qi+vh6dTifn0ifuVSJ2QUHBrKWiPvvsM+677z4++OCDWSM2wMaNG0lPT5fnip9//vm8++67+5Lcs4I5yz2LMJvNfPbZZ6xatYoff/yRgw8+mJUrV3LYYYftdhGGFKGe6bptdxFrKcU2NDQ068T++uuvufvuu3n//fdnPY23atUq1q9fzzPPPAPAyy+/zI8//shjjz02q887BWbFcu+9Vhov8cADDyAIgjyR8acMPz8/Tj75ZJ577jlKSko477zzWLduHcuXL+e6667jo48+wmw2e71eT0+PHMia6bSQIAgEBgaSlpbGsmXLyMjIwGq1smnTJnket6eJrXuK7777jjvvvJO1a9futb72ifgJSTJ5jf3KLW9paeGTTz7xeaDeTwFqtZrjjjuO4447DpvNxrfffsuqVav4wx/+QG5uLitXruSYY47xSFpJoXQ2racr9Ho9o6OjqFQqioqK6Ovro7KyUh7mEBUVNSM92j/++CO33XYba9euJS4ubgZ2Pj0SEhJoaWmR/7+1tXWvPffexH7llp999tn84Q9/YMWKFWzatImIiIi9+fT7BHa7ne+//17uSc/KymLlypUcf/zxciFKe3s7ra2te02hFJz5/YaGhkmNLhaLRVZpkYY5REdH71ZTyJYtW7jhhht4991391oDDzjThBkZGXz22WfEx8dTVFTEq6++yqJFi/baHibgwA6orV27lvj4ePLy8vb1VvYqlEolhx56KIceeigOh4PNmzfz1ltv8Y9//IN58+YRGRkpd0PtrS4oT8QG58SQ+Ph44uPjZZWWuro6uSlkKn10V5SWlnL99dezZs2avUpsAJVKxWOPPcYJJ5yA3W7nyiuv3JfEnjXsVct97LHH0tHRMennf//737nnnnv4+OOP5cqun4vl9gSHw8Fdd93F6tWrCQoKknvSTznllBmfKuoKidgFBQU+eQnu9NElAYqJufTKykquuuoq3nrrrb1WE7Cf46dvuT/99FO3Py8vL5eH64HzDFRYWMjGjRt/ahK1Mwar1YrNZqO8vByNRkNVVRWrVq1i5cqVhIWFsWLFCk499dQZvQG6nut9df9dVV8dDgd9fX10dnayY8cOWY4pMDCQxsZGrrrqKl577bU5Ys8y9qszt4Q5y+0ZUrfZqlWrWLt2LTqdjhUrVnDaaaftUU+6wWCQxSRm8lwvyTHt2LGDq666CovFws0338y111476+OPf0L4eaTCZhK/+93vyMrKIjc3lzPOOIP+/v59vaU9hiAIZGRkcOedd/L999/zzDPPYLFYuOSSSzjppJN4/PHH2blzp9t0jyfMFrGl/YaEhMgNLPfddx/9/f3cdtttM/o8c5iM/dJyzxQ+/vhjjj76aFQqFbfffjsA999//z7e1exAFEVaW1vlnnSbzcZpp53G6aefPmVPemdnJ83NzbMaiW9paeG8887jySefZNmyZbPyHK743e9+x3vvvYdGoyEtLY3nn39+xmrU//CHPxARESHrlt91111ER0fz61//ek+Wnast3xO8/fbbrFq1iv/973/7eiuzDlEU6ejokHvSh4eHOeWUU1ixYsW4nnSJ2AUFBbMWid+5cyfnnHMOjz76KIceeuisPMdEzOZNvbGxkTPPPJMtW7bgcDiYP38+Gzdu3FPt+Z9+QG1f4rnnnuO8887b19vYKxAEgdjYWG644QZuuOEGurq6ePvtt7n99tvp6enhpJNOQqVSYbPZuPXWW2eN2B0dHZx33nk8/PDDe43YAMcff7z874MOOohVq1bN2NopKSmEh4ezdetWOjs7KSgo2CtDJXYHP3nLPVV6bcWKFfK/N23axJo1aw7IMkNf0Nvby1133cW7775LfHw8xxxzDGecccaU44V2B11dXZx11lnce++9Myne7zNOO+00zjvvPC6++OIZW/ONN95gw4YNdHR0cNlll82EltqcW747ePHFF3niiSf47LPPZmWkzU8NAwMDXH755bz00ks4HA7WrVvH6tWrqaur47jjjmPlypXk5+fvEdF7eno466yz+POf/zyTIoLjsC9v6haLhZycHKxWKzU1NTPR1jtHbl+xfv16brnlFr766isiIyP39Xb2awwPD/PBBx+watUqtm3bxtFHH82KFSsoKiry6eLt7+/nzDPP5I477pBJti8w2zf1a6+9lpCQEO67776ZWG523ElRFKf6+kkjLS1NTEhIEPPy8sS8vDzxl7/85W6v9eGHH4oZGRliWlqaeO+9987gLvc/jIyMiG+//bZ40UUXiYsWLRKvu+46cf369eLAwIBoNBo9frW3t4vLly8X33rrrX26/w8//FBcsGCBaDAYZmV9u90u5uXlidXV1TO15HQ83K2vA5rcMwWbzSbOmzdPrKurE81ms5ibmytWVlbu623tFZhMJnHdunXi5ZdfLi5atEi8+uqrxXXr1on9/f3jiN3Z2Skefvjh4quvvrqvtzyjN/WJqKysFFNTU8VbbrllxtYUZ4ncB7RbPlP4/vvv+fOf/8xHH30EwL333gvAHXfcsS+3tddhtVplqeFvv/2WoqIiVq5cybJly7jooou47LLLuOyyy/b1Nn+KmKtQ21doa2sjMTFR/v+EhATa2tr24Y72DdRqNccffzxPPvkkpaWlXH755XzyySfk5ORw/PHHzxF7P8PPJs+9J3Dn3fzcU2oqlYojjzySI488koceemivj/iZw/SYI7cX+Lkod+wuZksJdQ57hjm33AsUFRVRU1NDQ0MDFouF119/ndNPP31fb+tniQNJY2+2MUduL+Cq3LFgwQLOPffcGVHuaGlp4aijjmLBggUsWrSIRx55ZAZ2e+DiQNbYmw3MRcv3Idrb22lvb6ewsJChoSEWL17MO++8c8DpZ88UDmCNvblo+YGG2NhYCgsLAQgMDGTBggU/yyi8N/i5auztCeYCavsJGhsb2bp1617pd95f4Y3G3hy8x5xbvh9geHiYI444grvuuoszzzxzX29nv0N5eTnHHHOMXCMuZSsOII29ucaRAxFWq5VTTz2VE044gVtuuWVfb+cngQNQY2/uzH2gQRRFrrrqKhYsWDBH7DnMOOYs9z7Et99+y2GHHUZOTo7cP33PPffMSA+03W5nyZIlxMfHs27duj1ebw6zijmZpQMNhx56qE8qpb7gkUceYcGCBQwODs7K+nPY//Gzd8uLi4vJzc3FZDJhNBpZtGgRFRUV+3pbe4TW1lbef/99rr766n29lTnsQ0znlv8sIAjC3wAt4A+0iqJ47z7e0h5BEIRVwL1AIHCrKIqn7uMtzWEfYM4td+IvQDFgAvZIgHpfQxCEUwGDKIqbBUE4ch9vZw77ED97t3wMYUAATkun3cd72VMcApwuCEIj8DpwtCAIr+zbLc1hX2DOLQcEQViLkwipQKwoijfu4y3NCMYs95xb/jPFz94tFwThUsAmiuKrgiAogQ2CIBwtiuLn+3pvc5jDnmDOcs9hDgco5s7cc5jDAYo5cs9hDgco5sg9hzkcoJgj9xzmcIBijtxzmMMBijlyz2EOByjmyD2HORygmCP3HOZwgOL/AaJgSf7ygNsrAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits import mplot3d\n", + "import torch\n", + "import torch.nn as nn\n", + "\n", + "x = torch.linspace(-5,5,10)\n", + "y = torch.linspace(-5,5,10)\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111, projection='3d')\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "X, Y = torch.meshgrid(x, y)\n", + "m = torch.stack([X, Y])\n", + "z = nn.functional.softmax(m, dim=0)\n", + "ax.plot_wireframe(x, y, z[0])\n", + "fname = 'softmax3d.png'\n", + "plt.savefig(fname)\n", + "fname" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[file:# Out[27]:\n", + "\n", + " 'softmax3d.png'\n", + "\n", + "![img](./obipy-resources/p96515.png)]]\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Wagi\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Podobnie jak funkcja sigmoidalna, softmax nie ma żadnych wyuczalnych wag.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Zastosowania\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Podstawowym zastosowaniem funkcji softmax jest klasyfikacja\n", + "wieloklasowa, również w wypadku zadań przetwarzania sekwencji, które\n", + "mogą być interpretowane jako klasyfikacja wieloklasowa:\n", + "\n", + "- przewidywanie kolejnego słowa w modelowaniu języka (klasą jest słowo, zbiór klas to słownik, np. klasą początku tekstu *Dzisiaj rano kupiłem w piekarni* może być *bułki*)\n", + "- przypisywanie etykiet (np. części mowy) słowom.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### LogSoftmax\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ze względów obliczeniowych często korzysta się z funkcji **LogSoftmax**\n", + "która zwraca logarytmy pradopodobieństw (*logproby*).\n", + "\n", + "$$log s(z_i) = log \\frac{e^{z_i}}{\\Sigma_{j=1}^k e^{z_j}}$$\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### PyTorch\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-1.1971, -1.3971, -0.7971])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch.nn as nn\n", + "\n", + "s = nn.LogSoftmax(dim=0)\n", + "s(torch.tensor([0.0, -0.2, 0.4]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Niektóre funkcje kosztu (np. `NLLLoss`) zaimplementowane w PyTorchu\n", + "operują właśnie na logarytmach prawdopobieństw.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Przykład: klasyfikacja wieloklasowa\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Na przykładzie rozpoznawania dyscypliny sportu: git://gonito.net/sport-text-classification.git\n", + "\n", + "Wczytujemy zbiór uczący:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'zimowe': 0,\n", + " 'moto': 1,\n", + " 'tenis': 2,\n", + " 'pilka-reczna': 3,\n", + " 'sporty-walki': 4,\n", + " 'koszykowka': 5,\n", + " 'siatkowka': 6,\n", + " 'pilka-nozna': 7}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import gzip\n", + "from pytorch_regression.analyzer import vectorize_text, vector_length\n", + "\n", + "texts = []\n", + "labels = []\n", + "labels_dic = {}\n", + "labels_revdic = {}\n", + "c = 0\n", + "\n", + "with gzip.open('sport-text-classification/train/train.tsv.gz', 'rt') as fh:\n", + " for line in fh:\n", + " line = line.rstrip('\\n')\n", + " line = line.replace('\\\\\\t', ' ')\n", + " label, text = line.split('\\t')\n", + " texts.append(text)\n", + " if label not in labels_dic:\n", + " labels_dic[label] =c\n", + " labels_revdic[c] = label\n", + " c += 1\n", + " labels.append(labels_dic[label])\n", + "nb_of_labels = len(labels_dic)\n", + "labels_dic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Przygotowujemy model:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.nn as nn\n", + "from torch import optim\n", + "\n", + "model = nn.Sequential(\n", + " nn.Linear(vector_length, nb_of_labels),\n", + " nn.LogSoftmax()\n", + " )\n", + "\n", + "optimizer = optim.Adam(model.parameters())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Funkcja kosztu to log-loss.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(2.3026)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "import torch.nn.functional as F\n", + "\n", + "loss_fn = torch.nn.NLLLoss()\n", + "\n", + "expected_class_id = torch.tensor([2])\n", + "loss_fn(torch.log(\n", + " torch.tensor([[0.3, 0.5, 0.1, 0.0, 0.1]])),\n", + " expected_class_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pętla ucząca:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/lib/python3.9/site-packages/torch/nn/modules/container.py:119: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " input = module(input)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0415690578520298 2.0784528255462646 0 0 tensor([[0.1251, 0.1250, 0.1249, 0.1248, 0.1250, 0.1251, 0.1252, 0.1249]],\n", + " grad_fn=) MŚ w hokeju: mocny początek Finów w Danii. Francja podniosła się po laniu od Rosjan Reprezentacja Finlandii po niepowodzeniach na ostatnich igrzyskach olimpijskich rozpoczęła dobrze tegoroczny turniej mistrzostw świata elity od pewnej wygranej z Koreą Południową. Francuzi zdobyli pierwsze punkty po pokonaniu Białorusi.\n", + "2.078942060470581 2.065171003341675 50 4 tensor([[0.1260, 0.1263, 0.1243, 0.1247, 0.1268, 0.1240, 0.1240, 0.1238]],\n", + " grad_fn=) Fotorelacja: Ważenie przed galą KSW 27 - Cage Time Prezentujemy fotorelację z oficjalnej ceremonii ważenia przed sobotnią galą KSW 27 - Cage Time.\n", + "2.06972599029541 2.1077024936676025 100 5 tensor([[0.1271, 0.1261, 0.1257, 0.1251, 0.1266, 0.1215, 0.1224, 0.1254]],\n", + " grad_fn=) Wisła podpisała swój najważniejszy kontrakt Gdyby nie firma Can-Pack S.A. nie byłoby w ostatnich latach wielkich sukcesów koszykarek z Krakowa. We wtorek ogłoszono przedłużenie umowy i koszykarki spod znaku Białej Gwiazdy nadal będą występować pod nazwą Wisła Can-Pack Kraków.\n", + "2.0650651454925537 2.0973997116088867 150 5 tensor([[0.1307, 0.1282, 0.1242, 0.1246, 0.1255, 0.1228, 0.1176, 0.1265]],\n", + " grad_fn=) Basket 90 znalazł nową podkoszową. W poprzednim sezonie grała w polskim klubie Nie trzeba było długo czekać na koszykarkę, która wypełni podkoszową lukę w Baskecie 90 Gdynia. Nową zawodniczką ekipy z Trójmiasta została Niemka Sonja Greinacher, która ostatni sezon spędziła w Wiśle CanPack Kraków.\n", + "2.0588021278381348 2.043689727783203 200 0 tensor([[0.1295, 0.1279, 0.1258, 0.1220, 0.1227, 0.1241, 0.1217, 0.1263]],\n", + " grad_fn=) Wicemistrzyni olimpijska zakończyła karierę Olga Wiłuchina podjęła decyzję o zakończeniu sportowej kariery. Największymi sukcesami rosyjskiej biathlonistki są dwa srebrne medale wywalczone na igrzyskach olimpijskich w Soczi.\n", + "2.0487422943115234 2.101975679397583 250 5 tensor([[0.1223, 0.1301, 0.1216, 0.1232, 0.1244, 0.1222, 0.1264, 0.1297]],\n", + " grad_fn=) Duże wzmocnienie reprezentacji Polski. Wraca Maciej Lampe Maciej Lampe dołączył już do reprezentacji Polski, która przygotowuje się do eliminacyjnych meczów z Litwą oraz Kosowem. 33-latek wraca do kadry po dwuletniej przerwie.\n", + "2.037230968475342 2.0833020210266113 300 5 tensor([[0.1307, 0.1343, 0.1224, 0.1174, 0.1203, 0.1245, 0.1220, 0.1284]],\n", + " grad_fn=) Kibice Celtów mogą spać spokojnie. Kyrie Irving planuje zostać w Bostonie Rozgrywający Boston Celtics, Kyrie Irving, przyznał, że w następne lato zamierza przedłużyć swoją umowę z klubem, o ile ten nadal będzie go uwzględniał w swoich planach.\n", + "2.036482095718384 2.0419692993164062 350 6 tensor([[0.1260, 0.1288, 0.1273, 0.1187, 0.1147, 0.1228, 0.1298, 0.1320]],\n", + " grad_fn=) We włoskiej Serie A nie ma żartów. Kolejny trener stracił posadę Brak cierpliwości włodarzy włoskich klubów charakteryzuje tegoroczne rozgrywki Serie A. Ostatnio z rolą szkoleniowca Exprivia Molfetta pożegnał się Vincenzo Di Pinto. Nie jest on pierwszym trenerem, który po 7. kolejce rozgrywek stracił posadę.\n", + "2.027297258377075 2.080472707748413 400 3 tensor([[0.1276, 0.1222, 0.1308, 0.1249, 0.1144, 0.1190, 0.1309, 0.1303]],\n", + " grad_fn=) Polska B rozpoczyna turniej w Płocku Od piątku do niedzieli w płockiej Orlen Arenie odbędzie się turniej z udziałem reprezentacji Polski B. Wezmą w nim też udział druga reprezentacja Danii, a także pierwsze kadry Wysp Owczych i Estonii.\n", + "2.007331371307373 2.0565202236175537 450 0 tensor([[0.1279, 0.1289, 0.1230, 0.1234, 0.1223, 0.1171, 0.1308, 0.1266]],\n", + " grad_fn=) Najpiękniesze polskie sportsmenki! Sprawdź kto znalazł się w zestawieniu! Przygotowaliśmy dla was zestawienie 20 najpiękniejszych polskich sportsmenek! Zgadzacie się z naszym wyborem? Swoje typy wpisujcie w komentarzach! Razem wybierzemy tę najładniejszą.\n", + "2.0114476680755615 1.9756197929382324 500 0 tensor([[0.1387, 0.1302, 0.1213, 0.1187, 0.1179, 0.1192, 0.1241, 0.1299]],\n", + " grad_fn=) Aleksander Zniszczoł został ojcem. Urodziła mu się córka Piątek był niezwykle ważnym dniem w życiu Aleksandra Zniszczoła. Polskiemu skoczkowi narciarskiemu urodziła się córka. Pochwalił się jej zdjęciem na Instagramie.\n", + "2.0088744163513184 2.0376784801483154 550 1 tensor([[0.1344, 0.1303, 0.1194, 0.1186, 0.1222, 0.1192, 0.1287, 0.1271]],\n", + " grad_fn=) Rajd Azorów: czołówka miała problemy. Łukjaniuk się broni Aleksiej Łukjaniuk pod nieobecność Kajetana Kajetanowicza obronił pozycję lidera klasyfikacji generalnej Rajdu Azorów. Do czołowej dziesiątki przebił się Łukasz Habaj.\n", + "1.996506929397583 2.0374131202697754 600 4 tensor([[0.1278, 0.1271, 0.1198, 0.1233, 0.1304, 0.1189, 0.1224, 0.1303]],\n", + " grad_fn=) Andrzej Kostyra: Ciosy muszą się kumulować Podczas sobotniej gali Tomasz Adamek zmierzy się z Arturem Szpilką. Andrzej Kostyra większe szanse daje temu pierwszemu, ale zauważa też pewne mankamenty.\n", + "1.9676146507263184 2.062831163406372 650 3 tensor([[0.1316, 0.1252, 0.1289, 0.1271, 0.1153, 0.1162, 0.1209, 0.1348]],\n", + " grad_fn=) IO 2016: skład Chorwacji na przygotowania do Rio. Na liście Lovro Mihić, Manuel Strlek i Ivan Cupić Chorwacki selekcjoner Żeljko Babić powołał kadrę na przygotowania do igrzysk olimpijskich w Rio de Janeiro. Na liście nazwisk nie zabrakło \"polskich\" akcentów. Na zgrupowanie pojadą Manuel Strlek, Lovro Mihić, Filip Ivić i Ivan Cupić.\n", + "1.9686769247055054 1.9732800722122192 700 2 tensor([[0.1150, 0.1331, 0.1390, 0.1131, 0.1125, 0.1158, 0.1246, 0.1468]],\n", + " grad_fn=) Andy Murray: Kostka boli, ale wszystko z nią w porządku W swoim felietonie dla BBC Andy Murray ocenił środowy pojedynek II rundy z Andriejem Rublowem i cieszył się z sukcesu Daniela Evansa w Australian Open 2017. Lider rankingu ATP przyznał, że z jego kostką jest wszystko w porządku.\n", + "1.975778341293335 1.8176090717315674 750 1 tensor([[0.1206, 0.1624, 0.1202, 0.1145, 0.1110, 0.1177, 0.1233, 0.1301]],\n", + " grad_fn=) Daniel Ricciardo sugeruje Red Bullowi wybór silnika Daniel Ricciardo przyznał, że patrząc na obecny rozwój jednostki napędowej Renault, byłby gotowy zaufać francuskiemu producentowi także w kolejnym sezonie F1.\n", + "1.9462422132492065 2.1149277687072754 800 3 tensor([[0.1257, 0.1381, 0.1296, 0.1206, 0.1066, 0.1248, 0.1234, 0.1312]],\n", + " grad_fn=) Kamil Mokrzki jako jedyny gracz Gwardii Opole dobił do granicy 100 goli 24-letni rozgrywający opolan był najlepszym strzelcem zespołu w sezonie 2015/2016. Drugiego w wewnętrznej klasyfikacji Antoniego Łangowskiego wyprzedził o 10 trafień.\n", + "1.976908564567566 2.0184948444366455 850 4 tensor([[0.1225, 0.1332, 0.1265, 0.1110, 0.1329, 0.1158, 0.1144, 0.1439]],\n", + " grad_fn=) Deontay Wilder rzucił wyzwanie Anthony'emu Joshui. \"Aż krew się we mnie gotuje!\" - Anthony Joshua to facet, z którym chcę walczyć - mówi Deontay Wilder. Mistrz świata organizacji WBC wyzwał Anglika na pojedynek i liczy na to, że ten potraktuje jego propozycję na poważnie.\n", + "1.9368045330047607 2.0249950885772705 900 2 tensor([[0.1283, 0.1323, 0.1320, 0.1175, 0.1187, 0.1193, 0.1178, 0.1341]],\n", + " grad_fn=) Ronaldo, Bouchard, Bolt. Gwiazdy sportu wybierają stroje na Halloween Znani sportowcy wzięli udział w zabawie w wymyślaniu kostiumów na wieczór halloweenowych szaleństw. Kto zaprezentował najbardziej oryginalne przebranie?\n", + "1.9382176399230957 1.9976595640182495 950 4 tensor([[0.1245, 0.1259, 0.1214, 0.1200, 0.1357, 0.1182, 0.1261, 0.1283]],\n", + " grad_fn=) Andrzej Kostyra stworzył \"idealnego polskiego boksera\". Jest dużo cech Tomasza Adamka Andrzej Kostyra, ekspert bokserski, stworzył model \"idealnego polskiego pięściarza\". Wymienił najlepsze cechy poszczególnych bokserów. Najwięcej jest Tomasza Adamka.\n", + "1.9289162158966064 1.93954336643219 1000 1 tensor([[0.1224, 0.1438, 0.1319, 0.1217, 0.1120, 0.1137, 0.1201, 0.1346]],\n", + " grad_fn=) Rajd Niemiec: Andreas Mikkelsen i Jari-Matti Latvala najszybsi na shakedown W czwartek kierowcy mieli do pokonania odcinek testowy przed Rajdem Niemiec. Na mecie okazało się, że Andreas Mikkelsen i Jari-Matti Latvala uzyskali identyczny czas.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.9244329929351807 1.9046193361282349 1050 4 tensor([[0.1264, 0.1245, 0.1287, 0.1161, 0.1489, 0.1108, 0.1173, 0.1274]],\n", + " grad_fn=) Była rywalka Joanny Jędrzejczyk na dopingu. Czeka ją zawieszenie Była pretendenta to tytułu mistrzyni UFC w wadze słomkowej, Jessica Penne (MMA 12-5) została zawieszona przez Amerykańską Agencję Antydopingową za stosowanie niedozwolonego środka. Amerykankę czeka 1,5-roczne zawieszenie.\n", + "1.9093575477600098 1.8683863878250122 1100 2 tensor([[0.1120, 0.1147, 0.1544, 0.1150, 0.1141, 0.1240, 0.1093, 0.1566]],\n", + " grad_fn=) Finał WTA Sydney: Radwańska - Konta na żywo. Transmisja TV, stream online W piątek Agnieszka Radwańska zmierzy się z Johanną Kontą w ramach finału WTA Sydney. Transmisja TV na antenie TVP 1 i TVP Sport. Stream online w sport.tvp.pl.\n", + "1.9156808853149414 1.9488784074783325 1150 7 tensor([[0.1212, 0.1255, 0.1152, 0.1314, 0.1246, 0.1175, 0.1223, 0.1424]],\n", + " grad_fn=) Piękne zachowanie piłkarza Borussii. Pomógł kibicowi Takim zachowaniem piłkarze zyskują ogromny szacunek u kibiców. Christian Pulisić uratował fana, którym podczas próby zrobienia wspólnego zdjęcia z zawodnikiem Borussii Dortmund zajęła się ochrona.\n", + "1.865915060043335 2.0229783058166504 1200 4 tensor([[0.1118, 0.1370, 0.1273, 0.1281, 0.1323, 0.1156, 0.1209, 0.1271]],\n", + " grad_fn=) W przyszłym roku dojdzie do walki Joshua - Kliczko. \"Umowa jest dogadana\" Po fiasku wcześniejszych negocjacji wreszcie osiągnięto porozumienie. W przyszłym roku Anthony Joshua zmierzy się z Władimirem Kliczką, a w stawce będą dwa pasy mistrzowskie - informują menadżerowie obu pięściarzy. Został tylko jeden warunek.\n", + "1.8945144414901733 1.8897364139556885 1250 4 tensor([[0.1133, 0.1289, 0.1184, 0.1151, 0.1511, 0.1224, 0.1233, 0.1275]],\n", + " grad_fn=) MMA: Bartosz Fabiński zasila powracającą Fighters Arenę Bartosz Fabiński wystąpi na gali Fighters Arena 9, która 8 czerwca odbędzie się w Józefowie. Dla zawodnika z Warszawy będzie to już czwarta walka w tym roku.\n", + "1.8801826238632202 1.9434046745300293 1300 7 tensor([[0.1161, 0.1170, 0.1131, 0.1465, 0.1035, 0.1276, 0.1331, 0.1432]],\n", + " grad_fn=) Oficjalnie: Polski mecz w Serie A! Godzinę przed pierwszym gwizdkiem (20:45) meczu między Sampdorią, a Napoli potwierdziły się doniesienia włoskiej prasy. Po raz pierwszy w obecnym sezonie to samo spotkanie Serie A rozpocznie w wyjściowej jedenastce aż 4 polskich piłkarzy.\n", + "1.8571587800979614 1.7821911573410034 1350 1 tensor([[0.1144, 0.1683, 0.1177, 0.1231, 0.1154, 0.1158, 0.1183, 0.1272]],\n", + " grad_fn=) Bernie Ecclestone: Ferrari ma lepszy bolid Zdaniem Berniego Ecclestone'a, sezon 2017 będzie należeć do Ferrari. Włoski zespół ma spore szanse na pierwszy mistrzowski tytuł wśród konstruktorów od wielu lat.\n", + "1.8645442724227905 1.7102112770080566 1400 1 tensor([[0.1178, 0.1808, 0.1133, 0.1189, 0.1132, 0.1201, 0.1122, 0.1236]],\n", + " grad_fn=) Sauber potwierdza brak Pascala Wehrleina na testach. Kto go zastąpi? Po czwartkowych medialnych doniesieniach, w piątek zespół Sauber F1 Team oficjalnie potwierdził, iż Pascal Wehrlein opuści pierwszą turę przedsezonowych testów pod Barceloną.\n", + "1.8554599285125732 1.6869465112686157 1450 6 tensor([[0.1019, 0.1060, 0.1191, 0.1386, 0.0958, 0.1353, 0.1851, 0.1181]],\n", + " grad_fn=) Polski Cukier Muszynianka Enea - Giacomini Budowlani: przełamać pasmo porażek W 7. kolejce Orlen Ligi siatkarki Polskiego Cukru Muszynianki Enea Muszyna podejmą Giacomini Budowlani Toruń. Przyjezdne w czterech ostatnich meczach rozgrywek nie wygrały nawet seta i tą złą serię chcą przerwać w Małopolsce.\n", + "1.8279104232788086 1.714797019958496 1500 6 tensor([[0.1144, 0.1189, 0.1099, 0.1389, 0.0904, 0.1316, 0.1800, 0.1159]],\n", + " grad_fn=) Przyjmująca zostaje w Toruniu. Budowlani zamknęli skład W sezonie 2017/2018 Orlen Ligi w Budowlanych Toruń nadal będzie występować Marina Paulava. Ta siatkarka zamknęła skład zespołu.\n", + "1.8161158561706543 1.6653008460998535 1550 7 tensor([[0.1023, 0.1056, 0.1212, 0.1180, 0.1061, 0.1216, 0.1361, 0.1891]],\n", + " grad_fn=) Borussia Dortmund - Red Bull Salzburg na żywo. Transmisja TV, stream online W czwartek, w ramach 1/8 finału Ligi Europy, odbędzie się mecz Borussia Dortmund - Red Bull Salzburg. Transmisja TV na antenie Eurosport 1. Stream online na platformie Eurosport Player i Ipla TV. Relacja LIVE w WP SportoweFakty.\n", + "1.8106026649475098 1.7794651985168457 1600 0 tensor([[0.1687, 0.1026, 0.1228, 0.1103, 0.1031, 0.1189, 0.1177, 0.1559]],\n", + " grad_fn=) PŚ w Lahti: konkurs drużynowy na żywo. Transmisja TV, stream online za darmo W sobotę, w ramach Pucharu Świata w skokach narciarskich w Lahti odbędzie się konkurs drużynowy. Transmisja TV na antenie TVP 1 i Eurosport. Stream online za darmo w WP Pilot. Relacja LIVE w WP SportoweFakty.\n", + "1.8139138221740723 1.8474551439285278 1650 5 tensor([[0.0952, 0.1068, 0.1138, 0.1381, 0.1080, 0.1576, 0.1367, 0.1438]],\n", + " grad_fn=) Panathinaikos ma dość Euroligi. Wielki klub chce się wycofać z rozgrywek! Koszykarska Euroliga bez Panathinaikosu Ateny? To bardzo możliwy scenariusz. Właściciel klubu - Dimitrios Giannakopoulos - zapowiedział wycofanie drużyny ze stolicy Grecji z elitarnych rozgrywek.\n", + "1.7931458950042725 1.8012076616287231 1700 4 tensor([[0.1271, 0.1361, 0.1166, 0.1189, 0.1651, 0.1104, 0.0992, 0.1267]],\n", + " grad_fn=) Tomasz Adamek wrócił na salę treningową. Zobacz, w jakiej formie jest \"Góral\" (wideo) Coraz więcej wskazuje na to, że Tomasz Adamek raz jeszcze powróci na ring. Były mistrz świata kategorii półciężkiej i junior ciężkiej regularnie pojawia się na sali treningowej. W jakiej formie jest 40-latek?\n", + "1.7960119247436523 1.8428459167480469 1750 0 tensor([[0.1584, 0.1005, 0.1063, 0.1628, 0.1017, 0.1219, 0.1320, 0.1165]],\n", + " grad_fn=) 18 zawodników w finskiej kadrze. Aino-Kaisa Saarinen poza reprezentacją Finowie ogłosili skład reprezentacji na nadchodzący Puchar Świata w biegach narciarskich. W drużynie znalazło się 8 zawodniczek i 10 zawodników.\n", + "1.807226300239563 1.7165520191192627 1800 4 tensor([[0.1068, 0.1123, 0.1059, 0.1050, 0.1797, 0.1230, 0.1325, 0.1348]],\n", + " grad_fn=) FEN 19: karta walk skompletowana Znamy ostatnie, dziesiąte zestawienie na gali Fight Exclusive Night 19 \"Bitwa o Wrocław\". W kategorii do 70 kilogramów w formule K-1 zmierzą się ze sobą Marcin Stopka (2-2) i Krzysztof Kottas (0-0).\n", + "1.812751293182373 1.8602548837661743 1850 1 tensor([[0.1217, 0.1556, 0.1244, 0.1248, 0.1093, 0.1198, 0.1167, 0.1277]],\n", + " grad_fn=) Rajd Nadwiślański: Grzegorz Grzyb Liderem Grzegorz Grzyb i Robert Hundla zostali liderami Rajdu Nadwiślańskiego po przejechaniu dwóch sobotnich odcinków specjalnych.\n", + "1.8123970031738281 2.012942314147949 1900 3 tensor([[0.1353, 0.1215, 0.1276, 0.1336, 0.1160, 0.1320, 0.1176, 0.1163]],\n", + " grad_fn=) Bundesliga: Berlińskie TGV. Kolejna stacja w Hanowerze Füchse Berlin w niedzielę powalczy w Hanowerze o dziewiąte kolejne zwycięstwo w sezonie. Takiego otwarcia „Lisy” nie miały jeszcze nigdy. Z kolei wieczorem polski pojedynek w Magdeburgu: Piotr Chrapkowski vs Andrzej Rojewski. Oba mecze w Sportklubie.\n", + "1.803969383239746 1.9510834217071533 1950 4 tensor([[0.1261, 0.1341, 0.1076, 0.1294, 0.1421, 0.1202, 0.1165, 0.1240]],\n", + " grad_fn=) Utytułowany pięściarz zakończył karierę Czterokrotny obrońca tytułu mistrza świata kategorii super średniej Mikkel Kessler ogłosił zakończenie kariery pięściarskiej. To najbardziej utytułowany zawodnik w historii duńskiego boksu.\n", + "1.7355947494506836 1.9419602155685425 2000 6 tensor([[0.1116, 0.0959, 0.1303, 0.1196, 0.1004, 0.1257, 0.1434, 0.1731]],\n", + " grad_fn=) KMŚ 2017: ZAKSA - Sarmayeh Bank Teheran na żywo. Gdzie oglądać transmisję TV i online? We wtorek, ZAKSA Kędzierzyn-Koźle zmierzy się z Sarmayeh Bank Teheran w ramach Klubowych Mistrzostw Świata w siatkówce. Transmisja TV na antenie Polsat Sport. Stream online w Ipla TV. Relacja LIVE w WP SportoweFakty za darmo.\n", + "1.7900081872940063 1.9909334182739258 2050 1 tensor([[0.1211, 0.1366, 0.1348, 0.1286, 0.1105, 0.1252, 0.1181, 0.1251]],\n", + " grad_fn=) Wakacyjny freestyle Przygońskiego i Pawlusiaka na pustyni Pędzące po wydmach dakarowe MINI, specjalnie dostosowany snowboard, lina i dwóch utalentowanych sportowców - tak w skrócie można opisać projekt \"Przygoński & Pawlusiak Dune Freestyle\".\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.732917308807373 1.869311809539795 2100 5 tensor([[0.1091, 0.1430, 0.1048, 0.1265, 0.1092, 0.1542, 0.1102, 0.1428]],\n", + " grad_fn=) Martynas Sajus: Sobin jest bardziej doświadczonym graczem, ale w przyszłości będę od niego lepszy Pojedynek Josipa Sobina z Martynasem Sajusem może być jednym ze smaczków piątkowego spotkania Anwilu z Polpharmą. Który ze środkowych da więcej swojej ekipie? - On jest bardziej doświadczony, ale w przyszłości to ja będę lepszy - śmieje się Sajus.\n", + "1.7519197463989258 1.5113999843597412 2150 2 tensor([[0.0979, 0.1257, 0.2206, 0.1103, 0.1044, 0.1174, 0.1050, 0.1187]],\n", + " grad_fn=) Łukasz Iwanek: Każda tenisistka może być Williams, nie każda może zostać Radwańską (komentarz) W II rundzie Australian Open najlepsza polska tenisistka została stłamszona przez rywalkę uderzającą szybko i celnie. Każda tenisistka może w pojedynczym meczu zostać Sereną Williams, nie każda może być Agnieszką Radwańską.\n", + "1.7391284704208374 1.7576707601547241 2200 5 tensor([[0.1100, 0.0950, 0.1158, 0.1438, 0.0986, 0.1724, 0.1352, 0.1291]],\n", + " grad_fn=) Kolejny występ Przemysława Karnowskiego w Lidze Letniej NBA Kolejny występ w rozgrywkach Ligi Letniej NBA zanotował Przemysław Karnowski. Polak, który reprezentuje Charlotte Hornets, w przegranym meczu z Indianą Pacers (77:84) zdobył cztery punkty i miał trzy zbiórki.\n", + "1.6613290309906006 1.5939650535583496 2250 1 tensor([[0.1039, 0.2031, 0.1056, 0.1095, 0.1230, 0.1114, 0.1109, 0.1326]],\n", + " grad_fn=) Niebieskie flagi mogą zniknąć z F1 Formuła 1 rozważa, czy nie zrezygnować ze stosowania niebieskich flag podczas wyścigu. W ostatnich sezonach kierowcy często narzekali, iż rywale nie stosowali się do takiej sygnalizacji.\n", + "1.6618765592575073 1.8819133043289185 2300 5 tensor([[0.1059, 0.1279, 0.1030, 0.1496, 0.1200, 0.1523, 0.1245, 0.1168]],\n", + " grad_fn=) Nemanja Jaramaz nowym zawodnikiem Anwilu Włocławek! Doskonale znany na polskich parkietach z występów w drużynie ze Zgorzelca Nemanja Jaramaz został nowym zawodnikiem Anwilu Włocławek. Kontrakt z Serbem będzie obowiązywał do końca bieżącego sezonu.\n", + "1.7553699016571045 1.767181396484375 2350 5 tensor([[0.1026, 0.1128, 0.1074, 0.1354, 0.1201, 0.1708, 0.1244, 0.1264]],\n", + " grad_fn=) TOP5 zagrań minionej nocy NBA (wideo) 3 mecze odbyły się w nocy z wtorku na środę w NBA, dlatego liga miała mniejszy wybór do zestawienia najlepszych akcji. Na czele listy TOP5 zagrań znalazły się rzuty z elektryzującej końcówki spotkania Dallas Mavericks-Portland Trail Blazers.\n", + "1.7372195720672607 1.911428689956665 2400 2 tensor([[0.1144, 0.1585, 0.1479, 0.1187, 0.1099, 0.1224, 0.1075, 0.1208]],\n", + " grad_fn=) Roger Federer będzie występował w Bazylei aż do 2019 roku Roger Federer potwierdził, że na pewno do sezonu 2019 będzie występował w turnieju Swiss Indoors Basel, który jest organizowany pod koniec października w jego rodzinnej miejscowości.\n", + "1.6716208457946777 1.7947263717651367 2450 4 tensor([[0.1103, 0.1306, 0.1188, 0.1233, 0.1662, 0.1171, 0.1099, 0.1239]],\n", + " grad_fn=) Łukasz Wichowski przed DSF Kickboxing Challenge: Będzie ciężka walka i duże widowisko Już w sobotę odbędzie się gala DSF Kickboxing Challenge: Bitwa w Piasecznie. Walką wieczoru będzie starcie Łukasza Wichowskiego z Piotrem Kołakowskim. - To dodatkowa mobilizacja - mówi Wichowski.\n", + "1.6898037195205688 1.8188705444335938 2500 5 tensor([[0.1094, 0.1339, 0.1127, 0.1308, 0.1144, 0.1622, 0.1076, 0.1290]],\n", + " grad_fn=) Specjaliści od dzikich kart. Co GTK Gliwice może wnieśc do PLK? GTK Gliwice prawdopodobnie będzie 17. zespołem w ekstraklasie. Przybliżamy sylwetkę ekipy ze Śląska, dla której gra w PLK będzie absolutnym debiutem.\n", + "1.6765027046203613 1.7608693838119507 2550 7 tensor([[0.1264, 0.1094, 0.1139, 0.1419, 0.1052, 0.1027, 0.1286, 0.1719]],\n", + " grad_fn=) Agent Oezila przerywa milczenie i oskarża reprezentantów Niemiec Erkut Sogut, agent Mesuta Oezila przemówił na temat zakończenia kariery reprezentacyjnej przez pomocnika. Oberwało się trzem reprezentantom Niemiec.\n", + "1.6664674282073975 1.6870511770248413 2600 5 tensor([[0.0995, 0.1290, 0.0842, 0.1347, 0.1221, 0.1851, 0.1054, 0.1400]],\n", + " grad_fn=) NBA: ci koszykarze nie mają jeszcze kontraktu Dobiega końca lipiec, a wciąż bez kontraktów na kolejny sezon pozostaje kilku zawodników o znanych nazwiskach. Najbardziej znany to oczywiście LeBron James, ale on akurat lada moment ma podpisać nową umowę z Cleveland Cavaliers.\n", + "1.66078519821167 1.0688396692276 2650 2 tensor([[0.0996, 0.0816, 0.3434, 0.1018, 0.0990, 0.0843, 0.0997, 0.0906]],\n", + " grad_fn=) ATP Toronto: Tuzin zwycięstw nad Gaelem Monfilsem. Novak Djoković zmierza po kolejne trofeum Novak Djoković powalczy w niedzielę z Keiem Nishikorim o triumf w turnieju ATP World Tour Masters 1000 na kortach twardych w Toronto. W sobotnim półfinale Serb pewnie rozprawił się z Gaelem Monfilsem, zwyciężając Francuza 6:3, 6:2.\n", + "1.6436724662780762 1.9171333312988281 2700 6 tensor([[0.1121, 0.1252, 0.0957, 0.1340, 0.1205, 0.1321, 0.1470, 0.1334]],\n", + " grad_fn=) Joanna Wołosz: Mamy prawo do małego dołka Chemik Police poniósł trzecią ligową porażkę, tym razem ze zdecydowanie niżej notowanym Atomem Trefl Sopot. Kryzys mistrza Polski? Joanna Wołosz uspokaja zaniepokojonych kibiców.\n", + "1.6387537717819214 2.009342670440674 2750 4 tensor([[0.1320, 0.1551, 0.1222, 0.1034, 0.1341, 0.1161, 0.1032, 0.1340]],\n", + " grad_fn=) Legenda MMA czuje się jak wrak człowieka. Przeszedł 22 operacje Po raz pierwszy trafił na stół operacyjny jako dziecko. Antonio Rodrigo Nogueira wpadł pod koła ciężarówki, walczył o życie. Później musiał poddawać się zabiegom po kontuzjach odniesionych na treningach i w walkach. - Jestem cały rozbity - przyznaje.\n", + "1.6333057880401611 1.2051695585250854 2800 2 tensor([[0.1204, 0.1072, 0.2996, 0.1030, 0.0922, 0.0858, 0.0877, 0.1041]],\n", + " grad_fn=) Ostatni sprawdzian Kamila Majchrzaka przed Rolandem Garrosem. Polak zagra w Niemczech Kamil Majchrzak weźmie udział w turnieju ATP Challenger Tour na kortach ziemnych w niemieckim Heilbronn. Dla Polaka będzie to ostatni sprawdzian przed eliminacjami do wielkoszlemowego Rolanda Garrosa 2018.\n", + "1.627921462059021 1.3342788219451904 2850 7 tensor([[0.1052, 0.0826, 0.1170, 0.1082, 0.0921, 0.1132, 0.1185, 0.2633]],\n", + " grad_fn=) Real Sociedad - Atletico Madryt na żywo. Gdzie oglądać transmisję TV i stream online? W czwartek, w ramach Primera Division, odbędzie się spotkanie Real Sociedad - Atletico Madryt. Transmisja TV na antenie Eleven Sports 1. Stream online w WP Pilot. Relacja LIVE w WP SportoweFakty.\n", + "1.6219871044158936 1.3970237970352173 2900 1 tensor([[0.1192, 0.2473, 0.1046, 0.0930, 0.0986, 0.1155, 0.1034, 0.1184]],\n", + " grad_fn=) Williams został w tyle za rywalami. \"Nie odrobiliśmy swojej pracy domowej\" Problemy Williamsa w tym sezonie zdają się nie mieć końca. Paddy Lowe jest zdania, że na sytuację wpływa zacięta rywalizacja w Formule 1. - Obecnie każdy z zespołów funkcjonuje na bardzo wysokim poziomie - twierdzi Brytyjczyk.\n", + "1.6522719860076904 1.618353247642517 2950 5 tensor([[0.1019, 0.1230, 0.0985, 0.1354, 0.1012, 0.1982, 0.1130, 0.1287]],\n", + " grad_fn=) Basket 90 Gdynia zamknął \"zagraniczną\" kadrę na nowy sezon Basket 90 Gdynia zakończył poszukiwania zawodniczek zagranicznych na sezon 2016/2017. Ostatnią koszykarką spoza granic naszego kraju, która związała się z ekipą z Trójmiasta, jest Litwinka Monika Grigalauskyte.\n", + "1.637782096862793 1.4863955974578857 3000 3 tensor([[0.0879, 0.0816, 0.1089, 0.2262, 0.0699, 0.1200, 0.1660, 0.1395]],\n", + " grad_fn=) Liga Mistrzów: Paris Saint-Germain HB kolejnym uczestnikiem Final Four Paris Saint-Germain HB zremisował z MOL-Pickiem Szeged 30:30 w rewanżowym meczu ćwierćfinałowym Ligi Mistrzów 2016/2017, tym samym zdobywając awans do turnieju finałowego w Kolonii.\n", + "1.619870662689209 1.955154538154602 3050 5 tensor([[0.0999, 0.1600, 0.1024, 0.1031, 0.1241, 0.1415, 0.1173, 0.1517]],\n", + " grad_fn=) Chewbacca ma nową twarz. Jak koszykarz z Finlandii trafił do \"Gwiezdnych Wojen\" Zbliżający się weekend będzie tym, w którym miliony fanów \"Gwiezdnych Wojen\" zaczną szturmować kina, by obejrzeć 8. część sagi. Wielu z nich nie wie, że za maską Chewbakki od niedawna skrywa się nowa twarz - fińskiego koszykarza, Joonasa Suotamo.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.6506901979446411 1.7881494760513306 3100 7 tensor([[0.1112, 0.1332, 0.0891, 0.1127, 0.1326, 0.1294, 0.1245, 0.1673]],\n", + " grad_fn=) Ireneusz Mamrot liczy na przełamanie. \"Jest sportowa złość, która musi się przełożyć na naszą korzyść\" - Nie ma zdenerwowania, ale jest duża sportowa złość. To musi się przełożyć na naszą korzyść - mówi przed sobotnim pojedynkiem z Koroną Kielce trener Jagiellonii Białystok, Ireneusz Mamrot. - Nie można wiecznie mieć gorszego okresu - dodaje.\n", + "1.508833408355713 1.5515254735946655 3150 2 tensor([[0.1030, 0.1194, 0.2119, 0.1182, 0.1020, 0.1099, 0.1084, 0.1272]],\n", + " grad_fn=) Roland Garros: bogaty program gier na środę. Matkowski czeka na dokończenie meczu z braćmi Bryanami Przez ostatnie dwa dni tenisiści niemal nie rywalizowali na kortach Rolanda Garrosa. Plan gier na 11. dzień turnieju jest naprawdę bogaty.\n", + "1.6437448263168335 1.6302305459976196 3200 4 tensor([[0.0948, 0.1278, 0.1326, 0.1141, 0.1959, 0.1060, 0.1182, 0.1106]],\n", + " grad_fn=) Deontaya Wildera czekają dwie operacje. Na ring wróci w 2017 roku Deontay Wilder bez problemów pokonał Chrisa Arreolę w Birmingham i obronił pas mistrza świata federacji WBC. Podczas pojedynku \"Brązowy Bombardier\" nabawił się jednak dwóch kontuzji, które na dłuższy okres wykluczą go z walk.\n", + "1.4642627239227295 1.6695131063461304 3250 5 tensor([[0.0890, 0.0942, 0.0919, 0.1390, 0.1155, 0.1883, 0.1545, 0.1275]],\n", + " grad_fn=) Sfrustrowany Tweety Carter: Powinienem zatrzymać Irelanda W ramach 20. kolejki PLK PGE Turów przegrał na własnym parkiecie z Treflem Sopot 79:81. - To bardzo, bardzo frustrująca porażka - mówi Tweety Carter, który zawiódł w ostatniej minucie tego starcia.\n", + "1.6304278373718262 1.61961829662323 3300 1 tensor([[0.1347, 0.1980, 0.1101, 0.1148, 0.1029, 0.1226, 0.1072, 0.1097]],\n", + " grad_fn=) Rajd Estonii: Kajetanowicz utrzymuje podium Polska załoga Kajetan Kajetanowicz - Jarosław Baran jest coraz bliżej sięgnięcia po kolejne podium w wyścigach ERC. Po pewne zwycięstwo w Rajdzie Estonii zmierza Aleksiej Łukjaniuk.\n", + "1.5721299648284912 1.6800715923309326 3350 5 tensor([[0.0974, 0.1165, 0.1068, 0.1207, 0.0953, 0.1864, 0.1084, 0.1685]],\n", + " grad_fn=) Basket Poznań wrócił na właściwe tory? \"Do stacji końcowej jeszcze daleka droga\" I-ligowy Biofarm Basket Poznań jest projektem, który skupia wokół siebie wielu młodych graczy. W zespole możemy znaleźć także dwóch doświadczonych zawodników, a jednym z nich jest Tomasz Smorawiński.\n", + "1.5134963989257812 1.3521889448165894 3400 4 tensor([[0.1069, 0.1058, 0.1011, 0.1071, 0.2587, 0.1109, 0.1051, 0.1044]],\n", + " grad_fn=) Łukasz Rambalski i Wojciech Wierzbicki w karcie walk gali FEN 10 Do ciekawej walki dojdzie na gali FEN 10, 9 stycznia w Lubinie. Jeden z najbardziej utytułowanych polskich zawodników kickboxingu, Łukasz Rambalski, zmierzy się z aktualnym zawodowym mistrzem Europy organizacji WAKO-PRO, Wojciechem Wierzbickim.\n", + "1.549106478691101 1.571334958076477 3450 5 tensor([[0.0968, 0.0769, 0.1763, 0.1565, 0.0749, 0.2078, 0.1182, 0.0928]],\n", + " grad_fn=) Świetny mecz Marcina Sroki. Sokół z Pogonią w finale turnieju w Prudniku Marcin Sroka zdobył 25 punktów i poprowadził Max Elektro Sokół Łańcut do zwycięstwa 95:69 nad BK NH Ostrava. W drugim półfinale międzynarodowego koszykarskiego turnieju w Prudniku gospodarze pokonali Jamalex Polonię 1912 Leszno.\n", + "1.5032646656036377 1.6780941486358643 3500 1 tensor([[0.1183, 0.1867, 0.1078, 0.1018, 0.1283, 0.1219, 0.1093, 0.1259]],\n", + " grad_fn=) Niki Lauda wspomina Jamesa Hunta. \"Jego cząstka żyje we mnie\" Przed laty rywalizacja Nikiego Laudy i Jamesa Hunta emocjonowała kibiców Formuły 1. Austriaka i Brytyjczyka, choć na torze byli rywalami, połączyła specjalna więź. - Jakaś cząstka Jamesa żyje teraz we mnie - mówi Lauda.\n", + "1.4585016965866089 1.3136595487594604 3550 1 tensor([[0.1022, 0.2688, 0.1059, 0.0846, 0.1267, 0.0953, 0.0952, 0.1213]],\n", + " grad_fn=) Eksperci o słowach Felipe Massy. \"Sam wykluczył się z walki o miejsce w Williamsie\" Felipe Massa w ostrych słowach skomentował możliwy powrót Roberta Kubicy do Formuły 1. - Wygląda na to, że Brazylijczyk sam wykluczył się z walki o miejsce w Williamsie - twierdzi Tiff Needell, były prowadzący \"Top Gear\".\n", + "1.634122371673584 1.5287344455718994 3600 3 tensor([[0.1117, 0.0900, 0.0921, 0.2168, 0.0921, 0.1187, 0.1387, 0.1400]],\n", + " grad_fn=) AMŚ: pierwsza wygrana Biało-Czerwonych. Polska rozbiła Chińskie Tajpej Reprezentacja Polski piłkarzy ręcznych odniosła pierwsze zwycięstwo na Akademickich Mistrzostwach Świata. Drużyna Piotra Przybeckiego zgodnie z oczekiwaniami pokonała Chińskie Tajpej (35:20).\n", + "1.4305871725082397 0.677993655204773 3650 2 tensor([[0.0742, 0.0567, 0.5076, 0.0746, 0.0622, 0.0691, 0.0898, 0.0657]],\n", + " grad_fn=) ATP Tokio: Kei Nishikori wygrał japońskie starcie. W II rundzie także Milos Raonić i Denis Shapovalov Faworyt gospodarzy Kei Nishikori w dwóch setach pokonał Yuichiego Sugitę w I rundzie rozgrywanego na kortach twardych w hali turnieju ATP World Tour 500 w Tokio. Do 1/8 finału awansowali też Kanadyjczycy - Milos Raonić i Denis Shapovalov.\n", + "1.5231139659881592 1.5078407526016235 3700 2 tensor([[0.1061, 0.1268, 0.2214, 0.0988, 0.0971, 0.1361, 0.1114, 0.1024]],\n", + " grad_fn=) James Blake jak Tommy Haas czy Feliciano Lopez. Został dyrektorem turnieju w Miami Organizatorzy turnieju Miami Open ogłosili, że nowym dyrektorem tych kobiecych i męskich zawodów został były amerykański tenisista, James Blake. Tym samym potwierdziły się medialne doniesienia z ostatnich tygodni.\n", + "1.4987030029296875 1.3921600580215454 3750 7 tensor([[0.1257, 0.0679, 0.0981, 0.1364, 0.0642, 0.1028, 0.1564, 0.2485]],\n", + " grad_fn=) Mundial 2018. Historyczny wyczyn reprezentacji Rosji! Takiego pogromu w meczu otwarcia jeszcze nie było Na inaugurację MŚ 2018 Rosja pokonała Arabię Saudyjską aż 5:0 i ustanowiła nowy rekord mundialu - nigdy wcześniej w meczu otwarcia mistrzostw świata nie padł tak wysoki wynik.\n", + "1.4943546056747437 1.572141408920288 3800 3 tensor([[0.1084, 0.1078, 0.1184, 0.2076, 0.0941, 0.1287, 0.1333, 0.1016]],\n", + " grad_fn=) Wojciech Gumiński odnalazł się w Azotach. \"Start w nowym klubie bywa trudny\" Przeciętny początek rozgrywek i znacznie lepsza druga połowa sezonu. Wojciech Gumiński zaczyna spełniać oczekiwania w Azotach Puławy, stał się czołowym strzelcem brązowych medalistów PGNiG Superligi.\n", + "1.497003436088562 1.9663035869598389 3850 2 tensor([[0.1422, 0.1162, 0.1400, 0.1578, 0.1107, 0.1187, 0.1132, 0.1012]],\n", + " grad_fn=) Rio 2016. To nie są igrzyska faworytów Tenisowe turnieje olimpijskie rządzą się swoimi prawami i wielkie niespodzianki są w nich na porządku dziennym, ale chyba mało kto przypuszczał, że w Rio de Janeiro dojdzie do aż tylu niespodziewanych rozstrzygnięć.\n", + "1.4387949705123901 1.7787644863128662 3900 5 tensor([[0.1041, 0.0926, 0.1015, 0.1573, 0.0961, 0.1688, 0.1598, 0.1197]],\n", + " grad_fn=) Niezawodny Klima, szalejący Obarek. Najlepsi gracze 18. kolejki I ligi Marcin Dymała oraz Maciej Klima to stali bywalce w naszym rankingu. Którzy zawodnicy znaleźli się jeszcze w najlepszej piątce 18. kolejki?\n", + "1.484657883644104 1.4367222785949707 3950 4 tensor([[0.0838, 0.1276, 0.1142, 0.1065, 0.2377, 0.1056, 0.1090, 0.1156]],\n", + " grad_fn=) Czołowy brytyjski pięściarz zaproponował pojedynek Tomaszowi Adamkowi Tomasz Adamek otrzymał propozycję walki z Davidem Pricem. Jak poinformował portal worldboxingnews.net, obóz brytyjskiego pięściarza złożył \"Góralowi\" atrakcyjną ofertę.\n", + "1.4598438739776611 1.393087387084961 4000 7 tensor([[0.0934, 0.1558, 0.0804, 0.0927, 0.1255, 0.1069, 0.0970, 0.2483]],\n", + " grad_fn=) Grzegorz Krychowiak na zakręcie. Mundial to ostatnia szansa Grzegorz Krychowiak znowu jest na zakręcie i musi szukać nowego klubu. Paris-Saint Germain chce się pozbyć Polaka na dobre. Mundial w Rosji to dla mistrzów Francji ostatnia szansa, żeby sprzedać go za godne pieniądze.\n", + "1.457613229751587 1.5666451454162598 4050 6 tensor([[0.0992, 0.1111, 0.0903, 0.1400, 0.0904, 0.1379, 0.2087, 0.1223]],\n", + " grad_fn=) ZAKSA Kędzierzyn-Koźle trenuje już niemal w komplecie Na początku tygodnia do kędzierzyńskiej drużyny dołączyli zawodnicy, którzy brali udział w mistrzostwach Europy. Wyjątkiem jest francuski rozgrywający Benjamin Toniutti.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.5241613388061523 1.2555674314498901 4100 1 tensor([[0.0736, 0.2849, 0.0687, 0.0741, 0.1105, 0.1044, 0.1124, 0.1713]],\n", + " grad_fn=) Krzysztof Hołowczyc trzyma kciuki za Kubicę. \"Ci, którzy nie chcą jego powrotu, po prostu się go boją\" Trwa walka Roberta Kubicy o powrót do Formuły 1. Polak jest jednym z kandydatów do reprezentowania w przyszłym sezonie barw zespołu Williams. Za Kubicę kciuki trzyma Krzysztof Hołowczyc.\n", + "1.4491897821426392 1.4376769065856934 4150 1 tensor([[0.1067, 0.2375, 0.1000, 0.0920, 0.1161, 0.1186, 0.1079, 0.1212]],\n", + " grad_fn=) Honda znów ma problem z silnikiem. \"Musimy znaleźć główną przyczynę niepowodzeń\" Honda po raz kolejny ma problemy ze swoim silnikiem. Japończycy uważają jednak, że w przypadku Brendona Hartleya we Francji doszło do innej usterki niż w jednostce napędowej Pierre'a Gasly'ego w Kanadzie.\n", + "1.5472668409347534 1.088613748550415 4200 2 tensor([[0.0726, 0.0993, 0.3367, 0.0966, 0.0821, 0.1155, 0.1074, 0.0897]],\n", + " grad_fn=) Jelena Janković marzy o drugim tygodniu Wimbledonu. We wtorek Serbka zagra z Agnieszką Radwańską Jelena Janković chciałaby dojść do drugiego tygodnia Wimbledonu 2017. Serbka będzie rywalką Agnieszki Radwańskiej w I rundzie.\n", + "1.4705555438995361 1.9431947469711304 4250 4 tensor([[0.1108, 0.1164, 0.1035, 0.1276, 0.1432, 0.1303, 0.1392, 0.1290]],\n", + " grad_fn=) Kontrowersyjny klub MMA w Chinach. Walczą 12-letnie dzieci W Enbo Fight Club trenuje nawet 400 młodych ludzi. Część z nich stanowią osierocone dzieci. Działalność klubu wywołuje spore emocje w Chinach.\n", + "1.43092679977417 0.8142336010932922 4300 1 tensor([[0.1201, 0.4430, 0.0652, 0.0700, 0.0814, 0.0788, 0.0731, 0.0684]],\n", + " grad_fn=) MotoGP: Marc Marquez najlepszy w ostatnim treningu Marc Marquez wygrał ostatnią sesję treningową przed wyścigiem o Grand Prix Ameryk na torze w Austin. Kolejne pozycje zajęli Dani Pedrosa oraz Maverick Vinales.\n", + "1.4218653440475464 1.5884473323822021 4350 3 tensor([[0.0741, 0.1260, 0.0926, 0.2042, 0.1069, 0.1427, 0.1266, 0.1269]],\n", + " grad_fn=) Rafał Przybylski odchodzi z Azotów Puławy. Kierunek - zagranica Rafał Przybylski po zakończeniu sezonu 2016/17 odejdzie z Azotów Puławy. 25-letni prawy rozgrywający wyjedzie z Polski. W jakim kierunku? Tego jeszcze nie wiadomo. Po Polaka zgłosiło się kilka klubów. Rozmowy trwają.\n", + "1.4193757772445679 0.8862718939781189 4400 2 tensor([[0.0847, 0.0764, 0.4122, 0.0851, 0.0743, 0.0953, 0.0912, 0.0808]],\n", + " grad_fn=) WTA Lugano: Stefanie Voegele wygrała dwudniowy mecz z Magdaleną Fręch. Polka jeszcze bez zwycięstwa w tourze Stefanie Vögele okazała się w dwóch setach lepsza od Magdaleny Fręch w I rundzie turnieju WTA International na kortach ziemnych w Lugano. Polska tenisistka musi jeszcze poczekać na premierową wygraną w głównym cyklu.\n", + "1.341277003288269 1.338065505027771 4450 0 tensor([[0.2624, 0.1457, 0.0720, 0.1037, 0.0733, 0.0957, 0.1212, 0.1260]],\n", + " grad_fn=) MŚ w Lahti: Niemcy na czele klasyfikacji medalowej. To był ich piątek marzeń Niemcy znajdą się na prowadzeniu w klasyfikacji medalowej mistrzostw świata w Lahti po trzech dniach imprezy. W piątkowych konkurencjach reprezentanci tego kraju byli zdecydowanie najlepsi.\n", + "1.4628310203552246 1.8150346279144287 4500 0 tensor([[0.1628, 0.1528, 0.0743, 0.1220, 0.0933, 0.1242, 0.1056, 0.1650]],\n", + " grad_fn=) Pjongczang 2018. Austriacy zabiorą nam Horngachera? Trzeba jak najszybciej podpisać kontrakt Stefan Horngacher, jeden z autorów trzeciego złota Kamila Stocha, nie ma jeszcze podpisanego nowego kontraktu. PZN powinien uczynić to jak najszybciej, by sprzed nosa świetnego trenera nie zabrali polskiej kadrze Austriacy.\n", + "1.4924497604370117 0.9571889042854309 4550 1 tensor([[0.0926, 0.3840, 0.0861, 0.0762, 0.1012, 0.0839, 0.0782, 0.0978]],\n", + " grad_fn=) Wewnętrzna rywalizacja w Red Bull Racing. \"Powinienem wiedzieć, gdzie jest limit\" Wewnętrzna rywalizacja Daniela Ricciardo z Maxem Verstappenem korzystnie wpływa na formę kierowców Red Bull Racing. Australijczyk zdradził jednak, że w niektórych wyścigach przesadził z jazdą na limicie. - Zawsze byłem przed nim - odpowiada Holender.\n", + "1.4929934740066528 1.107985496520996 4600 6 tensor([[0.0819, 0.0615, 0.0737, 0.1038, 0.0659, 0.1301, 0.3302, 0.1528]],\n", + " grad_fn=) Puchar Polski: Skra Bełchatów - Asseco Resovia na żywo. Gdzie oglądać transmisję? W środę, w ramach Pucharu Polski w siatkówce odbędzie się mecz PGE Skra Bełchatów - Asseco Resovia Rzeszów. Tranmisja TV na antenie Polsat Sport. Stream online w Ipla TV. Relacja LIVE w WP SportoweFakty.\n", + "1.4484540224075317 1.1233779191970825 4650 1 tensor([[0.0860, 0.3252, 0.0828, 0.1039, 0.0873, 0.0995, 0.1065, 0.1088]],\n", + " grad_fn=) Mercedes z czwartym tytułem z rzędu jako czwarty zespół w historii Mercedes dzięki wygranej Lewisa Hamiltona w Austin zapewnił sobie kolejny z rzędu tytuł mistrzowski, który klasyfikuje niemiecki zespół wśród największych stajni w historii Formuły 1.\n", + "1.4267841577529907 1.2113006114959717 4700 6 tensor([[0.0845, 0.0772, 0.0979, 0.1274, 0.0651, 0.1551, 0.2978, 0.0950]],\n", + " grad_fn=) PlusLiga: ta ostatnia, decydująca niedziela W niedzielę zostanie rozegrana ostatnia kolejka PlusLigi. Poznamy w niej odpowiedzi na pytania, które drużyny zagrają o medale, a która pożegna się z rozgrywkami. Czy Indykpol AZS, Asseco Resovia i Jastrzębski Węgiel wykorzystają potknięcie ONICO?\n", + "1.4323785305023193 0.9162018299102783 4750 0 tensor([[0.4000, 0.0968, 0.0801, 0.0819, 0.0717, 0.0828, 0.0906, 0.0960]],\n", + " grad_fn=) Hula, Żyła i Kubacki szczęśliwi po MŚ w lotach. Już szykują się na konkurs drużynowy Polscy skoczkowie byli w bardzo dobrych nastrojach po indywidualnych MŚ w lotach narciarskich. Teraz wszyscy są myślami przy niedzielnej rywalizacji drużynowej.\n", + "1.4645687341690063 1.0090150833129883 4800 1 tensor([[0.1288, 0.3646, 0.0872, 0.0714, 0.0701, 0.0955, 0.0767, 0.1057]],\n", + " grad_fn=) Maverick Vinales myśli tylko o wygranej. \"Walka o podium mi nie wystarczy\" Upadek w Grand Prix Holandii sprawił, że Maverick Vinales stracił prowadzenie w klasyfikacji generalnej MotoGP. Hiszpan ma teraz jeden cel. Wygrać wyścig na Sachsenringu i wrócić na szczyt tabeli.\n", + "1.4902528524398804 1.4393011331558228 4850 5 tensor([[0.0799, 0.1133, 0.1005, 0.1091, 0.1096, 0.2371, 0.1070, 0.1435]],\n", + " grad_fn=) Zagrał na własne życzenie i... doznał kontuzji. Co dalej z Markiem Carterem? Marc Carter za wszelką cenę chciał pomóc drużynie w meczu z PGE Turowem Zgorzelec (93:78). Niestety Amerykanin swój występ przepłacił kontuzją ścięgna Achillesa. Na razie nie wiadomo, jak poważny jest uraz jednego z czołowych zawodników BM Slam Stal.\n", + "1.431559443473816 1.245039463043213 4900 7 tensor([[0.0937, 0.0672, 0.0871, 0.1039, 0.0763, 0.1125, 0.1714, 0.2879]],\n", + " grad_fn=) Anglia - Nigeria na żywo. Transmisja TV, stream online W sobotę, w ramach meczu towarzyskiego, odbędzie się starcie Anglia - Nigeria. Transmisja TV na antenie Eleven Sports 1. Stream online w WP Pilot. Relacja LIVE w WP SportoweFakty.\n", + "1.3498646020889282 1.471439242362976 4950 5 tensor([[0.1090, 0.0782, 0.1236, 0.1252, 0.0868, 0.2296, 0.1287, 0.1189]],\n", + " grad_fn=) Liga Letnia NBA: Zespół Ponitki w ćwierćfinale, 4 punkty Polaka Mateusz Ponitka zdobył cztery punkty dla Denver Nuggets, którzy pokonali Utah Jazz 80:60 i awansowali do ćwierćfinału Ligi Letniej NBA w Las Vegas.\n" + ] + } + ], + "source": [ + "iteration = 0\n", + "step = 50\n", + "closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False)\n", + "\n", + "for t, y_exp in zip(texts, labels):\n", + " x = vectorize_text(t).float().unsqueeze(dim=0)\n", + "\n", + " optimizer.zero_grad()\n", + "\n", + " y_logprobs = model(x)\n", + "\n", + " loss = loss_fn(y_logprobs, torch.tensor([y_exp]))\n", + "\n", + " loss.backward()\n", + "\n", + " with torch.no_grad():\n", + " closs += loss\n", + "\n", + " optimizer.step()\n", + "\n", + " if iteration % 50 == 0:\n", + " print((closs / step).item(), loss.item(), iteration, y_exp, torch.exp(y_logprobs), t)\n", + " closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False)\n", + " iteration += 1\n", + "\n", + " if iteration == 5000:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Model jest tak prosty, że jego wagi są interpretowalne.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0.0923, 0.1009, 0.0887, 0.0885, 0.0978, 0.3431, 0.0920, 0.0967]])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "with torch.no_grad():\n", + " x = vectorize_text('NBA').float().unsqueeze(dim=0)\n", + " y_prob = model(x)\n", + "torch.exp(y_prob)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.6279, -0.6502, -0.6364, -0.6375, -0.5847, 0.6373, -0.6372, -0.6437],\n", + " grad_fn=)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "with torch.no_grad():\n", + " x = vectorize_text('NBA').float().unsqueeze(dim=0)\n", + " ix = torch.argmax(x).item()\n", + "model[0].weight[:,ix]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Możemy nawet zaprezentować wykres przedstawiający rozmieszczenie słów względem dwóch osi odnoszących się do poszczególnych wybranych dyscyplin.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAD4CAYAAADhNOGaAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Z1A+gAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbWklEQVR4nO3de3RV5Z3/8ffXgMpQERCQa424uBQSMDaw+EEFVFCL1oDgVH/VCVZKbcfOTDuiIDrLSy+oHW/rR3ExVC5aEQsKlGHKKEpRxraJgIDYCGJGSSIEMCAGlITv749sTpP05MY+yUmyP6+1zjp7P/t59vM8OZBP9j7n7G3ujoiIRNcZyR6AiIgkl4JARCTiFAQiIhGnIBARiTgFgYhIxLVJ9gBq06VLF09NTU32MEREWoy33377gLt3bUibhASBmV0NPAmkAAvcfU617d8B7g5WjwI/cPd36tpvamoqubm5iRiiiEgkmNn/NrRN6FNDZpYCzAW+CQwCbjKzQdWqfQiMcfchwEPA/LD9iohIYiTiPYLhwG533+PuXwIvAFmVK7j7/7j7p8HqH4HeCei3Tvn5+aSlpZ1W25UrV7Jz584Ej0hEpPlJRBD0Aj6utL43KKvJbcB/JaDfRlNWVqYgEJHISEQQWJyyuNetMLPLqAiCu+NtD+pMN7NcM8stLi5OwPAq7Nmzh4yMDHJychgxYgRDhgxh0qRJfPppxYHK2LFjueeeexgzZgwPP/wwq1evZsaMGVx88cV88MEHCRuHiEhzk4gg2Av0qbTeGyisXsnMhgALgCx3P1jTztx9vrtnuntm164NeuO7Rnl5eUyePJmFCxdy22238fDDD7Nt2zbS09N54IEHYvVKSkr4wx/+wOzZs7nuuut49NFH2bp1KxdddFFCxiEi0hwl4lNDOUA/M7sQKABuBP5v5Qpm9lXgJeAWd38/AX3WaOWWAh5dl0dhyTE6+2H2Fu0jKyuLFStW0Lt3b0pKShgzZgwA2dnZ3HDDDbG23/72txtzaCIizVLoIwJ3LwPuANYB7wEvuvu7Zna7md0eVPs34DzgV2a21cwa5TOhK7cUMOul7RSUHMOBfUeOU8pZnN2xG5s2baqzffv27RtjWCIizVpCvkfg7muBtdXKnq60PA2Yloi+avPoujyOnSivWnhGCmdPuJslS37BV77yFTp16sQbb7zBpZdeyrPPPhs7OqjunHPO4bPPPmvsIYuIJF2z/mZxQxWWHItbvq8UtqxZw/jx47n++uuZMWMGpaWl9O3bl4ULF8Ztc+ONN/K9732Pp556iuXLl+t9AhFptaw535gmMzPTG/LN4lFzXqMgThj06tiOTTMvT+TQRESaJTN7290zG9KmVV10bsZVA2jXNqVKWbu2Kcy4akCSRiQi0vy1qlNDEzMqvsd26lNDPTu2Y8ZVA2LlIiLyt1pVEEBFGOgXv4hI/bWqU0MiItJwCgIRkYhTEIiIRJyCQEQk4hQEIiIRpyAQEYk4BYGISMQpCEREIk5BICIScQoCEZGIUxCIiEScgkBEJOIUBCIiEacgEBGJuIQEgZldbWZ5ZrbbzGbG2T7QzN4ysy/M7M5E9CkiIokR+n4EZpYCzAXGA3uBHDNb7e47K1U7BPwTMDFsfyIikliJOCIYDux29z3u/iXwApBVuYK773f3HOBEAvoTEZEESkQQ9AI+rrS+NygTEZEWIBFBYHHK/LR3ZjbdzHLNLLe4uDjEsEREpD4SEQR7gT6V1nsDhae7M3ef7+6Z7p7ZtWvX0IMTEZHaJSIIcoB+ZnahmZ0J3AisTsB+RUSkCYT+1JC7l5nZHcA6IAV4xt3fNbPbg+1Pm1l3IBfoAJw0s38BBrn7kbD9i4hIOKGDAMDd1wJrq5U9XWn5EypOGYmISDOjbxaLiEScgkBEJOIUBCIiEacgEBGJOAWBiEjEKQhERCJOQSAiEnEKAhGRiFMQiIhEnIJARCTiFAQiIhGnIBARiTgFgYhIxCkIREQiTkEgIhJxCgIRkYhTEIiIRJyCQEQk4hQEIiIRpyAQEYm4hASBmV1tZnlmttvMZsbZbmb2VLB9m5ldkoh+RUQkvNBBYGYpwFzgm8Ag4CYzG1St2jeBfsFjOjAvbL8iIpIYiTgiGA7sdvc97v4l8AKQVa1OFrDEK/wR6GhmPRLQt4iIhJSIIOgFfFxpfW9Q1tA6AJjZdDPLNbPc4uLiBAxPRERqk4ggsDhlfhp1Kgrd57t7prtndu3aNfTgRESkdokIgr1An0rrvYHC06gjIiJJkIggyAH6mdmFZnYmcCOwulqd1cA/BJ8eGgEcdveiBPQtIiIhtQm7A3cvM7M7gHVACvCMu79rZrcH258G1gITgN1AKXBr2H5FRCQxEvI9Andf6+793f0id/9ZUPZ0EAIEnxb6x2B7urvnJqJfkSiYNm0aO3fuBCA1NZUDBw6Qn59PWlpakkcmrUXoIwIRaVwLFixI9hCkldMlJkSaifz8fAYOHEh2djZDhgxhypQplJaWMnbsWHJz/3oQ/cEHH1Rpt2fPHjIyMsjJyeHPf/4zI0eOJCMjg5EjR5KXl9fU05AWSEEg0ozk5eUxffp0tm3bRocOHfjVr34V21ZeXs6XX37JkiVLqtSfPHkyCxcuZNiwYQwcOJCNGzeyZcsWHnzwQe65555kTENaGJ0aEkmilVsKeHRdHoUlx+jsh+nSvSejRo0C4Oabb+app56K1b3vvvs4cuQIDzzwAEePHqW4uJisrCxWrFjB4MGDATh8+DDZ2dns2rULM+PEiRNJmZe0LDoiEEmSlVsKmPXSdgpKjuHAviPHKSktY+WWglgds79+F/PnP/85Xbp0ia2fe+659OnTh02bNsXK7rvvPi677DJ27NjB7373O44fP94kc5GWTUEgkiSPrsvj2InyKmVlR/bzb/NfAmDp0qV84xvfqLH9mWeeycqVK1myZAnPP/88UHFE0KtXxdVbFi1a1DgDl1ZHQSCSJIUlx/6mrO15ffjwj2sZMmQIhw4d4gc/+EGt+2jfvj1r1qzh8ccfZ9WqVdx1113MmjWLUaNGUV5eXmtbkVPMPe4lf5qFzMxMr/xpCZHWZNSc1yioFAZlh/exf/kDDPvXhWyaeXkSRyYtmZm97e6ZDWmjIwKRJJlx1QDatU2pUmZmzLhqQJJGJFGlTw2JJMnEjIpz+ac+NXTBBan8v3WbYuUiTUVBIJJEEzN66Re/JJ1ODYmIRJyCQEQk4hQEIiIRpyAQEYk4BYGISMQpCEREIk5BICIScQoCEZGICxUEZtbZzF4xs13Bc6ca6j1jZvvNbEeY/qRlWbZsGfn5+ckehojUIewRwUxgvbv3A9YH6/EsAq4O2Zc0I1OnTmX58uU1bn/uuef46KOPSE1NPa32ItJ0wl5iIgsYGywvBjYAd1ev5O4bzSw1ZF/Sgtx8883JHoKI1FPYI4Lz3b0IIHjuFnZAZjbdzHLNLLe4uDjs7lqtzz//nGuuuYahQ4eSlpbGsmXLePDBBxk2bBhpaWlMnz6dU5cYHzt2LD/+8Y8ZPXo0X/va18jJyeH666+nX79+3HvvvbF9PvbYY6SlpZGWlsYTTzwRK1+yZAlDhgxh6NCh3HLLLbHyjRs3MnLkSPr27Rv7697dmTFjBmlpaaSnp7Ns2bJY+R133MGgQYO45ppr2L9/fxP8lESkXty91gfwKrAjziMLKKlW99Na9pMK7Kirv8qPr3/96y7xLV++3KdNmxZbLykp8YMHD8bWb775Zl+9erW7u48ZM8bvuusud3d/4oknvEePHl5YWOjHjx/3Xr16+YEDBzw3N9fT0tL86NGj/tlnn/mgQYN88+bNvmPHDu/fv78XFxe7u8f6yM7O9ilTpnh5ebm/++67ftFFF8XGNW7cOC8rK/NPPvnE+/Tp44WFhb5ixYpYeUFBgZ977rn+29/+tkl+ViJRAuR6A37Punvdp4bcfVxN28xsn5n1cPciM+sB6M+8RlT5RuedThylYO06Ot99N9deey2XXnopK1as4JFHHqG0tJRDhw4xePBgvvWtbwFw3XXXAZCens7gwYPp0aMHAH379uXjjz/mzTffZNKkSbRv3x6A66+/njfeeAMzY8qUKbF75Xbu3Dk2nokTJ3LGGWcwaNAg9u3bB8Cbb77JTTfdREpKCueffz5jxowhJyeHjRs3xsp79uzJ5ZfrxisizUXY9whWA9nAnOB5VegRSVynbnR+6h63h9p24dyb/p0vzili1qxZXHnllcydO5fc3Fz69OnD/fffX+XG5WeddRYAZ5xxRmz51HpZWVnsNFJ17l7lBuqVVd7PqfY17QeocT8iklxh3yOYA4w3s13A+GAdM+tpZmtPVTKzpcBbwAAz22tmt4XsN3Kq3+i87LODfEEbctqkceedd7J582YAunTpwtGjRxv8iZzRo0ezcuVKSktL+fzzz3n55Ze59NJLueKKK3jxxRc5ePAgAIcOHapzP8uWLaO8vJzi4mI2btzI8OHDGT16NC+88ALl5eUUFRXx+uuvN/AnICKNJdQRgbsfBK6IU14ITKi0flOYfuRvb3R+ojif/RsWUmTGz756HvPmzWPlypWkp6eTmprKsGHDGrT/Sy65hKlTpzJ8+HAApk2bRkZGBgCzZ89mzJgxpKSkkJGRwaJFi2rcz6RJk3jrrbcYOnQoZsYjjzxC9+7dmTRpEq+99hrp6en079+fMWPGNOwHICKNRjevbyGq3+j8lF4d2+lG5yISo5vXt2LxbnTerm2KbnQuIqHpnsUtRPUbnffs2I4ZVw3Q/W5FJDQFQQuiG52LSGPQqSERkYhTEIiIRJyCQEQk4hQEIiIJlJ+fT1paWr3rT5s2jZ07d9a4fezYsTT2x+j1ZrGISBItWLAg2UPQEYGISKKVlZWRnZ3NkCFDmDJlCqWlpaxfv56MjAzS09P57ne/yxdffAH89S/+8vJypk6dGruE++OPP15lnydPniQ7O5t7772X48ePc+utt5Kenk5GRkboS7YoCEREEiwvL4/p06ezbds2OnTowGOPPcbUqVNZtmwZ27dvp6ysjHnz5lVps3XrVgoKCtixYwfbt2/n1ltvjW0rKyvjO9/5Dv379+enP/0pc+fOBWD79u0sXbqU7OzsKheZbCgFgYhIgvXp04dRo0YBFXfrW79+PRdeeCH9+/cHIDs7m40bN1Zp07dvX/bs2cOPfvQjfv/739OhQ4fYtu9///ukpaUxe/ZsoOJy76duEjVw4EAuuOAC3n///dMer4JARCSklVsKGDXnNS6c+Z9Mnvc/HD9xssH76NSpE++88w5jx45l7ty5TJs2LbZt5MiRvP7667G/+hN9jTgFgYhICKfuFVJQcgwH9h05TvEnBcxZtBqApUuXMm7cOPLz89m9ezcAzz777N9cgffAgQOcPHmSyZMn89BDD8UuLQ9w2223MWHCBG644QbKysoYPXo0v/nNbwB4//33+eijjxgw4PSvO6ZPDYmIhFD9XiEAbc/rwxPz/oPnH7uXfv368eSTTzJixIjYL/Jhw4Zx++23V2lTUFDArbfeysmTFUcTv/jFL6ps/8lPfsLhw4e55ZZb+PWvf80Pf/hD0tPTadOmDYsWLapyo6iG0mWoRURCuHDmfxLvt6gBH865pqmHo8tQi4g0tZ4d2zWovDlSEIiIhNAa7hWi9whEREJoDfcKCRUEZtYZWAakAvnA37v7p9Xq9AGWAN2Bk8B8d38yTL8iIs1JS79XSNhTQzOB9e7eD1gfrFdXBvyru38NGAH8o5kNCtmviIgkSNggyAIWB8uLgYnVK7h7kbtvDpY/A94DWm50ioi0MmGD4Hx3L4KKX/hAt9oqm1kqkAH8qZY6080s18xyi4uLQw5PRETqUud7BGb2KhXn96ub3ZCOzOwrwArgX9z9SE313H0+MB8qvkfQkD5ERKTh6gwCdx9X0zYz22dmPdy9yMx6APtrqNeWihD4jbu/dNqjFRGRhAt7amg1kB0sZwOrqlcwMwN+Dbzn7o+F7E9ERBIsbBDMAcab2S5gfLCOmfU0s7VBnVHALcDlZrY1eEwI2a+IiCRIqO8RuPtB4Io45YXAhGD5TSouuyEiIs2QLjEhIhJxCgIRkYhTEIiIRJyCQEQk4hQEIiIRpyAQEYk4BYGISMQpCEREIk5BICIScQoCEZGIUxCIiEScgkBEJOIUBCIiEacgEBGJOAWBiEjEKQhERCJOQSAiEnEKAhGRiFMQiIhEXKggMLPOZvaKme0KnjvFqXO2mf3ZzN4xs3fN7IEwfYqISGKFPSKYCax3937A+mC9ui+Ay919KHAxcLWZjQjZr4iIJEjYIMgCFgfLi4GJ1St4haPBatvg4SH7FRGRBAkbBOe7exFA8NwtXiUzSzGzrcB+4BV3/1NNOzSz6WaWa2a5xcXFIYcnIiJ1aVNXBTN7FegeZ9Ps+nbi7uXAxWbWEXjZzNLcfUcNdecD8wEyMzN15CAi0sjqDAJ3H1fTNjPbZ2Y93L3IzHpQ8Rd/bfsqMbMNwNVA3CAQEZGmFfbU0GogO1jOBlZVr2BmXYMjAcysHTAO+EvIfkVEJEHCBsEcYLyZ7QLGB+uYWU8zWxvU6QG8bmbbgBwq3iNYE7JfERFJkDpPDdXG3Q8CV8QpLwQmBMvbgIww/YiISOPRN4tFRCJOQSAiEnEKAhGRiFMQiIhEnIJARCTiFAQiIhGnIBARiTgFgYhIxCkIREQiTkEgIhJxCgIRkYhTEIiIRJyCQEQk4hQEIiIRpyAQEYk4BYGISMQpCEREIk5BICIScQoCEZGICxUEZtbZzF4xs13Bc6da6qaY2RYz043rRUSakbBHBDOB9e7eD1gfrNfkn4H3QvYnIiIJFjYIsoDFwfJiYGK8SmbWG7gGWBCyPxERSbCwQXC+uxcBBM/daqj3BHAXcLKuHZrZdDPLNbPc4uLikMMTEZG6tKmrgpm9CnSPs2l2fTows2uB/e7+tpmNrau+u88H5gNkZmZ6ffoQEZHTV2cQuPu4mraZ2T4z6+HuRWbWA9gfp9oo4DozmwCcDXQws+fc/ebTHrWIiCRM2FNDq4HsYDkbWFW9grvPcvfe7p4K3Ai8phAQEWk+wgbBHGC8me0CxgfrmFlPM1sbdnAiItL46jw1VBt3PwhcEae8EJgQp3wDsCFMnyIiklj6ZrGISMQpCEREIk5BICIScQoCEZGIUxCIiEScgkBEJOIUBCIiEacgEBGJOAWBiEjEKQhERCJOQSAiEnEKAhGRiFMQiIhEnIJARCTiFAQiIhGnIBARiTgFgYhIxCkIREQiTkEgIhJxoe5ZbGadgWVAKpAP/L27fxqnXj7wGVAOlLl7Zph+RUQkccIeEcwE1rt7P2B9sF6Ty9z9YoWAiEjzEjYIsoDFwfJiYGLI/YmISBMLGwTnu3sRQPDcrYZ6Dvy3mb1tZtNr26GZTTezXDPLLS4uDjk8EZGWKT8/n7S0tCplGzZs4Nprr62r6ZlmtqMhfdX5HoGZvQp0j7NpdgP6GeXuhWbWDXjFzP7i7hvjVXT3+cB8gMzMTG9AHyIichrqPCJw93HunhbnsQrYZ2Y9AILn/TXsozB43g+8DAxP3BRERFq3PXv2kJGRQU5OTqzs/vvv55e//GVsPS0tjfz8/FOrbcxssZltM7PlZvZ3te0/7Kmh1UB2sJwNrKpewczam9k5p5aBK4EGHbaIiERVXl4ekydPZuHChQwbNqy+zQYA8919CHAE+GFtlUN9fBSYA7xoZrcBHwE3AJhZT2CBu08AzgdeNrNT/T3v7r8P2a+ISKuzcksBj67Lo7DkGJ39MHuL9pGVlcWKFSsYPHgwGzZsqO+uPnb3TcHyc8A/Ab+sqXKoIHD3g8AVccoLgQnB8h5gaJh+RERau5VbCpj10naOnSgHYN+R45RyFmd37MamTZsYPHhwlfpt2rTh5MmTsfXjx49X3lz9/dVa32/VN4tFRJqBR9flxUIg5owUzp5wN0uWLOH555+vsik1NZXNmzcDsHnzZj788MPKm79qZv8nWL4JeLO2vhUEIiLNQGHJsbjl+0phzZo1PP744xw+fDhWPnnyZA4dOsTFF1/MvHnz6N+/f+Vm7wHZZrYN6AzMq61vc2++n9DMzMz03NzcZA9DRKTRjZrzGgVxwqBXx3Zsmnl5vfdjZm839AoOOiIQEWkGZlw1gHZtU6qUtWubwoyrBjR632E/NSQiIgkwMaMXQOxTQz07tmPGVQNi5Y1JQSAi0kxMzOjVJL/4q9OpIRGRiFMQiIhEnIJARCTiFAQiIhGnIBARibhm/YUyMysG/jfZ44ijC3Ag2YNIgNYwj9YwB2gd89AcmocL3L1rQxo06yBorswstzXce7k1zKM1zAFaxzw0h5ZLp4ZERCJOQSAiEnEKgtMzP9kDSJDWMI/WMAdoHfPQHFoovUcgIhJxOiIQEYk4BYGISMQpCGpgZp3N7BUz2xU8d6qh3jNmtt/MdlQrv9/MCsxsa/CY0DQjrzKGsHOoV/vG1oB5XG1meWa228xmVipP2mtR05gqbTczeyrYvs3MLqlv26YScg75ZrY9+Lkn9S5T9ZjHQDN7y8y+MLM7G9K2xXN3PeI8gEeAmcHyTODhGuqNBi4BdlQrvx+4s4XPoV7tm8M8gBTgA6AvcCbwDjAoma9FbWOqVGcC8F+AASOAP9W3bXOfQ7AtH+iSjH83pzGPbsAw4GeV/700l9eiMR86IqhZFrA4WF4MTIxXyd03AoeaaEwNFXYO9WrfBOozjuHAbnff4+5fAi8E7ZKpPmPKApZ4hT8CHc2sRz3bNoUwc2hO6pyHu+939xzgREPbtnQKgpqd7+5FAMFzt9PYxx3BofIzSTqtEnYOifgZJEJ9xtEL+LjS+t6g7JRkvBZ1jam2OvVp2xTCzAHAgf82s7fNbHqjjbJuYX6ezeW1aDSRvkOZmb0KdI+zaXYCdj8PeIiK/wgPAf8OfDcB+62ikefQZBIwD4tTduqz0U3yWjRwTHXVqU/bphBmDgCj3L3QzLoBr5jZX4Ij0KYW5ufZXF6LRhPpIHD3cTVtM7N9ZtbD3YuCw9z9Ddz3vkr7+g9gzemPtNZ+Gm0OQNj29ZaAeewF+lRa7w0UBvtukteiIWOqR50z69G2KYSZA+5+6nm/mb1MxWmWZARBfebRGG1bBJ0aqtlqIDtYzgZWNaRxtXOkk4AdNdVtRKHmkID2iVKfceQA/czsQjM7E7gxaJfM16LGMVWyGviH4JM3I4DDwemv+rRtCqc9BzNrb2bnAJhZe+BKkvP/AML9PJvLa9F4kv1udXN9AOcB64FdwXPnoLwnsLZSvaVAERVvMO0FbgvKnwW2A9uo+EfTowXOIW77ZjyPCcD7VHzCY3al8qS9FvHGBNwO3B4sGzA32L4dyKxrPkn4+Z/WHKj4lM07wePdZM6hnvPoHvz7PwKUBMsdmtNr0VgPXWJCRCTidGpIRCTiFAQiIhGnIBARiTgFgYhIxCkIREQiTkEgIhJxCgIRkYj7/39flvbEd1ISAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "\n", + "with torch.no_grad():\n", + " words = ['piłka', 'klub', 'kort', 'boisko', 'samochód']\n", + " words_ixs = [torch.argmax(vectorize_text(w).float().unsqueeze(dim=0)).item() for w in words]\n", + "\n", + " x_label = labels_dic['pilka-nozna']\n", + " y_label = labels_dic['tenis']\n", + "\n", + " x = [model[0].weight[x_label, ix] for ix in words_ixs]\n", + " y = [model[0].weight[y_label, ix] for ix in words_ixs]\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.scatter(x, y)\n", + "\n", + " for i, txt in enumerate(words):\n", + " ax.annotate(txt, (x[i], y[i]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Zadanie etykietowania sekwencji\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Zadanie etykietowania sekwencji (*sequence labelling*) polega na przypisaniu poszczególnym wyrazom (tokenom) tekstu **etykiet** ze skończonego zbioru. Definiując formalnie:\n", + "\n", + "- rozpatrujemy ciąg wejściowy tokenów $(t^1,\\dots,t^K)$\n", + "- dany jest skończony zbiór etykiet $L = \\{l_1,\\dots,l_{|L|}\\}$, dla uproszczenia można założyć, że etykietami\n", + " są po prostu kolejne liczby, tj. $L=\\{0,\\dots,|L|-1\\}$\n", + "- zadanie polega na wygenerowaniu sekwencji etykiet (o tej samej długości co ciąg wejściowy!) $(y^1,\\dots,y^K)$,\n", + " $y^k \\in L$\n", + "\n", + "Zadanie etykietowania można traktować jako przypadek szczególny klasyfikacji wieloklasowej, z tym, że klasyfikacji dokonujemy wielokrotnie — dla każdego tokenu (nie dla każdego tekstu).\n", + "\n", + "Przykłady zastosowań:\n", + "\n", + "- oznaczanie częściami mowy (*POS tagger*) — czasownik, przymiotnik, rzeczownik itd.\n", + "- oznaczanie etykiet nazw w zadaniu NER (nazwisko, kwoty, adresy — najwięcej tokenów będzie miało etykietę pustą, zazwyczaj oznaczaną przez `O`)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### **Pytanie**: czy zadanie tłumaczenia maszynowego można potraktować jako problem etykietowania sekwencji?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Przykładowe wyzwanie NER CoNLL-2003\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Zob. [https://gonito.net/challenge/en-ner-conll-2003](https://gonito.net/challenge/en-ner-conll-2003).\n", + "\n", + "Przykładowy przykład uczący (`xzcat train.tsv.xz| head -n 1`):\n", + "\n", + "O O B-MISC I-MISC O O O O O B-LOC O B-LOC O O O O O O O O O O O B-MISC I-MISC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER I-PER O B-LOC O O O O O B-PER I-PER O O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O B-LOC O O O O O B-PER I-PER O O O O O\tGOLF - BRITISH MASTERS THIRD ROUND SCORES . NORTHAMPTON , England 1996-08-30 Leading scores after the third round of the British Masters on Friday : 211 Robert Allenby ( Australia ) 69 71 71 212 Pedro Linhart ( Spain ) 72 73 67 216 Miguel Angel Martin ( Spain ) 75 70 71 , Costantino Rocca ( Italy ) 71 73 72 217 Antoine Lebouc ( France ) 74 73 70 , Ian Woosnam 70 76 71 , Francisco Cea ( Spain ) 70 71 76 , Gavin Levenson ( South Africa ) 66 75 76 218 Stephen McAllister 73 76 69 , Joakim Haeggman ( Swe ) 71 77 70 , Jose Coceres ( Argentina ) 69 78 71 , Paul Eales 75 71 72 , Klas Eriksson ( Sweden ) 71 75 72 , Mike Clayton ( Australia ) 69 76 73 , Mark Roe 69 71 78 219 Eamonn Darcy ( Ireland ) 74 76 69 , Bob May ( U.S. ) 74 75 70 , Paul Lawrie 72 75 72 , Miguel Angel Jimenez ( Spain ) 74 72 73 , Peter Mitchell 74 71 75 , Philip Walton ( Ireland ) 71 74 74 , Peter O'Malley ( Australia ) 71 73 75 220 Barry Lane 73 77 70 , Wayne Riley ( Australia ) 71 78 71 , Martin Gates 71 77 72 , Bradley Hughes ( Australia ) 73 75 72 , Peter Hedblom ( Sweden ) 70 75 75 , Retief Goosen ( South Africa ) 71 74 75 , David Gilford 69 74 77 . \n", + "\n", + "W pierwszym polu oczekiwany wynik zapisany za pomocą notacji **BIO**.\n", + "\n", + "Jako metrykę używamy F1 (z pominięciem tagu `O`)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Metryka F1\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Etykietowanie za pomocą klasyfikacji wieloklasowej\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Można potraktować problem etykietowania dokładnie tak jak problem\n", + "klasyfikacji wieloklasowej (jak w przykładzie klasyfikacji dyscyplin\n", + "sportowych powyżej), tzn. rozkład prawdopodobieństwa możliwych etykiet\n", + "uzyskujemy poprzez zastosowanie prostej warstwy liniowej i funkcji softmax:\n", + "\n", + "$$p(l^k=i) = s(\\vec{w}\\vec{v}(t^k))_i = \\frac{e^{\\vec{w}\\vec{v}(t^k)}}{Z},$$\n", + "\n", + "gdzie $\\vec{v}(t^k)$ to reprezentacja wektorowa tokenu $t^k$.\n", + "Zauważmy, że tutaj (w przeciwieństwie do klasyfikacji całego tekstu)\n", + "reprezentacja wektorowa jest bardzo uboga: wektor one-hot! Taki\n", + "klasyfikator w ogóle nie będzie brał pod uwagę kontekstu, tylko sam\n", + "wyraz, więc tak naprawdę zdegeneruje się to do zapamiętania częstości\n", + "etykiet dla każdego słowa osobno.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Bogatsza reprezentacja słowa\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Można spróbować uzyskać bogatszą reprezentację dla słowa biorąc pod uwagę na przykład:\n", + "\n", + "- długość słowa\n", + "- kształt słowa (*word shape*), np. czy pisany wielkimi literami, czy składa się z cyfr itp.\n", + "- n-gramy znakowe wewnątrz słowa (np. słowo *Kowalski* można zakodować jako sumę wektorów\n", + " trigramów znakówych $\\vec{v}(Kow) + \\vec{v}(owa) + \\vec{v}(wal) + \\vec{v}(als) + \\vec{v}(lsk) + + \\vec{v}(ski)$\n", + "\n", + "Cały czas nie rozpatrujemy jednak w tej metodzie kontekstu wyrazu.\n", + "(*Renault* w pewnym kontekście może być nazwą firmy, w innym —\n", + "nazwiskiem).\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Reprezentacja kontekstu\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Za pomocą wektora można przedstawić nie pojedynczy token $t^k$, lecz\n", + "cały kontekst, dla *okna* o długości $c$ będzie to kontekst $t^{k-c},\\dots,t^k,\\dots,t^{k+c}$.\n", + "Innymi słowy klasyfikujemy token na podstawie jego samego oraz jego kontekstu:\n", + "\n", + "$$p(l^k=i) = \\frac{e^{\\vec{w}\\vec{v}(t^{k-c},\\dots,t^k,\\dots,t^{k+c})}}{Z_k}.$$\n", + "\n", + "Zauważmy, że w tej metodzie w ogóle nie rozpatrujemy sensowności\n", + "sekwencji wyjściowej (etykiet), np. może być bardzo mało\n", + "prawdopodobne, że bezpośrednio po nazwisku występuje data.\n", + "\n", + "Napiszmy wzór określający prawdopodobieństwo całej sekwencji, nie\n", + "tylko pojedynczego tokenu. Na razie będzie to po prostu iloczyn poszczególnych wartości.\n", + "\n", + "$$p(l) = \\prod_{k=1}^K \\frac{e^{\\vec{w}\\vec{v}(t^{k-c},\\dots,t^k,\\dots,t^{k+c})}}{Z_k} = \\frac{e^{\\sum_{k=1}^K\\vec{w}\\vec{v}(t^{k-c},\\dots,t^k,\\dots,t^{k+c})}}{\\prod_{k=1}^K Z_k}$$\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Warunkowe pola losowe\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Warunkowe pola losowe (*Conditional Random Fields*, *CRF*) to klasa\n", + "modeli, które pozwalają uwzględnić zależności między punktami danych\n", + "(które można wyrazić jako graf). Najprostszym przykładem będzie prosty\n", + "graf wyrażający „następowanie po” (czyli sekwencje). Do poprzedniego\n", + "wzoru dodamy składnik $V_{i,j}$ (który można interpretować jako\n", + "macierz) określający prawdopodobieństwo, że po etykiecie o numerze $i$ wystąpi etykieta o numerze $j$.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### **Pytanie**: Czy macierz $V$ musi być symetryczna? Czy $V_{i,j} = V_{j,i}$? Czy jakieś specjalne wartości występują na przekątnej?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Macierz $V$ wraz z wektorem $\\vec{w}$ będzie stanowiła wyuczalne wagi w naszym modelu.\n", + "\n", + "Wartości $V_{i,j}$ nie stanowią bezpośrednio prawdopodobieństwa, mogą\n", + "przyjmować dowolne wartości, które będę normalizowane podobnie jak to się dzieje w funkcji Softmax.\n", + "\n", + "W takiej wersji warunkowych pól losowych otrzymamy następujący wzór na prawdopodobieństwo całej sekwencji.\n", + "\n", + "$$p(l) = \\frac{e^{\\sum_{k=1}^K\\vec{w}\\vec{v}(t^{k-c},\\dots,t^k,\\dots,t^{k+c}) + \\sum_{k=1}^{K-1} V_{l_k,l_{k+1}}}}{\\prod_{k=1}^K Z_k}$$\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "org": null + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/wyk/09_neurozoo.org b/wyk/09_neurozoo.org new file mode 100644 index 0000000..4586151 --- /dev/null +++ b/wyk/09_neurozoo.org @@ -0,0 +1,658 @@ + +* Neurozoo +** Funkcja sigmoidalna + +Funkcja sigmoidalna zamienia dowolną wartość („sygnał”) w wartość z przedziału $(0,1)$, czyli wartość, która może być interperetowana jako prawdopodobieństwo. + +$$\sigma(x) = \frac{1}{1 + e^{-x}}$$ + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch + + def sigmoid(x): + return 1 / (1 + torch.exp(-x)) + + sigmoid(torch.tensor(0.6)) +#+END_SRC + +#+RESULTS: +:results: +# Out[1]: +: tensor(0.6457) +:end: + +#+BEGIN_SRC ipython :session mysession :results file + %matplotlib inline + import matplotlib.pyplot as plt + import torch + + x = torch.linspace(-5,5,100) + plt.xlabel("x") + plt.ylabel("y") + plt.plot(x, sigmoid(x)) + fname = 'sigmoid.png' + plt.savefig(fname) + fname +#+END_SRC + +#+RESULTS: +[[file:# Out[32]: +: 'sigmoid.png' +[[file:./obipy-resources/Tb0Of9.png]]]] + +*** PyTorch + +Funkcja ~torch.sigmoid~ po prostu stosuje sigmoidę do każdego elementu tensora (/element-wise/). + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch + + torch.sigmoid(torch.tensor([0.6, 1.0, -5.0])) +#+END_SRC + +#+RESULTS: +:results: +# Out[38]: +: tensor([0.6457, 0.7311, 0.0067]) +:end: + +Istnieje również ~torch.nn.Sigmoid~, które może być używane jako warstwa. + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + s = nn.Sigmoid() + s(torch.tensor([0.0, -0.2, 0.4])) +#+END_SRC + +#+RESULTS: +:results: +# Out[49]: +: tensor([0.5000, 0.4502, 0.5987]) +:end: + +**** Implementacja w Pytorchu + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + import torch + + class MySigmoid(nn.Module): + def __init__(self): + super(MySigmoid, self).__init__() + + def forward(self, x): + return 1 / (1 + torch.exp(-x)) + + s = MySigmoid() + s(torch.tensor([0.0, 0.5, 0.3])) +#+END_SRC + +#+RESULTS: +:results: +# Out[48]: +: tensor([0.5000, 0.6225, 0.5744]) +:end: + +*** Wagi + +Funkcja sigmoidalna nie ma żadnych wyuczalnych wag. + +**** *Pytanie*: Czy można rozszerzyć funkcję sigmoidalną o jakieś wyuczalne wagi? + +** Regresja liniowa + +** Softmax + +W klasyfikacji wieloklasowej należy zwrócić musimy zwrócić rozkład +prawdopodobieństwa po wszystkich klasach, w przeciwieństwie do +klasyfikacji binarnej, gdzie wystarczy zwrócić jedną liczbę — +prawdopodobieństwo pozytywnej klasy ($p$; prawdopodobieństwo drugiej +klasy to po prostu $1-p$). + +A zatem na potrzeby klasyfikacji wieloklasowej potrzeba wektorowego +odpowiednika funkcji sigmoidalnej, to jest funkcji, która zamienia +nieznormalizowany wektor $\vec{z} = [z_1,\dots,z_k]$ (pochodzący np. z +poprzedzającej warstwy liniowej) na rozkład prawdopobieństwa. +Potrzebujemy zatem funkcji $s: \mathcal{R}^k \rightarrow [0,1]^k$ + +spełniającej następujące warunki: + +- $s(z_i) = s_i(z) \in [0,1]$ +- $\Sigma_i s(z_i) = 1$ +- $z_i > z_j \Rightarrow s(z_i) > s(z_j)$ + +Można by podać takie (*błędne*!) rozwiązanie: + +$$s(z_i) = \frac{z_i}{\Sigma_{j=1}^k z_j}$$ + +To rozwiązanie zadziała błędnie dla liczb ujemnych, trzeba najpierw +użyć funkcji monotonicznej, która przekształaca $\mathcal{R}$ na $\mathcal{R^+}$. +Naturalna funkcja tego rodzaju to funkcja wykładnicza $\exp{x} = e^x$. +Tym sposobem dochodzimy do funkcji softmax: + +$$s(z_i) = \frac{e^{z_i}}{\Sigma_{j=1}^k e^{z_j}}$$ + +Mianownik ułamka w definicji funkcji softmax nazywamy czasami czynnikiem normalizacyjnym: +$Z(\vec{z}) = \Sigma_{j=1}^k e^{z_j}$, wtedy: + +$$s(z_i) = \frac{e^{z_i}}{Z(\vec{z})}$$ + +Definicja w PyTorchu: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch + + def softmax(z): + z_plus = torch.exp(z) + return z_plus / torch.sum(z_plus) + + softmax(torch.tensor([3., -1., 0., 5.])) +#+END_SRC + +#+RESULTS: +:results: +# Out[75]: +: tensor([0.1182, 0.0022, 0.0059, 0.8737]) +:end: + +#+CAPTION: Softmax +[[./softmax.png]] + +*** Soft vs hard + +Dlaczego /softmax/? Czasami używa się funkcji *hardmax*, która np. +wektora $[3, -1, 0, 5]$ zwróciłaby $[0, 0, 0, 5]$ — to jest po prostu +wektorowa wersja funkcji zwracającej maksimum. Istnieje też funkcja +hard*arg*max, która zwraca wektor /one-hot/ — z jedną jedynką na +pozycji dla największej wartości (zamiast podania największej +wartości), np. wartość hardargmax dla $[3, -1, 0, 5]$ zwróciłaby $[0, +0, 0, 1]$. + +Zauważmy, że powszechnie przyjęta nazwa /softmax/ jest właściwie +błędna, funkcja ta powinna nazywać się /softargmax/, jako że w +„miękki” sposób identyfikuje największą wartość przez wartość zbliżoną +do 1 (na pozostałych pozycjach wektora nie będzie 0). + +**** *Pytanie*: Jak można zdefiniować funkcję /softmax/ w ścisłym tego słowa znaczeniu („miękki” odpowiednik hardmax, nie hardargmax)? + + + +*** PyTorch + +Funkcja ~torch.nn.functional.softmax~ normalizuje wartości dla całego tensora: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + nn.functional.softmax(torch.tensor([0.6, 1.0, -5.0])) +#+END_SRC + +#+RESULTS: +:results: +# Out[5]: +: tensor([0.4007, 0.5978, 0.0015]) +:end: + +… zobaczmy, jak ta funkcja zachowuje się dla macierzy: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + nn.functional.softmax(torch.tensor([[0.6, 1.0], [-2.0, 3.5]])) +#+END_SRC + +#+RESULTS: +:results: +# Out[6]: +#+BEGIN_EXAMPLE + tensor([[0.4013, 0.5987], + [0.0041, 0.9959]]) +#+END_EXAMPLE +:end: + +Za pomocą (zalecanego zresztą) argumentu ~dim~ możemy określić wymiar, wzdłuż którego dokonujemy normalizacji: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + nn.functional.softmax(torch.tensor([[0.6, 1.0], [-2.0, 3.5]]), dim=0) +#+END_SRC + +#+RESULTS: +:results: +# Out[8]: +#+BEGIN_EXAMPLE + tensor([[0.9309, 0.0759], + [0.0691, 0.9241]]) +#+END_EXAMPLE +:end: + +Istnieje również ~torch.nn.Softmax~, które może być używane jako warstwa. + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + s = nn.Softmax(dim=0) + s(torch.tensor([0.0, -0.2, 0.4])) +#+END_SRC + +#+RESULTS: +:results: +# Out[10]: +: tensor([0.3021, 0.2473, 0.4506]) +:end: + +**** Implementacja w Pytorchu + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + import torch + + class MySoftmax(nn.Module): + def __init__(self): + super(MySoftmax, self).__init__() + + def forward(self, x): + ex = torch.exp(x) + return ex / torch.sum(ex) + + s = MySigmoid() + s(torch.tensor([0.0, 0.5, 0.3])) +#+END_SRC + +#+RESULTS: +:results: +# Out[48]: +: tensor([0.5000, 0.6225, 0.5744]) +:end: + +***** *Pytanie*: Tak naprawdę wyżej zdefiniowana klasa ~MySoftmax~ nie zachowuje się identycznie jak ~nn.Softmax~. Na czym polega różnica? + +*** Przypadek szczególny + +Sigmoida jest przypadkiem szczególnym funkcji softmax: + +$$\sigma(x) = \frac{1}{1 + e^{-x}} = \frac{e^x}{e^x + 1} = \frac{e^x}{e^x + e^0} = s([x, 0])_1$$ + +Ogólniej: softmax na dwuelementowych wektorach daje przesuniętą sigmoidę (przy ustaleniu jednej z wartości). + +#+BEGIN_SRC ipython :session mysession :results file + %matplotlib inline + import matplotlib.pyplot as plt + import torch + import torch.nn as nn + + x = torch.linspace(-5,5,100) + plt.xlabel("x") + plt.ylabel("y") + a = torch.Tensor(x.size()[0]).fill_(2.) + m = torch.stack([x, a]) + plt.plot(x, nn.functional.softmax(m, dim=0)[0]) + fname = 'softmax3.png' + plt.savefig(fname) + fname +#+END_SRC + +#+RESULTS: +[[file:# Out[19]: +: 'softmax3.png' +[[file:./obipy-resources/gjBA7K.png]]]] + +#+BEGIN_SRC ipython :session mysession :results file + %matplotlib inline + import matplotlib.pyplot as plt + from mpl_toolkits import mplot3d + import torch + import torch.nn as nn + + x = torch.linspace(-5,5,10) + y = torch.linspace(-5,5,10) + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + plt.xlabel("x") + plt.ylabel("y") + X, Y = torch.meshgrid(x, y) + m = torch.stack([X, Y]) + z = nn.functional.softmax(m, dim=0) + ax.plot_wireframe(x, y, z[0]) + fname = 'softmax3d.png' + plt.savefig(fname) + fname +#+END_SRC + +#+RESULTS: +[[file:# Out[27]: +: 'softmax3d.png' +[[file:./obipy-resources/p96515.png]]]] + +*** Wagi + +Podobnie jak funkcja sigmoidalna, softmax nie ma żadnych wyuczalnych wag. + +*** Zastosowania + +Podstawowym zastosowaniem funkcji softmax jest klasyfikacja +wieloklasowa, również w wypadku zadań przetwarzania sekwencji, które +mogą być interpretowane jako klasyfikacja wieloklasowa: + +- przewidywanie kolejnego słowa w modelowaniu języka (klasą jest słowo, zbiór klas to słownik, np. klasą początku tekstu /Dzisiaj rano kupiłem w piekarni/ może być /bułki/) +- przypisywanie etykiet (np. części mowy) słowom. + +** LogSoftmax + +Ze względów obliczeniowych często korzysta się z funkcji *LogSoftmax* +która zwraca logarytmy pradopodobieństw (/logproby/). + +$$log s(z_i) = log \frac{e^{z_i}}{\Sigma_{j=1}^k e^{z_j}}$$ + +*** PyTorch + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + + s = nn.LogSoftmax(dim=0) + s(torch.tensor([0.0, -0.2, 0.4])) +#+END_SRC + +#+RESULTS: +:results: +# Out[25]: +: tensor([-1.1971, -1.3971, -0.7971]) +:end: + +Niektóre funkcje kosztu (np. ~NLLLoss~) zaimplementowane w PyTorchu +operują właśnie na logarytmach prawdopobieństw. + +** Przykład: klasyfikacja wieloklasowa + +Na przykładzie rozpoznawania dyscypliny sportu: git://gonito.net/sport-text-classification.git + +Wczytujemy zbiór uczący: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import gzip + from pytorch_regression.analyzer import vectorize_text, vector_length + + texts = [] + labels = [] + labels_dic = {} + labels_revdic = {} + c = 0 + + with gzip.open('sport-text-classification/train/train.tsv.gz', 'rt') as fh: + for line in fh: + line = line.rstrip('\n') + line = line.replace('\\\t', ' ') + label, text = line.split('\t') + texts.append(text) + if label not in labels_dic: + labels_dic[label] =c + labels_revdic[c] = label + c += 1 + labels.append(labels_dic[label]) + nb_of_labels = len(labels_dic) + labels_dic +#+END_SRC + +#+RESULTS: +:results: +# Out[85]: +#+BEGIN_EXAMPLE + {'zimowe': 0, + 'moto': 1, + 'tenis': 2, + 'pilka-reczna': 3, + 'sporty-walki': 4, + 'koszykowka': 5, + 'siatkowka': 6, + 'pilka-nozna': 7} +#+END_EXAMPLE +:end: + +Przygotowujemy model: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch.nn as nn + from torch import optim + + model = nn.Sequential( + nn.Linear(vector_length, nb_of_labels), + nn.LogSoftmax() + ) + + optimizer = optim.Adam(model.parameters()) +#+END_SRC + +#+RESULTS: +:results: +# Out[8]: +:end: + +Funkcja kosztu to log-loss. + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + import torch + import torch.nn.functional as F + + loss_fn = torch.nn.NLLLoss() + + expected_class_id = torch.tensor([2]) + loss_fn(torch.log( + torch.tensor([[0.3, 0.5, 0.1, 0.0, 0.1]])), + expected_class_id) +#+END_SRC + +#+RESULTS: +:results: +# Out[9]: +: tensor(2.3026) +:end: + +Pętla ucząca: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + iteration = 0 + step = 50 + closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + + for t, y_exp in zip(texts, labels): + x = vectorize_text(t).float().unsqueeze(dim=0) + + optimizer.zero_grad() + + y_logprobs = model(x) + + loss = loss_fn(y_logprobs, torch.tensor([y_exp])) + + loss.backward() + + with torch.no_grad(): + closs += loss + + optimizer.step() + + if iteration % 50 == 0: + print((closs / step).item(), loss.item(), iteration, y_exp, torch.exp(y_logprobs), t) + closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + iteration += 1 + + if iteration == 5000: + break +#+END_SRC + +#+RESULTS: +:results: +# Out[86]: +:end: + +Model jest tak prosty, że jego wagi są interpretowalne. + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + with torch.no_grad(): + x = vectorize_text('NBA').float().unsqueeze(dim=0) + y_prob = model(x) + torch.exp(y_prob) +#+END_SRC + +#+RESULTS: +:results: +# Out[26]: +: tensor([[0.0070, 0.0075, 0.0059, 0.0061, 0.0093, 0.9509, 0.0062, 0.0071]]) +:end: + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + with torch.no_grad(): + x = vectorize_text('NBA').float().unsqueeze(dim=0) + ix = torch.argmax(x).item() + model[0].weight[:,ix] +#+END_SRC + +#+RESULTS: +:results: +# Out[89]: +#+BEGIN_EXAMPLE + Parameter containing: + tensor([[ 7.8818e-04, 1.0930e-03, 5.9632e-04, ..., 8.1697e-04, + 1.2976e-03, -8.4243e-04], + [-1.0164e-03, -8.9416e-04, -1.8650e-03, ..., 6.6075e-04, + -5.4883e-04, -1.1845e-03], + [-3.1395e-04, 1.8564e-03, -7.0267e-04, ..., -4.7028e-04, + 7.0584e-04, 9.8026e-04], + ..., + [ 4.8792e-05, 1.9183e-03, 1.3152e-03, ..., 4.6495e-04, + 9.5338e-04, 1.9107e-03], + [-5.2181e-04, 1.1135e-03, 7.1943e-04, ..., 3.7215e-04, + 1.0002e-03, -1.7985e-03], + [-9.1641e-04, 1.6301e-03, 1.7372e-03, ..., 1.2390e-03, + -9.1001e-04, 1.5711e-03]], requires_grad=True) +#+END_EXAMPLE +:end: + +Możemy nawet zaprezentować wykres przedstawiający rozmieszczenie słów względem dwóch osi odnoszących się do poszczególnych wybranych dyscyplin. + +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer + %matplotlib inline + import matplotlib.pyplot as plt + + with torch.no_grad(): + words = ['piłka', 'klub', 'kort', 'boisko', 'samochód'] + words_ixs = [torch.argmax(vectorize_text(w).float().unsqueeze(dim=0)).item() for w in words] + + x_label = labels_dic['pilka-nozna'] + y_label = labels_dic['tenis'] + + x = [model[0].weight[x_label, ix] for ix in words_ixs] + y = [model[0].weight[y_label, ix] for ix in words_ixs] + + fig, ax = plt.subplots() + ax.scatter(x, y) + + for i, txt in enumerate(words): + ax.annotate(txt, (x[i], y[i])) +#+END_SRC + +#+RESULTS: +:results: +# Out[45]: +[[file:./obipy-resources/5egYcv.png]] +:end: + +** Zadanie etykietowania sekwencji + +Zadanie etykietowania sekwencji (/sequence labelling/) polega na przypisaniu poszczególnym wyrazom (tokenom) tekstu *etykiet* ze skończonego zbioru. Definiując formalnie: + +- rozpatrujemy ciąg wejściowy tokenów $(t^1,\dots,t^K)$ +- dany jest skończony zbiór etykiet $L = \{l_1,\dots,l_{|L|}\}$, dla uproszczenia można założyć, że etykietami + są po prostu kolejne liczby, tj. $L=\{0,\dots,|L|-1\}$ +- zadanie polega na wygenerowaniu sekwencji etykiet (o tej samej długości co ciąg wejściowy!) $(y^1,\dots,y^K)$, + $y^k \in L$ + +Zadanie etykietowania można traktować jako przypadek szczególny klasyfikacji wieloklasowej, z tym, że klasyfikacji dokonujemy wielokrotnie — dla każdego tokenu (nie dla każdego tekstu). + +Przykłady zastosowań: + +- oznaczanie częściami mowy (/POS tagger/) — czasownik, przymiotnik, rzeczownik itd. +- oznaczanie etykiet nazw w zadaniu NER (nazwisko, kwoty, adresy — najwięcej tokenów będzie miało etykietę pustą, zazwyczaj oznaczaną przez ~O~) + +*** *Pytanie*: czy zadanie tłumaczenia maszynowego można potraktować jako problem etykietowania sekwencji? + +*** Przykładowe wyzwanie NER CoNLL-2003 + +Zob. . + +Przykładowy przykład uczący (~xzcat train.tsv.xz| head -n 1~): + +O O B-MISC I-MISC O O O O O B-LOC O B-LOC O O O O O O O O O O O B-MISC I-MISC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER I-PER O B-LOC O O O O O B-PER I-PER O O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O O O O B-PER I-PER O B-LOC O O O O O O B-PER I-PER O B-LOC O O O O O B-PER I-PER O B-LOC O B-LOC O O O O O B-PER I-PER O O O O O GOLF - BRITISH MASTERS THIRD ROUND SCORES . NORTHAMPTON , England 1996-08-30 Leading scores after the third round of the British Masters on Friday : 211 Robert Allenby ( Australia ) 69 71 71 212 Pedro Linhart ( Spain ) 72 73 67 216 Miguel Angel Martin ( Spain ) 75 70 71 , Costantino Rocca ( Italy ) 71 73 72 217 Antoine Lebouc ( France ) 74 73 70 , Ian Woosnam 70 76 71 , Francisco Cea ( Spain ) 70 71 76 , Gavin Levenson ( South Africa ) 66 75 76 218 Stephen McAllister 73 76 69 , Joakim Haeggman ( Swe ) 71 77 70 , Jose Coceres ( Argentina ) 69 78 71 , Paul Eales 75 71 72 , Klas Eriksson ( Sweden ) 71 75 72 , Mike Clayton ( Australia ) 69 76 73 , Mark Roe 69 71 78 219 Eamonn Darcy ( Ireland ) 74 76 69 , Bob May ( U.S. ) 74 75 70 , Paul Lawrie 72 75 72 , Miguel Angel Jimenez ( Spain ) 74 72 73 , Peter Mitchell 74 71 75 , Philip Walton ( Ireland ) 71 74 74 , Peter O'Malley ( Australia ) 71 73 75 220 Barry Lane 73 77 70 , Wayne Riley ( Australia ) 71 78 71 , Martin Gates 71 77 72 , Bradley Hughes ( Australia ) 73 75 72 , Peter Hedblom ( Sweden ) 70 75 75 , Retief Goosen ( South Africa ) 71 74 75 , David Gilford 69 74 77 . + +W pierwszym polu oczekiwany wynik zapisany za pomocą notacji *BIO*. + +Jako metrykę używamy F1 (z pominięciem tagu ~O~) + +*** Metryka F1 + +*** Etykietowanie za pomocą klasyfikacji wieloklasowej + +Można potraktować problem etykietowania dokładnie tak jak problem +klasyfikacji wieloklasowej (jak w przykładzie klasyfikacji dyscyplin +sportowych powyżej), tzn. rozkład prawdopodobieństwa możliwych etykiet +uzyskujemy poprzez zastosowanie prostej warstwy liniowej i funkcji softmax: + +$$p(l^k=i) = s(\vec{w}\vec{v}(t^k))_i = \frac{e^{\vec{w}\vec{v}(t^k)}}{Z},$$ + +gdzie $\vec{v}(t^k)$ to reprezentacja wektorowa tokenu $t^k$. +Zauważmy, że tutaj (w przeciwieństwie do klasyfikacji całego tekstu) +reprezentacja wektorowa jest bardzo uboga: wektor _one-hot_! Taki +klasyfikator w ogóle nie będzie brał pod uwagę kontekstu, tylko sam +wyraz, więc tak naprawdę zdegeneruje się to do zapamiętania częstości +etykiet dla każdego słowa osobno. + +**** Bogatsza reprezentacja słowa + +Można spróbować uzyskać bogatszą reprezentację dla słowa biorąc pod uwagę na przykład: + +- długość słowa +- kształt słowa (/word shape/), np. czy pisany wielkimi literami, czy składa się z cyfr itp. +- n-gramy znakowe wewnątrz słowa (np. słowo /Kowalski/ można zakodować jako sumę wektorów + trigramów znakówych $\vec{v}(Kow) + \vec{v}(owa) + \vec{v}(wal) + \vec{v}(als) + \vec{v}(lsk) + + \vec{v}(ski)$ + +Cały czas nie rozpatrujemy jednak w tej metodzie kontekstu wyrazu. +(/Renault/ w pewnym kontekście może być nazwą firmy, w innym — +nazwiskiem). + +**** Reprezentacja kontekstu + +Za pomocą wektora można przedstawić nie pojedynczy token $t^k$, lecz +cały kontekst, dla /okna/ o długości $c$ będzie to kontekst $t^{k-c},\dots,t^k,\dots,t^{k+c}$. +Innymi słowy klasyfikujemy token na podstawie jego samego oraz jego kontekstu: + +$$p(l^k=i) = \frac{e^{\vec{w}\vec{v}(t^{k-c},\dots,t^k,\dots,t^{k+c})}}{Z_k}.$$ + +Zauważmy, że w tej metodzie w ogóle nie rozpatrujemy sensowności +sekwencji wyjściowej (etykiet), np. może być bardzo mało +prawdopodobne, że bezpośrednio po nazwisku występuje data. + +Napiszmy wzór określający prawdopodobieństwo całej sekwencji, nie +tylko pojedynczego tokenu. Na razie będzie to po prostu iloczyn poszczególnych wartości. + +$$p(l) = \prod_{k=1}^K \frac{e^{\vec{w}\vec{v}(t^{k-c},\dots,t^k,\dots,t^{k+c})}}{Z_k} = \frac{e^{\sum_{k=1}^K\vec{w}\vec{v}(t^{k-c},\dots,t^k,\dots,t^{k+c})}}{\prod_{k=1}^K Z_k}$$ + +** Warunkowe pola losowe + +Warunkowe pola losowe (/Conditional Random Fields/, /CRF/) to klasa +modeli, które pozwalają uwzględnić zależności między punktami danych +(które można wyrazić jako graf). Najprostszym przykładem będzie prosty +graf wyrażający „następowanie po” (czyli sekwencje). Do poprzedniego +wzoru dodamy składnik $V_{i,j}$ (który można interpretować jako +macierz) określający prawdopodobieństwo, że po etykiecie o numerze $i$ wystąpi etykieta o numerze $j$. + +*** *Pytanie*: Czy macierz $V$ musi być symetryczna? Czy $V_{i,j} = V_{j,i}$? Czy jakieś specjalne wartości występują na przekątnej? + +Macierz $V$ wraz z wektorem $\vec{w}$ będzie stanowiła wyuczalne wagi w naszym modelu. + +Wartości $V_{i,j}$ nie stanowią bezpośrednio prawdopodobieństwa, mogą +przyjmować dowolne wartości, które będę normalizowane podobnie jak to się dzieje w funkcji Softmax. + +W takiej wersji warunkowych pól losowych otrzymamy następujący wzór na prawdopodobieństwo całej sekwencji. + +$$p(l) = \frac{e^{\sum_{k=1}^K\vec{w}\vec{v}(t^{k-c},\dots,t^k,\dots,t^{k+c}) + \sum_{k=1}^{K-1} V_{l_k,l_{k+1}}}}{\prod_{k=1}^K Z_k}$$ diff --git a/wyk/pytorch-regression/analyzer.py b/wyk/pytorch_regression/analyzer.py similarity index 100% rename from wyk/pytorch-regression/analyzer.py rename to wyk/pytorch_regression/analyzer.py diff --git a/wyk/pytorch-regression/analyzer_classification.py b/wyk/pytorch_regression/analyzer_classification.py similarity index 100% rename from wyk/pytorch-regression/analyzer_classification.py rename to wyk/pytorch_regression/analyzer_classification.py diff --git a/wyk/pytorch-regression/linear0-infer.py b/wyk/pytorch_regression/linear0-infer.py similarity index 100% rename from wyk/pytorch-regression/linear0-infer.py rename to wyk/pytorch_regression/linear0-infer.py diff --git a/wyk/pytorch-regression/linear0.py b/wyk/pytorch_regression/linear0.py similarity index 100% rename from wyk/pytorch-regression/linear0.py rename to wyk/pytorch_regression/linear0.py diff --git a/wyk/pytorch-regression/linear1-infer.py b/wyk/pytorch_regression/linear1-infer.py similarity index 100% rename from wyk/pytorch-regression/linear1-infer.py rename to wyk/pytorch_regression/linear1-infer.py diff --git a/wyk/pytorch-regression/linear1.py b/wyk/pytorch_regression/linear1.py similarity index 100% rename from wyk/pytorch-regression/linear1.py rename to wyk/pytorch_regression/linear1.py diff --git a/wyk/pytorch-regression/linear1b.py b/wyk/pytorch_regression/linear1b.py similarity index 100% rename from wyk/pytorch-regression/linear1b.py rename to wyk/pytorch_regression/linear1b.py diff --git a/wyk/pytorch-regression/linear2.py b/wyk/pytorch_regression/linear2.py similarity index 100% rename from wyk/pytorch-regression/linear2.py rename to wyk/pytorch_regression/linear2.py diff --git a/wyk/pytorch-regression/linear3-infer.py b/wyk/pytorch_regression/linear3-infer.py similarity index 100% rename from wyk/pytorch-regression/linear3-infer.py rename to wyk/pytorch_regression/linear3-infer.py diff --git a/wyk/pytorch-regression/linear3.py b/wyk/pytorch_regression/linear3.py similarity index 100% rename from wyk/pytorch-regression/linear3.py rename to wyk/pytorch_regression/linear3.py diff --git a/wyk/pytorch-regression/linear4-batches.py b/wyk/pytorch_regression/linear4-batches.py similarity index 100% rename from wyk/pytorch-regression/linear4-batches.py rename to wyk/pytorch_regression/linear4-batches.py diff --git a/wyk/pytorch-regression/linear4.py b/wyk/pytorch_regression/linear4.py similarity index 100% rename from wyk/pytorch-regression/linear4.py rename to wyk/pytorch_regression/linear4.py diff --git a/wyk/pytorch-regression/linear5.py b/wyk/pytorch_regression/linear5.py similarity index 100% rename from wyk/pytorch-regression/linear5.py rename to wyk/pytorch_regression/linear5.py diff --git a/wyk/pytorch-regression/linear6.py b/wyk/pytorch_regression/linear6.py similarity index 100% rename from wyk/pytorch-regression/linear6.py rename to wyk/pytorch_regression/linear6.py diff --git a/wyk/pytorch-regression/logistic6.py b/wyk/pytorch_regression/logistic6.py similarity index 100% rename from wyk/pytorch-regression/logistic6.py rename to wyk/pytorch_regression/logistic6.py diff --git a/wyk/pytorch-regression/my_linear_regressor.py b/wyk/pytorch_regression/my_linear_regressor.py similarity index 100% rename from wyk/pytorch-regression/my_linear_regressor.py rename to wyk/pytorch_regression/my_linear_regressor.py diff --git a/wyk/pytorch-regression/my_linear_regressor2.py b/wyk/pytorch_regression/my_linear_regressor2.py similarity index 100% rename from wyk/pytorch-regression/my_linear_regressor2.py rename to wyk/pytorch_regression/my_linear_regressor2.py diff --git a/wyk/pytorch-regression/my_neural_network.py b/wyk/pytorch_regression/my_neural_network.py similarity index 100% rename from wyk/pytorch-regression/my_neural_network.py rename to wyk/pytorch_regression/my_neural_network.py diff --git a/wyk/softmax.drawio b/wyk/softmax.drawio new file mode 100644 index 0000000..e1d038e --- /dev/null +++ b/wyk/softmax.drawio @@ -0,0 +1 @@ +7VrbctowEP0aHuPRxTb2Y8ilmXYyzQztNOmbByug1liMEAHy9ZVr+SKJBOIYTGnykLHW8lo651ja1dLDF9PVJx7NJrcsJkkPgXjVw5c9hEIXyv+ZYZ0bPIxzw5jTODfByjCkz0QZgbIuaEzmWkfBWCLoTDeOWJqSkdBsEedsqXd7ZIn+1lk0JpZhOIoS2/qDxmKSWwPUr+w3hI4nxZuhH+Z3plHRWc1kPolitqyZ8FUPX3DGRH41XV2QJMOuwCV/7vqFu+XAOEnFLg+g65+f+VW8GoQPXyi5dAffxc2Z8vIUJQs1YTVYsS4Q4GyRxiRzAnp4sJxQQYazaJTdXUrKpW0ipolsQXmp3BEuyOrFccJy9lI1hE2J4GvZRT2AgAJMKQZ5qr2s8MeFbVLHvkA6UpyPS98VLPJCIfMGlPoWSsjxLKDklIWOxlxw9ptcsIRxaUlZKnsOHmmSGKYooeNUNkcSIiLtgwxAKkV4rm5MaRxnr9kIv05QGwwgnQG4gQF3AwF7wz+w8D+DjnvCBIRHRkBoEYBPF33cPzL0i72wBj9wgtMlwHWPjQC0fZskaXyexRsZjEk0n9ORzoWcO1/fZyA50p1qP8j2GXCA3y8slyuFY95a11t3hFM5oYyh3LiiIvcI+ki1H4rXyevKV9ZY1xqmp3w2JLZiIYMyOWO24CPyClb5ymBzW+Nu0+Zd2DhJIkGf9HFsIlS94Y5ROcJq5cShJh3s9x1geMmnoB6sB0ymryJ2Vb5cjJww1H2JiI+JsHz9VVk5+XcID7cgvFIlGPTrKnH+Y51gYOgkAM1EgqEpEnBYhbhHuTTtKpTO+A/MdaIp/6HBP/KcMDisBLwPCTSQgOu1JAHX714CviUB4Hh9SwYnEyKaMbrbeYhop0hyw/2PDgk6ZwBtypIAOOGPwDwm6J4C+zgx2z5OlwEzU+2eATtTJauZRcDBz3SNxQL5Nk6lmutAmdF0e0DZmVXK+FTq6zka/Yp65an98YCGceegtZBs9NpLIbvNIIzFF4Om4aOxhpQDPFDsiOzY8c2k1tIH4Pv1/EEaMN5n+oBAjs/WRfFYjqRg2FAoqGuh2GWwf0koHR41FcXCQgFB2PhQMvPmu6D801NPZOaw+5aEXZn7kMTb9453CSIEDjweQdhp8IcgdjiL8tsThPR1RILAdko4/Hr97fb83tLFyWSFEG7Pdg6aFeI2igS1YqOvl5H8oqy0eyGp9o172he+5eve9UPepQClMNgePnZaqYLmEUPTPAOaCcuBw0fcRpmiqmUiqIuw01pmtwmGh+S+GFZ/vs4z8JoHF74eueIDVzdxG7lpqRkvxJpmwMfCtU9Z+q/LEr5DloEhy0MvZW2kPaUsA5lFvXc/PZnFzEyNXNhwu9vf0iWb1a+28+7VT9/x1R8= \ No newline at end of file diff --git a/wyk/softmax.png b/wyk/softmax.png new file mode 100644 index 0000000..dad4090 Binary files /dev/null and b/wyk/softmax.png differ