diff --git a/README.md b/README.md index 47ca718ef47920a687b5f29f84d7e5723bde4a90..fd4cd4720314d7009ebf82d2bb5cfead1e8e9c5e 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,26 @@ conda env create -f environment-cpu.yml conda env create -f environment-gpu.yml ``` +If way above does not work for you (e.g. you are on Windows), try the following for CPU: +```bash +conda create --name mpv-assignments-cpu-only python=3.6 +conda activate mpv-assignments-cpu-only +conda install pytorch torchvision cpuonly -c pytorch +pip install kornia tqdm notebook matplotlib opencv-contrib-python seaborn tensorboard tensorboardX +conda install -c conda-forge widgetsnbextension +conda install -c conda-forge ipywidgets +``` + +And following for GPU: + +```bash +conda create --name mpv-assignments-gpu python=3.6 +conda activate mpv-assignments-gpu +conda install pytorch torchvision cudatoolkit=10.1 -c pytorch +pip install kornia tqdm notebook matplotlib opencv-contrib-python seaborn tensorboard tensorboardX +conda install -c conda-forge widgetsnbextension +conda install -c conda-forge ipywidgets +``` **Keep in mind that the assignments and the assignment templates will be updated during the semester. Always pull the current template version before starting to work on an assignment!** diff --git a/assignment_6_7_cnn_template/cnn_training.py b/assignment_6_7_cnn_template/cnn_training.py index a7bb899be36e640837739aeec238e5169e2fefcc..8f272ecc73d5a79a418ed183562a97173eb64dd1 100644 --- a/assignment_6_7_cnn_template/cnn_training.py +++ b/assignment_6_7_cnn_template/cnn_training.py @@ -7,18 +7,22 @@ import typing from typing import Tuple, List from PIL import Image import os -from tqdm import tqdm +from tqdm import tqdm_notebook as tqdm from time import time def get_dataset_statistics(dataset: torch.utils.data.Dataset) -> Tuple[List, List]: - '''Function, that calculates mean and std of a dataset (pixelwise)''' + '''Function, that calculates mean and std of a dataset (pixelwise) + Return: + tuple of Lists of floats. len of each list should equal to number of input image/tensor channels + ''' mean = [0., 0., 0.] std = [1.0, 1.0, 1.0] - return mean, std + return mean, std class SimpleCNN(nn.Module): + """Class, which implements image classifier. """ def __init__(self, num_classes = 10): super(SimpleCNN, self).__init__() self.features = nn.Sequential( @@ -49,43 +53,68 @@ class SimpleCNN(nn.Module): nn.Flatten(), nn.Linear(512, num_classes)) return - def forward(self, input): + """ + Shape: + - Input :math:`(B, C, H, W)` + - Output: :math:`(B, NC)`, where NC is num_classes + """ x = self.features(input) return self.clf(x) -def weight_init(m: nn.Module): +def weight_init(m: nn.Module) -> None: '''Function, which fills-in weights and biases for convolutional and linear layers''' if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear): - pass #do something + #do something here. You can access layer weight or bias by m.weight or m.bias + pass #do something return -def train_single_epoch(model: torch.nn.Module, +def train_and_val_single_epoch(model: torch.nn.Module, train_loader: torch.utils.data.DataLoader, + val_loader: torch.utils.data.DataLoader, optim: torch.optim.Optimizer, - loss_fn: torch.nn.Module) -> torch.nn.Module: - '''Function, which runs training over a single epoch in the dataloader and returns the model''' + loss_fn: torch.nn.Module, + epoch_idx = 0, + lr_scheduler = None, + writer = None) -> torch.nn.Module: + '''Function, which runs training over a single epoch in the dataloader and returns the model. Do not forget to set the model into train mode and zero_grad() optimizer before backward.''' + if epoch_idx == 0: + val_acc, val_loss = validate(model, val_loader, loss_fn) + if writer is not None: + writer.add_scalar("Accuracy/val", val_acc, 0) + writer.add_scalar("Loss/val", val_loss, 0) model.train() + for idx, (data, labels) in tqdm(enumerate(train_loader), total=num_batches): + pass #do something return model -def lr_find(model, train_dl, loss_fn, min_lr=1e-7, max_lr=100, steps = 50): - '''Function, which runs the mock training over with different learning rates''' +def lr_find(model: torch.nn.Module, + train_dl:torch.utils.data.DataLoader, + loss_fn:torch.nn.Module, + min_lr: float=1e-7, max_lr:float=100, steps:int = 50)-> Tuple: + '''Function, which run the training for a small number of iterations, increasing the learning rate and storing the losses. Model initialization is saved before training and restored after training''' lrs = np.ones(steps) losses = np.ones(steps) return losses, lrs -def validate(model: torch.nn.Module, val_loader: torch.utils.data.DataLoader) -> float: +def validate(model: torch.nn.Module, + val_loader: torch.utils.data.DataLoader, + loss_fn: torch.nn.Module) -> float: '''Function, which runs the module over validation set and returns accuracy''' print ("Starting validation") acc = 0 - return acc + loss = 0 + for idx, (data, labels) in tqdm(enumerate(val_loader), total=len(val_loader)): + with torch.no_grad(): + pass #do something + return acc, loss class TestFolderDataset(torch.utils.data.Dataset): - '''''' + '''Class, which reads images in folder and serves as test dataset''' def __init__(self, folder_name, transform = None): return def __getitem__(self, index): @@ -96,7 +125,7 @@ class TestFolderDataset(torch.utils.data.Dataset): return ln -def get_predictions(model, test_dl): - '''Outputs prediction over test data loader''' +def get_predictions(model: torch.nn.Module, test_dl: torch.utils.data.DataLoader)->torch.Tensor : + '''Function, which predicts class indexes for image in data loader. Ouput shape: [N, 1], where N is number of image in the dataset''' out = torch.zeros(len(test_dl)).long() return out diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN.ipynb b/assignment_6_7_cnn_template/training-imagenette-CNN.ipynb index 4995eadd8e0e0813f0ade18476d583394d4a3e81..766e6931de9b57c77574fbfa91c64f4b33ccf956 100644 --- a/assignment_6_7_cnn_template/training-imagenette-CNN.ipynb +++ b/assignment_6_7_cnn_template/training-imagenette-CNN.ipynb @@ -44,6 +44,9 @@ "\n", "In this lab we will train convolution neural network for image classification from scratch. It is typically done on GPUs, often multiple ones, as the process is very computationally intensive. \n", "The current assignment, on other hand, is created to be run on a CPU: single training epoch takes 1-5 minutes, depending on CNN architecture and hardware. \n", + "\n", + "Specifically, it takes 90 sec for training epoch on mobile i7 CPU and 26 sec on mobile GT940M GPU.\n", + "\n", "You will implement a CNN, training and validation loop, custom dataset loader and couple of helper functions." ] }, @@ -60,27 +63,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--2020-04-15 19:05:06-- https://s3.amazonaws.com/fast-ai-imageclas/imagenette2-160.tgz\n", - "Resolving s3.amazonaws.com (s3.amazonaws.com)... 52.216.138.189\n", - "Connecting to s3.amazonaws.com (s3.amazonaws.com)|52.216.138.189|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 98948031 (94M) [application/x-tar]\n", - "Saving to: â€imagenette2-160.tgz’\n", - "\n", - "imagenette2-160.tgz 100%[===================>] 94.36M 10.0MB/s in 11s \n", - "\n", - "2020-04-15 19:05:18 (8.92 MB/s) - â€imagenette2-160.tgz’ saved [98948031/98948031]\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "!wget https://s3.amazonaws.com/fast-ai-imageclas/imagenette2-160.tgz\n", "!tar -xzf imagenette2-160.tgz" @@ -117,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -172,23 +157,23 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[0.0, 0.0, 0.0] [1.0, 1.0, 1.0]\n" + "[0.46248055, 0.4579692, 0.42981696] [0.14145005, 0.1439656, 0.1707164]\n" ] } ], "source": [ "from cnn_training import get_dataset_statistics\n", "\n", - "mean, std = get_dataset_statistics(ImageNette_for_statistics)\n", - "print (mean, std)\n", - "#zeros and ones are stub, not the reference solution" + "#mean, std = get_dataset_statistics(ImageNette_for_statistics)\n", + "mean, std = [0.46248055, 0.4579692, 0.42981696], [0.14145005, 0.1439656, 0.1707164]\n", + "print (mean, std)" ] }, { @@ -233,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -263,7 +248,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -292,7 +277,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -312,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -365,7 +350,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -427,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -440,7 +425,7 @@ ")" ] }, - "execution_count": 18, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -456,7 +441,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now let's write a training loop function `train_single_epoch`. It should set the model to train mode by model.train(), \n", + "Now let's write a training loop function `train_and_val_single_epoch`. It should set the model to train mode by model.train(), \n", "create an optimizer, go through samples in training loader, calculate the loss function and apply the gradients.\n", "\n", "https://pytorch.org/docs/stable/optim.html\n", @@ -470,9 +455,10 @@ " loss = loss_fn(output, target)\n", " loss.backward()\n", " optimizer.step()\n", + "validate(model, val_loader, loss_fn)\n", "```\n", "\n", - "As optimizer is it good idea to take Adam or SGD. Loss function for classification: CrossEntropyLoss" + "As optimizer is it good idea to take AdamW or SGD. Loss function for classification: CrossEntropyLoss" ] }, { @@ -484,17 +470,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "Help on function train_single_epoch in module cnn_training:\n", + "Help on function train_and_val_single_epoch in module cnn_training:\n", "\n", - "train_single_epoch(model: torch.nn.modules.module.Module, train_loader: torch.utils.data.dataloader.DataLoader, optim: torch.optim.optimizer.Optimizer, loss_fn: torch.nn.modules.module.Module) -> torch.nn.modules.module.Module\n", - " Function, which runs training over a single epoch in the dataloader and returns the model\n", + "train_and_val_single_epoch(model: torch.nn.modules.module.Module, train_loader: torch.utils.data.dataloader.DataLoader, val_loader: torch.utils.data.dataloader.DataLoader, optim: torch.optim.optimizer.Optimizer, loss_fn: torch.nn.modules.module.Module, epoch_idx=0, lr_scheduler=None, writer=None) -> torch.nn.modules.module.Module\n", + " Function, which runs training over a single epoch in the dataloader and returns the model. Do not forget to set the model into train mode and zero_grad() optimizer before backward.\n", "\n" ] } ], "source": [ - "from cnn_training import train_single_epoch\n", - "help (train_single_epoch)" + "from cnn_training import train_and_val_single_epoch\n", + "help (train_and_val_single_epoch)" ] }, { @@ -506,7 +492,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -515,7 +501,7 @@ "text": [ "Help on function validate in module cnn_training:\n", "\n", - "validate(model: torch.nn.modules.module.Module, val_loader: torch.utils.data.dataloader.DataLoader) -> float\n", + "validate(model: torch.nn.modules.module.Module, val_loader: torch.utils.data.dataloader.DataLoader, loss_fn: torch.nn.modules.module.Module) -> float\n", " Function, which runs the module over validation set and returns accuracy\n", "\n" ] @@ -543,16 +529,31 @@ "6. Restore model weights from save (1)\n", "7. Plot the loss and select value, which is 3..10x smaller than one, corresponding to the minimum of loss function, or 3..10 times smaller than one just before loss increase.\n", "\n", - "Implement this proceduce in `lr_find` function" + "Implement this proceduce in `lr_find` function. Make sure that you use the same optimizer for the lr_find, as will be training with." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "1fa2bad4eb6b450ab4b65fb9681c3398", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=50.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "from cnn_training import lr_find\n", "\n", @@ -569,27 +570,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now lets plot and pick the best value" + "Now let's plot learning rate and losses and pick the best value. You can just use plt.semilogx(lrs, losses), but somehow ticks \n", + "are gone in such loarge range, so we will use a solution from stackoverflow" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "(0, 10.0)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] @@ -601,54 +593,480 @@ } ], "source": [ - "plt.semilogx(lrs, losses)\n", - "plt.grid()\n", - "plt.ylim([0, 10.])" + "# https://stackoverflow.com/questions/44078409/matplotlib-semi-log-plot-minor-tick-marks-are-gone-when-range-is-large/44079725#44079725\n", + "def plot_lrs_losses(lrs, losses):\n", + " import matplotlib.ticker\n", + " fig, ax=plt.subplots()\n", + " ax.semilogx(lrs, losses)\n", + " ax.set_ylim([0, 10.])\n", + " ax.grid(True, which=\"both\")\n", + " locmaj = matplotlib.ticker.LogLocator(base=10,numticks=12) \n", + " ax.xaxis.set_major_locator(locmaj)\n", + " locmin = matplotlib.ticker.LogLocator(base=10.0,subs=(0.1,0.2,0.5, 0.8),numticks=12)\n", + " ax.xaxis.set_minor_locator(locmin)\n", + " ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())\n", + " ax.set_xlabel('Learning rate')\n", + " ax.set_ylabel('Loss')\n", + " plt.show()\n", + " return\n", + "plot_lrs_losses(lrs, losses)" ] }, { - "attachments": { - "image.png": { - "image/png": "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" - } - }, "cell_type": "markdown", "metadata": {}, "source": [ + "Here is the plot for AdamW optimizer with exampleCNN \n", "```python\n", - "plt.semilogx(lrs, losses)\n", - "plt.grid()\n", - "plt.ylim([0, 10.])\n", + "plot_lrs_losses(lrs, losses)\n", "```\n", - "\n", + "\n", + "\n", + "And for SGD\n", + "\n", + "\n", "\n", - "Good value would be 1e-3" + "Good value would be 1e-3 for AdamW and 3e-3 for SGD with momentum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use tensorboard for plotting training and validation statistics. \n", + "It works as following: writer writes logs in a specific format as training goes on. \n", + "In separate console window you run \n", + "```bash\n", + "tensorboard --logdir=runs --port=6006\n", + "```\n", + "And open in a separate browser window [localhost:6006](http://localhost:6006/)\n", + "\n", + "\n", + "To add a value to tensorboard, one needs to use function add_scalar.\n", + "For detailed reference see https://pytorch.org/docs/stable/tensorboard.html\n", + "\n", + "\n", + "```python\n", + " writer.add_scalar(\"Accuracy/val\", acc.item(), epoch_idx)\n", + "```" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ - "from cnn_training import train_single_epoch, validate\n", + "from torch.utils.tensorboard import SummaryWriter" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6a1e1574dfef45a6a5f2674f5478b66d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.0973, in 2.9 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "67745955e6c44d099d775faa82ead8cf", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5c91cb94c7b541b886913b5ecbadd288", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.4397, in 3.3 sec\n", + "Train epoch in 30.7 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "39fb5f98ca3545058c753c601c9dc8be", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "66a64a0b2f4a47cab9f33c6eac910961", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.6036, in 3.5 sec\n", + "Train epoch in 27.2 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a8cca15be0bb45a88b7c4ca0f1de950e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a42668943d94442886ebe1d013d73044", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.6754, in 3.2 sec\n", + "Train epoch in 26.7 sec\n" + ] + } + ], + "source": [ + "#from cnn_training import train_single_epoch, validate\n", + "from torch.utils.tensorboard import SummaryWriter\n", + "\n", + "model = SimpleCNN(10)\n", + "\n", + "\n", + "model.features.apply(weight_init)\n", + "model.clf.apply(weight_init)\n", "loss_fn = nn.CrossEntropyLoss()\n", + "writer = SummaryWriter(comment=\"AdamW_no_scheduler\") #Comment is a name for graph (see screenshot below)\n", + "\n", "opt = torch.optim.AdamW(model.parameters(),lr=1e-3, weight_decay=1e-4, eps=1e-2)\n", - "for ep in range(2):\n", + "#opt = torch.optim.SGD(model.parameters(),lr=3e-3, weight_decay=1e-4, momentum=0.9)\n", + "for ep in range(3):\n", " t=time()\n", - " model = train_single_epoch(model, train_dl, opt, loss_fn)\n", + " model = train_and_val_single_epoch(model, train_dl, val_dl, opt, loss_fn, ep, writer=writer)\n", " el = time() -t\n", - " print (f\"Train epoch in {el:.1f} sec\")\n", - " validate(model, val_dl)" + " print (f\"Train epoch in {el:.1f} sec\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Also a good idea would be to use learning rate schedule, e.g. one-cycle policy, step-policy, linear policy.\n", + "Screenshot from tensorboard for the SGD\n", + "\n", + "\n", + "Screenshot from tensorboard for the AdamW\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A good idea would be to use learning rate scheduler i.e. not keeping learning rate constant, but changing it when training goes. See the different learning rate schules example (from [Systematic Evaluation of Convolution Neural Network Advances on the ImageNet](https://arxiv.org/pdf/1606.02228) paper).\n", + "\n", + "\n", + "\n", + "Lets compare no-schedule (above) with one-cycle.\n", + "Good schedules to try will be one-cycle policy, step-policy, linear policy.\n", "See an example here:\n", - "https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate" + "https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4ce0b2de074e4c9f9c387917674f651f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.1162, in 2.7 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "62999361b10b4873b9047c926f0a5aab", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0ad34f34d1f446c3ab961afa02715a04", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.4843, in 4.1 sec\n", + "Train epoch in 30.2 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c50eaec47ac346b89b33ad528e71919d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5f6aba0a8e4f457da4d3fd5ad950da3a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.6346, in 3.2 sec\n", + "Train epoch in 26.8 sec\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9de919d0a59a4ffbb19875305e1e3db2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=296.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Starting validation\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "e9d448cbd4284019bd157d8ab831f233", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=123.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Validation accuracy = 0.6879, in 3.3 sec\n", + "Train epoch in 26.7 sec\n" + ] + } + ], + "source": [ + "from torch.optim.lr_scheduler import OneCycleLR\n", + "from cnn_training import *\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "#Re-init the model\n", + "model = SimpleCNN(10)\n", + "model.features.apply(weight_init)\n", + "model.clf.apply(weight_init)\n", + "\n", + "writer = SummaryWriter(comment=\"AdamW_OneCycleSched\") \n", + "opt1 = torch.optim.AdamW(model.parameters(),lr=1e-3, weight_decay=1e-4, eps=1e-2)\n", + "lr_sched = OneCycleLR(opt1, max_lr=3e-3, steps_per_epoch=len(train_dl), epochs=3)\n", + "\n", + "for ep in range(3):\n", + " t=time()\n", + " model = train_and_val_single_epoch(model, train_dl, val_dl, opt1, loss_fn, ep, lr_sched, writer=writer)\n", + " el = time() -t\n", + " print (f\"Train epoch in {el:.1f} sec\")\n", + " " ] }, { @@ -658,23 +1076,33 @@ "# Reference example\n", "\n", "```python\n", - "from cnn_training import train_single_epoch, validate\n", + "from torch.optim.lr_scheduler import OneCycleLR\n", + "from cnn_training import *\n", "loss_fn = nn.CrossEntropyLoss()\n", - "opt = torch.optim.AdamW(model.parameters(),lr=1e-3, weight_decay=1e-4, eps=1e-2)\n", - "for ep in range(2):\n", + "#Re-init the model\n", + "model = SimpleCNN(10)\n", + "model.features.apply(weight_init)\n", + "model.clf.apply(weight_init)\n", + "\n", + "writer = SummaryWriter(comment=\"AdamW_OneCycleSched\") \n", + "opt1 = torch.optim.AdamW(model.parameters(),lr=1e-3, weight_decay=1e-4, eps=1e-2)\n", + "lr_sched = OneCycleLR(opt1, max_lr=3e-3, steps_per_epoch=len(train_dl), epochs=3)\n", + "\n", + "for ep in range(3):\n", " t=time()\n", - " model = train_single_epoch(model, train_dl, opt, loss_fn)\n", + " model = train_and_val_single_epoch(model, train_dl, val_dl, opt1, loss_fn, ep, lr_sched, writer=writer)\n", " el = time() -t\n", " print (f\"Train epoch in {el:.1f} sec\")\n", - " validate(model, val_dl)\n", "```\n", "\n", - " Train epoch in 93.6 sec\n", - " Starting validation\n", - " Validation accuracy = 0.5745, in 11.6 sec\n", - " Train epoch in 94.6 sec\n", - " Starting validation\n", - " Validation accuracy = 0.6321, in 10.8 sec" + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Training for more epochs than 3 would lead to better results. " ] }, { @@ -687,7 +1115,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -700,10 +1128,10 @@ { "data": { "text/plain": [ - "<matplotlib.image.AxesImage at 0x7fe4f81d3790>" + "<matplotlib.image.AxesImage at 0x7f16be95c110>" ] }, - "execution_count": 24, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" }, @@ -744,7 +1172,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -753,7 +1181,8 @@ "text": [ "Help on function get_predictions in module cnn_training:\n", "\n", - "get_predictions(model, test_dl)\n", + "get_predictions(model: torch.nn.modules.module.Module, test_dl: torch.utils.data.dataloader.DataLoader) -> torch.Tensor\n", + " Function, which predicts class indexes for image in data loader. Ouput shape: [N, 1], where N is number of image in the dataset\n", "\n" ] } @@ -772,18 +1201,28 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 23, "metadata": {}, "outputs": [ { - "name": "stderr", + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "7bbf99ff340546a7be5a60316463dd05", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=4.0), HTML(value='')))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", "output_type": "stream", "text": [ - "\n", - "\n", - " 0%| | 0/4 [00:00<?, ?it/s]\u001b[A\u001b[A\n", - "\n", - "100%|â–â–â–â–â–â–â–â–â–â–| 4/4 [00:00<00:00, 11.66it/s]\u001b[A\u001b[A\n" + "\n" ] } ], @@ -805,11 +1244,6 @@ "Your task is to implement the functions above and get as good as possible accuracy on the test set. \n", "For local evaluation use validation set. Good luck!" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] } ], "metadata": { diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00000.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00000.png new file mode 100644 index 0000000000000000000000000000000000000000..b87ee678cd1eb250545fe7fc5b2a0366fe6c8d29 Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00000.png differ diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00001.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1b711c063f4f671dd65be1b22f4029293ebad98a Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00001.png differ diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00002.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00002.png new file mode 100644 index 0000000000000000000000000000000000000000..78e80df2f42a02bc282d47efeea194e44ac54349 Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00002.png differ diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00003.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00003.png new file mode 100644 index 0000000000000000000000000000000000000000..945ccd3d53394f008bb5a63b153295cf2b6549f9 Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00003.png differ diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00004.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00004.png new file mode 100644 index 0000000000000000000000000000000000000000..5f70c0f36588150630c6a7e5573ecbc326d47511 Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00004.png differ diff --git a/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00005.png b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00005.png new file mode 100644 index 0000000000000000000000000000000000000000..a61d9ee5f2370caeb01581a226378a78900b2224 Binary files /dev/null and b/assignment_6_7_cnn_template/training-imagenette-CNN_files/att_00005.png differ diff --git a/conda_env_yaml/environment-cpu.yml b/conda_env_yaml/environment-cpu.yml index 4eef3df500d40cffccd73bf087e0ee27c1a0f84e..7a46428a341117d317bd7fb69eeb89f162c82cd2 100644 --- a/conda_env_yaml/environment-cpu.yml +++ b/conda_env_yaml/environment-cpu.yml @@ -1,289 +1,126 @@ name: mpv-assignments-cpu-only channels: - pytorch + - conda-forge - defaults dependencies: - - _anaconda_depends=2019.03=py36_0 - - _libgcc_mutex=0.1=main - - alabaster=0.7.12=py36_0 - - anaconda=custom=py36_1 - - anaconda-client=1.7.2=py36_0 - - anaconda-project=0.8.4=py_0 - - asn1crypto=1.3.0=py36_0 - - astroid=2.3.3=py36_0 - - astropy=4.0=py36h7b6447c_0 - - atomicwrites=1.3.0=py36_1 - - attrs=19.3.0=py_0 - - babel=2.8.0=py_0 - - backcall=0.1.0=py36_0 - - backports=1.0=py_2 - - backports.os=0.1.1=py36_0 - - backports.shutil_get_terminal_size=1.0.0=py36_2 - - beautifulsoup4=4.8.2=py36_0 - - bitarray=1.2.1=py36h7b6447c_0 - - bkcharts=0.2=py36_0 - - blas=1.0=mkl - - bleach=3.1.0=py36_0 - - blosc=1.16.3=hd408876_0 - - bokeh=1.4.0=py36_0 - - boto=2.49.0=py36_0 - - bottleneck=1.3.1=py36hdd07704_0 - - bzip2=1.0.8=h7b6447c_0 - - ca-certificates=2020.1.1=0 - - cairo=1.14.12=h8948797_3 - - certifi=2019.11.28=py36_0 - - cffi=1.14.0=py36h2e261b9_0 - - chardet=3.0.4=py36_1003 - - click=7.0=py36_0 - - cloudpickle=1.3.0=py_0 - - clyent=1.2.2=py36_1 - - colorama=0.4.3=py_0 - - contextlib2=0.6.0.post1=py_0 - - cpuonly=1.0=0 - - cryptography=2.8=py36h1ba5d50_0 - - curl=7.68.0=hbc83047_0 - - cycler=0.10.0=py36_0 - - cython=0.29.15=py36he6710b0_0 - - cytoolz=0.10.1=py36h7b6447c_0 - - dask=2.10.1=py_0 - - dask-core=2.10.1=py_0 - - dbus=1.13.12=h746ee38_0 - - decorator=4.4.1=py_0 - - defusedxml=0.6.0=py_0 - - distributed=2.10.0=py_0 - - docutils=0.16=py36_0 - - entrypoints=0.3=py36_0 - - et_xmlfile=1.0.1=py36_0 - - expat=2.2.6=he6710b0_0 - - fastcache=1.1.0=py36h7b6447c_0 - - flask=1.1.1=py_0 - - fontconfig=2.13.0=h9420a91_0 - - freetype=2.9.1=h8a8886c_1 - - fribidi=1.0.5=h7b6447c_0 - - fsspec=0.6.2=py_0 - - get_terminal_size=1.0.0=haa9412d_0 - - gevent=1.4.0=py36h7b6447c_0 - - glib=2.63.1=h5a9c865_0 - - gmp=6.1.2=h6c8ec71_1 - - gmpy2=2.0.8=py36h10f8cd9_2 - - graphite2=1.3.13=h23475e2_0 - - greenlet=0.4.15=py36h7b6447c_0 - - gst-plugins-base=1.14.0=hbbd80ab_1 - - gstreamer=1.14.0=hb453b48_1 - - h5py=2.10.0=py36h7918eee_0 - - harfbuzz=1.8.8=hffaf4a1_0 - - hdf5=1.10.4=hb1b8bf9_0 - - heapdict=1.0.1=py_0 - - html5lib=1.0.1=py36_0 - - hypothesis=5.4.1=py_0 - - icu=58.2=h9c2bf20_1 - - idna=2.8=py36_0 - - imageio=2.6.1=py36_0 - - imagesize=1.2.0=py_0 - - importlib_metadata=1.5.0=py36_0 - - intel-openmp=2020.0=166 - - ipykernel=5.1.4=py36h39e3cac_0 - - ipython=7.12.0=py36h5ca1d4c_0 - - ipython_genutils=0.2.0=py36_0 - - ipywidgets=7.5.1=py_0 - - isort=4.3.21=py36_0 - - itsdangerous=1.1.0=py36_0 - - jbig=2.1=hdba287a_0 - - jdcal=1.4.1=py_0 - - jedi=0.16.0=py36_0 - - jeepney=0.4.2=py_0 - - jinja2=2.11.1=py_0 - - joblib=0.14.1=py_0 - - jpeg=9b=h024ee3a_2 - - json5=0.9.1=py_0 - - jsonschema=3.2.0=py36_0 - - jupyter=1.0.0=py36_7 - - jupyter_client=5.3.4=py36_0 - - jupyter_console=6.1.0=py_0 - - jupyter_core=4.6.1=py36_0 - - jupyterlab=1.2.6=pyhf63ae98_0 - - jupyterlab_server=1.0.6=py_0 - - keyring=21.1.0=py36_0 - - kiwisolver=1.1.0=py36he6710b0_0 - - krb5=1.17.1=h173b8e3_0 - - lazy-object-proxy=1.4.3=py36h7b6447c_0 - - ld_impl_linux-64=2.33.1=h53a641e_7 - - libcurl=7.68.0=h20c2e04_0 - - libedit=3.1.20181209=hc058e9b_0 - - libffi=3.2.1=hd88cf55_4 - - libgcc-ng=9.1.0=hdf63c60_0 - - libgfortran-ng=7.3.0=hdf63c60_0 - - libpng=1.6.37=hbc83047_0 - - libsodium=1.0.16=h1bed415_0 - - libssh2=1.8.2=h1ba5d50_0 - - libstdcxx-ng=9.1.0=hdf63c60_0 - - libtiff=4.1.0=h2733197_0 - - libtool=2.4.6=h7b6447c_5 - - libuuid=1.0.3=h1bed415_2 - - libxcb=1.13=h1bed415_1 - - libxml2=2.9.9=hea5a465_1 - - libxslt=1.1.33=h7d1a2b0_0 - - llvmlite=0.31.0=py36hd408876_0 - - locket=0.2.0=py36_1 - - lxml=4.5.0=py36hefd8a0e_0 - - lz4-c=1.8.1.2=h14c3975_0 - - lzo=2.10=h49e0be7_2 - - markupsafe=1.1.1=py36h7b6447c_0 - - matplotlib=3.1.3=py36_0 - - matplotlib-base=3.1.3=py36hef1b27d_0 - - mccabe=0.6.1=py36_1 - - mistune=0.8.4=py36h7b6447c_0 - - mkl=2020.0=166 - - mkl-service=2.3.0=py36he904b0f_0 - - mkl_fft=1.0.15=py36ha843d7b_0 - - mkl_random=1.1.0=py36hd6b4f25_0 - - mock=4.0.1=py_0 - - more-itertools=8.2.0=py_0 - - mpc=1.1.0=h10f8cd9_1 - - mpfr=4.0.1=hdf1c602_3 - - mpmath=1.1.0=py36_0 - - msgpack-python=0.6.1=py36hfd86e86_1 - - multipledispatch=0.6.0=py36_0 - - nbconvert=5.6.1=py36_0 - - nbformat=5.0.4=py_0 - - ncurses=6.1=he6710b0_1 - - networkx=2.4=py_0 - - ninja=1.9.0=py36hfd86e86_0 - - nltk=3.4.5=py36_0 - - nose=1.3.7=py36_2 - - notebook=6.0.3=py36_0 - - numba=0.48.0=py36h0573a6f_0 - - numexpr=2.7.1=py36h423224d_0 - - numpy=1.18.1=py36h4f9e942_0 - - numpy-base=1.18.1=py36hde5b4d6_1 - - numpydoc=0.9.2=py_0 - - olefile=0.46=py36_0 - - openpyxl=3.0.3=py_0 - - openssl=1.1.1d=h7b6447c_4 - - packaging=20.1=py_0 - - pandas=1.0.1=py36h0573a6f_0 - - pandoc=2.2.3.2=0 - - pandocfilters=1.4.2=py36_1 - - pango=1.42.4=h049681c_0 - - parso=0.6.1=py_0 - - partd=1.1.0=py_0 - - path=13.1.0=py36_0 - - path.py=12.4.0=0 - - pathlib2=2.3.5=py36_0 - - patsy=0.5.1=py36_0 - - pcre=8.43=he6710b0_0 - - pep8=1.7.1=py36_0 - - pexpect=4.8.0=py36_0 - - pickleshare=0.7.5=py36_0 - - pillow=7.0.0=py36hb39fc2d_0 - - pip=20.0.2=py36_1 - - pixman=0.38.0=h7b6447c_0 - - pluggy=0.13.1=py36_0 - - ply=3.11=py36_0 - - prometheus_client=0.7.1=py_0 - - prompt_toolkit=3.0.3=py_0 - - psutil=5.6.7=py36h7b6447c_0 - - ptyprocess=0.6.0=py36_0 - - py=1.8.1=py_0 - - pycodestyle=2.5.0=py36_0 - - pycosat=0.6.3=py36h7b6447c_0 - - pycparser=2.19=py36_0 - - pycrypto=2.6.1=py36h14c3975_9 - - pycurl=7.43.0.5=py36h1ba5d50_0 - - pyflakes=2.1.1=py36_0 - - pygments=2.5.2=py_0 - - pylint=2.4.4=py36_0 - - pyodbc=4.0.30=py36he6710b0_0 - - pyopenssl=19.1.0=py36_0 - - pyparsing=2.4.6=py_0 - - pyqt=5.9.2=py36h05f1152_2 - - pyrsistent=0.15.7=py36h7b6447c_0 - - pysocks=1.7.1=py36_0 - - pytables=3.6.1=py36h71ec239_0 - - pytest=5.3.5=py36_0 - - pytest-arraydiff=0.3=py36h39e3cac_0 - - pytest-astropy=0.8.0=py_0 - - pytest-astropy-header=0.1.2=py_0 - - pytest-doctestplus=0.5.0=py_0 - - pytest-openfiles=0.4.0=py_0 - - pytest-remotedata=0.3.2=py36_0 - - python=3.6.10=h0371630_0 - - python-dateutil=2.8.1=py_0 - - pytorch=1.4.0=py3.6_cpu_0 - - pytz=2019.3=py_0 - - pywavelets=1.1.1=py36h7b6447c_0 - - pyyaml=5.3=py36h7b6447c_0 - - pyzmq=18.1.1=py36he6710b0_0 - - qt=5.9.7=h5867ecd_1 - - qtawesome=0.6.1=py_0 - - qtconsole=4.6.0=py_1 - - qtpy=1.9.0=py_0 - - readline=7.0=h7b6447c_5 - - requests=2.22.0=py36_1 - - rope=0.16.0=py_0 - - ruamel_yaml=0.15.87=py36h7b6447c_0 - - scikit-image=0.16.2=py36h0573a6f_0 - - scikit-learn=0.22.1=py36hd81dba3_0 - - scipy=1.4.1=py36h0b6359f_0 - - seaborn=0.10.0=py_0 - - secretstorage=3.1.2=py36_0 - - send2trash=1.5.0=py36_0 - - setuptools=45.2.0=py36_0 - - simplegeneric=0.8.1=py36_2 - - singledispatch=3.4.0.3=py36_0 - - sip=4.19.8=py36hf484d3e_0 - - six=1.14.0=py36_0 - - snappy=1.1.7=hbae5bb6_3 - - snowballstemmer=2.0.0=py_0 - - sortedcollections=1.1.2=py36_0 - - sortedcontainers=2.1.0=py36_0 - - soupsieve=1.9.5=py36_0 - - sphinx=2.4.0=py_0 - - sphinxcontrib=1.0=py36_1 - - sphinxcontrib-applehelp=1.0.1=py_0 - - sphinxcontrib-devhelp=1.0.1=py_0 - - sphinxcontrib-htmlhelp=1.0.2=py_0 - - sphinxcontrib-jsmath=1.0.1=py_0 - - sphinxcontrib-qthelp=1.0.2=py_0 - - sphinxcontrib-serializinghtml=1.1.3=py_0 - - sphinxcontrib-websupport=1.2.0=py_0 - - spyder=3.3.6=py36_0 - - spyder-kernels=0.5.2=py36_0 - - sqlalchemy=1.3.13=py36h7b6447c_0 - - sqlite=3.31.1=h7b6447c_0 - - statsmodels=0.11.0=py36h7b6447c_0 - - sympy=1.5.1=py36_0 - - tblib=1.6.0=py_0 - - terminado=0.8.3=py36_0 - - testpath=0.4.4=py_0 - - tk=8.6.8=hbc83047_0 - - toolz=0.10.0=py_0 - - torchvision=0.5.0=py36_cpu - - tornado=6.0.3=py36h7b6447c_3 - - traitlets=4.3.3=py36_0 - - typed-ast=1.4.1=py36h7b6447c_0 - - unicodecsv=0.14.1=py36_0 - - unixodbc=2.3.7=h14c3975_0 - - urllib3=1.25.8=py36_0 - - wcwidth=0.1.8=py_0 - - webencodings=0.5.1=py36_1 - - werkzeug=1.0.0=py_0 - - wheel=0.34.2=py36_0 - - widgetsnbextension=3.5.1=py36_0 - - wrapt=1.11.2=py36h7b6447c_0 - - wurlitzer=2.0.0=py36_0 - - xlrd=1.2.0=py36_0 - - xlsxwriter=1.2.7=py_0 - - xlwt=1.3.0=py36_0 - - xz=5.2.4=h14c3975_4 - - yaml=0.1.7=had09818_2 - - zeromq=4.3.1=he6710b0_3 - - zict=1.0.0=py_0 - - zipp=2.2.0=py_0 - - zlib=1.2.11=h7b6447c_3 - - zstd=1.3.7=h0b5b093_0 + - _libgcc_mutex=0.1 + - attrs=19.3.0 + - backcall=0.1.0 + - blas=1.0 + - bleach=3.1.4 + - ca-certificates=2020.4.5.1 + - certifi=2020.4.5.1 + - cpuonly=1.0 + - decorator=4.4.2 + - defusedxml=0.6.0 + - entrypoints=0.3 + - freetype=2.9.1 + - importlib-metadata=1.6.0 + - importlib_metadata=1.6.0 + - intel-openmp=2020.0 + - ipykernel=5.2.1 + - ipython=7.13.0 + - ipython_genutils=0.2.0 + - ipywidgets=7.5.1 + - jedi=0.17.0 + - jinja2=2.11.2 + - jpeg=9b + - jsonschema=3.2.0 + - jupyter_client=6.1.3 + - jupyter_core=4.6.3 + - ld_impl_linux-64=2.33.1 + - libedit=3.1.20181209 + - libffi=3.2.1 + - libgcc-ng=9.1.0 + - libgfortran-ng=7.3.0 + - libpng=1.6.37 + - libsodium=1.0.17 + - libstdcxx-ng=9.1.0 + - libtiff=4.1.0 + - markupsafe=1.1.1 + - mistune=0.8.4 + - mkl=2020.0 + - mkl-service=2.3.0 + - mkl_fft=1.0.15 + - mkl_random=1.1.0 + - nbconvert=5.6.1 + - nbformat=5.0.6 + - ncurses=6.2 + - ninja=1.9.0 + - notebook=6.0.3 + - numpy=1.18.1 + - numpy-base=1.18.1 + - olefile=0.46 + - openssl=1.1.1f + - pandoc=2.9.2.1 + - parso=0.7.0 + - pexpect=4.8.0 + - pickleshare=0.7.5 + - pillow=7.0.0 + - pip=20.0.2 + - prometheus_client=0.7.1 + - prompt-toolkit=3.0.5 + - ptyprocess=0.6.0 + - pygments=2.6.1 + - pyrsistent=0.16.0 + - python=3.6.10 + - python-dateutil=2.8.1 + - python_abi=3.6 + - pytorch=1.4.0 + - readline=8.0 + - send2trash=1.5.0 + - setuptools=46.1.3 + - six=1.14.0 + - sqlite=3.31.1 + - testpath=0.4.4 + - tk=8.6.8 + - torchvision=0.5.0 + - tornado=6.0.4 + - traitlets=4.3.3 + - wcwidth=0.1.9 + - wheel=0.34.2 + - widgetsnbextension=3.5.1 + - xz=5.2.5 + - zeromq=4.3.2 + - zipp=3.1.0 + - zlib=1.2.11 + - zstd=1.3.7 - pip: - - kornia==0.2.0 - - opencv-contrib-python==4.2.0.32 -prefix: /home/old-ufo/anaconda3/envs/mpv-assignments-cpu-only + - absl-py==0.9.0 + - cachetools==4.1.0 + - chardet==3.0.4 + - cycler==0.10.0 + - google-auth==1.14.0 + - google-auth-oauthlib==0.4.1 + - grpcio==1.28.1 + - idna==2.9 + - ipython-genutils==0.2.0 + - kiwisolver==1.2.0 + - kornia==0.2.1 + - markdown==3.2.1 + - matplotlib==3.2.1 + - oauthlib==3.1.0 + - opencv-contrib-python==4.2.0.34 + - pandas==1.0.3 + - pandocfilters==1.4.2 + - protobuf==3.11.3 + - pyasn1==0.4.8 + - pyasn1-modules==0.2.8 + - pyparsing==2.4.7 + - pytz==2019.3 + - pyzmq==19.0.0 + - requests==2.23.0 + - requests-oauthlib==1.3.0 + - rsa==4.0 + - scipy==1.4.1 + - seaborn==0.10.0 + - tensorboard==2.2.1 + - tensorboard-plugin-wit==1.6.0.post3 + - tensorboardx==2.0 + - terminado==0.8.3 + - tqdm==4.45.0 + - urllib3==1.25.9 + - webencodings==0.5.1 + - werkzeug==1.0.1 diff --git a/conda_env_yaml/environment-gpu.yml b/conda_env_yaml/environment-gpu.yml index 8ef1784b73121361806779e572984ad142f8f257..295b618a69424502d9fd1726b722bc0a5e5ed760 100644 --- a/conda_env_yaml/environment-gpu.yml +++ b/conda_env_yaml/environment-gpu.yml @@ -1,289 +1,126 @@ -name: mpv-assignments +name: mpv-assignments-gpu channels: - pytorch + - conda-forge - defaults dependencies: - - _anaconda_depends=2019.03=py36_0 - - _libgcc_mutex=0.1=main - - alabaster=0.7.12=py36_0 - - anaconda=custom=py36_1 - - anaconda-client=1.7.2=py36_0 - - anaconda-project=0.8.4=py_0 - - asn1crypto=1.3.0=py36_0 - - astroid=2.3.3=py36_0 - - astropy=4.0=py36h7b6447c_0 - - atomicwrites=1.3.0=py36_1 - - attrs=19.3.0=py_0 - - babel=2.8.0=py_0 - - backcall=0.1.0=py36_0 - - backports=1.0=py_2 - - backports.os=0.1.1=py36_0 - - backports.shutil_get_terminal_size=1.0.0=py36_2 - - beautifulsoup4=4.8.2=py36_0 - - bitarray=1.2.1=py36h7b6447c_0 - - bkcharts=0.2=py36_0 - - blas=1.0=mkl - - bleach=3.1.0=py36_0 - - blosc=1.16.3=hd408876_0 - - bokeh=1.4.0=py36_0 - - boto=2.49.0=py36_0 - - bottleneck=1.3.1=py36hdd07704_0 - - bzip2=1.0.8=h7b6447c_0 - - ca-certificates=2020.1.1=0 - - cairo=1.14.12=h8948797_3 - - certifi=2019.11.28=py36_0 - - cffi=1.14.0=py36h2e261b9_0 - - chardet=3.0.4=py36_1003 - - click=7.0=py36_0 - - cloudpickle=1.3.0=py_0 - - clyent=1.2.2=py36_1 - - colorama=0.4.3=py_0 - - contextlib2=0.6.0.post1=py_0 - - cryptography=2.8=py36h1ba5d50_0 - - cudatoolkit=10.1.243=h6bb024c_0 - - curl=7.68.0=hbc83047_0 - - cycler=0.10.0=py36_0 - - cython=0.29.15=py36he6710b0_0 - - cytoolz=0.10.1=py36h7b6447c_0 - - dask=2.10.1=py_0 - - dask-core=2.10.1=py_0 - - dbus=1.13.12=h746ee38_0 - - decorator=4.4.1=py_0 - - defusedxml=0.6.0=py_0 - - distributed=2.10.0=py_0 - - docutils=0.16=py36_0 - - entrypoints=0.3=py36_0 - - et_xmlfile=1.0.1=py36_0 - - expat=2.2.6=he6710b0_0 - - fastcache=1.1.0=py36h7b6447c_0 - - flask=1.1.1=py_0 - - fontconfig=2.13.0=h9420a91_0 - - freetype=2.9.1=h8a8886c_1 - - fribidi=1.0.5=h7b6447c_0 - - fsspec=0.6.2=py_0 - - get_terminal_size=1.0.0=haa9412d_0 - - gevent=1.4.0=py36h7b6447c_0 - - glib=2.63.1=h5a9c865_0 - - gmp=6.1.2=h6c8ec71_1 - - gmpy2=2.0.8=py36h10f8cd9_2 - - graphite2=1.3.13=h23475e2_0 - - greenlet=0.4.15=py36h7b6447c_0 - - gst-plugins-base=1.14.0=hbbd80ab_1 - - gstreamer=1.14.0=hb453b48_1 - - h5py=2.10.0=py36h7918eee_0 - - harfbuzz=1.8.8=hffaf4a1_0 - - hdf5=1.10.4=hb1b8bf9_0 - - heapdict=1.0.1=py_0 - - html5lib=1.0.1=py36_0 - - hypothesis=5.4.1=py_0 - - icu=58.2=h9c2bf20_1 - - idna=2.8=py36_0 - - imageio=2.6.1=py36_0 - - imagesize=1.2.0=py_0 - - importlib_metadata=1.5.0=py36_0 - - intel-openmp=2020.0=166 - - ipykernel=5.1.4=py36h39e3cac_0 - - ipython=7.12.0=py36h5ca1d4c_0 - - ipython_genutils=0.2.0=py36_0 - - ipywidgets=7.5.1=py_0 - - isort=4.3.21=py36_0 - - itsdangerous=1.1.0=py36_0 - - jbig=2.1=hdba287a_0 - - jdcal=1.4.1=py_0 - - jedi=0.16.0=py36_0 - - jeepney=0.4.2=py_0 - - jinja2=2.11.1=py_0 - - joblib=0.14.1=py_0 - - jpeg=9b=h024ee3a_2 - - json5=0.9.1=py_0 - - jsonschema=3.2.0=py36_0 - - jupyter=1.0.0=py36_7 - - jupyter_client=5.3.4=py36_0 - - jupyter_console=6.1.0=py_0 - - jupyter_core=4.6.1=py36_0 - - jupyterlab=1.2.6=pyhf63ae98_0 - - jupyterlab_server=1.0.6=py_0 - - keyring=21.1.0=py36_0 - - kiwisolver=1.1.0=py36he6710b0_0 - - krb5=1.17.1=h173b8e3_0 - - lazy-object-proxy=1.4.3=py36h7b6447c_0 - - ld_impl_linux-64=2.33.1=h53a641e_7 - - libcurl=7.68.0=h20c2e04_0 - - libedit=3.1.20181209=hc058e9b_0 - - libffi=3.2.1=hd88cf55_4 - - libgcc-ng=9.1.0=hdf63c60_0 - - libgfortran-ng=7.3.0=hdf63c60_0 - - libpng=1.6.37=hbc83047_0 - - libsodium=1.0.16=h1bed415_0 - - libssh2=1.8.2=h1ba5d50_0 - - libstdcxx-ng=9.1.0=hdf63c60_0 - - libtiff=4.1.0=h2733197_0 - - libtool=2.4.6=h7b6447c_5 - - libuuid=1.0.3=h1bed415_2 - - libxcb=1.13=h1bed415_1 - - libxml2=2.9.9=hea5a465_1 - - libxslt=1.1.33=h7d1a2b0_0 - - llvmlite=0.31.0=py36hd408876_0 - - locket=0.2.0=py36_1 - - lxml=4.5.0=py36hefd8a0e_0 - - lz4-c=1.8.1.2=h14c3975_0 - - lzo=2.10=h49e0be7_2 - - markupsafe=1.1.1=py36h7b6447c_0 - - matplotlib=3.1.3=py36_0 - - matplotlib-base=3.1.3=py36hef1b27d_0 - - mccabe=0.6.1=py36_1 - - mistune=0.8.4=py36h7b6447c_0 - - mkl=2020.0=166 - - mkl-service=2.3.0=py36he904b0f_0 - - mkl_fft=1.0.15=py36ha843d7b_0 - - mkl_random=1.1.0=py36hd6b4f25_0 - - mock=4.0.1=py_0 - - more-itertools=8.2.0=py_0 - - mpc=1.1.0=h10f8cd9_1 - - mpfr=4.0.1=hdf1c602_3 - - mpmath=1.1.0=py36_0 - - msgpack-python=0.6.1=py36hfd86e86_1 - - multipledispatch=0.6.0=py36_0 - - nbconvert=5.6.1=py36_0 - - nbformat=5.0.4=py_0 - - ncurses=6.1=he6710b0_1 - - networkx=2.4=py_0 - - ninja=1.9.0=py36hfd86e86_0 - - nltk=3.4.5=py36_0 - - nose=1.3.7=py36_2 - - notebook=6.0.3=py36_0 - - numba=0.48.0=py36h0573a6f_0 - - numexpr=2.7.1=py36h423224d_0 - - numpy=1.18.1=py36h4f9e942_0 - - numpy-base=1.18.1=py36hde5b4d6_1 - - numpydoc=0.9.2=py_0 - - olefile=0.46=py36_0 - - openpyxl=3.0.3=py_0 - - openssl=1.1.1d=h7b6447c_4 - - packaging=20.1=py_0 - - pandas=1.0.1=py36h0573a6f_0 - - pandoc=2.2.3.2=0 - - pandocfilters=1.4.2=py36_1 - - pango=1.42.4=h049681c_0 - - parso=0.6.1=py_0 - - partd=1.1.0=py_0 - - path=13.1.0=py36_0 - - path.py=12.4.0=0 - - pathlib2=2.3.5=py36_0 - - patsy=0.5.1=py36_0 - - pcre=8.43=he6710b0_0 - - pep8=1.7.1=py36_0 - - pexpect=4.8.0=py36_0 - - pickleshare=0.7.5=py36_0 - - pillow=7.0.0=py36hb39fc2d_0 - - pip=20.0.2=py36_1 - - pixman=0.38.0=h7b6447c_0 - - pluggy=0.13.1=py36_0 - - ply=3.11=py36_0 - - prometheus_client=0.7.1=py_0 - - prompt_toolkit=3.0.3=py_0 - - psutil=5.6.7=py36h7b6447c_0 - - ptyprocess=0.6.0=py36_0 - - py=1.8.1=py_0 - - pycodestyle=2.5.0=py36_0 - - pycosat=0.6.3=py36h7b6447c_0 - - pycparser=2.19=py36_0 - - pycrypto=2.6.1=py36h14c3975_9 - - pycurl=7.43.0.5=py36h1ba5d50_0 - - pyflakes=2.1.1=py36_0 - - pygments=2.5.2=py_0 - - pylint=2.4.4=py36_0 - - pyodbc=4.0.30=py36he6710b0_0 - - pyopenssl=19.1.0=py36_0 - - pyparsing=2.4.6=py_0 - - pyqt=5.9.2=py36h05f1152_2 - - pyrsistent=0.15.7=py36h7b6447c_0 - - pysocks=1.7.1=py36_0 - - pytables=3.6.1=py36h71ec239_0 - - pytest=5.3.5=py36_0 - - pytest-arraydiff=0.3=py36h39e3cac_0 - - pytest-astropy=0.8.0=py_0 - - pytest-astropy-header=0.1.2=py_0 - - pytest-doctestplus=0.5.0=py_0 - - pytest-openfiles=0.4.0=py_0 - - pytest-remotedata=0.3.2=py36_0 - - python=3.6.10=h0371630_0 - - python-dateutil=2.8.1=py_0 - - pytorch=1.4.0=py3.6_cuda10.1.243_cudnn7.6.3_0 - - pytz=2019.3=py_0 - - pywavelets=1.1.1=py36h7b6447c_0 - - pyyaml=5.3=py36h7b6447c_0 - - pyzmq=18.1.1=py36he6710b0_0 - - qt=5.9.7=h5867ecd_1 - - qtawesome=0.6.1=py_0 - - qtconsole=4.6.0=py_1 - - qtpy=1.9.0=py_0 - - readline=7.0=h7b6447c_5 - - requests=2.22.0=py36_1 - - rope=0.16.0=py_0 - - ruamel_yaml=0.15.87=py36h7b6447c_0 - - scikit-image=0.16.2=py36h0573a6f_0 - - scikit-learn=0.22.1=py36hd81dba3_0 - - scipy=1.4.1=py36h0b6359f_0 - - seaborn=0.10.0=py_0 - - secretstorage=3.1.2=py36_0 - - send2trash=1.5.0=py36_0 - - setuptools=45.2.0=py36_0 - - simplegeneric=0.8.1=py36_2 - - singledispatch=3.4.0.3=py36_0 - - sip=4.19.8=py36hf484d3e_0 - - six=1.14.0=py36_0 - - snappy=1.1.7=hbae5bb6_3 - - snowballstemmer=2.0.0=py_0 - - sortedcollections=1.1.2=py36_0 - - sortedcontainers=2.1.0=py36_0 - - soupsieve=1.9.5=py36_0 - - sphinx=2.4.0=py_0 - - sphinxcontrib=1.0=py36_1 - - sphinxcontrib-applehelp=1.0.1=py_0 - - sphinxcontrib-devhelp=1.0.1=py_0 - - sphinxcontrib-htmlhelp=1.0.2=py_0 - - sphinxcontrib-jsmath=1.0.1=py_0 - - sphinxcontrib-qthelp=1.0.2=py_0 - - sphinxcontrib-serializinghtml=1.1.3=py_0 - - sphinxcontrib-websupport=1.2.0=py_0 - - spyder=3.3.6=py36_0 - - spyder-kernels=0.5.2=py36_0 - - sqlalchemy=1.3.13=py36h7b6447c_0 - - sqlite=3.31.1=h7b6447c_0 - - statsmodels=0.11.0=py36h7b6447c_0 - - sympy=1.5.1=py36_0 - - tblib=1.6.0=py_0 - - terminado=0.8.3=py36_0 - - testpath=0.4.4=py_0 - - tk=8.6.8=hbc83047_0 - - toolz=0.10.0=py_0 - - torchvision=0.5.0=py36_cu101 - - tornado=6.0.3=py36h7b6447c_3 - - traitlets=4.3.3=py36_0 - - typed-ast=1.4.1=py36h7b6447c_0 - - unicodecsv=0.14.1=py36_0 - - unixodbc=2.3.7=h14c3975_0 - - urllib3=1.25.8=py36_0 - - wcwidth=0.1.8=py_0 - - webencodings=0.5.1=py36_1 - - werkzeug=1.0.0=py_0 - - wheel=0.34.2=py36_0 - - widgetsnbextension=3.5.1=py36_0 - - wrapt=1.11.2=py36h7b6447c_0 - - wurlitzer=2.0.0=py36_0 - - xlrd=1.2.0=py36_0 - - xlsxwriter=1.2.7=py_0 - - xlwt=1.3.0=py36_0 - - xz=5.2.4=h14c3975_4 - - yaml=0.1.7=had09818_2 - - zeromq=4.3.1=he6710b0_3 - - zict=1.0.0=py_0 - - zipp=2.2.0=py_0 - - zlib=1.2.11=h7b6447c_3 - - zstd=1.3.7=h0b5b093_0 + - _libgcc_mutex=0.1 + - attrs=19.3.0 + - backcall=0.1.0 + - blas=1.0 + - bleach=3.1.4 + - ca-certificates=2020.4.5.1 + - certifi=2020.4.5.1 + - cudatoolkit=10.1.243 + - decorator=4.4.2 + - defusedxml=0.6.0 + - entrypoints=0.3 + - freetype=2.9.1 + - importlib-metadata=1.6.0 + - importlib_metadata=1.6.0 + - intel-openmp=2020.0 + - ipykernel=5.2.1 + - ipython=7.13.0 + - ipython_genutils=0.2.0 + - ipywidgets=7.5.1 + - jedi=0.17.0 + - jinja2=2.11.2 + - jpeg=9b + - jsonschema=3.2.0 + - jupyter_client=6.1.3 + - jupyter_core=4.6.3 + - ld_impl_linux-64=2.33.1 + - libedit=3.1.20181209 + - libffi=3.2.1 + - libgcc-ng=9.1.0 + - libgfortran-ng=7.3.0 + - libpng=1.6.37 + - libsodium=1.0.17 + - libstdcxx-ng=9.1.0 + - libtiff=4.1.0 + - markupsafe=1.1.1 + - mistune=0.8.4 + - mkl=2020.0 + - mkl-service=2.3.0 + - mkl_fft=1.0.15 + - mkl_random=1.1.0 + - nbconvert=5.6.1 + - nbformat=5.0.6 + - ncurses=6.2 + - ninja=1.9.0 + - notebook=6.0.3 + - numpy=1.18.1 + - numpy-base=1.18.1 + - olefile=0.46 + - openssl=1.1.1g + - pandoc=2.9.2.1 + - parso=0.7.0 + - pexpect=4.8.0 + - pickleshare=0.7.5 + - pillow=7.0.0 + - pip=20.0.2 + - prometheus_client=0.7.1 + - prompt-toolkit=3.0.5 + - ptyprocess=0.6.0 + - pygments=2.6.1 + - pyrsistent=0.16.0 + - python=3.6.10 + - python-dateutil=2.8.1 + - python_abi=3.6 + - pytorch=1.4.0 + - readline=8.0 + - send2trash=1.5.0 + - setuptools=46.1.3 + - six=1.14.0 + - sqlite=3.31.1 + - testpath=0.4.4 + - tk=8.6.8 + - torchvision=0.5.0 + - tornado=6.0.4 + - traitlets=4.3.3 + - wcwidth=0.1.9 + - wheel=0.34.2 + - widgetsnbextension=3.5.1 + - xz=5.2.5 + - zeromq=4.3.2 + - zipp=3.1.0 + - zlib=1.2.11 + - zstd=1.3.7 - pip: - - kornia==0.2.0 - - opencv-contrib-python==4.2.0.32 -prefix: /home/old-ufo/anaconda3/envs/mpv-assignments + - absl-py==0.9.0 + - cachetools==4.1.0 + - chardet==3.0.4 + - cycler==0.10.0 + - google-auth==1.14.0 + - google-auth-oauthlib==0.4.1 + - grpcio==1.28.1 + - idna==2.9 + - ipython-genutils==0.2.0 + - kiwisolver==1.2.0 + - kornia==0.2.1 + - markdown==3.2.1 + - matplotlib==3.2.1 + - oauthlib==3.1.0 + - opencv-contrib-python==4.2.0.34 + - pandas==1.0.3 + - pandocfilters==1.4.2 + - protobuf==3.11.3 + - pyasn1==0.4.8 + - pyasn1-modules==0.2.8 + - pyparsing==2.4.7 + - pytz==2019.3 + - pyzmq==19.0.0 + - requests==2.23.0 + - requests-oauthlib==1.3.0 + - rsa==4.0 + - scipy==1.4.1 + - seaborn==0.10.0 + - tensorboard==2.2.1 + - tensorboard-plugin-wit==1.6.0.post3 + - tensorboardx==2.0 + - terminado==0.8.3 + - tqdm==4.45.0 + - urllib3==1.25.9 + - webencodings==0.5.1 + - werkzeug==1.0.1