├── .autolinks_ignore
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── autolinks.py
├── autotc.py
├── cleaner.py
├── hooks
├── pre-commit
└── pre-merge-commit
├── out
├── Curriculum.md
├── EXTRA_publish
│ └── Publish_or_perish.ipynb
├── L01_Intro.ipynb
├── L02_Linear_models.ipynb
├── L03_Classic_ML.ipynb
├── L04_Feature_Engineering.ipynb
├── L05_Neural_networks.ipynb
├── L06_CNN.ipynb
├── L07_Learning_techniques.ipynb
├── L08_NN_architectures.ipynb
├── L09_RNN.ipynb
├── L10_Transformers.ipynb
├── L11_Segmentation_Detection.ipynb
├── L12_Representation_learning.ipynb
├── L13_Generative_models.ipynb
├── L14_Explainability.ipynb
├── L15_RL.ipynb
└── Simplified
│ └── L01_Intro_Simplified.ipynb
└── requirements.txt
/.autolinks_ignore:
--------------------------------------------------------------------------------
1 | *.csv
2 | *.zip
3 | *.txt
4 | *.md
5 | fox.jpg
6 | imagenet_class_index.json
7 | cat_and_dog2.png
8 | cat_and_dog1.jpg
9 | audio_example.wav
10 | weights_stylegan.pt
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.mp4 filter=lfs diff=lfs merge=lfs -text
2 | *.jpg filter=lfs diff=lfs merge=lfs -text
3 | *.jpeg filter=lfs diff=lfs merge=lfs -text
4 | *.onnx filter=lfs diff=lfs merge=lfs -text
5 | *.png filter=lfs diff=lfs merge=lfs -text
6 | *.bmp filter=lfs diff=lfs merge=lfs -text
7 | *.pt filter=lfs diff=lfs merge=lfs -text
8 |
9 | *.ipynb text
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.icloud
2 | *.DS_Store
3 | *.idea
4 | *.vs
5 | *.ipynb_checkpoints
6 | *__pycache__
7 | *runs
8 | *_backup.ipynb
9 | *.env
10 | *.venv
11 | *env
12 | *venv
13 | out/*/cleaner.py
14 | out/cleaner.py
15 | src/*/cleaner.py
16 | src/cleaner.py
17 | run_script.bat
18 | clean.bat
19 | links.log
20 | autolinks.bat
21 | autolinks.sh
22 | out/content/
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MSU.AI
2 |
3 | Репозиторий проекта **[Искусственный интеллект и наука МГУ имени М.В. Ломоносова](https://msu.ai)**
4 |
5 | Курс: **[Нейронные сети и их применение в научных исследованиях](https://msu.ai/nn_for_scientists)**
6 |
7 | Здесь разрабатываются блокноты jupyter, по которым читается курс. Наиболее актуальные блокноты доступны в верхушке дефолтной ветви репозитория. Все изображения и другие медиаресурсы блокнотов хранятся отдельно на веб сервере и попадают в блокноты через гиперссылки. Рекомендуемая среда для запуска блокнотов - [Google Colab](https://colab.research.google.com). **Блокноты нужно сначала запускать** на полное выполнение (Run all), а затем читать, так как часть иллюстраций генерируется кодом. Блокноты с заданиями не публикуются.
8 |
9 | ## СС0 - лицензия публичного достояния
10 |
11 | Весь разработанный **курс передан в публичное достояние**. Тексты, коды - написаны нами. Изображения по большей части нарисованы нами и тоже распространяются **вместе с исходниками** под лицензией CC0 в отдельном репозитории https://github.com/EPC-MSU/EduNet-content. Все остальные изображения это ссылки на чужой результат, который не требует перерисовки и мы ссылаемся на автора в тексте блокнота. Датасеты, тем более, по большей части заимствованные и тоже содержат ссылки на источник.
12 |
13 | **Зачем это сделано?** Для того, чтобы без оглядки на юристов, можно было на основе наших материалов создать свой учебный курс, полностью скопировать наш, создать свой коммерческий продукт и продавать его, и т.д. Иными словами - заниматься конструктивной деятельностью и не беспокоиться об ограничениях. Это подарок человечеству во имя всеобщего процветания.
14 |
15 | **Что позволило это сделать?** Мы работаем при поддержке некоммерческого фонда развития науки и образования [«Интеллект»](https://intellect-foundation.ru/). Мы не ставим целью продажу курса, поэтому наработанные материалы не нужно прятать от потенциальных покупателей. Наши цели это повышение качества науки в МГУ. Максимально открытая лицензия этому не противоречит.
16 |
17 | ## Как пользоваться
18 |
19 | В папке `out` находятся сами блокноты. Они разбиты по лекциям. План занятий выделен в файл `Curriculum.md` и он автогенерируется на основе заголовков H1 и H2 в блокнотах.
20 |
21 | Для использования нужно иметь аккаунт в Google. Зайти в [Google Colab](https://colab.research.google.com). Выбрать там загрузку файла блокнота (Upload). Загрузить любой файл блокнота лекции - например `L07_Batch_normalization.ipynb`. В меню `Runtime` выбрать `Change runtime type` и вместо None поставить GPU. Затем там же нажать `Run all` и подождать выполнения блокнота до конца. Мы следим за тем, что блокноты должны выполнятся от начала до конца без остановок, а также за тем, чтобы время выполнения блокнота было не больше 20 минут (на Google Colab Pro).
22 |
23 | **Profit!**
24 |
25 | ### Возможные проблемы
26 |
27 | - **Не грузятся картинки**. Это может быть по нашей вине, а может вы выбрали не ту ветвь. Проверьте, что файл лекции выгружен с верхушки дефолтной ветви. Обычно мы поддерживаем одновременно несколько ветвей, но бывают разные сбои, даже с применением автоматики.
28 | - **Не работает код**. Причиной чаще всего являются изменения в версиях библиотек в [Google Colab](https://colab.research.google.com). Иногда разработчик библиотек меняет правила пользования без периода предупреждения. Причиной также может быть недоступность внешнего ресурса (не скачивается датасет). Мы кэшируем датасеты на своём сервере, чтобы от этого защититься. Два раза в год мы проверяем, что код работает без сбоев и исправляем его, а также внешние зависимости, если видим ошибку.
29 |
30 | Будем признательны, если вы сообщите об обнаруженных проблемах через Issue. Мы тратим силы на проверки, чтобы наши материалы работали у всех, так что информация о сбоях важна для нас.
31 |
32 | ### Локальный запуск
33 |
34 | Все блокноты должны запускаться и локально, с помощью jupyter notebook, но мы это не проверяем. Нужные пакеты мы выписывали в `requirements.txt`.
35 |
36 | ```
37 | pip install -r requirements.txt
38 | ```
39 | Также, предположительно, блокноты можно запускать в [**DataSphere**](https://u.habr.com/yds_service) от Яндекса.
40 |
41 | ## Как разрабатывать
42 |
43 | В папке `hooks` находятся хуки для чистки блокнотов перед коммитом. Это важный автоматический инструмент, чтобы блокнот не прорастал метаданными, которые там остаются даже после команды `Clear all outputs`. Этим особенно страдает Colab, в котором как раз удобно редактировать файлы блокнотов. Хук запускает скрипт очистки блокнота от метаданных `cleaner.py`. Скрипт можно запускать и вручную, но это неудобно.
44 |
45 | `autotc.py` нужен для построения файла `Curriculum.md`, содержащего программу занятий. Таким образом, программа занятий всегда соответствует заголовкам блокнота.
46 |
47 | `autolinks.py` нужен для автоматизированной проверки внешних ссылок.
48 |
49 | ### Workflow
50 |
51 | Разработка ведётся с использованием `ticket-branch`. Номер `ticket-branch` привязан к внутренней системе треккинга задач. Именование главных ветвей двухциферное (например dev-1.7). Ведётся несколько таких ветвей, где наиболее старые это legacy, затем есть дефолтная ветвь, являющаяся стабильной, и ветвь для новых нестабильных доработок для следующего набора на курс.
52 |
53 | ### Нейминг
54 |
55 | Кириллица в названиях недопустима, вместо пробелов - нижние подчеркивания, префикс - L для обозначения лекции, нумерация из двух цифр, далее - тема лекции.
56 | Первая буква темы лекции заглавная, остальные строчные.
57 |
58 | #### Подробнее о cleaner.py
59 | * Скрипт `cleaner.py` очищает метаданные (чтобы блокноты не весили десятки МБ), выводит предупреждения о ссылках на локальные изображения или изображения вставленные в бинарном виде.
60 | * Запускать можно из консоли с аргументами (аргументы смотрите через `-h`) либо настроить гит-хук, который автоматически будет его запускать во время коммита.
61 | * Настройка хуков:
62 | * Копировать папку `hooks` внутрь папки `.git` слиянием/заменой (.git может быть скрыта в системе)
63 | * Если у вас Linux/Mac могут возникнуть проблемы с правами файла, поэтому нужно дать доступ:
64 | * (Linux/Mac) В терминале: `chmod +x .git/hooks/pre-commit` и `chmod +x .git/hooks/pre-merge-commit`
65 | * (Mac) Иногда нужно дополнительно вызвать: `xattr -d com.apple.quarantine .git/hooks/pre-commit` и `xattr -d com.apple.quarantine .git/hooks/pre-merge-commit`
66 | * При нажатии на кнопку коммит, скрипт автоматически запустится и в локальную ветвь попадут уже почищенные блокноты.
67 | * В smartgit до нажатия кнопки коммита изменения не видны. После нажатия, перед пушем их можно увидеть в локальной ветке.
68 | * Не забыть сделать всё то же самое для репозитория secret
69 |
--------------------------------------------------------------------------------
/autolinks.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import re
4 | import logging
5 | import argparse
6 | from fnmatch import fnmatch
7 |
8 |
9 | img_pattern = re.compile(r"
") # pattern for image markdown in notebook
10 | path_pattern = re.compile(r"^https://edunet\.kea\.su/repo/(EduNet-(?:(?:content)|(?:web_dependencies))/(L\d+)/.+\..+)$") # pattern for image path
11 | lpattern = re.compile(r"^(L\d+)(_\w*)?\.ipynb$") # lecture filename pattern
12 |
13 |
14 | parser = argparse.ArgumentParser()
15 | parser.add_argument("--diskpath",
16 | help="Path to disk on your computer",
17 | default=os.path.join("Z:", "Sites", "edunet.kea.su", "repo"))
18 | parser.add_argument("--path",
19 | help="Path to notebooks with lectures",
20 | default=os.path.join(".", "out"))
21 | parser.add_argument("--logfile", help="Path to log file", default="links.log")
22 | parser.add_argument("--append", help="Append previous log", default=False, action="store_true")
23 |
24 |
25 | logger = logging.getLogger(__name__)
26 | logger.setLevel(logging.DEBUG)
27 | fmt = logging.Formatter("[%(levelname)s] [%(asctime)s] %(name)s: %(message)s")
28 | sh = logging.StreamHandler()
29 | sh.setLevel(logging.DEBUG)
30 | sh.setFormatter(fmt)
31 | logger.addHandler(sh)
32 |
33 |
34 | def get_lecture_links(path):
35 | with open(path, encoding="utf-8") as f:
36 | lecture = json.load(f)
37 | if "cells" not in lecture:
38 | logger.warning(f"File ({path}) incorrect!")
39 | return []
40 | links = []
41 | for i, cell in enumerate(lecture["cells"]):
42 | if cell["cell_type"] != "markdown":
43 | continue
44 | for src in cell["source"]:
45 | match = img_pattern.search(src)
46 | if not match:
47 | continue
48 | link = match.group(1)
49 | match = path_pattern.match(link)
50 | if match:
51 | links.append((True, link, match.group(1), match.group(2)))
52 | else:
53 | links.append((False, link, None, None))
54 | return links
55 |
56 |
57 | def get_disk_links(relpath):
58 | links = set()
59 | abspath = os.path.join(REPO_PATH, relpath)
60 | try:
61 | for filename in os.listdir(abspath):
62 | if any([fnmatch(filename, pattern) for pattern in ignore_list]):
63 | continue
64 | links.add(relpath.replace("\\", "/") + "/" + filename)
65 | except FileNotFoundError:
66 | logger.warning(f"Can't get disk links from {abspath}")
67 | return links
68 |
69 |
70 | def check_lecture(path, lecture_code, logfile):
71 | disk_links = get_disk_links(os.path.join(CONTENT_DIR_NAME, lecture_code, "img_license"))
72 | disk_links = disk_links | get_disk_links(os.path.join(DEP_DIR_NAME, lecture_code))
73 |
74 | lecture_links = get_lecture_links(path)
75 |
76 | unsupported = set()
77 | incorrect_code = set()
78 | not_on_disk = set()
79 | existing = set()
80 |
81 | for supported, link, ref, code in lecture_links:
82 | if not supported:
83 | unsupported.add(link)
84 | continue
85 | if code != lecture_code:
86 | incorrect_code.add(link)
87 | continue
88 |
89 | if ref not in disk_links:
90 | not_on_disk.add(link)
91 |
92 | existing.add(ref)
93 |
94 | not_used = set()
95 |
96 | for link in disk_links:
97 | if link not in existing:
98 | not_used.add(link)
99 |
100 | with open(logfile, "a") as f:
101 | print(f"Lecture {lecture_code}:", file=f)
102 | print("\tNot used:", file=f)
103 | for link in not_used:
104 | print(f"\t\t- {link}", file=f)
105 | print("\tNot on disk:", file=f)
106 | for link in not_on_disk:
107 | print(f"\t\t- {link}", file=f)
108 | print("\tIncorrect code:", file=f)
109 | for link in incorrect_code:
110 | print(f"\t\t- {link}", file=f)
111 | print("\tUnsupported source:", file=f)
112 | for link in unsupported:
113 | print(f"\t\t- {link}", file=f)
114 | print("\n", file=f)
115 |
116 |
117 | if __name__ == "__main__":
118 | args = parser.parse_args()
119 |
120 | CONTENT_DIR_NAME = "EduNet-content"
121 | DEP_DIR_NAME = "EduNet-web_dependencies"
122 | REPO_PATH = args.diskpath
123 |
124 | if not os.path.exists(REPO_PATH):
125 | logger.error(f"Path to repo on disk not exists: '{REPO_PATH}'")
126 | exit(1)
127 |
128 | mode = "a" if args.append else "w"
129 |
130 | logger.debug(f"Disk files located in {REPO_PATH}")
131 |
132 | autolinks_ignore_path = os.path.join(os.getcwd(), ".autolinks_ignore")
133 | ignore_list = set()
134 | if os.path.isfile(autolinks_ignore_path):
135 | with open(autolinks_ignore_path) as f:
136 | ignore_list |= {line.strip() for line in f.readlines()}
137 | print(ignore_list)
138 |
139 | with open(args.logfile, mode) as f:
140 | print("--- Links checker log ---\n", file=f) # create logfile
141 |
142 | logger.info("Check started!")
143 |
144 | for fname in sorted(os.listdir(args.path)):
145 | match = lpattern.match(fname)
146 | if not match:
147 | continue
148 | lecture_code = match.group(1)
149 | path = os.path.join(args.path, fname)
150 | check_lecture(path, lecture_code, args.logfile)
151 |
152 | logger.info("Check success!")
153 |
--------------------------------------------------------------------------------
/autotc.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import re
4 | import logging
5 | import argparse
6 |
7 |
8 | logger = logging.getLogger(__name__)
9 | logger.setLevel(logging.DEBUG)
10 | ch = logging.StreamHandler()
11 | ch.setLevel(logging.DEBUG)
12 | fmt = logging.Formatter("[%(levelname)s] [%(asctime)s] %(name)s: %(message)s")
13 | ch.setFormatter(fmt)
14 | logger.addHandler(ch)
15 |
16 | parser = argparse.ArgumentParser()
17 | parser.add_argument("--dir", help="Directory with notebooks to process", default="out")
18 | parser.add_argument("--output", help="Output filename", default="temp_Curriculum.md")
19 |
20 | lpattern = re.compile(r"L\d+(_\w*)?\.ipynb") # filename pattern
21 | tpattern = re.compile(r".*<.*>(.*)<\/.*>.*") # title pattern
22 | hpattern = re.compile(r"#{1,2}\s*([^#\n<>]+)") # header pattern
23 | cpattern = re.compile(r"```[^`]*?```") # code pattern in markdown
24 |
25 | def analyze_lecture(path):
26 | with open(path, encoding="utf-8") as f:
27 | lecture = json.load(f)
28 | cells = lecture.get("cells")
29 | if not cells:
30 | logger.warning(f"File '{fname}' incorrect")
31 | return
32 | title_src = "".join(cells[1]["source"])
33 | title = tpattern.match(title_src)
34 | if not title:
35 | title = os.path.basename(path)
36 | logger.warning(f"Lecture's title not found, using name '{title}'")
37 | else:
38 | title = title.group(1).strip()
39 | headers = []
40 | for v in cells[2:]:
41 | if v["cell_type"] != "markdown":
42 | continue
43 |
44 | # get rid of code in markdown so that we don't grab comments
45 | s = "".join(v["source"])
46 | s = cpattern.sub("", s)
47 |
48 | for source in s.split("\n"):
49 | source = cpattern.sub("", source)
50 | header = hpattern.match(source.strip())
51 | if not header:
52 | continue
53 | headers.append(header.group(1))
54 | return title, headers
55 |
56 |
57 | def generate_md(lectures, path):
58 | f = open(path, "w", encoding="utf-8")
59 | print("Программа курса\n", file=f)
60 | i = 1
61 | for title, headers in lectures.items():
62 | print(f"## Лекция {i} “{title}”\n", file=f)
63 | print(". ".join(headers) + "\n", file=f)
64 | i += 1
65 | f.close()
66 | logger.info(f"File created: {path}")
67 |
68 |
69 | def main():
70 | args = parser.parse_args()
71 | out_dir = os.path.abspath(args.dir)
72 | lectures = {}
73 | for fname in sorted(os.listdir(out_dir)):
74 | if not lpattern.fullmatch(fname):
75 | continue
76 | title, headers = analyze_lecture(os.path.join(out_dir, fname))
77 | lectures[title] = headers
78 | logger.info(f"Total analyzed: {len(lectures)}")
79 | generate_md(lectures, os.path.join(out_dir, args.output))
80 |
81 |
82 | if __name__ == "__main__":
83 | main()
84 |
--------------------------------------------------------------------------------
/cleaner.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import base64
4 | import argparse
5 |
6 | import nbformat
7 |
8 |
9 | def save_attachment(filepath, filename, data):
10 | if len(data) == 1:
11 | for meme, base64str in data.items():
12 | with open(os.path.join(filepath, filename), "wb") as f:
13 | f.write(base64.b64decode(base64str))
14 | print(f"\t[SAVED: {filename}]")
15 | else:
16 | print(f"\t[Failed to save: {filename}]")
17 |
18 |
19 | def save_attachments(cell, count_cells, i, lect_path):
20 | if "attachments" in cell:
21 | print(f"\t[WARNING][Cell:{i + 1}/{count_cells}]: Markdown attachments found.")
22 | cell_text = "".join(cell["source"]).replace("\n", "")
23 | print("\t\t", cell_text[:100].rstrip())
24 | for att_name, data in cell["attachments"].items():
25 | name_to_save = f"""img-{ctr["attachments"]}.{os.path.splitext(att_name)[1][1:].strip()}"""
26 | save_attachment(lect_path, name_to_save, data)
27 | ctr["attachments"] += 1
28 |
29 |
30 | def check_source(cell, count_cells, i):
31 | if args.warnings:
32 | cell_text = "".join(cell["source"]).replace("\n", "")
33 | if ";base64," in cell_text:
34 | print(f"\t[WARNING][Cell:{i + 1}/{count_cells}]: Binary data found.")
35 | print("\t\t", cell_text[:150].rstrip())
36 | ctr["warnings"] += 1
37 | elif re.match(r'^.*!\[.*]\(.*\).*$', cell_text) is not None:
38 | print(f"\t[WARNING][Cell:{i + 1}/{count_cells}]: Probably local link found.")
39 | print("\t\t", cell_text[:150].rstrip())
40 | ctr["warnings"] += 1
41 |
42 |
43 | def count_fixes(cell, count_cells, i):
44 | if 'execution_count' in cell:
45 | if cell["execution_count"] is not None:
46 | if cell["execution_count"] != 0:
47 | ctr["execution_count"] += 1
48 | if cell["metadata"] != nbformat.NotebookNode():
49 | ctr["metadata"] += 1
50 | if 'outputs' in cell:
51 | if cell["outputs"] != list():
52 | ctr["outputs"] += 1
53 | if cell['cell_type'] == 'raw':
54 | print(f"\t[WARNING][Cell:{i + 1}/{count_cells}]: Raw cell. Please fix cell type.") #
55 |
56 |
57 | def fix_cell(cell, count_cells, i, lecture_path):
58 | count_fixes(cell, count_cells, i)
59 | check_source(cell, count_cells, i)
60 | save_attachments(cell, count_cells, i, lecture_path)
61 |
62 | # Now save only required data
63 | d_to_save = {'cell_type': cell['cell_type'],
64 | 'metadata': nbformat.NotebookNode(),
65 | 'source': cell['source']}
66 | if cell['cell_type'] == 'code':
67 | d_to_save['execution_count'] = None
68 | d_to_save['outputs'] = []
69 | return nbformat.from_dict(d_to_save)
70 |
71 |
72 | def fix_cells(cells, lecture_path):
73 | new_cells = []
74 | for i, cell in enumerate(cells):
75 | new_cell = fix_cell(cell, len(cells), i, lecture_path)
76 | new_cells.append(new_cell)
77 | return new_cells
78 |
79 |
80 | def process_one_lecture(pathname, backup):
81 | lecture_path = os.path.dirname(pathname)
82 | notebook_name = os.path.basename(pathname)
83 | lect_unchanged = nbformat.read(pathname, as_version=nbformat.NO_CONVERT)
84 |
85 | new_cells = fix_cells(lect_unchanged["cells"], lecture_path)
86 |
87 | new_nb = lect_unchanged
88 | new_nb['cells'] = new_cells
89 | if new_nb["metadata"] != nbformat.NotebookNode():
90 | new_nb["metadata"] = nbformat.NotebookNode()
91 | ctr["metadata"] += 1
92 | if ctr.is_changed():
93 | save_path = pathname
94 | if backup:
95 | backup_patch = os.path.join(lecture_path, notebook_name.split(".")[-2] + "_backup.ipynb")
96 | os.replace(pathname, backup_patch)
97 | nbformat.validate(new_nb)
98 | nbformat.write(new_nb, save_path, version=nbformat.NO_CONVERT)
99 |
100 |
101 | class Counter(dict):
102 | def __init__(self):
103 | super().__init__()
104 | self["metadata"] = 0
105 | self["outputs"] = 0
106 | self["execution_count"] = 0
107 | self["attachments"] = 0
108 | self["warnings"] = 0
109 |
110 | def summary(self):
111 | if sum(list(self.values())) == 0:
112 | print("\tMy congratulations, notebook is perfect!")
113 | else:
114 | if self['warnings'] != 0:
115 | print(f"\tWarings: {self['warnings']}")
116 | if self['metadata'] != 0:
117 | print(f"\tMetadata fixes: {self['metadata']}")
118 | if self['outputs'] != 0:
119 | print(f"\tOutputs fixes: {self['outputs']}")
120 | if self['execution_count'] != 0:
121 | print(f"\tExecution counts fixes: {self['execution_count']}")
122 | if self['attachments'] != 0:
123 | print(f"\tAttachments fixes: {self['attachments']}")
124 |
125 | def reset(self):
126 | self.__init__()
127 |
128 | def is_changed(self):
129 | if sum(list(self.values())) - self['warnings'] == 0:
130 | return False
131 | else:
132 | return True
133 |
134 |
135 | def main():
136 | if args.filepath is not None:
137 | lecture_pathname = args.filepath
138 | if lecture_pathname.endswith('.ipynb'):
139 | ctr.reset()
140 | process_one_lecture(lecture_pathname, backup=args.backup)
141 | ctr.summary()
142 | else:
143 | print('-' * 80)
144 | for path, subdirs, files in os.walk(args.root if args.root is not None else "."):
145 | for name in files:
146 | if name.endswith('.ipynb') and \
147 | ".ipynb_checkpoints" not in path and \
148 | not name.endswith('_backup.ipynb'):
149 | lecture_pathname = os.path.join(path, name)
150 | print(lecture_pathname)
151 | ctr.reset()
152 | process_one_lecture(lecture_pathname, backup=args.backup)
153 | ctr.summary()
154 | if args.root is None:
155 | break
156 |
157 |
158 | if __name__ == "__main__":
159 | parser = argparse.ArgumentParser(description='Script for cleaning notebooks.')
160 | parser.add_argument('--backup', dest='backup', action='store_true',
161 | help="If provided, create a ipynb backup.")
162 | parser.add_argument('--disable-warnings', dest='warnings', action='store_false',
163 | help="Script disable warnings like 'Probably local link found.'")
164 | parser.add_argument('--filepath', default=None,
165 | help='Notebook filepath, if not provided, script processed all files in root, if root '
166 | 'not provided, processed all file in current directory.')
167 | parser.add_argument('--root', default=None,
168 | help="""(default:"None") Processed all file in root folder and all subfolders.""")
169 | parser.set_defaults(backup=False)
170 | parser.set_defaults(warnings=True)
171 |
172 | args = parser.parse_args()
173 | ctr = Counter()
174 | main()
175 |
--------------------------------------------------------------------------------
/hooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #==========BLACK MAGIC ==========
4 | git diff --staged --name-only |
5 | while IFS= read -r line; do
6 | if ! command -v python &> /dev/null
7 | then
8 | python3 cleaner.py --filepath $line
9 | else
10 | python cleaner.py --filepath $line
11 | fi
12 | done
13 | git add --update $(git diff --staged --name-only)
14 | #================================
15 |
16 | if git rev-parse --verify HEAD >/dev/null 2>&1
17 | then
18 | against=HEAD
19 | else
20 | # Initial commit: diff against an empty tree object
21 | against=$(git hash-object -t tree /dev/null)
22 | fi
23 |
24 | # If you want to allow non-ASCII filenames set this variable to true.
25 | allownonascii=$(git config --type=bool hooks.allownonascii)
26 |
27 | # Redirect output to stderr.
28 | exec 1>&2
29 |
30 | # Cross platform projects tend to avoid non-ASCII filenames; prevent
31 | # them from being added to the repository. We exploit the fact that the
32 | # printable range starts at the space character and ends with tilde.
33 | if [ "$allownonascii" != "true" ] &&
34 | # Note that the use of brackets around a tr range is ok here, (it's
35 | # even required, for portability to Solaris 10's /usr/bin/tr), since
36 | # the square bracket bytes happen to fall in the designated range.
37 | test $(git diff --cached --name-only --diff-filter=A -z $against |
38 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
39 | then
40 | cat <<\EOF
41 | Error: Attempt to add a non-ASCII file name.
42 |
43 | This can cause problems if you want to work with people on other platforms.
44 |
45 | To be portable it is advisable to rename the file.
46 |
47 | If you know what you are doing you can disable this check using:
48 |
49 | git config hooks.allownonascii true
50 | EOF
51 | exit 1
52 | fi
53 |
54 | # If there are whitespace errors, print the offending file names and fail.
55 | exec git diff-index --check --cached $against --
56 | cd ..
57 | cd ..
--------------------------------------------------------------------------------
/hooks/pre-merge-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #==========BLACK MAGIC ==========
4 | git diff --staged --name-only |
5 | while IFS= read -r line; do
6 | if ! command -v python &> /dev/null
7 | then
8 | python3 cleaner.py --filepath $line
9 | else
10 | python cleaner.py --filepath $line
11 | fi
12 | done
13 | git add --update $(git diff --staged --name-only)
14 | #================================
15 |
16 | . git-sh-setup
17 | test -x "$GIT_DIR/hooks/pre-commit" &&
18 | exec "$GIT_DIR/hooks/pre-commit"
19 | :
20 |
--------------------------------------------------------------------------------
/out/Curriculum.md:
--------------------------------------------------------------------------------
1 | Программа курса
2 |
3 | ## Лекция 1 “Введение в машинное обучение”
4 |
5 | Два пути. Задача курса. AI, ML, DL. Области применения. Связь с наукой. Обзор курса. Типы задач в ML. Базовые задачи. Комбинированные задачи. План исследования. Сбор и подготовка данных. Разведочный анализ. Baseline. Метрики. Построение модели, эксперименты. Проверка гипотез. Анализ работы модели. Инструменты. Данные. Связность данных. Загрузка и визуализация данных. Работа с данными и моделью. Описание модели k-NN. Простейшая метрика. Параметры и гиперпараметры модели. Разделение train-validation-test. Стратификация. Кросс-валидация. Алгоритм кросс-валидации. Оценка результата кросс-валидации. Типичные ошибки при кросс-валидации. GridSearch. RandomizedSearch. Метрики классификации. Accuracy. Confusion matrix. Balanced accuracy. Precision, Recall. F-мера. AUC-ROC. PR-кривая. Multiclass accuracy. Multilabel. Метрики регрессии. MAE (mean absolute error). MSE (mean squared error). RMSE (root mean squared error). R². MSLE (mean squared logarithmic error)
6 |
7 | ## Лекция 2 “Линейные модели”
8 |
9 | Линейная регрессия. Модель и ее параметры. Функция потерь. Поиск локального минимума. Метод наименьших квадратов. Метрики регрессии. Модель линейной регрессии из библиотеки Sklearn. Метод градиентного спуска. Градиент. Идея градиентного спуска. Выбор скорости обучения. Единый подход к учету смещения. Необходимость нормализации. Cтохастический градиентный спуск. Условия применимости линейной регрессии. Квартет Энскомбе (Anscombe’s quartet). Анализ остатков. Проблема корреляции признаков. Регуляризация. Линейная классификация. Постановка задачи. Переход к вероятностям. Многоклассовая классификация. Cross-Entropy loss. Метод опорных векторов (SVM). 1D классификация. Многомерная классификация. Обобщенные линейные модели. Полиномиальная модель. Kernel SVM. Наивный Байесовский классификатор. Пример на табличных данных. Практические особенности работы с линейными моделями. Нормализация данных. Борьба с переобучением
10 |
11 | ## Лекция 3 “Классическое машинное обучение”
12 |
13 | Необходимость методов классического машинного обучения. Деревья решений. Принцип работы дерева решений. Классификация. Регрессия. Свойства деревьев решений. Bias, Variance, Irreducible error. Бутстрэп. Построение доверительного интервала для качества метрики. Ансамбли. Bagging = **B**ootstrap **agg**regat**ing**. Метод случайных подпространств (RSM, random subspace method). Комбинация RSM и Bagging. Случайный лес. Boosting. Gradient boosting (градиентный бустинг). Модификации градиентного бустинга. Блендинг и Стэкинг. Применение нейронных сетей к табличным данным
14 |
15 | ## Лекция 4 “Генерация и отбор признаков”
16 |
17 | Проблемы при работе с реальными данными. Дисбаланс классов. Обнаружение аномалий. Кластеризация. Алгоритм K-Means. Алгоритм DBSCAN. Кодирование признаков. Типы признаков. Преобразования признаков. Разведочный анализ данных. Описательные статистики. Взаимодействие признаков. Анализ категориальных признаков. Генерация признаков. Baseline. Генерация признаков, полученных при помощи другой модели. Ручная генерация признаков. Отбор признаков. Зачем отбирать признаки. Полный перебор. Одномерный отбор признаков. Отбор признаков на основе моделей. Randomization/Permutation. Boruta. Жадный отбор признаков. Рекомендации по отбору признаков. Задача понижения размерности. Manifold assumption. PCA (Метод главных компонент). Kernel PCA (нелинейный) метод главных компонент. t-SNE (t-distributed Stochastic Neighbor Embedding). UMAP
18 |
19 | ## Лекция 5 “Нейронные сети”
20 |
21 | Ограничения линейных моделей. Проблемы классификации более сложных объектов. Многослойные нейронные сети. Веса и смещения. Нейронная сеть как универсальный аппроксиматор. Обучение нейронной сети. Прямое и обратное распространение. Метод обратного распространения ошибки. Функции потерь (loss functions). Функции активации. Углубление в PyTorch. Пример нейронной сети на MNIST. Dataset и DataLoader. Трансформации (Transforms). Создание нейронной сети. Обучение нейронной сети
22 |
23 | ## Лекция 6 “Сверточные нейронные сети”
24 |
25 | Введение в сверточные нейронные сети. Полносвязная нейронная сеть. Нарушение связей между соседними пикселями. Свертка с фильтром. Сверточный слой нейросети. Применение свёрточных слоёв. Общая структура свёрточной нейронной сети. Другие виды сверток. 1D. 3D. Визуализация. Визуализация весов. Визуализация карт признаков. Feature extractor. Аугментации. Графовые структуры данных. Понятие графа и его составляющих. Графовые свертки. Графовая нейросеть. Lightning. Практические рекомендации
26 |
27 | ## Лекция 7 “Улучшение сходимости нейросетей и борьба с переобучением”
28 |
29 | Трудности при обучении глубоких нейронных сетей. Затухание градиента. Нормализация входов и выходов. Нормализация входных данных. Нормализация целевых значений в задаче регрессии. Инициализация весов. Инициализация Ксавье (Xavier Glorot). Инициализация Каймин Хе (Kaiming He). Важность инициализации весов. Инициализация весов в PyTorch. Слои нормализации. Internal covariate shift. Batch Normalization. Другие Normalization. Регуляризация. L1, L2 регуляризации. Dropout. DropConnect. DropBlock. Batch Normalization до или после Dropout. Оптимизация параметров нейросетей. Обзор популярных оптимизаторов. Ландшафт функции потерь. Сравнение оптимизаторов. Режимы обучения. Ранняя остановка. Уменьшение скорости обучения на плато. Понижение скорости обучения на каждой эпохе. Neural Network WarmUp. Cyclical learning schedule. Model soup. Взаимодействие learning schedule и адаптивного изменения learning rate
30 |
31 | ## Лекция 8 “Архитектуры CNN”
32 |
33 | Базовые компоненты свёрточных сетей. ImageNet. Метрики ImageNet. Baseline (AlexNet 2012). Тюнинг гиперпараметров (ZFnet). Базовый блок (VGGNet 2014). Вычислительные ресурсы. Inception module (GoogLeNet 2014). Stem network. Global Average Pooling. Затухание градиента. BatchNorm (революция глубины). Skip connection (ResNet 2015). Архитектура ResNet. BasicBlock в PyTorch. Bottleneck layer. Stage ratio. Обучение ResNet. Grouped Convolution. Grouped Convolution in PyTorch. ResNeXt. Обзор сети MobileNet (2017 г.). Сравнение моделей. Много skip connection (DenseNet 2016). Ширина вместо глубины (WideResNet 2016). Squeeze-and-Excitation (SENet 2017). Поиск хорошей архитектуры. Обзор сети EfficientNet (2019 г.). Трансформеры. ConvNext (2022). Transfer learning. Torch Image Models (timm). Custom feature extractor. Дистилляция. Hard targets. Soft targets
34 |
35 | ## Лекция 9 “Рекуррентные нейронные сети (RNN)”
36 |
37 | Временные ряды. Компоненты временных рядов. Задачи анализа временных рядов. Особенности валидации при анализе временных рядов. Линейные модели временных рядов. Нелинейные модели временных рядов. Рекуррентный слой в нейронных сетях. RNN слой в PyTorch. Пример прогнозирования временного ряда с помощью RNN. Проблемы RNN. LSTM (Long Short-Term Memory). GRU (Gated Recurrent Unit). Обработка естественного языка (NLP). Bidirectional RNN. Представления текстовых данных. Пример посимвольной генерации текста. Подготовка данных. Создание и обучение модели. Задача Sequence-to-Sequence. Задача машинного перевода. Пример реализации машинного перевода. Метрики качества машинного перевода
38 |
39 | ## Лекция 10 “Трансформеры”
40 |
41 | Классический seq2seq. Cross-Attention. RNN + Cross-Attention. Разновидности функций сходства. Self-Attention. Архитектура сети Transformer. Кодировщик. Подготовка данных. Hugging Face. BERT. Декодировщик. GPT. Методы Генерации текста. Файнтюнинг. Большие языковые модели (LLM). LLaMA. LoRa. DeepSpeed. NLP метрики. BERTScore. Self Attention (ViT 2020). Архитектура ViT. Предсказание с помощью ViT. DeiT: Data-efficient Image Transformers. Использование ViT с собственным датасетом
42 |
43 | ## Лекция 11 “Сегментация и детектирование”
44 |
45 | Постановка задач. Датасет COCO (Common Objects in Context). Семантическая сегментация (Semantic segmentation). Подходы к решению задачи. Увеличение размерности карты признаков. Пирамида признаков. Метрики сегментации. Loss функции для сегментации. Модели для сегментации. Совместимость с timm. Аугментация. Практические рекомендации. Детектирование (Object detection). Детектирование одного объекта. Детектирование нескольких объектов. YOLO: You Only Look Once. Swin Transformer (2021). Оценка качества детекции. Instance Segmentation. Panoptic Segmentation. Promptable Detection and Segmentation. Open-World Localization. Segment Anything Model
46 |
47 | ## Лекция 12 “Обучение представлений”
48 |
49 | Глубокие нейронные сети как модели обучения представлений. Понижение размерности и гипотеза о многообразии. Metric learning. Формирование векторов признаков. Сиамская сеть. Реализация сиамской сети. CLIP. Автоэнкодеры (AE). Архитектура автоэнкодера. Функции потерь в автоэнкодерах. Очищение изображения от шумов. Реализация автоэнкодера. Обнаружение аномалий. Предобучение на неразмеченных данных. Автоэнкодер как генератор и его ограничения. Вариационные автоэнкодеры (VAE). Семплирование в латентном пространстве. Регуляризация латентного пространства. Реализация VAE. Плавная интерполяция. Векторная арифметика. Ограничения VAE. Условные вариационные автоэнкодеры (CVAE). Реализация CVAE
50 |
51 | ## Лекция 13 “Генеративные модели”
52 |
53 | Общий взгляд на генеративные алгоритмы. Задача генерации. Простейший пример: генерация объектов из нормального распределения. Генеративные алгоритмы, основанные на глубоком обучении. Введение в генеративно-состязательные нейронные сети GAN. Вход модели (latent space). Наивный подход в решении задачи генерации. Дискриминатор. Generative adversarial network (GAN). DCGAN — Генерация изображений. Тонкости обучения GAN. Метрики генерации. cGAN — GAN с условием. Модификации GAN. Диффузионные модели. Базовые понятия библиотеки Diffusers. Прямой диффузионный процесс (добавление шума). Обратный диффузионный процесс (удаление шума). Обучение модели. Solver. Диффузия в латентном пространстве. Каскадная диффузия. ControlNet. Конвейеры
54 |
55 | ## Лекция 14 “Explainability”
56 |
57 | Мотивация использования Explainability. Объяснимость моделей классического ML. Оценка важности признаков для линейных моделей. Оценка важности признаков для деревьев решений. Методы, изучающие отклик модели на изменение входных данных. ICE (Individual Conditional Expectation). LIME (Local Interpretable Model-agnostic Explanations). SHAP (SHapley Additive exPlanations). Градиентные методы. Vanilla Gradient. SmoothGrad. Integrated Gradients. Grad-CAM. Критика градиентных методов
58 |
59 | ## Лекция 15 “Обучение с подкреплением”
60 |
61 | Обучение методом проб и ошибок. Мотивация использования обучения с подкреплением. Устоявшаяся терминология. Примеры задач, решаемых с использованием RL. Stateless environment in RL. Задача о многоруких бандитах. Gymnasium framework. Поиск оптимальной стратегии решения. Мета-эвристики в обучении с подкреплением. Cross-entropy method (CEM). Пример CEM в Gym. Марковский процесс принятия решений (Markov decision process, MDP). Markov process. Проблема поиска оптимальной политики. Поиск оптимальной политики Беллмана для MDP (решение "MDP"). Temporal difference (TD)-обучение (TD-learning). Q-Learning. Deep Q-Learning
62 |
63 |
--------------------------------------------------------------------------------
/out/Simplified/L01_Intro_Simplified.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "source": [
6 | "# 1. Машинное обучение "
7 | ],
8 | "metadata": {}
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "source": [
13 | "### 1.1. ML и DL и AI в Computer Science "
14 | ],
15 | "metadata": {}
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "source": [
20 | "**Место глубокого обучения и нейронных сетей в ИИ**\n",
21 | "\n",
22 | "
"
23 | ],
24 | "metadata": {}
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "source": [
29 | "Существует множество разных определений, однако большая часть из них завязана на человеко-машинном взаимодействии, то есть это алгоритмы или методы, которые либо имитируют поведение людей, либо позволяют машине вести себя аналогично людям (то есть проявлять некоторое интеллектуальное-разумное поведение). Область ИИ не ограничивается исключительно машинным обучением, которое состоит из обучения на примерах. В ИИ входит целый ряд алгоритмов, например многоагентные системы (расшифровка) или базы знаний, в которых люди создают связи между разными понятиями."
30 | ],
31 | "metadata": {}
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "source": [
36 | "**Искусственный интеллект (AI/ИИ)** ≈ область ИТ/Computer science, связанная с моделированием интеллектуальных или творческих видов человеческой деятельности.\n",
37 | "\n",
38 | "**Машинное обучение(ML)** — подраздел ИИ, основыванный на концепции, что система с искусственным интеллектом должна уметь самостоятельно накапливать знания, отыскивая закономерности в исходных данных, что позволяет компьютерной системе совершенствоваться по мере накопления опыта. Машинное обучение —не единственный раздел ИИ. Например, базы знаний или многоагентные системы также относят к разделам ИИ.\n",
39 | "\n",
40 | "**Глубокое обучение (Deep Learning, DL)** ≈ Многослойная нейросеть (MLP = multi layer perceptron). Частный случай машинного обучения, позволяющий достичь большей эффективности и гибкости за счет представления мира в виде иерархии понятий, каждое из которых определено через более простые понятия. Иерархическая организация организация дает компьютеру возможность учиться более сложным концепциям путем построения их из более простых.\n",
41 | "\n",
42 | "Модели, которые имеют подобную иерархию, называются глубокими или нейросетевыми. Хотя, если мы возьмем один уровень (слой) такой модели (например линейный классификатор, он же перцептрон), он перестанет быть глубокой моделью, хотя по факту он и является простейшей нейросетью."
43 | ],
44 | "metadata": {}
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "source": [
49 | "### 1.2. Области применения DL "
50 | ],
51 | "metadata": {}
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "source": [
56 | "
"
57 | ],
58 | "metadata": {}
59 | },
60 | {
61 | "cell_type": "markdown",
62 | "source": [
63 | "В последнее время именно такого рода модели показывают высокую эффективность в тех областях, в которых влияние человека казалось превалирующим. В частности, это человеко-компьютерное зрение (Computer Vision, CV), распознавание естественного языка (NLP, извлечение смысла, машинный перевод) и речи. В рамках курса мы рассмотрим, как эта область может применяться на практических задачах и моделях, их решающих. Также мы познакомимся с результатами самых современных исследований по теме. "
64 | ],
65 | "metadata": {}
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "source": [
70 | "### 1.3. Связь DL с наукой "
71 | ],
72 | "metadata": {}
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "source": [
77 | "
"
78 | ],
79 | "metadata": {}
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "source": [
84 | "Помимо прикладных задач существуют еще и научные исследования, результаты которых до известной степени непредсказуемы. Нельзя исключать то, что они окажутся применимы к решению новых задач, в том числе в областях, где применяются технологии DL, где до сих пор активно не использовались. Поддержка такого рода исследований и есть основная задача нашего курса. \n",
85 | "\n",
86 | "В первую очередь для нас важны задачи аспирантов, на которых и будет построены дальнейшие исследования. И именно на основе ваших задач будут сделаны выводы о моделях, рекомендованных под конкретно ваш случай."
87 | ],
88 | "metadata": {}
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "source": [
93 | "# 2. История глубокого обучения "
94 | ],
95 | "metadata": {}
96 | },
97 | {
98 | "cell_type": "markdown",
99 | "source": [
100 | "Теоретические основы искусственных нейронных сетей были заложены более 50 лет назад."
101 | ],
102 | "metadata": {}
103 | },
104 | {
105 | "cell_type": "markdown",
106 | "source": [
107 | "
"
108 | ],
109 | "metadata": {}
110 | },
111 | {
112 | "cell_type": "markdown",
113 | "source": [
114 | "Почему же для решения практических задач их начали активно стали применять только в последние 10 лет?\n",
115 | "\n",
116 | "Давайте разберемся."
117 | ],
118 | "metadata": {}
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "source": [
123 | "### 2.1. Перцептрон"
124 | ],
125 | "metadata": {}
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "source": [
130 | "Предшественниками современных глубоких нейронных сетей были простые линейные модели на основе нейробиологических аналогий. Они принимали множество $n$ входных значений $x_1,...,x_n$ и ассоциировали с ними выход $y$. В ходе обучения такой линейной модели нужно было подобрать такие веса $w_1,...,w_n$, чтобы приблизить выход модели $f(x,w)=x_1w_1+...+x_nw_n$ к желаемому $y$. Веса задавал человек.\n",
131 | "\n",
132 | "Первая модель, которая могла находить нужные веса в процессе обучения, имея примеры входных данных — **перцептрон**."
133 | ],
134 | "metadata": {}
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "source": [
139 | "
"
140 | ],
141 | "metadata": {}
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "source": [
146 | "Перцептро́н, или персептрон (англ. perceptron от лат. perceptio — восприятие; нем. Perzeptron) — математическая или компьютерная модель восприятия информации мозгом (кибернетическая модель мозга), предложенная Фрэнком Розенблаттом в 1957 году и впервые реализованная в виде электронной машины «Марк-1» в 1960 году. Перцептрон стал одной из первых моделей нейросетей, а «Марк-1» — первым в мире нейрокомпьютером. \n",
147 | "\n",
148 | "Классический метод обучения перцептрона — это метод коррекции ошибки. Он представляет собой такой вид обучения с учителем, при котором вес связи не изменяется до тех пор, пока текущая реакция перцептрона остаётся правильной. При появлении неправильной реакции вес изменяется на единицу, а знак (+/-) определяется противоположным от знака ошибки. \n",
149 | "\n",
150 | "У перцептрона имеется ряд ограничений. Самое известное состоит в невозможности обучить функцию XOR — разделения объектов на два класса на основании двух признаков, принимающих значения 1 или 0, для которой объекты с признаками [0,1] и [1,0] относятся к категории 1, а объекты с признаками [1,1] и [0,0] — к категории 0. В данной задаче объекты категории 1 и 0 линейно неразделимы, т.е не существует прямой на плоскости, для которой все точки объекты одного класса расположены с одной стороны, а другого — с другой.\n",
151 | "\n",
152 | "На фоне роста популярности нейронных сетей в 1969 году вышла книга Марвина Минского и Сеймура Паперта, которая показала принципиальные ограничения перцептронов. Это привело к смещению интереса исследователей искусственного интеллекта в противоположную от нейросетей область символьных вычислений."
153 | ],
154 | "metadata": {}
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "source": [
159 | "
"
160 | ],
161 | "metadata": {}
162 | },
163 | {
164 | "cell_type": "markdown",
165 | "source": [
166 | "Одной из важнейших работ, связанных с глубоким обучением, является эксперимент американских биологов из Гарварда. В 1959 были изучены реакции определенных участков кошачьего мозга на определенные простые визуальные стимулы. Как и большая часть открытий, это выяснилось абсолютно случайно. \n",
167 | "\n",
168 | "В мозг кошке был вживлен электрод для того, чтобы определить, на какой рисунок будет реакция. Однако стоит вспомнить, что в то время слайды переключались последовательным движением и именно на это движение случилась реакция. Как только менялся слайд и по экрану проходила граница затвора, по сути простая прямая линия, реакция передавалась и записывалась.\n",
169 | "\n",
170 | "После ряда экспериментов выяснилось, что существуют клетки, реагирующие на простые формы (линии и углы), на движение и движение в определенном направлении или определенной формы. Слои этих клеток образуют определенного рода иерархию, которая лежит в основе концепции нейросетевых методов."
171 | ],
172 | "metadata": {}
173 | },
174 | {
175 | "cell_type": "markdown",
176 | "source": [
177 | "
\n",
178 | "\n",
179 | "\n",
180 | "
1975 - Cognitron: A self-organizing multilayered neural network K.Fukushima"
181 | ],
182 | "metadata": {}
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "source": [
187 | "Таким образом мы можем подчерпнуть некоторые концепции из нейробиологии. Основная заимствованная идея — наличие большого числа вычислительных блоков, взаимодействующих друг с другом.\r\n",
188 | "\r\n",
189 | "Модель **неокогнитрона** — иерархическая многослойная искусственная нейронная сеть, была предложена Кунихико Фукусима для эффективной обработки изображений на основании структуры зрительной системы млекопитающих. Эта модель впоследствии легла в основу современных **сверточных нейронных сетей** — специального вида нейронных сетей для обработки данных с сетчатой структурой (например, изображений, представимых в виде сетки пикселей).\r\n",
190 | "\r\n",
191 | "На момент описания не было ни компьютерных ресурсов для обучения такой модели, ни эффективного алгоритма обучения. Несмотря на то, что нейробиология легла в основу нескольких успешных архитектур нейронных сетей, мы до сих пор знаем недостаточно об обучении биологических нейронных сетей, чтобы использовать эти знания для построения алогритмов обучения искуственных нейронных сетей."
192 | ],
193 | "metadata": {}
194 | },
195 | {
196 | "cell_type": "markdown",
197 | "source": [
198 | "### 2.2. Метод обратного распространения ошибки"
199 | ],
200 | "metadata": {}
201 | },
202 | {
203 | "cell_type": "markdown",
204 | "source": [
205 | "При обучении нейронной сети, информация передается по ней в одном направлении — от входных данных до следующих слоев и далее, порождая некий выход $\\hat{y}$. Такой поток информации называется **прямым распространением**. На основании этого выхода нейронной сети вычисляется функция ошибки $L(\\hat{y},y)$, которая говорит о том, насколько предсказание $\\hat{y}$, сделанное нейронной сетью, отличается от настоящего значения $y$. В простейшем случае $L(\\hat{y},y)=\\hat{y}-y$. Для дальнейшего обучения необходимо учесть эту ошибку, чтобы скорректировать предсказание нейронной сети. **Градиент** функции ошибки показывает направление её наискорейшего возрастания. Соответственно, отрицательный градиент может быть использован для поиска минимума функции ошибки. В современных нейронных сетях для вычисления градиента используется метод обратного распространения ошибки (англ. backpropagation).\n",
206 | "\n",
207 | "**Метод обратного распространения ошибки** позволяет передавать сигналы об ошибке, сделанной нейронной сетью, от выходов сети к её входам, в направлении, обратном прямому распространению. Эти сигналы затем используются для вычисления градиента, используемого для корректировки предсказания нейронной сети. \n",
208 | "\n",
209 | "Для возможности применения метода обратного распространения ошибки передаточные функции нейронов, используемые при прямом распространении, должны быть дифференцируемы.\n",
210 | "\n",
211 | "
\n",
212 | "\n",
213 | "Впервые метод был описан в 1974 г. А. И. Галушкиным, а также независимо и одновременно Полом Дж. Вербосом. Далее существенно развит в 1986 г. Дэвидом И. Румельхартом, Дж. Е. Хинтоном и Рональдом Дж. Вильямсом.\n"
214 | ],
215 | "metadata": {}
216 | },
217 | {
218 | "cell_type": "markdown",
219 | "source": [
220 | "По ссылке можно найти полный перечень работ А.И. Галушкина."
221 | ],
222 | "metadata": {}
223 | },
224 | {
225 | "cell_type": "markdown",
226 | "source": [
227 | "### 2.3. Успехи современных нейронных сетей"
228 | ],
229 | "metadata": {}
230 | },
231 | {
232 | "cell_type": "markdown",
233 | "source": [
234 | "
"
235 | ],
236 | "metadata": {}
237 | },
238 | {
239 | "cell_type": "markdown",
240 | "source": [
241 | "Появление алгоритма обратного распространения ошибки вкупе с возрастающими компьютерными мощностиями позволило обучить многослойную нейронную сеть, которую можно было применять для решения практических задач.\n",
242 | "\n",
243 | "Архитектура такой сети была разработана в 1989 г. Яном Ле Куном. \n",
244 | "Сеть имела **5** слоёв, из них **2** свёрточных.\n",
245 | "\n",
246 | "Применялась в США для распознавания рукописных букв на почтовых конвертах до начала 2000г."
247 | ],
248 | "metadata": {}
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "source": [
253 | "**Победа нейросети AlexNet на соревновании ImageNet в 2012**\n",
254 | "\n",
255 | "
"
256 | ],
257 | "metadata": {}
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "source": [
262 | "В 2012 году свёрточная нейронная сеть **AlexNet** (Alex Krizhevsky in collaboration with Ilya Sutskever and Geoffrey Hinton) победила на ImageNet c большим отрывом от конкурентов.\r\n",
263 | "Это событие породило новую волну интереса к алгоритмам глубокого обучения и, в частности, к свёрточным нейронным сетям.\r\n",
264 | "\r\n",
265 | "**AlexNet** — свёрточная нейронная сеть, которая оказала большое влияние на развитие машинного обучения, в особенности — на алгоритмы компьютерного зрения. Сеть с большим отрывом выиграла конкурс по распознаванию изображений ImageNet LSVRC-2012 в 2012 году (с количеством ошибок 15,3% против 26,2% у второго места). Архитектура AlexNet схожа с созданной Yann LeCum сетью LeNet. Однако у AlexNet больше фильтров на слое и вложенных свёрточных слоев.\r\n",
266 | "\r\n",
267 | "Ссылка"
268 | ],
269 | "metadata": {}
270 | },
271 | {
272 | "cell_type": "markdown",
273 | "source": [
274 | "**ImageNet: Large Scale Visual Recognition Challenge (ILSVRC)**\n",
275 | "\n",
276 | "
"
277 | ],
278 | "metadata": {}
279 | },
280 | {
281 | "cell_type": "markdown",
282 | "source": [
283 | "Fei-Fei Li \n",
284 | "\n",
285 | "Christiane Fellbaum\n",
286 | "\n",
287 | "\n",
288 | "С 2010 года в рамках проекта ILSVRC проводятся соревнования между исследовательскими группами по классификации объектов. ILSVCR возникла по аналогии с небольшой кампанией 2005 года PASCAL VOC, которая располагала набором из 20 тысяч изображений и 20 классов объектов. Существенный прогресс в распознавании образов был достигнут в 2010 году. В 2011 году хорошим результатом считалась ошибка классификации 25 %. В 2012 году система глубокого обучения на основе свёрточной нейронной сети смогла достичь 16 % ошибки, а в следующие годы ошибка упала до нескольких процентов. В 2015 году исследователи констатировали, что программы в определённых задачах проекта ILSVRC превзошли человеческие способности. \n",
289 | "\n",
290 | "**Условия соревнования:**\n",
291 | "На каждом изображении может быть один или несколько предметов, относящихся к одному из **1000** классов.\n",
292 | "Для метрики *Тop5* алгоритм выдает метки 5 классов. Если предмет, относящийся к одному из этих классов, есть на изображении, то ответ засчитывается как верный.\n",
293 | "Для *Top1* соответственно принимается только метка одного класса."
294 | ],
295 | "metadata": {}
296 | },
297 | {
298 | "cell_type": "markdown",
299 | "source": [
300 | "
"
301 | ],
302 | "metadata": {}
303 | },
304 | {
305 | "cell_type": "markdown",
306 | "source": [
307 | "Чтобы понять важность победы AlexNet в 2012г., достаточно посмотреть на количество ссылок на данную работу.\n",
308 | "\n",
309 | "Оно сравнимо с количеством цитирований основополагающих трудов в различных областях науки и продолжает расти.\n",
310 | "\n",
311 | "• Клод Шеннон “Математическая теория связи” — позволила решить основные задачи теории информации;\n",
312 | "\n",
313 | "• Фрэнсис Криком и Джеймсом Д. Уотсон “Молекулярная структура нуклеиновых кислот: структура дезоксирибонуклеиновой кислоты” - первая статья, в которой было опубликовано описание открытия двойной спирали структуры ДНК;\n",
314 | "\n",
315 | "• Обнаружение бозона Хиггса."
316 | ],
317 | "metadata": {}
318 | },
319 | {
320 | "cell_type": "markdown",
321 | "source": [
322 | "#### Количество Цитирований\n",
323 | "\n",
324 | "Ч. Дарвин, \"О происхождении видов\", 1859: **50,007**\n",
325 | "\n",
326 | "К. Шеннон, “Математическая теория связи”, 1953: **69,351**\n",
327 | "\n",
328 | "Д. Уотсон и Ф. Крик, “Молекулярная структура нуклеиновых кислот”, 1953: **13,111**\n",
329 | "\n",
330 | "ATLAS Collaboration, \"Наблюдение новой частицы в поисках Стандартной модели бозона Хиггса с детектором ATLAS на баке\", 2012: **14 429**"
331 | ],
332 | "metadata": {}
333 | },
334 | {
335 | "cell_type": "markdown",
336 | "source": [
337 | "## 3. ML — Подход к научным проблемам "
338 | ],
339 | "metadata": {}
340 | },
341 | {
342 | "cell_type": "markdown",
343 | "source": [
344 | "### 3.1. Извлечение закономерностей — закон Ньютона \n",
345 | "\n",
346 | "
"
347 | ],
348 | "metadata": {}
349 | },
350 | {
351 | "cell_type": "markdown",
352 | "source": [
353 | "На основе наблюдений люди выявляют закономерности и делают обобщение, наблюдая за реальным миром.\n",
354 | "Результатом такой умственной деятельности является модель, описывающая некоторые процессы реального мира.\n",
355 | "\n",
356 | "Она может быть описана при помощи математических формул или алгоритмического языка.\n",
357 | "\n",
358 | "Сейчас появилась технология, которая может это делать вместо человека."
359 | ],
360 | "metadata": {}
361 | },
362 | {
363 | "cell_type": "markdown",
364 | "source": [
365 | "
"
366 | ],
367 | "metadata": {}
368 | },
369 | {
370 | "cell_type": "markdown",
371 | "source": [
372 | "**Это ML**\n",
373 | "\n",
374 | "**ML** — это технология, которая позволяет выявлять закономерности в данных и обобщать их. \n",
375 | "\n",
376 | "Вы можете использовать её для поиска закономерностей, которые люди ещё не обнаружили и таким образом совершить открытие.\n",
377 | "Правда, результатом обучения такой модели будет не компактная формула, а набор весов. \n",
378 | "По сути это набор коэффициентов для некоторого математического выражения.\n",
379 | "\n",
380 | "Для этого нужно две вещи: **данные** и **валидация результата.**\n"
381 | ],
382 | "metadata": {}
383 | },
384 | {
385 | "cell_type": "markdown",
386 | "source": [
387 | "
"
388 | ],
389 | "metadata": {}
390 | },
391 | {
392 | "cell_type": "markdown",
393 | "source": [
394 | "Как человеку, так и алгоритму машинного обучения требуется подготовка данных.\n",
395 | "\n",
396 | "Законы Ньютоны **не** сформулированы для яблок. Для описания закономерностей в науке используются абстракции: *сила, масса, ускорение.*\n",
397 | "\n",
398 | "Данные для **ML** моделей тоже должны быть подготовлены. Типичная форма такой абстракции — вектор или n-мерный массив чисел.\n",
399 | "\n",
400 | "Именно с такой формой представления данных работают большинство современных моделей."
401 | ],
402 | "metadata": {}
403 | },
404 | {
405 | "cell_type": "markdown",
406 | "source": [
407 | "
"
408 | ],
409 | "metadata": {}
410 | },
411 | {
412 | "cell_type": "markdown",
413 | "source": [
414 | "Второй элемент, который потребуется для процесса обучения — разработка способа оценки результата (*валидации*).\n",
415 | "\n",
416 | "Вне зависимости от того, какой метод обучения используется — с учителем или без, требуется некий критерий, по которому будет оцениваться выход модели и впоследствии корректироваться веса.\n",
417 | "\n",
418 | "В базовом варианте: полученный результат сравнивают с эталонным и если разница велика — корректируют модель."
419 | ],
420 | "metadata": {}
421 | },
422 | {
423 | "cell_type": "markdown",
424 | "source": [
425 | "### 3.2 Пример \n",
426 | "\n",
427 | "
"
428 | ],
429 | "metadata": {}
430 | },
431 | {
432 | "cell_type": "markdown",
433 | "source": [
434 | "\n",
435 | "Поясним эту идею на конкретном примере. Допустим, у нас есть наручный шагомер, который фиксирует перемещения в пространстве. Скорее всего в нем встроен акселерометр, который способен фиксировать перемещения по трем осям. На выходе мы получаем сигнал с нескольких(3-х) датчиков.\n",
436 | "\n",
437 | "Если задача состоит в том, чтобы подсчитать количество шагов, то к её решению можно подойти двумя способами.\n"
438 | ],
439 | "metadata": {}
440 | },
441 | {
442 | "cell_type": "markdown",
443 | "source": [
444 | "#### Вариант №1"
445 | ],
446 | "metadata": {}
447 | },
448 | {
449 | "cell_type": "markdown",
450 | "source": [
451 | "Классический: напишем программу. \n",
452 | "Если появилось ускорение по одной из осей, которое больше определенного порога, то мы создаем то условие, которое срабатывает. Позже мы выясним, что подобные сигнатурные сигналы с датчика могут поступить и при других определенных движениях, не связанных с шагами, например, во время плавания.\n",
453 | " Добавляется дополнительное условие, которое фильтрует подобные ситуации. \n",
454 | "\n",
455 | "Находятся всё новые и новые исключения из общего правила, программа и ее алгоритмическая сложность будет расти.\n",
456 | "\n",
457 | "Программу будет сложнее поддерживать из-за большого объема кода в ней. \n",
458 | "Изменение в одной из частей потребует внесение правок в другой код и.т.п."
459 | ],
460 | "metadata": {}
461 | },
462 | {
463 | "cell_type": "markdown",
464 | "source": [
465 | "\n",
466 | "
\n"
467 | ],
468 | "metadata": {}
469 | },
470 | {
471 | "cell_type": "markdown",
472 | "source": [
473 | "#### Вариант №2\n",
474 | "\n",
475 | "\n",
476 | "С появлением машинного обучения мы можем применить принципиально другой подход. \n",
477 | "Не задумываясь о том, что значат показания каждого из акселерометров, мы можем просто собрать некоторый архив данных за определенное время (возможно разбив на более короткие промежутки времени). Всё, что нам потребуется помимо этих данных — это информация о том, сколько было сделано реальных шагов. После этого данные загружаются в модель и она на этих данных учится. При достаточном количестве данных и адекватно подобранной модели (чем мы и будем заниматься) мы сможем научить ее решать конкретные задачи (в данном случае — считать шаги). \n"
478 | ],
479 | "metadata": {}
480 | },
481 | {
482 | "cell_type": "markdown",
483 | "source": [
484 | "
"
485 | ],
486 | "metadata": {}
487 | },
488 | {
489 | "cell_type": "markdown",
490 | "source": [
491 | "Стоит отметить, что по сути модели всё равно, что считать: шаги, сердечный ритм, количество калорий, ударов по клавиатуре и пр. Нет необходимости писать под каждый пример отдельную программу, достаточно собрать данные и мы сможем решить множество абсолютно разных задач. \n",
492 | "\n",
493 | "Важно лишь понимать, какую модель предпочтительнее выбрать. С этим мы и будем разбираться в ходе курса."
494 | ],
495 | "metadata": {}
496 | },
497 | {
498 | "cell_type": "markdown",
499 | "source": [
500 | "
"
501 | ],
502 | "metadata": {}
503 | },
504 | {
505 | "cell_type": "markdown",
506 | "source": [
507 | "### 3.3 Базовые задачи машинного обучения "
508 | ],
509 | "metadata": {}
510 | },
511 | {
512 | "cell_type": "markdown",
513 | "source": [
514 | "
"
515 | ],
516 | "metadata": {}
517 | },
518 | {
519 | "cell_type": "markdown",
520 | "source": [
521 | "Ссылка "
522 | ],
523 | "metadata": {}
524 | },
525 | {
526 | "cell_type": "markdown",
527 | "source": [
528 | "Все многообразие практических задач базируются на трех базовых.\r\n",
529 | "\r\n",
530 | "* Регрессия — предсказание числового значения, характеризующего объект, на основании признаков объекта; \r\n",
531 | "* Классификация — предсказание класса, к которому принадлежит объект на основании признаков объекта;\r\n",
532 | "* Кластеризация — разбиение объектов на заранее неизвестное число классов (близка к классификации, но не эквивалентна ей).\r\n",
533 | "\r\n",
534 | "Умея решать эти задачи, можно перейти почти к любой, рассматриваемой в примерах (детекции, сегментации и.т.п.). Начнем с них."
535 | ],
536 | "metadata": {}
537 | },
538 | {
539 | "cell_type": "markdown",
540 | "source": [
541 | "
\n",
542 | "\n",
543 | "Решение задачи классификации является одним из важнейших способов применения нейронных сетей."
544 | ],
545 | "metadata": {}
546 | },
547 | {
548 | "cell_type": "markdown",
549 | "source": [
550 | "Задача классификации представляет собой отнесение объекта к одному из нескольких попарно не пересекающихся множеств.\n",
551 | "\n",
552 | "Объекты могут быть различны по своей природе: символы текста, изображения, образцы звуков и т. д. При обучении, модели подаются на вход различные объекты с указанием того, к какому классу они относятся. Объект характеризуется некоторыми признаками, используемыми для построения модели. Образец подается на вход модели как вектор значений признаков. При этом совокупность всех признаков должна однозначно определять класс, к которому относится образец. В случае, если признаков недостаточно, модель может соотнести один и тот же образец с несколькими классами, что неверно. \n",
553 | "\n",
554 | "По окончании обучения модели, ей можно предъявлять неизвестные ранее образы и получать ответ об их принадлежности к определённому классу.\n",
555 | "\n",
556 | "Примером задачи классификации может служить предсказание ответа пациента на терапию."
557 | ],
558 | "metadata": {}
559 | },
560 | {
561 | "cell_type": "markdown",
562 | "source": [
563 | "
"
564 | ],
565 | "metadata": {}
566 | },
567 | {
568 | "cell_type": "markdown",
569 | "source": [
570 | "В задаче регрессии модель должна предсказать некоторое числовое значение по входным данным. Регрессия отличается от классификации форматом выхода.\n",
571 | "\n",
572 | "При обучении, регрессионной модели также подаются на вход различные объекты (в виде вектора значений призаков) с указанием числового, которое модель будет учиться предсказывать. После обучения модель способна предсказать значение искомого признака объекта на основе зависимостей между входными и выходными данными, выявленных в процессе обучения. \n",
573 | "\n",
574 | "Примером задачи регрессии может служить предсказание стоимости жилья, или прогнозирование котировок акций.\n"
575 | ],
576 | "metadata": {}
577 | },
578 | {
579 | "cell_type": "markdown",
580 | "source": [
581 | "Прогнозирование возможно только тогда, когда предыдущие изменения действительно в какой-то степени предопределяют будущие. В частности, прогнозирование котировок акций на основе котировок за прошлую неделю может оказаться успешным (а может и не оказаться), тогда как прогнозирование результатов завтрашней лотереи на основе данных за последние 50 лет почти наверняка не даст никаких результатов."
582 | ],
583 | "metadata": {}
584 | },
585 | {
586 | "cell_type": "markdown",
587 | "source": [
588 | "
"
589 | ],
590 | "metadata": {}
591 | },
592 | {
593 | "cell_type": "markdown",
594 | "source": [
595 | "Под кластеризацией понимается разбиение множества входных объектов на классы, при том, что ни количество, ни признаки классов заранее не известны. После обучения модель способна определять, к какому классу относится входной объект. Модель также может сигнализировать о том, что входной объект не относится ни к одному из выделенных классов — это является признаком новых, отсутствующих в обучающей выборке, данных. Таким образом, подобная модель может выявлять новые, неизвестные ранее классы объектов. Соответствие между классами, выделенными сетью, и классами, существующими в предметной области, устанавливается человеком. Задача кластеризации относится к к широкому классу задач обучения без учителя."
596 | ],
597 | "metadata": {}
598 | },
599 | {
600 | "cell_type": "markdown",
601 | "source": [
602 | "### 3.4 Данные "
603 | ],
604 | "metadata": {}
605 | },
606 | {
607 | "cell_type": "markdown",
608 | "source": [
609 | "
"
610 | ],
611 | "metadata": {}
612 | },
613 | {
614 | "cell_type": "markdown",
615 | "source": [
616 | "Большинство процессов и объектов, с которыми научились работать ML/DL модели, можно отнести к одному из перечисленных типов. Наша задача будет состоять в том, как данные из вашей предметной области свести к одному из них и представить в виде набора чисел. "
617 | ],
618 | "metadata": {}
619 | },
620 | {
621 | "cell_type": "markdown",
622 | "source": [
623 | "Для работы с различными типами данных используют разные типы моделей:\n",
624 | "\n",
625 | "**Табличный** — классические ML модели либо полносвязанные NN;\n",
626 | "\n",
627 | " **Последовательности** — рекуррентные сети + свёртка;\n",
628 | " \n",
629 | " **Изображения/видео** — 2,3 .. ND свёрточные сети.\n",
630 | " \n",
631 | "\n",
632 | "\n",
633 | "В разных типах данных количество связей между элементами разное и зависит только от типа этих данных. Важно НЕ количество элементов, а СВЯЗИ между ними.\n"
634 | ],
635 | "metadata": {}
636 | },
637 | {
638 | "cell_type": "markdown",
639 | "source": [
640 | "
"
641 | ],
642 | "metadata": {}
643 | },
644 | {
645 | "cell_type": "markdown",
646 | "source": [
647 | "\n",
648 | "Данные мы можем условно делить по степени связанности. Это степень взаимного влияния между соседними элементами. \n",
649 | "Например, в таблице, в которой есть определенные параметры (например: рост, вес) данные между собой связаны, но порядок столбцов значения не имеет.\n",
650 | "Если мы поменяем столбцы местами, то не потеряем никакой важной информации. \n",
651 | "\n",
652 | "Такие данные можно представить в виде вектора, но порядок элементов в нем не важен.\n",
653 | "\n",
654 | "При работе с изображениями нам становится важно, как связаны между собой пиксели и по горизонтали, и по вертикали. \n",
655 | "При добавлении цвета появляются 3 RGB канала, и значения в каждом канале также связаны между собой. Эту связь нельзя терять, если мы хотим корректно извлечь максимум информации из данных. Соответственно, если дано цветное изображение, то у нас уже есть три измерения, в которых мы должны эти связи учитывать."
656 | ],
657 | "metadata": {}
658 | },
659 | {
660 | "cell_type": "markdown",
661 | "source": [
662 | "## 4 Области применения и технологии "
663 | ],
664 | "metadata": {}
665 | },
666 | {
667 | "cell_type": "markdown",
668 | "source": [
669 | "### 4.1. Робототехника \n",
670 | "\n",
671 | "
"
672 | ],
673 | "metadata": {}
674 | },
675 | {
676 | "cell_type": "markdown",
677 | "source": [
678 | "Нейросети широко применяются для решения задач технического зрения. Различным роботизированным устройствам от таких, как беспилотные транспортные средства, до промышленных роботов или домашнего пылесоса, требуется определять своё местоположение в пространстве и/или местоположение окружающих объектов. \r\n",
679 | "\r\n",
680 | "Эту задачу можно решать путем обработки изображений с камер. Здесь очень эффективными оказались свёрточные нейросети, подобные AlexNet. \r\n",
681 | "\r\n",
682 | "Роботы присутствуют в нашей жизни в виде дронов, машин, пылесосов. Для моделирования их зрения используется задачи детекции, треккинга на видео, сегментации."
683 | ],
684 | "metadata": {}
685 | },
686 | {
687 | "cell_type": "markdown",
688 | "source": [
689 | "#### Детектирование (object detection)"
690 | ],
691 | "metadata": {}
692 | },
693 | {
694 | "cell_type": "markdown",
695 | "source": [
696 | "
"
697 | ],
698 | "metadata": {}
699 | },
700 | {
701 | "cell_type": "markdown",
702 | "source": [
703 | " КЛАССИФИКАЦИЯ + РЕГРЕССИЯ ~ = ДЕТЕКТИРОВАНИЕ "
704 | ],
705 | "metadata": {}
706 | },
707 | {
708 | "cell_type": "markdown",
709 | "source": [
710 | "Ссылка "
711 | ],
712 | "metadata": {}
713 | },
714 | {
715 | "cell_type": "markdown",
716 | "source": [
717 | "Задача поиска местоположения объекта в кадре — это задача детектирования. Она тесно связана с задачей классификации:\n",
718 | "\n",
719 | "Сначала обучается сеть, которая классифицирует изображения. То есть определяет, что на изображении присутствует человек. \n",
720 | "\n",
721 | "Затем к такой сети добавляются несколько слоев, которые предсказывают координаты объектов. То есть решают задачу регрессии."
722 | ],
723 | "metadata": {}
724 | },
725 | {
726 | "cell_type": "markdown",
727 | "source": [
728 | "Знание координат объектов вокруг позволяет решать различные более сложные задачи: \n",
729 | "\n",
730 | "• Трекинг (отслеживание перемещения);\n",
731 | "\n",
732 | "• Предсказание действий;\n",
733 | "\n",
734 | "• SLAM (*simultaneous localization and mapping* — одновременная локализация и построение карты);\n",
735 | "\n",
736 | "• Оценка расстояний до объектов."
737 | ],
738 | "metadata": {}
739 | },
740 | {
741 | "cell_type": "markdown",
742 | "source": [
743 | "#### Automatic whale counting in satellite images with deep learning"
744 | ],
745 | "metadata": {}
746 | },
747 | {
748 | "cell_type": "markdown",
749 | "source": [
750 | "
"
751 | ],
752 | "metadata": {}
753 | },
754 | {
755 | "cell_type": "markdown",
756 | "source": [
757 | "Вот пример использования аналогичного подхода у биологов. Авторы статьи обучили нейронную сеть искать на спутниковых снимках китов и подсчитывать их количество. \n",
758 | "Отдельно можно использовать классификатор для определения вида кита по ссылке. \n",
759 | "Аналогичным образом можно обучить сеть искать объекты любых других категорий. Совсем не обязательно на изображениях в видимом диапазоне.\n",
760 | "\n",
761 | "Ссылка на репозиторий с реализацией: https://github.com/EGuirado/CNN-Whales-from-Space"
762 | ],
763 | "metadata": {}
764 | },
765 | {
766 | "cell_type": "markdown",
767 | "source": [
768 | "### 3.2 Безопасность "
769 | ],
770 | "metadata": {}
771 | },
772 | {
773 | "cell_type": "markdown",
774 | "source": [
775 | "
"
776 | ],
777 | "metadata": {}
778 | },
779 | {
780 | "cell_type": "markdown",
781 | "source": [
782 | "Видеоаналитика.\n",
783 | "\n",
784 | "Про системы распознавания лиц все вероятно слышали.\n",
785 | " Что скрывается “под капотом”?\n",
786 | "Несколько моделей. Одна ищет лицо на изображении. Кстати, с этим достаточно успешно справлялись и алгоритмы без применения глубокого обучения (ViolaJones 2001). \n",
787 | "Другая ищет ключевые точки, чтобы потом изображение выронить. \n",
788 | "\n",
789 | "Решаются те же две задачи (классификация + регрессия).\n",
790 | "\n",
791 | "Но количество людей, проходящих мимо камеры в метрополитене, огромно. И что хуже, их список заранее не известен. Поэтому мы не можем использовать классификатор, чтобы отличить лицо одного человека от другого. Нам просто неизвестно количество классов."
792 | ],
793 | "metadata": {}
794 | },
795 | {
796 | "cell_type": "markdown",
797 | "source": [
798 | "#### Кластеризация"
799 | ],
800 | "metadata": {}
801 | },
802 | {
803 | "cell_type": "markdown",
804 | "source": [
805 | "
"
806 | ],
807 | "metadata": {}
808 | },
809 | {
810 | "cell_type": "markdown",
811 | "source": [
812 | "Поэтому при распознавании лиц применяется другая техника: по вырезанному и выравненному прямоугольнику с лицом строится вектор-признак “embedding” — некое компактное представление.\r\n",
813 | "\r\n",
814 | "По сути сильно снижается размерность изображения.\r\n",
815 | "\r\n",
816 | "А дальше можно сравнить между собой полученные векторы, использовав любую метрику расстояния. \r\n",
817 | "\r\n",
818 | "То есть к классификации и регрессии добавляется 3-я базовая задача: **кластеризация**."
819 | ],
820 | "metadata": {}
821 | },
822 | {
823 | "cell_type": "markdown",
824 | "source": [
825 | "### 3.3 Анализ медицинских изображений "
826 | ],
827 | "metadata": {}
828 | },
829 | {
830 | "cell_type": "markdown",
831 | "source": [
832 | "
"
833 | ],
834 | "metadata": {}
835 | },
836 | {
837 | "cell_type": "markdown",
838 | "source": [
839 | "Ссылка "
842 | ],
843 | "metadata": {}
844 | },
845 | {
846 | "cell_type": "markdown",
847 | "source": [
848 | "Задача: поиск аномалий (опухолей) и определение их четких границ.\r\n",
849 | "\r\n",
850 | "В данном примере приведена задача сегментации. Эта задача очень похожа на детектирование. Нужно найти, где находится объект. Но в данном случае нужно найти четкие границы. Желательно с точностью до пикселя.\r\n",
851 | "\r\n",
852 | "То есть для каждого пикселя нужно предсказать, к какому объекту он относится. \r\n",
853 | "\r\n",
854 | "**Получается попиксельный классификатор.**"
855 | ],
856 | "metadata": {}
857 | },
858 | {
859 | "cell_type": "markdown",
860 | "source": [
861 | "Но проблема состоит в том, что пикселей много, и решать её в лоб — неэффективно."
862 | ],
863 | "metadata": {}
864 | },
865 | {
866 | "cell_type": "markdown",
867 | "source": [
868 | "Поэтому при сегментации используется подход, подобный тому, что при **кластеризации лиц:**\n",
869 | "\n",
870 | "• Часть нейросети сжимает изображение — получается карта признаков (карта, потому что структура сохраняется);\n",
871 | "\n",
872 | "• На этой карте (см. выше) предсказываются границы объектов;\n",
873 | "\n",
874 | "• Вторая часть сети (симметрично первой восстанавливает размеры)."
875 | ],
876 | "metadata": {}
877 | },
878 | {
879 | "cell_type": "markdown",
880 | "source": [
881 | "**Это концепция энкодер - декодер.**"
882 | ],
883 | "metadata": {}
884 | },
885 | {
886 | "cell_type": "markdown",
887 | "source": [
888 | "#### GAN"
889 | ],
890 | "metadata": {}
891 | },
892 | {
893 | "cell_type": "markdown",
894 | "source": [
895 | "
"
896 | ],
897 | "metadata": {}
898 | },
899 | {
900 | "cell_type": "markdown",
901 | "source": [
902 | "На базе концепции энкодер - декодер появились так называемые генеративно-состязательные сети.\n",
903 | "Сжатое представление, которое получается на внутреннем слое сети, содержит какие-то ключевые признаки изображения."
904 | ],
905 | "metadata": {}
906 | },
907 | {
908 | "cell_type": "markdown",
909 | "source": [
910 | "Но не всю информацию об изображении и в зависимости от того как будет идти процедура восстановления мы можем получить разные вариации изображения."
911 | ],
912 | "metadata": {}
913 | },
914 | {
915 | "cell_type": "markdown",
916 | "source": [
917 | "*Почему состязательные?*"
918 | ],
919 | "metadata": {}
920 | },
921 | {
922 | "cell_type": "markdown",
923 | "source": [
924 | "Поскольку сеть генерирует совершенно новое изображение, у нас нет шаблона, с которым мы могли бы его сравнить и дать оценку работы модели.\n",
925 | "Поэтому для оценки качества работы первой сети (генератора) обучается вторая (дискриминатор), которая дает ответ на вопрос: похоже ли полученное изображение на настоящее или нет."
926 | ],
927 | "metadata": {}
928 | },
929 | {
930 | "cell_type": "markdown",
931 | "source": [
932 | "
"
933 | ],
934 | "metadata": {}
935 | },
936 | {
937 | "cell_type": "markdown",
938 | "source": [
939 | "С результатами работы таких моделей вы все хорошо знакомы по соцсетям и мобильным приложениям.\n",
940 | "Помимо использования в развлекательных целях, эта технология широко используется и в научных работах."
941 | ],
942 | "metadata": {}
943 | },
944 | {
945 | "cell_type": "markdown",
946 | "source": [
947 | "Очистка изображений галактик"
948 | ],
949 | "metadata": {}
950 | },
951 | {
952 | "cell_type": "markdown",
953 | "source": [
954 | "
"
955 | ],
956 | "metadata": {}
957 | },
958 | {
959 | "cell_type": "markdown",
960 | "source": [
961 | "Ссылка "
962 | ],
963 | "metadata": {}
964 | },
965 | {
966 | "cell_type": "markdown",
967 | "source": [
968 | "Изображения, полученные при помощи телескопов, оказываются зашумленными по причинам:\n",
969 | "- атмосферных помех;\n",
970 | "- шумам, которые даёт сенсор телескопа."
971 | ],
972 | "metadata": {}
973 | },
974 | {
975 | "cell_type": "markdown",
976 | "source": [
977 | "Классический способ борьбы с этой проблемой состоит в подборе сигнала похожего на суммарный шум: point spread function (PSF) и последующей сверке изображения с этим сигналом."
978 | ],
979 | "metadata": {}
980 | },
981 | {
982 | "cell_type": "markdown",
983 | "source": [
984 | "В данной работе для решения той же проблемы авторы статьи обучили GAN.\n",
985 | "В качестве входных данных использовались изображения галактик.\n",
986 | "\n",
987 | "*4550 galaxies from the Sloan Digital Sky Survey Data Release 12 (York et al. 2000; Alam et al. 2015)*"
988 | ],
989 | "metadata": {}
990 | },
991 | {
992 | "cell_type": "markdown",
993 | "source": [
994 | "
"
995 | ],
996 | "metadata": {}
997 | },
998 | {
999 | "cell_type": "markdown",
1000 | "source": [
1001 | "Изображения преобразовывались в RGB формат. И к ним искусственно добавлялись искажения, имитирующие шум от сенсора и размытие, возникающее за счёт потоков воздуха в атмосфере(PSF).\n",
1002 | "Датасет состоял из пар зашумленных и чистых изображений.\n",
1003 | "\n",
1004 | "Генератор обучался на основе изображения с шумом генерировать чистое изображение, а дискриминатор отличал зашумленные изображения от чистых.\n",
1005 | "\n",
1006 | "На первый взгляд результат впечатляет. Однако авторы признают что на фотографиях, где присутствуют объекты, редко появляющиеся в датасете, результат хуже."
1007 | ],
1008 | "metadata": {}
1009 | },
1010 | {
1011 | "cell_type": "markdown",
1012 | "source": [
1013 | "Ссылка "
1014 | ],
1015 | "metadata": {}
1016 | },
1017 | {
1018 | "cell_type": "markdown",
1019 | "source": [
1020 | "### GAN & OneShot learning"
1021 | ],
1022 | "metadata": {}
1023 | },
1024 | {
1025 | "cell_type": "markdown",
1026 | "source": [
1027 | "
"
1028 | ],
1029 | "metadata": {}
1030 | },
1031 | {
1032 | "cell_type": "markdown",
1033 | "source": [
1034 | "Модели, которые мы рассматривали, до сих обучаются на большом количестве данных. \n",
1035 | "В ряде областей (например, в медицине) их может не хватать.\n",
1036 | "\n",
1037 | "Вот пример статьи, в которой авторы обучили GAN сегметировать МРТ снимках мозга с признаками рассеянного склероза, а затем использовали её для поиска опухолей, дообучив модель всего на 5 снимках.\n",
1038 | "\n",
1039 | "Ссылка"
1040 | ],
1041 | "metadata": {}
1042 | },
1043 | {
1044 | "cell_type": "markdown",
1045 | "source": [
1046 | "**Применение сегментации МРТ в медицине:**\r\n",
1047 | "\r\n",
1048 | "• анализ и мониторинг опухолей (например, головного мозга, печени);\r\n",
1049 | "\r\n",
1050 | "• обнаружение бляшек рассеянного склероза;\r\n",
1051 | "\r\n",
1052 | "• обнаружение гиперестезии белого вещества."
1053 | ],
1054 | "metadata": {}
1055 | },
1056 | {
1057 | "cell_type": "markdown",
1058 | "source": [
1059 | "### 3.4. Человеко-машинное взаимодействие "
1060 | ],
1061 | "metadata": {}
1062 | },
1063 | {
1064 | "cell_type": "markdown",
1065 | "source": [
1066 | "#### NLP & Speech recognition"
1067 | ],
1068 | "metadata": {}
1069 | },
1070 | {
1071 | "cell_type": "markdown",
1072 | "source": [
1073 | "
"
1074 | ],
1075 | "metadata": {}
1076 | },
1077 | {
1078 | "cell_type": "markdown",
1079 | "source": [
1080 | "Область применения DL не ограничивается только изображениями. \r\n",
1081 | "\r\n",
1082 | "Они так же весьма эффективны для распознавания голоса и машинного перевода.\r\n",
1083 | "В отличие от изображений, входные данные имеют другую структуру: это последовательность, длина которой заранее неизвестна.\r\n",
1084 | "\r\n",
1085 | "Для работы с такого рода данными используются сети другого типа — **рекуррентные**. "
1086 | ],
1087 | "metadata": {}
1088 | },
1089 | {
1090 | "cell_type": "markdown",
1091 | "source": [
1092 | "### RNN "
1093 | ],
1094 | "metadata": {}
1095 | },
1096 | {
1097 | "cell_type": "markdown",
1098 | "source": [
1099 | "
"
1100 | ],
1101 | "metadata": {}
1102 | },
1103 | {
1104 | "cell_type": "markdown",
1105 | "source": [
1106 | "Ссылка "
1108 | ],
1109 | "metadata": {}
1110 | },
1111 | {
1112 | "cell_type": "markdown",
1113 | "source": [
1114 | "Рекуррентные нейронные стеи — это семейство нейронных сетей для обработки последовательных данных. Примером таких данных может быть предложение, состоящие из слов, записанных в определенном порядке. Порядок слов учитывается при подаче предложения в сеть таким образом, что\r\n",
1115 | "каждое слово (каждый элемент данных) может оказывать влияние на выход модели и менять ее состояние. \r\n",
1116 | "\r\n",
1117 | "Ниже можно найти статью, в которой авторы использовали эту технологию для анализа сигналов, которыми общаются киты.\r\n",
1118 | "\r\n",
1119 | "Ссылка"
1120 | ],
1121 | "metadata": {}
1122 | },
1123 | {
1124 | "cell_type": "markdown",
1125 | "source": [
1126 | "### 3.5 Наука "
1127 | ],
1128 | "metadata": {}
1129 | },
1130 | {
1131 | "cell_type": "markdown",
1132 | "source": [
1133 | "#### Фолдинг белка "
1134 | ],
1135 | "metadata": {}
1136 | },
1137 | {
1138 | "cell_type": "markdown",
1139 | "source": [
1140 | "
"
1141 | ],
1142 | "metadata": {}
1143 | },
1144 | {
1145 | "cell_type": "markdown",
1146 | "source": [
1147 | "На данный момент существует важный процесс — фолдинг (укладка) белка. Белок синтезируются в клетке в виде соединённых последовательно аминокислот. Эта последовательность обычно известна и кодируется в геноме.\r\n",
1148 | "\r\n",
1149 | "Однако после синтеза цепочка будет складываться в сложные пространственные структуры и, в зависимости от того, как эта структура будет выглядеть, зависит то, как белок будет себя вести в дальнейшем. Соответственно, понимание особенностей фолдинга белка служит ключом для производства лекарств и интерпретации генетических аномалий. \r\n",
1150 | "\r\n",
1151 | "В геноме человека могут происходить мутации — ошибки в геноме, которые могут приводить к изменению аминокислотной последовательности белка. \r\n",
1152 | "\r\n",
1153 | "Далеко не все мутации, которые есть в геноме, приведут к проблемам в конечной структуре, и если мы заранее будем знать, что одна мутация белка с дефектом, а другая безопасная, мы сможем предсказать вероятность развития болезни. \r\n"
1154 | ],
1155 | "metadata": {}
1156 | },
1157 | {
1158 | "cell_type": "markdown",
1159 | "source": [
1160 | "Поскольку эти связи обусловлены достаточно сложными внутримолекулярными взаимодействиями, просчитать заранее, как будет выглядеть молекула, достаточно трудозатратно. На каждом этапе формирования действуют разные связи между аминокислотами (водородные связи, гидрофобные взаимодействия и пр.), тем самым образуя сложную структуру.\r\n",
1161 | "\r\n",
1162 | "Рассчитать аналитически структуру, которая образуется в ходе этих взаимодействий, сложно, но можно применить для этого нейросеть, подав ей аминокислотную последовательность белка. \r\n",
1163 | "\r\n",
1164 | "Автора AlphaFold2 обучают нейросеть, которая предсказывает расстояния и углы между атомами аминокислот в конечном белке, причем делает это итеративно, улучшая предсказание с предыдущего шага. Далее специальный алгоритм преобразует это в набор координат атомов, что и является пространственной структурой белка. \r\n",
1165 | "Этот трехмерный массив координат атомов можно визуализировать, и дальше структурные биологи могут делать вывод о том, получится конкретный белок дефектным или нет. "
1166 | ],
1167 | "metadata": {}
1168 | },
1169 | {
1170 | "cell_type": "markdown",
1171 | "source": [
1172 | "А эти знания уже применяются в области производства лекарств. Например, есть база веществ и известно, какая у них структура. Имея структуру белка, можно предсказать, в каком месте и с какой формой белка они могут и должны соединяться. Соответственно, по базе данных можно найти вещества, которые будут с этим белком связаны и уже подобрать из имеющихся “претендентов” тот, который наилучшим образом будет работать. \r\n",
1173 | "\r\n",
1174 | "Про мутации. Есть базы данных нормальных и мутагенных белков, и мы можем сравнить то, что получилось у нас в результате фолдинга с эталоном и посмотреть, насколько большая разница в структурах (опять же, для этого нужны структурные биологи, так как не все части структуры белка равнозначны). И на основе этого уже предсказать, насколько опасна будет та или иная мутация. \r\n",
1175 | "\r\n",
1176 | "\r\n",
1177 | "Заявление от deepmind\r\n",
1178 | "\r\n",
1179 | "[Мнение структурных биологов 1](https://yakovlev.me/para-slov-za-alphafold2/?fbclid=IwAR23L8XigP7byPcx10o-4y5L3VTLRzDmuioqw99iKZ0SkPrauezrJJJayiM)\r\n",
1180 | "\r\n",
1181 | "[Мнение структурных биологов 2]()"
1182 | ],
1183 | "metadata": {}
1184 | },
1185 | {
1186 | "cell_type": "markdown",
1187 | "source": [
1188 | "
"
1189 | ],
1190 | "metadata": {}
1191 | },
1192 | {
1193 | "cell_type": "markdown",
1194 | "source": [
1195 | "\n",
1196 | "Ссылка"
1197 | ],
1198 | "metadata": {}
1199 | },
1200 | {
1201 | "cell_type": "markdown",
1202 | "source": [
1203 | "### 3.6. Причины успехов технологий на основе DL \n",
1204 | "\n",
1205 | "
"
1206 | ],
1207 | "metadata": {}
1208 | },
1209 | {
1210 | "cell_type": "markdown",
1211 | "source": [
1212 | "**Почему всё это произошло так внезапно?**\n",
1213 | "\n",
1214 | "1. Чтобы модель могла извлечь и запомнить все важные закономерности, все они должны присутствовать в данных. Доступные цифровые фотокамеры и быстрый интернет, обеспечивший исследователям доступ к данным и возможность коллаборативной разметки, стали появляться только в начале 2000-х годов.\n",
1215 | "\n",
1216 | "\n",
1217 | "2. Вычислительные мощности:\n",
1218 | "\n",
1219 | "* Lenet обучали на Pentium2 это примерно $10^7$ транзисторов;\n",
1220 | "\n",
1221 | "* AlexNet на двух GPU GTX580 это уже примерно $10^{14}$;\n",
1222 | "\n",
1223 | "С данными у ученых дела обстоят не так хорошо.\n"
1224 | ],
1225 | "metadata": {}
1226 | },
1227 | {
1228 | "cell_type": "markdown",
1229 | "source": [
1230 | "## Примеры датасетов"
1231 | ],
1232 | "metadata": {}
1233 | },
1234 | {
1235 | "cell_type": "markdown",
1236 | "source": [
1237 | "
"
1238 | ],
1239 | "metadata": {}
1240 | },
1241 | {
1242 | "cell_type": "markdown",
1243 | "source": [
1244 | "Ссылка "
1245 | ],
1246 | "metadata": {}
1247 | },
1248 | {
1249 | "cell_type": "markdown",
1250 | "source": [
1251 | "
"
1252 | ],
1253 | "metadata": {}
1254 | },
1255 | {
1256 | "cell_type": "markdown",
1257 | "source": [
1258 | "ImageNet — массивная база данных аннотированных изображений предназначенная для построения и тестирования моделей компьютерного зрения. На этом датасете предобученны все модели для классификации, которые присутствуют в “зоопарке моделей” Pytorch."
1259 | ],
1260 | "metadata": {}
1261 | },
1262 | {
1263 | "cell_type": "markdown",
1264 | "source": [
1265 | "http://image-net.org/download"
1266 | ],
1267 | "metadata": {}
1268 | },
1269 | {
1270 | "cell_type": "markdown",
1271 | "source": [
1272 | "
"
1273 | ],
1274 | "metadata": {}
1275 | },
1276 | {
1277 | "cell_type": "markdown",
1278 | "source": [
1279 | "Coco содержит сложные бытовые сцены предметов в их естественном контексте. Используется для обучения моделей, решающих задачи классификации, сегментации и детектирования. В нём намного меньше категорий объектов, чем в ImageNet, но присутствует разметка по bounding box и маскам.\n",
1280 | "\n",
1281 | "http://cocodataset.org"
1282 | ],
1283 | "metadata": {}
1284 | },
1285 | {
1286 | "cell_type": "markdown",
1287 | "source": [
1288 | "#### Набор данных MosMedData: COVID19_1110"
1289 | ],
1290 | "metadata": {}
1291 | },
1292 | {
1293 | "cell_type": "markdown",
1294 | "source": [
1295 | "
"
1296 | ],
1297 | "metadata": {}
1298 | },
1299 | {
1300 | "cell_type": "markdown",
1301 | "source": [
1302 | "Набор содержит результаты исследований компьютерной томографии органов грудной клетки с признаками COVID-19\n",
1303 | "\n",
1304 | "Предыдущие два датасета были исследовательские. На них соревнуются, проверяют гипотезы, качество работы новых моделей.\n",
1305 | "Для них много примеров и хорошие описания.\n",
1306 | "\n",
1307 | "По ссылке можно найти пример реального датасета\n",
1308 | "\n",
1309 | "Скорее всего разобраться с тем, как использовать эти данные, будет сложнее.\n"
1310 | ],
1311 | "metadata": {}
1312 | },
1313 | {
1314 | "cell_type": "markdown",
1315 | "source": [
1316 | "
"
1317 | ],
1318 | "metadata": {}
1319 | },
1320 | {
1321 | "cell_type": "markdown",
1322 | "source": [
1323 | "http://yann.lecun.com/exdb/mnist/\n",
1324 | "\n",
1325 | "База данных рукописных цифр."
1326 | ],
1327 | "metadata": {}
1328 | },
1329 | {
1330 | "cell_type": "markdown",
1331 | "source": [
1332 | "
"
1333 | ],
1334 | "metadata": {}
1335 | },
1336 | {
1337 | "cell_type": "markdown",
1338 | "source": [
1339 | "https://www.cs.toronto.edu/~kriz/cifar.html\n",
1340 | "\n",
1341 | "Маленькие изображения в низком разрешении, разделённые на 10 классов."
1342 | ],
1343 | "metadata": {}
1344 | },
1345 | {
1346 | "cell_type": "markdown",
1347 | "source": [
1348 | "CIFAR10/100 и MNIST — это **учебные датасеты.**\n",
1349 | "\n",
1350 | "В них изображения размечены по нескольким классам. Чтобы загрузка и обучение проходили быстро, картинки имеют небольшое разрешение, а количество классов невелико.\n",
1351 | "В остальном всё как у взрослых.\n",
1352 | "\n",
1353 | "И авторы статей, посвящённых разработке новых нейросетевых моделей, достаточно часто приводят результаты работы своих моделей на этих датасетах.\n"
1354 | ],
1355 | "metadata": {}
1356 | },
1357 | {
1358 | "cell_type": "markdown",
1359 | "source": [
1360 | "### 3.8 Оценка результата "
1361 | ],
1362 | "metadata": {}
1363 | },
1364 | {
1365 | "cell_type": "markdown",
1366 | "source": [
1367 | "
"
1368 | ],
1369 | "metadata": {}
1370 | },
1371 | {
1372 | "cell_type": "markdown",
1373 | "source": [
1374 | "Вторая часть работы — это оценка точности. Нам нужно определиться с тем, как оценивать результат.\n",
1375 | "Очень часто приходится слышать от заказчика вопрос со слайда.\n",
1376 | "Чаще всего ответ “99%” их более чем устраивает. \n",
1377 | "\n",
1378 | "\n",
1379 | "В большинстве случаев такой ответ воспринимается неверно, что в дальнейшем приводит к проблемам. Почему?"
1380 | ],
1381 | "metadata": {}
1382 | },
1383 | {
1384 | "cell_type": "markdown",
1385 | "source": [
1386 | "
"
1387 | ],
1388 | "metadata": {}
1389 | },
1390 | {
1391 | "cell_type": "markdown",
1392 | "source": [
1393 | "
"
1394 | ],
1395 | "metadata": {}
1396 | },
1397 | {
1398 | "cell_type": "markdown",
1399 | "source": [
1400 | "1. Скорость перемещения машины зависит от дороги: на дорогах бывают пробки, ограничивающие знаки, наконец, дороги бывают очень разного качества.\n",
1401 | "\n",
1402 | "Всё это влияет на скорость перемещения и порой радикально.\n",
1403 | "\n",
1404 | "Так же и точность наших моделей в первую очередь зависит от данных, на которых мы будем их оценивать. Модель, которая отлично работает на одном датасете, может намного хуже работать на другом или не работать вовсе. В том числе в силу технических причин (пример про Resnet и CIFAR10).\n",
1405 | "\n",
1406 | "2. Машина может быть подвергнута тюнингу. Например, внедорожный тюнинг поможет преодолеть участок бездорожья, на котором неподготовленный автомобиль застрянет. Но при этом скорость на дорогах общего пользования может снизиться. Так же и модель, как правило, имеет ряд параметров (гиперпараметров), от которых зависит её работа. Они могут подбираться в зависимости от задачи (ошибки первого и второго рода) и качества данных.\n",
1407 | "\n",
1408 | "3. Само понятие скорости допускает вариации: речь идет о средней или максимальной скорости? Аналогично и для оценки моделей существует несколько метрик, применение которых, опять же, зависит от целей заказчика и особенностей данных.\n",
1409 | "\n",
1410 | "Поэтому честный ответ на вопрос о точности должен звучать так: «На датасете X модель Y по метрике Z показала точность 99%».\n"
1411 | ],
1412 | "metadata": {}
1413 | },
1414 | {
1415 | "cell_type": "markdown",
1416 | "source": [
1417 | "
"
1418 | ],
1419 | "metadata": {}
1420 | },
1421 | {
1422 | "cell_type": "markdown",
1423 | "source": [
1424 | "Самый простой способ подсчёта точности модели — это деление количества правильно распознанных элементов на общее их количество.\n",
1425 | "\n",
1426 | "**Какие есть недостатки у такого способа?**\n"
1427 | ],
1428 | "metadata": {}
1429 | },
1430 | {
1431 | "cell_type": "markdown",
1432 | "source": [
1433 | "
"
1434 | ],
1435 | "metadata": {}
1436 | },
1437 | {
1438 | "cell_type": "markdown",
1439 | "source": [
1440 | "Accuracy нельзя использовать, если данные не сбалансированы. То есть в одном из классов больше представителей, чем в другом.\n",
1441 | "\n",
1442 | "Также она не подойдет для задач сегментации и детектирования, если требуется не только определить наличие объекта на изображении, но и найти место, где он находится, то весьма желательно учитывать разницу в координатах.\n",
1443 | "\n",
1444 | "Сегодня же мы будем решать задачу классификации на учебных датасетах, где данные либо сбалансированы, либо дисбалансом можно пренебречь."
1445 | ],
1446 | "metadata": {}
1447 | },
1448 | {
1449 | "cell_type": "markdown",
1450 | "source": [
1451 | "## 5. Демонстрация работы с данными "
1452 | ],
1453 | "metadata": {}
1454 | },
1455 | {
1456 | "cell_type": "markdown",
1457 | "source": [
1458 | "### 5.1 Табличные данные "
1459 | ],
1460 | "metadata": {}
1461 | },
1462 | {
1463 | "cell_type": "markdown",
1464 | "source": [
1465 | "#### 5.1.1 Обзор инструментов "
1466 | ],
1467 | "metadata": {}
1468 | },
1469 | {
1470 | "cell_type": "markdown",
1471 | "source": [
1472 | "Рассмотрим примеры решения задач классификации на различных типах данных."
1473 | ],
1474 | "metadata": {}
1475 | },
1476 | {
1477 | "cell_type": "markdown",
1478 | "source": [
1479 | "Будем использовать библиотеки:\r\n",
1480 | "\r\n",
1481 | "* [numpy](https://numpy.org/) — Работа с многомерными массивами данных и высокоуровневыми математическими функциями;\r\n",
1482 | "* [sklearn](https://scikit-learn.org/stable/) — ML алгоритмы, 'toy' — датасеты;\r\n",
1483 | "* [pandas](https://pandas.pydata.org/) — Удобная работа с табличными данными."
1484 | ],
1485 | "metadata": {}
1486 | },
1487 | {
1488 | "cell_type": "markdown",
1489 | "source": [
1490 | "* [**Pytorch**](https://pytorch.org/) — Основной фреймворк машинного обучения, который будет использоваться на протяжении всего курса."
1491 | ],
1492 | "metadata": {}
1493 | },
1494 | {
1495 | "cell_type": "markdown",
1496 | "source": [
1497 | "Познакомимся с инструментом:"
1498 | ],
1499 | "metadata": {}
1500 | },
1501 | {
1502 | "cell_type": "markdown",
1503 | "source": [
1504 | "* [Tensorboard](https://www.tensorflow.org/tensorboard) — визуализация данных."
1505 | ],
1506 | "metadata": {}
1507 | },
1508 | {
1509 | "cell_type": "markdown",
1510 | "source": [
1511 | "#### 5.1.2 Загрузка данных "
1512 | ],
1513 | "metadata": {}
1514 | },
1515 | {
1516 | "cell_type": "markdown",
1517 | "source": [
1518 | "#### Классификация вин \n",
1519 | "\n",
1520 | "Пример работы с табличными данными. \n",
1521 | "Классифицируем вина из датасета : https://archive.ics.uci.edu/ml/machine-learning-databases/wine/"
1522 | ],
1523 | "metadata": {}
1524 | },
1525 | {
1526 | "cell_type": "markdown",
1527 | "source": [
1528 | "Задача будет состоять в том, чтобы по химическому составу определить производителя вина.\n",
1529 | "\n",
1530 | "Количество экземпляров, полученных на тест от каждого из трех производителей, не одинаково."
1531 | ],
1532 | "metadata": {}
1533 | },
1534 | {
1535 | "cell_type": "markdown",
1536 | "source": [
1537 | "Производитель №1 (class_1) 59 бутылок \n",
1538 | "Производитель №2 (class_2) 71 бутылка \n",
1539 | "Производитель №3 (class_3) 48 бутылок "
1540 | ],
1541 | "metadata": {}
1542 | },
1543 | {
1544 | "cell_type": "markdown",
1545 | "source": [
1546 | "Этот датасет можно загрузить, используя модуль sklearn.datasets библиотеки [sklearn](https://scikit-learn.org/stable/), чем мы и воспользуемся."
1547 | ],
1548 | "metadata": {}
1549 | },
1550 | {
1551 | "cell_type": "code",
1552 | "execution_count": null,
1553 | "source": [
1554 | "import sklearn \r\n",
1555 | "from sklearn.datasets import load_wine\r\n",
1556 | "#https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_wine.html#sklearn.datasets.load_wine\r\n",
1557 | "\r\n",
1558 | "# Download dataset \r\n",
1559 | "data = load_wine(return_X_y=True) # Так же можно получить данные в Bunch(словарь) или pandas DataFrame\r\n",
1560 | "\r\n",
1561 | "features = data[0] # Массив 178x13 178 бутылок у каждой 13 признаков\r\n",
1562 | "class_labels = data[1] # Массив из 178 элементов каждый элемент это число обозначающее класс к которому относиться данная бутылка : 0,1 2 \r\n",
1563 | "print(\"Размерность массива с данными:\", features.shape)\r\n",
1564 | "print(\"Размерность массива с номерами классов:\", class_labels.shape)"
1565 | ],
1566 | "outputs": [],
1567 | "metadata": {}
1568 | },
1569 | {
1570 | "cell_type": "markdown",
1571 | "source": [
1572 | "#### 5.1.3 Визуализация данных "
1573 | ],
1574 | "metadata": {}
1575 | },
1576 | {
1577 | "cell_type": "markdown",
1578 | "source": [
1579 | "\n",
1580 | "Если параметр \n",
1581 | " \n",
1582 | " return_X_y == False\n",
1583 | "\n",
1584 | "то данные вернуться не в виде массива, а в объекте [Bunch](https://scikit-learn.org/stable/modules/generated/sklearn.utils.Bunch.html#sklearn.utils.Bunch).\n",
1585 | "\n",
1586 | "Обращаться к нему можно, как к обычному словарю в Python. Кроме того, у него есть свойство, соответствующее каждому полю данных.\n",
1587 | "\n",
1588 | "Чтобы отобразить данные в виде таблицы, преобразуем их в формат pandas.DataFrame.\n"
1589 | ],
1590 | "metadata": {}
1591 | },
1592 | {
1593 | "cell_type": "code",
1594 | "execution_count": null,
1595 | "source": [
1596 | "# Подключим библиотеку для работы с табличнымии данными: https://pandas.pydata.org/\r\n",
1597 | "import pandas as pd \r\n",
1598 | "\r\n",
1599 | "data_bunch = load_wine(return_X_y=False) # Загрузим данные в виде объекта Bunch\r\n",
1600 | "print(data_bunch.keys()) # Ключи соответствуют различным данным, которые находятся в нашем объекте\r\n",
1601 | "\r\n",
1602 | "df = pd.DataFrame(data_bunch.data, columns=data_bunch.feature_names) # data_bunch.data - набор признаков для каждого объекта \r\n",
1603 | " # data_bunch.feature_names - номер класса для каждого объекта\r\n",
1604 | "\r\n",
1605 | "df.head()"
1606 | ],
1607 | "outputs": [],
1608 | "metadata": {}
1609 | },
1610 | {
1611 | "cell_type": "markdown",
1612 | "source": [
1613 | "Каждая строка в таблице представляет собой один объект (бутылка вина), представленный как вектор из 13 признаков. Можно интерпретировать такой вектор как координаты точки в 13-мерном пространстве. Именно с таким представлением данных работают большинство алгоритмов машинного обучения. "
1614 | ],
1615 | "metadata": {}
1616 | },
1617 | {
1618 | "cell_type": "markdown",
1619 | "source": [
1620 | "Визуализировать 13-мерное пространство не получится :(. "
1621 | ],
1622 | "metadata": {}
1623 | },
1624 | {
1625 | "cell_type": "markdown",
1626 | "source": [
1627 | "Но можно визуализировать проекцию данных в трёхмерное пространство. Для этого воспользуемся инструментом projector из tensorboard."
1628 | ],
1629 | "metadata": {}
1630 | },
1631 | {
1632 | "cell_type": "markdown",
1633 | "source": [
1634 | "https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html"
1635 | ],
1636 | "metadata": {}
1637 | },
1638 | {
1639 | "cell_type": "markdown",
1640 | "source": [
1641 | "### Запуск Tensorboard "
1642 | ],
1643 | "metadata": {}
1644 | },
1645 | {
1646 | "cell_type": "markdown",
1647 | "source": [
1648 | "#### Локальный запуск\n",
1649 | "Для локального запуска tensorboard:\n",
1650 | "\n",
1651 | "* Нужно установить пакет: https://pypi.org/project/tensorboard/; \n",
1652 | "\n",
1653 | "* Затем выполнить команду:\n",
1654 | "\n",
1655 | " `tensorboard --logdir --port 6006`"
1656 | ],
1657 | "metadata": {}
1658 | },
1659 | {
1660 | "cell_type": "markdown",
1661 | "source": [
1662 | "где — путь к каталогу, в котором будут храниться файлы логов.\n",
1663 | " В результате выполнения этой команды будет запущен локальный web-сервер на порту 6060.\n",
1664 | "\n",
1665 | "\n",
1666 | "* Затем в браузере открыть адрес: localhost:6006"
1667 | ],
1668 | "metadata": {}
1669 | },
1670 | {
1671 | "cell_type": "markdown",
1672 | "source": [
1673 | "#### Запуск в Colab\n",
1674 | "\n",
1675 | "До некоторого времени запуск Tensorboard в Colab был сопряжен с некоторыми сложностями ввиду того, что виртуальная машина (docker-container), которую предоставляет нам Colab, не имеет постоянного IP адреса. И в интернете много устаревших инструкций по поводу того, как обойти эту проблемму. \n",
1676 | "Но в настоящее время этот инструмент встроили в Colab и для его запуска прямо в ячейке достаточно двух 'магических строк':\n",
1677 | "\n",
1678 | "\n",
1679 | "```\n",
1680 | " %load_ext tensorboard\n",
1681 | " %tensorboard --logdir {logs_base_dir}\n",
1682 | "```"
1683 | ],
1684 | "metadata": {}
1685 | },
1686 | {
1687 | "cell_type": "markdown",
1688 | "source": [
1689 | "Но так как Tensorboard работает только с логами на диске, то периодически приходится их очищать, для чего рекомендуется использовать метод \n",
1690 | "\n",
1691 | "`reinit_tensorboard`\n",
1692 | "\n",
1693 | "из ячейки ниже."
1694 | ],
1695 | "metadata": {}
1696 | },
1697 | {
1698 | "cell_type": "markdown",
1699 | "source": [
1700 | "Кроме того, если существует ячейка, в которой уже выполняется код (например, идёт процесс обучения), то другие ячейки блокируются. В том числе мы не сможем воспользоваться Tensorboard, если он запущен в другой ячейке."
1701 | ],
1702 | "metadata": {}
1703 | },
1704 | {
1705 | "cell_type": "markdown",
1706 | "source": [
1707 | "Поэтому, если требуется мониторинг блока кода, который исполняется долгое время, то можно создать Tensorboard в ячейке с этим блоком кода, добавив в конце вызов: `reinit_tensorboard(clear_log = False)`"
1708 | ],
1709 | "metadata": {}
1710 | },
1711 | {
1712 | "cell_type": "code",
1713 | "execution_count": null,
1714 | "source": [
1715 | "# Вспомогательный метод для запуска Tensorboard в Colab\r\n",
1716 | "\r\n",
1717 | "# Fix: https://stackoverflow.com/questions/60730544/tensorboard-colab-tensorflow-api-v1-io-gfile-has-no-attribute-get-filesystem\r\n",
1718 | "import tensorflow as tf\r\n",
1719 | "import tensorboard as tb\r\n",
1720 | "tf.io.gfile = tb.compat.tensorflow_stub.io.gfile\r\n",
1721 | "\r\n",
1722 | "import os\r\n",
1723 | "import shutil\r\n",
1724 | "\r\n",
1725 | "# Запуск Tensorboard в Colab\r\n",
1726 | "def reinit_tensorboard(clear_log = True):\r\n",
1727 | " # Лог-файлы читаются из этого каталога: \r\n",
1728 | " logs_base_dir = \"runs\"\r\n",
1729 | " if clear_log:\r\n",
1730 | " # Очистка логов\r\n",
1731 | " #!rm -rfv {logs_base_dir}/*\r\n",
1732 | " shutil.rmtree(logs_base_dir, ignore_errors = True)\r\n",
1733 | " os.makedirs(logs_base_dir, exist_ok=True)\r\n",
1734 | " # Магия Colab\r\n",
1735 | " %load_ext tensorboard\r\n",
1736 | " %tensorboard --logdir {logs_base_dir}"
1737 | ],
1738 | "outputs": [],
1739 | "metadata": {}
1740 | },
1741 | {
1742 | "cell_type": "markdown",
1743 | "source": [
1744 | "После загрузки Tensorboard измените значение опции \"Color by\" на \"label 3 colors\" чтобы объекты, принадлежащие к разным классам, отображались разными цветами."
1745 | ],
1746 | "metadata": {}
1747 | },
1748 | {
1749 | "cell_type": "code",
1750 | "execution_count": null,
1751 | "source": [
1752 | "from torch.utils.tensorboard import SummaryWriter\r\n",
1753 | "import numpy\r\n",
1754 | "\r\n",
1755 | "reinit_tensorboard()\r\n",
1756 | "\r\n",
1757 | "writer = SummaryWriter(comment = \"wine\") # объект SummaryWriter() служит для записи результатов в лог tehsorboard\r\n",
1758 | "np_f = numpy.array(features)\r\n",
1759 | "writer.add_embedding(np_f, metadata=class_labels) # метод add_embeddings() добавляет в объект класса SummaryWriter() \r\n",
1760 | " # проекцию данных в пространство меньшей размерности\r\n",
1761 | "writer.close()"
1762 | ],
1763 | "outputs": [],
1764 | "metadata": {}
1765 | },
1766 | {
1767 | "cell_type": "markdown",
1768 | "source": [
1769 | "Видно, что объекты классов 1 и 2 линейно неразделимы в 2-х измерениях. По этой причине так популярен переход к пространствам большей размерности. \n",
1770 | "\n",
1771 | "Обратите внимание, что данные центрированны около нуля — это результат нормализации, которой они подверглись в Tensorboard.\n",
1772 | "\n",
1773 | "Нам тоже потребуется нормализовывать данные."
1774 | ],
1775 | "metadata": {}
1776 | },
1777 | {
1778 | "cell_type": "markdown",
1779 | "source": [
1780 | "#### 5.1.4 Нормализация данных "
1781 | ],
1782 | "metadata": {}
1783 | },
1784 | {
1785 | "cell_type": "markdown",
1786 | "source": [
1787 | "Посмотрим на то, какие масштабы имеют значения разных признаков. \n",
1788 | "Для сохранения в формат Tensorboard используем модуль torch.utils.tensorboard.\n",
1789 | "\n",
1790 | "Для начала отобразим два признака: malic_acid и alcalinity_of_ash. Их значения отличаются примерно на порядок."
1791 | ],
1792 | "metadata": {}
1793 | },
1794 | {
1795 | "cell_type": "code",
1796 | "execution_count": null,
1797 | "source": [
1798 | "import torch\r\n",
1799 | "\r\n",
1800 | "f_names = data_bunch.feature_names\r\n",
1801 | "for i, feature in enumerate(features):\r\n",
1802 | " # Pass a dictinary with name:value pairs to writer\r\n",
1803 | " writer.add_scalars(\"Raw_2_par\",{ \r\n",
1804 | " f_names[1]:feature[1], # malic_acid\r\n",
1805 | " f_names[3]:feature[3], # alcalinity_of_ash\r\n",
1806 | " } )\r\n",
1807 | "writer.close()\r\n",
1808 | "# Uncomment if need\r\n",
1809 | "# reinit_tensorboard()"
1810 | ],
1811 | "outputs": [],
1812 | "metadata": {}
1813 | },
1814 | {
1815 | "cell_type": "markdown",
1816 | "source": [
1817 | "\n",
1818 | "После выполнения кода в этой ячейке, в Tensorboard выберите пункт меню \"SCALARS\" и нажмите иконку \"Обновить\" и затем 'Horizontal Axis' = Relative\n"
1819 | ],
1820 | "metadata": {}
1821 | },
1822 | {
1823 | "cell_type": "markdown",
1824 | "source": [
1825 | "Добавим в лог tensorboard ещё один признак, значения которого отличается от второго на 2 порядка."
1826 | ],
1827 | "metadata": {}
1828 | },
1829 | {
1830 | "cell_type": "code",
1831 | "execution_count": null,
1832 | "source": [
1833 | "for i, feature in enumerate(features):\r\n",
1834 | " writer.add_scalars(\"Raw_3par\",{ \r\n",
1835 | " f_names[1]:feature[1], # malic_acid\r\n",
1836 | " f_names[3]:feature[3], # alcalinity_of_ash\r\n",
1837 | " f_names[12]:feature[12] # proline \r\n",
1838 | " } ) \r\n",
1839 | "writer.close()"
1840 | ],
1841 | "outputs": [],
1842 | "metadata": {}
1843 | },
1844 | {
1845 | "cell_type": "markdown",
1846 | "source": [
1847 | "Значения в разных масштабах — модели будет сложно сравнивать их между собой. "
1848 | ],
1849 | "metadata": {}
1850 | },
1851 | {
1852 | "cell_type": "markdown",
1853 | "source": [
1854 | "#### Гистограммы в Tensorboard\n",
1855 | "\n",
1856 | "Для наглядности построим гистограмму. Сначала сделаем это для сырых данных."
1857 | ],
1858 | "metadata": {}
1859 | },
1860 | {
1861 | "cell_type": "code",
1862 | "execution_count": null,
1863 | "source": [
1864 | "writer.add_histogram(\"1.Raw\" , features[:,3])\r\n",
1865 | "writer.add_histogram(\"1.Raw\" , features[:,1])\r\n",
1866 | "writer.close()"
1867 | ],
1868 | "outputs": [],
1869 | "metadata": {}
1870 | },
1871 | {
1872 | "cell_type": "markdown",
1873 | "source": [
1874 | "Чтобы увидеть гистограмму, дождитесь выполнения кода в ячейку выше и затем выберите пункт меню\n",
1875 | "\n",
1876 | "* \"HISTOGRAMS\" в Tensorboard и\n",
1877 | "\n",
1878 | "* Offset time axis = WALL или RELATIVE"
1879 | ],
1880 | "metadata": {}
1881 | },
1882 | {
1883 | "cell_type": "markdown",
1884 | "source": [
1885 | "#### Min-Max нормализация\r\n",
1886 | "\r\n",
1887 | "Нормализация — это процедура предобработки данных, при которой значения признаков приводятся к некоторому заданному диапазону. Цель нормализации — приведение данных в разных диапазонах значений к единому виду, позволяющему сравнивать их между собой, а также использовать для рассчета расстояния между объектами в задачах кластеризации.\r\n",
1888 | "\r\n",
1889 | "В качестве примера важности нормализации представим, что у вас есть набор данных с некоторыми признаками. Признаки отличаются по типу распределения и диапазону значений. В большинстве методов кластеризации нужно рассчитать меру \"сходства\" — расстояние между объектами. Часто в роли такого расстнояния выступает евклидова метрика. Для точек $p$ и $q$ в $n$-мерном пространстве, евклидова метрика рассчитывается как $d(p,q)=\\sqrt{\\sum_{i=1}^{n}(p_i-q_i)^2}$. Если один из признаков лежит в диапазоне [-1;1], а второй — [-1000;1000], то изменения второго признака могут оказать существенно большее влияние на метрику, а значит он будет в привелигированном положении по сравнению с первым. Нормализация приводит значения признаков к одному диапазону, таким образом делая признаки равными в возможностях своего влияния на результат вычислений.\r\n",
1890 | "\r\n",
1891 | "Простейший способ нормализации — это **Min-Max нормализация**. Вычтем минимальное значение и поделим на среднее. Это преобразование сводится к тому, что данные сначала смещаются, а потом масштабируются.\r\n",
1892 | "\r\n",
1893 | "
"
1894 | ],
1895 | "metadata": {}
1896 | },
1897 | {
1898 | "cell_type": "code",
1899 | "execution_count": null,
1900 | "source": [
1901 | "# cast data to torch.Tensor \r\n",
1902 | "tensor_f = torch.tensor(features)\r\n",
1903 | "\r\n",
1904 | "# torch.min и torch.max return tuple (values, indexes)\r\n",
1905 | "# https://pytorch.org/docs/stable/generated/torch.min.html#torch.min\r\n",
1906 | "\r\n",
1907 | "min_values, _ = tensor_f.min(dim=0,keepdim=True) # shape = (1,13)\r\n",
1908 | "max_values, _ = tensor_f.max(dim=0,keepdim=True) # shape = (1,13)\r\n",
1909 | "\r\n",
1910 | "print(min_values.shape)\r\n",
1911 | "\r\n",
1912 | "# Substract min\r\n",
1913 | "min_max_centered = tensor_f - min_values # shape = (178,13)\r\n",
1914 | "\r\n",
1915 | "# Divide by mean\r\n",
1916 | "min_max_normalized = min_max_centered / (max_values - min_values) # shape = (1,13)\r\n",
1917 | "\r\n",
1918 | "# Write to Tensorboard logs\r\n",
1919 | "writer.add_histogram(\"2.Min_Max_Centered\" , min_max_centered[:,3])\r\n",
1920 | "writer.add_histogram(\"2.Min_Max_Centered\" , min_max_centered[:,1])\r\n",
1921 | "\r\n",
1922 | "writer.add_histogram(\"2.Min_Max_Normalized\" , min_max_normalized[:,3])\r\n",
1923 | "writer.add_histogram(\"2.Min_Max_Normalized\" , min_max_normalized[:,1])\r\n",
1924 | "writer.close()"
1925 | ],
1926 | "outputs": [],
1927 | "metadata": {}
1928 | },
1929 | {
1930 | "cell_type": "markdown",
1931 | "source": [
1932 | "В Tensorboard (выше) можно видеть, что после центрирования значения сместились в сторону нуля, а после нормализации они сильно перекрываются, то есть данные перестали заметно отличаться по масштабу."
1933 | ],
1934 | "metadata": {}
1935 | },
1936 | {
1937 | "cell_type": "markdown",
1938 | "source": [
1939 | "# Стандартизация / Z-нормализация\r\n",
1940 | "\r\n",
1941 | "
\r\n",
1942 | "\r\n",
1943 | "При Min-Max нормализации остается проблема выбросов (см. 1-ую гистограмму). Если в данных есть даже единичные выбросы, то они займут значительную часть диапазона. Это происходит потому что, при Min-Max нормализации, все значения признака помещаются в заранее предопределенный диапазон значений от 0 до 1, таким образом Min-Max нормализация влияет только на размах значений признака и после нормализации выбросы останутся выбросами.\r\n",
1944 | "\r\n",
1945 | "**Стандартизация** не имеет определенных границ значений признака. Её цель — преобразовать исходные данные в новые со средним значением равным 0 и стандартным отклонением равным 1. Соответственно, процедура стандартизации включает в себя два преобразорания: центрирование — вычитание среднего значения и нормирование — деление на стандартное отклонение."
1946 | ],
1947 | "metadata": {}
1948 | },
1949 | {
1950 | "cell_type": "code",
1951 | "execution_count": null,
1952 | "source": [
1953 | "# Substract min\r\n",
1954 | "centered = tensor_f - tensor_f.mean(dim=0)\r\n",
1955 | "# Divide by standard deviation\r\n",
1956 | "normalized = centered / tensor_f.std(dim=0)\r\n",
1957 | "\r\n",
1958 | "# Write to Tensorboard logs\r\n",
1959 | "writer.add_histogram(\"3.Z-Centered\" , centered[:,3])\r\n",
1960 | "writer.add_histogram(\"3.Z-Centered\" , centered[:,1])\r\n",
1961 | "\r\n",
1962 | "writer.add_histogram(\"3.Z-Normalized\" , normalized[:,3])\r\n",
1963 | "writer.add_histogram(\"3.Z-Normalized\" , normalized[:,1])\r\n",
1964 | "\r\n",
1965 | "\r\n",
1966 | "writer.add_histogram(\"4.Mix: raw, MM, Z\" , features[:,1])\r\n",
1967 | "writer.add_histogram(\"4.Mix: raw, MM, Z\" , min_max_normalized[:,1])\r\n",
1968 | "writer.add_histogram(\"4.Mix: raw, MM, Z\" , normalized[:,1])\r\n",
1969 | "\r\n",
1970 | "writer.close()"
1971 | ],
1972 | "outputs": [],
1973 | "metadata": {}
1974 | },
1975 | {
1976 | "cell_type": "markdown",
1977 | "source": [
1978 | "Посмотрите на гистограммы в Tensorboard.\n",
1979 | "\n",
1980 | "Наглядное приемущество стандартизации перед Max-Min нормализацией.\n"
1981 | ],
1982 | "metadata": {}
1983 | },
1984 | {
1985 | "cell_type": "markdown",
1986 | "source": [
1987 | "#### 5.1.5 Обучение"
1988 | ],
1989 | "metadata": {}
1990 | },
1991 | {
1992 | "cell_type": "markdown",
1993 | "source": [
1994 | "Базовая документация:\n",
1995 | "https://scikit-learn.org/stable/modules/svm.html\n",
1996 | "\n",
1997 | "Используем простую модель, пример использования SVM классификатора: \n",
1998 | "https://www.datacamp.com/community/tutorials/svm-classification-scikit-learn-python\n",
1999 | "\n",
2000 | "Её устройство будет рассмотрено на следующих лекциях, сейчас будем считать модель чёрным ящиком."
2001 | ],
2002 | "metadata": {}
2003 | },
2004 | {
2005 | "cell_type": "markdown",
2006 | "source": [
2007 | "#### 5.1.6 Разбиение данных на обучающую и тестовую выборки \n",
2008 | "\n",
2009 | "Самым простым способом научиться чему-либо является \"запомнить всё\"."
2010 | ],
2011 | "metadata": {}
2012 | },
2013 | {
2014 | "cell_type": "markdown",
2015 | "source": [
2016 | "Вспомним \"Таблицу умножения\". Если мы хотим проверить умение умножать, то проверки примерами из таблицы умножения будет недостаточно, ведь она может быть полностью запомнена. Нужно давать новые примеры, которых не было в таблице умножения (обучающей выборке)."
2017 | ],
2018 | "metadata": {}
2019 | },
2020 | {
2021 | "cell_type": "markdown",
2022 | "source": [
2023 | "Если модель \"запомнит всё\", то она будет идеально работать на данных, которые мы ей показали, но может вообще не работать на любых других данных.\n",
2024 | "\n",
2025 | "С практической точки зрения важно, как модель будет вести себя именно на незнакомых для неё данных. То есть насколько хорошо она научилась обобщать закономерности, которые в данных присутствовали (если они вообще существуют)."
2026 | ],
2027 | "metadata": {}
2028 | },
2029 | {
2030 | "cell_type": "markdown",
2031 | "source": [
2032 | "Для оценки этой способности набор данных разделяют на две, а иногда даже на три части:\n",
2033 | "\n",
2034 | "* train — Данные, на которых модель учится;\n",
2035 | "* validation/test — Данные, на которых идет проверка.\n",
2036 | "\n",
2037 | "В `sklearn.model_selection` есть модель для разделения массива данных на тренировочную и тестовую часть. "
2038 | ],
2039 | "metadata": {}
2040 | },
2041 | {
2042 | "cell_type": "code",
2043 | "execution_count": null,
2044 | "source": [
2045 | "# Split data\r\n",
2046 | "from sklearn.model_selection import train_test_split\r\n",
2047 | "\r\n",
2048 | "X_train, X_test, y_train, y_test = train_test_split(features, class_labels, test_size=0.2) # 80% training and 20% test\r\n",
2049 | "\r\n",
2050 | "print(\"X_train\",X_train.shape)\r\n",
2051 | "print(\"X_test\",X_test.shape)"
2052 | ],
2053 | "outputs": [],
2054 | "metadata": {}
2055 | },
2056 | {
2057 | "cell_type": "markdown",
2058 | "source": [
2059 | "А мы в дальнейшем будем пользоваться аналогичными инструментами библиотеки PyTorch."
2060 | ],
2061 | "metadata": {}
2062 | },
2063 | {
2064 | "cell_type": "markdown",
2065 | "source": [
2066 | "#### 5.1.7 Обучим модель и посчитаем точность (Accuracy) \n",
2067 | "\n",
2068 | "Теперь можно запустить процесс обучения и посчитать точность работы модели на данном датасете.\n",
2069 | "\n",
2070 | "То есть понять, насколько хорошо по химическому составу модель определит винодела, поставившего это вино.\n",
2071 | "\n",
2072 | "accuracy = p/N\n",
2073 | "\n",
2074 | "где p — количество верных ответов, а N — общее число примеров, использовавшихся в тесте. "
2075 | ],
2076 | "metadata": {}
2077 | },
2078 | {
2079 | "cell_type": "code",
2080 | "execution_count": null,
2081 | "source": [
2082 | "from sklearn import svm\r\n",
2083 | "from sklearn import metrics\r\n",
2084 | "\r\n",
2085 | "# Создаем модель\r\n",
2086 | "lin_clf = svm.LinearSVC()\r\n",
2087 | "\r\n",
2088 | "# Обучаем модель на части данных\r\n",
2089 | "lin_clf.fit(X_train, y_train)\r\n",
2090 | "\r\n",
2091 | "# Получаем предсказания\r\n",
2092 | "y_pred = lin_clf.predict(X_test)\r\n",
2093 | "\r\n",
2094 | "print(\"y_pred\",y_pred.shape)\r\n",
2095 | "\r\n",
2096 | "print(\"Accuracy:\",metrics.accuracy_score(y_test, y_pred))\r\n",
2097 | "\r\n",
2098 | "print(\"Predicted classes: \", y_pred)\r\n",
2099 | "print(\"Real classes: \", y_test)"
2100 | ],
2101 | "outputs": [],
2102 | "metadata": {}
2103 | },
2104 | {
2105 | "cell_type": "markdown",
2106 | "source": [
2107 | "### 5.2 Последовательности "
2108 | ],
2109 | "metadata": {}
2110 | },
2111 | {
2112 | "cell_type": "markdown",
2113 | "source": [
2114 | "Аналогичным образом можно работать с различными типами данных."
2115 | ],
2116 | "metadata": {}
2117 | },
2118 | {
2119 | "cell_type": "markdown",
2120 | "source": [
2121 | "#### 5.2.1 Загрузка даннных "
2122 | ],
2123 | "metadata": {}
2124 | },
2125 | {
2126 | "cell_type": "markdown",
2127 | "source": [
2128 | "\n",
2129 | "\n",
2130 | "В Pytorch есть три библиотеки для работы с разными типами данных:\n",
2131 | "\n",
2132 | "[torchvision](https://pytorch.org/docs/stable/torchvision/datasets.html)\n",
2133 | "\n",
2134 | "[torchaudio](https://pytorch.org/audio/stable/datasets.html)\n",
2135 | "\n",
2136 | "[torchtext](https://pytorch.org/text/stable/index.html)\n",
2137 | "\n",
2138 | "\n",
2139 | "Для загрузки данных используются классы [Dataset](https://pytorch.org/docs/stable/data.html#torch.utils.data.Dataset) и [Dataloader](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader). \n",
2140 | "\n",
2141 | "Они предоставляют единый интерфейс для доступа к данным различных типов.\n",
2142 | "\n"
2143 | ],
2144 | "metadata": {}
2145 | },
2146 | {
2147 | "cell_type": "markdown",
2148 | "source": [
2149 | "**Пример загрузки аудио средствами Pytorch**\n",
2150 | "\n",
2151 | "Рассмотрим пример того, как можно загрузить аудиоданные."
2152 | ],
2153 | "metadata": {}
2154 | },
2155 | {
2156 | "cell_type": "markdown",
2157 | "source": [
2158 | "Установим библиотеку torch.audio (она не входит в список пакетов, доступных в colab по умолчанию)."
2159 | ],
2160 | "metadata": {}
2161 | },
2162 | {
2163 | "cell_type": "code",
2164 | "execution_count": null,
2165 | "source": [
2166 | "# Remove version for local run\r\n",
2167 | "!pip install torchaudio==0.7.0"
2168 | ],
2169 | "outputs": [],
2170 | "metadata": {}
2171 | },
2172 | {
2173 | "cell_type": "markdown",
2174 | "source": [
2175 | "#### Загрузим датасет"
2176 | ],
2177 | "metadata": {}
2178 | },
2179 | {
2180 | "cell_type": "markdown",
2181 | "source": [
2182 | "Speech Commands: [A Dataset for Limited-Vocabulary SpeechRecognition](https://arxiv.org/pdf/1804.03209.pdf)\n",
2183 | "\n",
2184 | "Он представляет из себя набор звуковых файлов в формате .wav"
2185 | ],
2186 | "metadata": {}
2187 | },
2188 | {
2189 | "cell_type": "markdown",
2190 | "source": [
2191 | "в которых записан звук голоса разных людей, произносящих одно из 35 слов на английском языке. Часть слов таких как: \n",
2192 | "\n",
2193 | "- left;\n",
2194 | "- right;\n",
2195 | "- on;\n",
2196 | "- off;\n",
2197 | "- ..."
2198 | ],
2199 | "metadata": {}
2200 | },
2201 | {
2202 | "cell_type": "markdown",
2203 | "source": [
2204 | "А также слова, не являющиеся командами:\n",
2205 | "\n",
2206 | "- cat;\n",
2207 | "- bird;\n",
2208 | "- ..."
2209 | ],
2210 | "metadata": {}
2211 | },
2212 | {
2213 | "cell_type": "markdown",
2214 | "source": [
2215 | "https://pytorch.org/audio/stable/datasets.html#speechcommands"
2216 | ],
2217 | "metadata": {}
2218 | },
2219 | {
2220 | "cell_type": "markdown",
2221 | "source": [
2222 | "*В сравнении с датасетами из torchvision, этот датасет имеет более ограниченный функционал. В частности, в нём нет трансформаций и данные не выровнены. Благодяря этому появляется возможность продемонстрировать необходимость в операциях, которые в дальнейшем будут работать \"из коробки\".*"
2223 | ],
2224 | "metadata": {}
2225 | },
2226 | {
2227 | "cell_type": "code",
2228 | "execution_count": null,
2229 | "source": [
2230 | "import torchaudio\r\n",
2231 | "speech_commands_dataset = torchaudio.datasets.SPEECHCOMMANDS(\"sample_data\",download = True)"
2232 | ],
2233 | "outputs": [],
2234 | "metadata": {}
2235 | },
2236 | {
2237 | "cell_type": "markdown",
2238 | "source": [
2239 | "После загрузки данные будут распакованы в папку sample_data.\n",
2240 | "Откройте её, используя меню в правой панели Colab. Посмотрите, в каком виде они хранятся на диске.\n",
2241 | "\n",
2242 | "\n",
2243 | "Объект speech_commands_dataset — это экземпляр класса, который является наследником [torch.utils.data.Dataset](https://pytorch.org/docs/stable/data.html). Это означает, что в нём реализованы методы: \n",
2244 | "* __getitem__ \n",
2245 | "* __len__\n",
2246 | "\n",
2247 | "Благодаря этому мы можем узнать количество элементов или получить произвольный элемент данных, обращаясь к объекту класса [Dataset](https://pytorch.org/docs/stable/data.html) так же, как к обычному списку в python."
2248 | ],
2249 | "metadata": {}
2250 | },
2251 | {
2252 | "cell_type": "code",
2253 | "execution_count": null,
2254 | "source": [
2255 | "print(\"Количество элементов {} \".format(len(speech_commands_dataset)))\r\n",
2256 | "print(\"Первый элемент\",speech_commands_dataset[0])"
2257 | ],
2258 | "outputs": [],
2259 | "metadata": {}
2260 | },
2261 | {
2262 | "cell_type": "markdown",
2263 | "source": [
2264 | "#### 5.2.3. Визуализация "
2265 | ],
2266 | "metadata": {}
2267 | },
2268 | {
2269 | "cell_type": "markdown",
2270 | "source": [
2271 | "**Что представляет из себя элемент аудио-данных?** \n",
2272 | "Обратимся к документации: https://pytorch.org/audio/stable/datasets.html#speechcommands\n",
2273 | "\n",
2274 | "... returns:\n",
2275 | "\n",
2276 | " (waveform, sample_rate, label, speaker_id, utterance_number)\n",
2277 | "\n",
2278 | "utterance_number — номер повтора. Больше нуля, если один и тот же человек проговаривает одну и ту же фразу несколько раз. "
2279 | ],
2280 | "metadata": {}
2281 | },
2282 | {
2283 | "cell_type": "code",
2284 | "execution_count": null,
2285 | "source": [
2286 | "waveform, sample_rate, label, speaker_id, utterance_number = speech_commands_dataset[1]\r\n",
2287 | "print(\"Waveform: {}\\nSample rate: {}\\nLabel: {} \\nSpeaker_id: {} \\nutterance_number: {}\".format(waveform.shape, sample_rate, label,speaker_id,utterance_number))"
2288 | ],
2289 | "outputs": [],
2290 | "metadata": {}
2291 | },
2292 | {
2293 | "cell_type": "markdown",
2294 | "source": [
2295 | "\n",
2296 | "Размеры тензора waveform:\n",
2297 | " \n",
2298 | " [1, 16000] \n",
2299 | "\n",
2300 | "1 — количество каналов, 16000 — количество измерений в секунду.\n",
2301 | "\n",
2302 | "Если частота дискретизации(sample_rate) равна 16000, то этот фрагмент занимает ровно 1 секунду .\n",
2303 | "\n",
2304 | "**Визуализируем их:** \n",
2305 | "x — время \n",
2306 | "y — давление"
2307 | ],
2308 | "metadata": {}
2309 | },
2310 | {
2311 | "cell_type": "code",
2312 | "execution_count": null,
2313 | "source": [
2314 | "import matplotlib.pyplot as plt\r\n",
2315 | "print(type(waveform))\r\n",
2316 | "plt.figure()\r\n",
2317 | "plt.title(f\"Label: {label}\")\r\n",
2318 | "plt.plot(waveform.t().numpy())"
2319 | ],
2320 | "outputs": [],
2321 | "metadata": {}
2322 | },
2323 | {
2324 | "cell_type": "markdown",
2325 | "source": [
2326 | "**Озвучим:**"
2327 | ],
2328 | "metadata": {}
2329 | },
2330 | {
2331 | "cell_type": "code",
2332 | "execution_count": null,
2333 | "source": [
2334 | "import IPython.display as ipd\r\n",
2335 | "ipd.Audio(waveform.numpy(), rate=sample_rate)"
2336 | ],
2337 | "outputs": [],
2338 | "metadata": {}
2339 | },
2340 | {
2341 | "cell_type": "markdown",
2342 | "source": [
2343 | "#### 5.2.4 Обзор контейнеров "
2344 | ],
2345 | "metadata": {}
2346 | },
2347 | {
2348 | "cell_type": "markdown",
2349 | "source": [
2350 | "**Итерация по датасету**\n",
2351 | "\n",
2352 | "Запустим простую проверку: убедимся, что все записи одинаковой длины."
2353 | ],
2354 | "metadata": {}
2355 | },
2356 | {
2357 | "cell_type": "markdown",
2358 | "source": [
2359 | "**Почему это важно**\n",
2360 | "\n",
2361 | "Мы будем работать с массивами 3 типов:\n",
2362 | "\n",
2363 | "* list — стандартный тип в Python\n",
2364 | "* numpy — массив\n",
2365 | "* torch.tensor"
2366 | ],
2367 | "metadata": {}
2368 | },
2369 | {
2370 | "cell_type": "markdown",
2371 | "source": [
2372 | "Расссмотрим, чем они отличаются:\n",
2373 | "\n",
2374 | "## List"
2375 | ],
2376 | "metadata": {}
2377 | },
2378 | {
2379 | "cell_type": "code",
2380 | "execution_count": null,
2381 | "source": [
2382 | "python_list = ['a',15,123.8,[99,\"I love you\"],[True,True,False]]\r\n",
2383 | "python_list"
2384 | ],
2385 | "outputs": [],
2386 | "metadata": {}
2387 | },
2388 | {
2389 | "cell_type": "markdown",
2390 | "source": [
2391 | "В списке могут быть данные различных типов, в том числе подтипов произвольной длины.\n",
2392 | "\n",
2393 | "## Numpy\n",
2394 | "\n",
2395 | "* Массив может содержать данные только одного типа; \n",
2396 | "* Размер данных во всех измерениям кроме 0-го должен совпадать."
2397 | ],
2398 | "metadata": {}
2399 | },
2400 | {
2401 | "cell_type": "code",
2402 | "execution_count": null,
2403 | "source": [
2404 | "import numpy as np\r\n",
2405 | "\r\n",
2406 | "numpy_arr = np.array([[1,2,3],[4,5,6]],dtype = float)\r\n",
2407 | "print(numpy_arr)\r\n",
2408 | "\r\n",
2409 | "# This code this code will cause an error\r\n",
2410 | "#invalid_numpy_arr = np.array([[1,2,3],[4,5]],dtype = float)"
2411 | ],
2412 | "outputs": [],
2413 | "metadata": {}
2414 | },
2415 | {
2416 | "cell_type": "markdown",
2417 | "source": [
2418 | "Благодаря этому над numpy-массивами можно выполнять различные математические операции."
2419 | ],
2420 | "metadata": {}
2421 | },
2422 | {
2423 | "cell_type": "code",
2424 | "execution_count": null,
2425 | "source": [
2426 | "vector = np.array([1,0,0])\r\n",
2427 | "row_diff = numpy_arr - vector\r\n",
2428 | "print(\"Substract row from array\",row_diff)\r\n",
2429 | "\r\n",
2430 | "scalar_product = numpy_arr.dot(vector)\r\n",
2431 | "print(\"Scalar product\",scalar_product)"
2432 | ],
2433 | "outputs": [],
2434 | "metadata": {}
2435 | },
2436 | {
2437 | "cell_type": "markdown",
2438 | "source": [
2439 | "## Torch.Tensor\n",
2440 | "https://pytorch.org/docs/stable/tensors.html\n",
2441 | "\n",
2442 | " 'is a multi-dimensional matrix containing elements of a single data type.'"
2443 | ],
2444 | "metadata": {}
2445 | },
2446 | {
2447 | "cell_type": "markdown",
2448 | "source": [
2449 | "С точки зрения ограничений и функционала torch.Tensor эквивалентен numpy-массиву.\n",
2450 | "Но дополнительно этот объект поддерживает две важных операции:\n",
2451 | "\n",
2452 | "* Перенос данных на видеокарту (`my_tensor.to('cuda:0')`)\n",
2453 | "* Автоматический рассчет градиентов (`my_tensor.backward()`)"
2454 | ],
2455 | "metadata": {}
2456 | },
2457 | {
2458 | "cell_type": "markdown",
2459 | "source": [
2460 | "Эти возможности понадобятся нам в дальнейшем. Поэтому надо разобраться, как работать с данными в этом формате. Тем более, что torch.Tensor легко преобразуется в numpy-массив и обратно."
2461 | ],
2462 | "metadata": {}
2463 | },
2464 | {
2465 | "cell_type": "code",
2466 | "execution_count": null,
2467 | "source": [
2468 | "import torch\r\n",
2469 | "\r\n",
2470 | "my_tensor = torch.tensor(numpy_arr)\r\n",
2471 | "print(\"torch.Tensor\",my_tensor,\"shape = \",my_tensor.shape)\r\n",
2472 | "\r\n",
2473 | "squared_numpy = my_tensor.pow(2).numpy()\r\n",
2474 | "print(\"Numpy \",squared_numpy,\"shape = \",squared_numpy.shape)"
2475 | ],
2476 | "outputs": [],
2477 | "metadata": {}
2478 | },
2479 | {
2480 | "cell_type": "markdown",
2481 | "source": [
2482 | "#### Проверим, что все записи имеют одинаковую длину: "
2483 | ],
2484 | "metadata": {}
2485 | },
2486 | {
2487 | "cell_type": "code",
2488 | "execution_count": null,
2489 | "source": [
2490 | "import torch\r\n",
2491 | "\r\n",
2492 | "def_length = 16000\r\n",
2493 | "for i, sample in enumerate(speech_commands_dataset):\r\n",
2494 | " waveform, sample_rate, label, speaker_id, utterance_number = sample\r\n",
2495 | " if def_length != waveform.shape[1]: # [1, 16000]\r\n",
2496 | " print(\"Length of object #{i} not equal {def_length}\")\r\n",
2497 | " print(\"Waveform: {}\\nSample rate: {}\\nLabel: {} \\nSpeaker_id: {} \\nutterance_number: {}\".format(waveform.shape, sample_rate, label,speaker_id,utterance_number))\r\n",
2498 | " break\r\n",
2499 | " if not i% 10000 and i > 0 :\r\n",
2500 | " print(f\"Processed {i} objects\") "
2501 | ],
2502 | "outputs": [],
2503 | "metadata": {}
2504 | },
2505 | {
2506 | "cell_type": "markdown",
2507 | "source": [
2508 | "#### 5.2.5 Предобработка данных "
2509 | ],
2510 | "metadata": {}
2511 | },
2512 | {
2513 | "cell_type": "markdown",
2514 | "source": [
2515 | "Если элементы имеют различную длину, то мы не сможем их сравнивать. И даже технически поместить в один массив. \n",
2516 | "\n",
2517 | "\n",
2518 | "Необходимо их выровнять. \n",
2519 | "\n",
2520 | "Так как многие записи начинаются и заканчиваются тишиной, то просто дополним их нулями.\n",
2521 | "\n",
2522 | "\n",
2523 | "Для этого применим концепцию трансформаций (transform), которая широко применяется в Pytorch и встраивается во многие датасеты:"
2524 | ],
2525 | "metadata": {}
2526 | },
2527 | {
2528 | "cell_type": "code",
2529 | "execution_count": null,
2530 | "source": [
2531 | "import torchaudio\r\n",
2532 | "\r\n",
2533 | "# User defined transform\r\n",
2534 | "class PadWaveform(torch.nn.Module):\r\n",
2535 | " def __init__(self, desired_size = 16000):\r\n",
2536 | " self.desired_size = desired_size\r\n",
2537 | " super().__init__()\r\n",
2538 | "\r\n",
2539 | " # in nn.Module forward method called inside __call__ method\r\n",
2540 | "\r\n",
2541 | " def forward(self, waveform):\r\n",
2542 | " if waveform.shape[1] < self.desired_size:\r\n",
2543 | " # Calculate pad size\r\n",
2544 | " diff = self.desired_size - waveform.shape[1]\r\n",
2545 | " pad_left = diff // 2\r\n",
2546 | " pad_right = diff - pad_left\r\n",
2547 | " # Add zero pad to tensor\r\n",
2548 | " # https://pytorch.org/docs/stable/nn.functional.html#pad\r\n",
2549 | " return torch.nn.functional.pad(waveform,[pad_left, pad_right])\r\n",
2550 | " else:\r\n",
2551 | " # If size equal to desired size, do nothing\r\n",
2552 | " return waveform\r\n",
2553 | "\r\n",
2554 | "# Create custom dataset with transformations support \r\n",
2555 | "# it's common practice in pytorch\r\n",
2556 | "\r\n",
2557 | "class customSpeechCommandsDataset(torchaudio.datasets.SPEECHCOMMANDS):\r\n",
2558 | " def __init__(self,transform,root = \"sample_data\"):\r\n",
2559 | " self.transform = transform\r\n",
2560 | " super().__init__(root)\r\n",
2561 | "\r\n",
2562 | " # Override \r\n",
2563 | " def __getitem__(self,n):\r\n",
2564 | " # Get item\r\n",
2565 | " waveform, sample_rate, label, speaker_id, utterance_number = super().__getitem__(n)\r\n",
2566 | " # Apply transform\r\n",
2567 | " transformed_waveform = self.transform(waveform)\r\n",
2568 | " # Return ransformed item\r\n",
2569 | " return (transformed_waveform, sample_rate, label, speaker_id, utterance_number)\r\n",
2570 | "\r\n",
2571 | "\r\n",
2572 | "speech_commands_dataset = customSpeechCommandsDataset(transform = torch.nn.Sequential(PadWaveform(16000)))"
2573 | ],
2574 | "outputs": [],
2575 | "metadata": {}
2576 | },
2577 | {
2578 | "cell_type": "markdown",
2579 | "source": [
2580 | "Теперь можно добавлять дополнительные трансформации. Например, уменьшить частоту дискретизации (sample_rate) чтобы данные занимали меньше места.\n",
2581 | "\n",
2582 | "Для этого в модуле\n",
2583 | "[torchaudio.transforms](https://pytorch.org/audio/stable/transforms.html#resample) уже есть готовая трансформация:"
2584 | ],
2585 | "metadata": {}
2586 | },
2587 | {
2588 | "cell_type": "code",
2589 | "execution_count": null,
2590 | "source": [
2591 | "from torchaudio.transforms import Resample\r\n",
2592 | "\r\n",
2593 | "transform = torch.nn.Sequential(\r\n",
2594 | " Resample(16000,8000),\r\n",
2595 | " PadWaveform(8000))\r\n",
2596 | " \r\n",
2597 | "speech_commands_dataset = customSpeechCommandsDataset(transform)"
2598 | ],
2599 | "outputs": [],
2600 | "metadata": {}
2601 | },
2602 | {
2603 | "cell_type": "markdown",
2604 | "source": [
2605 | "#### 5.2.6 Пакетная обработка "
2606 | ],
2607 | "metadata": {}
2608 | },
2609 | {
2610 | "cell_type": "markdown",
2611 | "source": [
2612 | "**Визуализируем данные.**\n",
2613 | "\n",
2614 | "Датасет в архиве занимает > 2Gb и это далеко не предел. Поэтому работать с ним будем по частям. \n",
2615 | "\n",
2616 | "Для этой задачи в pytorch используется класс Dataloader. Одной из его функций является пакетная (batch) загрузка данных.\n",
2617 | "\n",
2618 | "Особенно она будет полезна при обучении:"
2619 | ],
2620 | "metadata": {}
2621 | },
2622 | {
2623 | "cell_type": "code",
2624 | "execution_count": null,
2625 | "source": [
2626 | "from torch.utils.tensorboard import SummaryWriter\r\n",
2627 | "import numpy\r\n",
2628 | "\r\n",
2629 | "# Clear logs and launch Tensorboard\r\n",
2630 | "reinit_tensorboard(False)\r\n",
2631 | "\r\n",
2632 | "data_loader = torch.utils.data.DataLoader(speech_commands_dataset, batch_size=128, shuffle=True)\r\n",
2633 | "\r\n",
2634 | "writer = SummaryWriter(comment = \"commands\")\r\n",
2635 | "\r\n",
2636 | "for i, batch in enumerate(data_loader):\r\n",
2637 | " waveforms, sample_rates, labels, speaker_ids, utterance_numbers = batch\r\n",
2638 | " print(waveforms.shape)\r\n",
2639 | " print(labels)\r\n",
2640 | " # Данные преобразовались в тензоры\r\n",
2641 | " # Убираем 1-е измерение оставшееся от канала\r\n",
2642 | " writer.add_embedding(torch.squeeze(waveforms), metadata=labels )\r\n",
2643 | " break\r\n",
2644 | "writer.close()"
2645 | ],
2646 | "outputs": [],
2647 | "metadata": {}
2648 | },
2649 | {
2650 | "cell_type": "markdown",
2651 | "source": [
2652 | "**Надо ли нормализовать эти данные?**\n",
2653 | "\n",
2654 | "Загрузим значения 2-х произвольных признаков в Tensorboard и проверим:"
2655 | ],
2656 | "metadata": {}
2657 | },
2658 | {
2659 | "cell_type": "code",
2660 | "execution_count": null,
2661 | "source": [
2662 | "writer = SummaryWriter(comment = \"commands\")\r\n",
2663 | "for i, batch in enumerate(data_loader):\r\n",
2664 | " waveforms, sample_rates, labels, speaker_ids, utterance_numbers = batch\r\n",
2665 | " writer.add_histogram(\"waves\" ,torch.squeeze(waveforms)[:,100])\r\n",
2666 | " writer.add_histogram(\"waves\" ,torch.squeeze(waveforms)[:,200])\r\n",
2667 | " break\r\n",
2668 | "writer.close()"
2669 | ],
2670 | "outputs": [],
2671 | "metadata": {}
2672 | },
2673 | {
2674 | "cell_type": "markdown",
2675 | "source": [
2676 | "Как видно из гистограммы, данные уже центрированны вокруг нуля и имеют один масшаб. Отчасти это связанно с тем, что они имеют одну и ту же природу, отчасти с форматом хранения звука. "
2677 | ],
2678 | "metadata": {}
2679 | },
2680 | {
2681 | "cell_type": "markdown",
2682 | "source": [
2683 | "#### 5.2.7 Обучение \n",
2684 | "\n",
2685 | "Для обучения потребуются метки. Попутно избавимся от лишнего. Создадим очередную трансформацию.\n"
2686 | ],
2687 | "metadata": {}
2688 | },
2689 | {
2690 | "cell_type": "code",
2691 | "execution_count": null,
2692 | "source": [
2693 | "class customSpeechCommandsDatasetFinal(customSpeechCommandsDataset):\r\n",
2694 | " def __init__(self,transform = torch.nn.Sequential(),root = \"sample_data\"):\r\n",
2695 | " super().__init__(transform,root)\r\n",
2696 | " self.labels = self.get_labels()\r\n",
2697 | "\r\n",
2698 | " def get_labels(self):\r\n",
2699 | " # Collect all unique labels\r\n",
2700 | " labels = set()\r\n",
2701 | " for i in range(len(self)):\r\n",
2702 | " item = super(customSpeechCommandsDataset,self).__getitem__(i)\r\n",
2703 | " labels.add(item[2])\r\n",
2704 | " # Sort labels and return it as a list\r\n",
2705 | " return sorted(list(labels)) \r\n",
2706 | "\r\n",
2707 | " # Override \r\n",
2708 | " def __getitem__(self,n):\r\n",
2709 | " waveform, sample_rate, label, speaker_id, utterance_number = super().__getitem__(n)\r\n",
2710 | " # Return only waveform and class_num\r\n",
2711 | " return (waveform[0],self.labels.index(label))\r\n",
2712 | "\r\n",
2713 | "transform = torch.nn.Sequential(\r\n",
2714 | " Resample(16000,8000),\r\n",
2715 | " PadWaveform(8000))\r\n",
2716 | "\r\n",
2717 | "speech_commands_dataset = customSpeechCommandsDatasetFinal(transform)"
2718 | ],
2719 | "outputs": [],
2720 | "metadata": {}
2721 | },
2722 | {
2723 | "cell_type": "code",
2724 | "execution_count": null,
2725 | "source": [
2726 | "print(\"Classes\",speech_commands_dataset.labels)\r\n",
2727 | "print(\"Classes num\",len(speech_commands_dataset.labels))\r\n",
2728 | "\r\n",
2729 | "wave, cls_num = speech_commands_dataset[0]\r\n",
2730 | "print(wave.shape)\r\n"
2731 | ],
2732 | "outputs": [],
2733 | "metadata": {}
2734 | },
2735 | {
2736 | "cell_type": "markdown",
2737 | "source": [
2738 | "Разделим данные на обучающую и валидационную выборки:"
2739 | ],
2740 | "metadata": {}
2741 | },
2742 | {
2743 | "cell_type": "code",
2744 | "execution_count": null,
2745 | "source": [
2746 | "total_len = len(speech_commands_dataset )\r\n",
2747 | "print(\"Total length\",total_len)\r\n",
2748 | "\r\n",
2749 | "# To speedup use only 10% of data\r\n",
2750 | "use_only = int(total_len*0.1)\r\n",
2751 | "to_skip,to_use = torch.utils.data.random_split(speech_commands_dataset, [total_len - use_only, use_only])\r\n",
2752 | "\r\n",
2753 | "# Split to train and validation set\r\n",
2754 | "val_len = int(len(to_use)*0.1)\r\n",
2755 | "train_set, val_set = torch.utils.data.random_split(to_use, [len(to_use) - val_len, val_len])\r\n",
2756 | "print(\"Train dataset length\",len(train_set))\r\n",
2757 | "print(\"Validation dataset length\",len(val_set))"
2758 | ],
2759 | "outputs": [],
2760 | "metadata": {}
2761 | },
2762 | {
2763 | "cell_type": "code",
2764 | "execution_count": null,
2765 | "source": [
2766 | "import numpy\r\n",
2767 | "from sklearn import metrics\r\n",
2768 | "# Another simple black-box model\r\n",
2769 | "from sklearn.linear_model import SGDClassifier\r\n",
2770 | "\r\n",
2771 | "reinit_tensorboard(False)\r\n",
2772 | "\r\n",
2773 | "def validate(model):\r\n",
2774 | " data_loader = torch.utils.data.DataLoader(val_set, batch_size=256, shuffle=False)\r\n",
2775 | " accuracy = []\r\n",
2776 | " for batch in data_loader:\r\n",
2777 | " waveforms, class_nums = batch \r\n",
2778 | " y_pred = model.predict(waveforms)\r\n",
2779 | " accuracy.append(metrics.accuracy_score(class_nums, y_pred))\r\n",
2780 | " print(\"Accuracy:\",numpy.array(accuracy).mean())\r\n",
2781 | " return numpy.array(accuracy).mean()\r\n",
2782 | "\r\n",
2783 | "model = SGDClassifier(loss='log') \r\n",
2784 | "\r\n",
2785 | "data_loader = torch.utils.data.DataLoader(train_set, batch_size=1024, shuffle=True)\r\n",
2786 | "\r\n",
2787 | "for epoch in range(5):\r\n",
2788 | " for batch in data_loader:\r\n",
2789 | " waveforms, class_nums = batch\r\n",
2790 | " model.partial_fit(waveforms, class_nums,range(35))\r\n",
2791 | " accuracy = validate(model)\r\n",
2792 | " writer.add_scalar(\"Accuracy\",accuracy,epoch)\r\n",
2793 | " writer.flush()"
2794 | ],
2795 | "outputs": [],
2796 | "metadata": {}
2797 | },
2798 | {
2799 | "cell_type": "markdown",
2800 | "source": [
2801 | "\n",
2802 | "Откройте вкладку \"SCALARS\".\n",
2803 | "\n",
2804 | "\n",
2805 | "Модель не обучается. Почему?\n",
2806 | "\n"
2807 | ],
2808 | "metadata": {}
2809 | },
2810 | {
2811 | "cell_type": "markdown",
2812 | "source": [
2813 | "### 5.2.8 Обзор видов связности данных "
2814 | ],
2815 | "metadata": {}
2816 | },
2817 | {
2818 | "cell_type": "markdown",
2819 | "source": [
2820 | "Причины этого в количестве связей между элементами данных.\n",
2821 | "Мы имеем дело с временным рядом. \n",
2822 | "\n",
2823 | "Аудиозапись — это набор измерений (давления на мембране микрофона), произведённых последовательно. \n",
2824 | "\n",
2825 | "То есть в каждый момент времени сигнал связан с предыдущим. \n",
2826 | "Если мы перемешаем их, получится какофония. \n",
2827 | "\n",
2828 | "Так же, как если перемешать слова в предложении или буквы в слове."
2829 | ],
2830 | "metadata": {}
2831 | },
2832 | {
2833 | "cell_type": "markdown",
2834 | "source": [
2835 | "
"
2836 | ],
2837 | "metadata": {}
2838 | },
2839 | {
2840 | "cell_type": "markdown",
2841 | "source": [
2842 | "В таких случаях мы тоже можем представить данные как вектор, но модель, которой мы подадим его на вход, должна учитывать связи между соседними элементами этого вектора.\n",
2843 | "\n",
2844 | "При работе с видео добавляется дополнительное «измерение» — время. \n",
2845 | "\n",
2846 | "Поскольку данные подаются в модель в виде многомерного массива чисел (тензора), то при работе с видео меняется только размерность этого массива: в нём появляется дополнительное измерение.\n",
2847 | "\n",
2848 | "С точки зрения PyTorch данные — это некоторый массив, у него может быть 1-2-3 измерения, но нам важно понимать, какие между ними существуют связи. От этого зависит, какой моделью мы будем их обрабатывать.\n",
2849 | "\n",
2850 | "Для работы с этими данными нужна модель, которая эти связи будет учитывать, например рекуррентная или свёрточная сеть.\n",
2851 | "С её помощью можно получить точность >85%:\n",
2852 | "\n",
2853 | "[Speech Command Recognition with torchaudio](https://colab.research.google.com/github/pytorch/tutorials/blob/gh-pages/_downloads/d87597d0062580c9ec699193e951e3f4/speech_command_recognition_with_torchaudio.ipynb#scrollTo=tl9K6deU4S10)"
2854 | ],
2855 | "metadata": {}
2856 | },
2857 | {
2858 | "cell_type": "markdown",
2859 | "source": [
2860 | "### 5.3 Работа с изображениями "
2861 | ],
2862 | "metadata": {}
2863 | },
2864 | {
2865 | "cell_type": "markdown",
2866 | "source": [
2867 | "#### 5.3.1 Загрузка "
2868 | ],
2869 | "metadata": {}
2870 | },
2871 | {
2872 | "cell_type": "markdown",
2873 | "source": [
2874 | "Загрузим датасет CIFAR-10. Он состоит из 60000 цветных изображений размером 32x32. На картинках объекты 10 классов.\n",
2875 | "\n",
2876 | "Для его загрузки используем билиотеку torchvision.\n",
2877 | "\n",
2878 | "В отличие от torchaudio, пакет torchvision входит в число предустановленных в colab.\n",
2879 | "\n",
2880 | "Датасеты из torcvision изначально поддерживают механизм transforms \n",
2881 | "и разбивку на тестовое и проверочные подмножества. Нам не придется добавлять их вручную.\n"
2882 | ],
2883 | "metadata": {}
2884 | },
2885 | {
2886 | "cell_type": "code",
2887 | "execution_count": null,
2888 | "source": [
2889 | "from torchvision import models, datasets, transforms\r\n",
2890 | "\r\n",
2891 | "trainset = datasets.CIFAR10(\"content\", train=True, download=True)\r\n",
2892 | "valset = datasets.CIFAR10(\"content\", train = False, download=True)"
2893 | ],
2894 | "outputs": [],
2895 | "metadata": {}
2896 | },
2897 | {
2898 | "cell_type": "markdown",
2899 | "source": [
2900 | "Выведем несколько картинок вместе с метками. Tensorboard имеет метод для вывода картинок:\n",
2901 | "[torchvision.utils.make_grid](https://pytorch.org/docs/stable/torchvision/utils.html)\n",
2902 | "\n",
2903 | "Однако он не поддерживает метки.\n",
2904 | "\n",
2905 | "https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjcxcStpNDtAhWllYsKHa7XDLoQFjAAegQIBBAC&url=https%3A%2F%2Fdiscuss.pytorch.org%2Ft%2Fadd-label-captions-to-make-grid%2F42863&usg=AOvVaw19bkv0_Q8VQxD7WBZ3pFR_\n",
2906 | "\n",
2907 | "Поэтому воспользуемся matplotlib:"
2908 | ],
2909 | "metadata": {}
2910 | },
2911 | {
2912 | "cell_type": "code",
2913 | "execution_count": null,
2914 | "source": [
2915 | "import matplotlib.pyplot as plt\r\n",
2916 | "import numpy as np\r\n",
2917 | "import pickle\r\n",
2918 | "plt.rcParams[\"figure.figsize\"] = (20,10)\r\n",
2919 | "\r\n",
2920 | "# Загрузим названия классов. Исключительно для наглядности, для обучения модели они не нужны.\r\n",
2921 | "with open(\"content/cifar-10-batches-py/batches.meta\",'rb') as infile:\r\n",
2922 | " cifar_meta = pickle.load(infile)\r\n",
2923 | "labels = cifar_meta['label_names']\r\n",
2924 | "\r\n",
2925 | "for j in range(10):\r\n",
2926 | " image, class_num = trainset[j]\r\n",
2927 | " plt.subplot(1, 10 ,j+1)\r\n",
2928 | " plt.imshow(image)\r\n",
2929 | " plt.axis('off') \r\n",
2930 | " plt.title(labels[class_num])"
2931 | ],
2932 | "outputs": [],
2933 | "metadata": {}
2934 | },
2935 | {
2936 | "cell_type": "markdown",
2937 | "source": [
2938 | "Посмотрим, в каком виде хранятся картинки в памяти:"
2939 | ],
2940 | "metadata": {}
2941 | },
2942 | {
2943 | "cell_type": "code",
2944 | "execution_count": null,
2945 | "source": [
2946 | "trainset[0]"
2947 | ],
2948 | "outputs": [],
2949 | "metadata": {}
2950 | },
2951 | {
2952 | "cell_type": "markdown",
2953 | "source": [
2954 | "Оказывается, в формате [PIL](https://pillow.readthedocs.io/en/stable/reference/Image.html).\n",
2955 | "\n",
2956 | "Чтобы обучать модель, нам придётся преобразовать их в тензоры. \n",
2957 | "Используем для этого transforms и Dataloder.\n",
2958 | "\n",
2959 | "Выведем размеры получившихся тензоров:"
2960 | ],
2961 | "metadata": {}
2962 | },
2963 | {
2964 | "cell_type": "code",
2965 | "execution_count": null,
2966 | "source": [
2967 | "from torch.utils.data import DataLoader\n",
2968 | "valset.transform = transforms.Compose([ transforms.ToTensor() ]) # PIL Image to Pytorch tensor\n",
2969 | "val_dataloder = DataLoader(valset, batch_size=8, shuffle=False)\n",
2970 | "\n",
2971 | "for batch in val_dataloder:\n",
2972 | " images, class_nums = batch\n",
2973 | " print(len(batch))\n",
2974 | " print(\"Images: \",images.shape)\n",
2975 | " print(\"Class nums: \",class_nums.shape)\n",
2976 | " print(class_nums)\n",
2977 | " break"
2978 | ],
2979 | "outputs": [],
2980 | "metadata": {}
2981 | },
2982 | {
2983 | "cell_type": "markdown",
2984 | "source": [
2985 | "**Разберемся с размерностями:**"
2986 | ],
2987 | "metadata": {}
2988 | },
2989 | {
2990 | "cell_type": "markdown",
2991 | "source": [
2992 | "На каждой итерации dataloader возвращает кортеж из двух элементов.\n",
2993 | "* Первый элемент — это изображения;\n",
2994 | "* Второй — метки классов."
2995 | ],
2996 | "metadata": {}
2997 | },
2998 | {
2999 | "cell_type": "markdown",
3000 | "source": [
3001 | "Количество элементов в каждом равно batch_size, в данном примере — 8.\n",
3002 | "\n",
3003 | "Изображение: \n",
3004 | "3 - C, каналы (В отличие от PIL и OpenCV они идут сначала); \n",
3005 | "32 - H, высота; \n",
3006 | "32 - W, ширина. "
3007 | ],
3008 | "metadata": {}
3009 | },
3010 | {
3011 | "cell_type": "markdown",
3012 | "source": [
3013 | "Метки: \n",
3014 | "числа от 0 до 9 по количеству классов."
3015 | ],
3016 | "metadata": {}
3017 | },
3018 | {
3019 | "cell_type": "markdown",
3020 | "source": [
3021 | "#### 5.3.2 Создадим модель-заглушку \n",
3022 | "\n",
3023 | "Она не будет ничего предсказывать, только возвращать случайный номер класса.\n",
3024 | "\n",
3025 | "В методе fit данные просто запоминаются. Этот фрагмент кода можно будет использовать при выполнении практического задания.\n"
3026 | ],
3027 | "metadata": {}
3028 | },
3029 | {
3030 | "cell_type": "code",
3031 | "execution_count": null,
3032 | "source": [
3033 | "import torch\n",
3034 | "\n",
3035 | "class FakeModel(torch.nn.Module):\n",
3036 | " def __init__(self):\n",
3037 | " super().__init__()\n",
3038 | " self.train_data = None\n",
3039 | " self.train_labels = None\n",
3040 | "\n",
3041 | " def fit(self,x,y):\n",
3042 | " # Simple store all data\n",
3043 | " self.train_data = torch.vstack((self.train_data,x)) if self.train_data != None else x\n",
3044 | " self.train_labels = torch.hstack((self.train_labels,y)) if self.train_labels != None else y\n",
3045 | " \n",
3046 | " def forward(self,x):\n",
3047 | " # x is a batch, not a single sample!\n",
3048 | " # Return random number instead of predictions\n",
3049 | " class_count = torch.unique(self.train_labels).shape[0]\n",
3050 | " # https://pytorch.org/docs/stable/generated/torch.randint.html#torch-randint\n",
3051 | " # size is shape of output tensor\n",
3052 | " class_num = torch.randint(low = 0, high = class_count-1, size = (x.shape[0],)) \n",
3053 | " return class_num"
3054 | ],
3055 | "outputs": [],
3056 | "metadata": {}
3057 | },
3058 | {
3059 | "cell_type": "markdown",
3060 | "source": [
3061 | "#### 5.3.3 Запустим процесс обучения "
3062 | ],
3063 | "metadata": {}
3064 | },
3065 | {
3066 | "cell_type": "code",
3067 | "execution_count": null,
3068 | "source": [
3069 | "trainset.transform = transforms.Compose([ transforms.ToTensor(), ]) # PIL Image to Pytorch tensor\n",
3070 | "train_dataloder = DataLoader(trainset, batch_size=1024, shuffle=True)\n",
3071 | "\n",
3072 | "model = FakeModel()\n",
3073 | "\n",
3074 | "for img_batch, labels_batch in train_dataloder:\n",
3075 | " model.fit(img_batch, labels_batch)"
3076 | ],
3077 | "outputs": [],
3078 | "metadata": {}
3079 | },
3080 | {
3081 | "cell_type": "markdown",
3082 | "source": [
3083 | "Проверим работу модели на нескольких изображениях из тестового набора данных:"
3084 | ],
3085 | "metadata": {}
3086 | },
3087 | {
3088 | "cell_type": "code",
3089 | "execution_count": null,
3090 | "source": [
3091 | "img_batch, class_num_batch = next(iter(val_dataloder))\n",
3092 | "predicted_cls_nums = model(img_batch)\n",
3093 | "\n",
3094 | "for i, predicted_cls_num in enumerate(predicted_cls_nums):\n",
3095 | " img = img_batch[i].permute(1,2,0).numpy()*255 \n",
3096 | " plt.subplot(1, len(predicted_cls_nums),i+1)\n",
3097 | " plt.imshow(img.astype(int))\n",
3098 | " plt.axis('off')\n",
3099 | " plt.title(labels[int(predicted_cls_num)])"
3100 | ],
3101 | "outputs": [],
3102 | "metadata": {}
3103 | },
3104 | {
3105 | "cell_type": "markdown",
3106 | "source": [
3107 | "Посчитаем точность:"
3108 | ],
3109 | "metadata": {}
3110 | },
3111 | {
3112 | "cell_type": "code",
3113 | "execution_count": null,
3114 | "source": [
3115 | "from sklearn.metrics import accuracy_score\n",
3116 | "accuracy = []\n",
3117 | "for img_batch, labels_batch in val_dataloder:\n",
3118 | " predicted = model(img_batch)\n",
3119 | " batch_accuracy = accuracy_score(labels_batch, predicted)\n",
3120 | " accuracy.append(batch_accuracy)\n",
3121 | "\n",
3122 | "print(\"Accuracy\",torch.tensor(accuracy).mean())"
3123 | ],
3124 | "outputs": [],
3125 | "metadata": {}
3126 | },
3127 | {
3128 | "cell_type": "markdown",
3129 | "source": [
3130 | "Будем повышать точность. В ходе выполнения практического задания заменим заглушку в методе predict реальным алгоритмом. Используем алгоритм:\n",
3131 | "\n",
3132 | "[K- Nearest Neighbor](https://colab.research.google.com/drive/1_5tGxAoxrWulPmwK2Ht9BHGsS-EpxVo0?usp=sharing)\n",
3133 | "\n"
3134 | ],
3135 | "metadata": {}
3136 | },
3137 | {
3138 | "cell_type": "markdown",
3139 | "source": [
3140 | "#### 5.3.4. Алгоритм k-nearest neighbors "
3141 | ],
3142 | "metadata": {}
3143 | },
3144 | {
3145 | "cell_type": "markdown",
3146 | "source": [
3147 | "Будем решать задачу классификации на примере CIFAR 10.\n",
3148 | "В ходе нескольких первых лекций мы будем решать её неоднократно, используя различные модели и постепенно улучшая результат.\n",
3149 | "\n",
3150 | "Цель сегодняшней работы — разобраться с загрузкой данных и общим ходом обучения модели."
3151 | ],
3152 | "metadata": {}
3153 | },
3154 | {
3155 | "cell_type": "markdown",
3156 | "source": [
3157 | "
"
3158 | ],
3159 | "metadata": {}
3160 | },
3161 | {
3162 | "cell_type": "markdown",
3163 | "source": [
3164 | "Первое, что мы должны сделать — это представить данные в виде чисел.\n",
3165 | "Но изображения уже хранится в памяти компьютера в виде массива пикселей. \n",
3166 | "\n",
3167 | "При этом соседние пиксели на изображении связаны между собой. Для анализа этих связей требуется относительно сложная логика, \n",
3168 | "попробуем сегодня проигнорировать эти связи и рассматривать изображение просто как массив чисел."
3169 | ],
3170 | "metadata": {}
3171 | },
3172 | {
3173 | "cell_type": "markdown",
3174 | "source": [
3175 | "
"
3176 | ],
3177 | "metadata": {}
3178 | },
3179 | {
3180 | "cell_type": "markdown",
3181 | "source": [
3182 | "**Метод ближайшего соседа** \n",
3183 | "Для классификации используем [Метод ближайшего соседа](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm), или k-ближайших соседей (в части 3, 4).\n",
3184 | "\n",
3185 | "Метод k-ближайших соседей (англ. k-nearest neighbors algorithm, k-NN) — метрический алгоритм для автоматической классификации объектов или регрессии.\n",
3186 | "\n",
3187 | "В случае использования метода для классификации объект присваивается тому классу, который является наиболее распространённым среди k соседей данного элемента, классы которых уже известны.\n",
3188 | "\n",
3189 | "Алгоритм может быть применим к выборкам с большим количеством атрибутов (многомерным). Для этого перед применением нужно определить функцию расстояния; классический вариант такой функции — евклидова метрика. \n"
3190 | ],
3191 | "metadata": {}
3192 | },
3193 | {
3194 | "cell_type": "markdown",
3195 | "source": [
3196 | "
"
3197 | ],
3198 | "metadata": {}
3199 | },
3200 | {
3201 | "cell_type": "markdown",
3202 | "source": [
3203 | "Остается вопрос: как определить метрику близости для изображений?\n",
3204 | "\n",
3205 | "Раз изображения в памяти компьютера — это просто массив чисел, давайте поэлементно вычтем одно из другого. \n",
3206 | "А затем оценим суммарную разницу. Для одинаковых изображений она будет нулевой."
3207 | ],
3208 | "metadata": {}
3209 | },
3210 | {
3211 | "cell_type": "markdown",
3212 | "source": [
3213 | "
"
3214 | ],
3215 | "metadata": {}
3216 | },
3217 | {
3218 | "cell_type": "markdown",
3219 | "source": [
3220 | "Однако может возникнуть ситуация, когда разность для одной пары пикселей -100, а для другой — +100. Когда мы их сложим, получится ноль, хотя изображения очень разные.\n",
3221 | "Чтобы избавиться от такого нежелательного эффекта, будем использовать модули разностей.\n",
3222 | "И таким образом получим метрику расстояния L1. Она же — манхэттенское расстояние, метрика прямоугольного города, метрика городского квартала, метрика такси, метрика Манхэттена, прямоугольная метрика, метрика прямого угла.\n",
3223 | "Если вместо модуля использовать возведение в квадрат, а затем из суммы извлекать корень — получим Евклидову метрику.\n",
3224 | "\n",
3225 | "Теперь алгоритм будет выглядеть так: \n",
3226 | "\n",
3227 | "1. На этапе обучения запоминаем все изображения тренировочной выборки; \n",
3228 | "2. Для определения класса нового изображения: \n",
3229 | "\n",
3230 | "a. Считаем расстояние L1 от него до всех заученных изображений;\n",
3231 | "\n",
3232 | "b. Находим минимальное;\n",
3233 | "\n",
3234 | "c. Возвращаем метку класса для этого изображения, расстояние до которого оказалось минимальным.\n"
3235 | ],
3236 | "metadata": {}
3237 | },
3238 | {
3239 | "cell_type": "markdown",
3240 | "source": [
3241 | "
"
3242 | ],
3243 | "metadata": {}
3244 | }
3245 | ],
3246 | "nbformat": 4,
3247 | "nbformat_minor": 2,
3248 | "metadata": {}
3249 | }
3250 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | sklearn
2 | pandas
3 | torch
4 | torchvision
5 | torchaudio
6 | tensorboard
7 | matplotlib
8 | nbformat
9 |
10 | # Windows only
11 | # PySoundFile
12 |
13 | # Linux only
14 | # sox
--------------------------------------------------------------------------------