From ced1bc8cb366134d2396e4609e748936c7a93d24 Mon Sep 17 00:00:00 2001 From: Timur Osmanov <54434686+TOsmanov@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:32:15 +0300 Subject: [PATCH] Documentation update, added info about the cloud storage UI and add AWS-S3 tutorial (#3745) * added info about cloud storage ui * fixed linter errors, improved list spacing * fixed linter errors v2 * fixed mistakes & indentation * Apply suggestions from code review Co-authored-by: Timur Osmanov <54434686+TOsmanov@users.noreply.github.com> * fixed errors & indentation issues * fixed errors & indentation issues v2 * fix mistakes in attach-cloud-storage.md * apply suggestions v2 * add aws-s3 tutorial * fix linter errors * update attach-cloud-storage.md * fix mistakes * update attach-cloud-storage.md * update image * fix link * update attach cloud storage section * fix markup * fix mistake * fix mistake * update the example manifest * apply suggestions Co-authored-by: Motov Co-authored-by: amotovx <87861362+amotovx@users.noreply.github.com> --- .../docs/manual/advanced/dataset_manifest.md | 6 +- .../manual/basics/attach-cloud-storage.md | 143 ++++++++++++++++-- site/content/en/images/aws-s3_tutorial_1.gif | Bin 0 -> 336047 bytes site/content/en/images/aws-s3_tutorial_1.jpg | Bin 0 -> 47697 bytes site/content/en/images/aws-s3_tutorial_2.jpg | Bin 0 -> 45327 bytes site/content/en/images/aws-s3_tutorial_3.jpg | Bin 0 -> 103267 bytes site/content/en/images/aws-s3_tutorial_4.jpg | Bin 0 -> 76092 bytes site/content/en/images/aws-s3_tutorial_5.jpg | Bin 0 -> 65150 bytes site/content/en/images/aws-s3_tutorial_6.jpg | Bin 0 -> 39244 bytes site/content/en/images/aws-s3_tutorial_7.jpg | Bin 0 -> 63846 bytes utils/dataset_manifest/core.py | 2 +- 11 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 site/content/en/images/aws-s3_tutorial_1.gif create mode 100644 site/content/en/images/aws-s3_tutorial_1.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_2.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_3.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_4.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_5.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_6.jpg create mode 100644 site/content/en/images/aws-s3_tutorial_7.jpg diff --git a/site/content/en/docs/manual/advanced/dataset_manifest.md b/site/content/en/docs/manual/advanced/dataset_manifest.md index 5d2c1f2f..64db6415 100644 --- a/site/content/en/docs/manual/advanced/dataset_manifest.md +++ b/site/content/en/docs/manual/advanced/dataset_manifest.md @@ -123,7 +123,7 @@ A maifest file contains some intuitive information and some specific like: ```json {"version":"1.0"} {"type":"images"} -{"name":"image1","extension":".jpg","width":720,"height":405,"checksum":"548918ec4b56132a5cff1d4acabe9947"} -{"name":"image2","extension":".jpg","width":183,"height":275,"checksum":"4b4eefd03cc6a45c1c068b98477fb639"} -{"name":"image3","extension":".jpg","width":301,"height":167,"checksum":"0e454a6f4a13d56c82890c98be063663"} +{"name":"image1","extension":".jpg","width":720,"height":405,"meta":{"related_images":[]},"checksum":"548918ec4b56132a5cff1d4acabe9947"} +{"name":"image2","extension":".jpg","width":183,"height":275,"meta":{"related_images":[]},"checksum":"4b4eefd03cc6a45c1c068b98477fb639"} +{"name":"image3","extension":".jpg","width":301,"height":167,"meta":{"related_images":[]},"checksum":"0e454a6f4a13d56c82890c98be063663"} ``` diff --git a/site/content/en/docs/manual/basics/attach-cloud-storage.md b/site/content/en/docs/manual/basics/attach-cloud-storage.md index 70c8a930..86117f86 100644 --- a/site/content/en/docs/manual/basics/attach-cloud-storage.md +++ b/site/content/en/docs/manual/basics/attach-cloud-storage.md @@ -6,13 +6,72 @@ description: 'Instructions on how to attach cloud storage using UI' --- In CVAT you can use AWS-S3 and Azure Blob Container cloud storages to store image datasets for your tasks. -Initially you need to create a manifest file for your image dataset. Information on how to do that is available -on the [Simple command line to prepare dataset manifest file](/docs/manual/advanced/dataset_manifest) page. -After the manifest file has been created, you can upload it and your dataset to an AWS-S3 or -Azure Blob Container cloud storage. +## Using AWS-S3 -After that you will be able to attach a cloud storage. To do this, press the `Attach new cloud storage` +### Create AWS account + +First, you need to create an AWS account, to do this, [register of 5 steps](https://portal.aws.amazon.com/billing/signup#/start) +following the instructions +(even if you plan to use a free basic account you may need to link a credit card to verify your identity). + +To learn more about the operation and benefits of AWS cloud, +take a free [AWS Cloud Practitioner Essentials](https://www.aws.training/Details/eLearning?id=60697) course, +which will be available after registration. + +### Create a bucket + +After the account is created, go to [console AWS-S3](https://s3.console.aws.amazon.com/s3/home) +and click `Create bucket`. + +![](/images/aws-s3_tutorial_1.jpg) + +You'll be taken to the bucket creation page. Here you have to specify the name of the bucket, region, +optionally you can copy the settings of another bucket by clicking on the `choose bucket` button. +Checkbox block all public access can be enabled as we will use `access key ID` and `secret access key` to gain access. +In the following sections, you can leave the default settings and click `create bucket`. +After you create the bucket it will appear in the list of buckets. + +### Create user and configure permissions + +To access bucket you will need to create a user, to do this, go [IAM](https://console.aws.amazon.com/iamv2/home#/users) +and click `add users`. You need to choose AWS access type, have an access key ID and secret access key. + +![](/images/aws-s3_tutorial_2.jpg) + +After pressing `next` button to configure permissions, you need to create a user group. +To do this click `create a group`, input the `group name` and select permission policies add `AmazonS3ReadOnlyAccess` +using the search (if you want the user you create to have write rights to bucket select `AmazonS3FullAccess`). + +![](/images/aws-s3_tutorial_3.jpg) + +You can also add tags for the user (optional), and look again at the entered data. In the last step of creating a user, +you will be provided with `access key ID` and `secret access key`, +they will need to be used in CVAT when adding cloud storage. + +![](/images/aws-s3_tutorial_4.jpg) + +### Upload dataset + +For example, let's take [The Oxford-IIIT Pet Dataset](https://www.robots.ox.ac.uk/~vgg/data/pets/): +- Download the [archive with images](https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz). +- Unpack the archive into the prepared folder + and create a manifest file as described in [prepare manifest file section](/docs/manual/advanced/dataset_manifest/): + ``` + python /utils/dataset_manifest/create.py --output-dir + ``` +- When the manifest file is ready, open the previously prepared bucket and click `Upload`: + + ![](/images/aws-s3_tutorial_5.jpg) + +- Drag the manifest file and image folder on the page and click `Upload`: + + ![](/images/aws-s3_tutorial_1.gif) + +## Attach new cloud storage + +After you upload the dataset and manifest file to AWS-S3 or Azure Blob Container +you will be able to attach a cloud storage. To do this, press the `Attach new cloud storage` button on the `Cloud storages` page and fill out the following form: ![](/images/image228.jpg) @@ -22,17 +81,17 @@ button on the `Cloud storages` page and fill out the following form: of an item on cloud storages page. - `Provider` - choose provider of the cloud storage: - - [AWS-S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/GetStartedWithS3.html): + - [AWS-S3](#using-aws-s3): - - `Bucket` - cloud storage bucket name + - [`Bucket`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket) - cloud storage bucket name - [`Authorization type`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-best-practices.html): - - `Key id and secret access key pair`: + - `Key id and secret access key pair` - available on [IAM](https://console.aws.amazon.com/iamv2/home?#/users) - `ACCESS KEY ID` - `SECRET ACCESS KEY ID` - - `Anonymous access` + - `Anonymous access` - For anonymous access, you need to enable public access to bucket - `Region` - here you can choose a region from the list or add a new one. To get more information click on [`?`](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions) @@ -60,3 +119,69 @@ For more information click on [`?`](/docs/manual/advanced/dataset_manifest/). To publish the cloud storage, click `submit`, after which it will be available on the [Cloud storages page](/docs/manual/basics/cloud-storages/). + +## Using AWS Data Exchange + +### Subscribe to data set + +You can use AWS Data Exchange to add image datasets. +For example, consider adding a set of datasets `500 Image & Metadata Free Sample`. +Go to [browse catalog](https://console.aws.amazon.com/dataexchange) and use the search to find +`500 Image & Metadata Free Sample`, open the dataset page and click `continue to subscribe`, +you will be taken to the page complete subscription request, read the information provided +and click send subscription request to provider. + +![](/images/aws-s3_tutorial_6.jpg) + +### Export to bucket + +After that, this dataset will appear in the +[list subscriptions](https://console.aws.amazon.com/dataexchange/home/subscriptions#/subscriptions). +Now you need to export the dataset to `Amazon S3`. +First, let's create a new one bucket similar to [described above](#create-a-bucket). +To export one of the datasets to a new bucket open it `entitled data` select one of the datasets, +select the corresponding revision and click export to Amazon S3 +(please note that if bucket and dataset are located in different regions, export fees may apply). +In the window that appears, select the created bucket and click export. + +![](/images/aws-s3_tutorial_7.jpg) + +### Prepare manifest file +Now you need to prepare a manifest file. I used [AWS cli](https://aws.amazon.com/cli/) and +[script for prepare manifest file](https://github.com/openvinotoolkit/cvat/tree/develop/utils/dataset_manifest). +Perform the installation using the manual [aws-shell](https://github.com/awslabs/aws-shell), +I used `aws-cli 1.20.49` `Python 3.7.9` `Windows 10`. +You can configure credentials by running `aws configure`. +You will need to enter `Access Key ID` and `Secret Access Key` as well as region. + +``` +aws configure +Access Key ID: +Secret Access Key: +``` + +Copy the content of the bucket to a folder on your computer: + +``` +aws s3 cp --recursive +``` + +After copying the files, you can create a manifest file as described in [preapair manifest file section](/docs/manual/advanced/dataset_manifest/): + +``` +python /utils/dataset_manifest/create.py --output-dir +``` + +When the manifest file is ready, you can upload it to aws s3 bucket. If you gave full write permissions +when you created the user, run: + +``` +aws s3 cp /manifest.jsonl +``` + +If you have given read-only permissions, use the download through the browser, click upload, +drag the manifest file to the page and click upload. + +![](/images/aws-s3_tutorial_5.jpg) + +Now you can [attach new cloud storage](#attach-new-cloud-storage) using the dataset `500 Image & Metadata Free Sample`. diff --git a/site/content/en/images/aws-s3_tutorial_1.gif b/site/content/en/images/aws-s3_tutorial_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5c98e1e6344a360f70601e5f570ec8fdde0d0e7 GIT binary patch literal 336047 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 z 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