WEBVTT 00:00:07.490 --> 00:00:11.786 Agora que você já sabe o que é um modelo de IA generativa, 00:00:11.786 --> 00:00:16.757 nós vamos dar um mergulho mais profundo e começar a ver 00:00:16.757 --> 00:00:20.530 como podemos implementar esses modelos na prática. 00:00:20.530 --> 00:00:24.710 Para isso, precisamos conhecer a base desses modelos. 00:00:24.710 --> 00:00:26.600 A base para modelos de IA generativas 00:00:26.600 --> 00:00:28.385 são redes neurais artificiais, 00:00:28.385 --> 00:00:32.310 e a base para redes neurais artificiais é álgebra linear. 00:00:32.310 --> 00:00:37.510 Então, nesse laboratório, veremos uma revisão sobre a álgebra linear 00:00:37.510 --> 00:00:41.310 utilizando a biblioteca NumPy do Python. 00:00:41.310 --> 00:00:45.560 Álgebra linear, basicamente, é como podemos fazer operações 00:00:45.560 --> 00:00:47.670 com vetores e matrizes. 00:00:47.670 --> 00:00:49.230 Então, para começar esse laboratório, 00:00:49.230 --> 00:00:52.420 a gente vai começar a relembrar um pouco sobre vetores 00:00:52.420 --> 00:00:56.270 e ver como podemos representar esses vetores no Python. 00:00:56.270 --> 00:00:59.790 Para isso, vamos utilizar a biblioteca NumPy do Python. 00:00:59.790 --> 00:01:05.190 Essa biblioteca é especializada em cálculo numérico e álgebra linear, 00:01:05.190 --> 00:01:08.610 então é a principal biblioteca do Python para esse fim. 00:01:08.610 --> 00:01:11.907 Então, vamos começar o código mportando essa biblioteca 00:01:11.907 --> 00:01:13.810 para dentro do código. 00:01:13.810 --> 00:01:16.970 Então "import numpy as np". 00:01:16.970 --> 00:01:20.893 Bom, para definir um vetor no NumPy, 00:01:20.893 --> 00:01:25.850 eu posso utilizar o módulo "array" do NumPy. 00:01:25.850 --> 00:01:29.424 Então, se eu criar um "vetor_a = np.array" 00:01:29.424 --> 00:01:31.507 e passar uma lista de valores para ele, 00:01:31.507 --> 00:01:35.170 ele vai criar um vetor para mim. 00:01:35.170 --> 00:01:38.960 Se eu quiser criar um segundo vetor, "b", 00:01:38.960 --> 00:01:43.620 eu também posso utilizar o mesmo código. 00:01:43.620 --> 00:01:46.992 Então, "np.array", vou passar uma lista de valores 00:01:46.992 --> 00:01:55.170 e será criado um array, ou um vetor, e associado à variável "vetor_b". 00:01:55.170 --> 00:01:58.602 Nesse código aqui, vamos criar dois vetores, "A" e "B", 00:01:58.602 --> 00:02:01.130 e vamos printar esses vetores. 00:02:01.130 --> 00:02:04.701 Então, aqui nas respostas, vetor A e vetor B, 00:02:04.701 --> 00:02:07.545 da forma como a gente criou anteriormente, 00:02:07.545 --> 00:02:09.651 e as dimensões do vetor A, 00:02:09.651 --> 00:02:13.090 por exemplo, o vetor B tem a mesma dimensão do vetor A. 00:02:13.090 --> 00:02:15.410 Então, o que é a dimensão de um vetor? 00:02:15.410 --> 00:02:17.750 São quantos elementos tem nesse vetor. 00:02:17.750 --> 00:02:21.830 Então, esse vetor tem três elementos, perfeito? 00:02:23.960 --> 00:02:26.916 Se eu quiser fazer a soma desses dois vetores, 00:02:26.916 --> 00:02:31.488 eu posso simplesmente vir aqui e criar uma variável "soma_vetores", 00:02:31.488 --> 00:02:34.879 que vai ser igual a "vetor_a + vetor_b". 00:02:34.879 --> 00:02:37.980 E, aqui, eu vou printar a soma desses vetores. 00:02:37.980 --> 00:02:42.160 Então, quando nós somamos dois vetores, qual a operação é feita? 00:02:42.160 --> 00:02:44.994 Basicamente, uma soma, elemento a elemento, 00:02:44.994 --> 00:02:47.205 então cada elemento do vetor A 00:02:47.205 --> 00:02:49.897 vai ser somado com o mesmo elemento do vetor B, 00:02:49.897 --> 00:02:53.320 e eu vou ter esse resultado aqui na soma. 00:02:53.320 --> 00:02:58.607 Se eu quiser fazer uma subtração, da mesma forma, "vetor_a - vetor_b", 00:02:58.607 --> 00:03:03.220 e o resultado é uma subtração elemento a elemento. 00:03:03.220 --> 00:03:07.240 Então, eu posso, por exemplo, criar uma variável "vetor_multiplicado", 00:03:07.240 --> 00:03:12.720 que vai ser igual ao vetor_a vezes um valor escalar, por exemplo, "2". 00:03:12.720 --> 00:03:15.670 Essa multiplicação também será feita elemento a elemento, 00:03:15.670 --> 00:03:19.054 então cada elemento do vetor A será multiplicado por 2, 00:03:19.054 --> 00:03:21.207 e aqui a gente tem, no nosso código, 00:03:21.207 --> 00:03:23.520 a resposta desse vetor multiplicado. 00:03:23.520 --> 00:03:26.864 Então, 1 vezes 2, 2 vezes 2, 3 vezes 2, 00:03:26.864 --> 00:03:30.980 e a resposta aqui na variável vetor_multiplicado. 00:03:30.980 --> 00:03:33.262 Uma outra operação muito importante 00:03:33.262 --> 00:03:35.081 que eu posso fazer com dois vetores, 00:03:35.081 --> 00:03:37.320 se chama "produto escalar". 00:03:37.320 --> 00:03:40.000 O produto escalar entre dois vetores 00:03:40.000 --> 00:03:43.021 é uma operação onde eu vou multiplicar esses dois vetores 00:03:43.021 --> 00:03:45.550 e o resultado será um número escalar. 00:03:45.550 --> 00:03:47.840 O que esse número representa? 00:03:47.840 --> 00:03:51.150 Esse número representa um certo grau de similaridade 00:03:51.150 --> 00:03:53.169 entre esses dois vetores, ou seja, 00:03:53.169 --> 00:03:55.839 se esses vetores estiverem apontando 00:03:55.839 --> 00:03:59.920 para uma mesma direção, esse produto será maior. 00:03:59.920 --> 00:04:03.760 Se esses produtos estiverem perpendiculares um com o outro, 00:04:03.760 --> 00:04:07.673 ou seja, se tiver um ângulo de 90 graus entre eles, 00:04:07.673 --> 00:04:11.860 esse produto escalar vai retornar algo próximo de 0. 00:04:11.860 --> 00:04:15.083 E se eles estiverem apontando para direções opostas, 00:04:15.083 --> 00:04:20.240 isso significa que esse produto escalar terá um valor negativo. 00:04:20.240 --> 00:04:22.900 Então, basicamente, o produto escalar 00:04:22.900 --> 00:04:25.080 é uma forma de você multiplicar dois vetores 00:04:25.080 --> 00:04:27.282 e obter um escalar como resposta, 00:04:27.282 --> 00:04:29.491 e esse escalar tem um certo significado, 00:04:29.491 --> 00:04:32.425 indica, mais ou menos, se esses dois vetores 00:04:32.425 --> 00:04:34.900 estão apontando para direções parecidas. 00:04:34.900 --> 00:04:36.480 Como eu calculo isso? 00:04:36.480 --> 00:04:38.630 Por trás dos panos, eu estou fazendo 00:04:38.630 --> 00:04:42.240 linhas de um vetor versus colunas do outro. 00:04:42.240 --> 00:04:44.280 Então, se for necessário, por exemplo, nesse caso, 00:04:44.280 --> 00:04:47.140 a gente tem vetores de mesmas dimensões, 00:04:47.140 --> 00:04:52.380 o segundo vetor vai ser transposto, nesse caso. 00:04:52.380 --> 00:04:55.924 Então, se eu fizer, aqui, o produto escalar do vetor A com o vetor B, 00:04:55.924 --> 00:04:58.560 eu vou ter um número, 32. 00:04:58.560 --> 00:05:02.557 Esse número indica, de certa forma, 00:05:02.557 --> 00:05:04.828 se esses dois vetores estão apontando 00:05:04.828 --> 00:05:07.820 para direções similares ou opostas. 00:05:07.820 --> 00:05:09.360 Outro conceito muito importante 00:05:09.360 --> 00:05:10.900 quando a gente fala de álgebra linear 00:05:10.900 --> 00:05:13.600 é o conceito de matrizes. 00:05:13.600 --> 00:05:17.187 Então, diferentemente dos vetores, que têm apenas uma dimensão, 00:05:17.187 --> 00:05:20.900 as matrizes podem ter duas dimensões. 00:05:20.900 --> 00:05:24.300 Então, as matrizes vão ter linhas e colunas. 00:05:24.300 --> 00:05:26.940 Então, serão parecidas com uma tabelinha, 00:05:26.940 --> 00:05:29.420 que teria linhas e colunas. 00:05:29.420 --> 00:05:32.260 Então, eu posso criar, aqui no Python, uma matriz X, 00:05:32.260 --> 00:05:34.247 usando o np.array, 00:05:34.247 --> 00:05:37.368 e, em vez de passar apenas uma lista de valores, 00:05:37.368 --> 00:05:41.786 eu vou passar uma lista de listas de valores, 00:05:41.786 --> 00:05:46.560 onde cada lista vai representar uma linha dessa matriz. 00:05:46.560 --> 00:05:53.006 Essa matriz tem duas linhas, essa linha e essa linha, 00:05:53.006 --> 00:05:57.240 e duas colunas, essa coluna e essa coluna. 00:05:57.240 --> 00:06:01.240 Então, é uma matriz que tem dimensões 2 por 2. 00:06:01.240 --> 00:06:04.404 A matriz Y também é uma matriz 2 por 2, 00:06:04.404 --> 00:06:08.460 porque ela tem duas linhas e duas colunas. 00:06:08.460 --> 00:06:13.310 Se a gente rodar esse código, a gente vai ver essas duas matrizes 00:06:13.310 --> 00:06:19.730 dispostas, aqui, da forma que a gente criou elas, perfeito? 00:06:20.380 --> 00:06:22.830 As operações que a gente pode fazer com as matrizes 00:06:22.830 --> 00:06:25.906 são muito similares às operações que a gente pode fazer 00:06:25.906 --> 00:06:29.200 com os vetores. 00:06:29.200 --> 00:06:32.867 Então, eu posso olhar para o shape dessa matriz, 00:06:32.867 --> 00:06:34.813 vai me dar as dimensões dela, 00:06:34.813 --> 00:06:37.200 então quais são as dimensões dessa matriz? 00:06:37.200 --> 00:06:39.312 No vetor, a gente tinha apenas uma dimensão, 00:06:39.312 --> 00:06:42.640 então a gente criou um vetor de três posições. 00:06:42.640 --> 00:06:46.683 Aqui, eu tenho duas dimensões, eu tenho linhas e colunas, 00:06:46.683 --> 00:06:50.600 então cada uma das nossas matrizes tem duas linhas e duas colunas. 00:06:50.600 --> 00:06:55.310 Isso, a gente consegue saber usando o atributo "shape" da nossa matriz. 00:06:56.990 --> 00:06:59.200 Da mesma forma como vetores, 00:06:59.200 --> 00:07:01.410 como a gente fez para os nossos vetores, 00:07:01.410 --> 00:07:03.250 a gente pode somar matrizes. 00:07:03.250 --> 00:07:05.975 Então, quando eu somo a matriz X com a matriz Y, 00:07:05.975 --> 00:07:09.810 eu estou fazendo a mesma operação que a gente fez para os vetores, 00:07:09.810 --> 00:07:11.816 então eu estou somando, elemento a elemento, 00:07:11.816 --> 00:07:14.970 os valores das duas matrizes. 00:07:14.970 --> 00:07:18.062 Então, se a gente fizer a soma e printar essa soma, 00:07:18.062 --> 00:07:20.956 a gente vai ter o resultado, que é a soma das duas matrizes, 00:07:20.956 --> 00:07:22.630 elemento a elemento. 00:07:22.630 --> 00:07:25.260 Da mesma forma, se a gente fizer a subtração 00:07:25.260 --> 00:07:30.474 entre essas duas matrizes, eu também vou ter o resultado 00:07:30.474 --> 00:07:35.760 como sendo uma matriz resultante de mesma dimensão, 2 por 2, 00:07:35.760 --> 00:07:38.405 onde cada valor é a subtração, elemento a elemento, 00:07:38.405 --> 00:07:42.930 dessas duas matrizes. 00:07:42.930 --> 00:07:47.790 Por fim, eu posso multiplicar essa matriz, ou alguma matriz, 00:07:47.790 --> 00:07:52.330 por um valor escalar, e aí eu também terei uma resposta 00:07:52.330 --> 00:07:56.060 que vai ser a multiplicação desse escalar, por exemplo, o valor "3", 00:07:56.060 --> 00:07:58.670 por cada elemento dessa matriz. 00:07:58.670 --> 00:08:02.224 Então, o resultado também é uma matriz 2 por 2, 00:08:02.224 --> 00:08:05.202 e essa matriz 2 por 2, cada elemento dela 00:08:05.202 --> 00:08:12.370 é o resultado da multiplicação desse escalar pelo valor da matriz. 00:08:12.370 --> 00:08:16.591 Da mesma forma que fizemos o produto escalar para vetores, 00:08:16.591 --> 00:08:19.186 podemos, também, aplicar para matrizes, 00:08:19.186 --> 00:08:21.710 porém, com uma pequena diferença. 00:08:21.710 --> 00:08:24.915 Nos vetores, temos apenas uma dimensão, 00:08:24.915 --> 00:08:29.230 nas matrizes, a gente tem duas dimensões. 00:08:29.230 --> 00:08:31.660 Então, se eu criar uma matriz, por exemplo, 00:08:31.660 --> 00:08:35.169 chamada "matriz_a_mult", 00:08:35.169 --> 00:08:38.712 como uma matriz que vai ter duas linhas e três colunas, 00:08:38.712 --> 00:08:44.010 eu utilizaria esse código aqui para criá-la. 00:08:44.010 --> 00:08:46.572 Poderia criar, também, uma "matriz_b_mult", 00:08:46.572 --> 00:08:49.968 essa matriz ao invés de ter duas linhas por três colunas, 00:08:49.968 --> 00:08:53.400 vai ter três linhas por duas colunas. 00:08:54.210 --> 00:08:55.960 Então, se a gente rodar esse código aqui, 00:08:55.960 --> 00:08:58.630 a gente pode ver, aqui, as nossas duas matrizes. 00:08:58.630 --> 00:09:04.230 Uma tem dimensões dois por três, uma tem dimensões três por dois. 00:09:04.230 --> 00:09:07.136 Para fazer o produto escalar dessas duas matrizes, 00:09:07.136 --> 00:09:09.523 eu posso utilizar o mesmo código do NumPy, 00:09:09.523 --> 00:09:11.726 a mesma função, o mesmo método, 00:09:11.726 --> 00:09:15.350 "np.dot", "matriz_a_mult" e "matriz_b_mult", 00:09:15.350 --> 00:09:19.570 e eu vou ter o resultado dessa multiplicação. 00:09:19.570 --> 00:09:22.570 Note que o resultado dessa multiplicação 00:09:22.570 --> 00:09:25.130 é uma matriz de 2 por 2. 00:09:25.130 --> 00:09:26.900 Então, existe uma regrinha 00:09:26.900 --> 00:09:31.664 para a gente fazer multiplicação matricial através do produto escalar 00:09:31.664 --> 00:09:35.950 e essa multiplicação ser possível. 00:09:35.950 --> 00:09:37.950 Qual seria essa regra? 00:09:37.950 --> 00:09:43.527 As dimensões da minha matriz A, a quantidade de colunas dela 00:09:43.527 --> 00:09:47.990 tem que ser igual à quantidade de linhas da matriz B. 00:09:47.990 --> 00:09:49.810 Então, sempre que eu estiver fazendo o produto escalar 00:09:49.810 --> 00:09:53.927 entre duas matrizes, a quantidade de colunas da primeira 00:09:53.927 --> 00:09:57.730 tem que ser igual à quantidade de linhas da segunda. 00:09:57.730 --> 00:10:02.586 E o resultado sempre será a quantidade de linhas da primeira 00:10:02.586 --> 00:10:06.490 por a quantidade de colunas da segunda. 00:10:06.490 --> 00:10:10.702 Então, essas duas matrizes, eu posso multiplicar, por quê? 00:10:10.702 --> 00:10:13.476 Porque elas obedecem o primeiro quesito, 00:10:13.476 --> 00:10:16.863 a quantidade de colunas da matriz A 00:10:16.863 --> 00:10:19.870 é igual à quantidade de linhas da matriz B. 00:10:19.870 --> 00:10:23.100 E o resultado dessa conta desse produto escalar 00:10:23.100 --> 00:10:28.003 vai dar a quantidade de linhas da matriz A 00:10:28.003 --> 00:10:32.250 pela quantidade de colunas da matriz B, que vai dar 2 por 2. 00:10:32.250 --> 00:10:35.300 Então, se a gente pudesse fixar um pouco essa regra, 00:10:35.300 --> 00:10:40.217 você poderia pensar assim: quando eu for multiplicar duas matrizes, 00:10:40.217 --> 00:10:45.597 fazer o produto escalar delas, os valores de dentro, ou seja, 00:10:45.597 --> 00:10:49.465 a quantidade de colunas da primeira e de linhas da segunda 00:10:49.465 --> 00:10:53.227 tem que ser igual, e o resultado vai dar os dois de fora, ou seja, 00:10:53.227 --> 00:10:55.078 a quantidade de linhas da primeira 00:10:55.078 --> 00:10:57.990 e a quantidade de colunas da segunda. 00:10:57.990 --> 00:11:00.090 Então, seguindo aqui, vamos passar, agora, 00:11:00.090 --> 00:11:05.530 por outras operações relevantes no nosso contexto de álgebra linear. 00:11:05.530 --> 00:11:08.830 Um conceito mega importante, uma operação mega importante 00:11:08.830 --> 00:11:11.170 é inverter uma matriz. 00:11:11.170 --> 00:11:15.980 Para inverter uma matriz, qualquer matriz tem que ser quadrada, 00:11:15.980 --> 00:11:17.875 como a que a gente está criando aqui, 00:11:17.875 --> 00:11:24.270 "matriz_quadrada = np.array", uma matriz de 2 por 2. 00:11:24.270 --> 00:11:25.930 Então, o que é uma matriz quadrada? 00:11:25.930 --> 00:11:29.270 Mesma quantidade de linhas é a mesma quantidade de colunas. 00:11:29.270 --> 00:11:31.230 E ela precisa ser não singular. 00:11:31.230 --> 00:11:37.130 Ser não singular significa que o determinante dela não pode ser 0. 00:11:37.130 --> 00:11:41.937 Então, basicamente, inverter uma matriz, no Python, 00:11:41.937 --> 00:11:47.210 a gente pode fazer utilizando o módulo do NumPy de linear algebra, 00:11:47.210 --> 00:11:50.380 então "np.linalg", 00:11:50.380 --> 00:11:54.150 e do linalg, eu vou usar o método "inv", de inverter. 00:11:54.150 --> 00:11:56.970 Então, vou criar uma variável matriz inversa 00:11:56.970 --> 00:11:59.035 e vou atribuir para ela a inversa, 00:11:59.035 --> 00:12:03.270 o cálculo da inversa dessa matriz quadrada que a gente criou. 00:12:03.270 --> 00:12:06.810 Quando a gente inverte uma matriz, o que significa? 00:12:06.810 --> 00:12:09.840 É como se eu estivesse fazendo um cálculo análogo 00:12:09.840 --> 00:12:13.890 a 1 sobre um determinado número, esse é o inverso dela. 00:12:13.890 --> 00:12:15.450 Então, 1 sobre essa matriz 00:12:15.450 --> 00:12:19.790 é a mesma coisa que a inversa dessa matriz, perfeito? 00:12:19.790 --> 00:12:21.738 Então, se a gente rodar esse código, 00:12:21.738 --> 00:12:25.219 a gente vai ver, aqui, a matriz quadrada que a gente tinha criado 00:12:25.219 --> 00:12:28.126 e, aqui, a inversa dessa matriz quadrada. 00:12:28.126 --> 00:12:31.358 Ela é uma matriz quadrada, então ela pode ser invertível 00:12:31.358 --> 00:12:34.990 e ela é não singular, então ela pode ser invertível também, 00:12:34.990 --> 00:12:38.690 tem que obedecer esses dois critérios aí, perfeito? 00:12:38.690 --> 00:12:41.180 E aí, a gente pode, depois, no nosso código 00:12:41.180 --> 00:12:45.550 verificar essa inversão dessa matriz. 00:12:45.550 --> 00:12:47.070 Como eu poderia fazer isso? 00:12:47.070 --> 00:12:51.230 Se eu fizer o produto escalar da matriz original com a sua inversa, 00:12:51.230 --> 00:12:56.166 eu tenho que ter como resultado a matriz identidade, ou seja, 00:12:56.166 --> 00:12:58.805 a matriz identidade no contexto de álgebra 00:12:58.805 --> 00:13:00.410 é como se fosse o valor 1. 00:13:00.410 --> 00:13:03.632 Então, é como se eu multiplicasse a matriz por 1 sobre a matriz, 00:13:03.632 --> 00:13:08.270 eu vou ter 1 como resposta, é isso que quer dizer esse código aqui. 00:13:10.060 --> 00:13:11.840 Seguindo no nosso código, 00:13:11.840 --> 00:13:14.530 como a gente falou de determinante da matriz, 00:13:14.530 --> 00:13:16.285 a gente pode verificar, aqui, 00:13:16.285 --> 00:13:18.960 como calcular o determinante de uma matriz. 00:13:18.960 --> 00:13:21.783 Então, vou criar, aqui, uma matriz 00:13:21.783 --> 00:13:24.564 para a gente calcular o determinante com base nela 00:13:24.564 --> 00:13:29.177 e eu vou utilizar o mesmo módulo de linear algebra do NumPy, 00:13:29.177 --> 00:13:33.720 só que eu vou usar, agora, o método "det", de determinante. 00:13:33.720 --> 00:13:36.100 Então, qual é o determinante dessa matriz? 00:13:36.100 --> 00:13:37.790 Se a gente rodar esse código, 00:13:37.790 --> 00:13:42.125 a gente vai ver que o determinante dessa matriz é 4.99. 00:13:42.125 --> 00:13:45.138 Se eu tiver uma matriz singular, 00:13:45.138 --> 00:13:47.660 o que significa uma matriz singular? 00:13:47.660 --> 00:13:50.560 Significa que é uma matriz cujo determinante é 0. 00:13:50.560 --> 00:13:54.920 Se o determinante dela é 0, eu não consigo inverter essa matriz. 00:13:54.920 --> 00:13:58.235 Então, essa matriz singular que a gente criou 00:13:58.235 --> 00:14:02.837 mais embaixo do nosso código é uma matriz que não teria inversa, 00:14:02.837 --> 00:14:08.320 não seria possível calcular a inversa dessa matriz, perfeito? 00:14:08.320 --> 00:14:12.647 Outra operação extremamente importante é a norma de um vetor. 00:14:12.647 --> 00:14:16.502 Então, a norma de um vetor é como a gente calcula, 00:14:16.502 --> 00:14:20.100 de certa forma, o tamanho desse vetor. 00:14:20.100 --> 00:14:22.340 Então, a norma desse vetor... 00:14:22.340 --> 00:14:25.900 Existem várias formas de se calcular a norma de um vetor. 00:14:25.900 --> 00:14:29.683 A mais conhecida e a mais utilizada é a norma L2, 00:14:29.683 --> 00:14:33.020 que é também conhecida como a norma Euclidiana. 00:14:33.020 --> 00:14:35.036 Então, ela é dada por essa continha aqui, 00:14:35.036 --> 00:14:40.978 então vai ser a raiz quadrada da soma dos valores dessa matriz, 00:14:40.978 --> 00:14:45.430 desse vetor, ao quadrado, então a raiz quadrada da soma 00:14:45.430 --> 00:14:48.680 dos quadrados dos valores dessa matriz, perfeito? 00:14:48.680 --> 00:14:51.970 Então, se a gente tiver aqui uma matriz 3 e -4, 00:14:51.970 --> 00:14:56.360 a norma Euclidiana dessa matriz vai ser 5. 00:14:56.360 --> 00:14:58.000 Como eu chego nesse cálculo? 00:14:58.000 --> 00:15:01.380 Fazendo a raiz quadrada da soma dos quadrados 00:15:01.380 --> 00:15:04.800 dos valores desse vetor, perfeito? 00:15:04.800 --> 00:15:08.550 Bom, então, para calcular a norma Euclidiana, 00:15:08.550 --> 00:15:12.325 eu posso usar o módulo de álgebra linear do NumPy, 00:15:12.325 --> 00:15:16.300 utilizando o método "norm", certo? 00:15:16.300 --> 00:15:18.520 E eu vou ter a norma Euclidiana. 00:15:18.520 --> 00:15:23.660 Existem, também, outras formas de normas que a gente pode utilizar, 00:15:23.660 --> 00:15:25.820 por exemplo, a norma de Frobenius. 00:15:25.820 --> 00:15:28.120 Não é uma norma muito utilizada, 00:15:28.120 --> 00:15:32.490 mas apenas para a gente conseguir visualizar que existe um parâmetro, 00:15:32.490 --> 00:15:35.945 eu posso parametrizar o tipo de norma que eu quero 00:15:35.945 --> 00:15:40.080 na função, no método "norm" do NumPy. 00:15:40.080 --> 00:15:45.355 Então, por padrão, essa biblioteca já utiliza a norma Euclidiana, 00:15:45.355 --> 00:15:49.087 mas eu poderia definir outra dentre as normas possíveis, 00:15:49.087 --> 00:15:51.163 e, para saber as normas possíveis, 00:15:51.163 --> 00:15:56.200 a gente pode olhar na documentação dessa biblioteca, perfeito? 00:15:57.380 --> 00:16:03.882 Outro cálculo muito interessante, muito importante para criar IAs 00:16:03.882 --> 00:16:06.642 e para a álgebra linear como um todo, 00:16:06.642 --> 00:16:09.620 é você calcular distâncias entre vetores. 00:16:09.620 --> 00:16:11.420 Então, eu posso ter dois vetores 00:16:11.420 --> 00:16:15.540 e eu quero calcular o quão distantes esses vetores são. 00:16:15.540 --> 00:16:18.517 Para fazer a distância entre vetores, 00:16:18.517 --> 00:16:22.080 eu posso, simplesmente, calcular a diferença entre eles. 00:16:22.080 --> 00:16:23.480 Então, se eu calcular a diferença entre eles, 00:16:23.480 --> 00:16:25.380 eu vou ter um menos o outro, 00:16:25.380 --> 00:16:29.430 eu vou ter a distância de cada vetor em cada dimensão. 00:16:30.850 --> 00:16:34.856 Quando eu quero criar, utilizar uma distância Euclidiana, 00:16:34.856 --> 00:16:36.470 o que é a distância Euclidiana? 00:16:36.470 --> 00:16:39.971 É uma distância baseada na norma Euclidiana, 00:16:39.971 --> 00:16:41.702 então vai ser a norma L2, 00:16:41.702 --> 00:16:45.890 a norma Euclidiana da diferença entre os dois vetores, 00:16:45.890 --> 00:16:51.536 então eu vou fazer a raiz quadrada das diferenças elevado ao quadrado, 00:16:51.536 --> 00:16:53.230 essa que é a conta. 00:16:53.230 --> 00:16:57.870 No Python, eu poderia, simplesmente, fazer a norma 00:16:57.870 --> 00:17:00.990 das diferenças dos vetores que a gente calculou aqui. 00:17:00.990 --> 00:17:05.535 E, aqui, eu coloco a ordem 2, a ordem já é presumida que é o 2, 00:17:05.535 --> 00:17:07.912 por default, e aí, a gente tem, aqui, 00:17:07.912 --> 00:17:10.843 o que a gente chama de distância Euclidiana entre dois vetores, 00:17:10.843 --> 00:17:15.910 o quão distantes esses dois vetores estão, certo? 00:17:15.910 --> 00:17:19.690 Outra métrica bastante interessante para se calcular entre dois vetores 00:17:19.690 --> 00:17:21.849 é a distância de Manhattan. 00:17:21.849 --> 00:17:24.406 Então, a única diferença entre a distância Euclidiana 00:17:24.406 --> 00:17:28.450 e a distância de Manhattan é a ordem dessa norma. 00:17:28.450 --> 00:17:30.660 Então, uma a gente chama de norma L2, 00:17:30.660 --> 00:17:32.180 a distância Euclidiana, 00:17:32.180 --> 00:17:34.410 a distância de Manhattan, a gente chama de L1, 00:17:34.410 --> 00:17:38.290 tudo por causa da norma, da ordem da norma. 00:17:38.290 --> 00:17:40.370 O que isso muda na prática? 00:17:40.370 --> 00:17:41.300 Na norma euclidiana, 00:17:41.300 --> 00:17:44.810 isso muda que a gente usa o quadrado das diferenças. 00:17:44.810 --> 00:17:48.102 Na norma de Manhattan, na distância de Manhattan, 00:17:48.102 --> 00:17:51.026 norma L1, a gente usa o módulo, 00:17:51.026 --> 00:17:52.818 como se estivesse usando uma ordem 1, 00:17:52.818 --> 00:17:57.890 elevado a 1, esse número, então a gente usa a norma dos valores. 00:17:57.890 --> 00:18:00.878 Então, se a gente verificar aqui, a gente vai ter diferentes normas 00:18:00.878 --> 00:18:04.402 e cada norma dessa vai ser mais útil ou menos útil 00:18:04.402 --> 00:18:07.420 dependendo do caso de uso que a gente tiver. 00:18:09.210 --> 00:18:12.839 Outras operações úteis aqui no contexto de álgebra linear: 00:18:12.839 --> 00:18:15.494 a gente pode transpor uma matriz, então, frequentemente, 00:18:15.494 --> 00:18:18.950 a gente vai ter que calcular a transposta de uma matriz. 00:18:18.950 --> 00:18:21.150 O que é a transposta de uma matriz? 00:18:21.150 --> 00:18:24.230 É simplesmente eu transformar o que era linha em coluna 00:18:24.230 --> 00:18:26.550 e o que era coluna em linha. 00:18:26.550 --> 00:18:30.170 Então, se eu criar uma matriz 3 por 2 com esses valores, 00:18:30.170 --> 00:18:31.115 com esses elementos, 00:18:31.115 --> 00:18:35.222 a transposta dessa matriz original vai ser, simplesmente, 00:18:35.222 --> 00:18:39.076 essa matriz transposta, ou seja, linhas vão virar colunas 00:18:39.076 --> 00:18:45.416 e colunas vão virar linhas, então, no final, a dimensão dessa matriz 00:18:45.416 --> 00:18:49.070 vai de 3 por 2 para 2 por 3. 00:18:49.070 --> 00:18:51.370 Então, vamos rodar esse código para visualizar. 00:18:51.370 --> 00:18:54.080 Eu tinha uma matriz original 3 por 2, 00:18:54.080 --> 00:18:58.910 a matriz transposta vai ser 2 por 3. 00:18:58.910 --> 00:19:02.730 Outro conceito interessante é você criar uma matriz identidade. 00:19:02.730 --> 00:19:06.935 Então, a matriz identidade é uma matriz similar a um número 1, 00:19:06.935 --> 00:19:10.529 então aquela matriz que, se você multiplicar uma matriz por ela, 00:19:10.529 --> 00:19:13.797 é como se você estivesse multiplicando um número por 1, 00:19:13.797 --> 00:19:16.170 então vai dar ela mesma. 00:19:16.170 --> 00:19:19.340 Então, a matriz identidade no Python, utilizando NumPy, 00:19:19.340 --> 00:19:22.350 a gente usa a função "eye". 00:19:22.350 --> 00:19:25.551 Se eu colocar aqui, como entrada, 2, 00:19:25.551 --> 00:19:30.230 eu vou ter uma matriz identidade 2 por 2, 00:19:30.230 --> 00:19:33.610 se eu colocar 3, eu vou ter uma matriz identidade 3 por 3. 00:19:33.610 --> 00:19:37.460 Então, matriz identidade sempre são matrizes quadradas, ou seja, 00:19:37.460 --> 00:19:40.730 mesmo número de linhas e de colunas. 00:19:40.730 --> 00:19:42.250 Então, se a gente rodar aqui, 00:19:42.250 --> 00:19:47.190 a gente vai ter a matriz identidade, ela é 2 por 2, 00:19:47.190 --> 00:19:49.350 vou ter a matriz transposta, 00:19:49.350 --> 00:19:55.850 e, se eu multiplicar uma matriz por sua identidade, 00:19:55.850 --> 00:19:57.608 se eu fizer o produto escalar entre eles, 00:19:57.608 --> 00:20:04.510 eu vou ter como resultado a mesma matriz original, certo? 00:20:04.510 --> 00:20:11.270 Olha, "[1. 2.] [3. 4.]", resposta "[1. 2.] [3. 4.]", perfeito? 00:20:11.270 --> 00:20:15.450 Agora, algumas funções auxiliares que o NumPy oferece para a gente: 00:20:15.450 --> 00:20:17.260 então o NumPy oferece, por exemplo, 00:20:17.260 --> 00:20:19.885 uma funçãozinha que é interessante 00:20:19.885 --> 00:20:22.767 para o que a gente vai fazer durante as aulas, 00:20:22.767 --> 00:20:25.890 que se chama "linspace". 00:20:25.890 --> 00:20:27.210 O que esse linspace faz? 00:20:27.210 --> 00:20:32.760 Ele simplesmente cria pontos linearmente, igualmente espaçados, 00:20:32.760 --> 00:20:34.030 vamos dizer assim. 00:20:34.030 --> 00:20:36.830 Então, o que essa funçãozinha aqui está fazendo? 00:20:36.830 --> 00:20:41.768 Eu vou criar 5 pontos entre 0 e 10, 00:20:41.768 --> 00:20:45.570 e esses pontos vão ser linearmente espaçados, 00:20:45.570 --> 00:20:49.670 então 0, 2.5, 5, 7.5, 10. 00:20:49.670 --> 00:20:53.440 Tenho 5 pontos e a distância entre eles é igual. 00:20:55.840 --> 00:20:57.647 Outras funções auxiliares: 00:20:57.647 --> 00:21:01.197 eu posso criar uma matriz só com zeros no Python, 00:21:01.197 --> 00:21:04.757 utilizando a função "np.zeros". 00:21:04.757 --> 00:21:06.643 E, aqui, eu posso passar como entrada, 00:21:06.643 --> 00:21:08.216 como parâmetro para essa função, 00:21:08.216 --> 00:21:11.190 a dimensão da matriz que eu quero criar. 00:21:11.190 --> 00:21:13.110 Então, eu vou criar uma matriz de zeros 00:21:13.110 --> 00:21:16.230 com dimensões de 2 linhas e 3 colunas. 00:21:16.230 --> 00:21:19.290 Da mesma forma, eu posso criar uma matriz de números 1s, 00:21:19.290 --> 00:21:22.350 utilizando "np.ones". 00:21:22.350 --> 00:21:25.980 Vou passar aqui, eu quero criar uma matriz de 3 linhas e 2 colunas 00:21:25.980 --> 00:21:28.230 só com números uns. 00:21:28.230 --> 00:21:33.190 Então, está aqui a nossa matriz de zeros e a nossa matriz de uns. 00:21:33.190 --> 00:21:37.734 E a gente pode, também, concatenar esses vetores, 00:21:37.734 --> 00:21:42.310 ou seja, eu posso juntar dois vetores, ou juntar duas matrizes. 00:21:42.310 --> 00:21:47.924 Então, aqui, por exemplo, eu tenho uma matriz chamada "array1" 00:21:47.924 --> 00:21:55.119 e essa matriz é "np.array", primeira linha, segunda linha, 00:21:55.119 --> 00:21:57.230 cada uma com duas colunas. 00:21:57.230 --> 00:22:00.319 E eu posso ter um vetor, uma matriz que, na verdade, 00:22:00.319 --> 00:22:05.850 aqui, vai ter uma linha só, uma linha e duas colunas. 00:22:05.850 --> 00:22:12.430 Então, se eu concatenar esses dois arrays aqui, esses dois vetores, 00:22:12.430 --> 00:22:14.760 essas duas matrizes, aqui no caso, 00:22:14.760 --> 00:22:18.715 eu vou ter, na verdade, no final, uma matriz, 00:22:18.715 --> 00:22:21.515 esse array concatenado vai adicionar essa linha 00:22:21.515 --> 00:22:24.670 nesse vetor original que tinha só duas linhas. 00:22:24.670 --> 00:22:27.280 Então, vou ter um vetor de 3 linhas e 2 colunas, 00:22:27.280 --> 00:22:30.810 uma matriz, no caso, de 3 linhas e 2 colunas. 00:22:32.090 --> 00:22:35.216 Esse parâmetro aqui, "axis", significa: 00:22:35.216 --> 00:22:38.033 quando é 0, eu vou adicionar nas linhas, 00:22:38.033 --> 00:22:41.530 quando são colunas, eu vou adicionar nas colunas, 00:22:41.530 --> 00:22:44.630 então um eu vou adicionar embaixo, o outro eu vou adicionar ao lado, 00:22:44.630 --> 00:22:46.470 é como se fosse isso. 00:22:46.970 --> 00:22:49.571 Então, aqui, eu tenho um exemplo tanto adicionando linhas 00:22:49.571 --> 00:22:51.650 a uma matriz original, 00:22:51.650 --> 00:22:54.190 quanto adicionando colunas a uma matriz original. 00:22:54.190 --> 00:22:56.515 Então, se a gente rodar esse exemplo, 00:22:56.515 --> 00:22:59.339 eu tenho a matriz 1, 2 por 2, 00:22:59.339 --> 00:23:04.150 e a matriz 2, que é uma linha por duas colunas. 00:23:04.150 --> 00:23:07.885 Quando eu concateno elas utilizando o eixo 0, o axis 0, 00:23:07.885 --> 00:23:10.650 eu vou adicionar uma linha a mais. 00:23:10.650 --> 00:23:12.810 No outro exemplo, no debaixo, 00:23:12.810 --> 00:23:19.512 eu tenho uma matriz de duas linhas e uma coluna, 00:23:19.512 --> 00:23:23.570 e eu vou concatenar um array nas colunas, 00:23:23.570 --> 00:23:27.170 então eu vou adicionar duas colunas diferentes. 00:23:27.170 --> 00:23:32.319 Então, eu continuo com o 7 e 8, vou adicionar o 1, 3, 2, 4 aqui, 00:23:32.319 --> 00:23:38.690 como colunas novas nessa matriz original. 00:23:38.690 --> 00:23:41.621 E, por último, para fechar o nosso lab, 00:23:41.621 --> 00:23:45.365 eu também posso utilizar uma função de reshape nos meus dados, 00:23:45.365 --> 00:23:48.670 nos meus arrays, nos meus vetores e matrizes. 00:23:48.670 --> 00:23:50.280 O que o reshape vai fazer? 00:23:50.280 --> 00:23:55.150 Eu consigo alterar o formato dessa matriz ou desse array. 00:23:55.150 --> 00:23:59.009 Então, imagina que eu tenho uma matriz, um array, na verdade, 00:23:59.009 --> 00:24:02.370 que eu tenho 6 elementos nesse array. 00:24:02.370 --> 00:24:07.040 Eu posso fazer um reshape nesse dado, nessa matriz, 00:24:07.040 --> 00:24:12.250 e transformá-lo em uma matriz de duas linhas e três colunas. 00:24:12.250 --> 00:24:15.045 O único ponto importante para a gente pensar é: 00:24:15.045 --> 00:24:18.290 no final, essa conta tem que fechar, 00:24:18.290 --> 00:24:23.259 então, se eu tenho 6 colunas, 6 números, 6 elementos nesse vetor, 00:24:23.259 --> 00:24:25.574 e eu quero transformá-lo em uma matriz, 00:24:25.574 --> 00:24:28.423 as dimensões, aqui, têm que multiplicar 00:24:28.423 --> 00:24:32.631 e dar o mesmo resultado que a quantidade de elementos 00:24:32.631 --> 00:24:34.890 desse vetor original. 00:24:34.890 --> 00:24:38.250 Então, se eu tenho 6 elementos, 2 vezes 3 tem que dar 6. 00:24:38.250 --> 00:24:41.500 Eu poderia, também, fazer 3 por 2, ou 6 por 1, 00:24:41.500 --> 00:24:45.310 mas eu não poderia fazer 2 por 4, porque daria erro. 00:24:45.310 --> 00:24:48.010 Então, se a gente rodar aqui, tem o array original, 00:24:48.010 --> 00:24:51.580 e esse array, quando eu fizer o reshape de 2 por 3 dele, 00:24:51.580 --> 00:24:54.445 ele vai reajustar esses elementos 00:24:54.445 --> 00:24:57.470 em uma matriz de duas linhas e três colunas. 00:24:57.470 --> 00:25:00.130 Se eu colocasse 4 aqui, daria erro. 00:25:00.470 --> 00:25:01.310 Por que daria erro? 00:25:01.730 --> 00:25:03.370 Porque eu só tenho 6 elementos. 00:25:03.750 --> 00:25:07.570 Para fazer um reshape de 2 e 4, eu teria que ter 8 elementos. 00:25:08.290 --> 00:25:11.670 Então o único ponto de atenção seria esse. 00:25:12.670 --> 00:25:17.910 Então agora você já sabe muito sobre a generativa e já deu seus 00:25:17.910 --> 00:25:23.710 primeiros passos sobre álgebra linear para conseguir você mesmo 00:25:23.710 --> 00:25:26.350 implementar os seus próprios modelos de a generativa.