{"id":723,"date":"2024-02-10T14:06:53","date_gmt":"2024-02-10T19:06:53","guid":{"rendered":"https:\/\/brian.digitalmaddox.com\/blog\/?p=723"},"modified":"2024-02-10T14:06:53","modified_gmt":"2024-02-10T19:06:53","slug":"applying-deep-learning-and-computer-vision-to-lidar-part-2-training-data","status":"publish","type":"post","link":"https:\/\/brian.digitalmaddox.com\/blog\/?p=723","title":{"rendered":"Applying Deep Learning and Computer Vision to Lidar Part 2: Training Data"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/brian.digitalmaddox.com\/blog\/?p=673\">part one<\/a> I described some of the issues I had on a recent project that applied deep learning to geographic feature recognition in LiDAR and the file sizes of such data.\u00a0 This time I want to talk about training data, how important it is, and how little there is for this type of problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One of the most important things in deep learning is having both quality training data and a good amount of such data.\u00a0 I have actually written a <a href=\"https:\/\/brian.digitalmaddox.com\/blog\/?p=673\">previous post<\/a> about the importance of quality data that you can read here.\u00a0 At a bare minimum, you should typically have around one thousand samples of each object class you want to train a model to recognize.\u00a0 Object classes in this case are geographic feature types that we want to recognize.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Training Data Characteristics<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These samples should mirror the characteristics of the data that your model will come across during classification tasks.\u00a0 With LiDAR in GeoTIFF format, the training data should be similar in resolution (0.5 meters in this case) and bit depth (32-bit) to the area for testing.\u00a0 There should be variability in the training data.\u00a0 Convolutional neural networks are <a href=\"https:\/\/pyimagesearch.com\/2021\/05\/14\/are-cnns-invariant-to-translation-rotation-and-scaling\/\">NOT rotational invariant<\/a>, meaning that unless you train your model on samples at different angles, it will not automatically recognize features.\u00a0 In this case, your training LiDAR features should be rotated at different angles to account for differences in projection or north direction.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Balanced Numbers of Features per Class<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Your training data should also be balanced, meaning that each class should have roughly the same number of training images where possible.\u00a0 You can perform some tasks that we will talk about in a bit to help with this, but generally if your model is unbalanced, it could mistakenly \u201clean\u201d towards one class more than others.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Related to this, when generating your training data, you should make sure your training and testing data contain samples from each of your object classes.  Especially when imbalanced, it is very easy to use something like <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.model_selection.train_test_split.html\">train_test_split<\/a> from the <a href=\"https:\/\/scikit-learn.org\/stable\/index.html\">sklearn<\/a> library and have it generate a training set that misses some object classes.  You should also shuffle your training data so that the samples from each class are sufficiently randomized and the model does not assume that features will appear in a specific order.  To alleviate this, make sure you pass in something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u2026 = train_test_split(\u2026, shuffle=True, stratify=labels)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">where <strong>labels<\/strong> is a list of your object classes.  For most cases this will ensure the order of your samples is sufficiently randomized and that your training\/testing data contains samples of each object class.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Complexity<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Geographic features also have a varying complexity in how they appear in LiDAR.\u00a0 The same feature can \u201clook\u201d differently based on its size or other characteristics.\u00a0 Humans will always look like humans, so training on them is fairly simple.\u00a0 Geographic features can be in the same class but appear differently based on factors such as weathering, erosion, vegetation, and even if it\u2019s a riverbed that is dry part of the year.\u00a0 This increased complexity means that samples need to have enough variability, even in the same object class, for proper training.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lack of Training Data for This Project<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With all of this out of the way, let us now talk about the issues that faced this particular project.\u00a0 First of all, there is not a lot of labeled training data for these types of features.\u00a0 At all.\u00a0 I used various search engines, ChatGPT, even bought a bucket of KFC so I could try to throw some bones to lead me to training data (although I don\u2019t know voodoo so probably read them wrong).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is a lot of data about these geographic features out there, but not labeled <strong>AND<\/strong> in LiDAR format.\u00a0 There is an abundance of photographs of these features.\u00a0 There are paper maps of these features.\u00a0 There are research papers with drawings of these features.\u00a0 I even found some GIS data that had polygons of these features, but the matching elevation model was too low of a resolution to be useful.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the end I was only able to find a <strong>single<\/strong> dataset that matched the bit depth and spatial resolution that matched the test data.\u00a0 There were a couple of problems with this dataset though.\u00a0 First, it only had three feature classes out of a dozen or more.\u00a0 Second, the number of samples of each of these three classes were way imbalanced.\u00a0 It broke down like this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Class 1 &#8211; 123 samples<\/li>\n\n\n\n<li>Class 2 &#8211; 2,214 samples<\/li>\n\n\n\n<li>Class 3 &#8211; 9,700 samples<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Realistically we should have just tried for Classes 2 and 3, but decided to try to use various techniques to help with the imbalance.\u00a0 Plus, since it was a bit of a research project, we felt it would be interesting to see what would happen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Data Augmentation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There are a few different methods of data augmentation you can do to add more training samples, especially with raster data.\u00a0 <a href=\"https:\/\/www.datacamp.com\/tutorial\/complete-guide-data-augmentation\">Data augmentation<\/a> is a technique where you generate new samples from existing data so that you can enhance your model\u2019s generalization and generate more data for training. The key part of this is making sure what the methods you use do not change the object class of the training sample.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Geometric Transformations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The first thing you can do with raster data is to apply geometric transformations (again, as long as they do not change the object class of your training sample).\u00a0 Randomly rotating your training images can help with the rotational invariance mentioned above.\u00a0 You can also flip your images, change their scale, and even crop them as long as the feature in the training sample remains.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can gain several benefits from applying geometric transformations to your training data.  If your features can appear at different sizes, scaling transforms can help your model become better generalized on feature size.  With LiDAR data, suppose someone did not generate the scene with North at the top.  Here, random rotations can help the model generalize to rotation so it can better detect features regardless of angle.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Spatial Relationships<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Regardless of what type of augmentations you apply to LiDAR, you have to be mindful that you do not change the spatial characteristics of the data.  Consider color space augmentation, something that is common with other areas of deep learning and computer vision.  With LiDAR, modifying the brightness\/contrast would actually be changing the elevation and\/or reflectance values of the data.  In some applications, especially those highly based on reflectance values such as detecting types of vegetation, this might be useful.  In high-resolution geography, you could end up altering the training data in such a way that it no longer represents real-world features.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I think I will end this one here as it got longer than I expected and I\u2019m tired of typing \ud83d\ude09\u00a0 Next time I\u2019ll cover issues with image processing libraries and 32-bit LiDAR data.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In part one I described some of the issues I had on a recent project that applied deep learning to geographic feature recognition in LiDAR and the file sizes of such data.\u00a0 This time I want to talk about training &hellip; <a href=\"https:\/\/brian.digitalmaddox.com\/blog\/?p=723\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":725,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,3],"tags":[],"class_list":["post-723","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gis","category-opencv"],"_links":{"self":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/723","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=723"}],"version-history":[{"count":1,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/723\/revisions"}],"predecessor-version":[{"id":726,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/723\/revisions\/726"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/725"}],"wp:attachment":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}