<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>thetestspecimen</title>
	<subtitle>testing the world</subtitle>
	
	<link href="https://www.thetestspecimen.com/feed/feed.xml" rel="self"/>
	<link href="https://www.thetestspecimen.com"/>
	<updated>Tue, 30 Dec 2025 00:00:00 GMT</updated>
	<id>https://www.thetestspecimen.com</id>
	<author>
		<name>thetestspecimen</name>
		<email></email>
	</author>
	
	<entry>
		<title>Crowdfunding – What Is It and Are Sites Like Kickstarter Safe?</title>
		<link href="https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/"/>
		<updated>Tue, 22 Mar 2016 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Crowdfunding is an exciting way of purchasing cutting edge design and technology, whilst also getting hands on in the development of some interesting and unusual ideas that typical investment routes may not favour or produce.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The question is, whether crowdfunding is an exciting and enjoyable journey, or a black hole of lost money and bad experiences?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In my experience, if you know what to expect before you jump in, it can be exciting and worthwhile, and you will end up with some unique and exclusive items!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the time of writing I have backed 20 separate projects on Kickstarter (&lt;a href=&quot;https://www.kickstarter.com/profile/testspecimen&quot;&gt;My backed projects&lt;/a&gt;) since I opened my account in Aug 2014. In that time I have backed projects ranging in value from £14 up to $495. This gives me a reasonable view of the ins and outs of the process.&lt;/p&gt;
&lt;p&gt;In this article I have outlined my experiences and attempted to point out some of the pitfalls and bad assumptions people tend to make the first time they use crowdfunding.&lt;/p&gt;
&lt;p&gt;I hope this article will help you avoid the common mistakes and get on with enjoying the rewards!&lt;/p&gt;
&lt;h2 id=&quot;what-is-crowdfunding%3F&quot; tabindex=&quot;-1&quot;&gt;What is Crowdfunding? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#what-is-crowdfunding%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Typically when you have a great idea, but not enough cash to make it happen, you need to get yourself an investor. Traditionally this meant pitching your idea to some rich guys or gals (think &lt;a href=&quot;https://www.bbc.co.uk/programmes/b006vq92&quot;&gt;Dragons Den&lt;/a&gt;) who then decided whether it was feasible or not as an investment. Your idea may be a great idea, but it might have niche or limited appeal, thus limiting overall value to an investor. It could also be something that traditional investors don&#39;t have the foresight to appreciate, like cutting edge technology.&lt;/p&gt;
&lt;p&gt;This is where crowdfunding comes in.&lt;/p&gt;
&lt;p&gt;Crowdfunding allows you to generate the money you need, but rather than one or two investors investing a large amount of money, it involves a large amount of investors investing a small amount of money. Same outcome, different method. This has a few advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If enough people are willing to stump up money to make your idea a reality, then maybe it IS a good idea&lt;/li&gt;
&lt;li&gt;You gain the money you need to make the idea a reality&lt;/li&gt;
&lt;li&gt;You have a large community to gain ideas and feedback from&lt;/li&gt;
&lt;li&gt;You have your first batch of customers already (assuming you are producing something)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;where-can-i-go-to-get-involved%3F&quot; tabindex=&quot;-1&quot;&gt;Where can I go to get involved? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#where-can-i-go-to-get-involved%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to get involved in crowdfunding there are two main places that you should probably start with. The first is called Kickstarter:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.kickstarter.com/&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/kickstarter/kickstarter-logo.png&quot; alt=&quot;Kickstarter&quot; title=&quot;Kickstarter&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;...and the second is called Indiegogo:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiegogo.com/&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/kickstarter/indiegogo-logo.png&quot; alt=&quot;Indiegogo&quot; title=&quot;Indiegogo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are probably more crowdfunding websites out there, but these two have both been around a while and tend to dominate. In terms of my experience with crowdfunding, I have only actively used Kickstarter, so all of my comments in this article are based on my experiences there. Although the basic principles and ideas are the same on both sites.&lt;/p&gt;
&lt;h2 id=&quot;so-how-does-it-work%2C-and-what-do-i-get-in-return%3F&quot; tabindex=&quot;-1&quot;&gt;So how does it work, and what do I get in return? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#so-how-does-it-work%2C-and-what-do-i-get-in-return%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Basically, the way it works is that the creator of the product provides information on what they intend to create or provide to you. They also state the minimum total amount of money they need to allow the project to become a reality.&lt;/p&gt;
&lt;p&gt;The creator also sets up the &amp;quot;rewards&amp;quot; they will provide if you &amp;quot;pledge&amp;quot; a certain amount of money (you could effectively read &amp;quot;reward&amp;quot; as &amp;quot;product&amp;quot; and &amp;quot;pledge&amp;quot; as &amp;quot;give them&amp;quot;). It should be noted that both the reward and the amount it will cost is set by the creator, not you, and is typically representative of the items value.&lt;/p&gt;
&lt;p&gt;Once the campaign is started by the creator people are allowed to pledge money through the &amp;quot;pledge levels&amp;quot; (see the next section for details) for a set amount of time (usually a month). Over this time, the creator must get enough people to pledge money to support their product to ensure they achieve the monetary target they set at the beginning of their campaign.&lt;/p&gt;
&lt;p&gt;If they don&#39;t reach the target, the campaign fails, nobody is charged any money, and the creator doesn&#39;t have to create the product. However, if the target is reached by the end of the campaign the money is taken from all the backers and given to the creator, who is then contractually obliged to (at least attempt) to produce or create what they set out in the campaign.&lt;/p&gt;
&lt;p&gt;You can see an example below of some of the information provided. I have pixilated the names and pictures as this campaign is live at the moment, and as I know nothing about the product I would rather not unintentionally promote it!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5246 backers&lt;/li&gt;
&lt;li&gt;the target was to raise $100,000 and so far they have $1,323,124 so it certain this campaign will be successful unless a large majority of the backers pull out at the last minute&lt;/li&gt;
&lt;li&gt;there are 29 days left before the campaign closes. At that point the money is taken and the creation of the product begins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/kickstarter/kickstarter-live-project.jpg&quot; alt=&quot;Example Live&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It should be noted that if you back a campaign you will not be charged any money until the campaign finishes. Up until the campaign finishes you can cancel your pledge and you will not be charged any money.&lt;/p&gt;
&lt;p&gt;However, once the campaign finishes you will be charged for the product and cannot get a refund unless the creator agrees to refund your money or is proved to be fraudulent. At which point you would effectively need to take the appropriate legal action.&lt;/p&gt;
&lt;h2 id=&quot;what-are-reward%2Fpledge-levels-and-how-do-they-work%3F&quot; tabindex=&quot;-1&quot;&gt;What are reward/pledge levels and how do they work? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#what-are-reward%2Fpledge-levels-and-how-do-they-work%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The pledge/reward levels are set up by the creator to give you some choice, as you are only allowed to select a single pledge level. The different pledge levels are a combination of the following (I have used the Pebble Time campaign as an example due to its popularity and the fact it is now finished &lt;a href=&quot;https://www.kickstarter.com/projects/597507018/pebble-time-awesome-smartwatch-no-compromises/description&quot;&gt;link&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lower prices for backing the campaign early. Usually called &amp;quot;early bird&amp;quot; and have a limited availability. If the product is popular these places will disappear fast!&lt;/li&gt;
&lt;li&gt;Different products. For example with the Pebble Time, there was the basic &amp;quot;Pebble Time&amp;quot; and the premium &amp;quot;Pebble Time Steel&amp;quot;&lt;/li&gt;
&lt;li&gt;Multiples of the same product. As you are only allowed to select a single reward/pledge this means you cannot, for example, get multiples of the same product. To get around this creators will often make a pledge level that allows the purchase of multiples. For example, one of the pledge levels may say &amp;quot;2 Pebble Time Steel Watches&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/kickstarter/kickstarter-pebble.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/kickstarter/kickstarter-pebble.jpg&quot; alt=&quot;Crowdfunding&quot; title=&quot;crowdfunding, kickstarter&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You may have noticed in the above picture that the pledge prices actually have &amp;quot;or more&amp;quot; appended to the end of the price. What this effectively means is that the minimum you can pledge to receive the stated reward is, in the example above, $179, but you can pledge more if you wish.&lt;/p&gt;
&lt;p&gt;As mentioned earlier, you can only select one pledge level, and you will only receive what is detailed in that pledge. If you select a pledge level, and then pledge twice the money in the hope you can have two, you will be disappointed...so be careful!&lt;/p&gt;
&lt;h2 id=&quot;so-how-is-this-different-from-buying-something-from-an-online-shop%3F&quot; tabindex=&quot;-1&quot;&gt;So how is this different from buying something from an online shop? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#so-how-is-this-different-from-buying-something-from-an-online-shop%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well...this is a very important point, and often the main cause of people&#39;s complaint with the whole process. Crowdfunding is definitely &lt;strong&gt;not&lt;/strong&gt; the same as buying something from Amazon or any other online retailer. The main reason for this is the time that you will have to wait to receive the product.&lt;/p&gt;
&lt;p&gt;Each campaign will state a date they expect to deliver the product to your door. For example in the pebble campaign above you can see that the delivery date given was stated as &amp;quot;May 2015&amp;quot;. For my particular reward on the Pebble Time campaign I had an expected delivery of &amp;quot;July 2015&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/kickstarter/my-reward-level.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/kickstarter/my-reward-level.jpg&quot; alt=&quot;Reward Selection&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When did I receive the reward? Well although I can&#39;t remember the exact day they landed at my door, I received the tracking email 16th September 2015...so my guess would be around the 25th September 2015...and it doesn&#39;t end there. That is only when PART of the reward landed at my door. The &amp;quot;extra metal strap&amp;quot; mentioned above was delayed further due to production issues.&lt;/p&gt;
&lt;p&gt;...so on a campaign that was run by a company that has used kickstarter previously to launch their original smartwatch (the original &lt;a href=&quot;https://www.kickstarter.com/projects/597507018/pebble-e-paper-watch-for-iphone-and-android&quot;&gt;Pebble&lt;/a&gt;). They managed to provide an estimated date that was wrong by approximately one and a half months, and had further delays beyond that...and that was my specific delay, which will have been longer for some people.&lt;/p&gt;
&lt;p&gt;My point is that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;if you look something up on a crowdfunding website and are expecting to be able to have it in a short space of time, crowdfunding is &lt;strong&gt;not&lt;/strong&gt; for you&lt;/li&gt;
&lt;li&gt;if you are willing to wait until the estimated delivery date but no longer, crowdfunding is &lt;strong&gt;not&lt;/strong&gt; for you&lt;/li&gt;
&lt;li&gt;if you want the item to replace something, and need it within a set timeframe, crowdfunding is &lt;strong&gt;not&lt;/strong&gt; for you&lt;/li&gt;
&lt;li&gt;I would also not advise getting something from crowdfunding as a present for someone as you may overshoot the date&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Patience is essential, otherwise you are going to go crazy! I can only think of one campaign where I received my reward on time.&lt;/p&gt;
&lt;p&gt;...and currently I have a project I have backed that had an estimated delivery of April 2015. I still don&#39;t have the reward, and don&#39;t expect to get it till &lt;em&gt;maybe&lt;/em&gt; later this year!&lt;/p&gt;
&lt;h2 id=&quot;is-it-possible-for-me-to-lose-my-money%3F&quot; tabindex=&quot;-1&quot;&gt;Is it possible for me to lose my money? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#is-it-possible-for-me-to-lose-my-money%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The short answer is yes...and I have lost money (although not a lot).&lt;/p&gt;
&lt;p&gt;Of the 20 projects I have backed so far I have lost my money on one of them. The project creator turned out to be a fraud, and although has promised to return my money has yet to do so (I&#39;m not holding my breath!). In theory I could take this up with the authorities, as all project creators are bound by certain terms and conditions, but the monetary value was so small it wasn&#39;t worth my time. Although, some projects have been investigated as you can see &lt;a href=&quot;https://www.cnet.com/news/ftc-goes-after-fraudulent-board-game-kickstarter/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You may now be thinking that this is too risky? All I would say is that if you want to back something on a crowdfunding website common sense tends to prevail.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out the creators behind the project. Although they don&#39;t have to, it is typical that they are open and willing to expose their personal or company&#39;s identity. If not I would be suspicious&lt;/li&gt;
&lt;li&gt;As with many things, if it sounds too good to be true it probably is&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Any potentially risky items I have backed on kickstarter have been of low value. The higher value items were from established companies or traceable and easily checkable people. I would advise you to use the same approach. If you stick to this you won&#39;t go far wrong.&lt;/p&gt;
&lt;h2 id=&quot;it-is-less-convenient-than-an-online-shop%2C-and-potentially-i-could-lose-my-money%2C-so-why-would-i-bother%3F&quot; tabindex=&quot;-1&quot;&gt;It is less convenient than an online shop, and potentially I could lose my money, so why would I bother? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#it-is-less-convenient-than-an-online-shop%2C-and-potentially-i-could-lose-my-money%2C-so-why-would-i-bother%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ok so now we get to the plus sides!&lt;/p&gt;
&lt;p&gt;It is not an accident that I keep backing projects on kickstarter. I enjoy the process.&lt;/p&gt;
&lt;p&gt;Here are the main reasons I use kickstarter:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I can find items that are simply not available anywhere else, either online or in my local shops. This is either because they are bespoke and unique ideas, or are pushing current technological boundaries&lt;/li&gt;
&lt;li&gt;The price you get the product for is typically reduced compared to the retail price of the product after launch&lt;/li&gt;
&lt;li&gt;You will be the first users of the new product&lt;/li&gt;
&lt;li&gt;If the campaign is run correctly you will, at least to some degree, be able to influence the direction of the product. For example a current product I am backing has a unique colour scheme that was selected by the backers (and will only ever be available to the backers, never to retail customers)&lt;/li&gt;
&lt;li&gt;In some cases you know that you have contributed to the start of a small company. Which can never be a bad thing!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To sum up, I would say that if you are interested in purchasing unique products, and are willing to be patient, crowdfunding can be an enjoyable journey. As long as you are sensible about the products you choose to back, and stick within the limits of what you can easily afford, you are unlikely to have many (if any) problems...and at the end of the day (or maybe at the end of the year!) you will receive a unique product that in at least a small way &lt;strong&gt;you&lt;/strong&gt; helped to shape and create!&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Nextbit Robin Smartphone – Kickstarter Edition (Unboxing and Photos)</title>
		<link href="https://www.thetestspecimen.com/posts/nextbit-robin-smartphone-kickstarter-edition/"/>
		<updated>Wed, 30 Mar 2016 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/nextbit-robin-smartphone-kickstarter-edition/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;In the latter part of last year I backed a Kickstarter project for a new phone called Robin, by a new startup called Nextbit. This article details the phone and accessories I received in the form of an unboxing video and photos, with some basic specs. I will provide a more thorough review once I have used the phone for a while.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can check out the Kickstarter campaign page or their website here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.kickstarter.com/projects/nextbit/robin-the-smarter-smartphone&quot;&gt;Kickstarter&lt;/a&gt; and/or &lt;a href=&quot;https://www.nextbit.com/&quot;&gt;Main Website&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;nextbit-robin---specification-and-features&quot; tabindex=&quot;-1&quot;&gt;Nextbit Robin - Specification and Features &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-smartphone-kickstarter-edition/#nextbit-robin---specification-and-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The phone is basically an android smartphone with a unique twist. The phone has a fairly standard 32GB of internal storage, but it also has 100GB of storage (for free) available in the cloud. Although I am not going to go into detail in this article I have provided a direct link to the specs of the phone here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nextbit.com/pages/specs/&quot;&gt;Specification&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;nextbit-robin---unboxing-video-and-photos&quot; tabindex=&quot;-1&quot;&gt;Nextbit Robin - Unboxing Video and Photos &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-smartphone-kickstarter-edition/#nextbit-robin---unboxing-video-and-photos&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have made a video available on youtube which shows the unboxing of the phone and accessories. The video was shot at night, in a rush, on my birthday, so I apologise for the bad light. It should however show you what you need.&lt;/p&gt;
&lt;p&gt;Since then I have taken some photos (in daylight) which should give you a bit more detail (see below for those).&lt;/p&gt;
&lt;p&gt;Just for reference the photos and video detail the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Nextbit Robin Phone in the electric colorway/scheme - This colour scheme is exclusive to kickstarter, so is now unavailable, but you can still get the mint and midnight colorways detailed on the nextbit website&lt;/li&gt;
&lt;li&gt;Bumps Fog Case&lt;/li&gt;
&lt;li&gt;Scratches Frost Case&lt;/li&gt;
&lt;li&gt;Quick Charger (EU version)&lt;/li&gt;
&lt;li&gt;Glass screen protector&lt;/li&gt;
&lt;li&gt;Nextbit T-shirt&lt;/li&gt;
&lt;li&gt;Very special SIM tray (Gold)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will provide more details on the phones software and general day to day usage once I have used the phone for a while, and if you have read this article and don&#39;t know what Kickstarter is you can check out my article which explains this &lt;a href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please let me know if you want any further details/photos in the comments, and share if you like!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=N0DpDlNoaTc&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/N0DpDlNoaTc/0.jpg&quot; alt=&quot;Nextbit Robin video&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Unboxing video&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1869-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1869-Large.jpg&quot; alt=&quot;Front of the Nextbit Robin&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Front of the Nextbit Robin&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1872-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1872-Large.jpg&quot; alt=&quot;Back of the Nextbit Robin&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Back of the Nextbit Robin&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1874-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1874-Large.jpg&quot; alt=&quot;Camera and flash&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Camera and flash&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1875-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1875-Large.jpg&quot; alt=&quot;Nextbit&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1879-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1879-Large.jpg&quot; alt=&quot;Very special gold SIM tray&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Very special gold SIM tray&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1877-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1877-Large.jpg&quot; alt=&quot;IMG_1877 (Large)&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Here you can see the glass screen protector installed. It is a good fit and fairly thin, you can just about see the lip it creates. It only covers the glass, not the top and bottom of the phone.&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1867-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1867-Large.jpg&quot; alt=&quot;Top of the phone showing the headphone jack, also featuring the bumps fog case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Top of the phone showing the headphone jack, also featuring the bumps fog case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1866-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1866-Large.jpg&quot; alt=&quot;Bottom of the phone showing the USB type C port and microphone, also featuring the fog bumps case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Bottom of the phone showing the USB type C port and microphone, also featuring the fog bumps case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1859-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1859-Large.jpg&quot; alt=&quot;Nextbit Robin front with fog bumps case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit Robin front with fog bumps case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1861-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1861-Large.jpg&quot; alt=&quot;Nextbit Robin back with fog bumps case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit Robin back with fog bumps case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1864-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1864-Large.jpg&quot; alt=&quot;Nextbit Robin side showing the volume buttons and featuring the fog bumps case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit Robin side showing the volume buttons and featuring the fog bumps case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1863-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1863-Large.jpg&quot; alt=&quot;Power button and fingerprint scanner&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit Robin side showing the power button (also a fingerprint scanner) and featuring fog bumps case&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1880-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1880-Large.jpg&quot; alt=&quot;Scratches frost case from the back&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Scratches frost case from the back&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1882-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1882-Large.jpg&quot; alt=&quot;Scratches fog case top&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Scratches fog case top&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1883-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1883-Large.jpg&quot; alt=&quot;scratches frost case bottom&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Scratches frost case bottom&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1885-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1885-Large.jpg&quot; alt=&quot;Nextbit t-shirt front&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit t-shirt front&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1886-Large.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/IMG_1886-Large.jpg&quot; alt=&quot;Nextbit t-shirt back&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nextbit t-shirt back&lt;/figcaption&gt;

		</content>
	</entry>
	
	<entry>
		<title>Nextbit Robin – Software Review and 3rd Party Launchers (Nova)</title>
		<link href="https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/"/>
		<updated>Sun, 17 Apr 2016 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;The Nextbit Robin incorporates 100GB of free, automatically organised, cloud storage as part of the phone purchase. To integrate this functionality into the phone Nexbit has created a unique launcher which ships with the phone.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The question is: How good is the launcher, and if you don&#39;t like it is there an alternative without losing cloud functionality?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;...so-what-is-the-answer%3F&quot; tabindex=&quot;-1&quot;&gt;...So what is the answer? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#...so-what-is-the-answer%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well to put it bluntly, the Nextbit Robin&#39;s launcher is somewhat lacking in areas that I wasn&#39;t expecting (more details below)...fortunately alternative launchers can be used and cloud functionality will work. The downside is that some of the design features integrated into the Nextbit Robin&#39;s native launcher do not transfer over to the 3rd party launcher. This means app management in terms of cloud storage can become cumbersome.&lt;/p&gt;
&lt;p&gt;It seems, for the moment at least, whether you stick with the native launcher or move to a third party launcher you will have to compromise at some level.&lt;/p&gt;
&lt;p&gt;Checkout the video below which runs through the basic launcher functionality, and then goes on to discuss how Nova launcher functions on the Robin. If you would rather not watch the video I have included some screenshots in the article below to cover the same areas:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=y-jtzbB6cws&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/y-jtzbB6cws/0.jpg&quot; alt=&quot;Nextbit Robin video&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-nextbit-robin%3F&quot; tabindex=&quot;-1&quot;&gt;What is the Nextbit Robin? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#what-is-the-nextbit-robin%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want a brief overview of what the Nextbit Robin is about you can check out my previous article here &lt;a href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-smartphone-kickstarter-edition/&quot;&gt;Nextbit Robin&lt;/a&gt;. You can find out more about Kickstarter, which is the platform the Nextbit Robin was launched on here &lt;a href=&quot;https://www.thetestspecimen.com/posts/crowdfunding-kickstarter/&quot;&gt;Kickstarter&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-exactly-is-this-a-cloud-phone%3F&quot; tabindex=&quot;-1&quot;&gt;How exactly is this a cloud phone? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#how-exactly-is-this-a-cloud-phone%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The robin comes with 32GB of onboard storage, but your apps and photos are automatically uploaded to the 100GB of cloud storage (I believe this should also be possible with videos in the near future).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-1.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-1.jpg&quot; alt=&quot;Robin Screen Shots&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Cloud Storage and Archived Apps&lt;/figcaption&gt;
&lt;p&gt;The basic idea is that the phone manages your photos and apps for you between the cloud and local storage, so you don&#39;t have to worry about running out of space. You could break this down into two areas:&lt;/p&gt;
&lt;h3 id=&quot;photos&quot; tabindex=&quot;-1&quot;&gt;Photos &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#photos&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I like how the photos are handled, it is quite clever. You take a photo, the phone uploads the full resolution photo to the cloud, leaving you with a downsized version (I believe 1080p, i.e. screen resolution) on your phone locally. If you think about it, this is perfect for on phone browsing. Should you then want to share an image the smart storage will automatically send the full res version when you attach it to an email or share.&lt;/p&gt;
&lt;h3 id=&quot;apps&quot; tabindex=&quot;-1&quot;&gt;Apps &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#apps&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Applications are handled a little differently. Should you start to run out of storage locally the phone will start to delete apps off your phone (don&#39;t panic they are still in the cloud!). It starts with the least used apps and moves up the list from there. The icon for the app stays on the phone, but is greyed. Should you want the app back, just tap the grey icon and it comes back with all the app data too! As if you never uninstalled it, so no need to sign into the app again.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-3.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-3.jpg&quot; alt=&quot;Robin Restore App&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Restoring Snapchat&lt;/figcaption&gt;
&lt;h2 id=&quot;what-about-the-native-launcher%3F&quot; tabindex=&quot;-1&quot;&gt;What about the native launcher? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#what-about-the-native-launcher%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &amp;quot;Nextbit&amp;quot; launcher that comes with the phone is somewhat lacking in my opinion. In many ways it is a few backward steps in terms of ease of use and functionality considering how far the android ecosystem has now come. The best way I can think of describing the implementation of the launcher is &amp;quot;iphone like&amp;quot;. If that&#39;s your thing great, but I think it fails in terms of functionality.&lt;/p&gt;
&lt;p&gt;Consider what this phone is designed for. It is designed with 32GB of onboard storage, with an extra 100GB in the cloud. Great! So this would imply that the people it is aimed at are heavy users of storage. This could of course be in terms of videos (not yet supported) or photos only, but it is likely that it will also involve a reasonable number of apps.&lt;/p&gt;
&lt;p&gt;If this launcher was designed with use of a large amount of apps in mind I am struggling to see how this went through development without an issue. Then there is the implementation of the widgets... Here are some of my issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is no app draw, so all apps live on the home screens&lt;/li&gt;
&lt;li&gt;There is a sort of app draw available using the purple button which sticks to each homescreen in the bottom right, but it is just a vertically scrolling list of alphabetically sorted apps, and no way to search it quickly!&lt;/li&gt;
&lt;li&gt;As I have mentioned, the homescreen is just for apps, so where are the widgets? Well if you pinch the screen you can see (and add to) the widgets. Basically they are not visible unless you pinch gesture. Really! I thought the whole point of widgets was to serve up information from within apps so it is visible easily ON the homescreens not BEHIND them?!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In terms of other functionality of the launcher:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You swipe down on an app icon to &amp;quot;pin&amp;quot; it. This means the app will never be removed off the phone even if you run out of space&lt;/li&gt;
&lt;li&gt;There are three separate lists of apps under the purple button, which show you archived, pinned and all apps, so you know what the status of each app is&lt;/li&gt;
&lt;li&gt;You can bulk restore or completely uninstall archived apps (see screenshots below)&lt;/li&gt;
&lt;li&gt;You can bulk unpin apps (see screenshots below)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of the three issues I have mentioned above, it is number three that really baffles me. I can only assume that Nextbit came up with a way of integrating their cloud functionality by having interactive apps on the home screens (to allow pinning of apps by down-swiping an app icon, see the video for a demonstration) and then couldn&#39;t figure out what to do with the widgets.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-2.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-2.jpg&quot; alt=&quot;Robin Purple Button&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Purple button menu and all apps and archived apps &quot;draw&quot;&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-4.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-4.jpg&quot; alt=&quot;Mixture of robin screenshots&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Restoration message, pinned apps &quot;draw&quot; and widgets screen&lt;/figcaption&gt;
&lt;h2 id=&quot;can-i-use-a-different-launcher-such-as-nova-launcher%2C-and-what-happens-to-the-cloud-functions-when-i-do%3F&quot; tabindex=&quot;-1&quot;&gt;Can I use a different launcher such as Nova Launcher, and what happens to the cloud functions when I do? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#can-i-use-a-different-launcher-such-as-nova-launcher%2C-and-what-happens-to-the-cloud-functions-when-i-do%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simple answer is: yes you can, and the cloud functions will work (with a few caveats).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-5.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/nextbit-robin/Robin-Combined-Images-5.jpg&quot; alt=&quot;Nova Launcher App Drawer&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Nova Launcher App Drawer&lt;/figcaption&gt;
&lt;p&gt;Nova launcher works as expected, but the important question is how the cloud features work.&lt;/p&gt;
&lt;p&gt;As you can see from the image above, the application icons do grey out when they are offloaded to the cloud, which is great. I currently have my nova launcher app draw setup with tabs across the top. What happens when the phone archives an app, is that it moves from a specific tab, for example &amp;quot;Games&amp;quot;, to the &amp;quot;Apps&amp;quot; tab. When you restore the app it goes back to correct tab. Which I suspect is more to do with Novas settings than the phones.&lt;/p&gt;
&lt;p&gt;If you want to restore an app you just tap the greyed icon and it will be brought back down to your phone. You won&#39;t see the nice reloading animation that you get with the Nextbit launcher (see the images above with snapchat), but it performs the same function at the end of the day.&lt;/p&gt;
&lt;p&gt;Another problem with restoring apps from Nova Launcher is that you can only do them one by one (i.e. you can&#39;t restore all or queue them)...which is tedious if you have many apps to restore.&lt;/p&gt;
&lt;p&gt;Another problem occurs when you want to pin apps. You would usually achieve this by swiping down on the icons on the homescreen to pin an app. As far as I can tell this doesn&#39;t work in Nova Launcher, and there seems to be no way to do this from any settings menu. Your only option is to go into the Nextbit Launcher, pin the apps you want, and then go back to Nova Launcher.&lt;/p&gt;
&lt;p&gt;You also have no way of seeing which apps are pinned without switching launcher.&lt;/p&gt;
&lt;p&gt;That is about it, but it amounts to losing quite a few convenient features of the Nextbit Launcher that make the extra cloud features easy to use.&lt;/p&gt;
&lt;h2 id=&quot;anything-else-i-should-be-careful-of%3F&quot; tabindex=&quot;-1&quot;&gt;Anything else I should be careful of? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#anything-else-i-should-be-careful-of%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yes.&lt;/p&gt;
&lt;p&gt;One thing I noticed when testing out the cloud storage is that if you start to run out of local storage space there are some applications that the phone started to automatically archive that I didn&#39;t want it to, but hadn&#39;t thought of. Basically, any apps that you use all the time, but never open. Examples of this in my case are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Any license checker apps (Nova launcher prime in my case)&lt;/li&gt;
&lt;li&gt;Any live wallpaper apps (Chrooma in my case)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because the phone is ranking the apps in terms of usage, the above types of apps that are required but never opened are seen as the least used apps, and therefore are the first to be archived. I would recommend going through your apps and pinning the apps that fall into this category so you don&#39;t, for example, lose your wallpaper suddenly as happened to me!&lt;/p&gt;
&lt;h2 id=&quot;in-conclusion&quot; tabindex=&quot;-1&quot;&gt;In conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/nextbit-robin-launcher-review-nova/#in-conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The phone itself has a unique design and is well made. The implementation of the cloud storage has potential, but at the moment it is a little lacking in features (video archiving) and I think the launcher is a step in the wrong direction. If the development continues I can see the potential, so hopefully the next iteration will be one to watch out for.&lt;/p&gt;
&lt;p&gt;Would I recommend the phone? Yes I would, but because of the style of the phone, build quality, barebones android implementation, unlocked network and bootloader; not necessarily for the cloud storage feature.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>My Android App Development Journey (So Far), and Some Guidance for Others</title>
		<link href="https://www.thetestspecimen.com/posts/android-app-journey/"/>
		<updated>Sun, 12 Aug 2018 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/android-app-journey/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;About a year and a half ago I decided that I wanted to try something new. I love learning new skills and I wanted something to focus my mind and give myself a new challenge. I decided the &amp;quot;thing&amp;quot; would be to try and learn to computer program, but where to start? Well I did start and (while I can still remember) I wanted to write down some of the experiences, frustrations and successes of the last year and half, so that I can look back at them, but also to try and help others that might want to start the same journey.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is my journey from not knowing how to code, to publishing a fully working &lt;a href=&quot;http://play.google.com/store/apps/details?id=com.thetestspecimen.wanderfile&quot;&gt;android application&lt;/a&gt; on the Google play store (more info about the app at the website &lt;a href=&quot;https://wanderfile.app/&quot;&gt;here&lt;/a&gt;). I hope you find it useful.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-computer-programming%3F&quot; tabindex=&quot;-1&quot;&gt;Why computer programming? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#why-computer-programming%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a couple of reasons:&lt;/p&gt;
&lt;h3 id=&quot;i-like-technical-subjects&quot; tabindex=&quot;-1&quot;&gt;I like technical subjects &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#i-like-technical-subjects&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&#39;m an engineer by trade, and this means that I&#39;m generally quite good at technical type subjects that involve logic, problem solving and patience. I would say computer programming falls into this category.&lt;/p&gt;
&lt;h3 id=&quot;accessibility&quot; tabindex=&quot;-1&quot;&gt;Accessibility &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#accessibility&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The other main reason is accessibility. What I mean by this is that, typically, at least in western countries, a computer is already available to most people. The information available on the internet is also extensive, especially with regard to computer programming.&lt;/p&gt;
&lt;p&gt;Overall this means that with little to no outlay you can begin, and likely complete, what you set out to do.&lt;/p&gt;
&lt;h2 id=&quot;why-did-you-pick-android%3F&quot; tabindex=&quot;-1&quot;&gt;Why did you pick Android? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#why-did-you-pick-android%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was initially one of the sticking points. There are hundreds, if not thousands of programming languages to choose from, and there are new ones coming out all the time. So how do you pick?&lt;/p&gt;
&lt;h3 id=&quot;my-criteria&quot; tabindex=&quot;-1&quot;&gt;My criteria &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#my-criteria&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I decided the best way to approach it was to set some high level goals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I must be able to produce something complete by the end (i.e. a complete app or program that I can actually use, not some abstract code)&lt;/li&gt;
&lt;li&gt;The tools to build the application or program to completion must be free&lt;/li&gt;
&lt;li&gt;It needs to be mainstream enough that I will have enough resources available to successfully learn. Otherwise frustration or boredom (or both) will likely set in&lt;/li&gt;
&lt;li&gt;It should be a good representation of current modern programming languages so that I can potentially move forward with other languages at a later date&lt;/li&gt;
&lt;li&gt;It should be as self contained as possible. I wanted to avoid any confusion that will likely come from having to get my head around which tools are required to accomplish the job. I wanted to concentrate on learning to code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using the above criteria I did some research...&lt;/p&gt;
&lt;h3 id=&quot;thinning-it-out&quot; tabindex=&quot;-1&quot;&gt;Thinning it out &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#thinning-it-out&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first port of call was potentially web development (i.e. making a website). I threw this out quite quickly as the ecosystem is very complex. It would require the knowledge of HTML, css, php, javascript (and more...) and the tools to deal with these are even more numerous and fast evolving. I needed something more contained...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/coding-on-computer.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/coding-on-computer.jpg&quot; alt=&quot;Laptop with code&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It needed to be a program or app. I could therefore pick a platform:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iOS (requires monetary outlay as I have no apple devices, and an annual fee to release an app)&lt;/li&gt;
&lt;li&gt;Mac (requires outlay for a device)&lt;/li&gt;
&lt;li&gt;Windows (maybe, but the tools I would use to make it were not clear enough, and C++ is maybe not the best beginner language)&lt;/li&gt;
&lt;li&gt;Linux (not familiar enough with the platform)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-decision&quot; tabindex=&quot;-1&quot;&gt;The decision &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#the-decision&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;...which left Android:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I have many android devices already, so I&#39;m familiar with the platform usage and will have no hardware outlay&lt;/li&gt;
&lt;li&gt;Android Studio (the program used to make android apps) is free and self contained. You only need to use that one program, and you can output a complete working app.&lt;/li&gt;
&lt;li&gt;It uses only two languages. Java and XML, which keeps it simple. Note: you can also use Kotlin, a new language, but it wasn&#39;t available when I started out.&lt;/li&gt;
&lt;li&gt;Java is a good representation of a modern language, and one of the most utilised programming languages in the world&lt;/li&gt;
&lt;li&gt;There are extensive tutorial videos and websites on how to code in Java AND how to make an Android application. I should therefore be set in terms of learning material&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now I had that out of the way, how to start?&lt;/p&gt;
&lt;h2 id=&quot;where-did-you-begin%3F&quot; tabindex=&quot;-1&quot;&gt;Where did you begin? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#where-did-you-begin%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think this is a good point at which to state my level of knowledge with regard to computer programming before I started.&lt;/p&gt;
&lt;p&gt;Mainly through my experience as an Engineer I had some basic knowledge of what a for loop and if statement were through usage within Microsoft Excel VBA macros (don&#39;t worry if you have no idea what that is, it doesn&#39;t really matter). I didn&#39;t write the macros, rather adjusted macros that were automatically generated by excel. We are talking really basic stuff...&lt;/p&gt;
&lt;p&gt;If you know what things like strings and ints are then you are way ahead of where I was. If not, don&#39;t worry, neither did I!&lt;/p&gt;
&lt;h3 id=&quot;learning-the-basics&quot; tabindex=&quot;-1&quot;&gt;Learning the basics &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#learning-the-basics&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the above in mind I thought the best place to start would be with Java. Java is the main thing I would be using while writing an android application, so this seemed sensible. I needed to start from the basics. Now I know this was a good choice, as it made following the android tutorials that much easier later on.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/programming.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/programming.jpg&quot; alt=&quot;Code on screen&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I started searching for places I could start to learn Java. Probably the best place to start is with online videos. There are many on youtube, but you can also find some great courses on sites like &lt;a href=&quot;https://www.udemy.com/&quot;&gt;udemy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I spent a long time jumping between different courses (some are terrible and hard to follow) and youtube can also be hit and miss, but I am going to make a solid recommendation.&lt;/p&gt;
&lt;h4 id=&quot;recommendation&quot; tabindex=&quot;-1&quot;&gt;Recommendation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#recommendation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There is an Australian developer who produces online tutorials called &lt;a href=&quot;https://www.udemy.com/user/timbuchalka/&quot;&gt;Tim Buchalka&lt;/a&gt;. His videos are easily the best I have seen, and as a plus, he has video courses on both Java AND Android development (and Kotlin now too). Both are excellent. They are not free, so this may not be an option for some, which is fine, but if you can spend a small amount then you won&#39;t regret it (his Complete Java Development Course is currently EUR 9.99 on udemy just to give you and idea of price). [I also want to make it absolutely clear that I am not affiliated with either Udemy or Tim Buchalka, and receive no kickback from either.&lt;/p&gt;
&lt;h4 id=&quot;practise-makes-perfect&quot; tabindex=&quot;-1&quot;&gt;Practise makes perfect &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#practise-makes-perfect&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Whether you decide to go with the video suggestion above or with text books, there is one thing that you absolutely must do, and that is actually write the code yourself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can sit for hours reading and watching videos, but it will be no use if you don&#39;t actually put it into practice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can sit for hours reading and watching videos, but it will be no use if you don&#39;t actually put it into practice. I cannot stress this enough, it is essential!&lt;/p&gt;
&lt;h2 id=&quot;which-software-did-you-use%3F&quot; tabindex=&quot;-1&quot;&gt;Which software did you use? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#which-software-did-you-use%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For Android it is easy, you use &lt;a href=&quot;https://developer.android.com/studio/&quot;&gt;Android Studio&lt;/a&gt;. You can download it for free directly from Google. You will literally never have to use any other software if you don&#39;t want to.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/android_studio.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/android_studio.png&quot; alt=&quot;Android Studio&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;other-useful-software&quot; tabindex=&quot;-1&quot;&gt;Other useful software &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#other-useful-software&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is however useful when you are learning Java (or Kotlin) to have an interface that is just for Java and not cluttered by all the other things that Android Studio includes (i.e. keep it simple). There are two programs I ended coming back to again and again:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;JetBrains IntelliJ IDEA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sublimetext.com/&quot;&gt;Sublime Text&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/android_studio.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/sublimeintellilogo.png&quot; alt=&quot;SublimeText and Intellij&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;intellij&quot; tabindex=&quot;-1&quot;&gt;IntelliJ &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#intellij&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;IntelliJ is excellent for writing Java (and Kotlin) code as it is designed for Java development, it is also free to use. The second advantage of IntelliJ is that Android Studio is made by JetBrains, the same company who make IntelliJ, so the interface is very similar. Learning with IntelliJ will help you later with Android Studio.&lt;/p&gt;
&lt;p&gt;As an aside, the programming language Kotlin was invented by JetBrains, and is now an officially supported language of Android development. Interestingly, Android Studio will actually convert Java code into Kotlin code for you if you want, as they are similar languages.&lt;/p&gt;
&lt;h4 id=&quot;sublime-text&quot; tabindex=&quot;-1&quot;&gt;Sublime Text &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#sublime-text&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Sublime Text is almost like an advanced notepad, which is specifically designed for coding. It doesn&#39;t look very impressive at first sight, but you will keep coming back to it because it is light and fast. Sublime text has a weird payment model. You can essentially download it from their website, and use it for free forever. However, officially you should buy a licence for &amp;quot;continued use&amp;quot;. I would say that if you end up using it extensively then that is fair enough, the developers certainly deserve to get paid!&lt;/p&gt;
&lt;h2 id=&quot;how-did-you-progress-and-what-were-some-challenges-you-faced%3F&quot; tabindex=&quot;-1&quot;&gt;How did you progress and what were some challenges you faced? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#how-did-you-progress-and-what-were-some-challenges-you-faced%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I will start by saying that programming is a rewarding, but at the same time frustrating process. It has definitely been worth the time, and you will, and should, never stop learning. For want of a better phrase, app development is a bottomless pit of things to learn and master.&lt;/p&gt;
&lt;h3 id=&quot;first-steps&quot; tabindex=&quot;-1&quot;&gt;First Steps &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#first-steps&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As I have mentioned above I started by learning Java. This was very enjoyable, and it&#39;s really fun seeing your first lines of code run. The very first program being &amp;quot;Hello World&amp;quot;, which seems to be a tradition for programmers as the first code output you ever make.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;app development is a bottomless pit of things to learn and master&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then I moved on to trying to understand some concepts of Object Oriented Programming (OOP). This is worth looking at as it underpins a lot of modern languages, and certainly Java. This can take a while to get your head around but is not too bad at a basic level, and ultimately it will help you take advantage of the powerful features the language has to offer.&lt;/p&gt;
&lt;h4 id=&quot;android-studio&quot; tabindex=&quot;-1&quot;&gt;Android Studio &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#android-studio&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Then I decided I was ready to jump into android development. Before you even begin you need to get your head around Android Studio. It is an excellent program, but you will need to learn where everything is, and what the correct naming convention is for files etc. The best way to do this is to follow a video tutorial for a basic app, and then do it yourself in android studio.&lt;/p&gt;
&lt;h4 id=&quot;learn-from-others&quot; tabindex=&quot;-1&quot;&gt;Learn from others &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#learn-from-others&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In addition it is a really good idea to take a moment and see how other developers layout their android projects. This you can do by looking at the structure on some GitHub projects (check &lt;a href=&quot;https://blog.aritraroy.in/20-awesome-open-source-android-apps-to-boost-your-development-skills-b62832cf0fa4&quot;&gt;this&lt;/a&gt; article for some links to some GitHub Projects). It allows you to see what convention developers tend to follow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;class names&lt;/li&gt;
&lt;li&gt;package names&lt;/li&gt;
&lt;li&gt;method names&lt;/li&gt;
&lt;li&gt;how long are methods typically&lt;/li&gt;
&lt;li&gt;where do they write notes, and what do the notes contain&lt;/li&gt;
&lt;li&gt;where are resources kept (like pictures etc.)&lt;/li&gt;
&lt;li&gt;what libraries are used a lot&lt;/li&gt;
&lt;li&gt;how do they write their code (code style)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can certainly learn a lot from other people&#39;s successful projects. This will also help you avoid some pitfalls that you may otherwise have fallen into.&lt;/p&gt;
&lt;h3 id=&quot;progression&quot; tabindex=&quot;-1&quot;&gt;Progression &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#progression&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At this point I have managed to get android studio up and running, I know some Java, and I can knock together a very, very basic app, and run a test version on my phone. At this point I started the &amp;quot;main&amp;quot; app I had in mind.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/dual-screen.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/dual-screen.png&quot; alt=&quot;two computer screens&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Starting with the initial screen I began to build. In my mind I had an image of what I wanted to achieve, but due to lack of experience you come upon a couple of problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I had no way to plan ahead properly as I didn&#39;t have the knowledge to know what makes the most sense to proceed with first, and I didn&#39;t know how to properly structure my code to make life easier later&lt;/li&gt;
&lt;li&gt;I realised that some of the ideas in my head, although on the face of it seemed simple, were not necessarily that simple to implement. (Sometimes it can be the reverse! You think it will be hard, and it takes two lines of code, but this is rare.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The outcome of this is that you will write code, learn, and then re-write the code later when you realise the mistakes you have made, or the inefficiencies in your code. This makes the whole process longer, but it is the best way to learn.&lt;/p&gt;
&lt;p&gt;For example, the first problem you will likely hit is that you will write all your code in one big block. Then later you will realise this is terrible as you can&#39;t follow your own code, and you will break it into smaller sections or separate files, as it should be. Seeing the problems that large blocks of code causes teaches you why you shouldn&#39;t do it. This process repeats multiple times for various different settings&lt;/p&gt;
&lt;h3 id=&quot;i&#39;m-a-coding-god!&quot; tabindex=&quot;-1&quot;&gt;I&#39;m a coding god! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#i&#39;m-a-coding-god!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the next stage of the journey. There will come a point when you think &amp;quot;Aha! I get it, this is not so bad now. I think maybe I&#39;m a natural!&amp;quot;. It runs well on your phone, it looks like you want (almost)...&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aha! I get it, this is not so bad now. I think maybe I&#39;m a natural!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not long after, it will dawn on you that you have only scratched the surface. Yes, you can code, but due to your new knowledge you will have a better view of the whole picture, and it is vast. Here is a small selection of the things that popped into view once I stepped back a little and reviewed what I had achieved so far:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is your code backed up on something like Git (What is Git??!!)&lt;/li&gt;
&lt;li&gt;Have you properly tested your code with things like unit tests or similar (What?!!)&lt;/li&gt;
&lt;li&gt;Do your resources load efficiently, fast and not on the main thread (That sounds complicated!)&lt;/li&gt;
&lt;li&gt;Do you have any memory leaks (How do I even look for that?)&lt;/li&gt;
&lt;li&gt;Is your code structured in a way that is easily expandable and readable (to me yes...but others maybe not)&lt;/li&gt;
&lt;li&gt;Does it run without crashing on just your phone and android version, or ALL phones and android versions (hmmm...)&lt;/li&gt;
&lt;li&gt;Is your code using the correct method of implementation for a particular task, or is it just a hack of inefficient methods because that&#39;s all you know at the moment (...more code review then)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;ok%2C-i&#39;m-not-a-coding-god...&quot; tabindex=&quot;-1&quot;&gt;Ok, I&#39;m not a coding god... &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#ok%2C-i&#39;m-not-a-coding-god...&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My point is that you will never know everything, the subject is huge. If you think you do then you are not trying hard enough, or you are doing it wrong! As I now know, even large companies like Google with their thousands of well paid software engineers do not have perfect bug free code. I know this because I have personally had to work around various bugs in Google&#39;s code while making this app.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;even large companies like Google with their thousands of well paid software engineers do not have perfect bug free code&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A really good resource for any questions you have about android, java or any other coding is &lt;a href=&quot;https://stackoverflow.com/&quot;&gt;StackOverflow&lt;/a&gt; forum. I literally wouldn&#39;t have a working app without that forum. It is a goldmine of information.&lt;/p&gt;
&lt;p&gt;Then one day I asked myself...&lt;/p&gt;
&lt;h3 id=&quot;what-about-user-login-and-data-backup-and-sync%3F&quot; tabindex=&quot;-1&quot;&gt;What about user login and data backup and sync? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#what-about-user-login-and-data-backup-and-sync%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ah such a simple question, but what a can of worms.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/can-of-worms.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/can-of-worms.jpg&quot; alt=&quot;Can of worms&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The thing is by this point I was fairly committed to the app, so I wanted to do it properly. I wanted to be able to record my data in the app, have it sync across devices, and be backed up.&lt;/p&gt;
&lt;p&gt;You can use various services to do this for you that will make the interface simpler...but you will pay eventually, as it is initially free to entice you in, and then the costs quickly ramp up with usage. You will also be locked into their system. I wanted to avoid that. Which left me with one option. My own server.&lt;/p&gt;
&lt;h4 id=&quot;getting-a-server&quot; tabindex=&quot;-1&quot;&gt;Getting a server &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#getting-a-server&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I signed up for a &lt;a href=&quot;https://tspc.men/recommendslinode&quot;&gt;Linode VPS&lt;/a&gt; (which I thoroughly &lt;a href=&quot;https://www.thetestspecimen.com/hosting-provider/&quot;&gt;recommend&lt;/a&gt;) for $5 a month and got cracking. I managed to build a Linux Ubuntu server. This also had the advantage of allowing me to setup my own emails, and an associated website so I could explain how the app worked (yet more work I hadn&#39;t planned for). I then created a REST API using Django Rest Framework (essentially a communication protocol between the app and the server).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/linode-logo.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/linode-logo.png&quot; alt=&quot;Linode logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Again, this took time to research and implement. I had done none of this before, and in the process I had to learn a new language called Python (not as bad as it sounds once you know a language like Java to some degree), and how to administer and secure a webserver (this was a little involved, but worth it).&lt;/p&gt;
&lt;p&gt;Then I had to get the webserver to communicate with the app! To do this correctly was the biggest challenge to date.&lt;/p&gt;
&lt;h4 id=&quot;another-recommendation&quot; tabindex=&quot;-1&quot;&gt;Another recommendation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#another-recommendation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I will make another recommendation here. When you are dealing with a REST framework you need a program to test it with. I won&#39;t go into the detail here, but one of the most popular is called &lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt;. However, I found the interface a little clunky, and I found an alternative which is (in my opinion) much better: &lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt;. Give both a try if you like.&lt;/p&gt;
&lt;h3 id=&quot;one-last-hurdle&quot; tabindex=&quot;-1&quot;&gt;One last hurdle &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#one-last-hurdle&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As I went through the process of making the app, I would often come up with new ideas or changes I wanted to make, but at some point you have to actually release the app!&lt;/p&gt;
&lt;p&gt;I therefore decided to draw a line in the sand, make sure the app functioned smoothly and release....then I noticed GDPR.&lt;/p&gt;
&lt;p&gt;If you don&#39;t know what GDPR is, then I will assume you are a hermit living in a cave, but I&#39;ll humour you. It is basically legislation implemented by the EU that affects any &amp;quot;thing&amp;quot; (business, website, app, service etc.) that may be used by an EU citizen in terms of privacy and rights to personal information. Overall this is a good thing for all our internet related futures, but it meant that I had to implement various changes to ensure I was in compliance, as the criteria is very strict.&lt;/p&gt;
&lt;p&gt;What didn&#39;t help was that the efforts of large companies such as Google were a little half-hearted in relation to helping out developers on their platform adhere to the legislation.&lt;/p&gt;
&lt;p&gt;This set me back a good month, if not more. Absolute pain in the ass. Anyway...&lt;/p&gt;
&lt;h2 id=&quot;finishing-up&quot; tabindex=&quot;-1&quot;&gt;Finishing up &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#finishing-up&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I finally got to the point of release. Here it is if you want to give it a spin, or search for &amp;quot;Wanderfile&amp;quot; on the play store:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://play.google.com/store/apps/details?id=com.thetestspecimen.wanderfile&amp;amp;pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/google-play-badge.png&quot; alt=&quot;Get it on Google Play&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wanderfile.app/&quot;&gt;Wanderfile Website&lt;/a&gt; (Explains how the app works)&lt;/p&gt;
&lt;p&gt;It is a really excellent feeling, but it doesn&#39;t end there...you need to keep it up to date and promote the app. You are competing with thousands of other apps, and to even get a little bit noticed is a struggle. Don&#39;t expect 1000 downloads on your first day (or week, or month for that matter).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/android-app/wanderfilelogogrey.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/android-app/wanderfilelogogrey.png&quot; alt=&quot;wanderfile logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have no idea if the app I made will succeed or not. It certainly won&#39;t be the next Facebook, but that was never the intention.&lt;/p&gt;
&lt;h2 id=&quot;what-i-achieved&quot; tabindex=&quot;-1&quot;&gt;What I achieved &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#what-i-achieved&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I created what I wanted to use, but more importantly, I learnt a huge amount. I can now, at least to some degree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Administer a Linux Server (Ubuntu)&lt;/li&gt;
&lt;li&gt;Write an Android application&lt;/li&gt;
&lt;li&gt;Write a website from scratch using html, css, php and javascript&lt;/li&gt;
&lt;li&gt;I know how to setup an email server for personalised emails including web access secured by second factor authentication&lt;/li&gt;
&lt;li&gt;Can write in Java and Python programming languages, although less so in Python&lt;/li&gt;
&lt;li&gt;Have dealt with various frameworks for the website and app (e.g. Django Rest Framework)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would never have thought I would get this far, and certainly didn&#39;t expect to get involved in so many areas. It was, in the end, consistent hard work in my spare time. Occasionally it felt like a chore, but generally it was a series of little rewards, with a large reward at the end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The worst that could happen is you will learn something.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you think you might enjoy coding I would encourage you to give it a look, and try. It is free, accessible and very rewarding. Plus you will learn things that are applicable to a whole host of fields. The worst that could happen is you will learn something.&lt;/p&gt;
&lt;h2 id=&quot;would-you-change-anything-looking-back%3F&quot; tabindex=&quot;-1&quot;&gt;Would you change anything looking back? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#would-you-change-anything-looking-back%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Nothing. Honestly. I messed up plenty, but it is all part of the learning process. Now I know things I didn&#39;t even have the first clue about before.&lt;/p&gt;
&lt;h2 id=&quot;what-are-you-going-to-do-now%3F&quot; tabindex=&quot;-1&quot;&gt;What are you going to do now? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-journey/#what-are-you-going-to-do-now%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now I will do my best to keep the app up to date and add new features. I will blog a little here and there, and I will try to think of the next app I could potentially make.&lt;/p&gt;
&lt;p&gt;Next challenge basically!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article is already too long, but I could write forever detailing exactly what I did and didn&#39;t do. With that in mind, if you have any questions that you would like to ask either send me an email and ping me a message on twitter and I&#39;ll be happy to give you some insight.&lt;/strong&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Linux – Should I Switch from Windows to Linux (Ubuntu, Fedora) or Not?</title>
		<link href="https://www.thetestspecimen.com/posts/linux-windows-switch/"/>
		<updated>Wed, 15 Aug 2018 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/linux-windows-switch/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Linux still has the reputation of being a geeky alternative to Windows and Mac that snotty little know-it-alls use to make everybody else feel inferior and stupid. I would say this reputation is wrongly attributed, and in its current form Linux provides a real alternative to Windows for most people. I will do my best to explain why I think this is so...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The question is: is Linux a good replacement for everyday computing, and should you be using it instead of Windows?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-do-i-use-and-prefer%3F&quot; tabindex=&quot;-1&quot;&gt;What do I use and prefer? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#what-do-i-use-and-prefer%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Personally I use both Windows (still Windows 7 actually) and Linux. On a day to day basis I use Linux, with windows usage coming in at maybe once a month.&lt;/p&gt;
&lt;p&gt;I much prefer using Linux for a variety of reasons I will get into, but that doesn&#39;t mean I think it will suit everyone.&lt;/p&gt;
&lt;h2 id=&quot;if-i-decide-to-use-linux%2C-which-distribution-should-i-use%3F&quot; tabindex=&quot;-1&quot;&gt;If I decide to use Linux, which distribution should I use? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#if-i-decide-to-use-linux%2C-which-distribution-should-i-use%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the main problem that Linux has at the moment.&lt;/p&gt;
&lt;p&gt;Linux is the &lt;strong&gt;type&lt;/strong&gt; of operating system, but there are many different versions of Linux:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ubuntu&lt;/li&gt;
&lt;li&gt;Fedora&lt;/li&gt;
&lt;li&gt;Manjaro&lt;/li&gt;
&lt;li&gt;Arch&lt;/li&gt;
&lt;li&gt;OpenSUSE&lt;/li&gt;
&lt;li&gt;Mint&lt;/li&gt;
&lt;li&gt;Gentoo&lt;/li&gt;
&lt;li&gt;Mandriva&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;...and there are more, a lot more.&lt;/p&gt;
&lt;p&gt;Basically every version of Linux uses the same core (officially called a Kernel), so what you are really deciding between is the user interface, and how well it is maintained as a system. The &amp;quot;core&amp;quot; functionality is the same.&lt;/p&gt;
&lt;p&gt;I will therefore make this very simple for you. If you have never used a Linux distribution before you either use &lt;strong&gt;&lt;a href=&quot;https://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt; or &lt;a href=&quot;https://getfedora.org/&quot;&gt;Fedora&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-windows/fedora-ubuntulogos.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-windows/fedora-ubuntulogos.jpg&quot; alt=&quot;fedora ubuntu&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;These two distributions are the biggest, have the best support, and will therefore make your life easier. Please don&#39;t assume that because they will make your life easier they are missing attributes that some other distributions have, as this is not the case.&lt;/p&gt;
&lt;p&gt;Ubuntu is easily the most widely used, but personally I have had a better experience with Fedora (I use Fedora on a daily basis, as does the original creator of Linux &lt;a href=&quot;https://en.wikipedia.org/wiki/Linus_Torvalds&quot;&gt;Linus Torvalds&lt;/a&gt;). You can&#39;t really go very wrong with either.&lt;/p&gt;
&lt;p&gt;If you eventually decide you like using Linux you can look into the other variants, but chances are you will not need to unless you have very specific needs.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-advantages-of-using-linux%3F&quot; tabindex=&quot;-1&quot;&gt;What are the advantages of using Linux? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#what-are-the-advantages-of-using-linux%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;It is absolutely free&lt;/li&gt;
&lt;li&gt;The software you install is predominantly free&lt;/li&gt;
&lt;li&gt;It is fast, and doesn&#39;t have the same amount of annoying fluff as Windows&lt;/li&gt;
&lt;li&gt;The user interface is simple and easy to use&lt;/li&gt;
&lt;li&gt;It is by nature much more secure, and much less prone to viruses&lt;/li&gt;
&lt;li&gt;It is very easy to update&lt;/li&gt;
&lt;li&gt;It can be portable (usb drive, external ssd/hdd). You can&#39;t do that on Windows!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The other thing to bear in mind is that Linux as an operating system is not small in terms of market share. There are many, many things that use Linux:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All of the top 500 supercomputers in the world use Linux (i.e. the fastest computers in the world)&lt;/li&gt;
&lt;li&gt;66% of web servers world wide use Linux&lt;/li&gt;
&lt;li&gt;75% of all smartphones and tablets use Linux (this is because Android is based on Linux too)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The reason I mention the above is that it would be wrong to assume that Linux is less mature than Windows. Linux is a very advanced and constantly updated system, even Microsoft work on improving Linux, that is how important it is as a system.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-disadvantages-of-using-linux%3F&quot; tabindex=&quot;-1&quot;&gt;What are the disadvantages of using Linux? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#what-are-the-disadvantages-of-using-linux%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If something goes wrong, there are less resources available on the internet to help you fix it&lt;/li&gt;
&lt;li&gt;If something goes wrong, it is usually more difficult and involved to fix it&lt;/li&gt;
&lt;li&gt;You will likely have to use the commandline at some point (this is not really a negative as it is extremely easy, and I actually prefer it)&lt;/li&gt;
&lt;li&gt;You do not have access to the same programs as Windows has, but there are typically very good alternatives&lt;/li&gt;
&lt;li&gt;There will be a learning curve initially&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I mentioned in the previous section about the extensive use of Linux in various systems, but if you &lt;strong&gt;only&lt;/strong&gt; consider the desktop environment that consumers use, then the story of usage is a little different:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows market share: 88.5%&lt;/li&gt;
&lt;li&gt;Linux market share: 2%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This translates into, less information being available online (less help forums etc.), and less software being made available for the system. The reality in day to day use is not as significant as the numbers would suggest, as the Linux community online is knowledgeable and active. That 2% are generally active contributors, and know what they are talking about.&lt;/p&gt;
&lt;h2 id=&quot;who-shouldn&#39;t-be-using-linux%3F&quot; tabindex=&quot;-1&quot;&gt;Who shouldn&#39;t be using Linux? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#who-shouldn&#39;t-be-using-linux%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think this is potentially an easier question to answer than who &amp;quot;should&amp;quot; be.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are someone who absolutely has to use proprietary software then Linux is not for you&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are someone who absolutely has to use proprietary software (usually due to work) such as Adobe Photoshop, Adobe Premiere, Microsoft Office Suite, specific CAD software such as AutoCAD etc. then Linux is not for you. As currently you will only find software like that on either Windows or Mac.&lt;/p&gt;
&lt;p&gt;This is the only reason that I keep a version of Windows to hand, sometimes I still need software that is only available on Windows. This is however becoming less and less the case.&lt;/p&gt;
&lt;h2 id=&quot;who-should-be-using-linux%3F&quot; tabindex=&quot;-1&quot;&gt;Who should be using Linux? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#who-should-be-using-linux%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-windows/ubuntu.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-windows/ubuntu.png&quot; alt=&quot;ubuntu screen&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I think most people will find that using something like Fedora is actually a breeze on a day to day basis, so I would probably say that if you don&#39;t have to be tied down to specific software, or you only have basic needs, then it will suit you down to the ground.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I would even go as far as to say that I think my parents would find it easier to use than windows&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I would even go as far as to say that I think my parents (in this case representing a generation with not so great computer skills) would find it easier to use than windows, as it is more intuitive. There are less menus and settings to confuse them, and finding things is much simpler.&lt;/p&gt;
&lt;h3 id=&quot;what-if-i-need-programs-like-microsoft-office%3F&quot; tabindex=&quot;-1&quot;&gt;What if I need programs like Microsoft Office? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#what-if-i-need-programs-like-microsoft-office%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are not tied rigidly to any specific software or suites, you can switch them out for very capable alternatives. Just as an example you can swap out as follows (all free of course):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Microsoft Office --&amp;gt; Libre Office (or something like Google Docs, Sheets etc in the cloud)&lt;/li&gt;
&lt;li&gt;Adobe Premiere --&amp;gt; KdenLive&lt;/li&gt;
&lt;li&gt;Adobe Photoshop --&amp;gt; GIMP&lt;/li&gt;
&lt;li&gt;Adobe Illustrator --&amp;gt; InkScape&lt;/li&gt;
&lt;li&gt;CAD --&amp;gt; FreeCAD&lt;/li&gt;
&lt;li&gt;Microsoft Outlook --&amp;gt; Evolution Mail&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are just examples, but there are many more, and they are very comprehensive programs (don&#39;t view them as second class rubbish, they are not).&lt;/p&gt;
&lt;h3 id=&quot;what-about-the-commandline%2C-that-sounds-scary%3F&quot; tabindex=&quot;-1&quot;&gt;What about the commandline, that sounds scary? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#what-about-the-commandline%2C-that-sounds-scary%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-windows/bash-terminal.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-windows/bash-terminal.png&quot; alt=&quot;command line&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The commandline in Linux is not scary at all. It is much easier to use than having to delve into the travesty that is the settings menu structure of Windows. Let&#39;s take a couple of examples:&lt;/p&gt;
&lt;h4 id=&quot;i-want-to-install-a-program&quot; tabindex=&quot;-1&quot;&gt;I want to install a program &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#i-want-to-install-a-program&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I want to keep this simple on both platforms, so it is a fair comparison. Filezilla is an FTP program (could be anything it doesn&#39;t matter) available for free on both Windows and Linux, so...&lt;/p&gt;
&lt;h5 id=&quot;windows&quot; tabindex=&quot;-1&quot;&gt;Windows &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#windows&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Go to google in a browser&lt;/li&gt;
&lt;li&gt;Find filezilla website&lt;/li&gt;
&lt;li&gt;find download page and correct version&lt;/li&gt;
&lt;li&gt;download file&lt;/li&gt;
&lt;li&gt;find where downloaded file has saved to&lt;/li&gt;
&lt;li&gt;double click file to install&lt;/li&gt;
&lt;li&gt;go through the install guide (being careful not to accidentally install the guff that usually comes with installers of free programs [don&#39;t think filezilla do this, but it is way too common...])&lt;/li&gt;
&lt;li&gt;Open program&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&quot;fedora&quot; tabindex=&quot;-1&quot;&gt;Fedora &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#fedora&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Open terminal / commandline&lt;/li&gt;
&lt;li&gt;type &amp;quot;sudo dnf install filezilla&amp;quot; (the first three words never change, so it&#39;s easy to remember)&lt;/li&gt;
&lt;li&gt;type password (this is where the security of Linux becomes clear, you cannot install a program without a password, sounds like a pain, but it is MUCH more secure)&lt;/li&gt;
&lt;li&gt;Accept install by typing &amp;quot;y&amp;quot; and pressing &amp;quot;enter&amp;quot;&lt;/li&gt;
&lt;li&gt;Open program&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My point is with the above example that you have to go all over the place to install something on Windows, but you never have to leave the commandline in Fedora, not even once.&lt;/p&gt;
&lt;p&gt;This also illustrates how it would be simpler for the older generation. Installing a program on Windows involves downloading the exe file, but I have seen many times with older people that they have no clue where it goes once it&#39;s downloaded! Bit of a problem if you ask me. Fedora does not have this problem, it just works.&lt;/p&gt;
&lt;h4 id=&quot;other-commands&quot; tabindex=&quot;-1&quot;&gt;Other commands &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#other-commands&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I&#39;ll assume you are familiar with the process of Windows at this point, so I will give a couple more examples of how easy things are with the commandline for everyday tasks. Try to remember that all this becomes second nature after a while:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update operating system: &amp;quot;sudo dnf update&amp;quot;&lt;/li&gt;
&lt;li&gt;Uninstall filezilla (or other program): &amp;quot;sudo dnf remove filezilla&amp;quot;&lt;/li&gt;
&lt;li&gt;Open filezilla: &amp;quot;filezilla&amp;quot; (you can of course go and click on the icon too)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can do &lt;strong&gt;anything&lt;/strong&gt; from the commandline, which makes it very powerful. There is plenty of guidance on the internet too.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-windows-switch/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Is everybody suddenly going to jump on Linux, no I doubt it.&lt;/p&gt;
&lt;p&gt;When you are used to a system it can be very difficult to switch over to something new. However, I think that in general peoples usage of traditional computers is changing. People are moving towards more mobile, more cloud based and more secure systems that are a breeze to maintain. This has seen the rise of things like the Chromebook, which auto-updates, is cheap, fast and gets your day to day jobs done easily (it is also based on Linux by the way!) .&lt;/p&gt;
&lt;p&gt;My point is that people are becoming more open to alternatives to Windows in general, and I think this could be good for Linux as it really is an excellent alternative.&lt;/p&gt;
&lt;p&gt;At the very least I would give it a shot. It is free after all. You don&#39;t even have to get rid of windows to try it because you can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install it on VirtualBox in Windows (this is easy there are plenty of tutorials on YouTube)&lt;/li&gt;
&lt;li&gt;Burn it to a DVD and run a &amp;quot;Live&amp;quot; version from the DVD. This basically means you can use the operating system to see how it works, but once you log off all data is lost (great for trying it out though!)&lt;/li&gt;
&lt;li&gt;Write it to an external drive and delete it later if you don&#39;t like it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is much more flexible than Windows in this regard, so you can try it without losing Windows.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Make Broadcom WiFi Modules Work in Fedora</title>
		<link href="https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/"/>
		<updated>Sun, 02 Sep 2018 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Due to the fact that broadcom use proprietary drivers for their wireless modules it is not usually possible for them to work out of the box with Fedora. This tutorial is aimed at helping you to get the adapter working.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;notes-and-pre-requisites&quot; tabindex=&quot;-1&quot;&gt;Notes and Pre-requisites &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/#notes-and-pre-requisites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First I want to mention a couple of points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;to complete this tutorial you will need an internet connection. I know that sounds a little silly, but there is no other way. You therefore need a temporary wifi adaptor that works in Fedora already, or a hardwired connection&lt;/li&gt;
&lt;li&gt;this process has been tested on Fedora 26, 27 and 28, and I know it to be working for those systems&lt;/li&gt;
&lt;li&gt;the specific wifi adapter I have is &lt;strong&gt;BCM4352&lt;/strong&gt; (802.11ac Wireless Network Adapter (rev 03)). Although this process should work for all (or most) broadcom adaptors I can&#39;t guarantee it&lt;/li&gt;
&lt;li&gt;UEFI secure boot must be disabled in BIOS&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;let&#39;s-get-started&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s get started &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/#let&#39;s-get-started&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The process itself can be quite simple, but I am aware of some pitfalls that you may come up against in some cases. I know how to get around some of these. With this in mind I will try to highlight potential problems and their fixes as we go through.&lt;/p&gt;
&lt;h2 id=&quot;the-simple-way&quot; tabindex=&quot;-1&quot;&gt;The simple way &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/#the-simple-way&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You should first make sure you are up to date&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the rpmfusion repositories&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; %fedora&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; %fedora&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.noarch.rpm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Get the broadcom drivers:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; kmod-wl akmods akmod-wl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check if you have kernel-devel installed. It should be, but if not this will install it for you.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; kernel-devel&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Now reboot / restart your system&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once the system has booted and you have logged in again we need to check if the driver &amp;quot;broadcom-wl&amp;quot; has installed. Obviously the the actual driver version might be slightly different to the output below, but you should get a similar response&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-qa&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; broadcom-wl
broadcom-wl-6.30.223.271-1.fc22.noarch&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run modprobe&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; modprobe wl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check that akmods can be run&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; akmods

Checking kmods exist &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.17&lt;/span&gt;.19-200.fc28.x86_64           &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;  OK  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a chance that you will get a warning that &amp;quot;files needed for building modules against kernel could not be found&amp;quot; and &amp;quot;Is the correct kernel devel package installed?&amp;quot;. If that is the case don&#39;t worry, just continue.&lt;/p&gt;
&lt;p&gt;We then need to check that the kernel-devel package in the system is the same as the kernel-devel package installed with the $(uname -r) kernel of your system. First check the system:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; /usr/src/kernels/
&lt;span class=&quot;token number&quot;&gt;4.17&lt;/span&gt;.19-200.fc28.x86_64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then the $(uname -r)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;4.17&lt;/span&gt;.19-200.fc28.x86_64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If they are the same you can skip to the &amp;quot;Load the &amp;quot;wl&amp;quot; module&amp;quot; part just after the system restart in red below, otherwise you need to do the following&lt;/p&gt;
&lt;p&gt;You now need to install the correct kernel devel for your system. This is the version that was output when you ran the &amp;quot;uname -r&amp;quot; command. Go to the following website:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rpmfind.net/linux/rpm2html/search.php?query=kernel-devel&amp;amp;submit=Search+...&amp;amp;system=&amp;amp;arch=&quot;&gt;Kernel Devel RPM files&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You then need to find the correct rpm file for your system for example in my case it would be:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kernel-devel-4.17.19-200.fc28.x86_64.rpm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and download the file.&lt;/p&gt;
&lt;p&gt;Once downloaded (I am assuming you will download the file to the Downloads folder) run the following commands replacing the rpm file name with the correct one for your system that you just downloaded&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/Downloads
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost Downloads&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-Uvh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt; kernel-devel-4.17.19-200.fc28.x86_64.rpm
Preparing&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;. &lt;span class=&quot;token comment&quot;&gt;################################# [100%]&lt;/span&gt;
Updating / installing&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;:kernel-devel-4.17.19-200.fc28 &lt;span class=&quot;token comment&quot;&gt;################################# [50%]&lt;/span&gt;
Cleaning up / removing&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;:kernel-devel-4.17.19-200.fc28 &lt;span class=&quot;token comment&quot;&gt;################################# [100%]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run akmods again&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; akmods
Checking kmods exist &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.17&lt;/span&gt;.19-200.fc28.x86_64 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; OK &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
Building and installing wl-kmod &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; OK &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Reboot / restart the system&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Load the &amp;quot;wl&amp;quot; module&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; modprobe wl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check &amp;quot;wl&amp;quot; is loaded&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ lsmod &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; wl
wl                   &lt;span class=&quot;token number&quot;&gt;6463488&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
cfg80211              &lt;span class=&quot;token number&quot;&gt;770048&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; wl,rtlwifi,mac80211&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check that module &amp;quot;wl&amp;quot; is used as a wifi adapter. Please note that the terminal will output a lot of different components like the one below, so you will have to search for the wireless controller specifically.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ lspci &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt;
05:00.0 Network controller: Broadcom Inc. and subsidiaries BCM4352 &lt;span class=&quot;token number&quot;&gt;802&lt;/span&gt;.11ac Wireless Network Adapter &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rev 03&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    Subsystem: ASUSTeK Computer Inc. Device 855c
    Flags: bus master, fast devsel, latency &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;, IRQ &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;
    Memory at dfa00000 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;-bit, non-prefetchable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;32K&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    Memory at df800000 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;-bit, non-prefetchable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;2M&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    Capabilities: &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;access denied&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    Kernel driver &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; use: wl
    Kernel modules: bcma, wl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point unplug the temporary wifi card you are using or unplug the hardwired connection you are using. Then we can get a list of networks up&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ nmcli dev wifi list
IN-USE  SSID            MODE   CHAN  RATE        SIGNAL  BARS  SECURITY  
        OnePlus5        Infra  &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;130&lt;/span&gt; Mbit/s  &lt;span class=&quot;token number&quot;&gt;95&lt;/span&gt;      ▂▄▆█  WPA2        
        COSMOTE-F0CEBB  Infra  &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;270&lt;/span&gt; Mbit/s  &lt;span class=&quot;token number&quot;&gt;57&lt;/span&gt;      ▂▄▆_  WPA1 WPA2    
        COSMOTE-0EF1CE  Infra  &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;270&lt;/span&gt; Mbit/s  &lt;span class=&quot;token number&quot;&gt;35&lt;/span&gt;      ▂▄__  WPA1 WPA2 
        conn-x71aa38    Infra  &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;135&lt;/span&gt; Mbit/s  &lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;      ▂▄__  WPA1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can connect to the wifi network of your choice&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;testspecimen@localhost ~&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ nmcli dev wifi con &lt;span class=&quot;token string&quot;&gt;&quot;your_ssid&quot;&lt;/span&gt; password &lt;span class=&quot;token string&quot;&gt;&quot;your_ssid_password&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That should be it!&lt;/p&gt;
&lt;p&gt;Let me know if it worked for you, and if so which driver it worked for so I can create a working list for other people to reference.&lt;/p&gt;
&lt;h2 id=&quot;credits&quot; tabindex=&quot;-1&quot;&gt;Credits &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/#credits&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After many hours trawling through the internet I found the method detail above worked for me. The information in this article predominantly comes from one place:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forums.fedoraforum.org/showthread.php?303933-broadcom-wl-installed-but-wl-not-found&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Cryptocurrency Beginners Guide – What Are They, Should I Get Some, and How Does It Work?</title>
		<link href="https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/"/>
		<updated>Wed, 19 Sep 2018 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;The aim of this article is to get you up to speed on the basics of cryptocurrencies. I will go over some of the main terminology, and try to give you a good idea of how to get hold of some, and how to store it properly. Pointing out the differences between standard &amp;quot;fiat&amp;quot; money like dollars / euro / pounds and cryptocurrencies will also feature.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Once you get to the end of the article I hope you will understand what all the fuss is about, and have a better idea of why it is much more than a speculative money making investment.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cryptocurrencies have been all over the news in recent times, and there are a lot of cryptocurrencies on offer (literally thousands), including the ubiquitous Bitcoin.&lt;/p&gt;
&lt;p&gt;Unfortunately, the main focus has been on short term speculative gains, rather than the core technology and potential advantages that cryptocurrencies offer.&lt;/p&gt;
&lt;p&gt;Understandably, this may put some people off. However, I would encourage you to look beyond the current hype, as there are a lot of revolutionary ideas in cryptocurrency. It could dramatically change the way the world operates in the not so distant future.&lt;/p&gt;
&lt;p&gt;It really is a world worth exploring.&lt;/p&gt;
&lt;h2 id=&quot;what-i-won&#39;t-be-talking-about...&quot; tabindex=&quot;-1&quot;&gt;What I won&#39;t be talking about... &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-i-won&#39;t-be-talking-about...&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A lot of articles about cryptocurrencies focus on one subject:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which coin is going to make the largest gain in the near future, or make me a millionaire in a few years?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well if you came here for an answer to that you are in the wrong place. Just wanted to get that out of the way early so I don&#39;t waste anyone&#39;s time...&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-a-cryptocurrency%3F&quot; tabindex=&quot;-1&quot;&gt;What exactly is a cryptocurrency? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-exactly-is-a-cryptocurrency%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You could say that it is &amp;quot;digital money&amp;quot;, but that is a meaningless statement. The money you currently use dollars / euros / pounds is already digital. You don&#39;t keep all your money in cash form do you? Most of it lives in a &amp;quot;digital&amp;quot; database organised by your bank.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/cryptocurrency.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/cryptocurrency.jpg&quot; alt=&quot;cryptocurrency&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So if we are already digital, what exactly is cryptocurrency? I have outlined below some of the key differentiating factors between normal &amp;quot;fiat&amp;quot; currency and cryptocurrencies in general:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Transactions are permanently stored and cannot be changed, ever, by anyone&lt;/li&gt;
&lt;li&gt;The currency is decentralised. There is no single central authority such as a bank, government or person that controls the currency. It is distributed across many locations around the world.&lt;/li&gt;
&lt;li&gt;Transactions are secure by default due to public-private key cryptography. You don&#39;t need to trust any intermediary (such as a bank) to make a transaction.&lt;/li&gt;
&lt;li&gt;You don&#39;t need permission from anyone (government, bank etc.) to use them, as they are free to access for all&lt;/li&gt;
&lt;li&gt;Transactions have no borders. You can send cryptocurrencies anywhere and to anyone with no limits or restrictions on geographical location or amounts.&lt;/li&gt;
&lt;li&gt;Transactions are pseudonymous [this is not the same as being anonymous, although there are some cryptocurrencies that are anonymous]. You don&#39;t have a name on your account like a bank account, so people won&#39;t know who you are unless you tell them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What this boils down to is this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can send money to someone, and receive money from someone else. All without having to deal with a bank, or even having a bank account. You can also have absolute confidence that once the money is sent or received it is permanent, verifiable and cannot be changed or reversed.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-easy-are-they-to-use%3F&quot; tabindex=&quot;-1&quot;&gt;How easy are they to use? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#how-easy-are-they-to-use%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is a new way of doing things, so it is strange and confusing to try and understand at first. I will go over some of the terminology in the next section.  In reality though, once set up, it is not a lot different from how you currently use your bank account:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You have an account number that you can give out to people so they can send you money (called a public key in cryptocurrencies).&lt;/li&gt;
&lt;li&gt;With a bank account you confirm a transaction is real using your debit / credit card and pin (or card details online). With cyptocurrencies you have a private key (like a password) that you need to use to &amp;quot;sign&amp;quot; transactions. This can be simplified even further with hardware devices, but we will get to that later.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-main-issue-currently&quot; tabindex=&quot;-1&quot;&gt;The main issue currently &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#the-main-issue-currently&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The main issue at the moment is that you can&#39;t use cryptocurrencies in the real world &lt;strong&gt;everywhere&lt;/strong&gt;, which limits their current usefulness.&lt;/p&gt;
&lt;h3 id=&quot;what-can-you-use-cryptocurrencies-for-right-now&quot; tabindex=&quot;-1&quot;&gt;What can you use cryptocurrencies for right now &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-can-you-use-cryptocurrencies-for-right-now&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may be pleasantly surprised as to where you can already use cryptocurrencies.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/bitcoin-accepted-here.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/bitcoin-accepted-here.jpg&quot; alt=&quot;bitcoin accepted here&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;shopping&quot; tabindex=&quot;-1&quot;&gt;Shopping &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#shopping&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I would suggest taking a look at &lt;a href=&quot;https://coinmap.org/&quot;&gt;coinmap.org&lt;/a&gt;, which shows a heat-map of some of the places in the world where a form of cryptocurrency is accepted. There are even some big companies that will accept them such as Expedia, Newegg, Gyft etc.&lt;/p&gt;
&lt;p&gt;More interestingly Shopify, which allows people to create online shops, has integrated Bitcoin payments into their online shopping cart. This means that any company, big or small, that wants to accept Bitcoin payments through their online shop can do so with ease.&lt;/p&gt;
&lt;h4 id=&quot;international-money-transfer&quot; tabindex=&quot;-1&quot;&gt;International money transfer &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#international-money-transfer&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;One of the main advantages of cryptocurrency is the lack of borders, and instant and automatic transfer of money.&lt;/p&gt;
&lt;p&gt;You can for example use cryptocurrency to settle balances with friends, family and co-workers. It can be as simple as scanning a QR code on your phone and confirming the amount to transfer. Really easy.&lt;/p&gt;
&lt;p&gt;Plus no extortionate international transfer fees. If you send it to your next door neighbour, or your cousin on the other side of the world, the cost is exactly the same. If you use a no fee cryptocurrency like nano, there is no fee at all, ever!&lt;/p&gt;
&lt;h3 id=&quot;it-will-improve&quot; tabindex=&quot;-1&quot;&gt;It will improve &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#it-will-improve&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The fact is that this situation will only improve. The methods by which you can utilise cryptocurrencies will get simpler to use, and more common. There is already a lot of research being done, and deals being made with large companies, and even banks. This should give you an idea of how important and revolutionary the technology is.&lt;/p&gt;
&lt;p&gt;Even if you plan to wait a little to get fully involved, I think it makes a lot of sense to get an understanding now. This will allow you to be ready and prepared.&lt;/p&gt;
&lt;h2 id=&quot;what-do-all-the-new-words-mean%3F&quot; tabindex=&quot;-1&quot;&gt;What do all the new words mean? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-do-all-the-new-words-mean%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Along with new technology usually comes new terminology. I will give you some quick definitions below before we dig in.&lt;/p&gt;
&lt;h3 id=&quot;blockchain&quot; tabindex=&quot;-1&quot;&gt;Blockchain &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#blockchain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In simple terms the (or a) blockchain is a database where all the transactions are stored (exactly like a traditional ledger).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/blockchain.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/blockchain.png&quot; alt=&quot;blockchain&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This database is stored at locations called nodes. A node is just a computer that contains a complete version of the database. There are thousands of nodes around the world, and they all contain exactly the same copy of the database. This means that the system does not exist in one place but is &amp;quot;distributed&amp;quot; around the world. This makes it impossible for governments or other authorities to shut down the system, as it doesn&#39;t exist in only one place. If they shut down one node, there are thousands of others.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is this decentralisation, autonomy and automatic error checking ability of cryptocurrencies that make them so unique.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These nodes talk to each other using a cryptographic algorithm, which ensures that they all agree and hold the same data, essentially forming a network. Furthermore, the cryptographic algorithm ensures that no false transactions can be recorded, and no values can be altered after they are accepted by the network.&lt;/p&gt;
&lt;p&gt;If someone tries to change values in the blockchain, or add erroneous data to the blockchain, there are cryptographic methods in place (which I won&#39;t go into here) that can spot and reject these transactions. It is this decentralisation, autonomy and automatic error checking ability of cryptocurrencies that make them so unique.&lt;/p&gt;
&lt;p&gt;Compare this to a bank. You have a system that is run by humans (notoriously useless error prone creatures) in a central location. This is usually overseen by governments / dictators, which depending on the country could be good or bad. Everybody trusts their bank though don&#39;t they?!&lt;/p&gt;
&lt;p&gt;I should point out that there are some cryptocurrencies that use something different to a blockchain. However, for all intents and purposes they do the same thing, record transactions. I will therefore stick with blockchain in the article to keep things simple.&lt;/p&gt;
&lt;h3 id=&quot;private-key&quot; tabindex=&quot;-1&quot;&gt;Private Key &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#private-key&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/secret-key.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/secret-key.jpg&quot; alt=&quot;private key&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A private key is literally a string of random letters and numbers like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is essentially your password to your money stored on the blockchain. Your private key should be known by you and you alone. &lt;strong&gt;Literally no-one else&lt;/strong&gt;. Treat it exactly as you would your banking login credentials&lt;/p&gt;
&lt;h3 id=&quot;public-key&quot; tabindex=&quot;-1&quot;&gt;Public Key &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#public-key&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A public key looks a lot like a private key, but tends to be a bit shorter. The key below is my personal Bitcoin public key:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;37yi7FUNwv5PQvRU1Q2JEmPYeH8XVyPDTL&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The fact that I have published my own public key should tell you that the public key is safe to give to people. In fact you will probably want to give it to people. The public key is effectively the equivalent of your bank account number and sort code (or IBAN if we go international). It gives people all the information they need to send you money.&lt;/p&gt;
&lt;h3 id=&quot;wallet&quot; tabindex=&quot;-1&quot;&gt;Wallet &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#wallet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A wallet is where you store your cryptocurrencies. You may hear the terms &amp;quot;software&amp;quot; and &amp;quot;hardware&amp;quot; wallets. They do the same job, but one is stored on a physical device you carry around with you, and the other is stored as a computer file. Typically hardware wallets are considered to be a more secure way to store your wallet information, and hence your cryptocurrencies.&lt;/p&gt;
&lt;h3 id=&quot;wallet-seed-or-seed-words&quot; tabindex=&quot;-1&quot;&gt;Wallet Seed or Seed Words &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#wallet-seed-or-seed-words&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The wallet seed is as important to keep safe as the private key. It is created when you make a wallet, and is effectively a more recognisable form of the private key.&lt;/p&gt;
&lt;p&gt;Looking at how long and random the private key above is, you can see that it would be very easy to make a mistake copying it or writing it down. It is also not exactly easy to memorise. The wallet seed is a list of (typically 25-ish) words that are commonly used in English (or other languages in some cases). The order of the list of these words is also fixed.&lt;/p&gt;
&lt;p&gt;Although a list of 25 commonly used words doesn&#39;t sound very secure or random, it is actually statistically very, very, very unlikely that one person will get the same list twice. Especially when you consider the unique order required.&lt;/p&gt;
&lt;p&gt;...so should you ever need to recreate your wallet, the ONLY thing you need are those 25-ish words, and you will have access to the same account again! You could also use the private key, they are one and the same just in different formats.&lt;/p&gt;
&lt;h3 id=&quot;altcoin&quot; tabindex=&quot;-1&quot;&gt;Altcoin &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#altcoin&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An altcoin is essentially anything that isn&#39;t either Bitcoin or Ethereum (i.e. the two biggest cryptocurrencies). It stands for alternative coin.&lt;/p&gt;
&lt;h3 id=&quot;mining&quot; tabindex=&quot;-1&quot;&gt;Mining &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#mining&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/crypto-mining.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/crypto-mining.jpg&quot; alt=&quot;cryptocurrency mining&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mining is not something you should really worry about too much. It does not happen for all cryptocurrencies, but in some, such as bitcoin, it is used to ensure that the currency stays secure and free from malicious attacks. You could mine cryptocurrency yourself and earn &amp;quot;free&amp;quot; coins, but it is not generally worth the effort as you will earn very, very little unless you have significant computing power at your disposal.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-get-some-cryptocurrencies%3F&quot; tabindex=&quot;-1&quot;&gt;How do I get some cryptocurrencies? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#how-do-i-get-some-cryptocurrencies%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently one of the problems with the general adoption of cryptocurrencies is that it is not necessarily obvious how to get hold of them. Even if people know, they are wary as they think they might lose their money.&lt;/p&gt;
&lt;p&gt;With the above in mind, I will explain how to get hold of some cryptocurrencies, and make some suggestions on which websites to use to achieve this.&lt;/p&gt;
&lt;h3 id=&quot;currency-exchange&quot; tabindex=&quot;-1&quot;&gt;Currency Exchange &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#currency-exchange&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best way to get some cryptocurrency, and start using them, is to exchange your normal fiat currency in your bank account (dollars, euros, pounds etc.) using an exchange website. It is like signing up for any online account. Although you may have to provide some form of ID before they let you transfer money into the account.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/crypto-exchange.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/crypto-exchange.jpg&quot; alt=&quot;cryptocurrency exchange&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As there are many exchanges out there, and there have been various scandals with cryptocurrency exchanges over the years, I will make some recommendations, all of which I currently use or have used in the past.&lt;/p&gt;
&lt;h4 id=&quot;kraken&quot; tabindex=&quot;-1&quot;&gt;Kraken &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#kraken&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/kraken.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/kraken.png&quot; alt=&quot;kraken&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.kraken.com/&quot;&gt;Kraken&lt;/a&gt; is my number 1 pick for an exchange that you can convert fiat into cryptourrency. It has a reasonable choice of cryptocurrencies. The only real downside to this exchange is that you will only have access via their website. I believe there is an iOS app available, but apparently it is not very good, and there is no android app available at all.&lt;/p&gt;
&lt;h4 id=&quot;coinbase&quot; tabindex=&quot;-1&quot;&gt;Coinbase &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#coinbase&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/coinbase-logo.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/coinbase-logo.png&quot; alt=&quot;coinbase&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.coinbase.com/&quot;&gt;Coinbase&lt;/a&gt; is one of the biggest exchanges that will convert fiat into cryptocurrency. It is very easy to use, and has both iOS and android apps available. However, they have a limited amount of different cryptocurrencies available.&lt;/p&gt;
&lt;p&gt;Once you have your account open on one of the two above, buying cryptocurrency is literally clicking a button. You won&#39;t struggle, believe me.&lt;/p&gt;
&lt;h4 id=&quot;binance&quot; tabindex=&quot;-1&quot;&gt;Binance &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#binance&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you start with one of the two exchanges above and find that you want access to more cryptocurrencies, then you can consider using &lt;a href=&quot;https://www.binance.com/&quot;&gt;&lt;strong&gt;Binance&lt;/strong&gt;&lt;/a&gt;. Binance has a lot of different cryptocurrencies available, is very easy to use, has iOS and android apps, and an impressive array of security features to help you secure your account. The only downside is that you cannot send fiat currency to the exchange. It only deals with cryptocurrencies. This ultimately means you will need to send fiat to kraken or coinbase first. Then change the fiat into cryptocurrencies, and then transfer them to Binance.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/binance.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/binance.png&quot; alt=&quot;binance&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The above may sound long winded and a bit of a pain, but it is actually a fairly simple process once you have tried it. I would suggest you transfer a small amount of money to the exchange of your choice and have a play around till you get a feel for it.&lt;/p&gt;
&lt;h3 id=&quot;cash&quot; tabindex=&quot;-1&quot;&gt;Cash &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#cash&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The other option is you skip the exchange, and you buy some cryptocurrency from someone else with cash.&lt;/p&gt;
&lt;p&gt;I would not recommend that you go down this road unless you know what you are doing already (i.e. you know how to confirm they have actually sent you the cryptocurrency or not) and absolutely trust the other person involved, or you have no other choice.&lt;/p&gt;
&lt;p&gt;Keep things simple and go with the exchange method above.&lt;/p&gt;
&lt;p&gt;If you insist on going down this route, you will first need to create a wallet (which I talk about in a later section). Then you simply get them to transfer the funds to your wallet public key address, you confirm the funds are in your wallet, then you give them the cash. Simple. But you &lt;strong&gt;MUST&lt;/strong&gt; confirm the funds arrived in &lt;strong&gt;YOUR&lt;/strong&gt; wallet before giving (or transferring) them any cash.&lt;/p&gt;
&lt;h2 id=&quot;there-are-too-many-coins-to-choose-from-which-do-i-pick!%3F&quot; tabindex=&quot;-1&quot;&gt;There are too many coins to choose from which do I pick!? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#there-are-too-many-coins-to-choose-from-which-do-i-pick!%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a good question. There are literally thousands! If you don&#39;t believe me take a look at &lt;a href=&quot;https://coinmarketcap.com/all/views/all/&quot;&gt;CoinMarketCap&lt;/a&gt;, which lists them all.&lt;/p&gt;
&lt;p&gt;As I stated at the beginning of my article, I am not interested in which one may go up the most so you can make money. What I am interested in is which coin has the best features for using it as money on a day to day basis.&lt;/p&gt;
&lt;p&gt;Unfortunately, due to the volatility (which I will touch on later) that we still see on a day to day basis with all cryptos, there are none that I would recommend you plough all your money into. However, there are some that cover a lot of other bases.&lt;/p&gt;
&lt;h3 id=&quot;bitcoin&quot; tabindex=&quot;-1&quot;&gt;Bitcoin &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#bitcoin&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/bitcoin-word.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/bitcoin-word.png&quot; alt=&quot;bitcoin&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is the obvious first choice. It is the original cryptocurrency, and as such, is the easiest to get hold of. It also has the most options in terms of where you can use it to buy things. I don&#39;t personally think it represents the future of cryptocurrencies, but for now it is a safe bet.&lt;/p&gt;
&lt;h3 id=&quot;nano&quot; tabindex=&quot;-1&quot;&gt;Nano &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#nano&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/nano.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/nano.png&quot; alt=&quot;nano&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This coin is a little less known, but it does have some features that make it a potential future winner in terms of use as a real currency:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Transactions are completely free (unlike Bitcoin and most (if not all) other cryptocurrency coins, which all have small transaction fees)&lt;/li&gt;
&lt;li&gt;It has implemented wallets on desktop, android and iOS making it easy to use (see the next section for more on wallets)&lt;/li&gt;
&lt;li&gt;Transactions are, near as makes no difference, instant&lt;/li&gt;
&lt;li&gt;Hardware wallets, such as the Ledger Nano S, can be used to increase security&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;monero&quot; tabindex=&quot;-1&quot;&gt;Monero &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#monero&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/monero.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/monero.png&quot; alt=&quot;monero&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This coin is the original privacy coin. Transactions are for all intents and purposes completely anonymous, making it great for people who need some privacy (think overbearing governments, dictatorships, law enforcement etc.).&lt;/p&gt;
&lt;p&gt;As a downside I would say it&#39;s not the easiest to use. However, that is changing quickly with the introduction of mobile and lite wallets, and also the integration of hardware wallets.&lt;/p&gt;
&lt;p&gt;The three I have mentioned above represent what I consider to be projects that serve a purpose. They also seem to have good teams behind their ongoing development (or in the case of Bitcoin are just the biggest at the moment). There are other big players like Ethereum, Litecoin, Ripple etc. With a little research you may find a coin that fits your needs better, but for now the above is what I think represent some projects that have the potential to achieve some real world success.&lt;/p&gt;
&lt;h2 id=&quot;wallets&quot; tabindex=&quot;-1&quot;&gt;Wallets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#wallets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the fundamental things to consider with cryptocurrencies is security. This is where wallets come in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/wallet.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/wallet.jpg&quot; alt=&quot;wallet&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wallets are basically a place where you store your cyptocurrencies, exactly the same as your bank account. Now you may say &amp;quot;I already have cryptocurrencies stored on the exchange (Kraken, Coinbase, Binance etc.)&amp;quot;. You would of course be correct, it is stored on the exchange, but they shouldn&#39;t stay there...&lt;/p&gt;
&lt;h3 id=&quot;problems-with-keeping-money-on-an-exchange&quot; tabindex=&quot;-1&quot;&gt;Problems with keeping money on an exchange &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#problems-with-keeping-money-on-an-exchange&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firstly, you don&#39;t own the private key that stores the cryptocurrencies, the exchange does. What this basically means is that if the exchange disappears over night or decides to lock you out for whatever reason, you have no way to get your money! This has actually happened before, so don&#39;t think it is impossible. I&#39;m not saying it is very likely, but just bear in mind that it can happen, and it&#39;s too late when it does.&lt;/p&gt;
&lt;p&gt;The second problem is that if you want to try and spend some of your cryptocurrencies, in a shop for example, you can&#39;t do that efficiently from the exchange, as exchanges are not designed with this feature in mind.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NEVER keep more cryptocurrency on an exchange than you need to, keep them in a wallet that YOU control.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what is the solution...Wallets!&lt;/p&gt;
&lt;p&gt;Wallets allow you, and you alone, to have access and control over your money. You will own the private key, and the private key is the only bit of information that can access the money in the account. You will also have a public key that allows people to send money to you.&lt;/p&gt;
&lt;p&gt;Furthermore depending on the specific cryptocurrency, you may have access to specialised wallet features that enhance usability or security.&lt;/p&gt;
&lt;p&gt;In essence always follow this rule:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NEVER keep more cryptocurrency on an exchange than you need to, keep them in a wallet that YOU control.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-exactly-is-a-wallet-then%3F&quot; tabindex=&quot;-1&quot;&gt;What exactly is a wallet then? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-exactly-is-a-wallet-then%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The title wallet is maybe a little bit misleading, as the wallet that you create (or own) actually contains no cryptocurrency at all. It is essentially the information that allows you to access the money that you &amp;quot;own&amp;quot; on the blockchain (a blockchain is just a big, publicly available, secure and immutable database as we discussed in a previous section).&lt;/p&gt;
&lt;p&gt;The best analogy is your bank account. You have a bank account number so that people can send you money (equivalent of your public key of your wallet), banking login credentials and debit card so you can send people money, and manage your funds (equivalent of your private key of your wallet). However, the money you have in your account is just an entry in the database of the bank (blockchain of that particular cryptocurrency).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your private key should be known by you and you alone.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A wallet can then be stated as basically the information needed to access your account (private key), send money (private key) and receive money (public key). There is no actual cryptocurrency in your wallet, it is always stored remotely in the blockchain.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/cryptocurrencies.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/cryptocurrencies.jpg&quot; alt=&quot;cryptocurencies&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Therefore, a wallet consists literally of a private key and a public key. Which are two different strings of random numbers and letters. Which when you think about it is very, very simple.&lt;/p&gt;
&lt;p&gt;What is important though is &lt;strong&gt;HOW&lt;/strong&gt; this information is both created and stored. This is where the types of wallet come in.&lt;/p&gt;
&lt;h3 id=&quot;what-wallet-%22types%22-are-there%3F&quot; tabindex=&quot;-1&quot;&gt;What wallet &amp;quot;types&amp;quot; are there? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-wallet-%22types%22-are-there%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are basically three different types of wallet. Hardware, software and paper. They all do exactly the same job, all it comes down to is the balance between convenience and security.&lt;/p&gt;
&lt;h4 id=&quot;software-wallets&quot; tabindex=&quot;-1&quot;&gt;Software Wallets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#software-wallets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Software wallets are the most common and convenient way to store cryptocurrencies, but they are also the least secure. They take the form of android or iPhone applications or desktop applications. They can also be accessed through a website.&lt;/p&gt;
&lt;p&gt;For example if you want to create a nano wallet you can download the nano wallet app from the playstore or apple appstore. The app will then take you through the process of creating a new wallet step by step.&lt;/p&gt;
&lt;p&gt;At some point it will show you a set of seed words that you should copy down and keep safe. This will allow you to regenerate the wallet should you lose your phone or device where the wallet is stored.&lt;/p&gt;
&lt;h5 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;Security &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#security&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;The thing that makes software wallets less secure than other methods is that the private key is stored in the software. Therefore, if someone was able to compromise the software, then they might get your private key. However, in practice this is unlikely.&lt;/p&gt;
&lt;p&gt;The other possibility is that someone has access to your device when you create the wallet, and copies your seed words. This is more likely than a wallet hack, and you should make sure that you only create wallets on devices you know and trust.&lt;/p&gt;
&lt;h4 id=&quot;hardware-wallets&quot; tabindex=&quot;-1&quot;&gt;Hardware Wallets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#hardware-wallets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Hardware wallets are the most secure, and in a lot of ways the easiest to use. If I had to recommend a way of storing your cryptocurrencies it would, without a second thought, be on a hardware wallet. Furthermore, if I had to recommend a specific hardware wallet it would be the &lt;a href=&quot;https://www.ledger.com/products/ledger-nano-s&quot;&gt;&lt;strong&gt;Ledger Nano S&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/ledger-nano-s.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/ledger-nano-s.png&quot; alt=&quot;ledger nano s&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A hardware wallet is basically a small usb device that you can plug into your computer or smartphone that lets you send, receive and manage your cryptocurrencies. The thing that makes the device so secure is that the private key is kept inside the device, but it never leaves the device. Not even you know what the private key is, and you don&#39;t need to know, as long as you have the device.&lt;/p&gt;
&lt;h5 id=&quot;what-if-i-lose-it!&quot; tabindex=&quot;-1&quot;&gt;What if I lose it! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#what-if-i-lose-it!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;You may be thinking &amp;quot;but what if I lose the device!&amp;quot;. Well this is where the seed words come in. When you set up the device you are given a list of approximately 25 small words to write down. This is only done once, and the words uniquely identify how your device was initialised during setup. Therefore if you ever lose your device, you can enter the same 25 words into a brand new hardware wallet, and it will be initialised identically to the one you lost.&lt;/p&gt;
&lt;p&gt;You can then continue as normal as if you never lost the device. The private key generated inside the device will be exactly the same.&lt;/p&gt;
&lt;p&gt;As you would expect the 25 words are therefore very important and should be kept very securely in multiple locations as a backup!&lt;/p&gt;
&lt;h5 id=&quot;how-do-i-use-it%3F&quot; tabindex=&quot;-1&quot;&gt;How do I use it? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#how-do-i-use-it%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;In simple terms you plug the device into the computer and confirm a transaction by clicking a button.&lt;/p&gt;
&lt;p&gt;What actually happens is that the device &amp;quot;signs&amp;quot; the transaction with your private key inside the device. It then sends the signed request to transfer funds to the blockchain. The transfer of your money from your funds that exist on the blockchain, to someone else&#39;s account on the blockchain, will only succeed if it was &lt;strong&gt;your&lt;/strong&gt; private key that signed the request.&lt;/p&gt;
&lt;p&gt;As the signing occurs inside the device, your private key is never exposed, and so cannot be stolen! (Please note that the transfer of funds occurs on the blockchain, there is no actual money inside the device).&lt;/p&gt;
&lt;p&gt;Another advantage is that you can access more than one cryptocurrency on a hardware wallet, so you only need one device to manage all your cryptocurrencies.&lt;/p&gt;
&lt;p&gt;Please note that although the hardware wallets can deal with a lot of different cryptocurrencies, they cannot deal with them all, so be sure to check your preferred coin is supported before buying the device.&lt;/p&gt;
&lt;h4 id=&quot;paper-wallet&quot; tabindex=&quot;-1&quot;&gt;Paper wallet &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#paper-wallet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A paper wallet is probably the most secure way to store funds for long periods of time. Unless you are extremely paranoid I would say this method is not necessary. Either the hardware and / or software wallet will cover most use cases.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/key.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/key.jpg&quot; alt=&quot;padlock and key&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To make a paper wallet, run the software needed to create the wallet on a computer that is not connected to the internet (the desktop software for each coin is typically available from the official website of that particular cryptocurrency). Then write on a piece of paper the private and public keys. You then format the drive of the computer used to generate the keys, so the only copy of the private key in existence is on the paper.&lt;/p&gt;
&lt;p&gt;With this method there is no way for anyone to get access to your money, unless they find and copy the piece of paper. You could keep it in a safety deposit box for example. It is also recommended to make multiple copies in case one is lost or destroyed.&lt;/p&gt;
&lt;p&gt;This method is only good if you want to store money for a long time. As to send money you need to use your private key. The only way to use your private key is on a computer connected to the internet, so you can access the blockchain to confirm the transaction. As you *may* have exposed your private key when you used the private key online, you will likely then need to transfer the remaining funds in the original wallet to a newly generated paper wallet to ensure security is to the same level.&lt;/p&gt;
&lt;p&gt;In reality this method only gives you a little bit more security than a hardware wallet, so in my opinion is not worth the effort.&lt;/p&gt;
&lt;h4 id=&quot;recommendation&quot; tabindex=&quot;-1&quot;&gt;Recommendation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#recommendation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In terms of which wallets to use I would therefore recommend the following:&lt;/p&gt;
&lt;p&gt;Software wallets should be used for a limited amount of funds used on a day to day basis for convenience (think current account)&lt;/p&gt;
&lt;p&gt;Hardware wallets should be used to store the bulk of your cryptocurrencies (think savings account). Then use the hardware wallet to top up the software wallet when required.&lt;/p&gt;
&lt;p&gt;Paper wallets are for people who wear tinfoil hats, or have vast, vast amounts of wealth.&lt;/p&gt;
&lt;h2 id=&quot;volatility&quot; tabindex=&quot;-1&quot;&gt;Volatility &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#volatility&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cryptocurrencies are very volatile at the moment. I would expect this to be the case for a while.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/crypto/volatility.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/crypto/volatility.png&quot; alt=&quot;volatile graph&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is mainly down to the fact that the general populous don&#39;t use them. Plus, the majority of the people that do use them seem to only use them as a commodity to make money, rather than for their core technology.&lt;/p&gt;
&lt;p&gt;As the technology is taken into the mainstream this will change. It will also become clearer which of the thousands of coins that are currently available are going to come out on top, and be used by the general populous.&lt;/p&gt;
&lt;p&gt;You could draw a parallel with MySpace vs Facebook: the initial idea was floated by Bitcoin (MySpace), but that does not mean it will be the winner in the end as [insert future top crypto here] (Facebook) will come out on top. Better alternatives may arise, and in the interim there will be many contenders for the crown.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/cryptocurrency-beginners-guide/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Personally, I am convinced that cryptocurrencies will be around permanently in one form or another. What form that eventually takes is anyone&#39;s guess, but rest assured they are not going to disappear soon.&lt;/p&gt;
&lt;p&gt;I am excited to see where it could take us in a few years time when the technology is a bit more mature, and some of the not so great ideas have fizzled out.&lt;/p&gt;
&lt;p&gt;I therefore think it is important that people generally have some kind of grasp of how the technology works. As with so many things in life, the best way to learn is to get your hands dirty! With that in mind I would suggest not putting all your savings into cryptocurrencies just yet, but certainly getting a feel for them is well worth your time.&lt;/p&gt;
&lt;p&gt;If anything in the article is unclear, or you want some more clarification or guidance on something I&#39;ve covered, please don&#39;t hesitate to write a comment below and I&#39;ll do my best to get back to you ASAP.&lt;/p&gt;
&lt;p&gt;Also...on the off chance that my article manages to get you up and running with cryptocurrencies, you could always experiment by sending a small amount my way! Check out my donation cryptocurrency addresses at the link below (and my android app Wanderfile as well if you like):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wanderfile.app/donations/&quot;&gt;Cryptocurrency Donations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Happy spending!&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Make Broadcom Bluetooth Work in Linux (Fedora, Ubuntu)</title>
		<link href="https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/"/>
		<updated>Sun, 30 Sep 2018 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;In my experience Broadcom bluetooth works out of the box on Linux (&lt;a href=&quot;https://www.thetestspecimen.com/posts/broadcom-wifi-modules-fedora/&quot;&gt;unlike Broadcom wifi&lt;/a&gt;). However, after some system updates it has ceased to function, which is quite an annoyance when your mouse works via bluetooth!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is however a way to fix this issue and it basically involves resetting the correct driver.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;notes-and-pre-requisites&quot; tabindex=&quot;-1&quot;&gt;Notes and Pre-requisites &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/#notes-and-pre-requisites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First I want to mention a few of points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;to complete this tutorial you will need an internet connection&lt;/li&gt;
&lt;li&gt;this process has been tested on Fedora 26, 27 and 28, and I know it to be working for those systems. It should also be relevant on Ubuntu and its derivatives&lt;/li&gt;
&lt;li&gt;if (like me) you have a bluetooth mouse, get a usb mouse temporarily!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;let&#39;s-get-started&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s get started &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/#let&#39;s-get-started&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open a terminal and type the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;dmesg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;egrep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue|firm&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output will contain various information, but there will be a particular line that will detail the bluetooth driver that is missing. It will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BCM20702A1-0b05-17cf&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In your case the letters and numbers might be a little different but the format will be the same. Note this down because this is the name of the driver that you need.&lt;/p&gt;
&lt;h2 id=&quot;time-to-get-the-drivers&quot; tabindex=&quot;-1&quot;&gt;Time to get the drivers &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/#time-to-get-the-drivers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://github.com/winterheart/broadcom-bt-firmware&quot;&gt;github repository&lt;/a&gt; that conveniently has all the Broadcom bluetooth firmware files available:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/winterheart/broadcom-bt-firmware/archive/master.zip&quot;&gt;Direct link to download&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Download the repository at the above link and then unzip the file.&lt;/p&gt;
&lt;p&gt;You will now have a directory with bluetooth firmware files in it (within &amp;quot;broadcom-bt-firmware/brcm&amp;quot; of the unzipped file). Go through the files and find the file that matches the output you got above. &lt;strong&gt;Be careful because the files have very similar names.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now copy the file to the following directory, and also change the filename to &amp;quot;BCM.hcd&amp;quot;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/lib/firmware/brcm&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;...or assuming you have the files in your Downloads folder run the following command (replace &amp;quot;filename&amp;quot; with the actual filename you have chosen that matches your Broadcom firmware):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; ~/Downloads/broadcom-bt-firmware-master/brcm/&lt;span class=&quot;token string&quot;&gt;&quot;filename&quot;&lt;/span&gt;.hcd /lib/firmware/brcm/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now reboot...&lt;/p&gt;
&lt;p&gt;Open a command line and run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;dmesg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;egrep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue|firm&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time there should be no error, but if there is then run the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; modprobe &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; btusb &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; modprobe btusb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now your bluetooth should be up and running!&lt;/p&gt;
&lt;h2 id=&quot;credits&quot; tabindex=&quot;-1&quot;&gt;Credits &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/broadcom-bluetooth-fedora/#credits&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Information in this article is predominantly taken from &lt;a href=&quot;https://dev-pages.info/ubuntu-bluetooth/&quot;&gt;this source.&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>What Are Hardware Security Keys Like Yubikey for, How Do They Work, and Do I Need One?</title>
		<link href="https://www.thetestspecimen.com/posts/security-keys-yubikey/"/>
		<updated>Fri, 02 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/security-keys-yubikey/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Hardware security keys are about to become the next big thing in online personal security. They provide a simpler, and more secure, way to protect your important online accounts. . .and no more passwords (at least eventually)!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As with all things new it is a bit mysterious and scary sounding to begin with, but for the majority of people it really is very simple and easy to implement. Let&#39;s get started. . .&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-security-key%3F&quot; tabindex=&quot;-1&quot;&gt;What is a Security Key? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#what-is-a-security-key%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A hardware security key is essentially a physical device (usually a usb stick) that contains cryptographic keys that allow you to log into your accounts by just plugging it into your computer or device. There are also NFC versions that work with smartphones.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/FIDO-keychain5-cc.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/FIDO-keychain5-cc.jpg&quot; alt=&quot;security key yubikey in a computer&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sounds simple, but this method is a LOT more secure than password based access to your accounts.&lt;/p&gt;
&lt;h2 id=&quot;do-i-need-a-hardware-security-key%3F&quot; tabindex=&quot;-1&quot;&gt;Do I need a hardware security key? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#do-i-need-a-hardware-security-key%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course not, but you really, really should consider getting one. It will give you peace of mind that your accounts and data are REALLY secure.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Google has 85,000+ employees and NONE of their work accounts were maliciously taken over, or used by unauthorised persons, after the introduction of hardware security keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just to give you a solid example of how effective this technology is at combating account hacks and stolen data, consider this:&lt;/p&gt;
&lt;p&gt;It has been reported that with the compulsory introduction of hardware security keys at Google the number of employee accounts that were compromised was. . .wait for it. . .ZERO. Google has 85,000+ employees and NONE of their work accounts were maliciously taken over, or used by unauthorised persons, after the introduction of hardware security keys. For more details please refer to this &lt;a href=&quot;https://krebsonsecurity.com/2018/07/google-security-keys-neutered-employee-phishing/&quot;&gt;article&lt;/a&gt; over at &lt;a href=&quot;http://krebsonsecurity.com/&quot;&gt;krebsonsecurity.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Consider also that these companies all use hardware security keys currently to secure their work systems:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/yubikey-companies-kraked.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/yubikey-companies-kraked.jpg&quot; alt=&quot;google, facebook, dropbox, gov.uk, dyson, salesforce, cern, github...&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Companies that use U2F&lt;/figcaption&gt;
&lt;h2 id=&quot;how-do-i-use-it%3F&quot; tabindex=&quot;-1&quot;&gt;How do I use it? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#how-do-i-use-it%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;simple-application&quot; tabindex=&quot;-1&quot;&gt;Simple application &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#simple-application&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can actually use hardware security keys for many applications, but the one most people will want is to log into an account. For example your gmail account or Facebook account.&lt;/p&gt;
&lt;h4 id=&quot;fido-u2f&quot; tabindex=&quot;-1&quot;&gt;FIDO U2F &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#fido-u2f&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;At the moment the protocol used is called FIDO U2F, which is also referred to as second factor authentication.&lt;/p&gt;
&lt;p&gt;Let&#39;s say you have a gmail account that you currently log into with a password. That will not change, you will still use your password as normal, but after you enter your password you will also be requested to plug in your hardware security key. Once that is done you will be logged in. Simple!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/fido-u2f.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/fido-u2f.png&quot; alt=&quot;FIDO U2F&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The setup process is very straight forward. You log into your account and go to the privacy and security section of your account in settings. Go to the section that is called Second Factor Authentication, and you will be guided through adding your key. It will literally ask you to plug it in at the appropriate moment. Very simple. This video shows how simple the process is:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Vja-SC791E8&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/Vja-SC791E8/0.jpg&quot; alt=&quot;Video for google U2F setup&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;fido2&quot; tabindex=&quot;-1&quot;&gt;FIDO2 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#fido2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There is also a new protocol that has just been released called FIDO2. At the time of writing I don&#39;t know of any company or website that actually uses FIDO2 for logins, but it is just a matter of time. There are hardware security keys available that work with FIDO2 now, so you can be prepared (for example the &lt;a href=&quot;https://www.yubico.com/product/security-key-by-yubico/&quot;&gt;Yubico Secrity Key 2&lt;/a&gt; and the &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;Yubico 5 Series&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/fido2.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/fido2.png&quot; alt=&quot;FIDO2&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main difference between FIDO U2F and FIDO2 is that FIDO2 does not need a password at all, just the key!&lt;/p&gt;
&lt;p&gt;Not only will you not have to remember passwords anymore, but it will be more secure and faster as well. You really can&#39;t lose. . .but you will have to wait a little until it becomes mainstream.&lt;/p&gt;
&lt;h3 id=&quot;more-complicated-applications&quot; tabindex=&quot;-1&quot;&gt;More complicated applications &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#more-complicated-applications&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are very tech savvy and have requirements beyond FIDO U2F and FIDO2, then some hardware security key devices also have the ability to use the following protocols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenPGP&lt;/li&gt;
&lt;li&gt;OATH-TOTP&lt;/li&gt;
&lt;li&gt;OATH-HOTP&lt;/li&gt;
&lt;li&gt;Challenge-Response&lt;/li&gt;
&lt;li&gt;Storage of long password strings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can allow you to achieve many things such as sending files and emails more securely, log into remote servers, log into windows, the list goes on...&lt;/p&gt;
&lt;h2 id=&quot;can-i-use-it-on-all-my-devices%3F&quot; tabindex=&quot;-1&quot;&gt;Can I use it on all my devices? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#can-i-use-it-on-all-my-devices%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yes you can, but this depends on how you connect the key to your device.&lt;/p&gt;
&lt;p&gt;Most keys use a standard USB Type A interface like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/YubiKey-4-1000-2016.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/YubiKey-4-1000-2016.png&quot; alt=&quot;security key with usb type-a&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Therefore you wouldn&#39;t be able to use it with a smartphone, or a device that only has a USB Type C port. Although there are a range of different devices available to cover those needs as well, including a NFC interface and USB Type C.&lt;/p&gt;
&lt;p&gt;If you want an in depth view of the different types of hardware security key devices available check out my related article &lt;a href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/YubiKey-NEO-phone-use.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/YubiKey-NEO-phone-use.png&quot; alt=&quot;security key with bluetooth&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-makes-it-so-secure%3F&quot; tabindex=&quot;-1&quot;&gt;What makes it so secure? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#what-makes-it-so-secure%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The process it uses to confirm the key is yours, and only yours, is what makes it so secure.&lt;/p&gt;
&lt;p&gt;In basic terms, it uses something called private-public key cryptography using the method of challenge-response.&lt;/p&gt;
&lt;p&gt;What you effectively have is a private key (which is a long string of random letters and numbers) on the hardware security key, and a public key (a different long string of random numbers and letters) on the hardware security key. You &amp;quot;send&amp;quot; the public key to the service (e.g. gmail) when you register the hardware security key.&lt;/p&gt;
&lt;p&gt;When you try to log into your account using the hardware security key, the website recognises which device it is (based on the public key, which is unique to your hardware security key) and sends a &amp;quot;challenge&amp;quot; to the device, which is created from a calculation made with your public key. The hardware security key then &amp;quot;solves&amp;quot; the challenge internally and returns the result, which the website checks against the public key. If the public key says the response is correct then you pass, otherwise you fail.&lt;/p&gt;
&lt;p&gt;There are a couple of items to note during this process which make it secure:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your private key is on your hardware security key and NEVER leaves the hardware security key. Your hardware security key only sends a &amp;quot;response&amp;quot; back with the solution to the challenge, never the private key. That means there is (practically) no way for someone to know what your private key actually is. Not even you will know! That means it can&#39;t be compromised, ever.&lt;/li&gt;
&lt;li&gt;The correct response to the challenge can only be generated by &lt;strong&gt;your&lt;/strong&gt; private key, nothing else.&lt;/li&gt;
&lt;li&gt;The challenge is different every time, so even if someone intercepts the response, they can&#39;t use it later to get into your account.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;are-there-any-downsides%3F&quot; tabindex=&quot;-1&quot;&gt;Are there any downsides? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#are-there-any-downsides%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a few things to consider.&lt;/p&gt;
&lt;h3 id=&quot;where-you-can-use-it&quot; tabindex=&quot;-1&quot;&gt;Where you can use it &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#where-you-can-use-it&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the moment you cannot use FIDO U2F everywhere, for all your accounts. It is widely used by a lot of major websites and companies, but not universally. This means you won&#39;t be able to make everything very secure just yet. Some of the places I use it at the moment (there are more than this available):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Facebook&lt;/li&gt;
&lt;li&gt;Twitter&lt;/li&gt;
&lt;li&gt;Dropbox&lt;/li&gt;
&lt;li&gt;all google accounts&lt;/li&gt;
&lt;li&gt;personal email accounts&lt;/li&gt;
&lt;li&gt;github&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;browser-support&quot; tabindex=&quot;-1&quot;&gt;Browser Support &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#browser-support&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;U2F is only supported by certain browsers at the moment, which limits its use if you don&#39;t want to use one of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome&lt;/li&gt;
&lt;li&gt;Firefox&lt;/li&gt;
&lt;li&gt;Opera&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although others are likely in the pipeline.&lt;/p&gt;
&lt;h2 id=&quot;what-if-i-lose-it%3F&quot; tabindex=&quot;-1&quot;&gt;What if I lose it? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#what-if-i-lose-it%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ah yes! this is a good point. If you setup a hardware security key on an account, then lose it, you will be in a bit of a pickle. However, it is common practise (i.e. it is forced on you by the website you are trying to activate the hardware security key with) to insist on having a backup second factor authentication method setup.&lt;/p&gt;
&lt;p&gt;I recommend one of the following:&lt;/p&gt;
&lt;h3 id=&quot;setup-two-hardware-security-keys&quot; tabindex=&quot;-1&quot;&gt;Setup two hardware security keys &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#setup-two-hardware-security-keys&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The absolute best solution is to have (at least) two hardware security keys. You can typically setup more than one hardware security key on the same account. This way you can carry one with you, and keep the other in a safe place for emergencies. This will allow you to get into your accounts should you lose the main hardware security key.&lt;/p&gt;
&lt;h3 id=&quot;alternative-two-factor-authentication-method&quot; tabindex=&quot;-1&quot;&gt;Alternative two factor authentication method &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#alternative-two-factor-authentication-method&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don&#39;t have this option, you should setup a different two factor authentication method which uses a TOTP (time based one time password). This is typically available as an option of two factor authentication wherever a hardware security key is accepted. If you decide to go down this route you will need an app or program that generates the passwords, which are typically 6 digit numbers, and change every 20 seconds or so.&lt;/p&gt;
&lt;p&gt;I recommend &lt;a href=&quot;https://authy.com/&quot;&gt;Authy&lt;/a&gt; as it is available on android, ios and desktop. It will also keep things backed-up should you lose your phone / laptop which the app is installed on.&lt;/p&gt;
&lt;h2 id=&quot;which-hardware-security-key-should-i-buy%3F&quot; tabindex=&quot;-1&quot;&gt;Which hardware security key should I buy? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#which-hardware-security-key-should-i-buy%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;brands&quot; tabindex=&quot;-1&quot;&gt;Brands &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#brands&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are various hardware security keys available on places like amazon (I can&#39;t vouch for their credability), but the leader in the market is &lt;a href=&quot;https://www.yubico.com/&quot;&gt;Yubico&lt;/a&gt;, which produces the Yubikey.  The only other &amp;quot;big&amp;quot; player at the moment that I am aware of is &lt;a href=&quot;https://www.ftsafe.com/&quot;&gt;Feitian&lt;/a&gt; if you really want an alternative.&lt;/p&gt;
&lt;p&gt;However, being one of the initial members of the FIDO Alliance, who set the standards for U2F, I would say Yubico are a solid bet when it comes to hardware security keys.&lt;/p&gt;
&lt;p&gt;Their main products are also high quality in terms of build, with the standard hardware keys featuring waterproof and crush-proof designs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-keys/press_diving.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-keys/press_diving.jpg&quot; alt=&quot;yubikey being used underwater&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you want a more in depth look at the Yubico hardware security keys, and also recommendations on which one you should buy to suit your needs, then check out our &lt;a href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/&quot;&gt;Yubikey article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hardware security keys for securing your accounts are the future. They effectively eliminate account takeovers, and will eventually make keeping track of your numerous online accounts manageable, without the hassle of remembering passwords.&lt;/p&gt;
&lt;p&gt;I think FIDO U2F and FIDO2 protocols have achieved what a lot of previous attempts have failed to, and that is to make the system simple for the average user.&lt;/p&gt;
&lt;p&gt;Currently FIDO U2F requires a password AND the physical key, and I expect that is just too much hassle for the masses, but FIDO2 represents a noticeable (and welcome) change to the process by &lt;strong&gt;eliminating passwords completely&lt;/strong&gt;. I think it is the removal of passwords that will eventually see this technology accepted by everyone.&lt;/p&gt;
&lt;p&gt;Bring on FIDO2!&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>VPN (Virtual Private Network) - What Is It and Do I Need One?</title>
		<link href="https://www.thetestspecimen.com/posts/do-i-need-a-vpn/"/>
		<updated>Mon, 05 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/do-i-need-a-vpn/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;A VPN (Virtual Private Network) is basically an encrypted/secure connection to a remote server. This allows you to access the internet anonymously. The question is, if I am a normal law abiding citizen do I need one? The simple answer is yes, and I will explain why in this article.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-does-an-ordinary-joe-need-a-vpn%3F&quot; tabindex=&quot;-1&quot;&gt;Why does an ordinary Joe need a VPN? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#why-does-an-ordinary-joe-need-a-vpn%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s say you want to access a website. To do that you go to your computer and type in the internet address of the website. When you press the enter button it sends a message to the website to tell it to send you the web page you want. You receive the data, and the web page loads on your computer.&lt;/p&gt;
&lt;h3 id=&quot;the-failing-points&quot; tabindex=&quot;-1&quot;&gt;The failing points &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#the-failing-points&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, for that to happen you basically sent some data down a wire or through the air (wifi) to your router/modem. It then passes the request on to your ISP (internet service provider), who then pass on the request to the internet site. Then it comes back through the same route. Already we have various points at which the information you sent is accessible:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;wireless routers can be hacked relatively easily (if you don&#39;t believe me take a look at this &lt;a href=&quot;http://www.howtogeek.com/185526/is-it-really-possible-for-most-enthusiasts-to-hack-wi-fi-networks/&quot;&gt;article&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;your ISP can not only see what you are doing, but is probably logging what you are doing too. If a government or the police want to investigate you, they will be able to request this information from the ISP, and they will get it&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Security is actually not so much a question of &#39;can it be hacked&#39;, but &#39;how long will it take&#39; to hack&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;davidgo (SuperUser Contributor)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;...but-vpn&#39;s-are-just-for-dodgy-people.-right%3F&quot; tabindex=&quot;-1&quot;&gt;...but VPN&#39;s are just for dodgy people. Right? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#...but-vpn&#39;s-are-just-for-dodgy-people.-right%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At this point you may be thinking &amp;quot;so what? I don&#39;t care if they know what websites I visit anyway. VPNs are just for people who want to hide their tracks when doing something dodgy online.&amp;quot;&lt;/p&gt;
&lt;p&gt;If you are not doing anything dodgy online that is great, but consider this. If someone has access to your router they can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hijack your connection and send you to malicious websites that contain viruses&lt;/li&gt;
&lt;li&gt;They can log all of your information&lt;/li&gt;
&lt;li&gt;They can steal your login information, bank details etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/vpn/hacker.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/vpn/hacker.jpg&quot; alt=&quot;Hacker&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s leave the relative security of the home setup for a moment, and move to mobile. How many times have you logged into a public wifi network on your phone? Do you trust all of those freely available networks? Do you know that they haven&#39;t been compromised? Do you know who operates them?&lt;/p&gt;
&lt;p&gt;The answer is probably &amp;quot;no, I don&#39;t know&amp;quot;, and I suspect generally you didn&#39;t even think about it.&lt;/p&gt;
&lt;h3 id=&quot;you-are-more-valuable-than-you-think&quot; tabindex=&quot;-1&quot;&gt;You are more valuable than you think &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#you-are-more-valuable-than-you-think&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My point is that in today&#39;s world most people are connected to the internet most of the time, and your information is valuable, even if you think it is not. There are criminal organisations making millions from credit card details and identity theft. Then if you are unfortunate enough to live in a country with an oppressive government, you have that to worry about too.&lt;/p&gt;
&lt;p&gt;It is wise to reduce the potential points of access to your information if at all possible.&lt;/p&gt;
&lt;h2 id=&quot;so-how-can-a-vpn-help%3F&quot; tabindex=&quot;-1&quot;&gt;So how can a VPN help? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#so-how-can-a-vpn-help%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;encryption&quot; tabindex=&quot;-1&quot;&gt;Encryption &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#encryption&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;VPNs provide an encrypted connection between your computer and a remote server (in this case your VPN provider). It is often described as a &amp;quot;secure tunnel&amp;quot; between you and the remote VPN server.&lt;/p&gt;
&lt;p&gt;If you are not sure what encryption is, it basically takes the data you send/receive from your computer, and changes it into something that makes no sense should someone try to intercept it. It only makes sense again once it is decrypted by you or the VPN server you connect to.&lt;/p&gt;
&lt;p&gt;This means that if someone hacks your router with the intention of monitoring your online activity, they will only receive nonsense. If your ISP (or the police/government) want to see what you are up to, all they can see is that you are connected to the VPN server. They won&#39;t see any web pages you visit, or anything else for that matter.&lt;/p&gt;
&lt;h3 id=&quot;where-is-the-encryption%3F&quot; tabindex=&quot;-1&quot;&gt;Where is the encryption? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#where-is-the-encryption%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you have sent the website request to the VPN provider, which is encrypted. The VPN server then sends a request to whichever website or server you want to access. The response from the server / website is then sent back to you through the VPN. Now I should point out that although the connection from the VPN to the website *could* be encrypted, it also may not be. The VPN has no control over the security of the connection to the website as it is determined by the website not the VPN.&lt;/p&gt;
&lt;p&gt;If you are trying to hide your tracks this may sound a bit pointless, but remember, they can only see the IP address of the VPN server, not your personal IP address. So although they see what you are doing, they don&#39;t know who is doing it.&lt;/p&gt;
&lt;h3 id=&quot;shared-ip-addresses&quot; tabindex=&quot;-1&quot;&gt;Shared IP Addresses &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#shared-ip-addresses&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One final trick VPN providers have is that they don&#39;t assign a unique IP address to everybody connected to the VPN. You will effectively share an external facing IP address with a large number of other people. This is important, as it makes it much more difficult to figure out who is doing what.&lt;/p&gt;
&lt;p&gt;As an example, I may be able to figure out that you used a particular VPN IP address. Perhaps you visit my website and I log your VPN IP address when you log into your account. This means that I definitely know that it is you as I can match your account login to the IP address. However, due to the shared IP address used by the VPN I cannot assume that all traffic from that IP address is you. It could be any of the hundreds or thousands of other people utilising that IP address.&lt;/p&gt;
&lt;h2 id=&quot;are-there-any-other-benefits%3F&quot; tabindex=&quot;-1&quot;&gt;Are there any other benefits? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#are-there-any-other-benefits%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apart from the obvious fact that your data is encrypted, you may find some of these features useful:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Typically VPN providers will have many servers, and usually they are in different countries. This allows you to appear, to the website you are visiting, as if you are from a country you are not physically in. Why would you want to do this? Well people typically do this to access region restricted content such as tv and movie subscription services. (I want to point out that Netflix has recently taken a hard stance against this practice, and at the moment they block VPN access to their content.)&lt;/li&gt;
&lt;li&gt;Bypass network restrictions. For example if your work, school or even government network blocks particular websites, you can connect to a VPN, and access will be possible&lt;/li&gt;
&lt;li&gt;It can in some circumstances speed up your connection. If your ISP restricts international bandwidth, or throttles certain services you can then bypass this restriction by connecting to a VPN in your home country&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/vpn/security-department.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/vpn/security-department.png&quot; alt=&quot;World Network&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;are-there-any-downsides%3F&quot; tabindex=&quot;-1&quot;&gt;Are there any downsides? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#are-there-any-downsides%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In theory you may lose a little connection speed, as you need to route all your internet traffic through a remote server. However, in reality you will hardly notice at all assuming you pick a good VPN provider (I recommend &lt;a href=&quot;http://tspc.men/recommendspia&quot;&gt;Private Internet Access&lt;/a&gt; as a VPN. I go into more detail as to why in the sections below).&lt;/p&gt;
&lt;h2 id=&quot;is-there-anything-else-i-should-be-aware-of%3F&quot; tabindex=&quot;-1&quot;&gt;Is there anything else I should be aware of? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#is-there-anything-else-i-should-be-aware-of%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Absolutely. There is one last thing that is &lt;strong&gt;VERY&lt;/strong&gt; impotant:&lt;/p&gt;
&lt;p&gt;Make sure that the VPN provider does not keep logs at all. This means any data that could identify you directly, or when you used the service, including logon and logoff times. Literally nothing should be kept. This ensures that if anybody sends a request to the VPN for information regarding a particular person or connection, they are unable to provide anything. Even if the VPN is raided by the police, there would be nothing to see.&lt;/p&gt;
&lt;h2 id=&quot;ok-i-want-a-vpn-but-how-much-does-it-cost-and-is-it-complicated%3F&quot; tabindex=&quot;-1&quot;&gt;Ok I want a VPN but how much does it cost and is it complicated? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#ok-i-want-a-vpn-but-how-much-does-it-cost-and-is-it-complicated%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is not complicated at all, as long as you use a decent VPN provider. Typically they have an app (android and iOS) for your phone/tablet, and a Windows/Mac/Linux program for your computer, which installs like any other program. Connection to the VPN is usually one click!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make sure that the VPN provider does not keep logs at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are free VPN providers, which will work fine. However, typically they either cap the speed of your connection, cap downloads, or limit the servers you have access to. If you can put up with some of these limitations then I recommend &lt;a href=&quot;http://tspc.men/recommendscyberghost&quot;&gt;Cyberghosts&lt;/a&gt; free service.&lt;/p&gt;
&lt;p&gt;If you want an easy to use and unlimited access VPN it is better to pay. It doesn&#39;t cost much either. The paid VPN provider I recommend is &lt;a href=&quot;http://tspc.men/recommendspia&quot;&gt;Private Internet Access&lt;/a&gt; and it costs (at the time of writing) $6.95 a month or as low as $3.33 a month if you sign up for a year. I can personally attest to the quality of this VPN as I use it myself. I think it is a small price to pay for the security it provides.&lt;/p&gt;
&lt;p&gt;Both of the services I recommend above do not keep any logs of your activity, which is very important.&lt;/p&gt;
&lt;h2 id=&quot;further-research&quot; tabindex=&quot;-1&quot;&gt;Further research &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/#further-research&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want an more information I would recommend looking at &lt;a href=&quot;https://torrentfreak.com/anonymous-vpn-service-provider-review-2015-150228/&quot;&gt;this article&lt;/a&gt; on torrentfreak. They basically sent an email to a large number of VPN providers and asked a few poignant questions. The answers they receive back are a great help in understanding who to trust, and who to avoid like the plague.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Fedora 29 Workstation – What’s New in the Latest and Greatest?</title>
		<link href="https://www.thetestspecimen.com/posts/fedora-29-release/"/>
		<updated>Wed, 07 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/fedora-29-release/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;At the end of October a new release of Fedora Workstation was made available: Fedora 29.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I just wanted to give a brief overview of what has changed, and some of the things to look out for.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;...so-what-has-changed-since-fedora-28%3F&quot; tabindex=&quot;-1&quot;&gt;...so what has changed since Fedora 28? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#...so-what-has-changed-since-fedora-28%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a quick list of the updates and additions. I go into more detail on each  point further into the article:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt; - this is the big change with this release, and potentially an important one, both now and for the future.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GNOME has been updated to 3.30&lt;/strong&gt; - Lots of new features and improved performance. Another important change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flatpak support is integrated by default&lt;/strong&gt;. This (potentially) represents the future of Linux inter-distribution package development.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inclusion of non-free packages&lt;/strong&gt; (if you enable them). Can be both good or bad depending on your viewpoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New wallpaper&lt;/strong&gt;. I&#39;m always in anticipation of the new wallpaper, and this one has been released with a dynamic version (more on that later).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS 1.3.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hidden Grub.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Various software package updates&lt;/strong&gt; (Python etc.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;modularity&quot; tabindex=&quot;-1&quot;&gt;Modularity &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#modularity&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a big one. Going forward this has a lot of potential.&lt;/p&gt;
&lt;p&gt;One of the big advantages of running Fedora is that it tends to be the linux distribution with the latest software packages. It is considered bleeding edge.&lt;/p&gt;
&lt;h3 id=&quot;being-at-the-bleeding-edge-has-downsides&quot; tabindex=&quot;-1&quot;&gt;Being at the bleeding edge has downsides &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#being-at-the-bleeding-edge-has-downsides&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Being at the forefront is great, but it does have a downside, especially if you are involved in software coding and design. For example you may have a software stack that utilises Python 3.6. Then you upgrade Fedora, and it now comes with Python 3.7. . .ooops!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/404-error.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/404-error.jpg&quot; alt=&quot;404 Error&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So now you have an issue. Your code is broken until you re-write it to be compatible with Python 3.7 (this is of course hypothetical and could be applied to many things, but you get the point).&lt;/p&gt;
&lt;h3 id=&quot;what-if-you-could-have-old-and-new-together%3F&quot; tabindex=&quot;-1&quot;&gt;What if you could have old and new together? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#what-if-you-could-have-old-and-new-together%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is where the modularity comes in.&lt;/p&gt;
&lt;p&gt;You can have a self contained module that runs Python 3.6, and a different one that contains Python 3.7. This allows you to keep a stable setup in one module, whilst taking advantage of the newer 3.7 version in a separate module.&lt;/p&gt;
&lt;p&gt;This could be used to test your upgrade path, or just try out new features, but the point is you have the choice!&lt;/p&gt;
&lt;h3 id=&quot;it-is-like-a-new-form-of-long-term-support-(lts)&quot; tabindex=&quot;-1&quot;&gt;It is like a new form of Long Term Support (LTS) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#it-is-like-a-new-form-of-long-term-support-(lts)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the oft mentioned downsides of Fedora is that it has a six month upgrade cycle, which is pretty rapid by any standard.&lt;/p&gt;
&lt;p&gt;Therefore, people often ask why an LTS version isn&#39;t offered. The simple answer is that it would require way too much work, and therefore money, to implement.&lt;/p&gt;
&lt;p&gt;If you don&#39;t believe me you can hear it from the horses mouth in this great interview with Fedora project leader Matthew Miller.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KLFnxwmhXVk&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/KLFnxwmhXVk/0.jpg&quot; alt=&quot;Matthew Miller intverview about Fedora&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you really think about it, what LTS provides is stability. Usually, that stability is achieved by not upgrading your operating system for a long time (in the order of years). This allows you to keep the base up to date (think security patches), whilst software versions remain stable.&lt;/p&gt;
&lt;p&gt;However, if you have the ability to continue to run the same software versions, even after an operating system upgrade, then LTS is not really required.&lt;/p&gt;
&lt;p&gt;The modularity that has been introduced in Fedora 29 gives you inherent stability if you require it, whilst also giving you access to the latest software versions. This enhances your ability to upgrade software smoothly.&lt;/p&gt;
&lt;p&gt;Furthermore, it also has the potential to work the other way around. . .there is more on that in the video above, but essentially it would allow Red Hat Enterprise Linux (RHEL) versions (which tend to be more LTS oriented) to take advantage of the more up to date software versions available in Fedora.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/redhat.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/redhat.png&quot; alt=&quot;redhat linux logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Redhat Linux (RHEL)&lt;/figcaption&gt;
&lt;p&gt;Modularity is an excellent addition all round, for now, and the future.&lt;/p&gt;
&lt;h2 id=&quot;gnome-3.30&quot; tabindex=&quot;-1&quot;&gt;GNOME 3.30 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#gnome-3.30&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GNOME is another of the main updates with regard to the release of Fedora 29. Some exciting and useful features are now available.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/GnomeLogoHorizontal.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/GnomeLogoHorizontal.png&quot; alt=&quot;GNOME logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;figcaption&gt;GNOME 3.30 now included in Fedora 29&lt;/figcaption&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I have picked out some specific new features that are of interest below, but for a full list be sure to checkout the &lt;a href=&quot;https://help.gnome.org/misc/release-notes/3.30/&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;performance&quot; tabindex=&quot;-1&quot;&gt;Performance &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#performance&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A major criticism of GNOME has always been that it is resource hungry. This has been somewhat remedied in this release, with a reduced RAM footprint and various behind the scenes fixes for memory leaks and the like.&lt;/p&gt;
&lt;h3 id=&quot;flatpaks&quot; tabindex=&quot;-1&quot;&gt;Flatpaks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#flatpaks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Flatpaks essentially represent (potentially at least) the future of how Linux software will be produced and distributed on the workstation variants of Linux.&lt;/p&gt;
&lt;p&gt;Currently if you want to produce software for Linux workstations you would have to consider the different package distribution types (rpm and deb), which I understand is not particularly straight forward. Flatpaks can be used on any Linux distribution. This simplifies the production process for developers.&lt;/p&gt;
&lt;p&gt;In addition, the new version of GNOME features automatic updates of Flatpaks, making the workstation users life easier as well.&lt;/p&gt;
&lt;p&gt;You can check out available software at &lt;a href=&quot;https://flathub.org/&quot;&gt;Flathub&lt;/a&gt;, which is the central repository for Flatpaks.&lt;/p&gt;
&lt;h3 id=&quot;veracrypt-integration&quot; tabindex=&quot;-1&quot;&gt;VeraCrypt Integration &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#veracrypt-integration&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;VeraCrypt (previously known as TrueCrypt) allows you to create encrypted containers (could be a file or a whole drive). Including advanced features such as hidden volumes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/VeraCrypt_Logo.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/VeraCrypt_Logo.png&quot; alt=&quot;VeraCrypt Logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;figcaption&gt;VeraCrypt (formally TrueCrypt)&lt;/figcaption&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;GNOME Disks utility now has the ability to decrypt and mount VeraCrypt volumes natively.&lt;/p&gt;
&lt;p&gt;An excellent addition for the security conscious.&lt;/p&gt;
&lt;h3 id=&quot;other-features&quot; tabindex=&quot;-1&quot;&gt;Other Features &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#other-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Apart from the above there is also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;improved screen sharing&lt;/li&gt;
&lt;li&gt;settings now features thunderbolt devices&lt;/li&gt;
&lt;li&gt;a more streamlined location and search bar in the Files app&lt;/li&gt;
&lt;li&gt;improvements to the GNOME note taking app Notes&lt;/li&gt;
&lt;li&gt;minimal reader view for webpages&lt;/li&gt;
&lt;li&gt;Windows server remote desktop access with RDP&lt;/li&gt;
&lt;li&gt;A new podcasts app&lt;/li&gt;
&lt;li&gt;More games&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;non-free-packages-included&quot; tabindex=&quot;-1&quot;&gt;Non-Free packages included &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#non-free-packages-included&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a limited number of non-free (i.e. proprietary) software packages available for install with Fedora 29. By default they are not installed, but the option is there.&lt;/p&gt;
&lt;h3 id=&quot;uh-oh!-this-is-a-slippery-slope...&quot; tabindex=&quot;-1&quot;&gt;Uh Oh! This is a slippery slope... &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#uh-oh!-this-is-a-slippery-slope...&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the reasons that people in the past have chosen to go with fedora is that by default &lt;strong&gt;ONLY&lt;/strong&gt; open source software is available upon install. With the release of Fedora 29 this is no longer the case, and there will be some people thinking that this is the beginning of the end for Fedora and its open source roots.&lt;/p&gt;
&lt;p&gt;Add this to the fact that IBM has acquired RHEL, and you have yourself quite the conspiracy story!&lt;/p&gt;
&lt;h3 id=&quot;it-is-likely-for-the-better&quot; tabindex=&quot;-1&quot;&gt;It is likely for the better &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#it-is-likely-for-the-better&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The fact is that you can still install Fedora, and without any effort whatsoever be guaranteed that you are still open source only.&lt;/p&gt;
&lt;p&gt;Even in previous Fedora releases it has always been a breeze to get proprietary packages due to the presence of the RPMFusion repository. It&#39;s not like we are opening the floodgates all of a sudden.&lt;/p&gt;
&lt;p&gt;. . .so the limited proprietary software that has been made available is likely just to ease the pain of installing software that the vast majority need anyway.&lt;/p&gt;
&lt;p&gt;As an example, I understand Nvidia users have a very hard time due to Nvidia drivers being proprietary, which with Fedora 29 should be a thing of the past!&lt;/p&gt;
&lt;p&gt;As for IBM acquiring RHEL, only time will tell. . .&lt;/p&gt;
&lt;h2 id=&quot;new-wallpaper!&quot; tabindex=&quot;-1&quot;&gt;New Wallpaper! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#new-wallpaper!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is my favourite part!&lt;/p&gt;
&lt;p&gt;The designs of the Fedora wallpapers are something to look forward to. Elegant, simple and imaginative without being tacky or distracting.&lt;/p&gt;
&lt;p&gt;Here is the new Fedora 29 wallpaper:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/fedora-29-background-day.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/fedora-29-background-day.jpg&quot; alt=&quot;Fedora 29 Background&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Fedora 29 desktop background&lt;/figcaption&gt;
&lt;p&gt;However, this time there is a twist. . .you can also have a dynamic version of the wallpaper!&lt;/p&gt;
&lt;p&gt;What this basically means is that as the day passes by, the colours in the wallpaper gradually change to reflect the time of day. It is a simple but beautiful concept. Here are the four wallpapers that it graduates between as the day wears on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/fedora-29-dawn-day-dusk-night.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/fedora-29-dawn-day-dusk-night.jpg&quot; alt=&quot;Fedora 29 Dynamic Wallpaper Transitions&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Fedora 29 - Dynamic Wallpapers&lt;/figcaption&gt;
&lt;p&gt;You will however have to install and activate the dynamic wallpaper manually, so run this:&lt;/p&gt;
&lt;p&gt;sudo dnf install f29-backgrounds-animated&lt;/p&gt;
&lt;p&gt;. . .and then go and activate the wallpaper on the desktop. The dynamic wallpaper is indicated by a (very) small clock in the bottom right of the thumbnail image.&lt;/p&gt;
&lt;p&gt;If you want access to the picture files then check out the &lt;a href=&quot;https://github.com/fedoradesign/backgrounds&quot;&gt;Fedora 29 wallpaper github repository&lt;/a&gt;, which contains them all.&lt;/p&gt;
&lt;p&gt;I believe this has featured before, but as far as I am aware the last time this happened was back in Fedora 26. Anyway, enjoy!&lt;/p&gt;
&lt;h2 id=&quot;grub-behaviour-update&quot; tabindex=&quot;-1&quot;&gt;Grub Behaviour Update &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#grub-behaviour-update&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Grub is what you see on boot telling you the Fedora kernel version you are about to boot into.&lt;/p&gt;
&lt;p&gt;From Fedora 29 this will no longer show if the only thing you have installed on your system is a single Fedora install. This will speed up the boot process.&lt;/p&gt;
&lt;h2 id=&quot;general-updates&quot; tabindex=&quot;-1&quot;&gt;General Updates &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#general-updates&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There have also been the usual upgrades to various software packages to keep you right up to date. Including the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TLS 1.3 is now supported&lt;/li&gt;
&lt;li&gt;Python 3.7&lt;/li&gt;
&lt;li&gt;Golang 1.11&lt;/li&gt;
&lt;li&gt;Perl 5.28&lt;/li&gt;
&lt;li&gt;Ruby on Rails 5.2&lt;/li&gt;
&lt;li&gt;Node.js 10.x&lt;/li&gt;
&lt;li&gt;MySQL 8&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot; tabindex=&quot;-1&quot;&gt;Conclusions &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-29-release/#conclusions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all I think Fedora 29 has been an impressive release, and it sets an excellent tone for the future.&lt;/p&gt;
&lt;p&gt;You should also bear in mind that the items covered in this article are primarily concentrated on the Workstation edition.&lt;/p&gt;
&lt;p&gt;However, the Fedora development team have been making great progress with what could be the next generation of desktop in the form of project &lt;a href=&quot;https://silverblue.fedoraproject.org/&quot;&gt;SilverBlue&lt;/a&gt;. In addition, IOT support has been enhanced by enabling support for ZRAM support for swap on ARMv7 and aarch64. This opens the door for devices such as the Raspberry Pi for example.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/fedora-29/silverblue-logo.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/fedora-29/silverblue-logo.png&quot; alt=&quot;silverblue logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A lot to look forward to in Fedora 30 and beyond!&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Android App Directory - Useful and Interesting Android Apps</title>
		<link href="https://www.thetestspecimen.com/posts/android-app-directory/"/>
		<updated>Thu, 15 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/android-app-directory/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;This is a list of Android apps that I think are the best in class or at least interesting. (I don&#39;t own an iPhone, so I can&#39;t comment on that. . .)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As I discover new apps I will gradually add to the list below, so be sure to check back regularly.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Last updated: 15th November 2018&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;my-apps&quot; tabindex=&quot;-1&quot;&gt;My Apps &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#my-apps&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;wanderfile&quot; tabindex=&quot;-1&quot;&gt;Wanderfile &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#wanderfile&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Allows you to log where you have been in the world using maps and lists. You can log countries, districts of countries and major cities. You can share a multitude of maps in picture form with your friends / family as well, which are produced on demand. It also provides cost and useful travel information for all countries (Disclaimer: I made this app)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://play.google.com/store/apps/details?id=com.thetestspecimen.wanderfile&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wanderfile.app/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;email&quot; tabindex=&quot;-1&quot;&gt;Email &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#email&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;typeapp-or-bluemail&quot; tabindex=&quot;-1&quot;&gt;TypeApp or BlueMail &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#typeapp-or-bluemail&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;These two represent the best free email apps on the playstore. I have found nothing better (unless you need specific security measures like PGP or S/MIME).&lt;/p&gt;
&lt;p&gt;Now just to clear something up...TypeApp and BlueMail are made by the same people, and operate in the same way. The only difference is the way they look (flat vs material design) and the default settings for some settings.&lt;/p&gt;
&lt;p&gt;...so essentially download both and then check which interface layout you prefer. I personally use TypeApp..&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.trtf.blue&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.typeapp.com/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;maildroid&quot; tabindex=&quot;-1&quot;&gt;MailDroid &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#maildroid&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is my main email app, as it has features that I haven&#39;t found in any other app. I would say that most likely if you want a general day to day email app you are better off with TypeApp or Bluemail. However, if you want to take advantage of the extra features (signing and encryption) that become available when you use PGP or S/MIME, then MailDroid is the app for you.&lt;/p&gt;
&lt;p&gt;I can understand that encrypting emails may be a bit much for most people as it is just a hassle, but signing emails is actually a great way of confirming to the recipient that the email came from you (and only you!).&lt;/p&gt;
&lt;p&gt;You may be surprised to hear that the recipients typically don&#39;t have to do anything to confirm signed emails with S/MIME, as it is quite well adopted. Gmail for example will confirm signed S/MIME emails natively without any special settings.&lt;/p&gt;
&lt;p&gt;I personally sign emails using S/MIME, as the process is a tad easier and more accessible than PGP, but you could use either with this app. Unfortunately, there is no Yubikey integration yet, but if it appears I may switch to PGP...we will see.&lt;/p&gt;
&lt;p&gt;One thing to note is that there are some separate apps (from the same developer) that you may need to download to use features like signing/encryption and app themes. They are both free on the playstore and I will list them below as well.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.maildroid&amp;amp;hl=en&quot;&gt;MailDroid&lt;/a&gt; - Free&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.maildroid.pro&amp;amp;hl=en&quot;&gt;MailDroid Pro&lt;/a&gt; - Paid&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.flipdog.crypto.plugin&amp;amp;hl=en&quot;&gt;Crypto Plugin&lt;/a&gt; - Free (for PGP and S/MIME)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.flipdog.maildroid.themes&amp;amp;hl=en&quot;&gt;Themes Plugin&lt;/a&gt; - Free&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://flipdogsolutions.com/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;terminal-access-(ssh%2Fftp)&quot; tabindex=&quot;-1&quot;&gt;Terminal Access (SSH/FTP) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#terminal-access-(ssh%2Fftp)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;termius&quot; tabindex=&quot;-1&quot;&gt;Termius &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#termius&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The best SSH/FTP client I have found on android. I can literally manage my server as though I was sat at a computer. The interface is also a breeze to use and navigate.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.server.auditor.ssh.client&amp;amp;hl=en&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.termius.com/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;termbot&quot; tabindex=&quot;-1&quot;&gt;TermBot &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#termbot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is another SSH app like Termius. This app is not as polished as Termius, but it does have one killer feature: you can use an NFC Yubikey (NEO or 5 Series) when paired with the OpenKeyChain app. This means you no longer need your ssh/pgp key on your phone, which greatly increases security.&lt;/p&gt;
&lt;p&gt;This is now my go to app for terminal access to my server. It is also completely open source, so you can contribute to it becoming a really excellent app!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.sufficientlysecure.termbot&amp;amp;hl=en&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/open-keychain/termbot&quot;&gt;Website/GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;Security &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#security&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;safeincloud&quot; tabindex=&quot;-1&quot;&gt;SafeInCloud &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#safeincloud&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There are a multitude of password managers on the android playstore, and I have tried a lot. SafeInCloud however is the best I have found.&lt;/p&gt;
&lt;p&gt;The interface is clean and simple, and it backs up your passwords (encrypted) to &lt;strong&gt;YOUR&lt;/strong&gt; cloud storage (dropbox, google drive etc.), but only if &lt;strong&gt;YOU&lt;/strong&gt; want it to. Plenty of customisation options and it can be used on Android, iOS, Windows and Mac.&lt;/p&gt;
&lt;p&gt;This is also one of those apps that you should really buy the pro version of, well worth it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.safeincloud.free&quot;&gt;SafeInCloud&lt;/a&gt; - Free&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.safeincloud&quot;&gt;SafeInCloud Pro&lt;/a&gt; - Paid&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://safe-in-cloud.com/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;authy&quot; tabindex=&quot;-1&quot;&gt;Authy &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#authy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A great way to securely store your second factor authentication keys across different platforms. Much better than Google Authenticator.&lt;/p&gt;
&lt;p&gt;Although this app is great you should consider hardware security keys, as they are the future. Check out my articles &lt;a href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/&quot;&gt;here&lt;/a&gt; to find out more.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.authy.authy&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://authy.com/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;openkeychain&quot; tabindex=&quot;-1&quot;&gt;OpenKeyChain &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#openkeychain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This app allows the use and storage of PGP keys. This allows you to sign and encrypt/decrypt files and messages. It also integrates fantastically with other apps to allow PGP keys to be used in all manner of ways with android (email, password manager etc.). BUT the best feature of this app is that it allows you to use a Yubikey (with NFC, so currently the NEO or the new Yubikey 5) which greatly increases security as you don&#39;t need to store your private keys on the phone!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.sufficientlysecure.keychain&amp;amp;hl=en&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.openkeychain.org/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;file-management&quot; tabindex=&quot;-1&quot;&gt;File Management &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#file-management&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;solid-explorer&quot; tabindex=&quot;-1&quot;&gt;Solid Explorer &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/android-app-directory/#solid-explorer&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Simply the best file manager available for android. Does what it&#39;s supposed to and can deal with root. It is not free, but it is worth it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=pl.solidexplorer2&amp;amp;hl=en&quot;&gt;App Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://neatbytes.com/solidexplorer/&quot;&gt;Website&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Website Directory – Useful and Interesting Websites</title>
		<link href="https://www.thetestspecimen.com/posts/website-directory/"/>
		<updated>Thu, 15 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/website-directory/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;These are some of the websites that have impressed me with their content and / or usefulness. This list does not include well know sites such as Reddit, Facebook, Google, Twitter, Instagram etc. because you probably know all those already. Hopefully some of them will be useful to you too.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As I discover new websites I will gradually add to the list below, so be sure to check back regularly.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Last updated: 15th November 2018&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.shareicon.net/&quot;&gt;ShareIcons&lt;/a&gt;: A great resource for finding icons and imagery. You can filter by colours, styles etc. making the searching process less tedious.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.taniarascia.com/&quot;&gt;Tania Rascia&lt;/a&gt;: This is essentially a personal blog by a web developer. It is well written, and very useful on many levels. Tania also has the perspective of changing careers, as she was originally a chef(?!), which means she has a unique perspective. One of the best blogs I have come across.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pixabay.com/&quot;&gt;Pixabay&lt;/a&gt;: this website is a directory of free to use images and graphics. All items are released under CC0 Creative Commons, which means they are free for commercial use and require no attribution.&lt;/p&gt;
&lt;p&gt;This makes finding images for your website or videos (or anything really) a worry free process. There are other sites that offer free pictures, but a lot of them require attribution, or have other requirements. I have no problem with attribution, but a lot of the time it is a hassle to check the requirements. This makes Pixabay a go to website.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ifttt.com/&quot;&gt;IFTTT&lt;/a&gt;: this is kind of an amazing website / app. It allows you to setup links between different accounts. For example, if you post a picture to instagram you can set it to automatically post to twitter, or vica-versa. If you receive an email, you can get your office lights to flash. The combinations are endless!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.guerrillamail.com/&quot;&gt;Guerrilla Mail&lt;/a&gt;: this is a website that allows you to use a temporary email address so that you can sign up to websites that require login but you don&#39;t want to give real details to. There are of course other websites that do this, but Guerrilla Mail has a few unique features, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;scrambled email addresses&lt;/li&gt;
&lt;li&gt;choosing your own address and domain&lt;/li&gt;
&lt;li&gt;easy to manage password manager should you need one (won&#39;t go into details here but this point is interesting...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.virustotal.com/&quot;&gt;Virustotal&lt;/a&gt;: checks files or websites against a lot of different antivirus software. This allows you to judge by consensus whether the file or website is actually malicious, or you just got a false positive from your own antivirus software.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://haveibeenpwned.com/&quot;&gt;HaveIBeenPwned&lt;/a&gt;: checks whether your email address or username information has been leaked in one of the many website hacks that have happened over the years. You can also sign up to a mailing list that will tell you if your info is leaked in future hacks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://downforeveryoneorjustme.com/&quot;&gt;Down for everyone or just me&lt;/a&gt;: this does the simple job of checking whether a webpage is alive and kicking. This allows you to check if the problem of connectivity is at your end or theirs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gethuman.com/&quot;&gt;GetHuman&lt;/a&gt;: this is a great resource that helps you skip the automated phone services large companies tend to use, and get straight through to a human (hence the name of the website). Not only that but it gives information on current and average wait times, best time to call etc. A very useful site.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.whichbook.net/&quot;&gt;WhichBook&lt;/a&gt;: this website allows you to search for books based on your interests. You set sliders for things like gentle - violent, beautiful - disgusting, sex - no sex, short-long etc. and it will return the best match. A great way to find new reads.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.justwatch.com/&quot;&gt;JustWatch&lt;/a&gt;: this website helps you find where you can legally watch or buy a television series in your country. For example if you want to watch Family Guy, which streaming services (or online shop services) currently have it in their library, and how many seasons do they have available.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cookingforengineers.com/&quot;&gt;CookingForEngineers&lt;/a&gt;: A breath of fresh air from the usual fancy pants cooking websites. This website tells you what to do in simple English, with plenty of pictures. And when I say pictures, I mean pictures of how it will &lt;strong&gt;actually&lt;/strong&gt; look, not the result of food dressing and professional photographers. If you want to make some normal food, this is where you go.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cleantalk.org/blacklists/&quot;&gt;CleanTalk&lt;/a&gt;: This site allows you to check if an email address, ip or domain is considered to be used for spam or non-legitimate causes. This is particularly useful to check email subscriptions and membership signups for your website.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mediabiasfactcheck.com/&quot;&gt;MediaBiasFactCheck&lt;/a&gt;: with all the &amp;quot;Fake News!&amp;quot; floating around today it makes sense to understand where the media you regularly read or listen to sits on the spectrometer of bias! Plus it might give you an idea of where you sit, which could be an eye opener for some...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://brandcolors.net/&quot;&gt;BrandColors&lt;/a&gt;: Want to know the exact colour palettes different big companies use? This site has you covered.&lt;/p&gt;
&lt;h2 id=&quot;attributions&quot; tabindex=&quot;-1&quot;&gt;Attributions &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/website-directory/#attributions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Credit where credit is due: I spend some of my time trawling blogs and YouTube looking for inspiration. Sometimes I come across a great source of information that surprises me. Some of the websites on this list I discovered from lists other people have put together, and if that is the case I will link them here:&lt;/p&gt;
&lt;p&gt;ThioJoe produced a youtube video of 11 useful websites. Surprisingly it was a very good list: &lt;a href=&quot;https://www.youtube.com/watch?v=oTnE8-wXhlE&quot;&gt;ThioJoe&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Signal – The Only Messaging, Voice Call and Video Call App You Should Use</title>
		<link href="https://www.thetestspecimen.com/posts/signal-messaging-app/"/>
		<updated>Sun, 25 Nov 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/signal-messaging-app/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;There are many messaging, voice call and video call apps available that claim to use the latest end-to-end encryption to keep your messages and conversations safe. These apps include Facebook Messenger, WhatsApp, Viber and Telegram.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;However, as I will explain in this article not all encrypted messaging apps are made equal, and currently if you really value your privacy (which you should) then Signal is the app you should be using.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-do-i-even-need-to-encrypt-communications%3F&quot; tabindex=&quot;-1&quot;&gt;Why do I even need to encrypt communications? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#why-do-i-even-need-to-encrypt-communications%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a fair question.&lt;/p&gt;
&lt;h3 id=&quot;are-you-ok-with-someone-opening-your-letters%3F&quot; tabindex=&quot;-1&quot;&gt;Are you ok with someone opening your letters? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#are-you-ok-with-someone-opening-your-letters%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best analogy I can think of is that of your post. Would you be ok with someone opening your post in transit? I know I wouldn&#39;t want someone opening my letters without permission. In the UK it is actually illegal to open mail that is not addressed to you.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/signal/envelope.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/signal/envelope.png&quot; alt=&quot;front of an envelope&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Your online communications should be treated exactly the same. Unfortunately it is not so easy to police digital content sent through wires, as it is physical mail.&lt;/p&gt;
&lt;h3 id=&quot;bad-people-and-data-collection&quot; tabindex=&quot;-1&quot;&gt;Bad people and data collection &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#bad-people-and-data-collection&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the post analogy is a little weak for you then consider the fact that your data, however bland and unimportant to you, is worth a lot to big companies and criminals.&lt;/p&gt;
&lt;p&gt;It is not a secret that large revenues are made from harvesting and processing peoples personal data. Using encryption means they don&#39;t have access to your data, so it can&#39;t be used by them, or stored in their servers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;your data, however bland and unimportant to you, is worth a lot to big companies and criminals&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which brings us on to the bad people (criminals. . .even some governments). . .they could monitor your communications to gather information about you to clone your identity, or get enough info to access your bank accounts. With controlling governments it might mean persecution for political, religious or sexual preferences.&lt;/p&gt;
&lt;p&gt;However, do not assume that you are not affected because you don&#39;t do anything bad so you have nothing to hide! There is much more to it than that.&lt;/p&gt;
&lt;h3 id=&quot;the-solution...&quot; tabindex=&quot;-1&quot;&gt;The solution... &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#the-solution...&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the best solutions to this problem is end-to-end encryption.&lt;/p&gt;
&lt;p&gt;What this basically means is that you write a message, then once you hit the send button, it is encrypted. The &lt;strong&gt;only&lt;/strong&gt; person able to decrypt the message is the intended recipient.&lt;/p&gt;
&lt;p&gt;This stops the message being read in transit, by a hacker, your internet service provider, the phone company, the government, the police or anybody else for that matter.&lt;/p&gt;
&lt;p&gt;The above can also be applied to voice calls and video calls.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-signal-so-special%3F&quot; tabindex=&quot;-1&quot;&gt;What makes Signal so special? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#what-makes-signal-so-special%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;it-is-open-source&quot; tabindex=&quot;-1&quot;&gt;It is open source &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#it-is-open-source&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It cannot be understated how important it is that software that involves encryption and communications is opensource.&lt;/p&gt;
&lt;p&gt;What opensource basically means is that the computer code that has been written to make the app is available for &lt;strong&gt;anybody&lt;/strong&gt; to review. It is therefore close to impossible for any backdoors or other dodgy code to go unnoticed. Someone would spot it.&lt;/p&gt;
&lt;p&gt;It also has the added benefit of allowing experts from around the world to review and suggest improvements to the code, which can only make the overall product stronger.&lt;/p&gt;
&lt;p&gt;As they say, many hands make light work...&lt;/p&gt;
&lt;h3 id=&quot;it-does-not-store-metadata&quot; tabindex=&quot;-1&quot;&gt;It does not store metadata &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#it-does-not-store-metadata&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;what-is-metadata%3F&quot; tabindex=&quot;-1&quot;&gt;What is metadata? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#what-is-metadata%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Metadata: a word used, and heard, very often.&lt;/p&gt;
&lt;p&gt;However, I suspect that people don&#39;t really know what metadata is exactly, and it is really important to know if you value your privacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Edward Snowden leaked an NSA document which stated that metadata collection is one of the agency&#39;s &amp;quot;most useful tools&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The easiest way to think about metadata is that it is all the data not contained within the message, phone call or video call. For example it may include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What device is being used?&lt;/li&gt;
&lt;li&gt;Where is the device (i.e. a geographic location) that sent the message or start the call?&lt;/li&gt;
&lt;li&gt;How long did the call last for?&lt;/li&gt;
&lt;li&gt;What date and time did the message get sent or the call start?&lt;/li&gt;
&lt;li&gt;Who was the message / call to?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The data above may not seem more important than the content of the message, but it can build a very detailed picture of a user over time.&lt;/p&gt;
&lt;p&gt;Where you are, who you communicate with, who you talk to the most etc.&lt;/p&gt;
&lt;p&gt;This can have many implications. For example if the government is monitoring you to see who you are talking to due to your political affiliation, or the police to know your whereabouts at a particular time. . .&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/signal/woman-secret.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/signal/woman-secret.jpg&quot; alt=&quot;woman with fingers on her lips&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe the above are too abstract for someone in a western society who is law abiding? How about these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they know you were calling / texting a particular helpline, and for how long (alcoholics anonymous etc.)&lt;/li&gt;
&lt;li&gt;do you phone sex lines or use sex messaging services? They can monitor how long and how often.&lt;/li&gt;
&lt;li&gt;having an affair? calling your co-worker out of work hours regularly? ooops!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think you get the idea. . .it&#39;s not just the content that matters.&lt;/p&gt;
&lt;p&gt;Have a read of this &lt;a href=&quot;https://www.businessinsider.com/nsa-document-metadata-2016-12&quot;&gt;Business Insider article&lt;/a&gt; for more insight...&lt;/p&gt;
&lt;h4 id=&quot;does-signal-store-any-data%3F&quot; tabindex=&quot;-1&quot;&gt;Does Signal store any data? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#does-signal-store-any-data%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Best heard from the horses mouth, in reference to a request for information on a user by the Eastern District of Virginia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’ve designed the Signal service to minimize the data we retain about Signal users, so the only information we can produce in response to a request like this is the date and time a user registered with Signal and the last date of a user’s connectivity to the Signal service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Futhermore:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Notably, things we &lt;em&gt;don’t&lt;/em&gt; have stored include anything about a user’s contacts (such as the contacts themselves, a hash of the contacts, any other derivative contact information), anything about a user’s groups (such as how many groups a user is in, which groups a user is in, the membership lists of a user’s groups), or any records of who a user has been communicating with.&lt;/p&gt;
&lt;p&gt;All message contents are end-to-end encrypted, so we don’t have that information either.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The quotes above are taken from a &lt;a href=&quot;https://signal.org/bigbrother/&quot;&gt;page provided by Signal&lt;/a&gt; on their website (appropriately called &amp;quot;Big Brother&amp;quot;) that details the types of requests for data they receive and how they deal with them. Take a look if you want a better understanding of how your data *should* be handled.&lt;/p&gt;
&lt;h3 id=&quot;it-uses-a-tried-and-tested-encryption-standard&quot; tabindex=&quot;-1&quot;&gt;It uses a tried and tested encryption standard &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#it-uses-a-tried-and-tested-encryption-standard&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The encryption used in Signal is based on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Signal_Protocol&quot;&gt;Signal Protocol&lt;/a&gt; (formerly known as the TextSecure Protocol).&lt;/p&gt;
&lt;p&gt;Again it is opensource, and as such has been thoroughly tested.&lt;/p&gt;
&lt;p&gt;An official &lt;a href=&quot;https://eprint.iacr.org/2016/1013.pdf&quot;&gt;academic paper&lt;/a&gt; written in collaboration across three different universities (Oxford University - UK, Royal Holloway University of London, UK and McMaster University - Canada) published in 2017 stated that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;we have found no major flaws in its design, which is very encouraging&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I would say the above statement represents a typically cautious academic statement. Essentially this means that as far as they are capable of testing the encryption method, it doesn&#39;t have any flaws that would compromise its safe use.&lt;/p&gt;
&lt;p&gt;The Signal Protocol is also generally accepted as being trustworthy and secure within the cryptographic community.&lt;/p&gt;
&lt;h3 id=&quot;it-is-available-on-many-platforms&quot; tabindex=&quot;-1&quot;&gt;It is available on many platforms &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#it-is-available-on-many-platforms&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can use it on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Android&lt;/li&gt;
&lt;li&gt;iOS&lt;/li&gt;
&lt;li&gt;Windows&lt;/li&gt;
&lt;li&gt;Mac&lt;/li&gt;
&lt;li&gt;Linux (debian based), but I understand that with Flatpak it can also be used on rpm based Linux systems as well&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;it-can-also-be-your-sms-app&quot; tabindex=&quot;-1&quot;&gt;It can also be your SMS app &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#it-can-also-be-your-sms-app&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Signals can replace the standard SMS application on your phone.&lt;/p&gt;
&lt;p&gt;This is a great feature as it means you don&#39;t need a separate SMS app and all messages can be consolidated in one place.&lt;/p&gt;
&lt;p&gt;However, you also need to be a little bit careful. . .&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/signal/sms-phone.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/signal/sms-phone.png&quot; alt=&quot;messages and phone&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You need to remember that you can only send encrypted messages to other people that also use signal.&lt;/p&gt;
&lt;p&gt;If you send an SMS message to someone not using signal, then it &lt;strong&gt;won&#39;t be encrypted&lt;/strong&gt; and will just be a standard text message.&lt;/p&gt;
&lt;p&gt;. . .so it pays to encourage other people to use the app too. As it ensures the conversations you have will always be encrypted and secure. Not to forget free, as you won&#39;t pay for an SMS message!&lt;/p&gt;
&lt;h2 id=&quot;what-do-the-others-lack%3F&quot; tabindex=&quot;-1&quot;&gt;What do the others lack? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#what-do-the-others-lack%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I alluded to at the beginning of this article - Not all encrypted messaging apps are made equal.&lt;/p&gt;
&lt;p&gt;I thought it only fair to go through some of the big names and point out exactly what they lack. In this section I will mention Facebook Messenger, Whatsapp, Telegram and Viber, which I think just about cover the most used messaging and phone apps currently available.&lt;/p&gt;
&lt;h3 id=&quot;encryption-is-not-on-by-default&quot; tabindex=&quot;-1&quot;&gt;Encryption is not on by default &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#encryption-is-not-on-by-default&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although all the apps generally feature end-to-end encryption, it is not typically enabled by default, you have to opt-in.&lt;/p&gt;
&lt;p&gt;This may not seem like a big thing. I mean having a choice is good right?&lt;/p&gt;
&lt;p&gt;The thing is that there is no reason not to use encryption. The only feasible argument is speed of communication, as the encryption-decryption takes additional time. However, it is a weak argument, and you will likely not even notice a difference.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/signal/padlock-and-key.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/signal/padlock-and-key.png&quot; alt=&quot;A padlock and key&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The problem is that people who are not tech savvy won&#39;t even notice the option is there, and won&#39;t use it. Which is not fair on those users, as they could also benefit.&lt;/p&gt;
&lt;p&gt;Quite frankly a stance like this stinks. It doesn&#39;t instil trust in any way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facebook Messenger and Telegram both do not encrypt by default. You must either turn it on or use a specific feature of the app.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;metadata-and-stored-data&quot; tabindex=&quot;-1&quot;&gt;Metadata and Stored Data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#metadata-and-stored-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You will find that one of the biggest downfalls of a lot of &amp;quot;secure&amp;quot; messenger apps is the *other* data that they collect and / or store.&lt;/p&gt;
&lt;p&gt;One of the excellent outcomes of the GDPR regulation that was enacted in the EU is that privacy policies are relatively transparent, and detail exactly what data is being held. Therefore if you are checking out a new app the best place to start looking for what they have access to is the Privacy Policy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facebook Messenger, Telegram, Viber and Whatsapp (owned by Facebook), all collect some form of metadata that I would consider unnecessary. Remember to check out their privacy policies for specifics.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;unique-encryption-methods&quot; tabindex=&quot;-1&quot;&gt;Unique Encryption Methods &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#unique-encryption-methods&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Actually most of the apps use an industry standard end-to-end encryption standard such as Signal. However, there is one exception:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Telegram&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Telegram uses it&#39;s own encryption method: MTProto&lt;/p&gt;
&lt;p&gt;There is of course nothing wrong with Telegram having it&#39;s own encryption protocol, but it does not benefit from the wide user participation that an open source protocol would benefit from.&lt;/p&gt;
&lt;p&gt;It is also not time tested as many of the widely used encryption protocols are. I don&#39;t think anybody would argue with the fact that if a method is exposed to, and tested by, as many people as possible for the greatest length of time feasible, and without failure. Then that method is at the very least solid and secure for the present day.&lt;/p&gt;
&lt;p&gt;It has also been the subject of not so glowing &lt;a href=&quot;https://courses.csail.mit.edu/6.857/2017/project/19.pdf&quot;&gt;research papers&lt;/a&gt; from places like MIT, and general &lt;a href=&quot;https://news.ycombinator.com/item?id=6913456&quot;&gt;user scepticism&lt;/a&gt;. Telegram have done their best to refute any claims of weakness or failure in their implementation, but it is fair to say that some people are still sceptical. Including me.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The point of this article was to convince you that Signal represents your best bet when it comes to a free, accessible, secure and trustworthy messaging app when compared to the main competition that you have likely heard of before.&lt;/p&gt;
&lt;p&gt;I hope I have managed that, if not let me know why in the comments.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think it should be an industry standard, and right, that you can call, and message anybody without having to worry about being snooped on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The final thing I wanted to point out is that potentially there may be other apps out there that are better than Signal. I hope there will be plenty of competition in this field. The more the better, because I think it should be an industry standard, and right, that you can call, and message anybody without having to worry about being snooped on.&lt;/p&gt;
&lt;p&gt;If you wish to look at alternatives to Signal then I have listed some other apps that you could take a look at below. I have briefly highlighted any concerns or positives to give you a head start...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For now my recommendation stands: Signal represents (currently) the example of what a secure messaging and call app should be - give it a try...&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;potential-alternatives&quot; tabindex=&quot;-1&quot;&gt;Potential Alternatives &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/#potential-alternatives&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Threema&lt;/strong&gt; - Possibly the best alternative to Signal. It is a paid option, but we aren&#39;t talking big bucks. The only downside is that it isn&#39;t completely open source. However, it has been audited by at least two separate auditors, and passed with flying colours. If you take privacy seriously this is really worth a look.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wire&lt;/strong&gt; - some of it is opensource, not all. &lt;a href=&quot;https://news.ycombinator.com/item?id=14069674&quot;&gt;They keep metadata&lt;/a&gt;...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wickr&lt;/strong&gt; - as far as I can tell it &lt;a href=&quot;https://wickr.com/privacy/#transparency&quot;&gt;keeps metadata&lt;/a&gt; such as date of last use and device type...but take a look if you like&lt;/p&gt;
&lt;p&gt;There are probably more, be sure to ping me a message if you have any other interesting suggestions.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Top 10 Essential Android Security Apps (Not Antivirus)</title>
		<link href="https://www.thetestspecimen.com/posts/top-10-security-apps/"/>
		<updated>Wed, 05 Dec 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/top-10-security-apps/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;The internet is not a place where you should let your guard down in this day and age. Even big companies have succumbed to hacks, and had &lt;a href=&quot;http://www.informationisbeautiful.net/visualizations/worlds-biggest-data-breaches-hacks/&quot;&gt;huge data leaks&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So without the expertise of a big company, what can we do to protect our private information and activities from prying eyes?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Well fortunately there are a wide array of apps out there to help you do the best you can to keep your info safe. A lot of these apps will allow you to easily implement best practices in terms of mobile security without too much effort on your part.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;. . .so in no particular order:&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;10%3A-signal---messenger%2C-voice-and-video&quot; tabindex=&quot;-1&quot;&gt;10: Signal - Messenger, Voice and Video &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#10%3A-signal---messenger%2C-voice-and-video&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/signal.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/signal.jpg&quot; alt=&quot;Signal Messenger&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://signal.org/&quot;&gt;Signal Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms&amp;amp;referrer=utm_source%3DOWS%26utm_medium%3DWeb%26utm_campaign%3DNav&quot;&gt;Signal App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Signal has you covered for almost all messaging, phone and video communications.&lt;/p&gt;
&lt;p&gt;It can send messages (including pictures and videos) and handle phone calls (inducing video if you like). You can also do the standard things you would expect from a messaging app such as group messaging.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Encrypted messages, encrypted phone calls and encrypted video calls&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a multitude of messaging and phone apps that now have end-to-end encryption. However, all messaging apps are not created equal. You may be surprised to find that Facebook Messenger, Whatsapp, Viber, Telegram and plenty of others are not quite as safe and secure as you think.&lt;/p&gt;
&lt;p&gt;What sets Signal apart from all the other messaging apps is not so simple to explain, so I wrote a &lt;a href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/&quot;&gt;separate article&lt;/a&gt; to tackle this very subject.&lt;/p&gt;
&lt;p&gt;Be sure to check out &lt;a href=&quot;https://www.thetestspecimen.com/posts/signal-messaging-app/&quot;&gt;the article&lt;/a&gt;, as messaging and phone calls probably feature quite highly in your phone usage, so it is one of the apps that has the potential to have the most impact on your privacy.&lt;/p&gt;
&lt;h1 id=&quot;9%3A-proton-mail---email&quot; tabindex=&quot;-1&quot;&gt;9: Proton Mail - Email &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#9%3A-proton-mail---email&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/protonmail.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/protonmail.jpg&quot; alt=&quot;Protonmail&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://protonmail.com/&quot;&gt;ProtonMail Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=ch.protonmail.android&quot;&gt;ProtonMail App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can think of proton mail as a replacement to Gmail or any other web based email client.&lt;/p&gt;
&lt;p&gt;You can now step away from the ads and email harvesting that is known to go on with companies like &lt;a href=&quot;https://www.reuters.com/article/us-yahoo-nsa-exclusive-idUSKCN1241YT?utm_content=bufferf5c61&amp;amp;utm_medium=social&amp;amp;utm_source=twitter.com&amp;amp;utm_campaign=buffer&quot;&gt;Yahoo&lt;/a&gt; and &lt;a href=&quot;https://variety.com/2017/digital/news/google-gmail-ads-emails-1202477321/&quot;&gt;Gmail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ProtonMail features the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;end-to-end encryption&lt;/li&gt;
&lt;li&gt;opensource&lt;/li&gt;
&lt;li&gt;anonymous signup&lt;/li&gt;
&lt;li&gt;no IP logging&lt;/li&gt;
&lt;li&gt;no tracking&lt;/li&gt;
&lt;li&gt;based in Switzerland&lt;/li&gt;
&lt;li&gt;free or paid options available&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The encryption means that no one is harvesting your emails for information, as no-one can read them. Not even ProtonMail.&lt;/p&gt;
&lt;p&gt;Not only can they now read your emails, but they don&#39;t bother to log your ip or track you in anyway. Which is exactly how is should work.&lt;/p&gt;
&lt;h1 id=&quot;8%3A-maildroid---email&quot; tabindex=&quot;-1&quot;&gt;8: MailDroid - Email &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#8%3A-maildroid---email&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/maildroid.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/maildroid.jpg&quot; alt=&quot;maildroid&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.maildroid&quot;&gt;MailDroid App - Free&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.maildroid.pro&quot;&gt;MailDroid App - Paid&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe you don&#39;t want to trust yet another faceless provider, even if it is as compelling as ProtonMail.&lt;/p&gt;
&lt;p&gt;MailDroid is an email client that you control.&lt;/p&gt;
&lt;p&gt;You enter the servers and settings and the app fetches and sends your emails for you. What this means is that you could use a whole array of email accounts with this app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gmail, Yahoo and others&lt;/li&gt;
&lt;li&gt;Work accounts&lt;/li&gt;
&lt;li&gt;Your own email accounts associated with your own domain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now it should be noted that there are a lot of apps that are available on the PlayStore that can do this, so what makes MailDroid so special? Well, MailDroid has the option to use S/MIME and/or PGP signing and encryption.&lt;/p&gt;
&lt;p&gt;At this point I will say that if you don&#39;t know what either S/MIME or PGP are, or you don&#39;t have your own server and domain, then this app is probably irrelevant for you. You should take a serious look at ProtonMail instead as it represents a mail app that doesn&#39;t require any setup.&lt;/p&gt;
&lt;p&gt;However, I will point out that S/MIME setup is not very complicated (PGP is a whole other ball game!). You can get a free S/MIME certificate from &lt;a href=&quot;https://www.comodo.com/home/email-security/free-email-certificate.php&quot;&gt;Comodo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once setup this gives you the following advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assuming you have your own server with mail: You own your emails! No remote third party server to worry about.&lt;/li&gt;
&lt;li&gt;You can sign your emails with your S/MIME or PGP key. This means people will be sure the email they receive *really* came from you (even Gmail recognises S/MIME signed emails with a green tick, so even if the recipient doesn&#39;t use S/MIME themselves, they can still benefit from the extra confirmation.)&lt;/li&gt;
&lt;li&gt;You can encrypt emails&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would also add that the app itself is very customisable both in terms of looks and features.&lt;/p&gt;
&lt;h1 id=&quot;7%3A-safeincloud---password-manager&quot; tabindex=&quot;-1&quot;&gt;7: SafeInCloud - Password Manager &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#7%3A-safeincloud---password-manager&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/safeincloud.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/safeincloud.png&quot; alt=&quot;safeincloud&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.safe-in-cloud.com/en/&quot;&gt;SafeInCloud Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.safeincloud.free&quot;&gt;SafeInCloud App - Free&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.safeincloud&quot;&gt;SafeInCloud - Paid&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This app is essential to me.&lt;/p&gt;
&lt;p&gt;There is nothing more important than keeping your passwords random and long. This app helps me achieve that with ease.&lt;/p&gt;
&lt;p&gt;There are many password managers out there, but they all typically have some sort of cloud sync feature, which more often than not uses the app providers cloud service. I dislike this as I want complete control over my data. Lets face it, if a big company like Facebook can&#39;t secure data properly, then any company is vulnerable.&lt;/p&gt;
&lt;p&gt;SafeInCloud gives you the &lt;strong&gt;option&lt;/strong&gt; of cloud sync, and even when it is available it is to a location that &lt;strong&gt;you&lt;/strong&gt; own, not them.&lt;/p&gt;
&lt;p&gt;You could for example sync to your Google Drive or Dropbox account, or if you are more paranoid you could use your own cloud implementation such as ownCloud or WebDAV.&lt;/p&gt;
&lt;p&gt;. . .and finally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;backups are encrypted (AES 256-bit)&lt;/li&gt;
&lt;li&gt;password generator&lt;/li&gt;
&lt;li&gt;fingerprint login&lt;/li&gt;
&lt;li&gt;android wear&lt;/li&gt;
&lt;li&gt;password strength analysis&lt;/li&gt;
&lt;li&gt;browser integration&lt;/li&gt;
&lt;li&gt;free desktop apps (Windows and MAC)&lt;/li&gt;
&lt;li&gt;auto import from other password managers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are both free and paid versions available. At least from my point of view a password manager is an essential piece of kit, and as such I would recommend shelling out the few quid it costs to get the pro (paid) version.&lt;/p&gt;
&lt;h1 id=&quot;6%3A-authy---second-factor-authentication&quot; tabindex=&quot;-1&quot;&gt;6: Authy - Second Factor Authentication &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#6%3A-authy---second-factor-authentication&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/authy.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/authy.jpg&quot; alt=&quot;authy&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://authy.com/&quot;&gt;Authy Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.authy.authy&quot;&gt;Authy App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Second Factor Authentication is just a piece of information (or confirmation) that you provide to log into an account in addition to your password. This could be for example a code received in a text message, or a link that you need to click in an email. However, one of the most convenient, secure and widely used methods is Time Based One-Time Password (TOTP).&lt;/p&gt;
&lt;p&gt;TOTP is typically a six digit number that changes every 20 to 30 seconds continuously. This means that even if you enter a TOTP in a website and someone figures out what you entered, it doesn&#39;t matter, as next time the number will be different.&lt;/p&gt;
&lt;p&gt;Authy stores and shows you TOTP numbers, and changes them as needed every 20 to 30 seconds.&lt;/p&gt;
&lt;p&gt;Second factor authentication is something that I would encourage everybody to use if it is made available by the website or service in question. It is not complicated for the user, and it increases the security of your account an enormous amount when compared to just having a password.&lt;/p&gt;
&lt;p&gt;There are of course other TOTP apps available including Google Authenticator. However, Authy stands out due to the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it backs up your TOTP codes&lt;/li&gt;
&lt;li&gt;it can sync your TOTP codes across multiple devices&lt;/li&gt;
&lt;li&gt;it works across many platforms&lt;/li&gt;
&lt;li&gt;it is easy to use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to take second factor authentication one step further, and in the future get rid of your passwords too. Then &lt;a href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/&quot;&gt;take a look hardware security keys like Yubikey&lt;/a&gt;, as they are even more secure and convenient.&lt;/p&gt;
&lt;h1 id=&quot;5%3A-private-internet-access-(or-cyberghost)---vpn&quot; tabindex=&quot;-1&quot;&gt;5: Private Internet Access (or CyberGhost) - VPN &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#5%3A-private-internet-access-(or-cyberghost)---vpn&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/pia.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/pia.png&quot; alt=&quot;private internet access&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.privateinternetaccess.com/&quot;&gt;Private Internet Access Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.privateinternetaccess.android&quot;&gt;Private Internet Access App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cyberghostvpn.com/en_US/&quot;&gt;CyberGhost Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=de.mobileconcepts.cyberghost&quot;&gt;CyberGhost App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Private Internet Access (PIA) is a VPN, the reason I have mentioned Cyberghost is that PIA is not free, you pay a subscription. Cyberghost is free.&lt;/p&gt;
&lt;p&gt;In my opinion PIA is the best VPN currently available, and you should give it a go. It works on most platforms including Windows, MAC, Android, iOS and even Linux.&lt;/p&gt;
&lt;p&gt;A plethora of server locations are available across the world, and it is fast and secure. Furthermore, it is one of the few that keeps no records at all of your usage (very important).&lt;/p&gt;
&lt;p&gt;If you want to learn more about why you need a VPN and what to look out for (and avoid) in a VPN provider, then I give more information in &lt;a href=&quot;https://www.thetestspecimen.com/posts/do-i-need-a-vpn/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;4%3A-duckduckgo---browser&quot; tabindex=&quot;-1&quot;&gt;4: DuckDuckGo - Browser &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#4%3A-duckduckgo---browser&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/duckduckgo.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/duckduckgo.jpg&quot; alt=&quot;Duck Duck Go&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://duckduckgo.com/&quot;&gt;DuckDuckGo Website&lt;/a&gt; (this is also a search engine you can use, not just info)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.duckduckgo.mobile.android&quot;&gt;DuckDuckGo App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;DuckDuckGo is essentially a search engine just like google, but &lt;strong&gt;they don&#39;t track you at all&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In the same way that you can use Chrome, which features the google search engine, DuckDuckGo have their own android app too.&lt;/p&gt;
&lt;p&gt;Using the app gives you access to well thought out features such as forced https connections where possible, and safety ratings for the sites you visit, which are easily visible in the address bar.&lt;/p&gt;
&lt;p&gt;It can also blocks trackers, so even if the website in question wants to track you it can&#39;t!&lt;/p&gt;
&lt;h1 id=&quot;3%3A-sync---cloud-storage&quot; tabindex=&quot;-1&quot;&gt;3: Sync - Cloud Storage &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#3%3A-sync---cloud-storage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/sync.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/sync.jpg&quot; alt=&quot;Sync&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sync.com/&quot;&gt;Sync Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.sync.mobileapp&quot;&gt;Sync App&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In terms of privacy, cloud storage is a bit of an issue.&lt;/p&gt;
&lt;p&gt;There are lots of options, but storing your personal data on the servers of a company you have no control over is risky at best.&lt;/p&gt;
&lt;p&gt;This is another area where I believe encryption of data should be a default, but this isn&#39;t even nearly the case with the majority of cloud storage providers.&lt;/p&gt;
&lt;p&gt;You therefore have a couple of options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Provide your own cloud storage on your own server. This is unlikely to be feasible for most people.&lt;/li&gt;
&lt;li&gt;Find a provider that respects your privacy and encrypts your data&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is where sync comes in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sync’s unique, zero-knowledge storage platform guarantees your privacy by encrypting and decrypting your data client-side (on your computer or device).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sync is a zero-knowledge encrypted cloud platform. That basically means that all the data you store on sync is encrypted using a key that only you hold, so even if law enforcement request access to your data from Sync, they wouldn&#39;t have the means to supply it, as they don&#39;t have the key.&lt;/p&gt;
&lt;p&gt;Sync also features second factor authentication for extra security at login, is easy to use, and can be used on most platforms (although not Linux).&lt;/p&gt;
&lt;h1 id=&quot;2%3A-solid-explorer---file-explorer&quot; tabindex=&quot;-1&quot;&gt;2: Solid Explorer - File Explorer &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#2%3A-solid-explorer---file-explorer&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/solidexplorer.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/solidexplorer.jpg&quot; alt=&quot;Solid Explorer&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://neatbytes.com/solidexplorer/&quot;&gt;Solid Explorer Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=pl.solidexplorer2&quot;&gt;Solid Explorer App&lt;/a&gt; (14-day trial with in app purchase)&lt;/p&gt;
&lt;p&gt;Simply the best file explorer available for Android.&lt;/p&gt;
&lt;p&gt;Easy to use, good looking design, root access (if you need it) and encryption if you need it.&lt;/p&gt;
&lt;p&gt;Basically it allows you to easily and quickly encrypt files and folders on your phone. It is really simple to use and can also integrate fingerprint recognition if your device allows it.&lt;/p&gt;
&lt;p&gt;I should add that it is not free, but the cost is minimal and you won&#39;t find better than this.&lt;/p&gt;
&lt;h1 id=&quot;1%3A-cerberus---anti-theft&quot; tabindex=&quot;-1&quot;&gt;1: Cerberus - Anti Theft &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/top-10-security-apps/#1%3A-cerberus---anti-theft&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/security-apps/cerberus.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/security-apps/cerberus.png&quot; alt=&quot;Cerberus&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cerberusapp.com/&quot;&gt;Cerberus Website&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.lsdroid.cerberus&quot;&gt;Cerberus App&lt;/a&gt; (7-day trial, purchase in app or on the website)&lt;/p&gt;
&lt;p&gt;The final consideration for your device is if it gets stolen!&lt;/p&gt;
&lt;p&gt;Then you are in trouble if you have sensitive data on your device. I mean lets face it with access to someones mobile phone you have access to a lot of info. Valuable info. . .&lt;/p&gt;
&lt;p&gt;Not to mention the fact that &amp;quot;normal&amp;quot; phones (i.e. not covered in gold or jewels) can cost in excess of GBP 1000. So you might actually want the device back too.&lt;/p&gt;
&lt;p&gt;Cerberus is an app that sits on your phone minding it&#39;s own business, but if set up correctly and your phone is stolen it can work magic.&lt;/p&gt;
&lt;p&gt;You could for example (all remotely):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;take a picture of the thief&lt;/li&gt;
&lt;li&gt;completely wipe your device&lt;/li&gt;
&lt;li&gt;set off alarms&lt;/li&gt;
&lt;li&gt;backup your data&lt;/li&gt;
&lt;li&gt;locate the device on a map&lt;/li&gt;
&lt;li&gt;generally control the device&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Again it is not free, but a couple of quid to protect a valuable phone is not a lot in my opinion.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Fedora Directory – Interesting and Useful Software and Tweaks</title>
		<link href="https://www.thetestspecimen.com/posts/fedora-directory/"/>
		<updated>Mon, 24 Dec 2018 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/fedora-directory/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;I tend to use Fedora as my main operating system these days, although I do occasionally use Windows when needs must. If you have never tried a Linux distribution before, then I would recommend Fedora as good starting point. I tried Ubuntu too, but for desktop environments I much prefer Fedora. At some point I might write about why. . .stay tuned.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Below are some of the tools and programs that I tend to install on a new Fedora system. For my own benefit, and hopefully yours too.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As I discover new tweaks or programs I will gradually add to the list below, so be sure to check back regularly.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Last updated: 24th December 2018&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;gnome-tweak-tool&quot; tabindex=&quot;-1&quot;&gt;Gnome Tweak Tool &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#gnome-tweak-tool&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Allows you to change various settings in the operating system. For example you can add minimise and maximise buttons on windows (not there by default). You can edit system fonts, the clock, mouse settings and many more.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gnome-tweak-tool&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;animated-wallpaper&quot; tabindex=&quot;-1&quot;&gt;Animated Wallpaper &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#animated-wallpaper&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are many things I like about Fedora, but one of the standout features is always the wallpaper. They are elegant and interesting, without being distracting or tacky.&lt;/p&gt;
&lt;p&gt;For the most recent release of Fedora 29 they have again provided an impressive wallpaper. However, they have gone one step further, and made a dynamic version which gradually changes colour throughout the day. It&#39;s subtle but impressive.&lt;/p&gt;
&lt;p&gt;You will however have to activate this otherwise you will be stuck with the static version. Which isn&#39;t that bad really, but why not if you can. . .&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; f29-backgrounds-animated&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I am aware they have done this before, but they don&#39;t seem to do it for every release of Fedora. The last I am aware of was Fedora 26.&lt;/p&gt;
&lt;h3 id=&quot;rpm-fusion-repository&quot; tabindex=&quot;-1&quot;&gt;RPM Fusion Repository &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#rpm-fusion-repository&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default fedora comes only with freely available open source software. If you need to get hold of proprietary software then you need to use the Fusion repository.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; %fedora&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; %fedora&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.noarch.rpm&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;removal-of-packagekit&quot; tabindex=&quot;-1&quot;&gt;Removal of PackageKit &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#removal-of-packagekit&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is not really a recommended program, but something I tend to do.&lt;/p&gt;
&lt;p&gt;Fedora comes with two package managers: rpm and PackageKit.&lt;/p&gt;
&lt;p&gt;rpm is the main Fedora package manager, and my preferred option. PackageKit is a part of GNOME and will automatically update Fedora for you. I have, however, had problems with PackageKit in the past, and I generally prefer the control rpm gives you over package installs.&lt;/p&gt;
&lt;p&gt;Technically PackageKit is preferable as it performs installs offline (i.e. when you restart), but the lack of transparency and automated nature of PackageKit does not sit well with me.&lt;/p&gt;
&lt;p&gt;I therefore always remove PackageKit to reduce the chance of conflicts and problems.&lt;/p&gt;
&lt;h4 id=&quot;disable-packagekit-only&quot; tabindex=&quot;-1&quot;&gt;Disable PackageKit Only &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#disable-packagekit-only&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Check PackageKit is running and functional.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl status packagekit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stop and disable PackageKit.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl stop packagekit
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl mask packagekit&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;completely-remove-packagekit&quot; tabindex=&quot;-1&quot;&gt;Completely Remove PackageKit &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#completely-remove-packagekit&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf remove PackageKit&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;unzip-and-archive-tools&quot; tabindex=&quot;-1&quot;&gt;Unzip and Archive Tools &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#unzip-and-archive-tools&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;unzip&lt;/span&gt; p7zip&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;video-codecs&quot; tabindex=&quot;-1&quot;&gt;Video Codecs &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#video-codecs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gstreamer1-plugins-bad-free gstreamer1-plugins-bad-freeworld gstreamer1-plugins-bad-nonfree gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugins-good-gtk gstreamer1-plugins-ugly gstreamer1-plugins-ugly-free&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;video-editing-and-streaming&quot; tabindex=&quot;-1&quot;&gt;Video Editing and Streaming &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#video-editing-and-streaming&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Handbrake is great for converting video formats, kdenlive is a great alternative to Adobe Premiere, and OBS Studio is great for streaming and video recording.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; kdenlive handbrake obs-studio&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;virtualbox&quot; tabindex=&quot;-1&quot;&gt;VirtualBox &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#virtualbox&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For creating virtual environments (note the capitalisation of &amp;quot;V&amp;quot; and &amp;quot;B&amp;quot; in VirtualBox as it matters). Which means I don&#39;t need to dual boot windows anymore!&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; VirtualBox&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;android-studio&quot; tabindex=&quot;-1&quot;&gt;Android Studio &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#android-studio&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.android.com/studio/install&quot;&gt;Install instructions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You need to increase your inotify watch limit as recommended by google.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;EOF&lt;span class=&quot;token bash punctuation&quot;&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; /etc/sysctl.d/android-studio.conf&lt;/span&gt;
# Increase inotify limit, required by Android Studio : https://confluence.jetbrains.com/display/IDEADEV/Inotify+Watches+Limit
fs.inotify.max&#92;_user&#92;_watches = 524288
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then...&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sysctl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--system&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;google-chrome%3A&quot; tabindex=&quot;-1&quot;&gt;Google Chrome: &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#google-chrome%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download the RPM package from the chrome website. Then run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ~/Downloads/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;.rpm&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;inkscape%2C-gimp-and-scribus&quot; tabindex=&quot;-1&quot;&gt;Inkscape, GIMP and Scribus &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#inkscape%2C-gimp-and-scribus&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have grouped these together as they are similar programs used for image manipulation and document creation. The best way to describe them is in terms of the Adobe software equivalents as follows: GIMP (Photoshop), Inkscape (Illustrator) and Scribus (InDesign).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gimp inkscape scribus&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;sublime-text&quot; tabindex=&quot;-1&quot;&gt;Sublime Text &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#sublime-text&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best text editor for programming and coding there is.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--import&lt;/span&gt; https://download.sublimetext.com/sublimehq-rpm-pub.gpg
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_64/sublime-text.repo
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; sublime-text&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;bittorrent-client&quot; tabindex=&quot;-1&quot;&gt;Bittorrent Client &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#bittorrent-client&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best so far is qbittorent client.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; qbittorrent&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;vlc&quot; tabindex=&quot;-1&quot;&gt;VLC &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#vlc&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best video player around.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; vlc&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;insomnia&quot; tabindex=&quot;-1&quot;&gt;Insomnia &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#insomnia&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In my opinion the best REST framework tester there is.&lt;/p&gt;
&lt;p&gt;First download the &lt;a href=&quot;https://builds.insomnia.rest/downloads/linux/latest&quot;&gt;appimage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As the file that you download is an app image, you can run it without installing it to the system by doubleclicking on the downloaded file. However, first you need to allow the execute permission for the file, so run this in the terminal:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x ~/Downloads/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;AppImage&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you double click on the file you will be asked if you want to just run the file, or if you want to also integrate it into the system. It is up to you, either will work fine, it depends what you prefer.&lt;/p&gt;
&lt;h3 id=&quot;filezilla&quot; tabindex=&quot;-1&quot;&gt;Filezilla &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#filezilla&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best FTP program.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; filezilla&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;yubikey-ssh-remote-access&quot; tabindex=&quot;-1&quot;&gt;Yubikey SSH Remote Access &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#yubikey-ssh-remote-access&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the ways to enhance security access to a remote server is to use a Yubikey security key for login and authentication.&lt;/p&gt;
&lt;p&gt;(If you are not sure what a Yubikey be sure to check out &lt;a href=&quot;https://www.thetestspecimen.com/posts/security-keys-yubikey/&quot;&gt;my article&lt;/a&gt; which explains why you should use one, and what they are).&lt;/p&gt;
&lt;p&gt;This is achieved with the use of a PGP key that can be setup and stored on the device.&lt;/p&gt;
&lt;p&gt;Within Fedora it can occur that ssh-agent and gpg-agent conflict meaning that the Yubikey is not recognised immediately. Running the following should allow the Yubikey to be recognised within the terminal.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;killall&lt;/span&gt; gpg-agent
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;killall&lt;/span&gt; ssh-agent
&lt;span class=&quot;token builtin class-name&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt; gpg-agent &lt;span class=&quot;token parameter variable&quot;&gt;--daemon&lt;/span&gt; --enable-ssh-support &lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;kernel-update-errors&quot; tabindex=&quot;-1&quot;&gt;Kernel Update Errors &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#kernel-update-errors&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometime after a Kernel update it can cause errors to occur on boot. Usually you will see some text in red displayed during the boot process.&lt;/p&gt;
&lt;p&gt;Although usually this does not appear to affect your ability to use Fedora, the following should get rid of the errors.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf reinstall dracut
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf reinstall kernel-core kernel-modules
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dracut &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;attributions&quot; tabindex=&quot;-1&quot;&gt;Attributions &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/fedora-directory/#attributions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Credit where credit is due: I spend some of my time trawling blogs and YouTube looking for inspiration. Sometimes I come across a great source of information that surprises me. Some of the programs / code on this list I discovered from info other people have put together, and if that is the case I will link them here:&lt;/p&gt;
&lt;p&gt;Personal Fedora setup of Robbi Nespu: &lt;a href=&quot;https://robbinespu.github.io/eng/2018/05/17/My_Personal_Fedora28_setup.html&quot;&gt;Robbi Nespu&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Django REST Framework (DRF) – Initial Setup and Configuration for Ubuntu</title>
		<link href="https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/"/>
		<updated>Fri, 18 Jan 2019 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Django Rest Framework (DRF) allows the easy creation of a reliable, flexible and secure RESTful APIs.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The idea of this guide is to take you through the setup of DRF on a live Ubuntu 18.04 LTS server running Apache2.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are of course some guides detailing setup in a local development environment, but not many that cover what is required on a live server.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Furthermore, a lot of the guides assume knowledge of Python, and how to deal with virtual environments. Python Virtual Environments can be confusing if you have never had to deal with them before, so when I say the beginning I really mean the beginning. . .&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this tutorial you should be able to see the successful install page at your domain, and log into the backend through a browser.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Although this guide doesn&#39;t detail the setup of views, models, serializers etc. I will likely include that in a part 2 at some point...&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-we-will-cover&quot; tabindex=&quot;-1&quot;&gt;What we will cover &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#what-we-will-cover&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I just wanted to briefly go over what we will go through in this tutorial, so you have an overall picture.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creation of a virtual environment which is required to install our DRF project in&lt;/li&gt;
&lt;li&gt;Installation of all required components and dependencies within the virtual environment&lt;/li&gt;
&lt;li&gt;Creation of the required folder structure for the project&lt;/li&gt;
&lt;li&gt;Setup of the settings file needed to get the project up and running&lt;/li&gt;
&lt;li&gt;Creation of a Postgresql database, and setup of the database to allow the app to function&lt;/li&gt;
&lt;li&gt;Creation of a superuser for use in the admin area of DRF&lt;/li&gt;
&lt;li&gt;Installation of the static files which allow a &amp;quot;browsable API&amp;quot;&lt;/li&gt;
&lt;li&gt;Setup of the API site Apache2 config file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now obviously the above is specific to Ubuntu 18.04 on an Apache2 server.&lt;/p&gt;
&lt;p&gt;However, most of the content will be applicable to other server OS and/or web servers with the appropriate changes to server config files and/or package management commands.&lt;/p&gt;
&lt;h2 id=&quot;creation-of-a-python-virtual-environment&quot; tabindex=&quot;-1&quot;&gt;Creation of a Python Virtual Environment &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#creation-of-a-python-virtual-environment&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;why-do-we-need-a-virtual-environment-anyway%3F&quot; tabindex=&quot;-1&quot;&gt;Why do we need a Virtual Environment anyway? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#why-do-we-need-a-virtual-environment-anyway%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When programming with Python it is considered good practise to always have you projects in a virtual environment.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/django-initial/python-logo.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/django-initial/python-logo.png&quot; alt=&quot;python logo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of the main reasons for this is that it allows you to keep project dependencies stable for each separate project.&lt;/p&gt;
&lt;h4 id=&quot;consider-this...&quot; tabindex=&quot;-1&quot;&gt;Consider this... &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#consider-this...&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;. . .so for example, your server last year may have been running Python 3.5. You started a project back then, and wrote the code using Python 3.5, but not within a virtual environment. Just directly on the server.&lt;/p&gt;
&lt;p&gt;When the release of Python 3.6 comes around, you would want to keep your server up to date, so that all the other programs that rely on Python can take advantage of the improvements. Also so any new projects you write are using the latest version.&lt;/p&gt;
&lt;p&gt;However, if you update your server, you will likely break your project that was written using Python 3.5!&lt;/p&gt;
&lt;p&gt;This means your options are to either update the project, or don&#39;t upgrade Python. Neither is ideal. . .&lt;/p&gt;
&lt;h4 id=&quot;...so-virtual-environments-are-your-friend&quot; tabindex=&quot;-1&quot;&gt;...so Virtual Environments are your friend &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#...so-virtual-environments-are-your-friend&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Virtual Environments help you avoid this situation.&lt;/p&gt;
&lt;p&gt;They are essentially a separate box that you install all the dependencies for your project in, and they stay fixed unless you specifically upgrade them from within the virtual environment.&lt;/p&gt;
&lt;p&gt;This means you can keep your server up to date without affecting your project!&lt;/p&gt;
&lt;h3 id=&quot;creating-our-project-and-virtual-environment&quot; tabindex=&quot;-1&quot;&gt;Creating our project and Virtual Environment &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#creating-our-project-and-virtual-environment&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you haven&#39;t already make sure your server us up to date.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then check the version of Python 3 you have installed&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:~$ python3 &lt;span class=&quot;token parameter variable&quot;&gt;-V&lt;/span&gt;
Python &lt;span class=&quot;token number&quot;&gt;3.6&lt;/span&gt;.7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a folder which will hold our project. I am going to work within:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/var/www/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but you can store your project wherever you see fit.&lt;/p&gt;
&lt;p&gt;I have called my project &amp;quot;myapi&amp;quot; but you can use whatever name you like. Just replace &amp;quot;myapi&amp;quot; as appropriate:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:~$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /var/www
user@server:/var/www$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; myapi 
user@server:/var/www$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; myapi
user@server:/var/www/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the Virtual Environment&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi$ virtualenv &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; python3 &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we now look at the contents of the &amp;quot;myapi&amp;quot; folder you will see that a folder called &amp;quot;env&amp;quot; has been created&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now activate and move into the virtual environment&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi$ &lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; env/bin/activate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that you are now in the virtual environment due to the bracketed &amp;quot;env&amp;quot; in the terminal at the beginning of the line&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whilst within the virtual environment you can use &amp;quot;python&amp;quot; rather than &amp;quot;python3&amp;quot; as a command.&lt;/p&gt;
&lt;p&gt;Any dependencies you install will be specific to the virtual environment not the server overall.&lt;/p&gt;
&lt;h2 id=&quot;installation-of-dependencies&quot; tabindex=&quot;-1&quot;&gt;Installation of dependencies &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#installation-of-dependencies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst in the virtual environment we will be using Python PIP, which is the Python package manager (just like apt for Ubuntu and dnf for Fedora). This is included by default with Python versions 3.4 and above, so you shouldn&#39;t need to install it.&lt;/p&gt;
&lt;p&gt;The main two packages we need are &amp;quot;django&amp;quot; and &amp;quot;djangorestframework&amp;quot;.&lt;/p&gt;
&lt;p&gt;I would also recommend installing the &amp;quot;markdown&amp;quot; package, which enables markdown in the browsable API (more on that later). Plus the &amp;quot;django-filter&amp;quot; package, which is a very useful addition when writing the api, as it allows filtering support.&lt;/p&gt;
&lt;p&gt;So run the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; django
pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; djangorestframework
pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; markdown
pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; django-filter&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;setup-the-project-and-folder-structure&quot; tabindex=&quot;-1&quot;&gt;Setup the project and folder structure &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#setup-the-project-and-folder-structure&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are now going to setup the project within the virtual environment. This will involve starting a &amp;quot;project&amp;quot; and an &amp;quot;app&amp;quot; within the virtual environment.&lt;/p&gt;
&lt;p&gt;This process creates a folder structure, and also produces various Python files that will define your project and app.&lt;/p&gt;
&lt;h3 id=&quot;why-do-we-need-a-project-and-app%3F&quot; tabindex=&quot;-1&quot;&gt;Why do we need a project and app? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#why-do-we-need-a-project-and-app%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To give you an idea of the concept of &amp;quot;projects&amp;quot; and &amp;quot;apps&amp;quot; in Django (which Djangorestframework is based on) I&#39;ll use a website as an example.&lt;/p&gt;
&lt;p&gt;The &amp;quot;project&amp;quot; would be the website as a whole. The &amp;quot;apps&amp;quot; would be sections of the website, for example, blog &amp;quot;app&amp;quot; or news &amp;quot;app&amp;quot; etc.&lt;/p&gt;
&lt;p&gt;The apps are separate components that are brought together in a &amp;quot;project&amp;quot;, but are effectively self contained and reusable.&lt;/p&gt;
&lt;p&gt;In this case there is little point making the distinction as we will only have one app, but it is always good to know why the structure exists.&lt;/p&gt;
&lt;p&gt;For more in depth info have a look as the &lt;a href=&quot;https://django-project-skeleton.readthedocs.io/en/latest/structure.html&quot;&gt;Django Project Structure.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;making-the-project-and-app&quot; tabindex=&quot;-1&quot;&gt;Making the project and app &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#making-the-project-and-app&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At this point you should be within the virtual environment at the root of the project folder you created. Like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we will create the &amp;quot;project&amp;quot;. &lt;strong&gt;Please note that there is a &amp;quot;.&amp;quot; at the end of the next command. This is not a mistake.&lt;/strong&gt; If you omit the &amp;quot;.&amp;quot; it will create an additional level of folders that you don&#39;t need:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;django-admin startproject myapi &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command will create a file called &amp;quot;&lt;a href=&quot;http://manage.py/&quot;&gt;manage.py&lt;/a&gt;&amp;quot; and a folder called &amp;quot;myapi&amp;quot;. You will therefore have the following folder structure:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;
manage.py &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; myapi&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then move into the new project folder and start a new app. In this case I will call the app &amp;quot;api&amp;quot;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; myapi
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi/myapi$ django-admin startapp api&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now exit the virtual environment. You will notice the (env) disappears.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi/myapi$ deactivate
user@server:/var/www/myapi/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point you should have a folder structure that looks something like this (Please note I have not given detail of the &amp;quot;env&amp;quot; folder contents as it is not necessary to know, but it will contain a lot of folders and files):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/var/www/myapi/manage.py
/var/www/myapi/env
/var/www/myapi/myapi/__init__.py
/var/www/myapi/myapi/settings.py
/var/www/myapi/myapi/urls.py
/var/www/myapi/myapi/wsgi.py
/var/www/myapi/myapi/__pycache__
/var/www/myapi/myapi/api/admin.py
/var/www/myapi/myapi/api/apps.py
/var/www/myapi/myapi/api/__init__.py
/var/www/myapi/myapi/api/models.py
/var/www/myapi/myapi/api/tests.py
/var/www/myapi/myapi/api/views.py
/var/www/myapi/myapi/api/migrations/__init__.py&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;adjusting-the-settings.py-file&quot; tabindex=&quot;-1&quot;&gt;Adjusting the &lt;a href=&quot;http://settings.py/&quot;&gt;settings.py&lt;/a&gt; file &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#adjusting-the-settings.py-file&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As you can see in the structure above there is a &lt;a href=&quot;http://settings.py/&quot;&gt;settings.py&lt;/a&gt; file located in the project folder. &lt;a href=&quot;http://settings.py/&quot;&gt;settings.py&lt;/a&gt; will have standard settings in it, but I have provided below an updated version to allow us to proceed. Take a little time to compare the two and make sure your file reflects the one below.&lt;/p&gt;
&lt;p&gt;Note: it is only necessary to be in the virtual environment when making dependency upgrades or working with Django or Python directly. If you just want to edit the &amp;quot;.py&amp;quot; files this can be done without being in the virtual environment.&lt;/p&gt;
&lt;p&gt;You can open the file and edit it with nano text editor (or any text editor you prefer). If you don&#39;t have nano installed you can do the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi/myapi$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;. . .and then open the file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi/myapi$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; settings.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Do not just copy and paste the file below over your file! Your file will have a &amp;quot;secret key&amp;quot; in it already. You need this, so don&#39;t overwrite it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remember to make sure you use your own folder paths if they differ from the ones used in this article.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&quot;
Django settings &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; myapi project.

Generated by &lt;span class=&quot;token string&quot;&gt;&#39;django-admin startproject&#39;&lt;/span&gt; using Django &lt;span class=&quot;token number&quot;&gt;2.1&lt;/span&gt;.5.

For &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&quot;

&lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; os

&lt;span class=&quot;token comment&quot;&gt;# Build paths inside the project like this: os.path.join(BASE_DIR, ...)&lt;/span&gt;
BASE_DIR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; os.path.dirname&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os.path.dirname&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os.path.abspath&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__file__&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Quick-start development settings - unsuitable for production&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# SECURITY WARNING: keep the secret key used in production secret!&lt;/span&gt;
SECRET_KEY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;removed-secret-key-leave-yours-here&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# SECURITY WARNING: don&#39;t run with debug turned on in production!&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#leave as True for now, but when you send into production (i.e. other people will use it) then set to false.&lt;/span&gt;

DEBUG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True

&lt;span class=&quot;token comment&quot;&gt;#where it says &#39;myapi.thetestspecimen.com&#39; you should replace this with your actual domain name for the api.&lt;/span&gt;

ALLOWED_HOSTS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;,&lt;span class=&quot;token string&quot;&gt;&#39;127.0.0.1&#39;&lt;/span&gt;,&lt;span class=&quot;token string&quot;&gt;&#39;myapi.thetestspecimen.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Application definition&lt;/span&gt;

INSTALLED_APPS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.admin&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.contenttypes&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.sessions&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.messages&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.staticfiles&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;rest_framework&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django_filters&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;myapi.api.apps.ApiConfig&#39;&lt;/span&gt;,
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

MIDDLEWARE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;django.middleware.security.SecurityMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.sessions.middleware.SessionMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.middleware.common.CommonMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.middleware.csrf.CsrfViewMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.messages.middleware.MessageMiddleware&#39;&lt;/span&gt;,
    &lt;span class=&quot;token string&quot;&gt;&#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;&lt;/span&gt;,
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

ROOT_URLCONF &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;myapi.urls&#39;&lt;/span&gt;

TEMPLATES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;BACKEND&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.template.backends.django.DjangoTemplates&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;DIRS&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;APP_DIRS&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; True,
        &lt;span class=&quot;token string&quot;&gt;&#39;OPTIONS&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&#39;context_processors&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&#39;django.template.context_processors.debug&#39;&lt;/span&gt;,
                &lt;span class=&quot;token string&quot;&gt;&#39;django.template.context_processors.request&#39;&lt;/span&gt;,
                &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.context_processors.auth&#39;&lt;/span&gt;,
                &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.messages.context_processors.messages&#39;&lt;/span&gt;,
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;,
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

WSGI_APPLICATION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;myapi.wsgi.application&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Database&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# https://docs.djangoproject.com/en/2.1/ref/settings/#databases&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;#We will be using a Postgresql database. Replace the database name, user and password with what you would like to use when we setup the database in the next section of the article&lt;/span&gt;

DATABASES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;default&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;ENGINE&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.db.backends.postgresql_psycopg2&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;NAME&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dbmyapi&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;USER&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;myusername&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;PASSWORD&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mypassword&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;HOST&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;,
        &lt;span class=&quot;token string&quot;&gt;&#39;PORT&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Password validation&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators&lt;/span&gt;

AUTH_PASSWORD_VALIDATORS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;NAME&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.password_validation.UserAttributeSimilarityValidator&#39;&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;NAME&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.password_validation.MinimumLengthValidator&#39;&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;NAME&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.password_validation.CommonPasswordValidator&#39;&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;NAME&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;django.contrib.auth.password_validation.NumericPasswordValidator&#39;&lt;/span&gt;,
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Internationalization&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# https://docs.djangoproject.com/en/2.1/topics/i18n/&lt;/span&gt;

LANGUAGE_CODE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;en-us&#39;&lt;/span&gt;

TIME_ZONE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;UTC&#39;&lt;/span&gt;

USE_I18N &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True

USE_L10N &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True

USE_TZ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True

&lt;span class=&quot;token comment&quot;&gt;# Static files (CSS, JavaScript, Images)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# https://docs.djangoproject.com/en/2.1/howto/static-files/&lt;/span&gt;

STATIC_URL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/&#39;&lt;/span&gt;
STATIC_ROOT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; os.path.join&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BASE_DIR, &lt;span class=&quot;token string&quot;&gt;&#39;static/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;#These are some settings that make the setup more secure you don&#39;t need these if you don&#39;t want them&lt;/span&gt;

SECURE_SSL_REDIRECT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True
SESSION_COOKIE_SECURE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True
CSRF_COOKIE_SECURE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; True
SECURE_HSTS_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt; 

&lt;span class=&quot;token comment&quot;&gt;#Uncomment the section below if you want to remove the browsable API later on. For now just leave this section hashed out&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;#REST_FRAMEWORK = {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#    &#39;DEFAULT_RENDERER_CLASSES&#39;: (&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#        &#39;rest_framework.renderers.JSONRenderer&#39;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#    )&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;########################################################&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;setting-up-the-postgresql-database&quot; tabindex=&quot;-1&quot;&gt;Setting up the Postgresql database &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#setting-up-the-postgresql-database&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There various options of database that can be used for DRF, but I personally recommend Postgres as it is the closest to the real SQL standard, has an extensive feature set, and is open source.&lt;/p&gt;
&lt;p&gt;The other options are sqlite, MySQL and Oracle, should you prefer to use one of those.&lt;/p&gt;
&lt;p&gt;I&#39;m not going to go into a lot of detail here, but if you want more info on setting up postgres, Digital Ocean have a &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04&quot;&gt;great tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First we will install postgres:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; postgresql postgresql-contrib&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we log into the commandline interface for postgres:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-u&lt;/span&gt; postgres psql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now see a new commandline like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to create a user, a database and then assign the user to the database.&lt;/p&gt;
&lt;p&gt;Remember to use the same details that you put in your &lt;a href=&quot;http://settings.py/&quot;&gt;settings.py&lt;/a&gt; file we setup in the previous section:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;# CREATE USER myusername WITH PASSWORD &#39;mypassword&#39;;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;# CREATE DATABASE dbmyapi;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;# GRANT ALL PRIVILEGES ON DATABASE dbmyapi to myusername;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can check it has worked by listing the databases.&lt;/p&gt;
&lt;p&gt;Note: that there may be other items listed, but we should have at least the below:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;# &#92;l&lt;/span&gt;
  List of databases
     Name     &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;  Owner   &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Encoding &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;   Collate   &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;    Ctype    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;     Access privileges     
--------------+----------+----------+-------------+-------------+---------------------------
 dbmyapi      &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; postgres &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; UTF8     &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; en&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_US.UTF-8 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; en&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_US.UTF-8 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Tc/postgres             +
              &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;          &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;          &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;             &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;             &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;CTc/postgres    +
              &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;          &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;          &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;             &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;             &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;myusername&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;CTc/postgres           &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the databases is listed correctly we can then quit the postgres commandline:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;# &#92;q&lt;/span&gt;
user@server:/var/www/myapi/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are now in a position to connect the database with django rest framework:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi/myapi$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /var/www/myapi
user@server:/var/www/myapi$ &lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; env/bin/activate
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ python manage.py migrate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command should setup the necessary parameters within the database you have just created.&lt;/p&gt;
&lt;p&gt;If there are any errors reported double check that the parameters you setup for the database are correct in the &lt;a href=&quot;http://settings.py/&quot;&gt;settings.py&lt;/a&gt; file.&lt;/p&gt;
&lt;h2 id=&quot;create-django-superuser&quot; tabindex=&quot;-1&quot;&gt;Create Django Superuser &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#create-django-superuser&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To allow you to log in and administer the API from a browser you need to create a superuser for the project:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ python manage.py createsuperuser &lt;span class=&quot;token parameter variable&quot;&gt;--email&lt;/span&gt; admin@example.com &lt;span class=&quot;token parameter variable&quot;&gt;--username&lt;/span&gt; admin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will then be prompted to enter a password for the user as well.&lt;/p&gt;
&lt;p&gt;Once the setup has been completed successfully you will be able to access the admin area from a url like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://myapi.thetestspecimen.com/admin/&quot;&gt;https://myapi.thetestspecimen.com/admin/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Obviously the domain will be whatever you choose to setup, which we will get to in the last section.&lt;/p&gt;
&lt;h2 id=&quot;download-static-files&quot; tabindex=&quot;-1&quot;&gt;Download static files &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#download-static-files&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DRF features a Browsable API.&lt;/p&gt;
&lt;p&gt;What this essential means is that once you have setup endpoints you will be able to access them from a browser to see how they respond.&lt;/p&gt;
&lt;p&gt;Take a look &lt;a href=&quot;https://www.django-rest-framework.org/topics/browsable-api/&quot;&gt;here&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;As the browsable API has some static components, we need to download them into our project so that the browsable API renders properly:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ python manage.py collectstatic  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you then run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;
manage.py &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; myapi static&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will see the addition of a static folder. You can then exit the virtual environment:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; user@server:/var/www/myapi$ deactivate
user@server:/var/www/myapi$&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;setup-apache2-for-the-api-domain&quot; tabindex=&quot;-1&quot;&gt;Setup Apache2 for the API domain &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#setup-apache2-for-the-api-domain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section you may be able to handle without instruction, but I have included just for completeness.&lt;/p&gt;
&lt;p&gt;We are basically going to setup the &amp;quot;sites-available&amp;quot; config file for the api domain. This will tell apache2 where to find the python files it should load when that specific domain name is requested.&lt;/p&gt;
&lt;p&gt;In this case the setup file will contain the configuration required for a https connection to the API. This assumes that an SSL certificate has been setup for the domain. If this is not the case, you will have to adjust the setup to work without SSL (which I don&#39;t recommend).&lt;/p&gt;
&lt;p&gt;You can setup a free SSL certificate using &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let&#39;s Encrypt&lt;/a&gt;, but it can be a little fiddly to get setup and to autorenew. I intend to write an article for this in the future, but for now check out this &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-18-04&quot;&gt;guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this case I am going to use an example domain of &amp;quot;&lt;a href=&quot;http://myapi.thetestspecimen.com/&quot;&gt;myapi.thetestspecimen.com&lt;/a&gt;&amp;quot;&lt;/p&gt;
&lt;h3 id=&quot;set-a-records&quot; tabindex=&quot;-1&quot;&gt;Set A Records &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#set-a-records&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you haven&#39;t already, go to your server setup and make sure that you have created a set of A records for the domain you intend to use.&lt;/p&gt;
&lt;p&gt;If you are not sure how to do this then check your server providers help files, as it varies with provider.&lt;/p&gt;
&lt;h3 id=&quot;create-config-file-in-sites-available&quot; tabindex=&quot;-1&quot;&gt;Create config file in sites available &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#create-config-file-in-sites-available&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We need to create the config file so apache knows where to look for the project. Obviously use your own domain name not the one below:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/var/www/myapi$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /etc/apache2/sites-available
user@server:/etc/apache2/sites-available$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; myapi.thetestsepcimen.com.conf
user@server:/etc/apache2/sites-available$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; myapi.thetestspecimen.com.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within the file paste the following, with the appropriate changes to folder paths and domain names:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#Example Django Rest Framework File&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;VirtualHost *:8&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;0&lt;/span&gt;&gt;&lt;/span&gt;
    ServerAdmin admin@thetestspecimen.com
    ServerName myapi.thetestspecimen.com
    
    Alias /.well-known/acme-challenge/ /var/www/myapi/.well-known/acme-challenge/
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Directory /var/www/myapi/&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    AllowOverride None
    Options None
    ForceType plain/text
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/Directory&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
     
    &lt;span class=&quot;token comment&quot;&gt;# This is optional, in case you want to redirect people &lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# from http to https automatically.&lt;/span&gt;
    RewriteEngine On
    RewriteCond %&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;REQUEST_URI&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;^/&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;.well&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;-known/acme&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;-challenge/
    RewriteCond %&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;HTTPS&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; off
    RewriteRule &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.*&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; https://%&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;HTTP_HOST&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;%&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;REQUEST_URI&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;R&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;301&lt;/span&gt;,L&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;VirtualHost *:44&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;3&lt;/span&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# Virtual host configuration + information (replicate changes to *:443 below)&lt;/span&gt;
  ServerAdmin admin@thetestspecimen.com
  ServerName api.thetestspecimen.com
  DocumentRoot /var/www/myapi

  Alias /static /var/www/myapi/static
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Directory /var/www/myapi/static&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	Require all granted
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/Directory&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
     
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Directory /var/www/myapi/myapi&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Files wsgi.py&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		Require all granted
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/Files&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/Directory&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

  WSGIDaemonProcess myapi  python-home&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/var/www/myapi/env python-path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/var/www/myapi
  WSGIProcessGroup myapi
  WSGIScriptAlias / /var/www/myapi/myapi/wsgi.py

  &lt;span class=&quot;token comment&quot;&gt;# SSL certificate + engine configuration&lt;/span&gt;
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/thetestspecimen.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/thetestspecimen.com/privkey.pem

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you have saved the file we then need to load the config file and restart apache2:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;user@server:/etc/apache2/sites-available$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; a2ensite myapi.thetestspecimen.com.conf
user@server:/etc/apache2/sites-available$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;service&lt;/span&gt; apache2 reload&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;check-the-admin-site-works!&quot; tabindex=&quot;-1&quot;&gt;Check the admin site works! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#check-the-admin-site-works!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point we are done with the basic setup.&lt;/p&gt;
&lt;p&gt;We can check if everything we have done worked by visiting the API url in a browser. In my case &amp;quot;&lt;a href=&quot;https://myapi.thetestspecimen.com/&quot;&gt;https://myapi.thetestspecimen.com&lt;/a&gt;&amp;quot;. You should see this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/django-initial/django-success.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/django-initial/django-success.png&quot; alt=&quot;Success screen for Django Rest Framework installation&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Django rest framework success screen&lt;/figcaption&gt;
&lt;p&gt;Furthermore, we can check all the settings worked by visiting the admin site and logging in with the superuser credentials you created earlier.&lt;/p&gt;
&lt;p&gt;Going to &amp;quot;&lt;a href=&quot;https://myapi.thetestspecimen.com/admin&quot;&gt;https://myapi.thetestspecimen.com/admin&lt;/a&gt;&amp;quot; I will see the following (remember to use your own domain when you try it):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/django-initial/django-admin.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/django-initial/django-admin.png&quot; alt=&quot;Django rest framework admin login screen&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Django rest framework admin login screen&lt;/figcaption&gt;
&lt;h2 id=&quot;the-end!&quot; tabindex=&quot;-1&quot;&gt;The End! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/django-rest-framework-initial-setup/#the-end!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You should now be able to start the journey of setting up your RESTful API.&lt;/p&gt;
&lt;p&gt;Django rest framework makes it really easy to achieve an excellent API without boilerplate code. You should be up and running in no time!&lt;/p&gt;
&lt;p&gt;Best of luck, and if you have any questions, let me know in the comments or send me an email.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As alluded to at the beginning of the article, I intend to write a part 2 to this tutorial. It will detail a basic setup of the configuration files so you can get some endpoints working. Watch this space. . .&lt;/strong&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Yubico Yubikey – Which Hardware Security Key Is the Best for Me?</title>
		<link href="https://www.thetestspecimen.com/posts/yubico-yubikey/"/>
		<updated>Sat, 19 Jan 2019 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/yubico-yubikey/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Yubico is the market leader when it comes to hardware security keys utilising FIDO U2F and FIDO2 such as the Yubikey, but which one should you buy to suit YOUR needs?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are actually a wide array of hardware security keys available from Yubico, and it can be quite confusing to try and pick out what you do and don&#39;t need.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I hate purchasing a product and then finding out it is either missing a feature I wanted, or there was something better suited to my needs that I missed...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update Jan 2019&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It turns out that Yubico have recently released an NFC version of their Security Key.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This along with the release of the Yubikey 5 series late last year makes picking up the best key a lot easier. I have therefore updated the article below to reflect this.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;before-we-begin&quot; tabindex=&quot;-1&quot;&gt;Before we begin &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#before-we-begin&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are looking at this article and you have no idea who Yubico are, or what a hardware security key is, then I recommend you read our &lt;a href=&quot;https://www.thetestspecimen.com/security-keys-yubikey/&quot;&gt;previous article&lt;/a&gt; which should bring you up to speed.&lt;/p&gt;
&lt;h2 id=&quot;the-main-yubico-family&quot; tabindex=&quot;-1&quot;&gt;The Main Yubico Family &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#the-main-yubico-family&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-yubikey-family-new.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-yubikey-family-new.jpg&quot; alt=&quot;Yubico Yubikey family and Yubico Security Key 2&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Yubico 5 series family plus the Yubico Security Key 2&lt;/figcaption&gt;
&lt;p&gt;The picture above shows the main security keys that are currently available form Yubico. The blue device on the left is the Yubico Security Key (of which there are now two versions: with NFC and without NFC), and the four devices on the right are the Yubikey 5 Series keys in different form factors. They all look fairly similar, but in some cases they have very different features, so I will do my best to point you in the right direction.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-the-difference%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#what&#39;s-the-difference%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the keys listed above can deal with both FIDO U2F and FIDO2 (if you don&#39;t know what either of those are take a look at my &lt;a href=&quot;https://www.thetestspecimen.com/security-keys-yubikey/&quot;&gt;previous article&lt;/a&gt;), which are the main protocols that everyday users will be interested in at the moment. One of the most important new releases is FIDO2 support, which represents the future of password-less login.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/fido2.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/fido2.png&quot; alt=&quot;FIDO2&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From that point is where the differences start to come in. Some have NFC, some don&#39;t. Some have more advanced protocols available, others don&#39;t. . .and as you can see from the picture above they come in a variety of form factors.&lt;/p&gt;
&lt;p&gt;So let&#39;s get stuck in!&lt;/p&gt;
&lt;h3 id=&quot;yubikey-5-series&quot; tabindex=&quot;-1&quot;&gt;Yubikey 5 Series &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#yubikey-5-series&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Yubikey 5 series is the most advanced key Yubico produce in terms of features. If you want all the possible features you can think of in one security key then these guys have you covered.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-family-1.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-family-1.jpg&quot; alt=&quot;The Yubico Yubikey family of keys&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Yubico Yubikey 5 series family&lt;/figcaption&gt;
&lt;p&gt;In terms of the security capabilities of the series 5 keys, all have exactly the same features. The only differences come with the interfaces used for connectivity. So from left to right:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;USB Type A and NFC&lt;/li&gt;
&lt;li&gt;USB Type C (no NFC)&lt;/li&gt;
&lt;li&gt;USB Type A low profile (no NFC) - designed to be very low profile in a laptop or server&lt;/li&gt;
&lt;li&gt;USB type C low profile (no NFC) - designed to be very low profile in a laptop or server&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In terms of protocols that the keys can deal with, here it is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FIDO2&lt;/li&gt;
&lt;li&gt;FIDO U2F&lt;/li&gt;
&lt;li&gt;OpenPGP&lt;/li&gt;
&lt;li&gt;Smart Card (PIV)&lt;/li&gt;
&lt;li&gt;Yubico OTP&lt;/li&gt;
&lt;li&gt;OATH-TOTP&lt;/li&gt;
&lt;li&gt;OATH-HOTP&lt;/li&gt;
&lt;li&gt;Challenge-Response&lt;/li&gt;
&lt;li&gt;Storage of long password strings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don&#39;t know what any of the above are apart from FIDO U2F and FIDO2, then it is likely you will not need them. If that is the case you may be more interested in the Yubico Security Key, which we will get to later in the article.&lt;/p&gt;
&lt;p&gt;I would encourage you to take a look at the uses for each item on the list above in case the use case interests you. For example OpenPGP can be used to send secure emails, and encrypt and decrypt files.&lt;/p&gt;
&lt;h3 id=&quot;which-of-the-four-series-5-keys-is-the-best-to-get%3F&quot; tabindex=&quot;-1&quot;&gt;Which of the four series 5 keys is the best to get? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#which-of-the-four-series-5-keys-is-the-best-to-get%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This depends on your circumstances, but in general you should opt for the USB type A version.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-laptop.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-laptop.jpg&quot; alt=&quot;Yubico Yubikey 5 NFC in use in a laptop&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are various reasons for this. Firstly the build quality of this key is excellent. It is waterproof and crush-proof.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/press_diving-1024x681.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/press_diving-1024x681.jpg&quot; alt=&quot;Yubikey press photo of diver to show they are waterproof&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is extremely thin, and about the same size as a standard house key, which makes it ideal for key-chains.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubikey-thickness.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubikey-thickness.jpg&quot; alt=&quot;Yubikey thickness comparison&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Thickness comparison of Yubico Security Key 2, Yubikey 5 and a standard house key&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/keyscompare.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/keyscompare.jpg&quot; alt=&quot;Yubikey size comparison to house key&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Yubico Securtiy Key 2, Yubikey 4 (same form factor as Yubikey 5) and standard house key&lt;/figcaption&gt;
&lt;p&gt;...and on top of all that it is the only key in the Yubico 5 Series that has NFC connectivity. This means that you can not only use this device to secure your logins on your desktop computer, but also your android smartphone or iPhone!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-nfc-android.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-nfc-android.jpg&quot; alt=&quot;Yubico Yubikey 5 NFC for android&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Yubico Yubikey 5 NFC for android&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-nfc-iphone.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/yubico-5-nfc-iphone.jpg&quot; alt=&quot;Yubico Yubikey 5 NFC for the iPhone&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Yubico Yubikey 5 NFC for the iPhone&lt;/figcaption&gt;
&lt;p&gt;With all that aside, there are obviously reasons you might want to opt for one of the other keys.&lt;/p&gt;
&lt;p&gt;For example if you want to have the keys permanently in a laptop or server, then the low profile USB-A and USB-C keys make sense. Also if you predominantly use devices with USB type C ports then the USB type C key makes a lot of sense.&lt;/p&gt;
&lt;p&gt;However, as detailed above I think for most people the USB Type A key is just the best all rounder. Rugged, and with the best connectivity options.&lt;/p&gt;
&lt;h3 id=&quot;yubico-security-key-2&quot; tabindex=&quot;-1&quot;&gt;Yubico Security Key 2 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#yubico-security-key-2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your main concern is securing your login into websites such as Facebook, Twitter, Google accounts etc. Then the main protocols of interest are FIDO2 and FIDO U2F.&lt;/p&gt;
&lt;p&gt;The Yubico Security key 2 covers those use cases without all the other more complicated protocols. As such it represents great value for most people, at around half the price of the 5 series keys.&lt;/p&gt;
&lt;p&gt;Furthermore, as of January 2019 the Security Key can now be purchased with NFC connectivity, so you can use it with your phone or other NFC capable devices.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/Security-Key-by-Yubico.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/Security-Key-by-Yubico.png&quot; alt=&quot;Yubico security key 2&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;yubico-fips-(not-pictured)&quot; tabindex=&quot;-1&quot;&gt;Yubico FIPS (not pictured) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#yubico-fips-(not-pictured)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Yubico has another series of keys that look identical to the 5 series keys. They are called the FIPS series.&lt;/p&gt;
&lt;p&gt;As I understand it, Yubico has been seeking certification for &lt;a href=&quot;https://en.wikipedia.org/wiki/FIPS_140-2&quot;&gt;FIPS 140&lt;/a&gt; for a while, and it just attained it.&lt;/p&gt;
&lt;p&gt;FIPS-140 is basically a set of standards that a hardware security device must meet according to the requirements of US government agencies. The requirements are quite stringent, which proves that the keys on offer by Yubico are indeed top notch.&lt;/p&gt;
&lt;p&gt;It was actually the previous series (4 series) keys that were entered for certification, which is why they look exactly the same (please note the 5 series and 4 series keys look literally identical with the exception of the NFC sign on the 5 series USB type A key). What this likely means is that the FIPS keys are based on the old 4 series keys, and so you would miss out on NFC connectivity for example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The long and short is:&lt;/strong&gt; you only need the FIPS series keys if you work for a government agency that requires FIPS certification, otherwise it really isn&#39;t worth the hassle.&lt;/p&gt;
&lt;h2 id=&quot;my-current-setup&quot; tabindex=&quot;-1&quot;&gt;My Current Setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#my-current-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just to give you an idea of what I use my keys for. . .&lt;/p&gt;
&lt;p&gt;I actually own three Yubikeys. I decided to buy a Security Key 2 (without NFC as there was no option at the time) and a Yubikey 4 USB type A originally (see picture below). I have since purchased a Yubikey 5 Series USB Type A key to take advantage of the NFC capabilities of the new key. For me this is just about perfect.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/keysabstract.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/yubico-yubikey/keysabstract.jpg&quot; alt=&quot;Two yubikeys balancing against each other on a table&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have my main 5 Series key that I carry around all the time, which can deal with FIDO U2F and FIDO2 for logins, whilst also holding my PGP keys for server login, and file signing / encryption. I then have the Yubico Security Key 2 as a backup for all the FIDO U2F and FIDO2 logins, and the Series 4 Key contains a backup of my PGP keys.&lt;/p&gt;
&lt;p&gt;If I was to do it all again I would likely just get two Yubikey 5 Series keys, but I didn&#39;t have that option when I originally purchased them.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-and-recommendations&quot; tabindex=&quot;-1&quot;&gt;Conclusion and Recommendations &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/yubico-yubikey/#conclusion-and-recommendations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For most people I would recommend that you buy &lt;strong&gt;at least two&lt;/strong&gt; Yubico Security Key 2 NFC devices.&lt;/p&gt;
&lt;p&gt;If you really need the extra features of the 5 Series Yubikeys, then I would recommend you buy &lt;strong&gt;at least two&lt;/strong&gt; Yubikey 5 Series NFC Type A keys.&lt;/p&gt;
&lt;p&gt;If you are not sure why you would need a pair of security keys I would suggest giving my &lt;a href=&quot;https://www.thetestspecimen.com/security-keys-yubikey/&quot;&gt;previous article&lt;/a&gt; a read, which explains why. The short answer is: it acts as a backup should you lose one!&lt;/p&gt;
&lt;p&gt;Overall, my experience so far has been excellent with regard to FIDO U2F. It really is a breeze to use, but I think the guidance and usage with regard to the more advanced features needs a little bit of work to make it easier to implement.&lt;/p&gt;
&lt;p&gt;Either way they are worth the effort to learn how to use as the extra security they bring cannot be understated.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Why I Switched to Manjaro As My Daily Linux Operating System</title>
		<link href="https://www.thetestspecimen.com/posts/linux-manjaro/"/>
		<updated>Fri, 14 May 2021 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/linux-manjaro/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;This article is not to convince Windows users to switch, although for some it may be beneficial. It is to detail why I decided on Manjaro over the long list of other Linux distributions that are available.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I have used other systems such as Ubuntu and Fedora for years, so have a reasonable view of what is going on elsewhere. So if you think another Linux users opinion may be interesting, maybe read on...&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-previous-linux-distros-have-you-used%3F&quot; tabindex=&quot;-1&quot;&gt;What previous Linux distros have you used? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#what-previous-linux-distros-have-you-used%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have been using Linux as my main and only OS for quite a few years now. I started off using Ubuntu, which I suspect a lot of people do. I still believe Ubuntu is probably the best starting point for someone new to Linux. Mainly because of the large community, and hence guidance, available online.&lt;/p&gt;
&lt;p&gt;When I got my first itch to try something different I ended up settling on Fedora (which I think was at about release 26 at the time). I then stuck with Fedora right up until switching to Manjaro at the start of this year (2021).&lt;/p&gt;
&lt;p&gt;I should also note that over all of that time my server has been running on Ubuntu. The option of &#39;fully up to date&#39; or Long Term Support (LTS) versions is one of the great attributes that Ubuntu has available.&lt;/p&gt;
&lt;h2 id=&quot;have-you-used-any-other-distributions-over-that-time&quot; tabindex=&quot;-1&quot;&gt;Have you used any other distributions over that time &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#have-you-used-any-other-distributions-over-that-time&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The amount of distributions Linux has available could be seen as a curse, and I am sure it is a bit overwhelming for newcomers.  However, I have generally found it to be of great use in various situations. These are the distributions I currently use:&lt;/p&gt;
&lt;h3 id=&quot;zorin-os&quot; tabindex=&quot;-1&quot;&gt;Zorin OS &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#zorin-os&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I chose Zorin OS xfce install to replace Chrome OS on my, now dated, Acer C720P chromebook. This was mainly because I was no longer receiving security updates from ChromeOS.&lt;/p&gt;
&lt;p&gt;The main problem I had is that it has non-upgradeable RAM, and there is only 2GB available on my particular model. This seriously limits your options.&lt;/p&gt;
&lt;p&gt;I basically wanted something that looked nice, and ran smoothly. With the limited power and RAM. Zorin OS xfce met these requirements perfectly.&lt;/p&gt;
&lt;h3 id=&quot;raspberry-pi-(raspbian)&quot; tabindex=&quot;-1&quot;&gt;Raspberry Pi (Raspbian) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#raspberry-pi-(raspbian)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I needed to produce something that was cheap but fully functional, and that could integrate with existing windows systems.&lt;/p&gt;
&lt;p&gt;Raspian, or more the cheapness of Raspberry Pi, fit the bill here perfectly.&lt;/p&gt;
&lt;h3 id=&quot;tails&quot; tabindex=&quot;-1&quot;&gt;Tails &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#tails&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I always have a tails install on one of my USB drives.&lt;/p&gt;
&lt;p&gt;If you need some temporary security while out and about, Tails is perfect.&lt;/p&gt;
&lt;h3 id=&quot;others&quot; tabindex=&quot;-1&quot;&gt;Others &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#others&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have also at various points in time used the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Qubes (A great security focused OS)&lt;/li&gt;
&lt;li&gt;Pop OS (Probably the best ubuntu based OS out there)&lt;/li&gt;
&lt;li&gt;Kali (Designed for penetration testing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There may be more that I can&#39;t remember.&lt;/p&gt;
&lt;p&gt;Considering all the distros I have tried, I haven&#39;t even really scratched the surface. There are many more!&lt;/p&gt;
&lt;h2 id=&quot;why-did-you-consider-manjaro-over-all-the-other-distros%3F&quot; tabindex=&quot;-1&quot;&gt;Why did you consider Manjaro over all the other distros? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#why-did-you-consider-manjaro-over-all-the-other-distros%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;rolling-updates&quot; tabindex=&quot;-1&quot;&gt;Rolling updates &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#rolling-updates&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the main reasons that I initially decided to look into Manjaro is that I heard it has a &#39;rolling&#39; update method of releasing updates.&lt;/p&gt;
&lt;h4 id=&quot;what-exactly-are-&#39;rolling&#39;-updates&quot; tabindex=&quot;-1&quot;&gt;What exactly are &#39;rolling&#39; updates &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#what-exactly-are-&#39;rolling&#39;-updates&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;What this basically means is that the OS is updated continuously as updates for various programs and packages are released by their maintainers. This differs from other large distros such as Ubuntu or Fedora which have major updates approximately every 6 months.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is nice to see the shiny new features after a major upgrade, but this is often tarnished by the fiddling about that is required afterwards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The problem withmajor updates every 6 months is that, more often than not, something will break. These days the operatings system itself will update perfectly. However, every time I have done a major update there is a program or system utility that will need fixing or readjusting to work as it did before the update ran.&lt;/p&gt;
&lt;p&gt;It is nice to see the shiny new features after a major upgrade, but this is often tarnished by the fiddling about that is required afterwards.&lt;/p&gt;
&lt;p&gt;You don&#39;t have any of this pain with Manjaro.&lt;/p&gt;
&lt;h4 id=&quot;the-advantages-of-rolling-updates&quot; tabindex=&quot;-1&quot;&gt;The advantages of rolling updates &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#the-advantages-of-rolling-updates&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You may argue that things can go wrong with rolling updates, and yes they can. I haven&#39;t experienced it yet, but I have no doubt my day will come!&lt;/p&gt;
&lt;p&gt;The difference is, that with rolling updates you have far less to deal with. Trying to pin point the source of a problem after a major 6 month upgrade affecting hundreds, maybe thousands of packages is a nightmare. The smaller &#39;upgrade&#39; of rolling releases are much more managable.&lt;/p&gt;
&lt;h3 id=&quot;it-is-based-on-arch-linux&quot; tabindex=&quot;-1&quot;&gt;It is based on Arch Linux &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#it-is-based-on-arch-linux&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This more intrigued me than anything else. Arch linux has a reputation, and a good one at that.&lt;/p&gt;
&lt;p&gt;Think about the type of person you need to be to run Arch. You need to be &lt;strong&gt;really&lt;/strong&gt; into your system to want to spend the time it takes to basically build your operating system from scratch. And that&#39;s what Arch is, ultimate flexibility.&lt;/p&gt;
&lt;p&gt;...but this has a side effect. The people involved in the community are likely to be very knowledgable. This is basically proven by the existence of the &lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;Arch Wiki&lt;/a&gt; and  &lt;a href=&quot;https://aur.archlinux.org/&quot;&gt;Arch User Repository (AUR)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even if you don&#39;t use Arch Linux, the arch wiki is an insanely good source of information to troubleshoot all sorts of problems!&lt;/p&gt;
&lt;h2 id=&quot;if-you-like-the-idea-of-arch%2C-why-not-just-use-arch%3F&quot; tabindex=&quot;-1&quot;&gt;If you like the idea of Arch, why not just use Arch? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#if-you-like-the-idea-of-arch%2C-why-not-just-use-arch%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where it comes down to personal preference.&lt;/p&gt;
&lt;p&gt;I could go the whole hog, but the reality is I don&#39;t want to. I have no desire to build my system from scratch, because to be honest when I started looking into Manjaro it seemed to be well thought out, and pretty flexible &lt;strong&gt;if you want it to be&lt;/strong&gt;. I suspect I would struggle to beat it with my own build!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have no desire to build my system from scratch&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is also an added element of stability. The Manjaro developers test updates released for Arch for stability etc. before they are made available in Manjaro. I think this is a very good idea.&lt;/p&gt;
&lt;p&gt;Yes, you sacrafice some cutting-edge-ness, but for me at least, the amount I lose is very small, and irrelevant. I much prefer the added stability.&lt;/p&gt;
&lt;h2 id=&quot;so-you-like-manjaro%2C-what-made-you-stick-with-it%3F&quot; tabindex=&quot;-1&quot;&gt;So you like Manjaro, what made you stick with it? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#so-you-like-manjaro%2C-what-made-you-stick-with-it%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suprisingly quite a lot. I really liked using Fedora, and did for many years, but Manjaro fits me like a glove. It really is an excellent distro.&lt;/p&gt;
&lt;h3 id=&quot;many-install-options&quot; tabindex=&quot;-1&quot;&gt;Many install options &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#many-install-options&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;People have different tastes when it comes to desktop GUI environments. As main &#39;official&#39; options you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNOME&lt;/li&gt;
&lt;li&gt;KDE Plasma&lt;/li&gt;
&lt;li&gt;Xfce&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general I would say that covers most people. Not a bad start!&lt;/p&gt;
&lt;p&gt;Don&#39;t like those? Well you can also get the following community editions, easily downloadable from the official website:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Budgie&lt;/li&gt;
&lt;li&gt;Cinnamon&lt;/li&gt;
&lt;li&gt;i3&lt;/li&gt;
&lt;li&gt;MATE&lt;/li&gt;
&lt;li&gt;Sway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have an ARM device. No worries! There are loads of options for that too. Even the Rasperry Pi 4!&lt;/p&gt;
&lt;h3 id=&quot;further-install-flexibility-if-you-want-it&quot; tabindex=&quot;-1&quot;&gt;Further install flexibility if you want it &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#further-install-flexibility-if-you-want-it&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The previous section should satisfy most people, and the install is a breeze. But what if you didn&#39;t like one of the options chosen for you in the install?&lt;/p&gt;
&lt;p&gt;I had this problem. I wanted to use Btrfs as the disk filesystem, not ext4 which is standard.&lt;/p&gt;
&lt;p&gt;When I originally installed Manjaro at the start of this year there was an &#39;Architect&#39; version available that allowed a much more fine tuned install process, especially in terms of partitioning, swap, file system etc.&lt;/p&gt;
&lt;p&gt;I have noticed that currently this option seems to have disappeared from the official website, but it was possible to boot into the architect installer from any ISO (which is what I did), so hopefully this option remains for the added flexibility that some people will want.&lt;/p&gt;
&lt;p&gt;If you don&#39;t have any specific additional requirements (and you will know if you have) then the standard installs are sufficient, and really easy to deal with.&lt;/p&gt;
&lt;h3 id=&quot;package-management&quot; tabindex=&quot;-1&quot;&gt;Package management &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#package-management&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In previous distros I have tended to do all package updating on the command line. This was mainly because I found it easier and more informative. I have also never really been very impressed with the GUI package managers of either Ubuntu or Fedora, in my case in Gnome.&lt;/p&gt;
&lt;p&gt;Installing third party packages on either Fedora or Ubuntu (think PPAs if you are familiar with Ubuntu), always ends up being quite messy. It is something that I have put up with, as I didn&#39;t see another way, but the truth is I found it quite annoying.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Installing third party packages on either Fedora or Ubuntu (think PPAs if you are familiar with Ubuntu), always ends up being quite messy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think the package management, and the tools and methods used in Manjaro, is one of the major things that make it a pleasure to use. If you really think about it, you interact with package managers on a day to day basis. They need to work well.&lt;/p&gt;
&lt;p&gt;There are three items that make it work smoothly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pacman (the base package manager)&lt;/li&gt;
&lt;li&gt;Pamac (the GUI package manager)&lt;/li&gt;
&lt;li&gt;Arch User Repository (AUR)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...and unusually, it is the GUI package manager that is the stand-out item in this list. It is the only time I have started to favour the GUI package over the command line.&lt;/p&gt;
&lt;p&gt;To understand why it works well, you first need to understand what the AUR is. It is essentially a repository that contains user made packages, a bit like PPAs in Ubuntu. So any packages that you don&#39;t have access to from the main Manjaro repo, you can get from the AUR (if it exists). If not, you are free to contribute yourself, and as always there are extensive instructions in the Arch wiki to help you do just that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As you move forward, you don&#39;t end up with a fragmented mess.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The clever part is that Pamac keeps track of both normal Manjaro packages and AUR packages, and they are labelled clearly as such. You can install and uninstall either in exactly the same way - with the click of a button!&lt;/p&gt;
&lt;p&gt;Some of the credit for this simple setup needs to be given to the AUR itself, which by nature ensures a consistent way of packaging the files. This means that any dependencies are taken care of as well, so you don&#39;t have to go fiddling around in config files, or installing additional items manually. As you move forward, you don&#39;t end up with a fragmented mess.&lt;/p&gt;
&lt;h3 id=&quot;the-base-installs-are-aesthetically-pleasing&quot; tabindex=&quot;-1&quot;&gt;The base installs are aesthetically pleasing &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#the-base-installs-are-aesthetically-pleasing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First and foremost the default settings for a desktop environment are really nice in terms of aesthetics. I use GNOME as my desktop, so it is a little difficult to comment of the other spins (KDE and xfce), but I have briefly installed the xfce version, and I would say it is probably the most aesthetically pleasing xfce I have ever seen (with the exception of Zorin OS xfce, maybe).&lt;/p&gt;
&lt;p&gt;The above is subjective obviously, and of course you could customise it, as you could on any other GNOME desktop. However, out of the box I prefer the base GNOME setup to any other I have seen.&lt;/p&gt;
&lt;h3 id=&quot;desktop-layout-is-highly-configurable&quot; tabindex=&quot;-1&quot;&gt;Desktop layout is highly configurable &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#desktop-layout-is-highly-configurable&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;More inportant than the above, and another main reason for switching, is the flexibility they have made available out of the box. In this case I am talking about how you like to configure your desktop.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-layout-switcher.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-layout-switcher.jpg&quot; alt=&quot;Manjaro layout switcher options&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;The different layout options available with Manjaro&lt;/figcaption&gt;
&lt;p&gt;In the image above you can see the various options.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manjaro - a slightly tweaked traditional Gnome layout (uses dash-to-dock for example)&lt;/li&gt;
&lt;li&gt;Traditional - as close to Windows as you can get&lt;/li&gt;
&lt;li&gt;Unity&lt;/li&gt;
&lt;li&gt;Modern - think MacOS layout&lt;/li&gt;
&lt;li&gt;Gnome - the bog standard Gnome layout&lt;/li&gt;
&lt;li&gt;Tiling - an auto tiling desktop&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can switch between any of the above with ease and try out which one you like. This means that if you are not a massive fan of the traditional Gnome layout then you can get things how you like them without installing additional 3rd party packages.&lt;/p&gt;
&lt;p&gt;As for me, I went with the Manjaro layout, but moved the dash-to-dock bar down to the bottom rather than the left edge. I never understood the left edge layout, as all your icons end up squashed.&lt;/p&gt;
&lt;p&gt;The layout switcher also has a settings tab that gives you quick access to things like gnome tweak tool and gnome extensions, as well as some additional features such as auto dark theme and window tiling.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-layout-switcher-settings.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-layout-switcher-settings.jpg&quot; alt=&quot;Manjaro layout switcher settings&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Access to different tools and some additional settings&lt;/figcaption&gt;
&lt;h3 id=&quot;pop-shell-window-tiling&quot; tabindex=&quot;-1&quot;&gt;Pop-shell window tiling &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#pop-shell-window-tiling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may have spotted in the previous section that the settings section of the layout switcher has an item called &amp;quot;Window Tiling (Pop-shell)&amp;quot;.&lt;/p&gt;
&lt;p&gt;This, in my opinion is a really excellent addition. Pop shell is essentially a window tiling system developed by &lt;a href=&quot;https://system76.com/&quot;&gt;System76&lt;/a&gt; for &lt;a href=&quot;https://pop.system76.com/&quot;&gt;PopOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If this feature is turned on you then have access to Pop-shell within Manjaro! The way it is integrated is by the addition of a simple icon in the top bar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-pop-shell-options.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-pop-shell-options.jpg&quot; alt=&quot;Manjaro Pop shell integration&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;System76 Pop shell in Manjaro&lt;/figcaption&gt;
&lt;p&gt;This allows you to quickly and easily have an easy to use window tiling system when it suits the situation, and then turn it off when you don&#39;t need it. All integrated perfectly and easy to use.&lt;/p&gt;
&lt;h3 id=&quot;change-your-kernel-on-demand&quot; tabindex=&quot;-1&quot;&gt;Change your kernel on demand &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#change-your-kernel-on-demand&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Not something that I specifically use, but is noteworthy, is that Manjaro has within it&#39;s GUI settings manager a kernel manager.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-settings-kernel.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/linux-manjaro/manjaro-settings-kernel.jpg&quot; alt=&quot;Manjaro kernel manager&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Manjaro kernel manager&lt;/figcaption&gt;
&lt;p&gt;This means you can easily switch kernel at a moments notice. I imagine some people will find this quite useful.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/linux-manjaro/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all Manjaro is really well rounded OS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;plenty of features to allow you to easily set up the OS the way you want it,&lt;/li&gt;
&lt;li&gt;solid and well thought out packageing system and software so you don&#39;t end up with an unkempt mess after a few months of use.&lt;/li&gt;
&lt;li&gt;no major updates to contend with every six months&lt;/li&gt;
&lt;li&gt;looks pretty good out of the box&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recommend you give it a try.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Use a Yubikey in WSL2 on Windows</title>
		<link href="https://www.thetestspecimen.com/posts/wsl2-yubikey/"/>
		<updated>Wed, 22 Dec 2021 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/wsl2-yubikey/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Windows now includes, natively, a subsystem that provides access to a real instance of Linux (by default Ubuntu). Access to a bash commandline, and Linux tools, can make some situations much easier. However, if you use a yubikey, or other hardware based authentication, it is not obvious how to utilise these within the Linux subsystem for ssh access to remote servers or github commits&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article is aimed at helping to get you setup in WSL2 with working yubikey gpg/ssh access.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;before-we-get-started&quot; tabindex=&quot;-1&quot;&gt;Before we get started &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#before-we-get-started&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is assumed that you already have a yubikey, and that you have your gpg/pgp keys setup and ready to go.&lt;/p&gt;
&lt;p&gt;If this is not the case, there are a plethora of tutorials available to guide you through it. Please set it up and come back here once you are ready.&lt;/p&gt;
&lt;h2 id=&quot;the-yubikey-must-function-for-gpg-and-ssh-in-windows&quot; tabindex=&quot;-1&quot;&gt;The yubikey must function for GPG and SSH in Windows &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#the-yubikey-must-function-for-gpg-and-ssh-in-windows&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we dive into the WSL2 environment, it is probably wise to check that the yubikey works in a Windows&lt;br /&gt;
environment as we would expect. Essentially, we are just creating a path for the yubikey to access authentication tools from Windows...so if your Yubikey doesn&#39;t work properly in Windows, it won&#39;t in WSL2 either.&lt;/p&gt;
&lt;p&gt;If you are happy that all is well in Windows, then you can skip this section, otherwise make sure to follow the steps that follow.&lt;/p&gt;
&lt;h3 id=&quot;install-gnupg-and-putty-in-windows&quot; tabindex=&quot;-1&quot;&gt;Install GnuPG and PuTTY in Windows &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#install-gnupg-and-putty-in-windows&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You should install &lt;a href=&quot;https://gnupg.org/download/index.html&quot;&gt;GnuPG&lt;/a&gt; and &lt;a href=&quot;https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html&quot;&gt;PuTTY&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This will give you all the tools you need to successfully use a yubikey in Windows for SSH.&lt;/p&gt;
&lt;p&gt;As part of the install for GnuPG you should have a program called Kleopatra. If you open this program and plug in your yubikey, you should be able to click on &amp;quot;Smartcards&amp;quot; in the interface, then click F5 on your keyboard, and it will display the info about the yubikey.&lt;/p&gt;
&lt;h3 id=&quot;gpg-config-file&quot; tabindex=&quot;-1&quot;&gt;GPG Config file &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#gpg-config-file&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To enable SSH to work properly you will need to create a config file.&lt;/p&gt;
&lt;p&gt;If we assume our username is &amp;quot;Dave&amp;quot; then the path to this file would be:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:&#92;Users&#92;Dave&#92;AppData&#92;Roaming&#92;gnupg&#92;gpg-agent.conf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;(Obviously change &amp;quot;Dave&amp;quot; to your own username on Windows in the path above)&lt;/p&gt;
&lt;p&gt;The above mentioned file will likely not exist. If it doesn&#39;t, then just create a blank file, otherwise use the one that is already there.&lt;/p&gt;
&lt;p&gt;Then you need to add to the file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;enable-putty-support
enable-ssh-support
default-cache-ttl &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;
max-cache-ttl &lt;span class=&quot;token number&quot;&gt;7200&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;ultimate-trust-for-your-public-key&quot; tabindex=&quot;-1&quot;&gt;Ultimate trust for your public key &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#ultimate-trust-for-your-public-key&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although potentially not essential to this process, it is probably a good idea to include this step.&lt;/p&gt;
&lt;p&gt;Essentially we are going to give our public key ultimate trust. I am going to assume you can locate your own public key, from either your own location, or from a keyserver. Once you have located it you need it import it into Kleopatra, or on the commandline if you know how.&lt;/p&gt;
&lt;p&gt;Now we are going to assign the key ultimate trust.&lt;/p&gt;
&lt;p&gt;Open powershell and type &lt;code&gt;gpg --card-status&lt;/code&gt; and you should see various information about your yubikey. If not, something is not working correctly, try rebooting and give it another go. If you still have issues try going through the steps above again.&lt;/p&gt;
&lt;p&gt;The next command is &lt;code&gt;gpg --list-keys&lt;/code&gt;. This will give you the gpg public key. The top two lines of the output will look something like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pub   rsa4096 &lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;-05-02 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;SC&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  1CA87B39873495770098080098336BC4E5C445AB&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The long string is your public key fingerprint, which you will need in the next step.&lt;/p&gt;
&lt;p&gt;Type &lt;code&gt;gpg --edit-key 1CA87B39873495770098080098336BC4E5C445AB&lt;/code&gt; this will bring up a &lt;code&gt;gpg&amp;gt;&lt;/code&gt; prompt in which you should type &amp;quot;trust&amp;quot;. It will then prompt you for a number. Enter &amp;quot;5&amp;quot;, which is ultimate trust. Then confirm as instructed.&lt;/p&gt;
&lt;p&gt;If you now go and check in Kleopatra or type &lt;code&gt;gpg --list-keys&lt;/code&gt; in the commandline you will see your key has been assigned ultimate trust.&lt;/p&gt;
&lt;h3 id=&quot;final-checks&quot; tabindex=&quot;-1&quot;&gt;Final checks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#final-checks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You should now be in a position where SSH works within windows.&lt;/p&gt;
&lt;p&gt;Before we proceed, it would make sense to check you can actually use SSH within windows with your yubikey. Either use PuTTY to SSH into a server, or try to sign a git commit etc., and you should see that it is fully functional.&lt;/p&gt;
&lt;p&gt;If this is not the case, then something is amiss, and there is no point proceeding to the next stage as it will not work.&lt;/p&gt;
&lt;p&gt;One thing you can try is running in powershell the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;gpgconf &lt;span class=&quot;token parameter variable&quot;&gt;--kill&lt;/span&gt; gpg-agent
gpg-connect-agent /bye&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should restart gpg-agent so you can give it another shot.&lt;/p&gt;
&lt;h2 id=&quot;wsl2-setup&quot; tabindex=&quot;-1&quot;&gt;WSL2 Setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#wsl2-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;install-wsl2-(ubuntu)&quot; tabindex=&quot;-1&quot;&gt;Install WSL2 (Ubuntu) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#install-wsl2-(ubuntu)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firstly, install WSL2, which is as easy as running the following command in a powershell prompt with &lt;strong&gt;administrator&lt;/strong&gt; privileges:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;wsl &lt;span class=&quot;token parameter variable&quot;&gt;--install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will take you through the various install steps, restarts etc. It is very straight forward. You can install other distributions than Ubuntu, but by default Ubuntu is installed.&lt;/p&gt;
&lt;p&gt;After the install you can search for Ubuntu in Windows search, and it will open for you.&lt;/p&gt;
&lt;p&gt;If you ever need to properly close a WSL instance, type the following command into the terminal:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;wsl.exe &lt;span class=&quot;token parameter variable&quot;&gt;--shutdown&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just closing the window will not do this.&lt;/p&gt;
&lt;h3 id=&quot;initial-steps&quot; tabindex=&quot;-1&quot;&gt;Initial steps &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#initial-steps&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Make sure you are up to date:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the following commands (change the wsl2-ssh-pageant version number in the download link as appropriate):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; socat
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; ~/.ssh
&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; https://github.com/BlackReloaded/wsl2-ssh-pageant/releases/download/v1.4.0/wsl2-ssh-pageant.exe &lt;span class=&quot;token parameter variable&quot;&gt;-O&lt;/span&gt; ~/.ssh/wsl2-ssh-pageant.exe
&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x ~/.ssh/wsl2-ssh-pageant.exe&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;edit-bash-rc&quot; tabindex=&quot;-1&quot;&gt;Edit bash-rc &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#edit-bash-rc&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Append the following to your &lt;code&gt;~/.bashrc&lt;/code&gt; file (use nano, vim etc.):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# SSH Socket&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Removing Linux SSH socket and replacing it by link to wsl2-ssh-pageant socket&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;&lt;span class=&quot;token environment constant&quot;&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/.ssh/agent.sock&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; ss &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$SSH_AUTH_SOCK&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$SSH_AUTH_SOCK&lt;/span&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;wsl2_ssh_pageant_bin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/.ssh/wsl2-ssh-pageant.exe&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;setsid &lt;span class=&quot;token function&quot;&gt;nohup&lt;/span&gt; socat UNIX-LISTEN:&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$SSH_AUTH_SOCK&lt;/span&gt;,fork&quot;&lt;/span&gt; EXEC:&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;/dev/null &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;&amp;amp;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;&amp;amp;2&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WARNING: &lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt; is not executable.&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;unset&lt;/span&gt; wsl2_ssh_pageant_bin
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# GPG Socket&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Removing Linux GPG Agent socket and replacing it by link to wsl2-ssh-pageant GPG socket&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# NOTE: the &quot;config_path&quot; and &quot;-gpgConfigBasepath ${config_path}&quot; are generally needed for&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# gpg4win 4.0 and later &lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;GPG_AGENT_SOCK&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/.gnupg/S.gpg-agent&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; ss &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-q&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$GPG_AGENT_SOCK&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$GPG_AGENT_SOCK&lt;/span&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;wsl2_ssh_pageant_bin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/.ssh/wsl2-ssh-pageant.exe&quot;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;config_path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;C&#92;:/Users/&amp;lt;username&gt;/AppData/Local/gnupg&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# replace &amp;lt;username&gt; with your own username&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;setsid &lt;span class=&quot;token function&quot;&gt;nohup&lt;/span&gt; socat UNIX-LISTEN:&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$GPG_AGENT_SOCK&lt;/span&gt;,fork&quot;&lt;/span&gt; EXEC:&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt; -gpgConfigBasepath &lt;span class=&quot;token variable&quot;&gt;${config_path}&lt;/span&gt; --gpg S.gpg-agent&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;/dev/null &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;&amp;amp;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;&amp;amp;2&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WARNING: &lt;span class=&quot;token variable&quot;&gt;$wsl2_ssh_pageant_bin&lt;/span&gt; is not executable.&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;unset&lt;/span&gt; wsl2_ssh_pageant_bin
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now restart WSL2:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;wsl.exe &lt;span class=&quot;token parameter variable&quot;&gt;--shutdown&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now have access to your Yubikey in WSL2:&lt;/p&gt;
&lt;p&gt;Try &lt;code&gt;gpg --card-status&lt;/code&gt; in WSL2 and you should get info about your yubikey. If not something is wrong. Try going through the steps again.&lt;/p&gt;
&lt;p&gt;It should also be possible to use SSH. For example &lt;code&gt;ssh-add -L&lt;/code&gt; should return a key.&lt;/p&gt;
&lt;h3 id=&quot;change-key-trustworthiness-to-ultimate&quot; tabindex=&quot;-1&quot;&gt;Change key trustworthiness to ultimate &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#change-key-trustworthiness-to-ultimate&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the same thing we did previously in windows, except we will do it on the commandline (obviously use your own key):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ gpg --edit-key 1CA87B39873495770098080098336BC4E5C445AB
gpg&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; trust
Please decide how far you trust this user to correctly verify other &lt;span class=&quot;token function&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39; keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don&#39;&lt;/span&gt;t know or won&#39;t say
  &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; I &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; NOT trust
  &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; I trust marginally
  &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; I trust fully
  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; I trust ultimately
  m &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; back to the main menu

Your decision? &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
Do you really want to &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; this key to ultimate trust? &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;y/N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; y
gpg&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; quit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you now run &lt;code&gt;gpg --list-keys&lt;/code&gt; the keys should have ultimate trust.&lt;/p&gt;
&lt;h3 id=&quot;done!&quot; tabindex=&quot;-1&quot;&gt;Done! &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#done!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;That should be it. You should be able to SSH into a server or use git commits etc.&lt;/p&gt;
&lt;h2 id=&quot;visual-studio-code&quot; tabindex=&quot;-1&quot;&gt;Visual Studio Code &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#visual-studio-code&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the things you may want to do is use a text editor/IDE rather than using VIM or Nano on the commandline. This is certainly preferable if you are a software developer and need to edit lots of text files.&lt;/p&gt;
&lt;p&gt;Fortunately, you can easily use a program such as VS Code for this.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-vs-code-in-wsl2&quot; tabindex=&quot;-1&quot;&gt;How to use VS Code in WSL2 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#how-to-use-vs-code-in-wsl2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You do not need to install VS Code within the WSL2 Ubuntu install. You only need VS Code installed in windows as normal.&lt;/p&gt;
&lt;p&gt;On the commandline in WSL2 just type the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;code &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dot is quite important so don&#39;t forget that!&lt;/p&gt;
&lt;p&gt;It will then open a VS Code instance with the path of where you are in the terminal, so maybe &amp;quot;cd&amp;quot; to your project root path first before running it.&lt;/p&gt;
&lt;p&gt;It is quite well intergrated so if for example you are running a python virtual environment, it will pick this up and allow you to select the virtual environment that exists within Ubuntu. This greatly helps with general work, and debugging.&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/wsl2-yubikey/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The main place that the info in this article comes from is here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jardazivny.medium.com/the-ultimate-guide-to-yubikey-on-wsl2-part-1-dce2ff8d7e45&quot;&gt;Jaroslav Živný&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also refer to the information provided by the wsl2-ssh-pageant tools author on github:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/BlackReloaded/wsl2-ssh-pageant&quot;&gt;wsl2-ssh-pageant&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>The Power of the Continuous Wavelet Transform (CWT) in Machine Learning</title>
		<link href="https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/"/>
		<updated>Fri, 01 Jul 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;The purpose of this article is to look into whether the use of the Continuous Wavelet Transform (CWT) is beneficial as a preprocessing technique before utilising a neural network to predict a human gesture classification problem.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There will be no heavy mathematics, with the focus being on the implementation, and results. Where necessary some explanation will be provided as to why certain parameters are used.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-use-the-cwt%3F&quot; tabindex=&quot;-1&quot;&gt;Why use the CWT? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#why-use-the-cwt%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the main challenges with machine learning is feeding in data that is going to be easy for the model to interpret and learn from, without losing any important information from the original data. If you can achieve this, it allows for simpler lightweight models, and reduces the chances of, for example, over-fitting to noise or other anomalies in your raw data.&lt;/p&gt;
&lt;p&gt;The CWT can potentially help you achieve this.&lt;/p&gt;
&lt;h3 id=&quot;the-basics&quot; tabindex=&quot;-1&quot;&gt;The basics &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-basics&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The CWT is a signal processing technique similar to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fourier_transform&quot;&gt;Fourier Transform&lt;/a&gt;, in that it lets you extract and separate out frequency information from a timeseries. Where it differs from the Fourier Transform is that it can also retain the time domain information as well (i.e. it can display the frequency data and where it occurred along the timeseries).&lt;/p&gt;
&lt;p&gt;The output for a single 2D input time series (x: time, y: amplitude) is therefore a 3D output matrix (x: time, y: frequency, z: amplitude). This means the output of a CWT can be rendered as a pictogram (i.e. visualised in a 2D image rather than a line).&lt;/p&gt;
&lt;h3 id=&quot;where-is-the-advantage%3F&quot; tabindex=&quot;-1&quot;&gt;Where is the advantage? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#where-is-the-advantage%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have turned the original signal into a picture, which is great for humans, as it is more interpretable for us. However, we are going to feed this into a neural network, so if it contains the same information as the original signal why bother?&lt;/p&gt;
&lt;p&gt;Turns out you have a few dials to play with when tuning the transform that will differentiate your CWT output from the original signal.&lt;/p&gt;
&lt;h4 id=&quot;choosing-your-wavelet&quot; tabindex=&quot;-1&quot;&gt;Choosing your wavelet &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#choosing-your-wavelet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There are predefined &lt;a href=&quot;https://pywavelets.readthedocs.io/en/latest/ref/cwt.html#continuous-wavelet-families&quot;&gt;wavelets&lt;/a&gt; that you can use against the signal. Each wavelet is different in terms of shape and characteristics, you should pick a wavelet shape that fits well with the characteristics of the signal you are trying to process. I won&#39;t go further into this selection process here, but if unsure the Morlet wavelet is a good starting point, and what we will use throughout this article.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/morlet-wavelet.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/morlet-wavelet.jpg&quot; alt=&quot;Morlet wavelet&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;The morlet wavelet&lt;/figcaption&gt;
&lt;p&gt;The wavelet is basically convolved (multiplied) with the time series at each timestep, moving across the signal. This is done at varying &#39;scales&#39;, so scale 1 will be for high frequencies (i.e. the wavelet is narrow and picks up higher frequencies in the signal). As you increase the scale the wavelet is stretched horizontally, and therefore a better match to lower frequencies. This process is repeated for a variety of scales which allows the extraction of frequency information from the signal.&lt;/p&gt;
&lt;h4 id=&quot;setting-the-scale&quot; tabindex=&quot;-1&quot;&gt;Setting the scale &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#setting-the-scale&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;As mentioned in the previous section you can stretch the signal using a parameter called &#39;scale&#39;. This is equivalent of targeting specific frequencies within the signal.&lt;/p&gt;
&lt;p&gt;You can literally specify a range of scales to be processed, so this gives you the flexibility to, for example, filter out high frequency noise from the signal. Or very specifically target a certain frequency range.&lt;/p&gt;
&lt;h4 id=&quot;use-as-an-exploratory-tool&quot; tabindex=&quot;-1&quot;&gt;Use as an exploratory tool &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#use-as-an-exploratory-tool&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;As mentioned earlier you can make visualisations from the CWT, so one approach might be to visually review a random selection of data to help determine where the most appropriate &#39;scale&#39; range is, and fine tune the scale to that range before passing to the neural network.&lt;/p&gt;
&lt;h4 id=&quot;complex-wavelets&quot; tabindex=&quot;-1&quot;&gt;Complex wavelets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#complex-wavelets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Some of the wavelet transforms are complex (i.e. the wavelets extend into the complex domain). Ultimately, this means that you can extract phase information from a signal, if this is of use for your analysis. However, it is worth noting that this is an additional layer of information that may be useful for a neural network. We will utilise complex wavelets (in a very superficial way) in this article.&lt;/p&gt;
&lt;h2 id=&quot;why-not-use-the-discrete-wavelet-transform-(dwt)%3F&quot; tabindex=&quot;-1&quot;&gt;Why not use the Discrete Wavelet Transform (DWT)? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#why-not-use-the-discrete-wavelet-transform-(dwt)%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may have heard of the Discrete Wavelet Transform (DWT), and wonder why we don&#39;t use that?&lt;/p&gt;
&lt;p&gt;The truth is they are very similar (both being wavelet transforms), however to get into the differences at any meaningful level requires a dive into mathematics, which is not what this article is for.&lt;/p&gt;
&lt;p&gt;Very simply the DWT also breaks down the signal into frequency components. However, each &#39;level&#39; of detail (like the scales in the CWT) extracted from the original time series results in a halving of the samples (i.e. the signal gets shorter). This is more efficient computationally than the CWT, but not ideal for our purposes here. You can&#39;t produce an image for example.&lt;/p&gt;
&lt;p&gt;What the DWT is very useful for is filtering. As an example, if you want to filter noise from your signal the DWT is an excellent choice, but that is beyond the remit of this article.&lt;/p&gt;
&lt;h2 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Direct quote from the data source:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Eight different users performed twenty repetitions of twenty different gestures, for a total of 3200 sequences. Each sequence contains acceleration data from the 3-axis accelerometer of a first generation Sony SmartWatch™, as well as timestamps from the different clock sources available on an Android device. The smartwatch was worn on the user&#39;s right wrist. The gestures have been manually segmented by the users performing them by tapping the smartwatch screen at the beginning and at the end of every repetition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An example of each of the movements performed by the participants and their associated labels can be seen in the image below:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/movements-labels.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/movements-labels.jpg&quot; alt=&quot;Movements and associated labels&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;The movements performed with the watch and associated labels&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://tev.fbk.eu/resources/smartwatch&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://drive.google.com/a/fbk.eu/file/d/1nEs-JlAQv6xpuSIqahTKK68TgK37GirP/view?usp=sharing&quot;&gt;Source dataset direct link&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-plan&quot; tabindex=&quot;-1&quot;&gt;The plan &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-plan&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the overall plan of how the data will be prepared and compared.&lt;/p&gt;
&lt;p&gt;If you wish to look in detail at the code used to produce the results that follow, please feel free to reference the jupyter notebook, which is available on my github here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/thetestspecimen/continuous-wavelets-cnn&quot;&gt;Jupyter Notebook&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-split&quot; tabindex=&quot;-1&quot;&gt;Data split &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#data-split&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Initially, I will use 7 out of the 8 people as training and validation, and the 8th person as a holdout test set.&lt;/p&gt;
&lt;p&gt;The 7 people will be completely randomised and then split 85%-15% (train-validation). The final outcome of the models being judged on the holdout test &#39;person&#39;.&lt;/p&gt;
&lt;p&gt;This should result in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;training timeseries --&amp;gt; 2380 sequences&lt;/li&gt;
&lt;li&gt;validation timeseries --&amp;gt; 420 sequences&lt;/li&gt;
&lt;li&gt;testing timeseries --&amp;gt; 400 sequences&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total timeseries: 3200&lt;/p&gt;
&lt;h3 id=&quot;models&quot; tabindex=&quot;-1&quot;&gt;Models &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#models&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The models that will be created are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Model 1 - A CNN model (Conv1D) used as a baseline on the raw timeseries data - &lt;strong&gt;this is the benchmark&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Model 2 - A CNN model (Conv2D) utilising a CWT on the timeseries before input into the model&lt;/li&gt;
&lt;li&gt;Model 3 - A CNN model (Conv2D) utilising a complex CWT on the timeseries before input into the model&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All the above models will use the same parameters and number/type of layers to keep them as comparable as possible.&lt;/p&gt;
&lt;h3 id=&quot;comparison&quot; tabindex=&quot;-1&quot;&gt;Comparison &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#comparison&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;stage-1&quot; tabindex=&quot;-1&quot;&gt;Stage 1 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#stage-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A single run of the model to get an idea of accuracy and see where the model is failing (or succeeding) to generalise.&lt;/p&gt;
&lt;p&gt;(Users 1 to 7 as train/validation, User 8 as holdout test).&lt;/p&gt;
&lt;h4 id=&quot;stage-2&quot; tabindex=&quot;-1&quot;&gt;Stage 2 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#stage-2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Ten repeat runs to get a more accurate average accuracy, which removes any variation due to numerical randomness / initialisation parameters.&lt;/p&gt;
&lt;p&gt;(Users 1 to 7 as train/validation, User 8 as holdout test).&lt;/p&gt;
&lt;h4 id=&quot;stage-3&quot; tabindex=&quot;-1&quot;&gt;Stage 3 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#stage-3&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For Model 1 and either Model 2 or 3 (depending which performs best), a cross validation of users will be performed.&lt;/p&gt;
&lt;p&gt;Essentially, each individial user (1 to 8) will be used as the hold out test set in a completely independent set of tests. Each set of tests will be repeated 10 times (like Stage 2) to get an average accuracy.&lt;/p&gt;
&lt;p&gt;This will give a good indication as to how the models perform for each individual, ultimately giving a better indication as to how the model will likely perform with a completely new user in the future.&lt;/p&gt;
&lt;h1 id=&quot;preprocessing-the-data&quot; tabindex=&quot;-1&quot;&gt;Preprocessing the data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#preprocessing-the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h3 id=&quot;exploration&quot; tabindex=&quot;-1&quot;&gt;Exploration &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#exploration&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In an initial exploration of the data the following points were discovered:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the data is sampled at around 9Hz (0.11s per sample)&lt;/li&gt;
&lt;li&gt;the timeseries samples are all of different lengths (longest 51 sample (5.61s), average of 20 samples (2.2s))&lt;/li&gt;
&lt;li&gt;the total amount of timeseries is not 3200 it is actually 3251, with some users having more samples than others (although still a very even split, not highly skewed to one user or another)&lt;/li&gt;
&lt;li&gt;the accelerometer data is close to normally distributed for the purposes of scaling&lt;/li&gt;
&lt;li&gt;accelerometer in the z direction looks to have a more significant mean offset from zero than the other two components (possibly gravity?)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/comparison-of-movements.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/comparison-of-movements.jpg&quot; alt=&quot;Example plots for each movement&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;An example of all the movements performed by User 1&lt;/figcaption&gt;
&lt;h3 id=&quot;preprocessing&quot; tabindex=&quot;-1&quot;&gt;Preprocessing &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#preprocessing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the initial problems with the dataset is that the timeseries are all of different lengths. This means we need to pad the sequences to length of the longest sequence (assuming we don&#39;t want to truncate the data).&lt;/p&gt;
&lt;p&gt;We will take two different approaches here. The first will be for the raw timeseries data and the second for the data intended for the CWT.&lt;/p&gt;
&lt;p&gt;As the data crosses zero we will use a large padding value (-9999.0) on the timeseries input data, and then use a masking layer to mask these values in the model. As the CWT is a pre-processor before the model, we cannot feed exaggerated padding values like this into the CWT, as it will heavily skew the data. A zero pad will therefore be used on the data that will be fed into the CWT.&lt;/p&gt;
&lt;p&gt;To ensure that the zero pad will not skew the data too much SciKitLearn&#39;s StandardScaler will be used to scale the data to zero mean and unit variance before applying the pad (we have already confirmed the data is relatively normally distributed so this should be appropriate). For consistency, and the benefits scaling generally provides for neural networks anyway, this scaling will also be applied to the raw time series data used in the reference model (Model 1).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/standardscaler.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/standardscaler.jpg&quot; alt=&quot;Timeseries data after passing though StandardScaler&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;An example of data after passing through StandardScaler (before padding)&lt;/figcaption&gt;
&lt;p&gt;All models will also include a scaling layer to scale the input data between the values of 1 and -1 before hitting the neural network.  The scaling value used will be based on the highest absolute value across all accelerometers after standard scaling (rather than each individually) to retain relative magnitude between the sensors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the data used to fit StandardScaler consisted of the whole dataset. Only the training dataset should really be used for this otherwise you leak information about the validation and test sets, which are meant to be independent. In this particular case it is not a big deal, as we are just exploring, but if you have to present reliable bulletproof figures, please do not do this.&lt;/p&gt;
&lt;h2 id=&quot;picking-scales-for-the-cwt&quot; tabindex=&quot;-1&quot;&gt;Picking scales for the CWT &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#picking-scales-for-the-cwt&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the items that first needs to be considered before jumping into preprocessing the data with a CWT is what scales you wish to compute the continuous wavelet transform over, as this will decide how well the signal is represented in the output.&lt;/p&gt;
&lt;p&gt;The scales are arbitrary, but a sensible selection can be made by translating the scales into associated frequencies. Scales can be &#39;translated&#39; into frequencies if the sample rate of the data is known. Basically, a small scale (1 for example) is related to a higher frequency, and a larger scale to a lower frequency. This is basically due to the increase in scale &#39;stretching&#39; the wavelet, and hence being a better match to &#39;longer&#39; signals (i.e. lower frequencies).&lt;/p&gt;
&lt;p&gt;In our case the sample rate of the data is approximately 9Hz (0.11 seconds, sample to sample). This is not a particularly high sample rate, so we need to retain as much of the data as possible.&lt;/p&gt;
&lt;p&gt;Unfortunately, the CWT is subject to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Nyquist_frequency&quot;&gt;Nyquist frequency&lt;/a&gt;, so in theory any frequency above 4.5Hz will experience aliasing, which is not ideal as it will polute the signal.&lt;/p&gt;
&lt;p&gt;At the other end of the scale:&lt;/p&gt;
&lt;p&gt;Our longest signal is 51 timesteps long which is 5.61s (which is about 0.18Hz). The average signal is 20 timesteps long which is 2.20s (which is about 0.45Hz)&lt;/p&gt;
&lt;p&gt;This gives a good starting point for picking our scales. To keep the output small, as we are not using particularly deep neural networks, we will limit the lower frequency to about half the maximum, so ~0.36Hz and try to get as close to 4.5Hz as we can. This should give us a nice range to work with.&lt;/p&gt;
&lt;p&gt;Here is the code which shows the result of the above. The output is an array of frequencies hitting the range we discussed above:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Standard Morlet Wavelet frequencies at double the sampling frequency&lt;/span&gt;
dt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.11&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# ~9 Hz sampling&lt;/span&gt;
input_scales &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;arange&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;float32&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
input_scales &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input_scales&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
frequencies &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pywt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;scale2frequency&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;morl&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input_scales&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; dt
frequencies

array&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4.5038805&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.6931818&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.4621212&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.8465909&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.4772726&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;1.2310606&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0551947&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.92329544&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.8207071&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.7386363&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.67148757&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6155303&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5681818&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.52759737&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.49242425&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.46164772&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.434492&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.41035354&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.38875598&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.36931816&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.35173163&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Complex Morlet Wavelet frequencies at double the sampling frequency&lt;/span&gt;
input_scales_comp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;arange&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;27&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;float32&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
frequencies &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pywt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;scale2frequency&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cmor1.5-1.0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input_scales_comp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; dt
frequencies

array&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4.5454545&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.0303032&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.2727273&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.8181819&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.5151516&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;1.2987014&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.1363636&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0101011&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.90909094&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.8264463&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.7575758&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6993007&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6493507&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6060606&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5681818&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.53475934&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.50505054&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.4784689&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.45454547&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.43290043&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token number&quot;&gt;0.41322315&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.39525694&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.3787879&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.36363634&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.34965035&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So from the above we can see that the appropriate scales to hit our intended frequency ranges for the data will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Morlet: 1.64 to 21&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complex morlet: 2 to 26&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/complex-graphs.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/complex-graphs.jpg&quot; alt=&quot;Example complex wavelet graphs&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Example complex wavelet graph outputs&lt;/figcaption&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In the example above there are six graphs as the complex wavelet has both imaginary and real parts. The normal CWT will produce only three graphs, as there are no imaginary parts.&lt;/p&gt;
&lt;h3 id=&quot;what-do-the-graphs-show%3F&quot; tabindex=&quot;-1&quot;&gt;What do the graphs show? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#what-do-the-graphs-show%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The graphs above are printed in grey and red fading to white at the centre value (roughly zero in this case). I have left a scale bar off as it is mostly irrelevant due to the data being scaled. So when you see dark red or dark grey, those are high energy areas (peaks or troughs). This is where most of the information resides in our signal.&lt;/p&gt;
&lt;p&gt;You can immediately see both in terms of time and scale (or frequency) where in the signal has the most information. This could help you further tune the scales to focus on a particular area of interest, should you want to experiment further.&lt;/p&gt;
&lt;h2 id=&quot;the-models&quot; tabindex=&quot;-1&quot;&gt;The models &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-models&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The models were constructed to be as close as possible, and simple. I have included dropout and pooling layers in the model to reduce overfitting since the data is limited and not particularly complicated.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Model 1 - for raw timeseries data&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; model_number &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                        Input&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shape&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;input_shape&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Masking&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mask_value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;9999.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Rescaling&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scaling_value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;valid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               kernel_initializer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;glorot_uniform&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Dropout&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;valid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               kernel_initializer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;glorot_uniform&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                               activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Dropout&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;softmax&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Conv1D_Model_1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Model 2 - for CWT images &lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# (Model 3 (for the complex CWT) is the same as this, but has been cut for brevity)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;elif&lt;/span&gt; model_number &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                    Input&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shape&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;input_shape&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Rescaling&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scaling_value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;valid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           kernel_initializer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;glorot_uniform&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    MaxPooling2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Dropout&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;valid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           kernel_initializer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;glorot_uniform&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    MaxPooling2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Dropout&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;softmax&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;CWT_Model_2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The models are all compiled with the Adam optimiser and run for 50 epochs each. At the end of the 50 epochs the best weights are restored based on val_loss.&lt;/p&gt;
&lt;p&gt;Learning rates were tuned once for each model prior to the main runs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Model 1 - 0.005&lt;/li&gt;
&lt;li&gt;Model 2 - 0.001&lt;/li&gt;
&lt;li&gt;Model 3 - 0.001&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the main runs a scheduler also halved the learning rate every 20 epochs to help the model converge.&lt;/p&gt;
&lt;h2 id=&quot;the-results&quot; tabindex=&quot;-1&quot;&gt;The results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All models managed an accuracy and val_accuracy of 99%. Game over? Not really...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/accuracy-curve.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/accuracy-curve.jpg&quot; alt=&quot;Model 2 accuracy curve&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Model 2 - Accuracy training curve&lt;/figcaption&gt;
&lt;p&gt;What that means is that our models have all learnt really well (or over-fit). Remember, our test and validation set is a random mixture of 7 users, but the hold out test set is a completely different person that doesn&#39;t exist at all in training or validation sets. So for the trained models on the initial run on the holdout test set (User 8):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Model&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Accuracy&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;F1-Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1 (Raw time-series)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.88&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.88&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2 (CWT)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.93&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3 (Complex CWT)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.96&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.96&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For an initial run that result looks pretty impressive! We still need to repeat the runs 10 times like we said at the start to remove any initialisation randomness and see how stable the outputs are, but it is looking promising.&lt;/p&gt;
&lt;p&gt;What might be interesting is to see where the models are making mistakes...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/movements-labels.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/movements-labels.jpg&quot; alt=&quot;Movements and associated labels&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;The movements performed with the watch and associated labels&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/model1-confusion-2.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/model1-confusion-2.jpg&quot; alt=&quot;Model 1 confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Model 1 - Confusion Matrix&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/model2-confusion.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/model2-confusion.jpg&quot; alt=&quot;Model 2 confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Model 2 - Confusion Matrix&lt;/figcaption&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/model3-confusion.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/model3-confusion.jpg&quot; alt=&quot;Model 3 confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Model 3 - Confusion Matrix&lt;/figcaption&gt;
&lt;p&gt;As you can see by comparing the movements to Model 1 and 3, the movements that the models get wrong make a lot of sense (i.e. they are similar movements). The worst mismatched predicted labels are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Model 1 - 16 confused with 12&lt;/li&gt;
&lt;li&gt;Model 2 - 16 confused with 12&lt;/li&gt;
&lt;li&gt;Model 3 - 20 confused with 19&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interestingly, although Model 3 on the whole does a better job, Model 1 manages to almost perfectly classify label 20 whereas Model 3 struggles with this particular label. It shows that the information is there, but Model 3 fails to capture it, or it has been removed by the transform. To further solidify this point, Model 2 also performs well for label 20, so the CWT is capable of capturing the correct information, but some fine tuning of scales is probably required.&lt;/p&gt;
&lt;h3 id=&quot;solidifying-the-numbers&quot; tabindex=&quot;-1&quot;&gt;Solidifying the numbers &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#solidifying-the-numbers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get a more solid grasp on the how the models perform the tests were repeated 10 times and the result averaged:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Model&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Accuracy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1 (Raw timeseries)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.859&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2 (CWT)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.945&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3 (Complex CWT)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.952&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A box plot as another visual aid as to the results distribution:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/accuracy-boxplot.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/accuracy-boxplot.jpg&quot; alt=&quot;Results boxplot&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Boxplot of the results distribution&lt;/figcaption&gt;
&lt;p&gt;The result of this is that there is a fairly significant advantage to using a CWT on this data (at least under the parameters used in this article). It is also noted that, although the difference is small, it may be beneficial to consider a complex wavelet transform to try and extract as much data as possible out of the time series before processing.&lt;/p&gt;
&lt;h2 id=&quot;the-definitive-check---cross-validation&quot; tabindex=&quot;-1&quot;&gt;The definitive check - cross validation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#the-definitive-check---cross-validation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the previous sections we have explored the benefit of using the continuous wavelet transform in a neural network. So far the hold out test set has been user 8. However, we have no idea whether this user is a good representation of the general population, or a fairly unique individual.&lt;/p&gt;
&lt;p&gt;A cross validation across all users will therefore be run (i.e. each user will be the hold out test set for it&#39;s own set of train/val/test runs). This should give a much more reliable indication of the performance that has been achieved, especially considering the small size of the dataset.&lt;/p&gt;
&lt;p&gt;To avoid any bias due to randomness, we will also repeat each test 10 times and take an average, as we have done previously.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/mean-stdev-final-result.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/mean-stdev-final-result.jpg&quot; alt=&quot;Cross validation results&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Mean and standard deviation cross-validation results&lt;/figcaption&gt;
&lt;p&gt;It seems the hold out user really does matter! Although there are a wide variation of results, depending on the user, almost across the board the CWT transform outperforms the normal time series model (from 2% to 15% improvement). The exception, as you can see, is User 4, where the CWT is beaten on average by the normal model. Although it should be noted that there is only a 2% difference, and Model 3 managed a quite respectful 92% accuracy in this case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the standard deviation graph presented is calculated across the 10 repeat runs for each user, and represents how consistent the model is across the 10 repeat runs.&lt;/p&gt;
&lt;p&gt;Further to the above, it should be noted that the validation results across all tests and all users was very high (97%+).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/cwt/mean-stdev-final-result-val.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/cwt/mean-stdev-final-result-val.jpg&quot; alt=&quot;Cross validation results - validation set&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Mean and standard deviation cross-validation results (validation)&lt;/figcaption&gt;
&lt;p&gt;This indicates that although the models were able to learn the data provided to them equally well, the CWT model was able to both, pick out more relevant features, and generalise better than than the normal time series model.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this particular case I think we can conclude that the CWT should definitely be considered as a tool in the arsenal of machine learning practitioners. It will not be suitable for every case, perhaps because of the additional overhead of processing that is required. However, it is a flexible tool that can be moulded to suit your specific data, and potentially improve model bias and accuracy.&lt;/p&gt;
&lt;p&gt;This article has only really touched the surface, as no in depth tuning of parameters has been performed. Items like the complex parameters of the complex Morlet wavelet were fixed throughout this experiment, and plenty of experimentation of a suitable range of scales could be conducted, so there is plenty of scope for further investigation in to the CWTs use in machine learning.&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/continuous-wavelet-transform-cnn/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From the authors of the dataset:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;G. Costante, L. Porzi, O. Lanz, P. Valigi, E. Ricci, &lt;a href=&quot;http://www.google.com/url?q=http%3A%2F%2Fwww.eurasip.org%2FProceedings%2FEusipco%2FEusipco2014%2FHTML%2Fpapers%2F1569922319.pdf&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AOvVaw3o-AErJ6J6zO4hNidkW5uD&quot;&gt;Personalizing a Smartwatch-based Gesture Interface With Transfer Learning&lt;/a&gt;, 22nd European Signal Processing Conference, EUSIPCO 2014&lt;/li&gt;
&lt;li&gt;L. Porzi and S. Messelodi and C.M. Modena and E. Ricci: &lt;a href=&quot;https://www.google.com/url?q=https%3A%2F%2Fdoi.org%2F10.1145%2F2505483.2505487&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AOvVaw3mWoxp7VFIMYX372aR2Yl9&quot;&gt;A Smart Watch-based Gesture Recognition System for Assisting People with Visual Impairments&lt;/a&gt;. ACM International Workshop on Interactive Multimedia on Mobile and Portable Devices  - IMMPD, Barcelona, Spain, 2013&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other references and articles of interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://pywavelets.readthedocs.io/&quot;&gt;Pywavelets python library&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6048575/&quot;&gt;Introduction to redundancy rules: the continuous wavelet transform comes of age&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ataspinar.com/2018/12/21/a-guide-for-using-the-wavelet-transform-in-machine-learning/&quot;&gt;A guide for using the Wavelet Transform in Machine Learning&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://towardsdatascience.com/multiple-time-series-classification-by-using-continuous-wavelet-transformation-d29df97c0442&quot;&gt;Multiple Time Series Classification by Using Continuous Wavelet Transformation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

		</content>
	</entry>
	
	<entry>
		<title>How I Passed the TensorFlow Developer Certificate Exam</title>
		<link href="https://www.thetestspecimen.com/posts/tensorflow-certificate/"/>
		<updated>Fri, 05 Aug 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/tensorflow-certificate/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Having been through the process of preparing for, and passing, the TensorFlow Developer Certificate exam, I thought it might be useful to give other people an overview of what to expect, the best resources to use to prepare, what to watch out for in the exam, and advice on whether it would be useful for you in particular.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note: this article will NOT reveal any questions / answers on the actual exam. Although this might disappoint some people, it is very important to uphold the integrity of the exam. This is to ensure that when you finally get your certificate, it has value.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;what-is-the-tensorflow-developer-certificate%3F&quot; tabindex=&quot;-1&quot;&gt;What is the TensorFlow Developer Certificate? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#what-is-the-tensorflow-developer-certificate%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.tensorflow.org/certificate&quot;&gt;TensorFlow certificate website&lt;/a&gt; describes this quite succinctly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This certificate in TensorFlow development is intended as a foundational certificate for students, developers, and data scientists who want to demonstrate practical machine learning skills through the building and training of models using TensorFlow.&lt;/p&gt;
&lt;p&gt;The program consists of an assessment exam developed by the TensorFlow team. Developers who pass the exam can join our &lt;a href=&quot;https://www.tensorflow.org/certificate-network&quot;&gt;Certificate Network&lt;/a&gt; and display their certificate and badges on their resume, GitHub, and social media platforms including LinkedIn, making it easy to share their level of TensorFlow expertise with the world.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...so it is a &lt;strong&gt;practical&lt;/strong&gt; exam that requires you to build actual TensorFlow models to predict outcomes (categorical and regression).&lt;/p&gt;
&lt;h1 id=&quot;frame-of-reference-for-my-advice&quot; tabindex=&quot;-1&quot;&gt;Frame of reference for my advice &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#frame-of-reference-for-my-advice&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now you know &lt;em&gt;what&lt;/em&gt; the certificate is, I think it is important to understand a little about my background and experience before I continue. This may help some people formulate a plan of attack for their preparation, and also judge how relevant my advice is to them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On a day to day basis I am a &#39;traditional&#39; engineer (i.e. Mechanical Engineer, Civil Engineer etc.), not a software developer or data scientist / data analyst.&lt;/li&gt;
&lt;li&gt;I have experience with software development, and data analysis within my day to day work roles (a lot of traditional engineering work is data analysis of some sort).&lt;/li&gt;
&lt;li&gt;I have made a concerted effort over the past 5 to 6 years to expand and improve upon my software development / data analysis skill set. This is both due to it being beneficial to my work, and also out of interest in the subject in general.&lt;/li&gt;
&lt;li&gt;Although I have a Masters degree, it is not in the software development domain (Aeronautical Engineering).&lt;/li&gt;
&lt;li&gt;I spend a reasonable amount of my spare time working on various software / analytics projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above should give you a good gauge as to where your level of experience might fit compared to me, and allow you to take the advice that follows as such.&lt;/p&gt;
&lt;h1 id=&quot;is-it-worth-doing%3F&quot; tabindex=&quot;-1&quot;&gt;Is it worth doing? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#is-it-worth-doing%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This is a very valid question, and one I want to cover before I explain what resources I recommend etc.&lt;/p&gt;
&lt;h2 id=&quot;cost&quot; tabindex=&quot;-1&quot;&gt;Cost &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#cost&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It costs &lt;strong&gt;$100&lt;/strong&gt; to do the certificate. That might be fine for some people, but I can see this being a significant hurdle for some.&lt;/p&gt;
&lt;p&gt;Fortunately, there is a &lt;a href=&quot;https://www.tensorflow.org/static/extras/cert/TF_Education_Stipend.pdf&quot;&gt;stipend program&lt;/a&gt; if you meet the criteria, so this could be help to reduce this cost in some cases.&lt;/p&gt;
&lt;h2 id=&quot;job-prospects&quot; tabindex=&quot;-1&quot;&gt;Job prospects &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#job-prospects&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the cost doesn&#39;t put you off, then the main question is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Will this certificate improve my job prospects?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my opinion, this all depends on your current status. If you have a CS degree and are currently employed as a data scientist with years of experience, then this is going to add little value to your CV. However, as you peel away the skills, the further up the pecking order this certificate will go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a CS degree but no data science experience?&lt;/li&gt;
&lt;li&gt;Have no CS degree, and some data analyst experience?&lt;/li&gt;
&lt;li&gt;Have none of the above?&lt;/li&gt;
&lt;li&gt;Straight out of university?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all of the above situations (and many variations inbetween) it is clear to see that some value can be added by this certificate. It is a proof of competence in a very specific skill.&lt;/p&gt;
&lt;p&gt;However, I think the most important factor to remember is &lt;em&gt;visibility&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the only thing this certificate achieves is getting your CV noticed initially, it is worth it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When applying for jobs, the person that initially scans your CV (and they do just scan them) may be checking against key criteria, and if one of those is TensorFlow then you have a clear defining proof of competence. If the only thing this certificate achieves is getting your CV noticed initially, it is worth it. This could even apply to very experienced data scientists, as the person who initially scans the CVs at larger companies may not have significant domain knowledge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So is it worth it? I think in most cases, yes. If you can stomach the cost.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;is-it-difficult%2C-and-what-do-i-need-to-know%3F&quot; tabindex=&quot;-1&quot;&gt;Is it difficult, and what do I need to know? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#is-it-difficult%2C-and-what-do-i-need-to-know%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The best place to start in terms of understanding what knowledge is required for the exam is the &lt;a href=&quot;https://www.tensorflow.org/static/extras/cert/TF_Certificate_Candidate_Handbook.pdf&quot;&gt;candidate handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It details exactly which topics you will be expected to know in five major sections, and even breaks down each section into specific skills. The five sections are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TensorFlow developer skills&lt;/li&gt;
&lt;li&gt;Building and training neural network models using TensorFlow 2.x&lt;/li&gt;
&lt;li&gt;Image classification&lt;/li&gt;
&lt;li&gt;Natural language processing (NLP)&lt;/li&gt;
&lt;li&gt;Time series, sequences and predictions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you can go through this checklist and tick off most, if not all the requirements, then you should be in good stead for the exam. If not, then you need some prep work...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/study.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/study.jpg&quot; alt=&quot;Study&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@siora18?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Siora Photography&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/study?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;we will get to that shortly!&lt;/p&gt;
&lt;h2 id=&quot;difficulty&quot; tabindex=&quot;-1&quot;&gt;Difficulty &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#difficulty&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even if you have experience, or work as a data scientist, you will likely need to do &lt;strong&gt;some&lt;/strong&gt; preparation for this exam (although there are always exceptions!). If you think you can do no prep and pass this exam, I think you might be in for a shock.&lt;/p&gt;
&lt;p&gt;Is this because it is really hard? No. But it isn&#39;t a walk in the park either, you need to know more than the basics.&lt;/p&gt;
&lt;p&gt;If you work as a data scientist you will likely have a very specific skill set (object detection / classification maybe?), and this test also covers Natural Language Processing (NLP), among others, which you may be rusty on. So you may just need a refresh.&lt;/p&gt;
&lt;p&gt;To summarise, it is not something you can just jump into with zero prep. If you are relatively new to the subject you will need to study properly, and if you have experience you will &lt;em&gt;likely&lt;/em&gt; need a bit of a refresh on some areas that you may not have used in a while.&lt;/p&gt;
&lt;h1 id=&quot;how-should-i-prepare%3F&quot; tabindex=&quot;-1&quot;&gt;How should I prepare? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#how-should-i-prepare%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;essentials&quot; tabindex=&quot;-1&quot;&gt;Essentials &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#essentials&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before I get into the courses I recommend to prepare for the test, I just wanted to mention that I am assuming that you are familiar with the Python programming language. This is kind of essential. If not you should first start by learning Python.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/python.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/python.jpg&quot; alt=&quot;Python&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@davidclode?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;David Clode&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/python?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, I would also recommend that you are familiar with the following, before you attempt this certificate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Python libraries: pandas, numpy, matplotlib, scikit-learn.&lt;/li&gt;
&lt;li&gt;Some practise with machine learning algorithms - this is not essential, but gives you a solid base, and typically provides exposure to the ins and outs of libraries such as scikit-learn without the added complication of TensorFlow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;courses&quot; tabindex=&quot;-1&quot;&gt;Courses &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#courses&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are some great courses designed to help you, and it is very easy to tune based on your experience level.&lt;/p&gt;
&lt;p&gt;There are two courses I recommend, both are designed to help with this certification:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.coursera.org/professional-certificates/tensorflow-in-practice&quot;&gt;Coursera: DeepLearning.AI TensorFlow Developer Professional Certificate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.udemy.com/course/tensorflow-developer-certificate-machine-learning-zero-to-mastery/&quot;&gt;Udemy: TensorFlow Developer Certificate in 2022: Zero to Mastery&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The two courses above are very different in their method, and I would recommend the approach detailed in the following sections based on your experience.&lt;/p&gt;
&lt;h2 id=&quot;in-all-cases&quot; tabindex=&quot;-1&quot;&gt;In all cases &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#in-all-cases&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I am about to recommend which resources I think are best in relation to your skill level. However, I need to ram home one particular item first:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regardless of whether you use the courses I suggest, or books, or YouTube videos to prepare for the exam. It ESSENTIAL to practise by coding it out yourself. Just watching the videos / reading will not be enough in most cases.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;experience%3A-mid-level-to-expert&quot; tabindex=&quot;-1&quot;&gt;Experience: mid-level to expert &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#experience%3A-mid-level-to-expert&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If are reasonably familiar with TensorFlow and comfortable building, testing and debugging models, then I would recommend you go with the course from &lt;a href=&quot;https://www.coursera.org/professional-certificates/tensorflow-in-practice&quot;&gt;Coursera&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The course is listed as taking &amp;quot;Approximately 4 months to complete&amp;quot;, but this is not really true. You could easily get through the course content in a couple of days if you already have experience with the subject matter.&lt;/p&gt;
&lt;p&gt;Content is concise and to the point, with plenty of explanation of why things are done a certain way. You also have access to coded examples and walkthroughs of code.&lt;/p&gt;
&lt;p&gt;It covers all the main areas that are required for the exam.&lt;/p&gt;
&lt;p&gt;It should also be noted that this course is an officially listed course on the &lt;a href=&quot;https://www.tensorflow.org/certificate&quot;&gt;TensorFlow website&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;experience%3A-little-to-none&quot; tabindex=&quot;-1&quot;&gt;Experience: Little to none &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#experience%3A-little-to-none&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have very little experience with TensorFlow or machine/deep learning in general, I would recommend that you start with the course from &lt;a href=&quot;https://www.udemy.com/course/tensorflow-developer-certificate-machine-learning-zero-to-mastery/&quot;&gt;Udemy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While the Coursera course is concise and focused, the course from Udemy is significantly more drawn out. It will take quite a while to get through all the videos, but if you stick with it you will have a great general understanding of the subject, rather than just hyper-focused content for an exam.&lt;/p&gt;
&lt;p&gt;The course is taught in a very code-centric way, and the teacher codes throughout the videos. What is interesting is the teacher makes mistakes (most likely deliberately) as they are coding, and teaches you approaches to fix things on the fly. The mistakes are usually things that are overlooked by beginners, so it is a very useful feature of the videos.&lt;/p&gt;
&lt;p&gt;However, if you have experience you may find these videos repetitive and annoying after a while, hence why I think the Coursera course is preferable if you have a bit more experience.&lt;/p&gt;
&lt;p&gt;I should also note that the Jupyter notebooks provided for this course are extensive, and a very useful reference.&lt;/p&gt;
&lt;p&gt;Once you have finished the Udemy course, I still &lt;strong&gt;HIGHLY&lt;/strong&gt; recommend that you go through the Coursera course. It covers some content you won&#39;t see in the Udemy course, and is a great general refresher that can be completed relatively quickly.&lt;/p&gt;
&lt;h2 id=&quot;other-courses&quot; tabindex=&quot;-1&quot;&gt;Other courses &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#other-courses&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is also a course available from &lt;a href=&quot;https://www.udacity.com/course/intro-to-tensorflow-for-deep-learning--ud187&quot;&gt;Udacity&lt;/a&gt;, but I have not seen the content, so cannot comment on whether it is a good course or not. Might be worth checking out though.&lt;/p&gt;
&lt;h1 id=&quot;what-is-the-exam-like%3F&quot; tabindex=&quot;-1&quot;&gt;What is the exam like? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#what-is-the-exam-like%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The basics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it is open book, so you can use all the resources you need throughout the exam&lt;/li&gt;
&lt;li&gt;it is timed (5 hours). You can finish at any time, but the test will auto submit if 5 hours elapses.&lt;/li&gt;
&lt;li&gt;you are tested on the models. Models are uploaded by you, and a score out of 5 is returned. You can submit as many models as you want over the course of the test, but you must submit only one final model for each section.&lt;/li&gt;
&lt;li&gt;you must do the test in PyCharm IDE with a specific version of TensorFlow and Python.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/exam.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/exam.jpg&quot; alt=&quot;Exam&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@bimarahmanda?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Bima Rahmanda&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/exam?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You have to use a specific version of PyCharm to complete the test, you then install a specific &#39;TensorFlow Test&#39; Module. This module creates the test environment and provides the interface and buttons you need to complete and submit the test.&lt;/p&gt;
&lt;p&gt;When you &#39;buy&#39; the test you will be sent a pdf which details exactly what you need to setup, down to the version of PyCharm and Python that you must use, and the packages that it will install in the environment.&lt;/p&gt;
&lt;p&gt;You can check out the latest environment setup guidance &lt;a href=&quot;https://www.tensorflow.org/extras/cert/Setting_Up_TF_Developer_Certificate_Exam.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I would highly recommend setting up a test environment in PyCharm using the exact version of Python and packages that the guidance details. This should mitigate any potential problems you might come across in the exam. This is important, as the test is timed (5 hours), so you don&#39;t want to waste time debugging your environment while the test clock is running!&lt;/p&gt;
&lt;h2 id=&quot;starting-the-test&quot; tabindex=&quot;-1&quot;&gt;Starting the test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#starting-the-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you are setup and you have clicked to &#39;start the test&#39; you will have folders / files that contain everything you need to complete each section of the test. Instructions on exactly what you need to do are contained within the files that you will write the code. Obviously I can&#39;t go into detail here, but once you are at this point you just read the instructions and go!&lt;/p&gt;
&lt;h2 id=&quot;grading&quot; tabindex=&quot;-1&quot;&gt;Grading &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#grading&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You are graded on the models that you generate. These models are uploaded using the plugin (you just hit a button) and then the model you submit is tested. Throughout the course of the test you can submit as many models as you like, so you have plenty of opportunity to improve your models throughout the course of the exam.&lt;/p&gt;
&lt;p&gt;When you submit a model you receive a grade out of 5 for the submitted model. For example, you may submit a model and the result comes back as 3/5. You might therefore want to try and improve the model to get 5/5 before you end the test, or the time runs out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I should point out at this point that I have no idea what you need to achieve in terms of test scores to ensure you pass. I completed the test with 5/5 in every section, but this may not be necessary. I have no way of knowing.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;recommendations&quot; tabindex=&quot;-1&quot;&gt;Recommendations &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#recommendations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the things to remember is that this is an open book exam. You can use any resources you want to help you as you go through the exam, so have the resources you think will be helpful setup and readily accessible.&lt;/p&gt;
&lt;p&gt;If you do not have a GPU in the computer that you will use for the test, then you need to bear in mind that some of your models (depending on your strategy and choices in the test) may take a little while to run through. In reality the test time of 5 hours takes this into account, and the models you are required to build are reasonable, so it is not a major problem. However, if possible using a GPU would be preferable, and save you some time.&lt;/p&gt;
&lt;p&gt;One good option, if GPU access is not possible, is to use Google Colab to run your tests, and then transfer your code to PyCharm on your final model run. This is perfectly valid and even mentioned in &#39;setting up&#39; documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;During the exam, you are welcome to experiment with training models using GCP, AWS, Jupyter Notebooks or Google Colab, but you will still need to define, train and save your models within the exam environment, inside PyCharm, in order to submit it for grading&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This allows you to take advantage of the free GPU provided in a Colab environment, which should help you iterate a bit quicker as you fine tune your models.&lt;/p&gt;
&lt;h2 id=&quot;problems&quot; tabindex=&quot;-1&quot;&gt;Problems &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#problems&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In general the test went very smoothly. However, I did have an issue with my final model. When I ran the code for the model within PyCharm it would not save the model, and instead gave an error.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/problem.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/problem.jpg&quot; alt=&quot;Problem&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@elisa_ventur?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Elisa Ventur&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/problems?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the end I had to run the code in Colab and transfer the model to PyCharm to upload it. Fortunately, that worked fine, but due to the requirements of a specific version of Python etc. I can&#39;t guarantee this will always work. So, where possible I would try to stick to running your models in the PyCharm environment. It is, however, good to know that there is a potential alternative should you hit a technical issue like I did.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-know-if-i-passed%3F&quot; tabindex=&quot;-1&quot;&gt;How do I know if I passed? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#how-do-i-know-if-i-passed%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you have submitted your test with your final models, you should receive a confirmation that you completed the test.&lt;/p&gt;
&lt;p&gt;In my case, shortly after that I received an email saying I had passed. Literally within 5 minutes or so after completion. Again, I can&#39;t guarantee this will happen in your case, but that is what happened to me.&lt;/p&gt;
&lt;h1 id=&quot;what-do-you-get-in-the-end%3F&quot; tabindex=&quot;-1&quot;&gt;What do you get in the end? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#what-do-you-get-in-the-end%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;certificate&quot; tabindex=&quot;-1&quot;&gt;Certificate &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#certificate&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You are basically issued with a certificate through Google&#39;s partner service accredible:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/tensorflow-certificate.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/tensorflow-certificate.png&quot; alt=&quot;TensorFlow Certificate&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
TensorFlow Certificate&lt;/p&gt;
&lt;p&gt;Through the interface you have on your Accredible account you can do various things like download the certificate, create Gmail signatures, outlook signatures, and various embedding options for webpages.&lt;/p&gt;
&lt;p&gt;The certificate is valid for 3 years, after which:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To renew your certification at that time, you need to complete the registration and certificate process again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Slightly vague wording, but I think that means you need to do the exam again.&lt;/p&gt;
&lt;h2 id=&quot;tensorflow-certificate-network&quot; tabindex=&quot;-1&quot;&gt;TensorFlow Certificate Network &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#tensorflow-certificate-network&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apart from the actual certificate, you are also added to the &lt;a href=&quot;https://developers.google.com/certification/directory/tensorflow&quot;&gt;TensorFlow Certificate Network&lt;/a&gt; (if you opt in).&lt;/p&gt;
&lt;p&gt;This is basically an online searchable directory of all the people that have passed the TensorFlow certification. You can filter by name, country, experience etc. so it is very useful for employers, or potential clients to find local &#39;experts&#39;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/certificate-network.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/tensorflow-certificate/certificate-network.jpg&quot; alt=&quot;TensorFlow Certificate Network&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://developers.google.com/certification/directory/tensorflow&quot;&gt;TensorFlow Certificate Network&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Again, this may or may not add value for you personally, it is impossible to say, but it is extra visibility none the less.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/tensorflow-certificate/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;All in all I think the TensorFlow Developer Certificate is a positive addition to the machine learning / deep learning landscape.&lt;/p&gt;
&lt;p&gt;It has spawned a multitude of online courses that are tuned to give you a broad understanding of the main problems (Natural Language Processing (NLP), image classification, time series prediction etc.) that are currently being used within industry to solve a multitude of real world problems.&lt;/p&gt;
&lt;p&gt;This gives beginners a structured way to get a good feel for the machine learning / deep learning topic. It also allows more experienced practitioners to check or level-up their skill set. Even seasoned veterans of the industry may benefit from the added benefit of having a certification from Google, one of the biggest players in the deep learning space.&lt;/p&gt;
&lt;p&gt;Is it essential to do it? Of course not, but depending on your circumstances it could be of real benefit.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Speedup Data Processing with Numpy Vectorization</title>
		<link href="https://www.thetestspecimen.com/posts/numpy-vectorize/"/>
		<updated>Thu, 25 Aug 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/numpy-vectorize/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;When dealing with smaller datasets it is easy to assume that normal Python methods are quick enough to process data. However, with the increase in the volume of data produced, and generally available for analysis, it is becoming more important than ever to optimise code to be as fast as possible.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We will therefore look into how using vectorization, and the numpy library, can help you speed up numerical data processing.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;why-is-python-slow%3F&quot; tabindex=&quot;-1&quot;&gt;Why is python slow? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#why-is-python-slow%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Python is well known as an excellent language for data processing and exploration. The main attraction is that it is a high level language, so it is easy and intuitive to understand and learn, and quick to write and iterate. All the features you would want if your focus is data analysis / processing and not writing mountains of code.&lt;/p&gt;
&lt;p&gt;However, this ease of use comes with a downside. It is much slower to process calculations when compared to lower level languages such as C.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/numpy-vectorize/snail.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/numpy-vectorize/snail.jpg&quot; alt=&quot;Snail&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@wolfgang_hasselmann?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Wolfgang Hasselmann&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/snail?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fortunately, as python is one of the chosen languages of the data analysis and data science communities (among many others), there are extensive libraries and tools available to mitigate the inherent &#39;slowness&#39; of python when it comes to processing large amounts of data.&lt;/p&gt;
&lt;h1 id=&quot;what-exactly-is-vectorization%3F&quot; tabindex=&quot;-1&quot;&gt;What exactly is vectorization? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#what-exactly-is-vectorization%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;You will often see the term &amp;quot;vectorization&amp;quot; when talking about speeding calculations up with numpy. Numpy even has a method called &amp;quot;vectorize&amp;quot;, as we will see later.&lt;/p&gt;
&lt;p&gt;A general Google search will result in a whole lot of confusing and contradictory information about what vectorization actually is, or just generalised statements that don&#39;t tell you a great deal:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The concept of &lt;strong&gt;vectorized operations&lt;/strong&gt; on NumPy allows the use of more optimal and pre-compiled functions and mathematical operations on NumPy array objects and data sequences. The Output and Operations will speed up when compared to simple non-vectorized operations.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &lt;a href=&quot;https://www.geeksforgeeks.org/vectorized-operations-in-numpy/&quot;&gt;GeekForGeeks.org&lt;/a&gt; - the first google result when searching - what is numpy vectorization?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It just doesn&#39;t say much more than: &lt;em&gt;it will get faster due to optimisations&lt;/em&gt;. &lt;strong&gt;What optimisations?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-optimisations%3F&quot; tabindex=&quot;-1&quot;&gt;What optimisations? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#what-optimisations%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The trouble is that numpy is a very powerful, optimised tool. When implementing something like vectorization, the implementation in numpy includes a lot of well thought out optimisations, on top of just plain old vectorization. I think this is where a lot of the confusion comes from, and breaking down what is going on (to some degree at least) would help to make things clearer.&lt;/p&gt;
&lt;h1 id=&quot;breaking-down-vectorization-in-numpy&quot; tabindex=&quot;-1&quot;&gt;Breaking down vectorization in numpy &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#breaking-down-vectorization-in-numpy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The subsequent sections will breakdown what is typically included under the generalised &amp;quot;vectorization&amp;quot; umbrella as used in the numpy library.&lt;/p&gt;
&lt;p&gt;Knowing what each does, and how it contributes to the speed of numpy &amp;quot;vectorized&amp;quot; operations, should hopefully help with any confusion.&lt;/p&gt;
&lt;h2 id=&quot;actual-vectorization&quot; tabindex=&quot;-1&quot;&gt;Actual vectorization &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#actual-vectorization&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Vectorization is a term used outside of numpy, and in very basic terms is parallelisation of calculations.&lt;/p&gt;
&lt;p&gt;If you have a 1D array (or &lt;strong&gt;vector&lt;/strong&gt; as they are also known):&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and multiply each element in that vector by the scalar value 2, you end up with:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In normal python this would be done element by element using something like a for loop, so four calculations one after the other. If each calculation takes 1 second, that would be 4 seconds to complete the calculation and issue the result.&lt;/p&gt;
&lt;p&gt;However, numpy will actually multiply two vectors together &lt;code&gt;[2, 2, 2, 2]&lt;/code&gt; and &lt;code&gt;[2, 4, 6, 8]&lt;/code&gt; (numpy &#39;stretches&#39; the scalar value 2 into a vector using something called broadcasting, see the next section for more on that). Each of the four separate calculations is done all at once in parallel. So in terms of time, the calculation is completed in 1 second (each calculation takes 1 second, but they are all completed at the same time).&lt;/p&gt;
&lt;p&gt;A four fold improvement in speed just through &#39;vectorization&#39; of the calculation (or, if you like, a form of parallel processing). Please bare in mind that the example I have given is very simplified, but it does help to illustrate what is going on on a basic level.&lt;/p&gt;
&lt;p&gt;You can see how this could equate to a very large difference if you are dealing with datasets with thousands, if not millions, of elements.&lt;/p&gt;
&lt;p&gt;Just be aware, the parallelisation is not unlimited, and dependent on hardware to some degree. Numpy is not able to parallelise 100 million calculations all together, but it can reduce the amount of serial calculations required by a significant amount, especially when dealing with a large amount of data.&lt;/p&gt;
&lt;p&gt;If you want a more detailed explanation, then I recommend &lt;a href=&quot;https://stackoverflow.com/questions/35091979/why-is-vectorization-faster-in-general-than-loops&quot;&gt;this&lt;/a&gt; stackoverflow post, which does a great job of explaining in more detail. If you want even more detail then &lt;a href=&quot;https://towardsdatascience.com/decoding-the-performance-secret-of-worlds-most-popular-data-science-library-numpy-7a7da54b7d72&quot;&gt;this&lt;/a&gt; article, and &lt;a href=&quot;https://pythonspeed.com/articles/vectorization-python/&quot;&gt;this&lt;/a&gt; article are excellent.&lt;/p&gt;
&lt;h2 id=&quot;broadcasting&quot; tabindex=&quot;-1&quot;&gt;Broadcasting &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#broadcasting&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Broadcasting is a feature of numpy that enables mathematical operations to be carried out between arrays of different sizes. We actually did just that in the previous section.&lt;/p&gt;
&lt;p&gt;The scalar value 2 was &amp;quot;stretched&amp;quot; into an array full of 2s. That is broadcasting, and is one of the ways in which numpy &lt;strong&gt;prepares&lt;/strong&gt; data for much more efficient calculations. However, saying &amp;quot;it just creates an array of 2s&amp;quot; is a gross oversimplification, but it is not worth getting into the detail here.&lt;/p&gt;
&lt;p&gt;Numpy&#39;s own documentation is actually quite clear here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The term broadcasting describes how NumPy treats arrays with different shapes during arithmetic operations. Subject to certain constraints, the smaller array is “broadcast” across the larger array so that they have compatible shapes. Broadcasting provides a means of vectorizing array operations so that looping occurs in C instead of Python.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &lt;a href=&quot;https://numpy.org/doc/stable/user/basics.broadcasting.html&quot;&gt;numpy.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;a-faster-language&quot; tabindex=&quot;-1&quot;&gt;A faster language &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#a-faster-language&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/numpy-vectorize/burnout.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/numpy-vectorize/burnout.jpg&quot; alt=&quot;Car performing a burnout&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@vargasuillian?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Uillian Vargas&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/fast?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As detailed in the quote from numpy&#39;s own documentation in the previous section, numpy uses pre-compiled and optimised C functions to execute calculations.&lt;/p&gt;
&lt;p&gt;As C is a lower level language, there is much more scope for optimisation of calculations. This is not something you need to think about, as the numpy library does that for you, but it is something you benefit from.&lt;/p&gt;
&lt;h2 id=&quot;homogeneous-data-types&quot; tabindex=&quot;-1&quot;&gt;Homogeneous data types &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#homogeneous-data-types&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In python you have the flexibility to specify lists with a mixture of different datatypes (strings, ints, floats etc.). When dealing with data in numpy, the data is homogeneous (i.e. all the same type). This helps speed up calculations as the data type does not need to be figured out on the fly like in a python list.&lt;/p&gt;
&lt;p&gt;This can of course also been seen as a limitation, as it makes working with mixed data types more difficult.&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot; tabindex=&quot;-1&quot;&gt;Putting it all together &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#putting-it-all-together&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As previously mentioned, it is quite common for all of the above (and more) to be grouped together when talking about vectorization in numpy. However, as vectorization is also used in other contexts to describe more specific operations, this can be quite confusing.&lt;/p&gt;
&lt;p&gt;Hopefully, it is all a little bit clearer as to what we are dealing with, and now we can move on to the practical side.&lt;/p&gt;
&lt;p&gt;How much difference does numpy&#39;s implementation of vectorization really make?&lt;/p&gt;
&lt;h1 id=&quot;a-practical-example&quot; tabindex=&quot;-1&quot;&gt;A practical example &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#a-practical-example&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To demonstrate the effectiveness of vectorization in numpy we will compare a few different commonly used methods to apply mathematical functions, and also logic, using the &lt;a href=&quot;https://pandas.pydata.org/&quot;&gt;pandas&lt;/a&gt; library.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;pandas&lt;/strong&gt; is a fast, powerful, flexible and easy to use open source data analysis and manipulation tool,&lt;br /&gt;
built on top of the &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt; programming language.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &lt;a href=&quot;https://pandas.pydata.org/&quot;&gt;pydata.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pandas is widely used when dealing with tabular data, and is also built on top of numpy, so I think it serves as a great medium for demonstrating the effectiveness of vectorization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All the calculations that follow are available in a colab notebook&lt;/strong&gt; &lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/numpy_vectorize.ipynb&quot;&gt;&lt;img src=&quot;https://colab.research.google.com/assets/colab-badge.svg&quot; alt=&quot;Open In Colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The data will be a simple dataframe with two columns. Both columns will be comprised of 1 million rows of random numbers taken from a normal distribution.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;df &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataFrame&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;randn&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;randn&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which results in:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;row&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;series1&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;series2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2.024360&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.304465&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.294511&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.585608&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.580776&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.987834&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.403553&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.553986&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-2.004211&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.263476&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;...&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;...&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;999995&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.448020&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.040024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;999996&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.325896&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.574605&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;999997&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.679847&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-1.103830&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;999998&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.568573&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-1.695838&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;999999&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-0.362537&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.556493&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;1000000 rows × 2 columns&lt;/p&gt;
&lt;h2 id=&quot;the-manipulation&quot; tabindex=&quot;-1&quot;&gt;The manipulation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#the-manipulation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Then the above dataframe will be manipulated by two different functions to create a third column &lt;strong&gt;&#39;series3&#39;&lt;/strong&gt;. This is a very common operation in pandas, for example, when creating new features for machine or deep learning:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function 1 - a simple summation&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sum_nums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Function 2 - logic and arithmetic&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;categorise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;elif&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of the above functions will be applied using different methods (some vectorized, some not) to see which performs the calculations over the 1 million rows the quickest.&lt;/p&gt;
&lt;h2 id=&quot;the-methods-and-the-results&quot; tabindex=&quot;-1&quot;&gt;The methods and the results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#the-methods-and-the-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The processing methods that follow are arranged in order of speed. Slowest first.&lt;/p&gt;
&lt;p&gt;Each method was run multiple times using the &lt;a href=&quot;https://docs.python.org/3/library/timeit.html#module-timeit&quot;&gt;timeit library&lt;/a&gt;, and for both of the functions mentioned in the previous section. Once for the slower methods, up to 1000 times for the faster methods. This ensures the calculations don&#39;t run too long, and we get enough iterations to average out the run time per iteration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The pandas apply method&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The pandas apply method is very simple and intuitive. However, it is also one of the slowest ways for applying calculations on large datasets.&lt;/p&gt;
&lt;p&gt;There is no optimisation of the calculation. It is basically performing a simple for loop. This method should be avoided unless the requirements of the function rule out all other methods.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;lambda&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; sum_nums&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;axis&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;lambda&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; categorise&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;axis&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;11.60&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;11.60&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;11.58&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;11.58&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Itertuples&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Itertuples, in some simple implementations, is even slower than the apply method, but in this case it is used with list comprehension, so achieves almost a 20 times improvement in speed over the apply method.&lt;/p&gt;
&lt;p&gt;Itertuples removes the overhead of dealing with a pandas Series and instead uses named tuples for the iteration&lt;sup&gt;[1]&lt;/sup&gt;. As previously mentioned, this particular implementation also benefits from the speed up list comprehension provides, by removing the overhead of appending to a list&lt;sup&gt;[2]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: there is also a function called iterrows, but it is always slower, and therefore ignored for brevity.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;sum_nums&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;itertuples&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;categorise&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;itertuples&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.12&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.612&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.41&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.641&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;List comprehension&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The previous itertuples example also used list comprehension, but it seems this particular solution using &#39;zip&#39; instead of itertuples is about twice as fast.&lt;/p&gt;
&lt;p&gt;The main reason for this is the additional overhead introduced by the itertuples method. Itertuples actually uses zip internally, so any additional code to get to the point where zip is applied is just unnecessary overhead.&lt;/p&gt;
&lt;p&gt;A great investigation into this can be found in &lt;a href=&quot;https://medium.com/swlh/why-pandas-itertuples-is-faster-than-iterrows-and-how-to-make-it-even-faster-bc50c0edd30d&quot;&gt;this&lt;/a&gt; article. Incidentally, it also explains why iterrows is slower than itertuples.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;sum_nums&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;categorise&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;29.31&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.293&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;31.13&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.311&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x37&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Numpy vectorize method&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a bit of an odd one. The method itself is called &#39;vectorize&#39;, but the truth is it is no where near as fast as the full on optimised vectorization that we will see in the methods that follow. Even numpy&#39;s own documentation states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html#numpy.vectorize&quot;&gt;&lt;code&gt;vectorize&lt;/code&gt;&lt;/a&gt; function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html&quot;&gt;numpy.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, it is true that the syntax used to implement this function is extremely simple and clear. On top of that, the method actually does a great job of speeding up the calculation, more so than any method we have tried up till now.&lt;/p&gt;
&lt;p&gt;It is also more flexible than the methods that follow, and so is easier to implement in lots of situations without any messing about. Numpy vectorize is therefore a great method to use, and highly recommended.&lt;/p&gt;
&lt;p&gt;It is just worth bearing in mind that although this method is quick, it is not even close to what is achievable with the fully optimised methods we are about to see, so it should not just be your go to method in all situations.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vectorize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum_nums&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vectorize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;categorise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;22.13&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.221&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;21.41&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.214&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x54&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Pandas vectorization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now we come to full on optimised vectorization.&lt;/p&gt;
&lt;p&gt;The difference in speed is night and day compared to any method before, and a prime example of all the optimisations discussed in earlier sections of this article working together.&lt;/p&gt;
&lt;p&gt;The pandas implementation is still an implementation of numpy under the hood, but the syntax is very, very straight forward. If you can express your desired calculation this way, you can&#39;t do much better in terms of speed without coming up with a significantly more complicated implementation.&lt;/p&gt;
&lt;p&gt;Approximately, 7000 times faster than the apply method, and 130 times faster than the numpy vectorize method!&lt;/p&gt;
&lt;p&gt;The downside, is that such simple syntax does not allow for more complicated logic statements to be processed.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# N/A as a simple operation is not possible due to the included logic in the function.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1000&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.66&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.00166&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x7000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Numpy vectorization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The final implementation is as close as we can get to implementing raw numpy whilst still having the inputs from a pandas dataframe. Even so, by stripping away any pandas overhead in the calculation, a 15% reduction in processing time is achieved when compared to the pandas implementation.&lt;/p&gt;
&lt;p&gt;That is 8000 times faster than the apply method.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Function 1&lt;/span&gt;
series3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;series2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Function 2&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# N/A as a simple operation is not possible due to the included logic in the function.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Iterations&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Total Time (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Time per iteration (s)&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Improvement in speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1000&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.42&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.00142&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;x8000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I hope this article has helped to clarify some of the jargon that exists especially in relation to vectorization, and therefore allowed you to have a better understanding of which methods would be most appropriate depending on your particular situation.&lt;/p&gt;
&lt;p&gt;As a general rule of thumb if you are dealing with large datasets of numerical data, vectorized methods in pandas and numpy are your friend:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the calculation allows, try to use numpy&#39;s inbuilt mathematical functions&lt;sup&gt;[3]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Pandas&#39; mathematical operations are also a good choice&lt;/li&gt;
&lt;li&gt;If you require more complicated logic, use numpy&#39;s vectorize&lt;sup&gt;[4]&lt;/sup&gt; method&lt;/li&gt;
&lt;li&gt;Failing all of the above, it is a case of deciding exactly what functionality you need, and choosing one of the slower methods as appropriate (list comprehension, intertuples, apply)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you find yourself in a situation where you need both speed &lt;strong&gt;and&lt;/strong&gt; more flexibility, then you are in a particularly niche situation. You may need to start looking into implementing your own parallelisation, or writing your own bespoke numpy functions&lt;sup&gt;[5]&lt;/sup&gt;. All of which is possible.&lt;/p&gt;
&lt;h1 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/numpy-vectorize/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;[1] &lt;a href=&quot;https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.itertuples.html&quot;&gt;https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.itertuples.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] &lt;a href=&quot;https://stackoverflow.com/users/2867928/mazdak&quot;&gt;Mazdak&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/30245397/why-is-a-list-comprehension-so-much-faster-than-appending-to-a-list&quot;&gt;Why is a list comprehension so much faster than appending to a list?&lt;/a&gt; (2015), &lt;a href=&quot;https://stackoverflow.com/&quot;&gt;stackoverflow.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[3] &lt;a href=&quot;https://numpy.org/doc/stable/reference/routines.math.html&quot;&gt;https://numpy.org/doc/stable/reference/routines.math.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[4] &lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html&quot;&gt;https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[5] &lt;a href=&quot;https://numpy.org/doc/stable/user/c-info.ufunc-tutorial.html&quot;&gt;https://numpy.org/doc/stable/user/c-info.ufunc-tutorial.html&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Pick the Best Graphics Card for Machine Learning</title>
		<link href="https://www.thetestspecimen.com/posts/graphics-card-selection/"/>
		<updated>Mon, 19 Sep 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/graphics-card-selection/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;When dealing with machine learning, and especially when dealing with deep learning and neural networks, it is preferable to use a graphics card to handle the processing, rather than the CPU. Even a very basic GPU is going to outperform a CPU when it comes to neural networks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But which GPU should you buy? There is a lot of choice, and it can get confusing and expensive very quickly. I will therefore try to guide you on the relevant factors to consider, so that you can make an informed choice based on your budget and particular modelling requirements.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;why-is-a-gpu-preferable-over-a-cpu-for-machine-learning%3F&quot; tabindex=&quot;-1&quot;&gt;Why is a GPU preferable over a CPU for Machine Learning? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#why-is-a-gpu-preferable-over-a-cpu-for-machine-learning%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A CPU (Central Processing Unit) is the workhorse of your computer, and importantly is very flexible. It can deal with instructions from a wide range of programs and hardware, and it can process them very quickly. To excel in this multitasking environment a CPU has a small number of flexible and fast processing units (also called cores).&lt;/p&gt;
&lt;p&gt;A GPU (Graphics Processing Unit) is a little bit more specialised, and not as flexible when it comes to multitasking. It is designed to perform lots of complex mathematical calculations &lt;strong&gt;in parallel&lt;/strong&gt;, which increases throughput. This is achieved by having a higher number of simpler cores, sometimes thousands, so that many calculations can be processed all at once.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/artificial-neural-network-1.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/artificial-neural-network-1.png&quot; alt=&quot;Artificial neural network&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Image by &lt;a href=&quot;https://pixabay.com/users/ahmedgad-9403351/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3501528&quot;&gt;Ahmed Gad&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3501528&quot;&gt;Pixabay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This requirement of multiple calculations being carried out in parallel is a perfect fit for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;graphics rendering&lt;/strong&gt; - moving graphical objects need their trajectories calculated constantly, and this requires a large amount of constant repeat parallel mathematical calculations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;machine and deep learning&lt;/strong&gt; - large amounts of matrix/tensor calculations, which with a GPU can be processed in parallel.&lt;/li&gt;
&lt;li&gt;any type of mathematical calculation that can be split to run in parallel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think the best summary I have seen is on Nvidia&#39;s own &lt;a href=&quot;https://blogs.nvidia.com/blog/2009/12/16/whats-the-difference-between-a-cpu-and-a-gpu/&quot;&gt;blog&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Central Processing Unit&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Graphics Processing Unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Several cores&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Many cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Low latency&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;High throughput&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Good for serial processing&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Good for parallel processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Can do a handful of operations at once&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Can do thousands of operations at once&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://blogs.nvidia.com/blog/2009/12/16/whats-the-difference-between-a-cpu-and-a-gpu/&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;tensor-processing-unit-(tpu)&quot; tabindex=&quot;-1&quot;&gt;Tensor Processing Unit (TPU) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#tensor-processing-unit-(tpu)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the boom in AI and machine/deep learning there are now even more specialised processing cores called Tensor cores. These are faster and more efficient when performing tensor/matrix calculations. Exactly what you need for the type of mathematics involved in machine/deep learning.&lt;/p&gt;
&lt;p&gt;Although there are dedicated TPUs, some of the latest GPUs also include a number of Tensor cores, as you will see later in this article.&lt;/p&gt;
&lt;h1 id=&quot;nvidia-vs-amd&quot; tabindex=&quot;-1&quot;&gt;Nvidia vs AMD &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#nvidia-vs-amd&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This is going to be quite a short section, as the answer to this question is definitely: &lt;strong&gt;Nvidia&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can use AMD GPUs for machine/deep learning, but at the time of writing Nvidia&#39;s GPUs have much higher compatibility, and are just generally better integrated into tools like TensorFlow and PyTorch.&lt;/p&gt;
&lt;p&gt;I know from my own experience that trying to use an AMD GPU with TensorFlow requires using additional tools (&lt;a href=&quot;https://github.com/RadeonOpenCompute/ROCm&quot;&gt;ROCm&lt;/a&gt;), which tend to be a bit fiddly, and sometimes leave you with a not quite up to date version of TensorFlow/PyTorch, just so you can get the card working.&lt;/p&gt;
&lt;p&gt;This situation may improve in the future, but if you want a hassle free experience, it is better to stick with Nvidia for now.&lt;/p&gt;
&lt;h1 id=&quot;gpu-features&quot; tabindex=&quot;-1&quot;&gt;GPU Features &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#gpu-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Picking out a GPU that will fit your budget, and is also capable of completing the machine learning tasks you want, basically comes down to a balance of four main factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How much RAM does the GPU have?&lt;/li&gt;
&lt;li&gt;How many CUDA and/or Tensor cores does the GPU have?&lt;/li&gt;
&lt;li&gt;What chip architecture does the card use?&lt;/li&gt;
&lt;li&gt;What are your power draw requirements (if any)?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The subsequent sub sections will look into each of these areas, and hopefully give you a better grasp of what matters to you.&lt;/p&gt;
&lt;h2 id=&quot;gpu-ram&quot; tabindex=&quot;-1&quot;&gt;GPU RAM &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#gpu-ram&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The answer to this is the more the better! Very helpful I know...&lt;/p&gt;
&lt;p&gt;It really comes down to what you are modelling, and how big those models are. For example if you are dealing with images, videos or audio, then by definition you are going to be dealing with quite a large amount of data, and GPU RAM will be an extremely important consideration.&lt;/p&gt;
&lt;p&gt;There are always ways to get around running out of memory (e.g. reducing the batch size). However, you want to limit the amount of time you have to spend messing about with code just to get around memory requirements, so a good balance for your requirements is essential.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/ram-1.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/ram-1.png&quot; alt=&quot;RAM chip&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Image by &lt;a href=&quot;https://pixabay.com/users/openclipart-vectors-30363/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=152655&quot;&gt;OpenClipart-Vectors&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=152655&quot;&gt;Pixabay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a general rule of thumb I would suggest the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4GB&lt;/strong&gt; - The absolute minimum I would consider, this will work well in most cases as long as you are not dealing with overly complicated models, or large amounts of images, videos or audio. Great if you are just starting out and want to experiment without breaking the bank. The improvements over a CPU will still be night and day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8GB&lt;/strong&gt; - I would say this is a good middle ground. You can get most tasks done without hitting RAM limits, but you will have problems with more complicated models with images, video or audio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;12GB&lt;/strong&gt; - This I would describe as optimal without being ridiculous. You can deal with most larger models, even those that deal with images, video or audio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;12GB+&lt;/strong&gt; - The more the better, you will be able to handle larger datasets and bigger batch sizes. However, beyond 12GB is where the prices really start to ramp up.&lt;/p&gt;
&lt;p&gt;In my experience I would say it is better, on average, to opt for a card that is &#39;slower&#39; with more RAM, if the cost is the same. Remember, the advantage of a GPU is high throughput, and this is heavily dependent on available RAM to feed the data through the GPU.&lt;/p&gt;
&lt;h2 id=&quot;cuda-cores-and-tensor-cores&quot; tabindex=&quot;-1&quot;&gt;CUDA Cores and Tensor Cores &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#cuda-cores-and-tensor-cores&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is fairly simple really. The more CUDA (&lt;strong&gt;C&lt;/strong&gt;ompute &lt;strong&gt;U&lt;/strong&gt;nified &lt;strong&gt;D&lt;/strong&gt;evice &lt;strong&gt;A&lt;/strong&gt;rchitecture) cores / Tensor cores the better.&lt;/p&gt;
&lt;p&gt;The other items such as RAM and chip architecture (see the next section) should probably be considered first, and then look at cards with the highest number of CUDA/tensor cores from your narrowed down selection.&lt;/p&gt;
&lt;p&gt;For machine/deep learning Tensor cores are better (faster and more efficient) than CUDA cores. This is due to them being designed precisely for the calculations that are required in the machine/deep learning domain.&lt;/p&gt;
&lt;p&gt;The reality is it doesn&#39;t matter a great deal, CUDA cores are plenty fast enough. If you can get a card which includes tensor cores too, that is a good plus point to have, just don&#39;t get too hung up on it.&lt;/p&gt;
&lt;p&gt;Moving forward you will see &amp;quot;CUDA&amp;quot; mentioned a lot, and it can get confusing, so to summarise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CUDA cores&lt;/strong&gt; - these are the physical processors on the graphics cards, typically in their thousands.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CUDA 11&lt;/strong&gt; - The number may change, but this is referring to the software/drivers that are installed to allow the graphics card to work. New releases are made regularly, and it can be installed like any other software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CUDA generation (or compute capability)&lt;/strong&gt; - this describes the capability of the graphics card in terms of it&#39;s generational features. This is fixed in hardware, and so can only be changed by upgrading to a new card. It is distinguished by numbers and a code name. Examples: 3.x [Kepler], 5.x [Maxwell], 6.x [Pascal], 7.x [Turing] and 8.x [Ampere].&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;chip-architecture&quot; tabindex=&quot;-1&quot;&gt;Chip architecture &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#chip-architecture&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is actually more important than you might think. As I mentioned earlier we are basically discarding AMD at this point, so in terms of generations of chip architecture we only have Nvidia.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/electrical-traces-1.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/electrical-traces-1.jpg&quot; alt=&quot;Electrical circuit traces&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/es/@manueljota?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Manuel&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/computer-chip?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main thing to look out for is the &amp;quot;&lt;a href=&quot;https://developer.nvidia.com/cuda-gpus&quot;&gt;Compute Capability&lt;/a&gt;&amp;quot; of the chipset, sometimes called &amp;quot;CUDA generation&amp;quot;. This is fixed for each card, so once you buy the card you are stuck with whatever compute capability the card has.&lt;/p&gt;
&lt;p&gt;It is important to know what the compute capability of the card is for two main reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;significant feature improvements&lt;/li&gt;
&lt;li&gt;deprecation&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;significant-feature-improvement&quot; tabindex=&quot;-1&quot;&gt;Significant feature improvement &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#significant-feature-improvement&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s start with a significant feature improvement. &lt;strong&gt;Mixed precision training&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are numerous benefits to using numerical formats with lower precision than 32-bit floating point. First, they require less memory, enabling the training and deployment of larger neural networks. Second, they require less memory bandwidth which speeds up data transfer operations. Third, math operations run much faster in reduced precision, especially on GPUs with Tensor Core support for that precision. Mixed precision training achieves all these benefits while ensuring that &lt;em&gt;no&lt;/em&gt; task-specific accuracy is lost compared to full precision training. It does so by identifying the steps that require full precision and using 32-bit floating point for only those steps while using 16-bit floating point everywhere else.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://docs.nvidia.com/deeplearning/performance/mixed-precision-training/index.html&quot;&gt;Nvidia Learning Performance Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is only possible to use mixed precision training if you have a GPU with compute capability 7.x (Turing) or higher. That is basically the RTX 20 series or newer, or the RTX, &amp;quot;T&amp;quot; or &amp;quot;A&amp;quot; series on desktop/server.&lt;/p&gt;
&lt;p&gt;The main reason mixed precision training is such an advantage when considering a new graphics card is that it lowers RAM usage, so by having a slightly newer card your RAM requirements are reduced.&lt;/p&gt;
&lt;h3 id=&quot;deprecation&quot; tabindex=&quot;-1&quot;&gt;Deprecation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#deprecation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Then we move to the other end of the scale.&lt;/p&gt;
&lt;p&gt;If you have particularly high RAM requirements, but not enough money for a high end card, then it may be the case that you will opt for an older model of GPU on the second hand market.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, there is quite a large downside...the card is end of life.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A prime example of this is the Tesla K80, which has &lt;strong&gt;4992 CUDA cores&lt;/strong&gt; and &lt;strong&gt;24GB of RAM&lt;/strong&gt;. It originally retailed at about USD 7000.00 back in 2014. I just had a look on e-bay in the UK, and it is going for anything from GBP 130.00 (USD/EUR 150) to GBP 170.00 (USD/EUR 195)! That is a lot of RAM for such a small price.&lt;/p&gt;
&lt;p&gt;However, there is quite a large downside. The K80 has a compute capability of 3.7 (Kepler), which is deprecated from CUDA 11 onwards (the current CUDA version is 11). That means the card is end of life, and won&#39;t work on future releases of CUDA drivers. A great pity really, but something to bear in mind, as it is very tempting.&lt;/p&gt;
&lt;h2 id=&quot;graphics-cards-vs-workstation%2Fserver-cards&quot; tabindex=&quot;-1&quot;&gt;Graphics Cards vs Workstation/Server Cards &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#graphics-cards-vs-workstation%2Fserver-cards&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Nvidia basically splits their cards into two sections. There are the &lt;a href=&quot;https://www.nvidia.com/en-eu/geforce/graphics-cards/compare/&quot;&gt;consumer graphics cards&lt;/a&gt;, and then cards aimed at &lt;a href=&quot;https://www.nvidia.com/en-gb/design-visualization/desktop-graphics/&quot;&gt;desktops/servers&lt;/a&gt; (i.e. professional cards).&lt;/p&gt;
&lt;p&gt;There are obviously differences between the two sections, but the main thing to bear in mind is that the consumer graphics cards will generally be cheaper for the same specs (RAM, CUDA cores, architecture). However, the professional cards will generally have better build quality, and lower energy consumption.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/gpu-held-1.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/gpu-held-1.jpg&quot; alt=&quot;Held graphics card&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://www.pexels.com/@elias-gamez-2002621/&quot;&gt;Elias Gamez&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/photo/person-holding-a-graphics-card-10558582/&quot;&gt;Pexels&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Looking at the higher end (and very expensive) professional cards you will also notice that they have a lot of RAM (the RTX A6000 has 48GB for example, and the A100 has 80GB!). This is due to the fact that  they are typically aimed directly at 3D modelling, rendering, and machine/deep learning professional markets, which require high levels of RAM. Again, if you have those sort of requirements you will likely not need advice on what to purchase!&lt;/p&gt;
&lt;p&gt;In summary, you will likely be best sticking to the consumer graphics market, as you will get a better deal.&lt;/p&gt;
&lt;h1 id=&quot;recommendation&quot; tabindex=&quot;-1&quot;&gt;Recommendation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#recommendation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Finally, I thought I would actually make some recommendations based on budget and requirements. I have split this into three sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Low budget&lt;/li&gt;
&lt;li&gt;Medium budget&lt;/li&gt;
&lt;li&gt;High budget&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please bear in mind the high budget does not consider anything beyond top end consumer graphics cards. If you really have a very high budget you should be looking at the professional card series, such as the Nvidia &lt;a href=&quot;https://www.nvidia.com/en-us/data-center/a100/&quot;&gt;A series&lt;/a&gt; of cards which can run costs up into many thousands.&lt;/p&gt;
&lt;p&gt;I have included one card that is only available on the second hand market in the low budget section. This is mainly because I think in the low budget section it is worth considering second hand cards.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/gtx-1080-1.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/gtx-1080-1.jpg&quot; alt=&quot;GTX 1080&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nanadua11?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Nana Dua&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/gpu?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have also included professional desktop series cards in the mix as well (T600, A2000 and A4000). You will notice that some of the specs are a little worse than comparable consumer graphics cards, but power draw is significantly better, which may be of concern for some people.&lt;/p&gt;
&lt;h2 id=&quot;low-budget-(less-than-gbp-220---eur%2Fusd-250)&quot; tabindex=&quot;-1&quot;&gt;Low Budget (Less than GBP 220 - EUR/USD 250) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#low-budget-(less-than-gbp-220---eur%2Fusd-250)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;RAM&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Compute Capability&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CUDA Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Tensor Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Mixed Precision&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Power Consumption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;GTX 1070 / 1070ti / 1080&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.1 (Pascal)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1920 / 2432 / 2560&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;No&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;150W / 180W / 180W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;GTX 1660&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.5 (Turing)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1408&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;120W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;T600&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;4GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.5 (Turing)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;640&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;40W&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;medium-budget-(less-than-gbp-440---eur%2Fusd-500)&quot; tabindex=&quot;-1&quot;&gt;Medium Budget (Less than GBP 440 - EUR/USD 500) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#medium-budget-(less-than-gbp-440---eur%2Fusd-500)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;RAM&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Compute Capability&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CUDA Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Tensor Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Mixed Precision&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Power Consumption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 2060 12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.5 (Turing)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2176&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;272 (Gen 2)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;184W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX A2000 6GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.6 (Ampere)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3328&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;104 (Gen 3)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;70W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 3060 12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.6 (Ampere)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3584&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;112 (Gen 3)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;170W&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;high-budget-(less-than-gbp-1050---eur%2Fusd-1200)&quot; tabindex=&quot;-1&quot;&gt;High Budget (Less than GBP 1050 - EUR/USD 1200) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#high-budget-(less-than-gbp-1050---eur%2Fusd-1200)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;RAM&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Compute Capability&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CUDA Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Tensor Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Mixed Precision&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Power Consumption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 3080 Ti&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.6 (Ampere)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;10240&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;320 (Gen 3)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;350W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;A4000 16GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.6 (Ampere)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6144&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;192 (Gen 3)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;140W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 3090&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;24GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.6 (Ampere)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;10496&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;328 (Gen 3)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Yes&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;350W&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&quot;other-options&quot; tabindex=&quot;-1&quot;&gt;Other Options &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#other-options&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you have decided the outlay and bother of getting a graphics card is not for you, you can always take advantage of &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Google Colab&lt;/a&gt;, which gives you access to a GPU for free. Just bear in mind there are time limitations to this, and the GPU is automatically assigned, so having your own graphics card is usually worth it in the long run.&lt;/p&gt;
&lt;p&gt;At the time of writing the following GPUs are available through Colab:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;RAM&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Compute Capability&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CUDA Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Tensor Cores&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Tesla K80&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;12GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3.7&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2496&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Tesla P100&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3584&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Tesla T4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.5&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2560&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;320&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I mentioned earlier in the article that the K80 has 24GB of RAM and 4992 CUDA cores, and it does. However, the K80 is an unusual beast in that it is basically two K40 cards bolted together. This means that when you use a K80 in Colab, you are actually given access to half the card, so only 12GB and 2496 CUDA cores.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/graphics-card-selection/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There is a lot of choice out there, and it can be very confusing. Hopefully you have come away from this article with a much better idea of what will fit your particular requirements.&lt;/p&gt;
&lt;p&gt;Is there a particular graphics card that you think deserves a special mention? Let me know in the comments.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Mixed Precision Training - Less RAM, More Speed</title>
		<link href="https://www.thetestspecimen.com/posts/mixed-precision/"/>
		<updated>Sat, 24 Sep 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/mixed-precision/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;When it comes to large complicated models it is essential to reduce the model training time as much as possible, and utilise the available hardware efficiently. Even small gains per batch or epoch are very important.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mixed precision training can both significantly reduce GPU RAM utilisation, as well as speeding up the training process itself, all without any loss of precision in the outcome.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will show (with code examples) the sort of gains that can actually be attained, whilst also going over the requirements to use mixed precision training in your own models.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The first half of this article is aimed at giving an overview of what mixed precision is, and when, why and how to use it.&lt;/p&gt;
&lt;p&gt;The second half goes through the results of a comparison between &#39;normal&#39; and mixed precision training on a set of dummy images. The images are trained through a multi-layer Conv2D neural network in TensorFlow, and both RAM usage and execution speed are monitored throughout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All the code relevant to the comparison is available in a colab notebook&lt;/strong&gt; &lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/mixed_precision_training.ipynb&quot;&gt;&lt;img src=&quot;https://colab.research.google.com/assets/colab-badge.svg&quot; alt=&quot;Open In Colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;what-exactly-is-mixed-precision%3F&quot; tabindex=&quot;-1&quot;&gt;What exactly is mixed precision? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#what-exactly-is-mixed-precision%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before we dive into what mixed precision is, it is probably a good idea to outline what we are referring to when we say &#39;precision&#39; in this particular context.&lt;/p&gt;
&lt;p&gt;Precision in this case is basically referring to how a floating point number is stored i.e. how much space it takes up in memory. The smaller the memory footprint, the less accurate the number. There are basically three options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Half precision - 16-bit (float16) - low level of storage used to represent number, low level of accuracy&lt;/li&gt;
&lt;li&gt;Single precision - 32-bit (float32) - medium level of storage used to represent number, medium level of accuracy&lt;/li&gt;
&lt;li&gt;Double precision - 64-bit (float64) - high level of storage used to represent number, high level of accuracy&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Typically with machine learning / deep learning and neural networks, you will be dealing with single precision 32-bit floating point numbers.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/mixed-precision/sega-mega-drive-close.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/mixed-precision/sega-mega-drive-close.jpg&quot; alt=&quot;Sega Mega Drive&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Image by &lt;a href=&quot;https://pixabay.com/users/inspiredimages-57296/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=6223513&quot;&gt;InspiredImages&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=6223513&quot;&gt;Pixabay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, in almost all cases it is possible for &lt;strong&gt;calculations&lt;/strong&gt; to be run using 16-bit floating point numbers instead of 32-bit floating point numbers, &lt;strong&gt;without&lt;/strong&gt; any degradation of the accuracy of the model.&lt;/p&gt;
&lt;h2 id=&quot;mixing-precisions&quot; tabindex=&quot;-1&quot;&gt;Mixing precisions &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#mixing-precisions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ideal, and simplest solution, is to use a mixture of 16-bit and 32-bit floating point numbers. Calculations can be run as fast as possible using lower precision 16-bit floating point numbers, and then the inputs and outputs can be stored as 32-bit floating point variables to ensure a high level of accuracy is preserved and there are no compatibility issues on the output.&lt;/p&gt;
&lt;p&gt;This combination is what is referred to as &#39;Mixed Precision&#39;.&lt;/p&gt;
&lt;h1 id=&quot;why-should-i-use-mixed-precision%3F&quot; tabindex=&quot;-1&quot;&gt;Why should I use mixed precision? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#why-should-i-use-mixed-precision%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are two main reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There will be a significant improvement in GPU RAM usage. The difference can be as much as 50% less GPU RAM utilisation&lt;/li&gt;
&lt;li&gt;There can be a significant speed up in time taken to run through the model&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using mixed precision in TensorFlow could:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;improve performance by more than 3 times on modern GPUs and 60% on TPUs&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The RAM usage reduction alone is a big deal. This will allow larger batch sizes to be utilised, or open the door to larger and more intensive models being possible on the same hardware.&lt;/p&gt;
&lt;p&gt;We will of course see actual results for these two factors in the comparison later in the article.&lt;/p&gt;
&lt;h1 id=&quot;what-are-the-requirements-to-use-mixed-precision%3F&quot; tabindex=&quot;-1&quot;&gt;What are the requirements to use mixed precision? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#what-are-the-requirements-to-use-mixed-precision%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;For mixed precision training to be an advantage you will need one of the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A Nvidia GPU with compute compatibility of 7.0 or above (you can get more details on &#39;compute compatibility&#39; and why Nvidia specifically in my previous article &lt;a href=&quot;https://towardsdatascience.com/how-to-pick-the-best-graphics-card-for-machine-learning-32ce9679e23b&quot;&gt;here&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;A TPU (Tensor Processing Unit)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/mixed-precision/graphics-cards-edited.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/mixed-precision/graphics-cards-edited.jpg&quot; alt=&quot;Two RTX 2080 graphics cards next to each other&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nanadua11?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Nana Dua&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/nvidia?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although you can use other GPUs for mixed precision, and it will run. You won&#39;t gain any real speed improvements without the items detailed above. However, if you are only looking for gains in RAM usage then it may still be worth it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Older GPUs offer no math performance benefit for using mixed precision, however memory and bandwidth savings can enable some speedups.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;when-should-i-use-mixed-precision%3F&quot; tabindex=&quot;-1&quot;&gt;When should I use mixed precision? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#when-should-i-use-mixed-precision%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The simple answer to this question is almost all the time, as the advantages greatly outweigh the disadvantages in most cases.&lt;/p&gt;
&lt;p&gt;The only thing to note is that if your models are relatively uncomplicated and small, you will likely not realise the difference. The larger and more complicated the models get, the more significant an advantage mixed precision is.&lt;/p&gt;
&lt;h1 id=&quot;how-do-i-use-mixed-precision%3F&quot; tabindex=&quot;-1&quot;&gt;How do I use mixed precision? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#how-do-i-use-mixed-precision%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In TensorFlow it is extremely easy, I&#39;m not that familiar with PyTorch, but I can&#39;t imagine it would be particularly difficult to implement either.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; tensorflow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; mixed_precision
mixed_precision&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_global_policy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mixed_float16&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and that&#39;s it.&lt;/p&gt;
&lt;p&gt;The only caveat to the above is that you should ensure that the inputs and outputs of the model are always float32. The inputs will likely be in float32 anyway, but just to be sure you can implicitly apply the dtype. For example:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;images &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uniform&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input_shape&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; minval&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; maxval&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; seed&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;SEED&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To ensure your output from your model is in float32, you can separate out the activation of the last layer of your model. For example:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Simple layer stack using the funcitonal API with separated activation layer as output&lt;/span&gt;

layer1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layer1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layer2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer4 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layer3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer5 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layer4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
output_layer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Activation&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sigmoid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layer5&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;custom-training-loops&quot; tabindex=&quot;-1&quot;&gt;Custom training loops &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#custom-training-loops&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Applying mixed precision to your models really is a simple as described in the previous section.&lt;/p&gt;
&lt;p&gt;However, if you are in a situation where you are not using &#39;model.fit&#39; because you are implementing your own training loop, then there are a few more steps to be aware of as you have to manually deal with loss scaling.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you use &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/keras/Model#fit&quot;&gt;&lt;code&gt;tf.keras.Model.fit&lt;/code&gt;&lt;/a&gt;, loss scaling is done for you so you do not have to do any extra work. If you use a custom training loop, you must explicitly use the special optimizer wrapper &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/keras/mixed_precision/LossScaleOptimizer&quot;&gt;&lt;code&gt;tf.keras.mixed_precision.LossScaleOptimizer&lt;/code&gt;&lt;/a&gt; in order to use loss scaling.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is important as float16 values are prone to &#39;underflow&#39; and &#39;overflow&#39; due to the smaller storage available compared to float32. All this essential means is that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;values above 65504 will overflow to infinity and values below 6.0×10−8 will underflow to zero.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To avoid this a strategy called loss scaling is utilised to mitigate this problem. For a deeper understanding I suggest taking a look at the &lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;mixed precision guide&lt;/a&gt; on &lt;a href=&quot;http://tensorflow.org/&quot;&gt;tensorflow.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;tpus&quot; tabindex=&quot;-1&quot;&gt;TPUs &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#tpus&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are lucky enough to have access to a dedicated TPU (Tensor Processing Unit) then it is just worth noting that you should be using data type &#39;&#39;bfloat16&amp;quot; rather than &amp;quot;float16&amp;quot;.&lt;/p&gt;
&lt;p&gt;It is no harder to implement, and doesn&#39;t suffer from the loss scaling problem as mentioned in the previous section.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; tensorflow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; mixed_precision
mixed_precision&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_global_policy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mixed_bfloat16&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;a-practical-example&quot; tabindex=&quot;-1&quot;&gt;A practical example &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#a-practical-example&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As an example of the potential gains, I have made available a colab notebook &lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/mixed_precision_training.ipynb&quot;&gt;&lt;img src=&quot;https://colab.research.google.com/assets/colab-badge.svg&quot; alt=&quot;Open In Colab&quot; /&gt;&lt;/a&gt; so that you can see the benefits for yourself. There are some notes at the beginning of the notebook in relation to the GPU you must use, so please make sure you read those to get the most out of the notebook.&lt;/p&gt;
&lt;p&gt;I will go through the outcomes from this notebook in the following subsections.&lt;/p&gt;
&lt;h2 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The data is random uniform noise formatted into the shape of a batch of images.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# create dummy images based on random data&lt;/span&gt;
SEED &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_seed&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SEED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
total_images &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;
input_shape &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total_images&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# (batch, height, width, channels)&lt;/span&gt;
images &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uniform&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input_shape&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; minval&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; maxval&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; seed&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;SEED&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is important to note that I have explicitly set the data type to be float32. In this case it would have made no difference as this is the default for the function. However, this may not always be the case depending on where your data comes from.&lt;/p&gt;
&lt;p&gt;An example image looks as follows:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/mixed-precision/image-of-input-data.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/mixed-precision/image-of-input-data.png&quot; alt=&quot;an example plot of the input data&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Image by &lt;a href=&quot;https://thetestspecimen.com/&quot;&gt;author&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I also created random binary labels so that the model can be a binary classification model.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;labels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;choice&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total_images&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-model&quot; tabindex=&quot;-1&quot;&gt;The model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#the-model&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The model has been chosen to be simple, but complicated enough to use a reasonable amount of RAM, and have a decent batch run time. This ensures that any differences between the mixed precision and &#39;normal&#39; run are distinguishable. These are the layers of the model:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;layer1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Conv2D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer4 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
layer5 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
output_layer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Activation&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sigmoid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, take note that the output activation layer is cast to float32. This makes no difference on the &#39;normal&#39; run, but is essential for the mixed precision run.&lt;/p&gt;
&lt;h2 id=&quot;the-test&quot; tabindex=&quot;-1&quot;&gt;The test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#the-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The model mentioned in the previous section was run using the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;total images = 800&lt;/li&gt;
&lt;li&gt;image size = 256 x 256&lt;/li&gt;
&lt;li&gt;batch size = 50&lt;/li&gt;
&lt;li&gt;epochs = 10&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;overall-run-time-and-epoch-runtime&quot; tabindex=&quot;-1&quot;&gt;Overall run time and epoch runtime &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#overall-run-time-and-epoch-runtime&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The images are then run through once using the timeit module to get an overall run time.&lt;/p&gt;
&lt;p&gt;The epoch run times are also printed.&lt;/p&gt;
&lt;h3 id=&quot;gpu-ram-usage&quot; tabindex=&quot;-1&quot;&gt;GPU RAM usage &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#gpu-ram-usage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get GPU RAM usage information the following function is used:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;experimental&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_memory_info&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;GPU:0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This outputs the current and peak GPU RAM usage. Before each run the peak usage is reset and compared to the current GPU RAM usage (they should therefore be the same). Then at the end of the run the same comparison is made. This allows the calculation of the actual GPU RAM used during the run.&lt;/p&gt;
&lt;h2 id=&quot;the-results&quot; tabindex=&quot;-1&quot;&gt;The Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#the-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Single precision (float32) model:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;Epoch &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 10s 463ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;90.4716&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5038&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 475ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9.1019&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6625&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 477ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.6142&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.8737&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 475ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.2461&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9488&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 482ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0486&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9800&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 489ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0044&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9975&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 494ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7.3721e-05&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 497ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.4208e-05&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 496ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.2936e-05&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 8s 490ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.1361e-05&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;

RAM INFO&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

Current&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.63&lt;/span&gt; GB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Peak&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9.18&lt;/span&gt; GB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; USED MEMORY FOR RUN&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8.55&lt;/span&gt; GB

TIME TO COMPLETE RUN&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;79.73&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mixed precision (mixed_float16) model:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;Epoch &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 15s 186ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;71.8095&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5025&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 184ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15.2121&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 182ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.4640&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.7900&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 183ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.1157&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9187&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 183ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.2525&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9600&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 181ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0284&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9925&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 182ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0043&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9962&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 182ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7.3278e-06&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 182ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.4797e-06&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;
Epoch &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 3s 182ms&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;step &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.5154e-06&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; accuracy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0000&lt;/span&gt;

RAM INFO&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

Current&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.63&lt;/span&gt; GB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Peak&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.19&lt;/span&gt; GB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; USED MEMORY FOR RUN&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.57&lt;/span&gt; GB

TIME TO COMPLETE RUN&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42.16&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think that is fairly conclusive:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Data Type&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Epoch run time [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Overall run time [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU RAM Usage [GB]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;float32&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;79.73&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;mixed_float16&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;42.16&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;3.57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Improvement&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Almost 3x faster&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Almost 2x faster&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Less than half the RAM usage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One thing you may note in the above results is that the initial epoch for the mixed precision run takes five times longer than the subsequent epochs, and even longer than the float32 run. This is normal, and is due to the optimisations that TensorFlow runs at the start of the learning process. However, even with this initial deficit, it doesn&#39;t take long for the mixed precision model to catch up and surpass the float32 model.&lt;/p&gt;
&lt;p&gt;The longer initial epoch for mixed precision also helps to illustrate why smaller models may not see the benefits, as there are initial overheads that need to be overcome to realise the advantages of mixed precision.&lt;/p&gt;
&lt;p&gt;This also happens to serve as a great example of overfitting. Both methods managed to achieve 100% accuracy on completely random data with completely random labels!&lt;/p&gt;
&lt;h1 id=&quot;the-future&quot; tabindex=&quot;-1&quot;&gt;The future &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#the-future&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The trend for lower precision calculations seems to be gaining traction, as with the latest generations of GPUs from Nvidia there are now implementations such as &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/config/experimental/enable_tensor_float_32_execution&quot;&gt;TensorFloat-32&lt;/a&gt;, which:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;automatically uses lower precision math in certain float32 ops such as &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/linalg/matmul&quot;&gt;&lt;code&gt;tf.linalg.matmul&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is also the case that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TPUs do certain ops in bfloat16 under the hood even with the default dtype policy of float32&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/mixed_precision&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As such, as time goes on it may not be necessary to actually implement mixed precision directly as it will all be taken care of under the hood.&lt;/p&gt;
&lt;p&gt;However, We are not there yet, so for now it is still worth the effort to consider utilising mixed precision training.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/mixed-precision/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The only conclusion to draw is that mixed precision is an excellent tool to speed up training, but more importantly free up GPU RAM.&lt;/p&gt;
&lt;p&gt;Hopefully, this article has helped you get a grasp of what mixed precision is all about, and I would encourage you to have a play around with the colab notebook to see if it fits your particular requirements, and get a feel for the benefits it could bring.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>The Best Methods for One-Hot Encoding Your Data</title>
		<link href="https://www.thetestspecimen.com/posts/one-hot-encoding/"/>
		<updated>Sun, 30 Oct 2022 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/one-hot-encoding/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Pre-processing data before feeding it into a machine / deep learning model is one of the most important phases in the whole process. Without properly pre-processed data it won’t matter how advanced and slick your model is, it will ultimately be inefficient and inaccurate.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One Hot Encoding is probably the most commonly utilised pre-processing method for independent categorical data, ensuring that the model can interpret the input data fairly, and without bias.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will explore the three most common methods of encoding categorical data using the one-hot method, and discuss why you would want to use this technique in the first place.&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The following methods are going to be compared and discussed in this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pandas&lt;/strong&gt; — get_dummies()&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scikit-Learn&lt;/strong&gt; — OneHotEncoder()&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keras&lt;/strong&gt; — to_categorical()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All methods basically achieve the same outcome. However, they go about it in completely different ways, and have different features and options.&lt;/p&gt;
&lt;p&gt;So which of these methods would be best suited for your specific circumstances?&lt;/p&gt;
&lt;h1 id=&quot;what-is-one-hot-encoding%3F&quot; tabindex=&quot;-1&quot;&gt;What is One-Hot Encoding? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#what-is-one-hot-encoding%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before we dive in I though it might be worthwhile giving a quick primer as to why you might want to use this method in the first place.&lt;/p&gt;
&lt;p&gt;One hot encoding is basically a way of preparing categorical data to ensure the categories are viewed as independent of each other by the machine learning / deep learning model.&lt;/p&gt;
&lt;h2 id=&quot;a-solid-example&quot; tabindex=&quot;-1&quot;&gt;A solid example &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#a-solid-example&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s give a practical example to really ram the idea home. We have three categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chicken&lt;/li&gt;
&lt;li&gt;Rock&lt;/li&gt;
&lt;li&gt;Gun&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are in no way related to each other, completely independent.&lt;/p&gt;
&lt;p&gt;To feed these categories into a machine learning model we need to turn them into numerical values, as machine / deep learning models cannot deal with any other type of input. So how best to do this?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/chicken.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/chicken.jpg&quot; alt=&quot;Running chicken&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A chicken on the run. Photo by &lt;a href=&quot;https://unsplash.com/@tumbao1949?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;James Wainscoat&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/chicken?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The most simple way is just to assign each category a number:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Chicken&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rock&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gun&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The problem with this approach (called ordinal encoding) is that the model can infer a relationship between the categories as the numbers follow each other.&lt;/p&gt;
&lt;p&gt;Is a gun more important than a chicken because it has a higher number? Is a chicken half a rock? If you have three chickens, is that the same as a gun?&lt;/p&gt;
&lt;p&gt;What if these values are labels, if the model outputs 1.5 as the answer, is that some sort of chicken-rock? All of these statements are nonsense, but as the model only sees numbers, not the names that we see, inferring these things is perfectly feasible for the model.&lt;/p&gt;
&lt;p&gt;To avoid this we need complete separation of the categories. This is what One-Hot Encoding achieves:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Chicken&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Rock&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Gun&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The values are only ever one or zero (on or off). One means it is that thing, and zero means it isn’t.&lt;/p&gt;
&lt;p&gt;So on the first row you have a chicken (no rock and no gun), the second row has a rock (no chicken and no gun) etc. As the values are either on or off, there is no possibility of relating one to the other in any way.&lt;/p&gt;
&lt;h1 id=&quot;a-quick-note&quot; tabindex=&quot;-1&quot;&gt;A quick note &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#a-quick-note&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before I dive into each of the three methods in more detail I just wanted to point out that I will be using an alternative to Colab, which I would typically use to make code available for the article.&lt;/p&gt;
&lt;p&gt;The alternative I will be using is &lt;a href=&quot;https://deepnote.com/&quot;&gt;deepnote&lt;/a&gt;. It is essentially the same as Colab in that it lets you run Jupyter notebooks in an online environment (there are some differences, which I won’t go into here, but check out the website to learn more).&lt;/p&gt;
&lt;p&gt;The main reason for this is that to demonstrate the latest features for some of the methods in this article, I needed access to Pandas 1.5.0 (the latest release at the time of writing), and I can’t seem to achieve this in Colab.&lt;/p&gt;
&lt;p&gt;However, in deepnote I can specify a Python version (in this case 3.10), and also make my own requirements.txt to ensure the environment installs Pandas 1.5.0, not the default version.&lt;/p&gt;
&lt;p&gt;It also allows very simple live embeds directly from the Jupyter notebook into this article (as you will see), which is very useful.&lt;/p&gt;
&lt;p&gt;I will still make the notebook available in colab as usual, but some of the code won’t run, so just bear that in mind.&lt;/p&gt;
&lt;h1 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The data¹²³ is basically related to the effects of alcohol consumption on exam results. Not something that you need to remember, but incase you are interested…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/alcohol.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/alcohol.jpg&quot; alt=&quot;Sloshing drink&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@viniciusamano?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Vinicius “amnx” Amano&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/alcohol?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As ever I have made the data available in a Jupyter notebook. You can access this in either deepnote:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fone_hot_encoding_comparison.ipynb%0A&quot;&gt;&lt;img src=&quot;https://deepnote.com/buttons/launch-in-deepnote.svg&quot; alt=&quot;Open In deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(as previously mentioned, Pandas 1.5.0 is available in deepnote. Just activate Python 3.10 in the &amp;quot;Environment&amp;quot; section on the right, and create a text file in the &amp;quot;Files&amp;quot; section on the right called &amp;quot;requirements.txt&amp;quot; with the line &amp;quot;pandas==1.5.0&amp;quot; in it. Then run the notebook.)&lt;/p&gt;
&lt;p&gt;or colab:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/one_hot_encoding_comparison.ipynb&quot;&gt;&lt;img src=&quot;https://colab.research.google.com/assets/colab-badge.svg&quot; alt=&quot;Open In Colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(some methods that follow will not work as Pandas 1.5.0 is required)&lt;/p&gt;
&lt;p&gt;I have selected a dataset that includes a wide range of different categorical and non-categorical columns so that it is easy to see how each of the methods works depending on the datatype. The columns are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;sex&lt;/strong&gt; — binary string (‘M’ for male and ‘F’ for female)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;age&lt;/strong&gt; — standard numerical column (int)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Medu&lt;/strong&gt; — Mother’s education — Multiclass integer representation (0 [none], 1 [primary education], 2 [5th to 9th grade], 3 [secondary education] or 4 [higher education])&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mjob&lt;/strong&gt; — Mother’s job — Multiclass string representation — (‘teacher’, ‘health’ care related, civil ‘services’ (e.g. administrative or police), ‘at_home’ or ‘other’)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dalc&lt;/strong&gt; — Workday alcohol consumption — Multiclass graduated integer representation (from 1 [very low] to 5 [very high])&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Walc&lt;/strong&gt; — Weekend alcohol consumption — Multiclass graduated integer representation (from 1 [very low] to 5 [very high])&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G3&lt;/strong&gt; — Final grade (the label) — Multiclass graduated integer representation (numeric: from 0 to 20)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example of the top five rows is as follows:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/31c9967c50f14cbebbeed0a560c87c85?height=387&quot; height=&quot;387px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;and the data types:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/8d4217d35ba9492784749280586926c6?height=337.625&quot; height=&quot;337.625px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h1 id=&quot;pandas-%E2%80%94-get_dummies()&quot; tabindex=&quot;-1&quot;&gt;Pandas — get_dummies() &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#pandas-%E2%80%94-get_dummies()&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/pandas.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/pandas.jpg&quot; alt=&quot;Two baby Pandas&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@millerthachiller?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Pascal Müller&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/panda?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;pandas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_dummies&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prefix&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prefix_sep&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;’_’&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dummy_na&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; columns&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sparse&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; drop_first&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://pandas.pydata.org/docs/reference/api/pandas.get_dummies.html&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I would describe the get_dummies() method from Pandas as a very middle of the road one-hot encoder. It keeps things simple while giving a reasonable amount of options to allow you to adjust to the most common use cases.&lt;/p&gt;
&lt;p&gt;You can very simply just pass a Pandas dataframe to get_dummies() and it will work out which columns are most suitable for one hot encoding.&lt;/p&gt;
&lt;p&gt;However, this is not the best way to approach things as you will see:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/66abace5caf346f1af2ae7b15109d02e?height=445&quot; height=&quot;445px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;If you review the output above you will see that only columns with type ‘Object’ have been one-hot encoded (sex and MJob). Any integer datatype columns have been ignored, which in our case is not ideal.&lt;/p&gt;
&lt;p&gt;However, you can specify the columns you wish to encode as follows:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/7b13f66914c649c8904e19a9e9907c9f?height=445&quot; height=&quot;445px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;One thing to note is that when using get_dummies() it keeps everything within the dataframe. There are no extra arrays to deal with. It is just all neatly kept in one place. This is not the case with OneHotEncoder() or to_categorical() methods, which will be discussed in subsequent sections.&lt;/p&gt;
&lt;p&gt;There may be specific circumstances where it is advisable, or useful to drop the first column of each one hot encoded series (for example to avoid multi-colinearity). get_dummies() has this ability built in:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/7e4ced3b447c460d886a9627db60214b?height=445&quot; height=&quot;445px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Note in the above how, for example, “Medu_0” is now missing.&lt;/p&gt;
&lt;p&gt;The way this now works is that if Medu_1 to Medu_4 are all zero, this effectively means Medu_0 (the only other alternative) is “selected”.&lt;/p&gt;
&lt;p&gt;Previously, when Medu_0 was included (i.e. drop_first wasn’t used), there would never have been a case where all values were zero. So in effect by dropping the column we don’t lose any information about the categories, but we do reduce the overall amount of columns, and therefore the processing power needed to run the model.&lt;/p&gt;
&lt;p&gt;There are more nuanced things to consider when deciding if dropping a column is appropriate, but as that discussion would warrant a whole article of it’s own, I will leave it for you to look into.&lt;/p&gt;
&lt;h2 id=&quot;additional-options&quot; tabindex=&quot;-1&quot;&gt;Additional options &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#additional-options&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apart from ‘drop_first’ there are also additional methods such as ‘sparse’ to produce a sparse matrix, and ‘dummy_na’ to help deal with NaN values that may be in your data.&lt;/p&gt;
&lt;p&gt;There are also a couple of customisations available for the prefix and separators, should you need that level of flexibility.&lt;/p&gt;
&lt;h2 id=&quot;reversing-get_dummies()-with-from_dummies()&quot; tabindex=&quot;-1&quot;&gt;Reversing get_dummies() with from_dummies() &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#reversing-get_dummies()-with-from_dummies()&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There was until very recently no available method for reversing get_dummies() from the Pandas library. You would have had to do this manually.&lt;/p&gt;
&lt;p&gt;However, as of &lt;strong&gt;Pandas 1.5.0&lt;/strong&gt; there is a new method called &lt;strong&gt;from_dummies()&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;pandas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;from_dummies&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sep&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default_category&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://pandas.pydata.org/docs/dev/reference/api/pandas.from_dummies.html&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This allows the reversal to be achieved without writing your own method. It can even handle the reversal of a one-hot encoding that utilised ‘drop_first’ with the use of the ‘default_category’ parameter as you will see below:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/cde94bdaa35b444da8e4e09913f92562?height=430&quot; height=&quot;430px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;To reverse when you have used ‘drop_first’ in the encoding you must specify the dropped items:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/b67e5a0843724ca0a3229cc05b2443fa?height=430&quot; height=&quot;430px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h1 id=&quot;scikit-learn-%E2%80%94-onehotencoder()&quot; tabindex=&quot;-1&quot;&gt;scikit-learn — OneHotEncoder() &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#scikit-learn-%E2%80%94-onehotencoder()&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/notebook-learn.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/notebook-learn.jpg&quot; alt=&quot;Learn written in a notebook&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kellysikkema?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Kelly Sikkema&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/learn?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The OneHotEncoder() method from Scikit-Learn is probably the most comprehensive of all the available methods for one hot encoding.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;sklearn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;preprocessing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OneHotEncoder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; categories&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; drop&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sparse&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;numpy.float64&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handle_unknown&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;error&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min_frequency&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max_categories&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see the method inputs above can handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;automatically picking out the categories for one hot encoding&lt;/li&gt;
&lt;li&gt;drop columns (not just the first, there are more extensive options available)&lt;/li&gt;
&lt;li&gt;produce sparse matrices&lt;/li&gt;
&lt;li&gt;handle categories that may appear in future datasets (handle_unknown)&lt;/li&gt;
&lt;li&gt;you can limit the amount of categories returned from the encoding based on frequency or a maximum number of categories&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The method also uses the fit-transform methodology, which is very useful for using this method in your input pipelines for machine and deep learning.&lt;/p&gt;
&lt;h2 id=&quot;the-encoder&quot; tabindex=&quot;-1&quot;&gt;The encoder &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#the-encoder&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the differences between this method and all the others is that you create an encoder ‘object’, which stores all the parameters that will be used to encode the data.&lt;/p&gt;
&lt;p&gt;This can therefore be referred back to, re-used and adjusted at later points in your code, making it a very flexible approach.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/357e0d46a7a649f7b0b7b4a605ed3fae?height=83&quot; height=&quot;83px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Once the encoder has been instantiated we can one-hot encode some data:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/5ff5464a637c4312b0f3c09ae1edf260?height=286.5&quot; height=&quot;286.5px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;In this case I have used the ‘fit_transform’ method, but as with all sklearn methods that follow the ‘fit’/’transform’ pattern you can also fit and transform the data in separate steps.&lt;/p&gt;
&lt;p&gt;What OneHotEncoder does is it extracts the columns that it thinks should be one-hot encoded and returns them as a new array.&lt;/p&gt;
&lt;p&gt;This is different to get_dummies(), which keeps the output in the same dataframe. If you want to keep all your data contained within a dataframe with minimal effort then this is something worth considering.&lt;/p&gt;
&lt;p&gt;It should also be noted that OneHotEncoder recognises more input columns that get_dummies() when on ‘auto’ as you can see below.&lt;/p&gt;
&lt;p&gt;Regardless, it is still good practise to specify the columns you wish to target.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/8a8395402a134cac82f28029061ae557?height=268.5&quot; height=&quot;268.5px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;For consistency moving forward, I will encode the same columns as we looked at previously with get_dummies():&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/bdb742dfc5774434b1d8df66acd2e8ec?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Columns that have been encoded, and the parameters of the encoder:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/c4826113a0c946c39495caac053adab0?height=172.5625&quot; height=&quot;172.5625px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/e7a9242a3e4b48098e8ea13945151913?height=249.3125&quot; height=&quot;249.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;reversing-onehotencoder&quot; tabindex=&quot;-1&quot;&gt;Reversing OneHotEncoder &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#reversing-onehotencoder&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is a very simple method for reversing the encoding, and as the encoder is saved as it’s own object (in this case ‘skencoder’), then all the original parameters used to do the one-hot encoding are saved within this object. This makes reversal very easy:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/e2faaabf74354353acbc499ecc62dcf3?height=249.3125&quot; height=&quot;249.3125px&quot; width=&quot;100%&quot;&gt;
&lt;h2 id=&quot;other-useful-information&quot; tabindex=&quot;-1&quot;&gt;Other useful information &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#other-useful-information&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another advantage to using OneHotEncoder is that there are a wealth of attributes and helper methods that give you access to the information used in the encoding. I have provided some examples below:&lt;/p&gt;
&lt;h3 id=&quot;attributes&quot; tabindex=&quot;-1&quot;&gt;Attributes &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#attributes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/9b5574f87aaf44fe80ee5ff3dd2bb286?height=208.5625&quot; height=&quot;208.5625px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/8d05cff9bfd04fb6bdbb78ef488f8ef1?height=170.1875&quot; height=&quot;170.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/6ccf214f1ef84085bc270ebafab6c3af?height=188.1875&quot; height=&quot;188.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;methods&quot; tabindex=&quot;-1&quot;&gt;Methods &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#methods&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/3a28463d7d6a45258c35268526c26d51?height=226.5625&quot; height=&quot;226.5625px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/81b4811751e4480c98e4170c4e221d57?height=285.3125&quot; height=&quot;285.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;advanced-features&quot; tabindex=&quot;-1&quot;&gt;Advanced Features &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#advanced-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned earlier OneHotEncoder has quite a lot of useful features making it a very flexible method to use.&lt;/p&gt;
&lt;p&gt;I will touch on some of these methods below.&lt;/p&gt;
&lt;h3 id=&quot;min-frequency&quot; tabindex=&quot;-1&quot;&gt;Min frequency &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#min-frequency&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This can be used to limit the encoded categories. If you have a feature that is dominated by a few significant categories, but has a lot of smaller categories, then you can effectively group the smaller categories into a single ‘other’ category.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/2116ea146eea4657be0e60e2b994c6ab?height=357.3125&quot; height=&quot;357.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/b7e7a42cd14248b69f1c0a440234d3c8?height=189.375&quot; height=&quot;189.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/b4a6e822fac349da8fde6f962c658ae1?height=170.1875&quot; height=&quot;170.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;You may find that you don’t want to specify an exact amount of records for the infrequent categories. In this case you could specify a minimum amount of records compared to the overall amount of records available. To do this you specify a fraction of the total count.&lt;/p&gt;
&lt;p&gt;In our case there are 395 records, so to achieve the same outcome as specifying exactly 60 records as the limit, we could specify 60 / 395 = 0.152, or for simplicity 0.16 (which basically means that a category has to have 16% of the total count to be counted as significant).&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/f3fbd53ab0e74f918997fdeb11bec926?height=285.3125&quot; height=&quot;285.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/d6b4ae85d93549219ab9d7aeec28a06c?height=189.375&quot; height=&quot;189.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/d08676a297f14e2da68e91aee4f1131e?height=170.1875&quot; height=&quot;170.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;max-categories&quot; tabindex=&quot;-1&quot;&gt;Max categories &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#max-categories&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another way to approach the problem is to specify a maximum number of categories.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/fe41d6f32bd0411bbc6cb0d3366dee7d?height=246.9375&quot; height=&quot;246.9375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/550975dc3bd0470abf19c7a1a9e52570?height=285.3125&quot; height=&quot;285.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/9f0848f553a244a9877f86319dd1eed1?height=170.1875&quot; height=&quot;170.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/d451c3f07d8f43a59e4ac728065d696e?height=170.1875&quot; height=&quot;170.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;handle-unknown&quot; tabindex=&quot;-1&quot;&gt;Handle Unknown &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#handle-unknown&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Handle unknown is an extremely useful feature, especially when used in a pipeline for machine learning, or neural network model.&lt;/p&gt;
&lt;p&gt;It essentially allows you to plan for a case in the future where another category may appear, without breaking your input pipeline.&lt;/p&gt;
&lt;p&gt;For example, you may have a feature such as ‘Medu’, and in the future for some reason a ‘PhD’ category above the final category of ‘higher education’ is added to the input data. In theory, this additional category would break your input pipeline, as the amount of categories has changed.&lt;/p&gt;
&lt;p&gt;Handle unknown allows us to avoid this.&lt;/p&gt;
&lt;p&gt;Although I’m not going to give a concrete example of this, it is very easy to understand, especially if you have read the previous two sections on ‘max_categories’ and ‘min_frequency’.&lt;/p&gt;
&lt;p&gt;Setting options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;‘error’&lt;/strong&gt; : this will just raise an error if you try to add additional category, you could say this is standard behaviour&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;‘ignore’&lt;/strong&gt; : this will cause any extra categories to be encoded with all zeros, so if there were originally 3 categories [1,0,0], [0,1,0] and [0,0,1] then the additional category (or categories) will be encoded as [0,0,0]. When inverted this will have the value ‘None’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;‘infrequent_if_exist’&lt;/strong&gt; : if you have implemented ‘max_categories’ or ‘min_frequency’ in your encoder, then the additional category will be mapped to ‘xxx_infrequent_sklearn’ along with any infrequent categories. Otherwise it will be treated exactly the same as ‘ignore’.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; you cannot use handle_unknown=’ignore’ &lt;strong&gt;AND&lt;/strong&gt; the drop category parameter (e.g. drop: ‘first’) at the same time. This is because they both produce a category with all zeros, and therefore conflict.&lt;/p&gt;
&lt;h3 id=&quot;drop&quot; tabindex=&quot;-1&quot;&gt;Drop &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#drop&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As with Pandas from_dummies() you have the option to drop categories, although the options are a little more extensive.&lt;/p&gt;
&lt;p&gt;Here are the options (as per the documentation):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;None&lt;/strong&gt; : retain all features (the default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;‘first’&lt;/strong&gt; : drop the first category in each feature. If only one category is present, the feature will be dropped entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;‘if_binary’&lt;/strong&gt; : drop the first category in each feature with two categories. Features with 1, or more than 2 categories, are left intact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;array&lt;/strong&gt; : drop[i] is the category in feature X[:, i] that should be dropped.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; you cannot use handle_unknown=’ignore’ &lt;strong&gt;AND&lt;/strong&gt; the drop category parameter (e.g. drop: ‘first’) at the same time. This is because they both produce a category with all zeros, and therefore conflict.&lt;/p&gt;
&lt;h4 id=&quot;%E2%80%98first%E2%80%99&quot; tabindex=&quot;-1&quot;&gt;‘first’ &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#%E2%80%98first%E2%80%99&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first entry of each category will be dropped (‘sex_F’, ‘Medu_0’ and ‘Mjob_at_home’).&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/2681f7fcb3604d32bdb31c5de0995d40?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/d083e30b8fc44219bf5effeffd5d0ee9?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/f019c13bb56149e0b7c6453a24e5d53b?height=207.375&quot; height=&quot;207.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h4 id=&quot;%E2%80%98if_binary%E2%80%99&quot; tabindex=&quot;-1&quot;&gt;‘if_binary’ &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#%E2%80%98if_binary%E2%80%99&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Only features with exactly two categories will be affected (in our case only ‘sex_F’ is dropped).&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/edfdd8437d95458884fbf29f56642ada?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/611212af6f2940bd8f64161cc7d956d2?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/a2b0f289c6a24a069194b3e063d20277?height=208.5625&quot; height=&quot;208.5625px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h4 id=&quot;%E2%80%98array%E2%80%99&quot; tabindex=&quot;-1&quot;&gt;‘array’ &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#%E2%80%98array%E2%80%99&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this case you can pick exactly which category from each feature should be dropped. We will drop ‘sex_M’, ‘Medu_3’ and ‘Mjob_other’.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/8661e309fff94b1591762adae50b9e98?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/bc101f3994814a40bc5daaeefd2e96ce?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/4e76ec8a9dda429f85276cb09c07a695?height=189.375&quot; height=&quot;189.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h1 id=&quot;keras-to_categorical&quot; tabindex=&quot;-1&quot;&gt;Keras to_categorical &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#keras-to_categorical&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/drawers.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/drawers.jpg&quot; alt=&quot;A wall of small wooden drawers&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jankolar?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Jan Antonin Kolar&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/sorting?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Keras method is a very simple method, and although it can be used for anything just like the other methods, it can only handle numeric values.&lt;/p&gt;
&lt;p&gt;Therefore, if you have string categories you will have to convert them first, something that the other methods take care of automatically.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keras&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_categorical&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_classes&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;float32&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/keras/utils/to_categorical&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Keras to_categorical() is probably most useful for one hot encoding the labels:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/e024258bf42a4fc385a2931c6e27416e?height=575.5&quot; height=&quot;575.5px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/c0f0fb637af44a59bbef8b1239986b16?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The above doesn’t tell us a lot so let’s pick out the transformation at index 5 so we can see what was encoded:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/77a162a57f554990a06c27c41a387741?height=153.375&quot; height=&quot;153.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;reversal&quot; tabindex=&quot;-1&quot;&gt;Reversal &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#reversal&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no dedicated method for reversal, but typically argmax should allow us to reverse the encoding. Argmax will also work from the output of models where the numbers may not be whole integers.&lt;/p&gt;
&lt;p&gt;Smaller example:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/822ac1a44baf4441bb4b6d2a4b0af838?height=134.1875&quot; height=&quot;134.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;All the data:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/33da7cc4d86644118c289e330c2aad07?height=575.5&quot; height=&quot;575.5px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;specify-categories&quot; tabindex=&quot;-1&quot;&gt;Specify categories &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#specify-categories&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One useful feature is the ability to specify how many unique categories there are. By default the amount of categories is the highest number in the array + 1. The +1 is to take account of zero.&lt;/p&gt;
&lt;p&gt;It is worth noting that this is the minimum value you can specify. However, there may be cases where the data passed does not contain all the categories and you still wish to convert it (like a small set of test labels), in which case you should specify the number of classes.&lt;/p&gt;
&lt;p&gt;Even though the method requires whole numbers, it can deal with the float datatype as per the below.&lt;/p&gt;
&lt;p&gt;These are the unique classes:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/3874b6e3e5444132a00858423d916f67?height=153.375&quot; height=&quot;153.375px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;This is the count of the unique classes:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/a7488ec1f7b34d6b945f1a75e141bf23?height=134.1875&quot; height=&quot;134.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;There are only 18 unique classes, but we can encode as many as we want, so let’s encode 30 classes:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/cf826bfd48d94d8a84918a81cd9e395a?height=267.3125&quot; height=&quot;267.3125px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;We can then check the shape to see that we have 30 columns / classes:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/112faccf244347c6bd0375fe32c29fd1?height=134.1875&quot; height=&quot;134.1875px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;…and still reverse without issue:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/668fea72-6c55-453b-98ea-fb3354dc106c/5a7e9a90bd6e439d8752ec3401793d76/b07217acd7be429fb3ea1641928be787?height=575.5&quot; height=&quot;575.5px&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h1 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As a general roundup:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pandas — get_dummies()&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;creates one hot encoded columns within a dataframe without creating a new matrix. If you prefer to keep everything within a Pandas dataframe with minimal effort this may be the method for you&lt;/li&gt;
&lt;li&gt;can only &lt;strong&gt;automatically&lt;/strong&gt; recognise non-numeric columns as categorical data&lt;/li&gt;
&lt;li&gt;has a few useful options such as sparse matrices and dropping the first column&lt;/li&gt;
&lt;li&gt;as of Pandas 1.5.0 has a reversal method built in&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Scikit-learn — OneHotEncoder():&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is designed to work with Pipelines, and so is easy to integrate into your pre-processing workflow&lt;/li&gt;
&lt;li&gt;can automatically pick out the categories for one hot encoding, including numerical columns&lt;/li&gt;
&lt;li&gt;drop columns (not just the first, there are more extensive options available)&lt;/li&gt;
&lt;li&gt;produce sparse matrices&lt;/li&gt;
&lt;li&gt;various options for handling categories that appear in future datasets (handle_unknown)&lt;/li&gt;
&lt;li&gt;you can limit the amount of categories returned from the encoding based on frequency or a maximum number of categories&lt;/li&gt;
&lt;li&gt;has many helper methods and attributes to keep track of your encoding and parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Keras — to_categorical():&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a very simple method that one hot encodes only numerical data&lt;/li&gt;
&lt;li&gt;data must be converted to ordinal numerical categories first&lt;/li&gt;
&lt;li&gt;is probably most useful for labels&lt;/li&gt;
&lt;li&gt;has no built in reversal method&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;All in all, if I had to recommend any one method it would be the &lt;strong&gt;OneHotEncoder() from Scikit-Learn&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You could argue that the method is over complicated. However, I would argue that the method is very simple to use, and you ultimately gain both traceability and flexibility that is not achievable with any of the other methods.&lt;/p&gt;
&lt;p&gt;The ability to combine this pre-processing method along with others into a processing pipeline, and features such as handle_unknown, are also a huge advantage when considering production ready code.&lt;/p&gt;
&lt;h1 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/one-hot-encoding/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;[1] Aman Chauhan, &lt;a href=&quot;https://www.kaggle.com/datasets/whenamancodes/alcohol-effects-on-study&quot;&gt;Alcohol Effects On Study&lt;/a&gt; (2022), Kaggle, License: &lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/&quot;&gt;Attribution 4.0 International (CC BY 4.0)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] Paulo Cortez, &lt;a href=&quot;https://archive.ics.uci.edu/ml/datasets/student+performance&quot;&gt;Student Performance Data Set&lt;/a&gt; (2014), UCI Machine Learning Repository&lt;/p&gt;
&lt;p&gt;[3] P. Cortez and A. Silva, &lt;a href=&quot;http://www3.dsi.uminho.pt/pcortez/student.pdf&quot;&gt;Using Data Mining to Predict Secondary School Student Performance&lt;/a&gt; (2008), In A. Brito and J. Teixeira Eds., Proceedings of 5th FUture BUsiness TEChnology (FUBUTEC) Conference pp. 5–12, Porto, Portugal, April, 2008, EUROSIS, ISBN 978–9077381–39–7&lt;/p&gt;
&lt;/iframe&gt;
		</content>
	</entry>
	
	<entry>
		<title>Is Julia Really Faster than Python and Numpy?</title>
		<link href="https://www.thetestspecimen.com/posts/julia-python/"/>
		<updated>Fri, 11 Nov 2022 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/julia-python/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Python, along with the numpy/pandas libraries, has essentially become the language of choice for the data science profession (…I’ll add a quick nod to R here).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;However, it is well known that Python, although fast and easy to implement, is a slow language. Hence the need for excellent libraries like numpy to increase efficiency…but what if there was a better alternative?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Julia claims to be at least as easy and intuitive to use as Python, whilst being significantly faster to execute. Let’s put that claim to the test…&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;what-is-julia%3F&quot; tabindex=&quot;-1&quot;&gt;What is Julia? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#what-is-julia%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Just in case you have no idea what Julia is, here is a quick primer.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://julialang.org/&quot;&gt;Julia&lt;/a&gt; is an open source language that is dynamically typed, intuitive, and easy to use like Python, but with the speed of execution of a language like C.&lt;/p&gt;
&lt;p&gt;It has been around approximately 10 years (born in 2012), so it is a relatively new language. However, it is at a stage of maturity where you wouldn’t call it a fad.&lt;/p&gt;
&lt;p&gt;The original creators of the language are active in a relevant field of work:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the work we do — scientific computing, machine learning, data mining, large-scale linear algebra, distributed and parallel computing — …&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;julialang.org&lt;/a&gt; — Jeff Bezanson, Stefan Karpinski, Viral B. Shah, Alan Edelman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All in all, it is a &lt;strong&gt;modern language specifically designed to be used in the field of data science&lt;/strong&gt;. The aims of the creators themselves tell you a great deal:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We want the speed of C with the dynamism of Ruby. We want a language that’s homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab. We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell. Something that is dirt simple to learn, yet keeps the most serious hackers happy. We want it interactive and we want it compiled.&lt;/p&gt;
&lt;p&gt;(Did we mention it should be as fast as C?)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://julialang.org/blog/2012/02/why-we-created-julia/&quot;&gt;julialang.org&lt;/a&gt; — Jeff Bezanson, Stefan Karpinski, Viral B. Shah, Alan Edelman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds quite exciting right?&lt;/p&gt;
&lt;h1 id=&quot;the-basis-of-the-speed-test&quot; tabindex=&quot;-1&quot;&gt;The basis of the speed test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#the-basis-of-the-speed-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have written an article previously looking at vectorization using the numpy library in Python:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://towardsdatascience.com/how-to-speedup-data-processing-with-numpy-vectorization-12acac71cfca&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/clock.jpg&quot; alt=&quot;How to Speed up Data Processing with Numpy Vectorization&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;How to Speedup Data Processing with Numpy Vectorization | Towards Data Science&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Up to 8000 times faster than normal functions&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;Michael Clayton - Towards Data Science&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;The speed test that will be conducted in this article will basically be an extension / comparison to this article.&lt;/p&gt;
&lt;h1 id=&quot;how-will-the-test-work%3F&quot; tabindex=&quot;-1&quot;&gt;How will the test work? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#how-will-the-test-work%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A comparison will be made between the speed of execution of a simple mathematical statement:&lt;/p&gt;
&lt;h3 id=&quot;function-1-%E2%80%94-simple-summation&quot; tabindex=&quot;-1&quot;&gt;Function 1 — Simple summation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#function-1-%E2%80%94-simple-summation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#Python&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sum_nums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#Julia&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; sum_nums&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and more complicated conditional statement:&lt;/p&gt;
&lt;h3 id=&quot;function-2-%E2%80%94-more-complex-(logic-and-arithmetic)&quot; tabindex=&quot;-1&quot;&gt;Function 2 — More complex (logic and arithmetic) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#function-2-%E2%80%94-more-complex-(logic-and-arithmetic)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#Python&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;categorise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;elif&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#Julia&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; categorise&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;Float32
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;elseif&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When run through the following methods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Python- pandas.itertuples()&lt;/li&gt;
&lt;li&gt;Python- list comprehension&lt;/li&gt;
&lt;li&gt;Python- numpy.vectorize()&lt;/li&gt;
&lt;li&gt;Python- native pandas method&lt;/li&gt;
&lt;li&gt;Python- native numpy method&lt;/li&gt;
&lt;li&gt;Julia- native method&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;the-notebooks-for-this-article&quot; tabindex=&quot;-1&quot;&gt;The notebooks for this article &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#the-notebooks-for-this-article&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-python/notebook.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/notebook.jpg&quot; alt=&quot;A notebook&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/white-spiral-notebook-beside-orange-pencil-544115/&quot;&gt;Tirachard Kumtanom&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The previous article included a Jupyter notebook written in Python. I have taken this notebook (unchanged) from the previous article, and re-run it using a &lt;a href=&quot;https://deepnote.com/&quot;&gt;deepnote&lt;/a&gt; instance which utilises Python 3.10.&lt;/p&gt;
&lt;p&gt;The deepnote instance for both the Python runs, and the Julia runs, has &lt;strong&gt;the exact same&lt;/strong&gt; basic CPU instance (i.e. hardware). This ensures that the timed results included with this article are directly comparable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I have made sure to include the CPU information in each notebook so you can see what exact hardware was used, and that they were in fact exactly the same.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;running-the-julia-notebook&quot; tabindex=&quot;-1&quot;&gt;Running the Julia notebook &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#running-the-julia-notebook&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is worth noting that whether you wish to use the notebooks in &lt;a href=&quot;https://deepnote.com/&quot;&gt;deepnote&lt;/a&gt; as I have, or in &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;colab&lt;/a&gt;, you will need to setup Julia in the respective environments. This is mainly because most public online instances are currently setup for Python only (at least out of the box).&lt;/p&gt;
&lt;h2 id=&quot;environment-setup&quot; tabindex=&quot;-1&quot;&gt;Environment Setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#environment-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;deepnote&quot; tabindex=&quot;-1&quot;&gt;Deepnote &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#deepnote&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As deepnote utilises docker instances, you can very easily setup a ‘local’ dockerfile to contain the install instructions for Julia. This means you don’t have to pollute the Jupyter notebook with install code, as you will have to do in Colab.&lt;/p&gt;
&lt;p&gt;In the environment section select “Local ./Dockerfile”. This will open the actual Dockerfile where you should add the following:&lt;/p&gt;
&lt;pre class=&quot;language-docker&quot;&gt;&lt;code class=&quot;language-docker&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; deepnote/python:3.10&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; wget https://julialang-s3.julialang.org/bin/linux/x64/1.8/julia-1.8.2-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    tar -xvzf julia-1.8.2-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    mv julia-1.8.2 /usr/lib/ &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    ln -s /usr/lib/julia-1.8.2/bin/julia /usr/bin/julia &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    rm julia-1.8.2-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    julia  -e &lt;span class=&quot;token string&quot;&gt;&quot;using Pkg;pkg&#92;&quot;add IJulia&#92;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENV&lt;/span&gt; DEFAULT_KERNEL_NAME &lt;span class=&quot;token string&quot;&gt;&quot;julia-1.8&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can update the above to the latest Julia version from &lt;a href=&quot;https://julialang.org/downloads/&quot;&gt;this&lt;/a&gt; page, but at the time of writing 1.8.2 is the latest version.&lt;/p&gt;
&lt;h3 id=&quot;colab&quot; tabindex=&quot;-1&quot;&gt;Colab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#colab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For colab all the download and install code will have to be included in the notebook itself, as well as refreshing the page once the install code has run.&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;a href=&quot;https://github.com/ageron&quot;&gt;Aurélien Geron&lt;/a&gt; (…that name will be familiar to a few here I recon) has made available on his GitHub a &lt;a href=&quot;https://colab.research.google.com/github/ageron/julia_notebooks/blob/master/Julia_Colab_Notebook_Template.ipynb&quot;&gt;starter notebook&lt;/a&gt; for Julia in colab, which is probably the best way to get started.&lt;/p&gt;
&lt;h2 id=&quot;the-notebooks&quot; tabindex=&quot;-1&quot;&gt;The notebooks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#the-notebooks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The raw notebooks can be found here:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/julia-python-comparison&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/github.jpg&quot; alt=&quot;Notebooks on thetestspecimen github&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/julia-python-comparison at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;…or get kickstarted in either deepnote or colab.&lt;/p&gt;
&lt;p&gt;Python Notebook:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fjulia-python-comparison%2Fpython.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch python notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/julia-python-comparison/python.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Julia Notebook:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fjulia-python-comparison%2Fjulia.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch julia notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/julia-python-comparison/julia.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch julia notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-results&quot; tabindex=&quot;-1&quot;&gt;The Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#the-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-python/graph-paper.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/graph-paper.jpg&quot; alt=&quot;Paper with graphs&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/photo/person-pointing-paper-line-graph-590041/&quot;&gt;Lukas&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you haven’t read &lt;a href=&quot;https://medium.com/towards-data-science/how-to-speedup-data-processing-with-numpy-vectorization-12acac71cfca&quot;&gt;my previous article on numpy vectorization&lt;/a&gt; I would encourage you to (obviously!), as it will help you get an idea of how the Python methods stack up before we jump into the Julia results.&lt;/p&gt;
&lt;p&gt;All will be summarised and compared at the end of the article, so don’t worry too much if you don’t have the time.&lt;/p&gt;
&lt;h2 id=&quot;the-input-data&quot; tabindex=&quot;-1&quot;&gt;The input data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#the-input-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Define a random number generator, and two columns of one million random numbers taken from a normal distribution, just like in the numpy vectorization article:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/c3b6de9a91024d80a52b7de839a16065?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/8d5a517f84ba4503b8ef3d3179386473?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/d4931a4f310944249c76d1dd0073662a?height=524.1875&quot; height=&quot;524.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;function-1-%E2%80%94-simple-summation-1&quot; tabindex=&quot;-1&quot;&gt;Function 1 — Simple summation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#function-1-%E2%80%94-simple-summation-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/dc5456d3efa94d52a189dc9681bdf6d7?height=206.1875&quot; height=&quot;206.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Using Julia’s &lt;a href=&quot;https://github.com/JuliaCI/BenchmarkTools.jl&quot;&gt;BenchmarkTools&lt;/a&gt; it is possible to automatically get a fair estimate of the functions performance, as the “@benchmark” method will automatically decide how many times to evaluate the function to attain a fair estimate of runtime. It also provides a wealth of statistics as can be seen below:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/18e5e4f8ca4c4a6094c2131c4594a031?height=306.875&quot; height=&quot;306.875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;To gain a fair comparison to the Python methods the mean time will be used, which in this case is 711.7 micro seconds (or &lt;strong&gt;0.71 milliseconds&lt;/strong&gt;) to sum a 1 million element array with another 1 million element array.&lt;/p&gt;
&lt;h3 id=&quot;function-2-%E2%80%94-more-complex-(logic-and-arithmetic)-1&quot; tabindex=&quot;-1&quot;&gt;Function 2 — More complex (logic and arithmetic) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#function-2-%E2%80%94-more-complex-(logic-and-arithmetic)-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/f9d38d42aa7e48f9ab6594ef612c03d9?height=278.1875&quot; height=&quot;278.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;An example of what the method returns:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/3432cb7cb4ac437296d5c6142f791d55?height=724&quot; height=&quot;724&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The benchmark:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/06398b0fdfbc465ca3f7f17e861c2abb?height=306.875&quot; height=&quot;306.875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;So the more involved method results in a mean execution time of &lt;strong&gt;7.62 milliseconds&lt;/strong&gt;.&lt;/p&gt;
&lt;h1 id=&quot;how-does-this-compare-to-python%3F&quot; tabindex=&quot;-1&quot;&gt;How does this compare to Python? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#how-does-this-compare-to-python%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-python/pineapples.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/pineapples.jpg&quot; alt=&quot;Two pineapples in peoples hands&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/photo/two-people-holding-pineapple-fruits-against-a-multicolored-wall-4412925/&quot;&gt;Maksim Goncharenok&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now for the actual comparison. Firstly lets see what the results look like all together:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Method&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function 1 (Simple) [ms]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Function 2 (Complex) [ms]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Python(Pandas): iter tuples&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;419.14&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;419.22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Python: list comprehension&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;179.64&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;188.33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Python(Numpy): vectorize&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;163.07&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;140.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Python(Pandas): native&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.96&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Python(Numpy): native&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.81&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Julia: native&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.71&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Table — All Results&lt;/em&gt;&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/0e8e4a2f68494e41a98e69725a5de55f?height=475&quot; height=&quot;475&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;em&gt;Figure 1 — All Results&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Then we can proceed to break it down a little.&lt;/p&gt;
&lt;h2 id=&quot;results%3A-function-1-%E2%80%94-simple&quot; tabindex=&quot;-1&quot;&gt;Results: Function 1 — Simple &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#results%3A-function-1-%E2%80%94-simple&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is quite clear from Figure 1 for the simple summation function that there is a lot to be gained from ensuring you are using optimised libraries such as numpy where Python is concerned. The difference is so large the faster methods almost look to be zero.&lt;/p&gt;
&lt;p&gt;I covered the reasoning for this in my &lt;a href=&quot;https://towardsdatascience.com/how-to-speedup-data-processing-with-numpy-vectorization-12acac71cfca&quot;&gt;previous article&lt;/a&gt; on numpy vectorization, so if you want more details please refer to that.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/722e08025802458981c86561cb808c9e?height=475&quot; height=&quot;475&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;em&gt;Figure 2 — Simple Function Fastest Three Results&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, even optimised Python libraries are insufficient to elevate the execution speed to the level of a language that is designed to be fast from the ground up.&lt;/p&gt;
&lt;p&gt;As you can see in Figure 2, in this specific test &lt;strong&gt;Julia is 14% faster&lt;/strong&gt; using a native inbuilt implementation, compared to an optimised library in Python (numpy) that utilises execution in C under the hood.&lt;/p&gt;
&lt;h2 id=&quot;results%3A-function-2-complex&quot; tabindex=&quot;-1&quot;&gt;Results: Function 2-Complex &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#results%3A-function-2-complex&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although the previous result is already impressive, in the second test Julia blows the competition out of the water.&lt;/p&gt;
&lt;p&gt;As explained in my &lt;a href=&quot;https://medium.com/towards-data-science/how-to-speedup-data-processing-with-numpy-vectorization-12acac71cfca&quot;&gt;previous article&lt;/a&gt; it is not possible to implement a ‘native’ version of the complex function in numpy, so we instantly lose the closest competitors from the previous round.&lt;/p&gt;
&lt;p&gt;Even the method ‘Vectorize’ from numpy can’t hold a candle to Julia in this instance.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/ba5d412a-eb5b-429c-982a-4b9106975d01/5d29aa51fca2414893932d3ba47f095d/5abe832dee71421297d4dcea477f0211?height=475&quot; height=&quot;475&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;em&gt;Figure 3— Complex Function Fastest Two Results&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Julia is a full &lt;strong&gt;18 times faster&lt;/strong&gt; than numpy vectorize at completing the more complex calculation.&lt;/p&gt;
&lt;h2 id=&quot;so-what-happened%3F&quot; tabindex=&quot;-1&quot;&gt;So what happened? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#so-what-happened%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the ways numpy is so fast in certain circumstances, is that it is using &lt;strong&gt;pre-compiled&lt;/strong&gt; and optimised C functions to execute the calculations. As you may be aware C is extremely fast if used correctly. However, the important point is that: If something is &lt;strong&gt;pre-compiled&lt;/strong&gt;, then it is inherently fixed.&lt;/p&gt;
&lt;p&gt;What this illustrates is that if your calculation is simple (like Function 1), and has a predefined &lt;strong&gt;optimised&lt;/strong&gt; function within the numpy library, execution times are &lt;em&gt;almost&lt;/em&gt; the same as Julia.&lt;/p&gt;
&lt;p&gt;However, if the calculation you want to perform is a bit more convoluted or bespoke, and not covered by an optimised numpy function, you will be out of luck when it comes to speed. This is because you will have to rely on standard Python to fill the gap, which results in the large disparity we see in Figure 2 for the ‘complex’ function.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In terms of answering: &lt;strong&gt;Is Julia really faster than Python and Numpy?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, yes it is, and in some cases by a large margin.&lt;/p&gt;
&lt;p&gt;As always, it is important to take these results for what they are, a small comparison of some specific functions. Even so, the results are real and relevant all the same. Julia is a fast language, and although we haven’t touched on it much in this article, it is actually very intuative to use as well.&lt;/p&gt;
&lt;p&gt;If you want a more general guide as to how fast Julia is compared to a wider array of languages then you can take a look at the general benchmarks on Julia’s own website:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://julialang.org/benchmarks/&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/julia.jpg&quot; alt=&quot;Julia benchmark comparisons&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;Julia Micro-Benchmarks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;The official website for the Julia Language. Julia is a language that is fast, dynamic, easy to use, and open source. Click here to learn more.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;Jeff Bezanson, Stefan Karpinski, Viral Shah, Alan Edelman, et al. - julialang.org&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;Same result, it is in a league of it’s own, especially in the data science world. Unless of course you write all your code in C.&lt;/p&gt;
&lt;h1 id=&quot;a-final-question%E2%80%A6&quot; tabindex=&quot;-1&quot;&gt;A final question… &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-python/#a-final-question%E2%80%A6&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-python/question-mark.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-python/question-mark.jpg&quot; alt=&quot;Two pineapples in peoples hands&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Image by &lt;a href=&quot;https://pixabay.com/users/qimono-1962238/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1872634&quot;&gt;Arek Socha&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1872634&quot;&gt;Pixabay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If Julia is so good, why doesn’t it have the same traction and recognition as Python/Pandas/NumPy/R?&lt;/p&gt;
&lt;p&gt;I think the answer to that question is mainly time. It just hasn’t been around long enough, but the reality is that Julia is on the up, and at some point it is likely (at least in my opinion) that it will take over in the field of data science. It is already being used by the likes of Microsoft, Google, Amazon, Intel, IBM and Nasa, for example.&lt;/p&gt;
&lt;p&gt;Python and R are industry standards at this stage, and that will take a lot of momentum to change, regardless of how good the new upstart is.&lt;/p&gt;
&lt;p&gt;A additional factor is the availability of learning resources. Again, just due to time, and the sheer volume of people using Python and R for data science, resources to learn from are plentiful. Whereas for Julia although there is plenty of documentation, it can’t really compete for overall learning resources (yet!).&lt;/p&gt;
&lt;p&gt;…but if you are feeling adventurous I encourage you to give Julia a go and see what you think.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Julia’s Flux vs Python’s TensorFlow - How Do They Compare?</title>
		<link href="https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/"/>
		<updated>Fri, 02 Dec 2022 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;In my&lt;/strong&gt; &lt;a href=&quot;https://towardsdatascience.com/is-julia-really-faster-than-python-and-numpy-242e0a5fe34f&quot;&gt;&lt;strong&gt;previous article&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;I looked at what sort of advantage Julia has over Python/Numpy in terms of speed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Although this is useful to know, it isn’t the whole story. It is also important to understand how they compare in terms of syntax, library availability / integration, flexibility, documentation, community support etc.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article runs though an image classification deep learning problem from start to finish in both TensorFlow and Flux (Julia’s native TensorFlow equivalent). This should give a good overview of how the two languages compare in general usage, and hopefully help you get an insight into whether Julia is a potential option (or advantage) for you in this context.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I will also endeavour to highlight the advantages, and more importantly the gaps, or failings, that currently exist in the Julia ecosystem when compared to the tried and tested pairing of Python and TensorFlow.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have deliberately chosen an image classification problem for this particular exploration, as it throws up some nice challenges in both data preparation, and for the deep learning frameworks themselves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the images need to be loaded from disk (a ready prepared dataset such as MNIST will not be used), so loading and pre-processing methods and conventions will be explored&lt;/li&gt;
&lt;li&gt;images are typically represented as 3D-matrices (height, width, colour channels), so careful attention to dimensional ordering will be required&lt;/li&gt;
&lt;li&gt;to avoid over-fitting, image augmentation is typically required, allowing for an exploration into library availability and ease of use&lt;/li&gt;
&lt;li&gt;images are inherently a ‘large’ data type in terms of space requirements, which forces an investigation into batching, RAM allocation and GPU usage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Although code snippets will be made available throughout the article, Jupyter notebooks are available containing a full working end-to-end (image download through to model training) implementation of both the Julia and Python versions of the code. See the next section for links to the notebooks.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Incidentally, if this is the first time you have heard of Julia I recommend reading the “What is Julia?” section of my previous article to get a quick primer:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://towardsdatascience.com/is-julia-really-faster-than-python-and-numpy-242e0a5fe34f&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/laptop-fast-typing.jpg&quot; alt=&quot;Is Julia Really Faster than Python and Numpy?&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;Is Julia Really Faster than Python and Numpy? | Towards Data Science&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;The speed of C with the simplicity of Python&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;Michael Clayton - Towards Data Science&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h1 id=&quot;reference-notebooks&quot; tabindex=&quot;-1&quot;&gt;Reference Notebooks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#reference-notebooks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This section gives details on the location of the notebooks, and also the requirements for the environment setup for online environments such as &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Colab&lt;/a&gt; and &lt;a href=&quot;https://deepnote.com/&quot;&gt;Deepnote&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-notebooks&quot; tabindex=&quot;-1&quot;&gt;The notebooks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#the-notebooks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The raw notebooks can be found here for your local environment:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/julia-python-image-classification&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/favicon/maskable_icon_x512.png&quot; alt=&quot;Julia&#39;s Flux vs Python&#39;s TensorFlow Reference Notebooks&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/julia-python-image-classification at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;…or get kickstarted in either deepnote or colab.&lt;/p&gt;
&lt;p&gt;Python Notebook:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fjulia-python-image-classification%2Frps_python_tensorflow.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch python notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/julia-python-image-classification/rps_python_tensorflow.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Julia Notebook:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fjulia-python-image-classification%2Frps_julia_flux.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch julia notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/julia-python-image-classification/rps_julia_flux_colab.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch julia notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;environment-setup-for-julia&quot; tabindex=&quot;-1&quot;&gt;Environment Setup for Julia &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#environment-setup-for-julia&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;deepnote&quot; tabindex=&quot;-1&quot;&gt;Deepnote &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#deepnote&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As deepnote utilises docker instances, you can very easily setup a ‘local’ dockerfile to contain the install instructions for Julia. This means you don’t have to pollute the Jupyter notebook with install code, as you will have to do in Colab.&lt;/p&gt;
&lt;p&gt;In the environment section select “Local ./Dockerfile”. This will open the actual Dockerfile where you should add the following:&lt;/p&gt;
&lt;pre class=&quot;language-dockerfile&quot;&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; deepnote/python:3.10&lt;/span&gt;

&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; wget https://julialang-s3.julialang.org/bin/linux/x64/1.8/julia-1.8.3-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    tar -xvzf julia-1.8.3-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    mv julia-1.8.3 /usr/lib/ &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    ln -s /usr/lib/julia-1.8.3/bin/julia /usr/bin/julia &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    rm julia-1.8.3-linux-x86_64.tar.gz &amp;amp;&amp;amp; &lt;span class=&quot;token operator&quot;&gt;&#92;&lt;/span&gt;
    julia  -e &lt;span class=&quot;token string&quot;&gt;&quot;using Pkg;pkg&#92;&quot;add IJulia&#92;&quot;&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENV&lt;/span&gt; DEFAULT_KERNEL_NAME &lt;span class=&quot;token string&quot;&gt;&quot;julia-1.8&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can update the above to the latest Julia version from &lt;a href=&quot;https://julialang.org/downloads/&quot;&gt;this&lt;/a&gt; page, but at the time of writing 1.8.3 is the latest version.&lt;/p&gt;
&lt;h3 id=&quot;colab&quot; tabindex=&quot;-1&quot;&gt;Colab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#colab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For colab all the download and install code will have to be included in the notebook itself, as well as refreshing the page once the install code has run.&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;a href=&quot;https://github.com/ageron&quot;&gt;Aurélien Geron&lt;/a&gt; has made available on his GitHub a &lt;a href=&quot;https://colab.research.google.com/github/ageron/julia_notebooks/blob/master/Julia_Colab_Notebook_Template.ipynb&quot;&gt;starter notebook&lt;/a&gt; for Julia in colab, which is probably the best way to get started.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;if you use the “Open in Colab” button above (or the Julia notebook ending in “colab” from the repository I linked) I have already included this starter code in the Julia notebook.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The Data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.kaggle.com/datasets/drgfreeman/rockpaperscissors&quot;&gt;data&lt;/a&gt;&lt;sup&gt;[1]&lt;/sup&gt; utilised in this article is a set of images which depict the three possible combinations of hand position used in the game rock-paper-scissors.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/example-hands.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/example-hands.jpg&quot; alt=&quot;Four examples from the three different categories of the dataset&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Four examples from the three different categories of the &lt;a href=&quot;https://www.kaggle.com/datasets/drgfreeman/rockpaperscissors&quot;&gt;dataset&lt;/a&gt;. Composite image by Author.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Each image is of type PNG, and of dimensions 300(W) pixels x 200(H) pixels, in full colour.&lt;/p&gt;
&lt;p&gt;The original dataset contains 2188 images in total, but for this article a smaller selection has been used, which comprises of precisely 200 images for each of the three categories (600 images in total). This is mainly to ensure that the notebooks can be run with relative ease, and that the dataset is balanced.&lt;/p&gt;
&lt;p&gt;The smaller dataset that was used in this article is available here:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/datasets/rock_paper_scissors&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/favicon/maskable_icon_x512.png&quot; alt=&quot;Rock paper scissors dataset&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/datasets/rock_paper_scissors at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h1 id=&quot;the-plan&quot; tabindex=&quot;-1&quot;&gt;The Plan &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#the-plan&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are two separate notebooks. One written in Python using the TensorFlow deep learning framework, and a second that is written in Julia and utilises the Flux deep learning framework.&lt;/p&gt;
&lt;p&gt;Both notebooks use exactly the same raw data, and will go through the same steps to finally end up with a trained model at the end.&lt;/p&gt;
&lt;p&gt;Although it is not possible to match the methodology exactly between the two notebooks (as you might expect), I have tried to keep them as close as possible.&lt;/p&gt;
&lt;h2 id=&quot;a-general-outline&quot; tabindex=&quot;-1&quot;&gt;A general outline &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#a-general-outline&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each notebook covers the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the image data from a remote location and extract into local storage&lt;/li&gt;
&lt;li&gt;Load the images from a local folder structure ready for processing&lt;/li&gt;
&lt;li&gt;Review image data, and view sample images&lt;/li&gt;
&lt;li&gt;Split the data into train / validation sets&lt;/li&gt;
&lt;li&gt;Augment the training images to avoid over-fitting&lt;/li&gt;
&lt;li&gt;Prepare the images for the model (scaling etc.)&lt;/li&gt;
&lt;li&gt;Batch data&lt;/li&gt;
&lt;li&gt;Create model and associated parameters&lt;/li&gt;
&lt;li&gt;Train model (should be able to use the CPU or GPU)&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-packages&quot; tabindex=&quot;-1&quot;&gt;Comparison — Packages &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-packages&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/packages.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/packages.jpg&quot; alt=&quot;Packages on a table&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@fempreneurstyledstock?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Leone Venter&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/packages?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The comparison sections that follow will explore some of the differences (good or bad) that Julia has with the Python implementation. It will generally be broken down as per the bullet points in the previous section.&lt;/p&gt;
&lt;h2 id=&quot;package-installation&quot; tabindex=&quot;-1&quot;&gt;Package installation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#package-installation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To start with, a quick note on package installation and usage.&lt;/p&gt;
&lt;p&gt;The two languages follow a similar pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;make sure the package is installed in your environment&lt;/li&gt;
&lt;li&gt;‘import’ the package into your code to use it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The only real difference is that Julia can either install packages in the ‘environment’ before running code, or the packages can be installed from within the code (as is done in the Julia notebook for this article):&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/7eb9e99696504863b3aac72e823a32b1?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;“Pkg” in Julia is the equivalent of “pip” in Python, and can also be accessed from Julia’s command line interface.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/julia-pkg-commandline.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/julia-pkg-commandline.png&quot; alt=&quot;Julia package commandline example&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;An example of adding a package using the command line. Screenshot by author&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;package-usage&quot; tabindex=&quot;-1&quot;&gt;Package usage &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#package-usage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In terms of being able to access the installed packages from within the code, you would typically use the keyword “using” rather than “import”, as used in Python:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/52d150c3b7354fad8aa6604869515943?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Julia does also have an “import” keyword too. For more details on the difference please take a look at the &lt;a href=&quot;https://docs.julialang.org/en/v1/manual/modules/#Standalone-using-and-import&quot;&gt;documentation&lt;/a&gt;. In most general use cases “using” is more appropriate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;in this article I have deliberately used the full path, including the module names, when referencing a method from a module. This is not necessary, it just makes it clearer which package the methods are being referenced from. For example these two are equivalent and valid:&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; Random

Random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shuffle&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;my_array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Full path&lt;/span&gt;

shuffle&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;my_array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Without package name&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-download-and-extraction&quot; tabindex=&quot;-1&quot;&gt;Comparison — Download and Extraction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-download-and-extraction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/download.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/download.jpg&quot; alt=&quot;the word download in small tiles&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/close-up-shot-of-keyboard-buttons-2882550/&quot;&gt;Miguel Á. Padriñán&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The image data is provided remotely as a zip file. The zip file contains a folder for each of the three categories, and each folder has 200 images contained within.&lt;/p&gt;
&lt;p&gt;First step, download and extract the image files. This is relatively easy in both languages, and with the available libraries, probably more intuitive in Julia. The Python implementation:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/8d354157c42147f58e15aae00527f24b?height=155&quot; height=&quot;155&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;What the Julia implementation &lt;strong&gt;could&lt;/strong&gt; look like:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; InfoZIP

download&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/thetestspecimen/notebooks/raw/main/datasets/rock_paper_scissors/rock_paper_scissors.zip&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./rock_paper_scissors.zip&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

root_folder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rps&quot;&lt;/span&gt;
isdir&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./$root_folder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; mkdir&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./$root_folder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

InfoZIP&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unzip&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./rock_paper_scissors.zip&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./$root_folder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may notice that I said &lt;strong&gt;what it it could look like&lt;/strong&gt;. If you look at the notebooks you will see that in Julia I have actually used a custom function to do the unzipping, rather than utilising the &lt;a href=&quot;https://juliapackages.com/p/infozip&quot;&gt;InfoZIP&lt;/a&gt; package as detailed above.&lt;/p&gt;
&lt;p&gt;The reason for this is that I couldn’t get the InfoZIP package to install in &lt;strong&gt;all&lt;/strong&gt; of the environments I used, so I thought it would be unfair to include it.&lt;/p&gt;
&lt;p&gt;Is this a fault of the package? I suspect not. I think this is likely due to the fact that the online environments (colab and deepnote) are not primarily geared towards Julia, and sometimes that can cause problems. InfoZIP installs and works fine locally.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is this a fault of the package? I suspect not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I should also note here that to use the “Plots” library (which is the equivalent of something like matplotlib) in colab when utilising a GPU instance will result in failure to install!&lt;/p&gt;
&lt;p&gt;This may seem relatively trivial, but it is a direct illustration of the potential problems you can run into when dealing with a new-ish language. Furthermore, you are less likely to find a solution to the problem online as the community is smaller.&lt;/p&gt;
&lt;p&gt;It is still worth pointing out that when working locally on my computer I had no such issues with either package, and I would hope that with time online environments such as colab and deepnote may be a bit more Julia friendly out of the box.&lt;/p&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-handling-images&quot; tabindex=&quot;-1&quot;&gt;Comparison — Handling images &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-handling-images&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/photos.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/photos.jpg&quot; alt=&quot;polaroid pictures on a white background&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@iwnxx?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Ivan Shimko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/photos?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now the images are in the local environment, it is possible to take a look at how we can load and interact with them.&lt;/p&gt;
&lt;p&gt;Python:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/1ced9a2dff5c47a3b7ec48a90e9f89ce?height=551&quot; height=&quot;551&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/7a59cd12722d4f76bd8114e292950304?height=529.3125&quot; height=&quot;529.3125&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Julia:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/7559770f579f4ed28a186fa91ebfea1d?height=407&quot; height=&quot;407&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/ce477e4322624ace8dbd586f65725623?height=502.5&quot; height=&quot;502.5&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;In the previous section things were relatively similar. Now things start to diverge…&lt;/p&gt;
&lt;p&gt;This simple example of loading an image highlights some stark differences between Python and Julia, although that might not be immediately obvious from two similar looking code blocks.&lt;/p&gt;
&lt;h2 id=&quot;zero-indexing-vs-one-indexing&quot; tabindex=&quot;-1&quot;&gt;Zero indexing vs one indexing &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#zero-indexing-vs-one-indexing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Probably one of the major differences between the languages in general, is the fact that Julia uses indexing for arrays and matrices starting from 1 rather than 0.&lt;/p&gt;
&lt;p&gt;Python — the first element of “random_image”:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mpimg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;imread&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target_folder &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; random_image&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Julia — the first element of the shape of “image_channels”:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Colour channels: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img_channels&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can see how this could be a contentious difference. It all comes down to preference in reality, but putting any personal preferences aside, 1-indexing makes a lot more sense mathematically.&lt;/p&gt;
&lt;p&gt;It is also worth remembering the field of work this language is aimed at (i.e. more mathematical / statistics based professionals who are programming, rather than pure programmers / software engineers).&lt;/p&gt;
&lt;p&gt;Regardless of your stance, something to be very aware of, especially if you are thinking of porting a project over to Julia from Python.&lt;/p&gt;
&lt;h2 id=&quot;how-images-are-loaded-and-represented-numerically&quot; tabindex=&quot;-1&quot;&gt;How images are loaded and represented numerically &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#how-images-are-loaded-and-represented-numerically&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When images are loaded using python and “imread” they are loaded into a numpy array with the shape (height, width, RGB colour channels) as float32 numbers. Pretty simple.&lt;/p&gt;
&lt;p&gt;In Julia, images are loaded as:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;Type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;RGB&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;N0f8&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not so clear…so let’s explore this a little.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In JuliaImages, by default all images are displayed assuming that 0 means “black” and 1 means “white” or “saturated” (the latter applying to channels of an RGB image).&lt;/p&gt;
&lt;p&gt;Perhaps surprisingly, &lt;strong&gt;this 0-to-1 convention applies even when the intensities are encoded using only 8-bits per color channel&lt;/strong&gt;. JuliaImages uses a special type, &lt;code&gt;N0f8&lt;/code&gt;, that interprets an 8-bit &amp;quot;integer&amp;quot; as if it had been scaled by 1/255, thus encoding values from 0 to 1 in 256 steps.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://juliaimages.org/latest/tutorials/quickstart/&quot;&gt;Juliaimages.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Turns out this strange convention used by Julia is actually really helpful for machine / deep learning.&lt;/p&gt;
&lt;p&gt;One of the things you regularly have to do when dealing with images in Python is to scale the values by 1/255, so that all the values fall between 0 and 1. This is not necessary with Julia, as the scaling is automatically done by the “N0f8” type used for images natively!&lt;/p&gt;
&lt;p&gt;Unfortunately, you will not see the comparison in this article as the images are type PNG, and imread in Python returns the array as float values between 0 and 1 anyway (incidentally the only format it does that for).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/rgb-pixels.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/rgb-pixels.jpg&quot; alt=&quot;rgb pixels in a wave pattern&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@mgmaasen?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Michael Maasen&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/pixels?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, if you were to load in a JPG file in Python, you would receive integer values between 0 and 255 as the output from imread, and have to scale them later in your pre-processing pipeline.&lt;/p&gt;
&lt;p&gt;Apart from the auto scaling, it is also worth noting how the image is actually stored. Julia uses a concept of representing each pixel as a type of object, so if we look at the output type and shape:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;Type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;RGB&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;N0f8&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
Shape&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is literally stated as a 200x300 matrix. What about the three colour channels? We would expect 200x300x3, right?&lt;/p&gt;
&lt;p&gt;Well, Julia views each of the items in the 200x300 matrix as a ‘pixel’, which in this case has three values representing Red, Green and Blue (RGB), as indicated in the type ‘&lt;strong&gt;RGB&lt;/strong&gt;{N0f8}’. I suppose it would be like a matrix of objects, the object being defined as having three variables.&lt;/p&gt;
&lt;p&gt;However, there is reason behind the madness:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This design choice facilitates generic code that can handle both grayscale and color images without needing to introduce extra loops or checks for a color dimension. It also provides more rational support for 3d grayscale images–which might happen to have size 3 along the third dimension–and consequently helps unify the “computer vision” and “biomedical image processing” communities.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://juliaimages.org/latest/tutorials/quickstart/&quot;&gt;-Juliaimages.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some real thought went into these decisions it would seem.&lt;/p&gt;
&lt;p&gt;However, you cannot feed an image in this format into a neural network, not even Flux, so it will need to be split out into a ‘proper’ 3D matrix at a later stage. Which as it turns out is very easy indeed, as you will see.&lt;/p&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-data-preparation-pipeline&quot; tabindex=&quot;-1&quot;&gt;Comparison — Data preparation pipeline &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-data-preparation-pipeline&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/pipeline.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/pipeline.jpg&quot; alt=&quot;red pipe going into the distance&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jjying?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;JJ Ying&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/pipeline?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is definitely one of the areas where, in terms of pure ease of use Python and TensorFlow blow Julia out of the water.&lt;/p&gt;
&lt;h2 id=&quot;the-python-implementation&quot; tabindex=&quot;-1&quot;&gt;The Python implementation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#the-python-implementation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I can more or less load all my images into a batched optimised dataset ready to throw into a deep learning model in essentially four lines of code:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/79f7b8e6789d4c2fa9ed3f403532cb18?height=293.375&quot; height=&quot;293.375&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/0241e1387d8143c99ab51076b69cd0d8?height=293.375&quot; height=&quot;293.375&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/035f3532e82a4a56b8ff7d99a29192d0?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Training image augmentation is taken care of just as easily with a model layer:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/415e3d07-d64f-44e8-8e3e-7a244074c487/8c25d91c06664b8ea94487896a9475e9/87cda627ee384c38be9ff30c3a0f65e3?height=227&quot; height=&quot;227&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;the-julia-implementation&quot; tabindex=&quot;-1&quot;&gt;The Julia implementation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#the-julia-implementation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To achieve the same thing in Julia requires quite a bit more code. Let’s load the images and split them into train and validation sets:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/0e980aef75ea49a9b6794bfaabdb90c7?height=713&quot; height=&quot;713&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I should note that in reality, you could lose the “load and scale” and “shuffle” sections of this method and deal with it in a more terse form later, so it isn’t as bad as it looks. I mainly left those sections in as a reference.&lt;/p&gt;
&lt;p&gt;One useful difference between Python and Julia is that you can define types if you want, but it is not absolutely necessary. A good example is the type of “Tuple{Int,Int}” specified for the “image_size” in the function above. This ensures whole numbers are always passed, without having to do any specific checking within the function itself.&lt;/p&gt;
&lt;h3 id=&quot;augmentation-pipeline&quot; tabindex=&quot;-1&quot;&gt;Augmentation pipeline &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#augmentation-pipeline&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Image augmentation is very simple just like TensorFlow thanks to the Augmentor package, you can also add the image resizing here using the “Resize” layer (a more terse form as alluded to earlier):&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/9060ac5fa4ce4224952f8b7357af6743?height=394.5&quot; height=&quot;394.5&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;You should also note that Augmentor (using a wrapper of Julia Images) has the ability to change the ‘RGB{N0f8}’ type to a 3D matrix of type float32 ready for passing into the deep learning model:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/ee616d680f7b45b0b99206fa0c9536f9?height=245.75&quot; height=&quot;245.75&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I want to break down the three steps above as I think it is important to understand what exactly they do, as I can see it is potentially quite confusing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.juliahub.com/Augmentor/C7n2B/0.6.1/autodocs/#Augmentor.SplitChannels&quot;&gt;SplitChannels&lt;/a&gt; — takes an input of Matrix{RGB{N0f8}} with shape 160 (height) x 160 (width) and converts it to 3 (colour channels) × 160 (height) × 160 (width) with type Array{N0f8}. &lt;strong&gt;It is worth noting here that the colour channels become the first dimension, not the last like in python/numpy.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.juliahub.com/Augmentor/C7n2B/0.6.1/autodocs/#Augmentor.PermuteDims&quot;&gt;PermuteDims&lt;/a&gt; — just rearranges the shape of the array. In our case we change the dimensions of the output to 160 (width) x 160 (height) x 3 (colour channels). &lt;strong&gt;Note:&lt;/strong&gt; the order of height and width have also been switched.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.juliahub.com/Augmentor/C7n2B/0.6.1/autodocs/#Augmentor.ConvertEltype&quot;&gt;ConvertEltype&lt;/a&gt; — changes N0f8 into float32.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You may be wondering why the dimensions need to be switched about so much. The reason for this is due to the requirement of the input shape into a &lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/models/layers/#Flux.Conv&quot;&gt;Conv layer&lt;/a&gt; in Flux at a later stage. I will go into more detail once we have completed batching, as it one of my main gripes with the whole process…&lt;/p&gt;
&lt;h3 id=&quot;applying-the-augmentation&quot; tabindex=&quot;-1&quot;&gt;Applying the augmentation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#applying-the-augmentation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we have an interesting situation. I need to apply the augmentation pipelines to the images. No problem! Due to the excellent &lt;a href=&quot;https://evizero.github.io/Augmentor.jl/stable/interface/#Augmentor.augmentbatch!&quot;&gt;augmentbatch!()&lt;/a&gt; function provided by the Augmentor package.&lt;/p&gt;
&lt;p&gt;Except no matter how hard I tried I couldn’t get it to work with the data. Constant errors (forgot to note down exactly what while I was frantically trying to sort out a solution, but there were similar problems in various forums).&lt;/p&gt;
&lt;p&gt;There is always the possibility that this is my fault, I kind of hope it is!&lt;/p&gt;
&lt;p&gt;As a workaround, I used a loop using the ‘non-batched’ method &lt;a href=&quot;https://evizero.github.io/Augmentor.jl/stable/interface/#Augmentor.augment&quot;&gt;augment&lt;/a&gt;. I also one-hot encoded the labels at the same time using the &lt;a href=&quot;https://github.com/FluxML/OneHotArrays.jl&quot;&gt;OneHotArrays&lt;/a&gt; package:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/f16659fc26ec4f7f98f5298fd0af571c?height=353&quot; height=&quot;353&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/d8c6f12fa4484116a18460a02cf284ed?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/b32ac5f8a1ff465db1802346c8291b90?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I think this goes a long way to illustrate that there are some areas of the Julia ecosystem that may give you a few implementation headaches. You may not always find a solution online either, as the community is smaller.&lt;/p&gt;
&lt;p&gt;However, one of the major advantages of Julia is that if you have to resort to things like a for loop to navigate a problem, or just to implement a bit of a bespoke requirement, you can be fairly sure that the code you write will be optimised and quick. Not something you can rely on every time with Python.&lt;/p&gt;
&lt;p&gt;Some example augmented images from the train pipeline:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/1998fd9d9a8742c4a7a13131ea7642ff?height=188.265625&quot; height=&quot;188.265625&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;batching-the-data&quot; tabindex=&quot;-1&quot;&gt;Batching the data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#batching-the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Batching in Julia is TensorFlow level easy. There are multiple ways of going about this in Julia. In this case Flux’s built in &lt;a href=&quot;https://fluxml.ai/Flux.jl/v0.10/data/dataloader/#Flux.Data.DataLoader&quot;&gt;DataLoader&lt;/a&gt; will be used:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/4708de7defe6441ca78e38d7282aa9a2?height=190.5625&quot; height=&quot;190.5625&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Nothing much to note about the method. Does exactly what it says on the tin. (This is the alternative place you can shuffle the data as I alluded to earlier.)&lt;/p&gt;
&lt;p&gt;We are ready to pass the data to the model, but first a slight detour…&lt;/p&gt;
&lt;h1 id=&quot;confusing-input-shapes&quot; tabindex=&quot;-1&quot;&gt;Confusing input shapes &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#confusing-input-shapes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/goat.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/goat.jpg&quot; alt=&quot;a young goat tangled in a rope&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@tdederichs?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Torsten Dederichs&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/confusing?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I now want to come back to the input shape for the model. You can see in the last code block of the previous section that the dataset has shape:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data: 160(width) x 160(height) x 3(colour channels) x 32(batchsize)&lt;br /&gt;
Labels: 3(labels) x 32(batchsize)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In TensorFlow the input shape would be:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data: 32(batchsize) x 160(height) x 160(width) x 3(colour channels)&lt;br /&gt;
Labels: 32(batchsize) x 3(labels)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;From the Julia documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Image data should be stored in WHCN order (width, height, channels, batch). In other words, a 100×100 RGB image would be a &lt;code&gt;100×100×3×1&lt;/code&gt; array, and a batch of 50 would be a &lt;code&gt;100×100×3×50&lt;/code&gt; array.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/models/layers/#Flux.Conv&quot;&gt;fluxml.ai&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have no idea why this convention has been chosen, especially the switching of height and width.&lt;/p&gt;
&lt;p&gt;Frankly, there is nothing to complain about, it is just a convention. In fact, if previous experience is anything to go by I would suspect some very well thought out optimisation is the cause.&lt;/p&gt;
&lt;p&gt;I have come across some slightly odd changes in definition compared to other languages, only to find out there is a very real reason for it (as you would hope).&lt;/p&gt;
&lt;p&gt;As a concrete (and relevant) example, take &lt;a href=&quot;https://juliaimages.org/&quot;&gt;Julia’s Images&lt;/a&gt; package.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The reason we use CHW (i.e., channel-height-width) order instead of HWC is that this provides a memory friendly indexing mechanism for &lt;code&gt;Array&lt;/code&gt;. By default, in Julia the first index is also the fastest (i.e., has adjacent storage in memory). For more details, please refer to the performance tip: &lt;a href=&quot;https://docs.julialang.org/en/v1/manual/performance-tips/#Access-arrays-in-memory-order,-along-columns-1&quot;&gt;Access arrays in memory order, along columns&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://juliaimages.org/latest/tutorials/quickstart/&quot;&gt;juliaimages.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;extra-confusion&quot; tabindex=&quot;-1&quot;&gt;Extra confusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#extra-confusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This brings up one of the main gripes I have.&lt;/p&gt;
&lt;p&gt;I can accept that it is a different language, so there is potentially a good reason to have a new convention. However, during the course of loading images and getting them ready for plugging into a deep learning model in Flux, I have had to morph the input shape all over the place:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Images are loaded in: Matrix{RGB{N0f8}} (height x width)&lt;/li&gt;
&lt;li&gt;Split channels: {N0f8} (channels x height x width)&lt;/li&gt;
&lt;li&gt;Move channels &lt;strong&gt;AND&lt;/strong&gt; switch height and width: {N0f8} (width x height x channels)&lt;/li&gt;
&lt;li&gt;Convert to float32&lt;/li&gt;
&lt;li&gt;Batchsize (as last element): {float32} (width x height x channels x batchsize)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As apparently (channels x height x width) is optimal for images, and that is how native Julia loads them in. Could it not be:&lt;/p&gt;
&lt;p&gt;(channels x height x width x batchsize)?&lt;/p&gt;
&lt;p&gt;Might save a lot of potential confusion.&lt;/p&gt;
&lt;p&gt;I genuinely hope that someone can point out that I have stupidly overlooked something (really I do). Mainly because I have been very impressed with the attention to detail and thought that has gone into designing this language.&lt;/p&gt;
&lt;p&gt;OK. Enough moaning. Back to the project.&lt;/p&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-the-model&quot; tabindex=&quot;-1&quot;&gt;Comparison — The model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-the-model&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/model.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/model.jpg&quot; alt=&quot;a scale model car with a scale model man getting in&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/blue-volkswagen-beetle-scale-model-10215969/&quot;&gt;DS stories&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Model definition in Julia is very similar to the Sequential method of TensorFlow. It is just called &lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/models/layers/#Flux.Chain&quot;&gt;Chain&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I will mostly cease to include the TensorFlow code in the article at this point just to keep it readable, but both notebooks are complete and easy to reference if you need to.&lt;/em&gt;&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/543ff07a0799414c9e5d37c66a4e7dc4?height=615.25&quot; height=&quot;615.25&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Main differences:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You must explicitly load both the model (and data) onto the GPU if you want to use it&lt;/li&gt;
&lt;li&gt;You must specify the input and output channels explicitly (input=&amp;gt;output) — &lt;em&gt;I believe there are&lt;/em&gt; &lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/outputsize/#Shape-Inference&quot;&gt;&lt;em&gt;shape inference macros&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that can help with this, but we won’t get into that here&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All in all very intuitive to use. It also forces you to have a proper understanding of how the data moves and reshapes through the model. A good practise if you ask me.&lt;/p&gt;
&lt;p&gt;There is nothing more dangerous that a black box system, and no thinking. We all do it of course as sometimes we just want the answer quickly, but it can lead to some hard to trace and confusing outcomes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is nothing more dangerous than a black box system, and no thinking. We all do it…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;calculation-device-specification&quot; tabindex=&quot;-1&quot;&gt;Calculation device specification &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#calculation-device-specification&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the code for the notebook you can see where I have explicitly defined which device (CPU or GPU) should be used for calculation by using the variable “calc_device”.&lt;/p&gt;
&lt;p&gt;Changing the “calc_device” variable to gpu will use the gpu. Change it to cpu to use only the cpu. You can of course replace all the “calc_device” variables with gpu or cpu directly, and it will work in exactly the same way.&lt;/p&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-loss%2C-accuracy-and-optimiser&quot; tabindex=&quot;-1&quot;&gt;Comparison — Loss, Accuracy and Optimiser &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-loss%2C-accuracy-and-optimiser&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/bullseye.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/bullseye.jpg&quot; alt=&quot;an archery target with three arrows in the centre circle&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;https://pixabay.com/users/quincecreative-1031690/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=2886223&quot;&gt;3D Animation Production Company&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=2886223&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Again, very similar to TensorFlow:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/82ef09e1e8304108a6845588d47e9984?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/a07f0bfaf17d4a82b6df411f3bbb1d72?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;A couple of things of note:&lt;/p&gt;
&lt;h2 id=&quot;logitcrossentropy&quot; tabindex=&quot;-1&quot;&gt;logitcrossentropy &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#logitcrossentropy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may have noted that the model has no softmax layer (if not take a quick look).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is mathematically equivalent to &lt;code&gt;crossentropy(softmax(ŷ), y)&lt;/code&gt;, but is more numerically stable than using functions &lt;code&gt;crossentropy&lt;/code&gt; and &lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/models/nnlib/#Softmax&quot;&gt;softmax&lt;/a&gt; separately.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/models/losses/#Flux.Losses.logitcrossentropy&quot;&gt;fluxml.ai&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;onecold&quot; tabindex=&quot;-1&quot;&gt;onecold &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#onecold&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The opposite of onehot. Excellent name, not sure why someone hasn’t thought of that before.&lt;/p&gt;
&lt;h2 id=&quot;one-line-function-definition&quot; tabindex=&quot;-1&quot;&gt;One line function definition &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#one-line-function-definition&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are new to Julia it is also worth pointing out that the loss and accuracy functions are actually proper function definitions in one line. i.e. the same as this:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;X&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Losses&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logitcrossentropy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;X&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of many great features of the Julia language.&lt;/p&gt;
&lt;p&gt;(Note: you could actually omit the return keyword in the above. Another way of shortening a function.)&lt;/p&gt;
&lt;h1 id=&quot;comparison-%E2%80%94-training&quot; tabindex=&quot;-1&quot;&gt;Comparison — Training &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#comparison-%E2%80%94-training&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/training.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/training.jpg&quot; alt=&quot;a barbell on the floor with an arm getting ready to lift&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@victorfreitas?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Victor Freitas&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/training?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Training can be as complicated or simple as you like in Julia. There is genuinely a lot of flexibility available, I haven’t even touched the surface in what I’m about to show you.&lt;/p&gt;
&lt;p&gt;If you want to keep it really simple there is what I would call the equivalent to “model.fit” in TensorFlow:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; epoch &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
    Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;train&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loss&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; train_batches&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s right, basically a for loop. You can also add a callback parameter to do things like print loss or accuracy (which is not done automatically like TensorFlow), or early stopping etc.&lt;/p&gt;
&lt;p&gt;However, using the above method can cause problems when dealing with large amounts of data (like images), as it requires loading all of the train data into memory (either locally or on the GPU).&lt;/p&gt;
&lt;p&gt;The following function therefore allows the batches to be loaded onto the GPU (or memory for a CPU run) batch by batch. It also prints the training loss and accuracy (an average over all batches), and the validation loss on the whole validation dataset.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If the validation set is quite large you could also calculate the validation loss/accuracy on a batch by batch basis to save memory.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/115d1ee014834badaf24542f5b4df530?height=695&quot; height=&quot;695&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;In reality, it is two for loops: one for the epochs and an internal loop for the batches.&lt;/p&gt;
&lt;p&gt;The lines of note are:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; device&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;batch_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; device&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;batch_labels&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
gradients &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gradient&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Optimise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;update&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;optimiser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Flux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gradients&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the loading of a batch of data onto the device (cpu or gpu), and running the data through the model.&lt;/p&gt;
&lt;p&gt;All the rest of the code is statistics collection and printing.&lt;/p&gt;
&lt;p&gt;More involved than TensorFlow, but nothing extreme.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/b362fcc2-d6e4-4b0a-8d7f-90e06238ea7e/46dfa2ce6f2548f7acae0ae8a8142f41/65ae5865155744e0ad1509db7259098b?height=718&quot; height=&quot;718&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;…and we are done. An interesting journey.&lt;/p&gt;
&lt;h1 id=&quot;summary-(and-tl%3Bdr)&quot; tabindex=&quot;-1&quot;&gt;Summary (and TL;DR) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#summary-(and-tl%3Bdr)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/summary.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/summary.jpg&quot; alt=&quot;the word summary like it has been printed by a typewriter&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/close-up-shot-of-a-text-on-a-green-surface-6980523/&quot;&gt;Ann H&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At the beginning of the article I stated that apart from speed there are other important metrics when it comes to deciding if a language is worth the investment compared to what you already use. I specifically named:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;syntax&lt;/li&gt;
&lt;li&gt;flexibility&lt;/li&gt;
&lt;li&gt;library availability / integration&lt;/li&gt;
&lt;li&gt;documentation&lt;/li&gt;
&lt;li&gt;community support&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Having been over a whole project I thought it might be an idea to summarise some of the findings. Just bear in mind that this is based on my impressions while generating the code for this article, and is only my opinion.&lt;/p&gt;
&lt;h2 id=&quot;syntax&quot; tabindex=&quot;-1&quot;&gt;Syntax &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#syntax&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Coming from Python I think that the syntax is similar enough that it is relatively easy to pick up, and I would suggest that in quite a few circumstances it is even more ‘high level’ and easy to use than Python.&lt;/p&gt;
&lt;p&gt;Let’s get the contentious one out of the way first. Yes, Julia uses 1-indexed arrays rather than 0-indexed arrays. I personally prefer this, but I suspect there will be plenty who won’t. There are also more subtle differences such as array slicing being inclusive of the last element, unlike Python. Just be a little careful!&lt;/p&gt;
&lt;p&gt;But there is plenty of good stuff…&lt;/p&gt;
&lt;p&gt;For example when using functions you don’t need a colon or return keyword. You can even make a succinct one liner without losing the codes meaning:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# this returns the value of calculation, no return keyword needed&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; my_func&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# you can shorten this even further&lt;/span&gt;

my_func&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the use of “end” in the standard function expression. This is used as indentation doesn’t matter in Julia, which in my opinion is a vast improvement. The spaces vs tabs saga will not apply to Julia.&lt;/p&gt;
&lt;p&gt;The common if-else type statements can also be utilised in very terse and clear one line statements:&lt;/p&gt;
&lt;pre class=&quot;language-julia&quot;&gt;&lt;code class=&quot;language-julia&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ternary - if a is less than b print(a) otherwise print(b)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# only need to do something if the condition is met (or not met)? &lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# use short circuit evaluation.&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# if a is less than b print(a+b), otherwise do nothing&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# if a is less than b do nothing, otherwise print(a+b)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m likely just scratching the surface here, but already I am impressed.&lt;/p&gt;
&lt;h2 id=&quot;flexibility&quot; tabindex=&quot;-1&quot;&gt;Flexibility &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#flexibility&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think flexibility is something that Julia really excels at.&lt;/p&gt;
&lt;p&gt;As I have already mentioned, you can write code that is terse and to the point just like Python, but there are also additional features should you need, or want, to utilise them.&lt;/p&gt;
&lt;p&gt;The first and foremost is probably the option to use types, something not possible in Python. Although inferred types sound like a great idea, they do have various downsides, such as making code harder to read and follow, and introducing hard to trace bugs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;flexibility to specify types when it makes the most sense is an excellent ability&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having the flexibility to specify types when it makes the most sense is an excellent ability that Julia has. I’m glad it isn’t forced across the board though.&lt;/p&gt;
&lt;p&gt;Julia is also aimed at scientific and mathematical communities. Utilising unicode characters in your code, is therefore quite a useful feature. Not something I will likely use, but as I come from a mathematical / engineering background I can appreciate the inclusion.&lt;/p&gt;
&lt;h2 id=&quot;library-availability-%2F-consistency&quot; tabindex=&quot;-1&quot;&gt;Library availability / consistency &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#library-availability-%2F-consistency&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a bit of a mixed bag.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/library.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/library.jpg&quot; alt=&quot;a bookshelf with lots of old traditional looking books&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@inakihxz?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Iñaki del Olmo&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/library?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This article has utilised quite a few packages. From some larger packages such as Flux and Images, right down to more bespoke packages such as OneHotArrays and Augmentor.&lt;/p&gt;
&lt;p&gt;On the whole I would say they don’t, on average, approach the level of sophistication, integration, and ease of use that you can find in Python / TensorFlow. It takes a little bit more effort do the same thing, and you are likely to find more problems, and hit more inconsistencies. I am not surprised by this, at the end of the day it is a less mature ecosystem.&lt;/p&gt;
&lt;p&gt;For example the ability to batch and optimise your data with a simple one line interface is a really nice feature of TensorFlow. The fact you don’t have to write extra code to print training and validation loss / accuracy is also very useful.&lt;/p&gt;
&lt;p&gt;However, I think Julia’s library ecosystem has enough variation and sophistication to genuinely do more than enough. The packages on the whole play nicely together too. I don’t think it is even close to a deal breaker.&lt;/p&gt;
&lt;p&gt;To summarise my main issues I encountered with the packages in this article:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I couldn’t get the package &lt;a href=&quot;https://juliapackages.com/p/infozip&quot;&gt;InfoZIP&lt;/a&gt; to install consistently across all environments&lt;/li&gt;
&lt;li&gt;I couldn’t get the &lt;a href=&quot;https://evizero.github.io/Augmentor.jl/stable/interface/#Augmentor.augmentbatch!&quot;&gt;!augmentbatch()&lt;/a&gt; function to work for the data in this article at all, which would have been useful&lt;/li&gt;
&lt;li&gt;For some reason there is a slightly muddled approach to how the shape of an image is defined between JuliaImages and Flux, which leads to quite a lot of messing about with re-shaping matrices. It isn’t hard, it just seems unnecessary.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;documentation&quot; tabindex=&quot;-1&quot;&gt;Documentation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#documentation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.julialang.org/en/v1/&quot;&gt;Documentation for the core language&lt;/a&gt; is a pretty complete and reliable source. The only thing I would suggest is that the examples given for some methods could be a bit more detailed and varied. A minor quibble, otherwise excellent stuff.&lt;/p&gt;
&lt;p&gt;Moving beyond the core language, and the detail and availability of the documentation can vary.&lt;/p&gt;
&lt;p&gt;I’m impressed with the larger packages, which I suppose would be almost core packages anyway. In terms of this article, that would be &lt;a href=&quot;https://juliaimages.org/stable/&quot;&gt;JuliaImages&lt;/a&gt; and &lt;a href=&quot;https://fluxml.ai/Flux.jl/stable/&quot;&gt;Flux&lt;/a&gt;. I would say they are pretty comprehensive, and I particularly like the effort that goes into emphasising why things are done a certain way:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The reason we use CHW (i.e., channel-height-width) order instead of HWC is that this provides a memory friendly indexing mechanisim for &lt;code&gt;Array&lt;/code&gt;. By default, in Julia the first index is also the fastest (i.e., has adjacent storage in memory).&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://juliaimages.org/stable/tutorials/quickstart/&quot;&gt;juliaimages.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As the packages get smaller, the documenation is generally there, but a bit terse. &lt;a href=&quot;https://docs.juliahub.com/ZipFile/cOum2/0.9.2/&quot;&gt;ZipFile&lt;/a&gt; is a good example of this.&lt;/p&gt;
&lt;p&gt;Although, typically packages are open source and hosted on Github, and contributions are usually always welcome. As stated by JuliaImages:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please help improve this documentation–if something confuses you, chances are you’re not alone. It’s easy to do as you read along: just click on the “Edit on GitHub” link above, and then &lt;a href=&quot;https://help.github.com/articles/editing-files-in-another-user-s-repository/&quot;&gt;edit the files directly in your browser&lt;/a&gt;. Your changes will be vetted by developers before becoming permanent, so don’t worry about whether you might say something wrong.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://juliaimages.org/stable/&quot;&gt;juliaimages.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;community&quot; tabindex=&quot;-1&quot;&gt;Community &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#community&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The community is exactly what I expected it to be, lively and enthusiastic, but significantly smaller than Python’s / TensorFlow’s. If you need answers to queries, especially more bespoke queries, you may need to dig a little deeper than you usually would into the likes of Google and StackOverflow.&lt;/p&gt;
&lt;p&gt;This will obviously change with adoption, but fortunately the documentation is pretty good.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;All things considered I think Julia is a great language to actually use.&lt;/p&gt;
&lt;p&gt;The creators of the language were trying to take the best parts of the languages they loved to use, and combine them into a sort of super language, which they called Julia.&lt;/p&gt;
&lt;p&gt;In my opinion they have done an extremely good job. The syntax is genuinely easy to use and understand, but can also incorporate advanced and slightly more obscure elements — it is a very flexible language.&lt;/p&gt;
&lt;p&gt;It is also genuinely fast.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/learn.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/learn.jpg&quot; alt=&quot;the word learn in scrabble like wooden blocks&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;https://pixabay.com/users/wokandapix-614097/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1820039&quot;&gt;Wokandapix&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1820039&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes, there may be a slight learning curve to switch from the language you are using at the moment, but again, I don’t think it will be as severe as you might think. To help you out, Julia’s documentation includes a nice point by point comparison for major languages:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://docs.julialang.org/en/v1/manual/noteworthy-differences/&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/julia-logo.jpg&quot; alt=&quot;Noteworthy differences between Julia and other languages&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;Noteworthy Differences from other Languages · The Julia Language&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Documentation for The Julia Language.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - julialang.org&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;The only downsides I see are due to the fact that it is, even after 10 year of existence, relatively new compared to it’s competitors. This has a direct impact on the quality and quantity of documentation and learning resources. Which appears to have a bigger impact on adoption than most people would like to admit. Money also helps, as always…but I don’t have the data to comment on that situation.&lt;/p&gt;
&lt;p&gt;Being the best product or solution does not guarantee success and broad acceptance. That is just not how the real world works.&lt;/p&gt;
&lt;p&gt;…but after getting to know how Julia works (even on a basic level) I do hope more people see the potential and jump onboard.&lt;/p&gt;
&lt;h1 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/julia-flux-python-tensorflow-comparison/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;[1] Julien de la Bruère-Terreault, &lt;a href=&quot;https://www.kaggle.com/datasets/drgfreeman/rockpaperscissors&quot;&gt;Rock-Paper-Scissors Images&lt;/a&gt; (2018), Kaggle, License: &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0/&quot;&gt;CC BY-SA 4.0&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>A Simple Way to Speed Up Your Python Code — Stay Up to Date</title>
		<link href="https://www.thetestspecimen.com/posts/simple-speed-up-python/"/>
		<updated>Tue, 10 Jan 2023 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/simple-speed-up-python/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;A lot of time and money is spent trying to optimise code so that it can be as fast and efficient as possible, and within the field of data science this is becoming even more important due to the vast datasets that are now required to be processed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A simple, and often overlooked, way of achieving code optimisation is just to make sure that your language of choice, and associated libraries, are as up to date as they can reasonably be.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You will probably be surprised how relatively little time and effort, can result in some significant benefits.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is a fairly obvious statement to say that staying up to date could help “optimise” your code, but blindly updating your software or libraries without understanding what is changing is potentially a recipe for disaster.&lt;/p&gt;
&lt;p&gt;By the end of this article you should have a good idea of why you should stay up to date. You will have a solid plan of action to ensure you can hit a balance between ensuring you are optimised, and not wasting valuable time. In addition, you will also be aware of the potential pitfalls that can arise, and how to avoid them.&lt;/p&gt;
&lt;p&gt;To round things off, a concrete example using the latest release of NumPy (1.24.0) to illustrate the real world benefits of keeping your software and libraries bang up to date.&lt;/p&gt;
&lt;h1 id=&quot;why-should-i-stay-up-to-date%3F&quot; tabindex=&quot;-1&quot;&gt;Why should I stay up to date? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#why-should-i-stay-up-to-date%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/why.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/why.jpg&quot; alt=&quot;why, written on a pink background&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/why-text-on-a-pink-surface-11141733/&quot;&gt;Ann H&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The simple answer is that you can benefit from items such as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;brand new features&lt;/li&gt;
&lt;li&gt;optimisations&lt;/li&gt;
&lt;li&gt;bug fixes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All implemented for you by people who know software well, because remember…&lt;/p&gt;
&lt;h2 id=&quot;you-are-not-a-software-development-expert&quot; tabindex=&quot;-1&quot;&gt;You are not a software development expert &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#you-are-not-a-software-development-expert&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are a data science professional (or enthusiast), which I’m going to assume you are, then your main concern is processing, manipulating and analysing data to gain insights and predictions.&lt;/p&gt;
&lt;p&gt;Although you may have a certain level of competence with regard to software development, and general coding, it would be fair to say that it is not your expertise.&lt;/p&gt;
&lt;p&gt;As such, it is perfectly reasonable that you rely on a high level intuitive language (Python, R, Matlab etc.), and a mountain of libraries that provide a whole host of functionality and optimisation relevant to your field of work. Allowing you to concentrate on &lt;strong&gt;your&lt;/strong&gt; profession.&lt;/p&gt;
&lt;h2 id=&quot;rely-on-the-experts%2C-they-know-better&quot; tabindex=&quot;-1&quot;&gt;Rely on the experts, they know better &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#rely-on-the-experts%2C-they-know-better&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you can build optimisation into your code, great! But it should not be the thing that is consuming your time.&lt;/p&gt;
&lt;p&gt;As it turns out, there is an army of other professionals, who know software development extremely well. They are working hard to ensure the language and libraries you use are optimised, and constantly improved. Providing you with the exact tools you need to apply to your work.&lt;/p&gt;
&lt;p&gt;However, to take advantage of these optimisations you need to pay attention, or you may be missing out.&lt;/p&gt;
&lt;h1 id=&quot;read-the-release-notes%2C-it%E2%80%99s-important&quot; tabindex=&quot;-1&quot;&gt;Read the release notes, it’s important &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#read-the-release-notes%2C-it%E2%80%99s-important&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/notebook.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/notebook.jpg&quot; alt=&quot;a cup of coffee next to a notebook, overhead view&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/background-beverage-blank-brown-459458/&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;New versions of both the language, and associated libraries, are released with surprising regularity. However, if you don’t pay attention to what is actually changing, then you may miss out on the potential benefits, or introduce bugs / nonsensical parameters.&lt;/p&gt;
&lt;p&gt;A good example of both of these situations is an algorithm update applied to the NumPy &lt;code&gt;np.in1d&lt;/code&gt; function in NumPy 1.24.0, which is also utilised in the widely used &lt;code&gt;np.isin&lt;/code&gt; function.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;np.in1d&lt;/code&gt; (used by &lt;code&gt;np.isin&lt;/code&gt;) can now switch to a faster algorithm (up to &amp;gt;10x faster) when it is passed two integer arrays. This is often automatically used, but you can use &lt;code&gt;kind=&amp;quot;sort&amp;quot;&lt;/code&gt; or &lt;code&gt;kind=&amp;quot;table&amp;quot;&lt;/code&gt; to force the old or new method, respectively.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://numpy.org/doc/stable/release/1.24.0-notes.html#faster-version-of-np-isin-and-np-in1d-for-integer-arrays&quot;&gt;numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;missing-out-on-gains&quot; tabindex=&quot;-1&quot;&gt;Missing out on gains &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#missing-out-on-gains&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is important to note in the quote above that &lt;code&gt;kind=&amp;quot;table&amp;quot;&lt;/code&gt; is “often automatically used”, which implies &lt;strong&gt;not always&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You could be missing out on a 10x speed gain&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You could be missing out on a 10x speed gain just because you didn’t meet the requirements set by the developers to automatically use the new method:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If None, will automatically choose ‘table’ if the required memory allocation is less than or equal to 6 times the sum of the sizes of &lt;em&gt;ar1&lt;/em&gt; and &lt;em&gt;ar2&lt;/em&gt;, otherwise will use ‘sort’. This is done to not use a large amount of memory by default, &lt;strong&gt;even though ‘table’ may be faster in most cases&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.in1d.html&quot;&gt;numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you read the release notes, then simply adding &lt;code&gt;kind=”table”&lt;/code&gt; in the method parameters would be the simple change you needed to ensure a significant benefit in speed of execution, regardless of memory allocation.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; this automatic selection is likely introduced to ensure the new method doesn’t cause bugs in your code. There are cases where it could use more memory than the previous method, which may be a problem in memory restricted environments. Very sensible edge case coverage by the developers.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;introducing-bugs-or-confusing-code&quot; tabindex=&quot;-1&quot;&gt;Introducing bugs or confusing code &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#introducing-bugs-or-confusing-code&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you don’t set the new parameter (because you didn’t read the release notes), then very sensibly the developers set a default.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If None, will automatically choose ‘table’ if the required memory allocation is less than or equal to 6 times the sum of the sizes of &lt;em&gt;ar1&lt;/em&gt; and &lt;em&gt;ar2.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.in1d.html&quot;&gt;numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great! So you may automatically get a speed up of 10x. However:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If ‘table’ is chosen, &lt;em&gt;assume_unique&lt;/em&gt; will have no effect.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.in1d.html&quot;&gt;-numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case “assume_unique” having no effect is a minor problem, as the developers look like they have covered edge cases to ensure that if you previously assigned “assume_unique” it will just be ignored.&lt;/p&gt;
&lt;p&gt;However, it is messy, as your code specifies a parameter that is irrelevant, which could cause confusion for other people (or even you) in the future.&lt;/p&gt;
&lt;p&gt;It is also worth noting that there may be cases where the developers weren’t so thorough, or breaking changes couldn’t be avoided. If that happens, then you will suddenly have code that doesn’t run.&lt;/p&gt;
&lt;h2 id=&quot;new-methods&quot; tabindex=&quot;-1&quot;&gt;New methods &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#new-methods&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apart from potentially missing out on the improvement for the methods you already use in your code, you may miss out on completely new methods that would be of potential use to your project or workflow.&lt;/p&gt;
&lt;p&gt;In a previous article about one hot encoding data I touched on a new method implemented in the recently released Pandas 1.5.0 called &lt;code&gt;from_dummies()&lt;/code&gt;, which is a reversal for &lt;code&gt;get_dummies()&lt;/code&gt;, a commonly used one hot encoding method from Pandas:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://towardsdatascience.com/the-best-methods-for-one-hot-encoding-your-data-c29c78a153fd&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/one-hot-encoding/zeros-and-ones.jpg&quot; alt=&quot;The Best Methods for One-Hot Encoding Your Data&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;Page not found | Towards Data Science&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Publish AI, ML &amp;amp; data-science insights to a global community of data professionals.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;Partha Sarkar - Towards Data Science&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;Prior to the release of this method, reversal of the one hot encoding would have been a manual procedure.&lt;/p&gt;
&lt;p&gt;There are a whole host of new methods created across the libraries that you use, but the only way to be aware of when they appear is to review the release notes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;whatever method the developers have implemented will be optimised and less prone to bugs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;…and remember, it is &lt;em&gt;likely&lt;/em&gt; that whatever method the developers have implemented will be optimised and less prone to bugs than something you have coded yourself. They are professional software developers after all, and producing bug free well tested code is no easy feat.&lt;/p&gt;
&lt;h1 id=&quot;a-strategy-to-keep-up-to-date&quot; tabindex=&quot;-1&quot;&gt;A strategy to keep up to date &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#a-strategy-to-keep-up-to-date&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/postitnotes.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/postitnotes.jpg&quot; alt=&quot;a wall of postit notes&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@patrickperkins?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Patrick Perkins&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/ETRPjvb0KM0?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Time is money, as the famous aphorism goes.&lt;/p&gt;
&lt;p&gt;The reality is that a typical project may include a mountain of libraries, so it may not be practical to read the release notes for every library, for every tiny update, so it may be wise to prioritise.&lt;/p&gt;
&lt;h2 id=&quot;update-on-specific-release-points&quot; tabindex=&quot;-1&quot;&gt;Update on specific release points &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#update-on-specific-release-points&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is quite common to see numbering conventions that include three numbers separated by dots. For example the current release of NumPy is 1.24.0.&lt;/p&gt;
&lt;p&gt;Being aware of what these numbers (generally) signify can help plan when to pay attention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Major version number&lt;/strong&gt; (&lt;strong&gt;1&lt;/strong&gt;.24.0): large and significant changes to the software or library. &lt;strong&gt;Can include changes that are not backward compatible.&lt;/strong&gt; This requires careful review before upgrading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minor version number&lt;/strong&gt; (1.&lt;strong&gt;24&lt;/strong&gt;.0): typically a minor feature change / changes, or a larger set of bug fixes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patch version number&lt;/strong&gt; (1.24.&lt;strong&gt;0&lt;/strong&gt;): typically a smaller set of bug fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the major version number changes it is &lt;strong&gt;absolutely essential&lt;/strong&gt; that you review the release notes, as there could be breaking changes (i.e. your code could stop working completely in some cases).&lt;/p&gt;
&lt;p&gt;The minor version number change is something you should be paying attention to, as it is optimal in terms potential gains, and new or improved methods.&lt;/p&gt;
&lt;p&gt;The patch version number can generally be passed over if you don’t have time, unless you are waiting for a known bug to be fixed.&lt;/p&gt;
&lt;h2 id=&quot;pick-the-most-important-libraries&quot; tabindex=&quot;-1&quot;&gt;Pick the most important libraries &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#pick-the-most-important-libraries&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If time is of the essence, you should pick the libraries that are most utilised, or most relevant to the project (i.e. those with the biggest impact), and keep up to speed with any relevant changes as updates arrive. As detailed in the previous section this should involve mainly paying attention to major and minor version number changes.&lt;/p&gt;
&lt;p&gt;It is not essential that you update the library for every patch release, but keeping track of the changes that are published will give you the opportunity to update when it is beneficial to the project.&lt;/p&gt;
&lt;p&gt;In reality, the smaller the update you apply, the easier it is to pin down bugs when they do occur, reducing time taken for mitigation, and lessening the risk involved.&lt;/p&gt;
&lt;h2 id=&quot;update-strategy---summary&quot; tabindex=&quot;-1&quot;&gt;Update strategy - Summary &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#update-strategy---summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Pay attention to major version number changes for &lt;strong&gt;ALL&lt;/strong&gt; libraries.&lt;/li&gt;
&lt;li&gt;Pay attention to minor version number changes for libraries that are most utilised, or most relevant to the project&lt;/li&gt;
&lt;li&gt;Patch version number changes can mostly be passed over without review, unless you are actively waiting for a bug to be fixed&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;the-potential-dangers-of-upgrading&quot; tabindex=&quot;-1&quot;&gt;The potential dangers of upgrading &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#the-potential-dangers-of-upgrading&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/danger.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/danger.jpg&quot; alt=&quot;a wooden danger do not enter sign in a wood in autumn&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@reinf?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Raúl Nájera&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/MggK54YixfU?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As already discussed, there are some real gains to be had from keeping up to date, but it can also cause unwanted problems, and lost time, due to debugging new errors.&lt;/p&gt;
&lt;p&gt;Again, this can mostly be avoided by paying attention to the release notes.&lt;/p&gt;
&lt;p&gt;I will refer you to the release notes of NumPy for version 1.24.0 as an example of what to expect. It is well laid out with lots of information (not always the case with all libraries/software):&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://numpy.org/doc/stable/release.html&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/numpy.png&quot; alt=&quot;NumPy Logo&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;Release notes — NumPy v2.4 Manual&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;© Copyright 2008-2025, NumPy Developers.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - numpy.org&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;The main problems that you will face are generally due to one of the following.&lt;/p&gt;
&lt;h2 id=&quot;deprecations-%2F-expired-deprecations&quot; tabindex=&quot;-1&quot;&gt;Deprecations / Expired Deprecations &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#deprecations-%2F-expired-deprecations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is probably the main item to pay attention to. When a method becomes deprecated it will eventually be removed (timescales vary). This is excellent as, assuming you are aware of the deprecation being applied, it gives you time to implement a work around, or switch to an updated method from the library.&lt;/p&gt;
&lt;p&gt;However, if you are looking at the release notes and notice one of your methods is listed in expired deprecations, then an immediate fix is required before upgrade, as your code will literally stop working.&lt;/p&gt;
&lt;h2 id=&quot;compatibility-notes-%2F-changes&quot; tabindex=&quot;-1&quot;&gt;Compatibility notes / changes &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#compatibility-notes-%2F-changes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is less severe than a deprecation, but can be tricky as they can change behaviour and/or outputs of functions. Something you may not immediately notice if you weren’t aware of it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;array.fill(scalar) may behave slightly different&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;numpy.ndarray.fill&lt;/code&gt; may in some cases behave slightly different now due to the fact that the logic is aligned with item assignment.&lt;/p&gt;
&lt;p&gt;Previously casting may have produced slightly different answers when using values that could not be represented in the target &lt;code&gt;dtype&lt;/code&gt; or when the target had &lt;code&gt;object&lt;/code&gt; dtype.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://numpy.org/doc/stable/release/1.24.0-notes.html#array-fill-scalar-may-behave-slightly-different&quot;&gt;numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“May behave slightly differently” is about as vague as it gets! A perfect example of something that could cause ‘interesting’ bugs if it is relevant to your code. The above would be worth looking into should you have a very sensitive implementation that uses this function.&lt;/p&gt;
&lt;h1 id=&quot;what-if-i-can%E2%80%99t-upgrade%3F&quot; tabindex=&quot;-1&quot;&gt;What if I can’t upgrade? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#what-if-i-can%E2%80%99t-upgrade%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/possible.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/possible.jpg&quot; alt=&quot;impossible written on a chalk board covered by hand to make it read possible&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/possible-written-on-a-chalkboard-9755375/&quot;&gt;Towfiqu barbhuiya&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In industry the reality is that you may have limitations on the upgrade process that are outside of your control. This could be caused by a choice of base operating system / container, or due to limitations in other areas of the project you are working on that require very specific versioning.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember, without solid information, no decisions can be made.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, it is still worth keeping up to date with the developments of key packages and libraries. If nothing else it is ammunition to push for what might be quite a complicated, and/or costly, upgrade process to be put into action, as the benefits may outweigh the upgrade cost. Remember, without solid information, no real decisions can be made.&lt;/p&gt;
&lt;h1 id=&quot;a-concrete-example-of-the-benefits-of-staying-up-to-date&quot; tabindex=&quot;-1&quot;&gt;A concrete example of the benefits of staying up to date &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#a-concrete-example-of-the-benefits-of-staying-up-to-date&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/concrete.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/concrete.jpg&quot; alt=&quot;some people smoothing a concrete floor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/selective-focus-photography-cement-2219024/&quot;&gt;Rodolfo Quirós&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Fairly recently, NumPy had a minor version number change from 1.23.5 to 1.24.0. As explained in an earlier section of this article, a minor version number change, can result in “minor feature changes”, rather than just the simple bug fixes that a patch update would bring.&lt;/p&gt;
&lt;p&gt;A couple of these “minor feature changes” claim to result in significantly sped up versions of their original functions:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;np.in1d&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;np.in1d&lt;/code&gt; (used by &lt;code&gt;np.isin&lt;/code&gt;) can now switch to a faster algorithm (up to &amp;gt;10x faster)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://numpy.org/doc/stable/release/1.24.0-notes.html#faster-version-of-np-isin-and-np-in1d-for-integer-arrays&quot;&gt;-numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;NumPy comparison functions&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The comparison functions (&lt;code&gt;numpy.equal&lt;/code&gt;, &lt;code&gt;numpy.not_equal&lt;/code&gt;, &lt;code&gt;numpy.less&lt;/code&gt;, &lt;code&gt;numpy.less_equal&lt;/code&gt;, &lt;code&gt;numpy.greater&lt;/code&gt; and &lt;code&gt;numpy.greater_equal&lt;/code&gt;) are now much faster as they are now vectorized with universal intrinsics. For a CPU with SIMD extension AVX512BW, the performance gain is up to 2.57x, 1.65x and 19.15x for integer, float and boolean data types, respectively (with N=50000).&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://numpy.org/doc/stable/release/1.24.0-notes.html#faster-version-of-np-isin-and-np-in1d-for-integer-arrays&quot;&gt;numpy.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;testing-the-claims&quot; tabindex=&quot;-1&quot;&gt;Testing the claims &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#testing-the-claims&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although I have no reason to doubt the numbers, I thought it might be interesting to test it out in practise, so the following sections will run benchmarks between the old an new versions to see what real world speed gains can be realised.&lt;/p&gt;
&lt;h2 id=&quot;notebooks&quot; tabindex=&quot;-1&quot;&gt;Notebooks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#notebooks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the code that follows is available in jupyter notebooks.&lt;/p&gt;
&lt;p&gt;This section gives details on the location of the notebooks, and also the requirements for the environment setup for online environments such as &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Colab&lt;/a&gt; and &lt;a href=&quot;https://deepnote.com/&quot;&gt;Deepnote&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The raw notebooks can be found here for your local environment:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/python-libraries-update&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/favicon/maskable_icon_x512.png&quot; alt=&quot;A simple way to speed up your python code reference notebooks&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/python-libraries-update at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;…or get kickstarted in either deepnote or colab.&lt;/p&gt;
&lt;p&gt;Python 1.24.0:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fpython-libraries-update%2Fpython_libraries_1.24.0.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch python notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/python-libraries-update/python_libraries_1.24.0.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Python 1.23.5:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fpython-libraries-update%2Fpython_libraries_1.23.5.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch julia notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/python-libraries-update/python_libraries_1.23.5.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch julia notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;environment-setup-%E2%80%94-local-or-deepnote&quot; tabindex=&quot;-1&quot;&gt;Environment Setup — Local or Deepnote &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#environment-setup-%E2%80%94-local-or-deepnote&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whether using a local environment, or deepnote, all that is needed is to ensure that the appropriate version of NumPy is available. The easiest way to achieve this is to add it to your “requirements.txt” file.&lt;/p&gt;
&lt;p&gt;For deepnote you can create a file called “requirements.txt” in the files section in the right pane and add the line:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;numpy&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.24&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(change the version number as appropriate).&lt;/p&gt;
&lt;h2 id=&quot;environment-setup-%E2%80%94-colab&quot; tabindex=&quot;-1&quot;&gt;Environment Setup — Colab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#environment-setup-%E2%80%94-colab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As there is no access to something like a “requirements.txt” file in colab you will need to explicitly install the correct version of NumPy. To do this run the following code in a blank cell to install the appropriate version:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;!pip install numpy&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.24&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(change the version number as appropriate).&lt;/p&gt;
&lt;p&gt;Then refresh the web page before trying to run any code.&lt;/p&gt;
&lt;h2 id=&quot;the-test&quot; tabindex=&quot;-1&quot;&gt;The test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#the-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following speed tests were run to give an overview of the improvements to the &lt;code&gt;np.in1d&lt;/code&gt; and &lt;code&gt;np.equal&lt;/code&gt; methods when using the latest NumPy version (1.24.0) compared to the previous version (1.23.5):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Two integer arrays with length 50000 using method &lt;code&gt;np.equal&lt;/code&gt; (method run 1 million times) — &lt;strong&gt;should be up to 2.75x faster with numpy 1.24.0 according to the documentation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Two boolean arrays with length 50000 using method &lt;code&gt;np.equal&lt;/code&gt; (method run 1 million times) — &lt;strong&gt;should be up to 19.15x faster with numpy 1.24.0 according to the documentation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Two integer arrays compared using &lt;code&gt;np.in1d&lt;/code&gt; using &lt;code&gt;kind=&amp;quot;sort&amp;quot;&lt;/code&gt; (method run 10 thousand times) — this method is available in both numpy 1.23.5 and 1.24.0 — &lt;strong&gt;should be the same speed in numpy 1.23.5 and 1.24.0 (a good cross-check between notebooks to ensure that the results of the other tests can be directly compared)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Two integer arrays compared using &lt;code&gt;np.in1d&lt;/code&gt; using the new &lt;code&gt;kind=&amp;quot;table&amp;quot;&lt;/code&gt; method (method run 10 thousand times) — this method is only available in numpy 1.24.0 — &lt;strong&gt;should be up to 10x faster than the “sort” method according to the documentation&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;input-data&quot; tabindex=&quot;-1&quot;&gt;Input data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#input-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/3fc49b6ddde64298a4b37c7b16011046?height=317&quot; height=&quot;317&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;timeit-setup&quot; tabindex=&quot;-1&quot;&gt;Timeit setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#timeit-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/d3708e8fd9a44e9ea2c644a1967fdc9a?height=371&quot; height=&quot;371&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/40e6b0b1c97f474e8c2fa86b45a32e6b?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/aa082e3d9b244a86a4d8ab38e4402215?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/aab4da8318894cd78d1e1fe1e652b78e?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/54676b73ac9a450ab00292b5641794ed?height=119&quot; height=&quot;119&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;results-%E2%80%94-numpy-1.23.5&quot; tabindex=&quot;-1&quot;&gt;Results — NumPy 1.23.5 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#results-%E2%80%94-numpy-1.23.5&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/13bbe0b4-7bd7-4ee1-b0f3-b816f3b49a1d/6c326080c2d048d1b255a3806a0ba29e/f173f11c83434c64a45c75838bb21d53?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/13bbe0b4-7bd7-4ee1-b0f3-b816f3b49a1d/6c326080c2d048d1b255a3806a0ba29e/69a94ac0f0b144698271559bc97bb67b?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/13bbe0b4-7bd7-4ee1-b0f3-b816f3b49a1d/6c326080c2d048d1b255a3806a0ba29e/0a574c02f2f04a88a659a5ef02590ae6?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;results-numpy-1.24.0&quot; tabindex=&quot;-1&quot;&gt;Results-NumPy 1.24.0 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#results-numpy-1.24.0&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/c8135b709b764491ada479ae28d4b8c2?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/15e52bc6b5f74fa19e60eeae94620412?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/cd976b6126314986808ed682f80d6fa3?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/f3a39b59-badb-4fe8-bc04-c668b74c7694/ddca407994764ee0a32ef82dfddb4a37/a9475c4f7b3942c9b92b27b02fa63717?height=134.1875&quot; height=&quot;134.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/comparison.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/simple-speed-up-python/comparison.png&quot; alt=&quot;bar chart of the test results&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Results comparison — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can see from the results sections, the results achieved are roughly inline with what was expected, and all methods achieve an increase in speed of execution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Two integer arrays using method &lt;code&gt;np.equal&lt;/code&gt; — &lt;strong&gt;4.67x faster&lt;/strong&gt; with numpy 1.24.0&lt;/li&gt;
&lt;li&gt;Two boolean arrays using method &lt;code&gt;np.equal &lt;/code&gt;— &lt;strong&gt;15.56x faster&lt;/strong&gt; with numpy 1.24.0&lt;/li&gt;
&lt;li&gt;Two integer arrays compared using &lt;code&gt;np.in1d&lt;/code&gt; using the &lt;code&gt;kind=&amp;quot;sort&amp;quot;&lt;/code&gt; method — &lt;strong&gt;more or less exactly the same execution time&lt;/strong&gt; using numpy 1.23.5 and 1.24.0 as expected (18.5 seconds for 10000 iterations)&lt;/li&gt;
&lt;li&gt;Two integer arrays compared using &lt;code&gt;np.in1d&lt;/code&gt; using the new &lt;code&gt;kind=&amp;quot;table&amp;quot;&lt;/code&gt; method — &lt;strong&gt;3.84x faster&lt;/strong&gt; with numpy 1.24.0 and the newly introduced &lt;code&gt;kind=&amp;quot;table&amp;quot;&lt;/code&gt; method&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/simple-speed-up-python/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The efforts of software developers to constantly improve the languages and libraries that we all use on a daily basis should not be ignored. It is one of the easiest and most accessible ways to improve the efficiency, speed and reliability of your projects code.&lt;/p&gt;
&lt;p&gt;As you can see from the very small example outlined in this article, the benefits can be quite significant. All it takes a little organisation, and the willingness to invest some time into reviewing the release notes for your most important libraries / software.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>How to Improve Clustering Accuracy with Bayesian Gaussian Mixture Models</title>
		<link href="https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/"/>
		<updated>Wed, 15 Feb 2023 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;In the real world you will often find that data follows a certain probability distribution. Whether it is a Gaussian (or normal) distribution, Weibull distribution, Poisson distribution, exponential distribution etc., will depend on the specific data.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Being aware of which distribution describes your data, or likely best describes your data, allows you to take advantage of that fact, and improve your inference and/or predictions.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will look at how leveraging knowledge of an underlying probability distribution of a dataset can improve the fit of a bog standard K-Means clustering model, and even allow for automatic selection of the number of appropriate clusters, directly from the underlying data.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A lot of the headline grabbing machine / deep learning techniques tend to involve &lt;em&gt;&lt;strong&gt;supervised&lt;/strong&gt;&lt;/em&gt; machine / deep learning i.e. the data has been labelled, and the models are given the correct answers to learn from. The trained model is then applied to future data to make predictions.&lt;/p&gt;
&lt;p&gt;This is all very useful, but the reality is that data is constantly being produced by businesses and people around the world, and the majority of it is not labelled. It is actually quite expensive and time consuming to label data in the vast majority of cases. This is where &lt;em&gt;&lt;strong&gt;unsupervised&lt;/strong&gt;&lt;/em&gt; learning comes in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…data is constantly being produced by businesses and people around the world, and the majority of it is not labelled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finding the best way to infer meaning from unlabelled data is a very important pursuit for many businesses. It allows the unearthing of potentially unknown, or less obvious, trends or groupings. It is then possible to assign resources, target specific groups of customers, or just instigate additional research and development.&lt;/p&gt;
&lt;p&gt;Further to this, a large majority of the time, the data involves people or natural processes in one form or other. Natural processes, and the behaviour of people are, more often than not, captured and described well by a Gaussian distribution.&lt;/p&gt;
&lt;p&gt;With this in mind, this article will take a look into how a Gaussian distribution, in the form of both a Gaussian Mixture Model (GMM) and a Bayesian Gaussian Mixture Model (BGMM), can be utilised to improve the clustering accuracy of a dataset that represents ‘natural processes’ encountered in real world datasets.&lt;/p&gt;
&lt;p&gt;As a comparison and base for judgement, the ubiquitous K-Means clustering algorithm will be used.&lt;/p&gt;
&lt;h1 id=&quot;the-plan%3F&quot; tabindex=&quot;-1&quot;&gt;The Plan? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-plan%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/whiteboard.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/whiteboard.jpg&quot; alt=&quot;man looking at a whiteboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/man-standing-infront-of-white-board-1181345/&quot;&gt;Christina Morillo&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This article will cover quite a lot of ground, and also incorporate examples from a comprehensive Jupyter notebook.&lt;/p&gt;
&lt;p&gt;This section should give you some guidance on what is covered and where to skip to should you need access to specific information.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initially the article will cover the “what” and “why” questions in regard to the use of Gaussian Mixture Models in general.&lt;/li&gt;
&lt;li&gt;As there are two readily available implementations of Gaussian Mixture Models within the scikit-learn library, a discussion of the key differences between a plain &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html&quot;&gt;Gaussian Mixture Model&lt;/a&gt; and &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.mixture.BayesianGaussianMixture.html#sklearn.mixture.BayesianGaussianMixture&quot;&gt;Bayesian Gaussian Mixture Model&lt;/a&gt; will follow.&lt;/li&gt;
&lt;li&gt;The article will then dive into using Gaussian Mixture Models to cluster a real world multi-featured dataset. All examples will be implemented using K-Means, a plain Gaussian Mixture Model and a Bayesian Gaussian Mixture Model.&lt;/li&gt;
&lt;li&gt;There will then be two additional sections primarily focused on clearer visualisation of the algorithms. Complexity of the data will be reduced by a) using a two component principle component analysis (PCA) and b) analysing only two features from the dataset&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;the dataset chosen is in fact labelled. This has been done deliberately so that the performance of the clustering can be compared to the 100% correct and known primary clustering.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-explanations&quot; tabindex=&quot;-1&quot;&gt;The Explanations &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-explanations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/we-start-from-why.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/we-start-from-why.jpg&quot; alt=&quot;postit note on a corkboard with we start from why written on it&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/notes-on-board-3782142/&quot;&gt;Polina Zimmerman&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here we cover the “what” and “why” type questions before getting stuck into the data to see it all in action.&lt;/p&gt;
&lt;p&gt;Before we get started, it is worth noting that there will be no discussion of what a Gaussian / Normal distribution is, or even what K-Means clustering is. There are plenty of great resources out there, and there just isn’t the space to cover it in this article. Therefore, a basic understanding of those concepts is assumed from this point on.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;the phrases “Gaussian distribution” and “Normal distribution” mean one and the same thing, and will be used interchangeably throughout this article.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-gaussian-mixture-model%3F&quot; tabindex=&quot;-1&quot;&gt;What is a Gaussian Mixture Model? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#what-is-a-gaussian-mixture-model%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In simple terms, the algorithm assumes that the data you provide it can be approximated with an unspecified mixture of different Gaussian distributions.&lt;/p&gt;
&lt;p&gt;The algorithm will try to extract and separate this mixture of Gaussian distributions and pass them back to you as separate clusters.&lt;/p&gt;
&lt;p&gt;That’s it really.&lt;/p&gt;
&lt;p&gt;So in essence, it is like K-Means clustering, but it has the added advantage of being able to apply additional statistical constraints on the data. This gives more flexibility to the shape of the clusters it can capture. In addition, it allows closely spaced, or slightly conjoined, clusters to be separated more precisely, as the algorithm has access to the statistical probabilities generated by the assumed Gaussian distributions.&lt;/p&gt;
&lt;p&gt;In a visual sense, if the analysis is restricted to two or three dimensions, the K-Means algorithm pins down cluster centres and applies a ‘circular’ or ‘spherical’ distribution around those centres.&lt;/p&gt;
&lt;p&gt;However, if the underlying data is Gaussian it is perfectly possible, and even expected, that the distribution will be elongated to some extent due to the tails of a Gaussian distribution. This would be the equivalent of an ‘ellipse’ or ‘ellipsoid’ in terms of shape. These elongated ‘ellipse’ or ‘ellipsoid’ type shapes are something K-Means cannot model accurately, but the Gaussian Mixture Models can.&lt;/p&gt;
&lt;p&gt;On the other side of the coin, if you pass the Gaussian Mixture Models data that is definitely nowhere near Gaussian, the algorithm will still assume it is Gaussian. You will therefore likely end up with, at best, something that is no better than K-Means.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Side note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;the Gaussian Mixture Model and Bayesian Gaussian Mixture Model can use the K-Means clustering algorithm to generate some of the initial parameters of the model (it is in fact the default setting in scikit-learn).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Which begs the question…&lt;/p&gt;
&lt;h2 id=&quot;what-type-of-data-could-gaussian-mixture-models-be-used-for%3F&quot; tabindex=&quot;-1&quot;&gt;What type of data could Gaussian Mixture Models be used for? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#what-type-of-data-could-gaussian-mixture-models-be-used-for%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Natural processes are usually a good place to start. The reason for this is mainly due to the Central Limit Theorem (CLT):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In probability theory, the &lt;strong&gt;central limit theorem&lt;/strong&gt; (&lt;strong&gt;CLT&lt;/strong&gt;) establishes that, in many situations, when independent random variables are summed up, their properly normalized sum tends toward a normal distribution even if the original variables themselves are not normally distributed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Central_limit_theorem&quot;&gt;-wikipedia.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In very simple terms, what this essentially means with natural processes is that although the particular variable (a humans height for example) is caused by many factors that may, or may not, be normally distributed (diet, lifestyle, environment, genes etc.) the normalised sum of those parts (the human height) will be (approximately) normally distributed. That is why we tend to see natural processes appearing to be normally distributed so regularly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/x-ray.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/x-ray.jpg&quot; alt=&quot;hands pointing at an x-ray&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/person-holding-black-pen-and-an-x-ray-4989192/&quot;&gt;Ivan Samkov&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As such, there are a surprisingly large amount of real world instances where it is necessary to deal with Gaussian distributions, making Gaussian Mixture Models a very useful tool if it used in the appropriate setting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customer behaviour&lt;/strong&gt; — this could be in terms of purchases made, amounts spent, attention span, churn etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human characteristics&lt;/strong&gt; — height, weight, shoe size, IQ (or educational performance) etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Natural phenomena&lt;/strong&gt; — recognition of patterns / groups in the medical field (cancers, diseases, genes etc.) or other scientific fields&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are obviously many other examples, and other situations where a Gaussian distribution may arise for other reasons.&lt;/p&gt;
&lt;p&gt;There may of course be cases where you cannot discern the underlying structure of the data, and this will of course warrant investigation, but is also one of the reasons why domain experts can be so important.&lt;/p&gt;
&lt;h2 id=&quot;why-use-a-gaussian-mixture-model%3F&quot; tabindex=&quot;-1&quot;&gt;Why use a Gaussian Mixture Model? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#why-use-a-gaussian-mixture-model%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The main reason is that if you are fairly confident that your data is Gaussian (or more precisely a mixture of Gaussian data) then you will give yourself a much better chance of separating out real clusters with much more accuracy.&lt;/p&gt;
&lt;p&gt;The algorithm not only looks for basic clusters, but also considers the most appropriate shape, or distribution, of each cluster. This allows for tightly spaced, or even slightly conjoined, clusters to be separated out more accurately and easily.&lt;/p&gt;
&lt;p&gt;Furthermore, where there are cases that the separation is not clear (or maybe just for more in depth analysis) it is possible to produce, and analyse, the probability that each data point belongs to each cluster. This gives you a better understanding of what are core reliable data points, and those that are perhaps marginal, or unclear.&lt;/p&gt;
&lt;p&gt;With Bayesian Gaussian Mixture models it is also possible to let the algorithm infer from the data the most appropriate number of clusters. Rather than having to rely on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Elbow_method_(clustering)&quot;&gt;elbow method&lt;/a&gt; or produce &lt;a href=&quot;https://en.wikipedia.org/wiki/Bayesian_information_criterion&quot;&gt;BIC&lt;/a&gt; / &lt;a href=&quot;https://en.wikipedia.org/wiki/Akaike_information_criterion&quot;&gt;AIC&lt;/a&gt; curves.&lt;/p&gt;
&lt;h2 id=&quot;how-does-a-gaussian-mixture-model-work%3F&quot; tabindex=&quot;-1&quot;&gt;How does a Gaussian Mixture Model work? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#how-does-a-gaussian-mixture-model-work%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is basically using an iterative updating process to gradually optimise the fit of a number of Gaussian distributions to the data. I suppose in a similar way to gradient decent.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Check the fit — adjust — check the fit again — adjust…and repeat until converged.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case the algorithm is called the &lt;a href=&quot;https://en.wikipedia.org/wiki/Expectation%E2%80%93maximization_algorithm&quot;&gt;expectation-maximisation&lt;/a&gt; (EM) algorithm. More specifically this is what happens:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One of the input parameters to the model is the number of clusters, so this is a known quantity. For example, if two clusters are set, then an initial set of two Gaussian distributions will have their parameters assigned. The parameters could be assigned by a K-Means analysis (the default in scikit-learn), or just randomly. The parameters could even be specified specifically for every data point, if you have a very specific case. Now on to the iteration…&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expectation&lt;/strong&gt; — now there are two Gaussian distributions that are defined with specific parameters. The algorithm first assigns each data point to one of the two Gaussian distributions. It does this based on the &lt;strong&gt;probability&lt;/strong&gt; that it fits into that particular distribution, compared to the other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximisation&lt;/strong&gt; — once all the points are assigned, the parameters of each Gaussian distribution are adjusted slightly to better fit the data as a whole, based on the information generated from the previous step.&lt;/li&gt;
&lt;li&gt;repeat steps 2 and 3 until convergence.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The above is overly simplified, and I haven’t detailed the exact mathematical mechanism (or equations) that are optimised at each point in time. However, it should give you at least a conceptual understanding of how the algorithm operates.&lt;/p&gt;
&lt;p&gt;As ever, there are plenty of mathematics heavy articles out there explaining in much more detail the exact mechanisms should that interest you.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-difference-between-a-normal-gaussian-mixture-model-and-a-bayesian-gaussian-mixture-model%3F&quot; tabindex=&quot;-1&quot;&gt;What is the difference between a normal Gaussian Mixture Model and a Bayesian Gaussian Mixture Model? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#what-is-the-difference-between-a-normal-gaussian-mixture-model-and-a-bayesian-gaussian-mixture-model%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m going to start by saying that, to explain the additional processes used by the Bayesian Gaussian Mixture Model over and above the standard Gaussian Mixture Model is actually quite involved. It requires an understanding of a few different, and complicated, mathematical concepts at the same time, and there certainly isn’t space in this article to do it justice.&lt;/p&gt;
&lt;p&gt;What I will aim to do here is point you in the right direction, and outline the advantages and disadvantages. You will also gather further information as you pass through the rest of the article while the dataset is analysed.&lt;/p&gt;
&lt;h3 id=&quot;practical-differences&quot; tabindex=&quot;-1&quot;&gt;Practical Differences &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#practical-differences&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The standout difference is that the standard Gaussian Mixture Model uses the &lt;a href=&quot;https://en.wikipedia.org/wiki/Expectation%E2%80%93maximization_algorithm&quot;&gt;expectation-maximisation&lt;/a&gt; (EM) algorithm, whereas the Bayesian Gaussian Mixture Model uses variational inference (VI).&lt;/p&gt;
&lt;p&gt;Unfortunately, variational inference is not mathematically straight forward, but if you want to get your hands dirty I suggest &lt;a href=&quot;https://jonathan-hui.medium.com/machine-learning-variational-inference-273d8e6480bb&quot;&gt;this excellent article&lt;/a&gt; by &lt;a href=&quot;https://medium.com/u/bd51f1a63813?source=post_page-----2ef8bb2d603f--------------------------------&quot;&gt;Jonathan Hui&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main take-aways are these:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;variational inference is an extension of the expectation-maximisation algorithm. Both aim to find Gaussian distributions within your data (in this instance at least)&lt;/li&gt;
&lt;li&gt;Bayesian Gaussian Mixture Models require more input parameters to be provided, which is potentially more involved / cumbersome&lt;/li&gt;
&lt;li&gt;variational inference inherently has a form of regularisation built in&lt;/li&gt;
&lt;li&gt;variational inference is less likely to generate ‘unstable’ or ‘marginal’ solutions to the problem. This makes it more likely that the algorithm will tend towards a solidly backed ‘real’ solution. Or as &lt;a href=&quot;https://scikit-learn.org/stable/modules/mixture.html&quot;&gt;scikit-learn’s documentation&lt;/a&gt; puts it “&lt;em&gt;due to the incorporation of prior information, variational solutions have less pathological special cases than expectation-maximization solutions.&lt;/em&gt;”&lt;/li&gt;
&lt;li&gt;Bayesian Gaussian Mixture Models can directly estimate the most appropriate amount of clusters for the input data (no elbow methods required!)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;…so to summarise:&lt;/p&gt;
&lt;p&gt;Variational inference is a more advanced &lt;strong&gt;extension&lt;/strong&gt; to the idea behind expectation-maximisation. It should in theory be more accurate and more resistant to messy data or outliers.&lt;/p&gt;
&lt;h3 id=&quot;resources-and-further-reading&quot; tabindex=&quot;-1&quot;&gt;Resources and further reading &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#resources-and-further-reading&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As a start I would point you to the excellent overview provided in the literature for scikit-learn:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://scikit-learn.org/stable/modules/mixture.html&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/scikit_learn_logo.png&quot; alt=&quot;Gaussian mixture models&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;2.1. Gaussian mixture models&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;sklearn.mixture is a package which enables one to learn Gaussian Mixture Models (diagonal, spherical, tied and full covariance matrices supported), sample them, and estimate them from data. Facilit…&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - scikit-learn&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;For further reading, some relevant subjects to look up are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Expectation-Maximisation (EM)&lt;/li&gt;
&lt;li&gt;Variational Inference (VI)&lt;/li&gt;
&lt;li&gt;The Dirichlet distribution and Dirichlet process&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;now-for-some-real-data&quot; tabindex=&quot;-1&quot;&gt;Now for some real data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#now-for-some-real-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/wine.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/wine.jpg&quot; alt=&quot;a glass of red wine and bunch of black grapes on a wooden bench&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/a-glass-of-red-wine-on-a-wooden-bench-8473214/&quot;&gt;Cup of Couple&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Discussion and theory are great, but I often find exploring a real implementation can clarify a great deal. With that in mind, the following sections will make a comparison of the performance of each of the following clustering methods on a real world dataset:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;K-Means (the baseline)&lt;/li&gt;
&lt;li&gt;Gaussian Mixture Model&lt;/li&gt;
&lt;li&gt;Bayesian Gaussian Mixture Model&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The Data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://archive-beta.ics.uci.edu/dataset/109/wine&quot;&gt;real world dataset&lt;/a&gt;&lt;sup&gt;[1]&lt;/sup&gt; that will be used describes the chemical composition of three different varieties of wine from the same region of Italy.&lt;/p&gt;
&lt;p&gt;This dataset is labelled, so although all the clustering analysis that follows will not use the labels in the analysis, it will allow a comparison to a known correct answer. The three methods of clustering can therefore be compared fairly and without bias.&lt;/p&gt;
&lt;p&gt;Furthermore, the dataset meets the criterion of being a “natural” dataset, which should be a good fit for the Gaussian methods that are the intended test target.&lt;/p&gt;
&lt;p&gt;To ease the ability to load the data I have made the raw data available in CSV format in my GitHub repository:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/datasets/wine&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/favicon/maskable_icon_x512.png&quot; alt=&quot;bayesian gaussian mixing raw data&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/datasets/wine at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h2 id=&quot;reference-notebooks&quot; tabindex=&quot;-1&quot;&gt;Reference Notebooks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#reference-notebooks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the analysis that follows has been made available in a comprehensive Jupyter notebook.&lt;/p&gt;
&lt;p&gt;The raw notebook can be found here for your local environment:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/blob/main/bayesian_gaussian_mixture_model.ipynb&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/favicon/maskable_icon_x512.png&quot; alt=&quot;bayesian gaussian mixing reference notebook&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/bayesian_gaussian_mixture_model.ipynb at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;…or get kickstarted in either Deepnote or Colab if you want an online solution:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepnote.com/launch?url=https%3A%2F%2Fgithub.com%2Fthetestspecimen%2Fnotebooks%2Fblob%2Fmain%2Fbayesian_gaussian_mixture_model.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/deepnote-badge.png&quot; alt=&quot;Launch python notebook in deepnote&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/bayesian_gaussian_mixture_model.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are some functions that are used within the notebooks that require certain libraries to be reasonably up to date (specifically scikit-learn and matplotlib), so the following sections will describe what is needed.&lt;/p&gt;
&lt;h2 id=&quot;environment-setup-%E2%80%94-local-or-deepnote&quot; tabindex=&quot;-1&quot;&gt;Environment Setup — Local or Deepnote &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#environment-setup-%E2%80%94-local-or-deepnote&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whether using a local environment, or Deepnote, all that is needed is to ensure that the appropriate version of scikit-learn and matplotlib is available. The easiest way to achieve this is to add it to your “requirements.txt” file.&lt;/p&gt;
&lt;p&gt;For Deepnote you can create a file called “requirements.txt” in the files section in the right pane, and add the lines:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;scikit&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;learn&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.0&lt;/span&gt;
matplotlib&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3.6&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(more recent versions are also ok).&lt;/p&gt;
&lt;h2 id=&quot;environment-setup-%E2%80%94-colab&quot; tabindex=&quot;-1&quot;&gt;Environment Setup — Colab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#environment-setup-%E2%80%94-colab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As there is no access to something like a “requirements.txt” file in Colab you will need to explicitly install the correct versions of scikit-learn and matplotlib. To do this run the following code in a blank cell to install the appropriate versions:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;!pip install scikit&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;learn&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.0&lt;/span&gt;
!pip install matplotlib&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3.6&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(more recent versions are also ok).&lt;/p&gt;
&lt;p&gt;Then refresh the web page before trying to run any code, so the libraries are properly loaded.&lt;/p&gt;
&lt;h2 id=&quot;data-exploration&quot; tabindex=&quot;-1&quot;&gt;Data Exploration &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#data-exploration&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before running the actual clustering it might be worth just getting a rough overview of the data.&lt;/p&gt;
&lt;p&gt;There are 13 features and 178 examples for each feature (no missing or null data):&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/d7208d69f6004ee390d0057e62c29c52?height=532.9375&quot; height=&quot;532.9375&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/032b5f265f6e4963908804ae78b0e3ec?height=634&quot; height=&quot;634&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;…so a nice clean numerical dataset to get started with.&lt;/p&gt;
&lt;p&gt;The only thing that really needs changing is the scale. The range of numbers within each of the features varies quite a bit, so a simple &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html&quot;&gt;MinMaxScaler&lt;/a&gt; will be applied to the features so that they all sit between 0 and 1.&lt;/p&gt;
&lt;h2 id=&quot;data-distribution&quot; tabindex=&quot;-1&quot;&gt;Data Distribution &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#data-distribution&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As previously mentioned, it would be ideal if the data was at least approximately Gaussian to allow the Gaussian Mixture Model to work effectively. So how does it look?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/all-data-distribution.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/all-data-distribution.png&quot; alt=&quot;feature distribution histograms&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Feature data distribution — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now some of those look quite Gaussian (e.g. alkalinity of ash), but the reality is most do not. Is this a problem? Well not necessarily, as what really exists in a lot of cases is a *&lt;strong&gt;mixture*&lt;/strong&gt; of Gaussian distributions (or approximate Gaussian distributions).&lt;/p&gt;
&lt;p&gt;The whole point of the Gaussian Mixture Model is that it can find and separate out the individual Gaussian distributions from a mixture of more than one Gaussian distribution.&lt;/p&gt;
&lt;p&gt;In a real clustering problem you would not be able to achieve this next step, as you wouldn’t know the real clustering of the data. However, just for illustration purposes it is possible (as we know the labels) to plot each individual ‘real’ clusters distribution:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/feature-data-distribution.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/feature-data-distribution.png&quot; alt=&quot;kde feature distribution by label&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Feature data distribution by label — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can now see the real clusters are in most cases approximately Gaussian. This is not the case across the board, but it will never be the case with real data. As expected, due to the data being based on “natural” data we are indeed dealing with approximately Gaussian data.&lt;/p&gt;
&lt;p&gt;This very basic investigation of the distribution of the raw data illustrates the importance of being aware of the type of data you are dealing with, and which tools would be best suited to the analysis. This is also a good case for the importance of domain experts, where appropriate.&lt;/p&gt;
&lt;h2 id=&quot;feature-relations&quot; tabindex=&quot;-1&quot;&gt;Feature relations &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#feature-relations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, a few examples of how some of the variables are distributed in relation to each other (if you want a more comprehensive plot please take a look at the Jupyter notebook):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/scatter-example.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/scatter-example.png&quot; alt=&quot;example scatter plots of the data&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;An example of the distribution of data between components — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As can be seen from the scatter plots above, some features show reasonable separation. However, there is also quite a lot of mixing with some features, and more so on the periphery of each cluster. The shape (circular, elongated etc.) also varies quite widely.&lt;/p&gt;
&lt;h1 id=&quot;the-analysis&quot; tabindex=&quot;-1&quot;&gt;The Analysis &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-analysis&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/scientist.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/scientist.jpg&quot; alt=&quot;a chemist mixing liquids&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/a-chemist-analyzing-chemicals-on-test-tubes-in-a-laboratory-8532827/&quot;&gt;Artem Podrez&lt;/a&gt; from &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As mentioned earlier, there will be three different algorithms compared:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;K-Means (the baseline)&lt;/li&gt;
&lt;li&gt;Gaussian Mixture Model&lt;/li&gt;
&lt;li&gt;Bayesian Gaussian Mixture Model&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There will also be three phases to the exploration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All of the raw data analysed at once&lt;/li&gt;
&lt;li&gt;All of the data analysed after reducing complexity / features with a Principle Component Analysis (PCA)&lt;/li&gt;
&lt;li&gt;An analysis using just two features (mainly to allow easier illustration than using the full dataset)&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;analysis-1-%E2%80%94-the-full-dataset&quot; tabindex=&quot;-1&quot;&gt;Analysis 1 — the full dataset &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#analysis-1-%E2%80%94-the-full-dataset&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To keep the comparison consistent, and reduce the complexity of this article I am going to skip a thorough investigation into how many components is the correct number.&lt;/p&gt;
&lt;p&gt;However, just for completeness you should be aware that a crucial step in performing any clustering is gaining an understanding of the appropriate amount of clusters to use. Some common examples of how to achieve this are the &lt;a href=&quot;https://en.wikipedia.org/wiki/Elbow_method_(clustering)&quot;&gt;elbow method&lt;/a&gt;, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bayesian_information_criterion&quot;&gt;Bayesian Information Criterion (BIC)&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Akaike_information_criterion&quot;&gt;Akaike information criterion&lt;/a&gt;. As an example here are the BIC and AIC for the whole raw dataset:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bic-aic.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bic-aic.png&quot; alt=&quot;a line graph of the bic and aic curves for the data&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The BIC and AIC curves for this dataset — Image by Author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The BIC would suggest two components is appropriate, but I’m not going to go further into this result for now. However, it will come up in discussion later in the article.&lt;/p&gt;
&lt;p&gt;Three clusters will be assumed from now on for consistency and ease of comparison.&lt;/p&gt;
&lt;p&gt;Let’s get stuck in!&lt;/p&gt;
&lt;h2 id=&quot;k-means&quot; tabindex=&quot;-1&quot;&gt;K-Means &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#k-means&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/100eaabcd92f4cedad635096ffd32f2c?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/2303362e46344d3888d53cea9d497100?height=152.1875&quot; height=&quot;152.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/k-means-cm.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/k-means-cm.png&quot; alt=&quot;k-means confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;K-Means confustion matrix — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well that is a fairly impressive result.&lt;/p&gt;
&lt;p&gt;With all data taken together there is apparently very good separation between clusters 1 and 3. However, as cluster 2 generally sits between clusters 1 and 3 (refer back to the four example scatter plots in the previous section) it would appear that the points on the periphery of cluster 2 are being wrongly assigned to clusters 1 and 3 (i.e. the boundaries between those clusters are likely incorrectly defined).&lt;/p&gt;
&lt;p&gt;Let’s see if this improves with a Gaussian Mixture Model.&lt;/p&gt;
&lt;h2 id=&quot;gaussian-mixture-model&quot; tabindex=&quot;-1&quot;&gt;Gaussian Mixture Model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#gaussian-mixture-model&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/be1b6ed4ca6c4666b15b2c5951f2a130?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/015c5c0647b74c148b85c83897ef1f07?height=152.1875&quot; height=&quot;152.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/gmm-cm.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/gmm-cm.png&quot; alt=&quot;gaussian mixing confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Gaussian Mixture Model confusion matrix — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;An improvement. The Gaussian Mixture Model has managed to pick up three extra points and assign them correctly to cluster 2.&lt;/p&gt;
&lt;p&gt;Although that doesn’t seem like a big deal, it is worth bearing in mind that the dataset is quite small, and using a more comprehensive dataset would likely yield a more impressive number of points.&lt;/p&gt;
&lt;h2 id=&quot;bayesian-gaussian-mixture-model&quot; tabindex=&quot;-1&quot;&gt;Bayesian Gaussian Mixture Model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#bayesian-gaussian-mixture-model&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before producing the result, and as this is the main focus of the article, I think it is worth taking a little time to explain some of the relevant parameters that can be specified:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;n_components&lt;/strong&gt; — this is the number of clusters that you want the algorithm to consider. However, the algorithm may return, or prefer, less clusters than set here, which is one of the main advantages of this algorithm (we will see this in action soon)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;covariance_type&lt;/strong&gt; — there are four options here &lt;em&gt;full&lt;/em&gt;, &lt;em&gt;tied&lt;/em&gt;, &lt;em&gt;diag&lt;/em&gt; and &lt;em&gt;spherical&lt;/em&gt;. The most ‘accurate’ and typically preferred is &lt;em&gt;full&lt;/em&gt;. This parameter essentially decides the limitation of the distribution fit shape, a great illustration is provided &lt;a href=&quot;https://scikit-learn.org/stable/auto_examples/mixture/plot_gmm_covariances.html#sphx-glr-auto-examples-mixture-plot-gmm-covariances-py&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;weight_concentration_prior_type&lt;/strong&gt; — this can either be &lt;em&gt;dirichlet_process&lt;/em&gt; (infinite mixture model) or d&lt;em&gt;irichlet_distribution&lt;/em&gt; (finite mixture model). In general, it is better to opt for the Dirichlet process as it is less sensitive to parameter changes, and does not tend to divide natural clusters into unnecessary sub-components as the Dirichlet distribution can sometimes do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;weight_concentration_prior&lt;/strong&gt; — specifying a low value (e.g. 0.01) will cause the model to set a larger number of components to zero leaving just a few components remaining with significant value. High values (e.g. 100000) will tend to allow a larger number of components to remain active with relevant values i.e. less components will be set to zero.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As there are quite a lot of extra parameters it may be wise to perform cross validation analysis in some cases. For example, in this initial run covariance_type will be set to ‘diag’ rather than ‘full’ as the suggested cluster number is more convincing. I suspect in this specific case this is due to a combination of a smaller dataset, and a large number of features causing the ‘full’ covariance type to over-fit.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/4936745c1813462390397358f7fd805d?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;It is now possible to review what the algorithm has decided in terms of relevant clusters. This is possible by extracting the weights from the fitted model:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/2f5ae51c395442189e9dcf812ec71a7f?height=153.375&quot; height=&quot;153.375&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;A bit more clearly in graph form:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/components.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/components.png&quot; alt=&quot;Bayesian gaussian mixing weights of each group&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bayesian Gaussian Mixture Model group weights — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To be honest, not very convincing.&lt;/p&gt;
&lt;p&gt;It is clear that there are three clusters ahead of the rest, but this is only intuitive because the answer is known. The truth is it is not very clear. So why is this?&lt;/p&gt;
&lt;p&gt;The main reason is likely due to a combination of lack of data, and a high number of features (at least compared to the amount of data).&lt;/p&gt;
&lt;p&gt;Lack of data will cause items such as outliers to have a much larger effect on the overall distribution, but also reduce the models ability to generate a distribution in the first place.&lt;/p&gt;
&lt;p&gt;In the sections that follow we will look at a way to potentially combat this, and also at analysing a smaller selection of features to see what result we get in those circumstances.&lt;/p&gt;
&lt;p&gt;For now, as we know the correct number of components is three we will push on.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/fc8e3410ffe44099885e752cecdfe1b3?height=101&quot; height=&quot;101&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/08afd567dfc04760be028d55af199944?height=152.1875&quot; height=&quot;152.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bgmm-cm.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bgmm-cm.png&quot; alt=&quot;Bayesian gaussian mixing confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bayesian Gaussian Mixture Model confusion matrix — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Almost perfect clustering. Only two points remain incorrectly assigned.&lt;/p&gt;
&lt;p&gt;Let’s take a quick look at an overall comparison.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/main-result-comp.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/main-result-comp.png&quot; alt=&quot;Accuracy comparison of the different clustering methods&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Accuracy comparison of the different clustering methods — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;discussion&quot; tabindex=&quot;-1&quot;&gt;Discussion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#discussion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As can be seen from the accuracy results, there is a gradual improvement from one method to the next. This goes to show that understanding the structure of the underlying data is important, as it allows a more accurate representation of the patterns within the raw data, in our case Gaussian distributions.&lt;/p&gt;
&lt;p&gt;Even within the realm of Gaussian Mixture Models, it is also clear (at least in this case) that the use of variational inference in the Bayesian Gaussian Mixture Model can yield more accurate results than expectation-maximisation.&lt;/p&gt;
&lt;p&gt;All of this was expected, but it is interesting to see nonetheless.&lt;/p&gt;
&lt;h2 id=&quot;visualisation&quot; tabindex=&quot;-1&quot;&gt;Visualisation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#visualisation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To give a general overview of what exactly the Gaussian algorithms are doing, I have plotted the feature “alcohol” against each of the other features, and also included the confidence ellipses of the Bayesian Gaussian Mixture Model on each plot for each of the three clusters.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;the algorithm used to draw the confidence ellipses is adapted from&lt;/em&gt; &lt;a href=&quot;https://scikit-learn.org/stable/auto_examples/mixture/plot_gmm.html&quot;&gt;&lt;em&gt;this algorithm&lt;/em&gt;&lt;/a&gt; &lt;em&gt;provided in the scikit-learn documentation.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/main-fit-comparison.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/main-fit-comparison.png&quot; alt=&quot;bayesian gaussian mixture model comparison of all features to alcohol feature&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bayesian Gaussian Mixture Model - Alcohol compared to all other features — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Although this is interesting to look at, and does do a good job of showing how the algorithm can account for the various shapes of the clusters (i.e. round, of more elongated ellipses) it doesn’t allow any sort of understanding as to what factors may have influenced the outcome.&lt;/p&gt;
&lt;p&gt;This is mainly due to the fact that there are too many dimensions to deal with (i.e. too many features) in terms of representing the output as something interpretable.&lt;/p&gt;
&lt;h2 id=&quot;better-visualisation-and-further-investigation&quot; tabindex=&quot;-1&quot;&gt;Better visualisation and further investigation &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#better-visualisation-and-further-investigation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It would be interesting to visualise and compare the distributions produced by the various methods in a clear and concise way, so that it is possible to see exactly what is going on under the hood.&lt;/p&gt;
&lt;p&gt;However, due to the large amount of features (and therefore dimensions) the model is processing, it is not possible to represent what is going on in a simple 2D graph, as has just been illustrated in the previous section.&lt;/p&gt;
&lt;p&gt;With this in mind the aim of the next two sections of this article is to simplify the analysis by reducing the dimensions. The following two sections of this article will therefore look into:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the use of a two component Principle Component Analysis (PCA). This will allow all of the thirteen features to be distilled into two features, whilst keeping the *&lt;strong&gt;majority*&lt;/strong&gt; of the important information embedded in the data.&lt;/li&gt;
&lt;li&gt;specifically using only two features to run the analysis.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both of these investigations will allow a direct visualisation of the clusters as there are only two components, and therefore it is then possible to plot them on a standard 2D graph.&lt;/p&gt;
&lt;p&gt;Furthermore, these approaches will potentially make it easier to use the Bayesian Gaussian Mixture Model’s automatic cluster selection more effectively, as the amount of features in relation to the number of examples is more in balance.&lt;/p&gt;
&lt;h1 id=&quot;analysis-2-%E2%80%94-principle-component-analysis-(pca)&quot; tabindex=&quot;-1&quot;&gt;Analysis 2 — Principle Component Analysis (PCA) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#analysis-2-%E2%80%94-principle-component-analysis-(pca)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;By running a two component Principle Component Analysis (PCA) the 13 features can be compressed down to 2 components.&lt;/p&gt;
&lt;p&gt;The main aims for this section are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Gain insights into the data distribution from the reduced complexity afforded by the PCA before analysis.&lt;/li&gt;
&lt;li&gt;Review the automatic component selection generated by the Baysian Gaussian Mixture Model from the PCA dataset.&lt;/li&gt;
&lt;li&gt;Run the Bayesian Gaussian Mixture Model on the two PCA components, and review the clustering result in 2D graph form.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-result-of-the-pca&quot; tabindex=&quot;-1&quot;&gt;The result of the PCA &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-result-of-the-pca&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-grouping.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-grouping.png&quot; alt=&quot;result of running a PCA&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The two components of the PCA on all the data with distributions (colours are real label clusters) — Image by Author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The result of the PCA is interesting for quite a few reasons.&lt;/p&gt;
&lt;p&gt;Firstly, the distribution of the primary PCA component (and to some degree the secondary PCA component) is very close to a Gaussian distribution for all three components. Mirroring what we have discovered from the data investigation earlier in the article.&lt;/p&gt;
&lt;p&gt;Remembering for a second that the PCA is a distillation of all of the features, it is interesting to see that there is good separation between the three real clusters. This means there is a very good possibility that a clustering algorithm that targets the data well (regardless of the PCA) has the potential to achieve a good and accurate separation of the clusters.&lt;/p&gt;
&lt;p&gt;However, the clusters are close enough, that if the clustering algorithm does not represent the distribution, or shape, of the clusters correctly, there is no guarantee that the boundary between the clusters will be found accurately.&lt;/p&gt;
&lt;p&gt;For example, the distribution of cluster 1 is quite clearly elongated along the y-axis. Any algorithm would need to mimic this elongated shape to represent that particular cluster correctly.&lt;/p&gt;
&lt;h2 id=&quot;automatic-clusters&quot; tabindex=&quot;-1&quot;&gt;Automatic Clusters &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#automatic-clusters&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the initial analysis the automatic estimation of the correct number of clusters was a little ambiguous. Now that the data complexity has been reduced let’s see if there is any improvement.&lt;/p&gt;
&lt;p&gt;Again, the inputs request 8 components:&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/3863697be6a04af9b741a5e41dd72f17?height=83&quot; height=&quot;83&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-weights.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-weights.png&quot; alt=&quot;weights of requested clusters for the PCA&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The weights of each of the 8 requested clusters — Image by Author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;…and there we are. A very clear indication that even though the model was set up to consider up to 8 clusters, the algorithm clearly thinks that the actual appropriate number of clusters is 3. Which we of course know to be correct.&lt;/p&gt;
&lt;p&gt;This goes some way to indicate that for the Bayesian Gaussian Mixture Model to work effectively, in terms of automatic cluster selection, it is necessary to consider whether the dataset is large enough to generate a reasonable and definitive result if the number of clusters is not already known.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot; tabindex=&quot;-1&quot;&gt;The result &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#the-result&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For completeness let’s see how the clustering for the Bayesian Gaussian Mixture Model of the PCA went.&lt;/p&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/b6c6fa9be3044f1f8835c69369bc5249?height=94.1875&quot; height=&quot;94.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-cm.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-cm.png&quot; alt=&quot;Bayesian Gaussian Mixture Model (PCA) confusion matrix&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bayesian Gaussian Mixture Model (PCA) confusion matrix — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A definite accuracy drop when compared to using the raw data. This is of course expected. By running a PCA we are definitely losing data, there is no avoiding that, and in this case it is enough to introduce an additional 5 misassigned data points.&lt;/p&gt;
&lt;p&gt;Let’s look at this visually in a little more detail.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-ovals_v2.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/pca-ovals_v2.png&quot; alt=&quot;Bayesian Gaussian Mixing of a two component PCA mismatched points ringed red. Mismatched points from original analysis of all data ringed in blue&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bayesian Gaussian Mixing of a two component PCA (mismatched points ringed red) — Mismatched points from original analysis of all data ringed in blue — Image by Author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The graph above has a lot going on, so let’s break this down:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the coloured dots are the clusters that the PCA data was assigned to by the algorithm.&lt;/li&gt;
&lt;li&gt;the large shaded ellipses are the confidence ellipses, which essentially state the shape of the underlying distribution generated by the algorithm (co-variances).&lt;/li&gt;
&lt;li&gt;the red circles are the data points that have been misassigned by the Bayesian Gaussian Mixing Model from the PCA analysis.&lt;/li&gt;
&lt;li&gt;the blue circles are the data points that were misassigned by the Bayesian Gaussian Mixing Model in the original analysis that used all of the raw data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What is particularly interesting is that by running the PCA analysis, and likely due to the inherent loss of data, it forces some data points to be shifted well within the clusters / confidence ellipses that are generated (look at the orange point labelled with text, and dot circled blue within the green confidence ellipsoid).&lt;/p&gt;
&lt;p&gt;In the case of the blue circled green point it helped, it is an improvement over the original ‘all raw data’ analysis. However, it is quite clear the orange point that is misassigned would never be correctly assigned, as it too well embedded within the orange cluster, when in fact it should be in the green cluster. However, the original analysis correctly assigned this data point to the green cluster.&lt;/p&gt;
&lt;h2 id=&quot;pca-summary&quot; tabindex=&quot;-1&quot;&gt;PCA Summary &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#pca-summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this particular case, it was useful with a smaller dataset to run a PCA to help the Bayesian Gaussian Mixture Model fix on an appropriate number of clusters. Even as an aid in getting a good visual grasp of how the dataset is distributed, it is potentially very useful.&lt;/p&gt;
&lt;p&gt;However, it would not be an optimal solution to use the data generated by the PCA as a final input into the analysis. It is clear that the data shift / loss is sufficient enough as to potentially make some data points permanently wrongly assigned, and the overall accuracy is also reduced.&lt;/p&gt;
&lt;h1 id=&quot;analysis-3-%E2%80%94-fewer-features&quot; tabindex=&quot;-1&quot;&gt;Analysis 3 — Fewer features &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#analysis-3-%E2%80%94-fewer-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To take a closer look at the differences between the three clustering algorithms two specific features will be extracted, and the clustering algorithms run on only those features.&lt;/p&gt;
&lt;p&gt;The advantage of this in terms of reviewing the methods, is that it becomes possible to visualise what is going on a 2D-plane (i.e. a normal 2D graph).&lt;/p&gt;
&lt;p&gt;An added bonus, is that the available data has much less information than the whole dataset. This both reduces the discrepancy between the small number of samples and the number of features, whilst also forcing the clustering algorithms to work much harder to achieve an appropriate fit due to the reduced information.&lt;/p&gt;
&lt;h2 id=&quot;a-closer-look-at-the-data&quot; tabindex=&quot;-1&quot;&gt;A closer look at the data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#a-closer-look-at-the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-data.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-data.png&quot; alt=&quot;Colour intensity vs OD280/OD315 of diluted wines (raw data with labels)&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Colour intensity vs OD280/OD315 of diluted wines (raw data with labels) — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The reason for picking this pair (colour intensity and OD280/OD315 of diluted wines) is due to the challenges the dataset throws up for the different clustering algorithms.&lt;/p&gt;
&lt;p&gt;As you can see there are two clusters that are fairly intermingled (1 &amp;amp; 2). In addition, clusters 2 &amp;amp; 3 have quite elongated distributions compared to cluster 1, which is more rounded, or circular.&lt;/p&gt;
&lt;p&gt;In theory, the Gaussian mixing methods should fair quite a bit better than K-Means as they have the ability to accurately mould their distribution characteristics to the elongated distributions, whereas K-Means cannot, as it is limited to a circular representation.&lt;/p&gt;
&lt;p&gt;Furthermore, from the KDE plots at each side of the graph it is possible to see that the data distribution is reasonably Gaussian as we have confirmed a few times before in this article.&lt;/p&gt;
&lt;h2 id=&quot;k-means-%E2%80%94-results&quot; tabindex=&quot;-1&quot;&gt;K-Means — Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#k-means-%E2%80%94-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/5a0896a7d5434e4b943309fa57527b5c?height=152.1875&quot; height=&quot;152.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/k-means-cm-spec.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/k-means-cm-spec.png&quot; alt=&quot;Confusion matrix for the K-Means - Reduced features&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Confusion matrix for the K-Means - Reduced features — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;gaussian-mixture-model-%E2%80%94-results&quot; tabindex=&quot;-1&quot;&gt;Gaussian Mixture Model — Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#gaussian-mixture-model-%E2%80%94-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/6861b77fd10f4af097c78977e845635a?height=94.1875&quot; height=&quot;94.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/gmm-cm-spec.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/gmm-cm-spec.png&quot; alt=&quot;Confusion matrix for the Gaussian Mixture Model — Reduced features&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Confusion matrix for the Gaussian Mixture Model — Reduced features — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;bayesian-gaussian-mixture-model-%E2%80%94-component-selection&quot; tabindex=&quot;-1&quot;&gt;Bayesian Gaussian Mixture Model — Component selection &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#bayesian-gaussian-mixture-model-%E2%80%94-component-selection&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving straight into the results, as the Bayesian Gaussian Mixture Model has the ability to auto-select the appropriate number of components we will again ‘request’ 8 components and see what the model suggests.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-grouping.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-grouping.png&quot; alt=&quot;Component selection for the Bayesian Gaussian Mixture Model with two features only&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Component selection for the Bayesian Gaussian Mixture Model with two features only — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As previously seen with the reduced complexity of the PCA analysis, the model has found it much easier to distinguish the 3 clusters that are known to exist.&lt;/p&gt;
&lt;p&gt;This would fairly conclusively confirm that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;it is necessary to have sufficient data samples to ensure that the model can stand a decent chance of offering the correct suggestion for number of clusters. This is likely due to the need to have enough data to properly represent the underlying distribution. In this case Gaussian.&lt;/li&gt;
&lt;li&gt;a potential way to combat lack of samples is to in some way simplify or generalise the data to try and extract the appropriate number of clusters, and then revert to the full dataset for a final full clustering analysis&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;bayesian-gaussian-mixture-model-%E2%80%94-results&quot; tabindex=&quot;-1&quot;&gt;Bayesian Gaussian Mixture Model — Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#bayesian-gaussian-mixture-model-%E2%80%94-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;iframe title=&quot;Embedded cell output&quot; src=&quot;https://embed.deepnote.com/4ae8c2eb-68cc-494e-8996-818a48e0cf75/987957c609e146bca29ee50afcde38b0/640ce2f6e7054ff3a44a1e7af3f18902?height=152.1875&quot; height=&quot;152.1875&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bgmm-cm-spec.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/bgmm-cm-spec.png&quot; alt=&quot;Confusion matrix for the Bayesian Gaussian Mixture Model — Reduced features&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Confusion matrix for the Bayesian Gaussian Mixture Model — Reduced features — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-results-comparison&quot; tabindex=&quot;-1&quot;&gt;Final results comparison &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#final-results-comparison&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-result.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/selected-result.png&quot; alt=&quot;The accuracy of each clustering method for features colour intensity and OD280/OD315 of diluted wines&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The accuracy of each clustering method for features colour intensity and OD280/OD315 of diluted wines — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As expected, the accuracy is a lot lower than when using the full dataset. However, regardless of this fact, there are some stark differences between the accuracy of the various methods.&lt;/p&gt;
&lt;p&gt;Let’s dig a little deeper by comparing everything side-by-side.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/final-comparison.png&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/clustering-bayesian-gaussian/final-comparison.png&quot; alt=&quot;A comparison of the assignment of clusters for each of the three clustering methods — Cluster 1 (red) / Cluster 2 (orange/green) / Cluster 3 (grey/blue)&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A comparison of the assignment of clusters for each of the three clustering methods — Cluster 1 (red) / Cluster 2 (orange/green) / Cluster 3 (grey/blue) — Image by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first thing to note is that the real labels show that there is a certain amount of fairly deep mixing / crossover between the clusters in some instances, so 100% accuracy is out of the question.&lt;/p&gt;
&lt;p&gt;Reference for the following discussion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cluster 1 — Red&lt;/li&gt;
&lt;li&gt;Cluster 2 — Orange/Green&lt;/li&gt;
&lt;li&gt;Cluster 3 — Grey/Blue&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;k-means-1&quot; tabindex=&quot;-1&quot;&gt;K-means &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#k-means-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;K-means does a reasonable job of splitting out the clusters, but due to the fact that the distributions must ultimately be limited to a circular shape, there was never any hope of accurately capturing clusters 2 or 3 precisely.&lt;/p&gt;
&lt;p&gt;However, as cluster 3 is quite well separated from the other two, the elongated shape is less of a hindrance. A circular representation of the lower cluster is actually sufficient, and gives a comparable representation to the Gaussian methods.&lt;/p&gt;
&lt;p&gt;When considering clusters 1 and 2 the K-Means method fails to sufficiently represent the data. It has an inherent inability to properly represent the elliptical shape of cluster 2. This causes cluster 2 to be ‘squashed’ down in between clusters 1 and 3 as the real extension upwards cannot be sufficiently described by the K-Mean algorithm.&lt;/p&gt;
&lt;h3 id=&quot;gaussian-mixture-model-1&quot; tabindex=&quot;-1&quot;&gt;Gaussian Mixture Model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#gaussian-mixture-model-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The basic Gaussian Mixture Model is only a slight improvement in this case.&lt;/p&gt;
&lt;p&gt;As discussed in the previous section for K-Means, even though the distribution of cluster 3 is better suited to an elliptical rather than circular distribution, it is of no advantage in this particular scenario.&lt;/p&gt;
&lt;p&gt;However, when looking at the representation of cluster 1 and 2, which are significantly more intertwined, the ability of the Gaussian Mixture Model to represent the underlying elliptical distribution (i.e. better capturing the underlying tails of the Gaussian distribution) of cluster 2 more accurately, results in a slight increase in accuracy.&lt;/p&gt;
&lt;h3 id=&quot;bayesian-gaussian-mixture-model-1&quot; tabindex=&quot;-1&quot;&gt;Bayesian Gaussian Mixture Model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#bayesian-gaussian-mixture-model-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For a start, the more than 10% improvement in accuracy of the Bayesian Gaussian Mixture Model compared to the other methods is certainly impressive as a lone statistic.&lt;/p&gt;
&lt;p&gt;On review of the confidence ellipsoids it becomes clear why this is the case. Cluster 2 has been represented both in terms of shape, tilt and size just about as perfectly as it could be. This has allowed for a very accurate representation of the real clusters.&lt;/p&gt;
&lt;p&gt;Although the exact reasons for this will always be slightly opaque, it is most definitely down to the differences between the expectation-maximisation algorithm used by the standard Gaussian Mixture Model, and the variational inference used by the Bayesian Gaussian Mixture Model.&lt;/p&gt;
&lt;p&gt;As discussed earlier in the article, the main differences are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the in built regularisation&lt;/li&gt;
&lt;li&gt;less tendency for variational inference to generate ‘marginally correct’ solutions to the problem&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is quite clear that the use of Gaussian Mixture Models can help to elevate the accuracy of the clustering of data that is likely to have Gaussian distributions as it’s underpinning.&lt;/p&gt;
&lt;p&gt;This is particularly relevant and useful for natural processes, including human processes, which make this analytical approach relevant to a large number of industries, across a wide variety of fields.&lt;/p&gt;
&lt;p&gt;Furthermore, the introduction of variational inference in the Bayesian Gaussian Mixture Model can, with very little difference in overhead, return further improved accuracy in clustering. There is even the, not so insignificant bonus, of the algorithm having the ability to suggest the appropriate amount of clusters for the underlying data.&lt;/p&gt;
&lt;p&gt;I hope this article has provided you with a decent insight into what Gaussian Mixing Models and Bayesian Gaussian Mixture Models are, and whether they may help with data you are working with.&lt;/p&gt;
&lt;p&gt;They really are a powerful tool if used appropriately.&lt;/p&gt;
&lt;h1 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/clustering-bayesian-gaussian/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;[1] Riccardo Leardi, &lt;a href=&quot;https://archive-beta.ics.uci.edu/dataset/109/wine&quot;&gt;Wine&lt;/a&gt; (1991), UC Irvine Machine Learning Repository, License: &lt;a href=&quot;https://creativecommons.org/licenses/by/4.0/legalcode&quot;&gt;CC BY 4.0&lt;/a&gt;&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Pro GPU System vs Consumer GPU System for Deep Learning</title>
		<link href="https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/"/>
		<updated>Wed, 19 Apr 2023 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Having a GPU (or graphics card) in your system is almost essential when it comes to training neural networks, especially deep neural networks. The difference in training speed of a fairly modest GPU is a night and day difference when compared to a CPU.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;….but at what point might you consider jumping into the realms of professional, rather than consumer, level GPUs? Is there a huge difference in training and inference speed? Or is it other factors that make the jump compelling?&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The aim of this article is to give you an idea of the main differences between a GPU you might use as a normal consumer (or starting out in machine/deep learning), and those used in higher end systems. The type of systems that might be used in the development and/or inference of advanced deep learning models.&lt;/p&gt;
&lt;p&gt;Apart from being an interesting exercise in understanding the distinctions between cutting edge pro equipment and consumer level hardware in terms of pure processing speed, it will also highlight some of the other limitations that are present in consumer level GPUs, and associated systems, when dealing with cutting edge deep learning models.&lt;/p&gt;
&lt;h1 id=&quot;which-gpus-are-you-referring-to-when-you-say-%E2%80%9Cpro%E2%80%9D-or-%E2%80%9Cconsumer%E2%80%9D%3F&quot; tabindex=&quot;-1&quot;&gt;Which GPUs are you referring to when you say “Pro” or “Consumer”? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#which-gpus-are-you-referring-to-when-you-say-%E2%80%9Cpro%E2%80%9D-or-%E2%80%9Cconsumer%E2%80%9D%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The “real world” differences will be covered in the rest of the article, but if you want a solid technical distinction, with example graphics cards and specifications, then this section should cover it.&lt;/p&gt;
&lt;p&gt;As detailed in one of my &lt;a href=&quot;https://towardsdatascience.com/how-to-pick-the-best-graphics-card-for-machine-learning-32ce9679e23b&quot;&gt;previous articles&lt;/a&gt;, NVIDIA are the only sensible option when it comes to GPUs for deep learning and neural networks at the current time. This is mainly due to their more thorough integration into platforms such as TensorFlow and PyTorch.&lt;/p&gt;
&lt;p&gt;Making the distinction between professional and consumer, in terms of specifications from the manufacturer, is therefore relatively straight forward.&lt;/p&gt;
&lt;p&gt;Anything from the following page is the current batch of NVIDIA’s consumer graphics cards:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://www.nvidia.com/en-gb/geforce/graphics-cards/&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/nvidia-logo.jpg&quot; alt=&quot;NVIDIA graphics cards&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;NVIDIA GeForce Graphics Cards&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;GeForce RTX 50 series, 40 series &amp;amp; more.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - NVIDIA&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;…and professional level GPUs:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://www.nvidia.com/en-us/design-visualization/desktop-graphics/&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/nvidia-logo.jpg&quot; alt=&quot;NVIDIA pro GPUs&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;NVIDIA RTX PRO in Desktops&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;The World’s Most Powerful Platform for AI, Graphics, and Simulation.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - NVIDIA&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;There are also GPUs, mainly used in data centres, that go beyond even the pro level graphics cards listed above. The A100 is a good example:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://www.nvidia.com/en-us/data-center/a100/&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/nvidia-logo.jpg&quot; alt=&quot;NVIDIA datacenter GPUs&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;NVIDIA A100 GPUs Power the Modern Data Center&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;The fastest data center platform for AI and HPC.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - NVIDIA&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;You can also get an idea of the system specifications and GPUs being used in professional data centre and workstation systems certified by NVIDIA:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://docs.nvidia.com/certification-programs/nvidia-certified-systems/index.html&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/nvidia-logo.jpg&quot; alt=&quot;NVIDIA certified systems&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;NVIDIA-Certified Systems — NVIDIA Certification Programs Documentation&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;This document lists the systems that have been tested with the latest NVIDIA GPUs and networking and are evaluated by NVIDIA engineers for performance, functionality, scalability, and security.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - nvidia.com&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h1 id=&quot;the-plan&quot; tabindex=&quot;-1&quot;&gt;The Plan &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-plan&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I generally find that a real demonstration (or experiment) is the best way to illustrate a point, rather than just relying on specs and statistics provided by the manufacturers.&lt;/p&gt;
&lt;p&gt;With that in mind, although the article will discuss the relevant statistics, it will also directly compare three different GPUs (pro and consumer), at differing levels of sophistication, on the same deep learning model.&lt;/p&gt;
&lt;p&gt;This should help to highlight what is important, and what isn’t, when considering whether a professional level GPU is for you.&lt;/p&gt;
&lt;h1 id=&quot;the-gpu-specs-%E2%80%94-a-summary&quot; tabindex=&quot;-1&quot;&gt;The GPU Specs — A Summary &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-gpu-specs-%E2%80%94-a-summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/summary.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/summary.jpg&quot; alt=&quot;Summary&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/sand-sign-texture-writing-11022641/&quot;&gt;Ann H&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the experiment, there will be three different graphics cards, but four levels of comparison:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NVIDIA RTX 1070 (Basic)&lt;/li&gt;
&lt;li&gt;NVIDIA Tesla T4 (Mid range)&lt;/li&gt;
&lt;li&gt;NVIDIA RTX 6000 Ada (High end)&lt;/li&gt;
&lt;li&gt;2 x NVIDIA RTX 6000 Ada (Double high end!)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So how do these different graphics cards compare in terms of raw specs?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;GPU&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Memory&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;CUDA Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Tensor Cores&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;FP32 [TFLOPS]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Generation&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Power&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 6000 Ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;48GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;18176&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;568&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;91.1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.9 (Ada Lovelace)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;300W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;RTX 4090&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;24GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16384&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;512&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;82.6&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.9 (Ada Lovelace)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;450W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Tesla T4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2560&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;320&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8.14&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.5 (Turing)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;70W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;GTX 1070&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8GB&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1920&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.46&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.1 (Pascal)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;150W&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Comparison of different graphics cards&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;I have included the RTX 4090 in the table above as it is the pinnacle of current consumer level graphics cards, and probably the best direct comparison to the RTX 6000 Ada. I will reference the 4090 throughout the article as a comparison point, although it will not feature in the benchmarks.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If the table above is just a load of number with no meaning, then I recommend my previous article which goes over some of the jargon:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://towardsdatascience.com/how-to-pick-the-best-graphics-card-for-machine-learning-32ce9679e23b&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/graphics-card-selection/gpu-pair-closeup.jpg&quot; alt=&quot;NVIDIA GPUs close up&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;How to Pick the Best Graphics Card for Machine Learning | Towards Data Science&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Speed up your training, and iterate faster&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;Michael Clayton - Towards Data Science&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h1 id=&quot;the-professional-system&quot; tabindex=&quot;-1&quot;&gt;The Professional System &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-professional-system&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-all-angles.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-all-angles.jpg&quot; alt=&quot;Professional workstation from three angles&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A view from all angles of the professional workstation utilised in this article. Image via&lt;/em&gt; &lt;a href=&quot;https://www.exxactcorp.com/category/Deep-Learning-Solutions&quot;&gt;&lt;em&gt;Exxact Corporation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under license to Michael Clayton&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the problems with producing an article like this is that you need access to a professional level system, and therefore one of the main hurdles is…cost.&lt;/p&gt;
&lt;p&gt;Fortunately, there are companies out there that will give access to their equipment for trial runs, to allow you to see if it fits your needs. In this particular case Exxact have been kind enough to allow remote access to one of their builds for a limited period so I can get the comparisons I need.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…the workstation is worth in the region of USD 25,000&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To drive home my point about how much these systems can cost I estimate the workstation I have been given access to is worth in the region of USD 25,000. If you want to depress (or impress?) yourself further you can take a look at the configurator and see what can realistically be achieved.&lt;/p&gt;
&lt;p&gt;Incidentally, if you are seriously in the market for this level of hardware you can apply for a remote ‘‘test drive’’ too:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://www.exxactcorp.com/Services/Test-Drive&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/exxact-logo.png&quot; alt=&quot;NVIDIA certified systems&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;ExxactAccess+ Test Drive | Validate Workloads on 8x GPUs | Exxact Corp&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;ExxactAccess+ offers remote validation with up to 8x NVIDIA RTX PRO Blackwell GPUs. Validate your unique workload performance before you invest in your new Exxact system.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;null - exxactcorp.com&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;These are the complete specs of the “professional” system for those that are interested:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Component Type&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Component&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Motherboard&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Asus Pro WS WRX80E-SAGE SE WIFI-SI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;CPU&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;AMD Ryzen Threadripper PRO 5995WX 64-core 2.7GHz/4.5GHz Boost 280W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;GPU&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;2x NVIDIA RTX 6000 Ada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;RAM&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;8x 64GB DDR4 3200MHz ECC Reg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;SSD&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;1TB M.2 NVMe PCIe 4.0 / 4TB M.2 NVMe PCIe 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Power&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;2000W Modular ATX PS2 80Plus Platinum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Cooling&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;360mm AIO CPU Liquid Coole / 3x 120mm 1700RPM Fans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Case&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Fractal Meshify 2 XL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Specification of the professional system&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;Feel free to refer to any of the images in this article that included the two gold looking GPUs in a black computer case, as those are actual pictures of the system detailed above.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is interesting to note that having a high end system is not just about stuffing the best graphics card you can get your hands on into your current system. Other components need to scale up too. System RAM, motherboard, CPU, cooling, and of course power.&lt;/p&gt;
&lt;h1 id=&quot;the-contenders&quot; tabindex=&quot;-1&quot;&gt;The Contenders &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-contenders&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/1070_ftw.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/1070_ftw.jpg&quot; alt=&quot;Professional workstation from three angles&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The NVIDIA GeForce GTX 1070 FTW that will be used as the base in this article&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;nvidia-geforce-gtx-1070&quot; tabindex=&quot;-1&quot;&gt;NVIDIA GeForce GTX 1070 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#nvidia-geforce-gtx-1070&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the bottom of the pack is the GTX 1070, which is readily available to most people, but is still &lt;em&gt;&lt;strong&gt;significantly&lt;/strong&gt;&lt;/em&gt; faster than a CPU. It also has a decent amount of GPU RAM at 8GB. A good simple consumer level base.&lt;/p&gt;
&lt;h2 id=&quot;nvidia-tesla-t4&quot; tabindex=&quot;-1&quot;&gt;NVIDIA Tesla T4 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#nvidia-tesla-t4&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Tesla T4 is maybe a strange addition, but there are a few reasons for this.&lt;/p&gt;
&lt;p&gt;The first thing to note is that the Tesla T4 is actually a professional graphics card, it is just a few generations old.&lt;/p&gt;
&lt;p&gt;In terms of processing speed it is roughly the equivalent of an RTX 2070, but it has double the GPU RAM at 16GB. This additional RAM puts it firmly in the mid range of this test. Current generation consumer cards tend to have RAM in this range (RTX 4070 [12GB] and RTX 4080 [16GB]), so it represents consumer graphics cards in terms of GPU RAM quite nicely.&lt;/p&gt;
&lt;p&gt;The final reason is that you can easily access one of these graphics cards for free in &lt;a href=&quot;https://colab.research.google.com/&quot;&gt;Colab&lt;/a&gt;. That means anybody reading this article can get their hands dirty and run the code to see for themselves!&lt;/p&gt;
&lt;h1 id=&quot;the-pro-gpu-%E2%80%94-nvidia-rtx-6000-ada&quot; tabindex=&quot;-1&quot;&gt;The Pro GPU — NVIDIA RTX 6000 Ada &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-pro-gpu-%E2%80%94-nvidia-rtx-6000-ada&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-side.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-side.jpg&quot; alt=&quot;Side view of the professional workstation&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A view of the two NVIDIA RTX 6000 Ada graphics cards installed in the professional workstation utilised in this article. Image via&lt;/em&gt; &lt;a href=&quot;https://www.exxactcorp.com/category/Deep-Learning-Solutions?page=1&amp;amp;utm_source=web+referral&amp;amp;utm_medium=backlink&amp;amp;utm_campaign=Michael+Clayton&amp;amp;utm_term=Medium+Towards+Data+Science&quot;&gt;&lt;em&gt;Exxact Corporation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under license to Michael Clayton&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There is no doubt about it, the RTX 6000 Ada is an impressive graphics card both in terms of specs…and price. With an &lt;strong&gt;MSRP of USD 6,800&lt;/strong&gt; it is definitely not a cheap graphics card. So why would you buy one (or more!?) if you can get an RTX 4090 for a mere USD 1599 (MSRP)?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The RTX 4090 has half the RAM and uses 50% more power than the RTX 6000 Ada&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I slipped an RTX 4090 into the table to attempt to answer this question. It helps to demonstrate what tend to be the two most obvious differences between a consumer graphics card and a professional graphics card (at least from the specifications alone):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the amount of GPU RAM available&lt;/li&gt;
&lt;li&gt;the maximum power draw in use&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The RTX 4090 has &lt;strong&gt;half the RAM&lt;/strong&gt; and &lt;strong&gt;uses 50% more power&lt;/strong&gt; than the RTX 6000 Ada. This is no accident, as will become evident as the article progresses.&lt;/p&gt;
&lt;p&gt;Furthermore, considering the higher power draw of the RTX 4090, it is also worth noting that the RTX 6000 Ada is still roughly &lt;strong&gt;10% faster.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Does this additional RAM and reduced power consumption really make a difference? Hopefully, the comparison will help to answer that later in the article.&lt;/p&gt;
&lt;h2 id=&quot;any-other-less-obvious-advantages%3F&quot; tabindex=&quot;-1&quot;&gt;Any other less obvious advantages? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#any-other-less-obvious-advantages%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well, yes. There are a few additional benefits to getting a professional level graphics card.&lt;/p&gt;
&lt;h3 id=&quot;reliability&quot; tabindex=&quot;-1&quot;&gt;Reliability &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#reliability&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/car.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/car.jpg&quot; alt=&quot;An old broken down car&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;https://pixabay.com/users/wikiimages-1897/?utm_source=link-attribution&amp;amp;amp%3Butm_medium=referral&amp;amp;amp%3Butm_campaign=image&amp;amp;amp%3Butm_content=62827&quot;&gt;WikiImages&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;amp%3Butm_medium=referral&amp;amp;amp%3Butm_campaign=image&amp;amp;amp%3Butm_content=62827&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NVIDIA RTX professional graphics cards are certified with a broad range of professional applications, tested by leading independent software vendors (ISVs) and workstation manufacturers, and backed by a global team of support specialists.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/rtx-6000/proviz-print-rtx6000-datasheet-web-2504660.pdf&quot;&gt;nvidia.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In essence this means the graphics cards are likely to be more reliable and crash resistant, both on a software (drivers), and hardware level, and if you do have a problem, there is an extensive professional network available to solve the problem. These factors are obviously very important for enterprise applications where time is money.&lt;/p&gt;
&lt;p&gt;Imagine running a complicated deep learning model for a few days and then losing the results due to a crash or bug. Then spending a significant amount more time potentially dealing with the problem. Not good!&lt;/p&gt;
&lt;p&gt;Is this peace of mind an additional reason to pay up? That really depends on your priorities, and scale...&lt;/p&gt;
&lt;h3 id=&quot;scale&quot; tabindex=&quot;-1&quot;&gt;Scale &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#scale&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/egg.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/egg.jpg&quot; alt=&quot;A big egg and a small egg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@yogidan2012?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Daniele Levis Pelusi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/4mpsEm3EGak?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you are designing a computer system to have optimal GPU processing power, then it may well be that you need more than one GPU. There will obviously be a limit on how many GPUs can fit in the system based primarily on the availability of motherboard slots, and physical space constraints in the case.&lt;/p&gt;
&lt;p&gt;However, there are other limiting factors directly related to the GPU itself, and this is where consumer GPUs and professional GPUs start to deviate in terms of design.&lt;/p&gt;
&lt;p&gt;Consider the fact that a professional motherboard may have availability for four dual slot GPUs (like the pro system in this article). So in theory you could fit 4 x RTX 6000 Ada GPUs into the system no problem at all. However, you would only be able to fit 2 x RTX 4090 on the same board. Why? Because the 4090 is a triple slot graphics card (~61mm thick), whereas the 6000 is a dual slot graphics card (~40mm thick).&lt;/p&gt;
&lt;p&gt;Consumer level GPUs are just not designed with the same constraints in mind (i.e. high density builds), and therefore start to be less useful as you scale up.&lt;/p&gt;
&lt;h3 id=&quot;cooling&quot; tabindex=&quot;-1&quot;&gt;Cooling &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#cooling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Following on from the potential sizing problem…even if the consumer graphics card was the same dual slot design, there are further issues.&lt;/p&gt;
&lt;p&gt;Pro level GPUs tend to be built with cooling systems (blower type) that are designed to draw air through the graphics cards from front to back with a sealed shroud to direct the air &lt;strong&gt;straight out of the case&lt;/strong&gt; (i.e. no hot air recirculating through the case). This allows for pro GPUs to be stacked tightly into the case, and still be able to efficiently cool themselves. All with minimal impact on other components, or GPUs, in the rest of the case.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/blower-vs-fan.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/blower-vs-fan.jpg&quot; alt=&quot;Fan vs blower cooling&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Two graphics cards one utilising a ‘blower’ cooling system and the other a more common fan cooling system. Photo by &lt;a href=&quot;https://www.pexels.com/photo/black-and-silver-car-wheel-4581613/&quot;&gt;Nana Dua&lt;/a&gt; on &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;. Annotations by author.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Consumer GPUs, on the whole, tend to use fan cooling from above/below. This inevitably means hot air from the GPU will recirculate in the case to some degree, necessitating excellent case ventilation.&lt;/p&gt;
&lt;p&gt;However, in cases with multiple GPUs, the close proximity of the other graphics cards would make fan cooling very ineffective, and will inevitably lead to sub-optimal temperatures for both the GPUs, and other components in close proximity.&lt;/p&gt;
&lt;p&gt;All-in-all professional graphics cards are designed to be tightly and efficiently packed into systems, whilst also staying cool and self contained.&lt;/p&gt;
&lt;h3 id=&quot;accuracy&quot; tabindex=&quot;-1&quot;&gt;Accuracy &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#accuracy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/target.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/target.jpg&quot; alt=&quot;Arrow and a blurred target&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jrarce?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Ricardo Arce&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/cY_TCKr5bek?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This really isn’t particularly relevant to deep learning specifically, but pro GPUs tend to have ECC (Error-Correcting Code) RAM. This would be useful where high precision (i.e. a low level of potential random errors from bit flips) is a must for whatever processes you are running through the graphics card.&lt;/p&gt;
&lt;p&gt;However, deep learning models are sometimes tuned to be &lt;strong&gt;less&lt;/strong&gt; numerically precise (half-precision 8-bit calculations), so this is not something that is likely to be of real concern for the calculations being run.&lt;/p&gt;
&lt;p&gt;Although if those random bit flips happen to crash your model, then it may just be worth consideration too.&lt;/p&gt;
&lt;h1 id=&quot;the-deep-learning-model&quot; tabindex=&quot;-1&quot;&gt;The Deep Learning Model &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-deep-learning-model&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/book-stack.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/book-stack.jpg&quot; alt=&quot;A stack of books with a person hidden behind them&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/adult-blur-books-close-up-261909/&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the deep learning model I wanted something that is advanced, industry leading, and demanding for the GPUs. It also has to be scalable in terms of difficulty as the GPUs on test have a wide range of capabilities.&lt;/p&gt;
&lt;h2 id=&quot;a-pro-level-model%2C-for-a-pro-level-graphics-card&quot; tabindex=&quot;-1&quot;&gt;A pro level model, for a pro level graphics card &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#a-pro-level-model%2C-for-a-pro-level-graphics-card&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the model to be industry standard rules out building a model from scratch, so for this comparison an existing, tried and tested, model will be used by utilising transfer learning.&lt;/p&gt;
&lt;h2 id=&quot;heavy-data&quot; tabindex=&quot;-1&quot;&gt;Heavy data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#heavy-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To ensure the input data is heavy, the analysis will be image based, specifically image classification.&lt;/p&gt;
&lt;h2 id=&quot;scalability&quot; tabindex=&quot;-1&quot;&gt;Scalability &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#scalability&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The final criteria is scalability, and there is a particular set of models out there that fits this criteria perfectly…&lt;/p&gt;
&lt;h1 id=&quot;efficientnet&quot; tabindex=&quot;-1&quot;&gt;EfficientNet &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#efficientnet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://keras.io/api/applications/efficientnet/&quot;&gt;EfficientNet&lt;/a&gt; consists of a family of image classification models (B0 to B7). Each model gets progressively more complicated (and accurate). It also has a different expected input shape for the images that you feed in as you progress through the family of models, which increases data input size.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;EfficientNet&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Parameters&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;FLOPs&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;ImageNet Accuracy&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Input Shape&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B0&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;5.3M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.39B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;77.1%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;224x224x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;7.8M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;0.70B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;79.1%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;240x240x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;9.2M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.0B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;80.1%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;260x260x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B3&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;12M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1.8B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;81.6%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;300x300x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;19M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;4.2B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;82.9%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;380x380x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B5&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;30M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;9.9B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;83.6%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;456x456x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B6&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;43M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;19B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;84.0%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;528x528x3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center&quot;&gt;B7&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;66M&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;137B&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;84.3%&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;600x600x3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Comparison of the different EfficientNet models — Data from &lt;a href=&quot;https://arxiv.org/pdf/1905.11946.pdf&quot;&gt;EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks&lt;/a&gt; — Table by author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This has a two fold effect:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;as you progress through the different EfficientNet models, the model parameters will increase (i.e. a more complicated and demanding model for the GPUs to process)&lt;/li&gt;
&lt;li&gt;the volume of raw data that needs to be processed will also increase (ranging from 224x224 pixels up to 600x600 pixels)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ultimately, this gives a large range of possibilities in terms of loading the GPUs both in terms of processing speed and GPU RAM requirements.&lt;/p&gt;
&lt;h1 id=&quot;the-data&quot; tabindex=&quot;-1&quot;&gt;The Data &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.kaggle.com/datasets/drgfreeman/rockpaperscissors&quot;&gt;data&lt;/a&gt;¹ utilised in this article is a set of images which depict the three possible combinations of hand position used in the game rock-paper-scissors.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/example-hands.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/julia-flux-python-tensorflow-comparison/example-hands.jpg&quot; alt=&quot;Samples from the image data&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Four examples from the three different categories of the &lt;a href=&quot;https://www.kaggle.com/datasets/drgfreeman/rockpaperscissors&quot;&gt;dataset&lt;/a&gt;. Composite image by Author.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Each image is of type PNG, and of dimensions 300(W) pixels x 200(H) pixels, in full colour.&lt;/p&gt;
&lt;p&gt;The original dataset contains 2188 images in total, but for this article a smaller selection has been used, which comprises of precisely 2136 images (712 images for each category). This slight reduction in total images from the original has been done simply to balance the classes.&lt;/p&gt;
&lt;p&gt;The balanced dataset that was used in this article is available here:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/datasets/rock_paper_scissors&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/placeholder.png&quot; alt=&quot;Github&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/datasets/rock_paper_scissors at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;h1 id=&quot;the-test&quot; tabindex=&quot;-1&quot;&gt;The Test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/notepad.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/notepad.jpg&quot; alt=&quot;A blank piece of paper with pencil&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kellysikkema?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Kelly Sikkema&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/4JxV3Gs42Ks?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As mentioned previously, there are various levels of EfficientNet available, so for the purposes of testing, the following will be run on each GPU:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;EfficientNet B0&lt;/strong&gt; (simple)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EfficientNet B3&lt;/strong&gt; (intermediate)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EfficientNet B7&lt;/strong&gt; (intensive)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will test the graphics cards speed capabilities due to the difference in overall parameters of each model, but also a wide range of RAM requirements as the input image sizes will vary too.&lt;/p&gt;
&lt;p&gt;The EfficientNet models will have all of their layers unlocked and allowed to learn.&lt;/p&gt;
&lt;p&gt;The three final models:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;EfficientNetB0
_________________________________________________________________
 Layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                Output Shape              Param &lt;span class=&quot;token comment&quot;&gt;#   &lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
 input_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InputLayer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
                                                                 
 data_augmentation &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Sequenti  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 al&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                             
                                                                 
 efficientnetb0 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Functional&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, None, None, &lt;span class=&quot;token number&quot;&gt;1280&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;4049571&lt;/span&gt;  
                                                                 
 global_avg_pool_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Glob  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;1280&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 alAveragePooling2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                             
                                                                 
 output_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token number&quot;&gt;3843&lt;/span&gt;      
                                                                 
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
Total params: &lt;span class=&quot;token number&quot;&gt;4,053&lt;/span&gt;,414
Trainable params: &lt;span class=&quot;token number&quot;&gt;4,011&lt;/span&gt;,391
Non-trainable params: &lt;span class=&quot;token number&quot;&gt;42,023&lt;/span&gt;
_________________________________________________________________


EfficientNetB3
_________________________________________________________________
 Layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                Output Shape              Param &lt;span class=&quot;token comment&quot;&gt;#   &lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
 input_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InputLayer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
                                                                 
 data_augmentation &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Sequenti  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 al&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                             
                                                                 
 efficientnetb3 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Functional&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, None, None, &lt;span class=&quot;token number&quot;&gt;1536&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;10783535&lt;/span&gt; 
                                                                 
 global_avg_pool_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Glob  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;1536&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 alAveragePooling2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                             
                                                                 
 output_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token number&quot;&gt;4611&lt;/span&gt;      
                                                                 
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
Total params: &lt;span class=&quot;token number&quot;&gt;10,788&lt;/span&gt;,146
Trainable params: &lt;span class=&quot;token number&quot;&gt;10,700&lt;/span&gt;,843
Non-trainable params: &lt;span class=&quot;token number&quot;&gt;87,303&lt;/span&gt;
_________________________________________________________________


EfficientNetB7
_________________________________________________________________
 Layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                Output Shape              Param &lt;span class=&quot;token comment&quot;&gt;#   &lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
 input_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InputLayer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
                                                                 
 data_augmentation &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Sequenti  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 al&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                             
                                                                 
 efficientnetb7 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Functional&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, None, None, &lt;span class=&quot;token number&quot;&gt;2560&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;64097687&lt;/span&gt; 
                                                                 
 global_avg_pool_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Glob  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;2560&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;         
 alAveragePooling2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                             
                                                                 
 output_layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;None, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token number&quot;&gt;7683&lt;/span&gt;      
                                                                 
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
Total params: &lt;span class=&quot;token number&quot;&gt;64,105&lt;/span&gt;,370
Trainable params: &lt;span class=&quot;token number&quot;&gt;63,794&lt;/span&gt;,643
Non-trainable params: &lt;span class=&quot;token number&quot;&gt;310,727&lt;/span&gt;
_________________________________________________________________&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;speed-test&quot; tabindex=&quot;-1&quot;&gt;Speed Test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#speed-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The speed of the GPUs will be judged by how quickly they can complete an epoch.&lt;/p&gt;
&lt;p&gt;To be more specific, there will be a minimum of two epochs run on each graphics card, and the second epoch will be used to judge the processing speed. The first epoch generally has some additional loading time, so would not be a good reference for general execution time.&lt;/p&gt;
&lt;p&gt;The time to run the first epoch will be listed only for reference.&lt;/p&gt;
&lt;h2 id=&quot;gpu-ram-test&quot; tabindex=&quot;-1&quot;&gt;GPU RAM Test &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#gpu-ram-test&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To test the limits of the GPU RAM, the batch size for each graphics card, and each EfficientNet model (i.e. B0, B3 or B7), has been tuned to be as close as possible to the limit for that particular graphics card (i.e. to fill the GPU RAM as much as possible).&lt;/p&gt;
&lt;p&gt;The actual peak GPU RAM utilisation for the run will also be disclosed for comparison.&lt;/p&gt;
&lt;h1 id=&quot;the-code&quot; tabindex=&quot;-1&quot;&gt;The Code &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-code&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/laptop.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/laptop.jpg&quot; alt=&quot;Laptop screen wth code&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@oskaryil?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Oskar Yildiz&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/cOkpTiJMGzA?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As ever, I have made all the python scripts (GTX 1070 and RTX 6000 Ada) and notebooks (Tesla T4) available on GitHub:&lt;/p&gt;
&lt;a class=&quot;card-a&quot; href=&quot;https://github.com/thetestspecimen/notebooks/tree/main/pro-vs-consumer-graphics-card&quot; rel=&quot;noopener follow&quot; target=&quot;_blank&quot;&gt;
&lt;card-link&gt;
&lt;img src=&quot;https://www.thetestspecimen.com/img/placeholder.jpg&quot; alt=&quot;Github&quot; /&gt;
&lt;p&gt;&lt;span class=&quot;title&quot;&gt;notebooks/pro-vs-consumer-graphics-card at main · thetestspecimen/notebooks&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;desc&quot;&gt;Jupyter notebooks. Contribute to thetestspecimen/notebooks development by creating an account on GitHub.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;author&quot;&gt;thetestspecimen - GitHub&lt;/span&gt;&lt;/p&gt;
&lt;/card-link&gt;
&lt;/a&gt;
&lt;p&gt;You can also access the notebooks for the Tesla T4 directly on Colab if you so wish:&lt;/p&gt;
&lt;p&gt;EfficientNetB0:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/pro-vs-consumer-graphics-card/rps_t4_tf_B0.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;EfficientNetB3:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/pro-vs-consumer-graphics-card/rps_t4_tf_B3.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;EfficientNetB7:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/github/thetestspecimen/notebooks/blob/main/pro-vs-consumer-graphics-card/rps_t4_tf_B7.ipynb&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/colab-badge.png&quot; alt=&quot;Launch python notebook in colab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-results&quot; tabindex=&quot;-1&quot;&gt;The Results &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-results&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/dotmatrix.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/dotmatrix.jpg&quot; alt=&quot;Printing graph paper&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/business-commerce-computer-delivery-263194/&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;efficientnet-b0&quot; tabindex=&quot;-1&quot;&gt;EfficientNet B0 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#efficientnet-b0&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;1st Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;2nd Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Batch Size&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Peak RAM [GB]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GTX 1070&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;47 (+30s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;17&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;60&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;6.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesla T4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;67 (+40s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;17&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;128&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;13.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;26 (+20s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;512&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;47.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 x RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;39 (+38s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1024&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;47.7 (each)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;efficientnet-b3&quot; tabindex=&quot;-1&quot;&gt;EfficientNet B3 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#efficientnet-b3&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;1st Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;2nd Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Batch Size&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Peak RAM [GB]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GTX 1070&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;108 (+46s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;62&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;16&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;5.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesla T4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;129 (+74s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;55&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;40&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;13.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;46 (+33s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;13&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;128&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;40.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 x RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;65 (+57s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;8&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;256&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;41.2 (each)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;efficientnet-b7&quot; tabindex=&quot;-1&quot;&gt;EfficientNet B7 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#efficientnet-b7&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;1st Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;2nd Epoch [s]&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Batch Size&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;Peak RAM [GB]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GTX 1070&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;953 (+95s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;858&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;5.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesla T4&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;839 (+161s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;678&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;9.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;213 (+69s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;144&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;44.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 x RTX 6000 ada&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;203 (+125s)&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;78&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;20&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;41.8 (each)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;for the first epoch I have listed a number of seconds in brackets. This is the time difference between the first and second epoch.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;discussion-%E2%80%94-execution-speed&quot; tabindex=&quot;-1&quot;&gt;Discussion — Execution Speed &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#discussion-%E2%80%94-execution-speed&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/speedo.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/speedo.jpg&quot; alt=&quot;Car speedometer&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;https://pixabay.com/users/qimono-1962238/?utm_source=link-attribution&amp;amp;amp%3Butm_medium=referral&amp;amp;amp%3Butm_campaign=image&amp;amp;amp%3Butm_content=1249610&quot;&gt;Arek Socha&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;amp%3Butm_medium=referral&amp;amp;amp%3Butm_campaign=image&amp;amp;amp%3Butm_content=1249610&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first item to look at is execution speed.&lt;/p&gt;
&lt;p&gt;EfficientNet B0 doesn’t cause much of a challenge for any of the graphics cards with this particular dataset, with all completing an epoch in a matter of seconds.&lt;/p&gt;
&lt;p&gt;However, it is important to remember that the dataset utilised in this article is small, and in reality the two RTX 6000 Ada graphics cards are approximately &lt;strong&gt;17 times faster&lt;/strong&gt; that the GTX 1070 (and Tesla T4) in terms of execution speed. The story is pretty much the same for EfficientNet B3 (8x faster) and B7 (11x faster).&lt;/p&gt;
&lt;p&gt;The difference is that this slow down in speed, when viewed as execution time, starts to become more of a hindrance the more complicated the model gets.&lt;/p&gt;
&lt;p&gt;For example, to execute a single epoch, on this very small dataset, using EfficientNet B7 with a GTX 1070 takes approximately 15 mins. Compare that to just over 1 minute with a pair of RTX 6000 Ada.&lt;/p&gt;
&lt;p&gt;…and it gets worse.&lt;/p&gt;
&lt;h2 id=&quot;scaling-up&quot; tabindex=&quot;-1&quot;&gt;Scaling up &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#scaling-up&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s be realistic. No model is going to converge in one epoch. Four hundred might be a more reasonable number for a model like EfficientNet.&lt;/p&gt;
&lt;p&gt;That would be the difference between &lt;strong&gt;4 days&lt;/strong&gt; on a GPU like the GTX 1070, and only a few hours (6.5 to be precise) on a dual RTX 6000 Ada setup. Then consider that a real dataset doesn’t have only 2188 images, it could have millions (for reference &lt;a href=&quot;https://www.image-net.org/&quot;&gt;ImageNet&lt;/a&gt; has just over &lt;strong&gt;14 million images&lt;/strong&gt;).&lt;/p&gt;
&lt;h2 id=&quot;industry-progress&quot; tabindex=&quot;-1&quot;&gt;Industry progress &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#industry-progress&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another thing to bear in mind is progress in industry. EfficientNet is a few years old now, and things have moved on.&lt;/p&gt;
&lt;p&gt;As a small example take &lt;a href=&quot;https://arxiv.org/pdf/1911.04252v4.pdf&quot;&gt;NoisyStudent&lt;/a&gt;, which builds on the standard EfficientNets with a variation called EfficientNet-L2 and states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Due to the large model size, the training time of EfficientNet-L2 is approximately five times the training time of EfficientNet-B7&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://arxiv.org/pdf/1911.04252v4.pdf&quot;&gt;Self-training with Noisy Student improves ImageNet classification&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;…so speed really does matter if you need to stay at the cutting edge.&lt;/p&gt;
&lt;h2 id=&quot;what-does-that-mean-for-pro-vs-consumer-graphics-cards-then%3F&quot; tabindex=&quot;-1&quot;&gt;What does that mean for pro vs consumer graphics cards then? &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#what-does-that-mean-for-pro-vs-consumer-graphics-cards-then%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The truth is that if you &lt;strong&gt;only&lt;/strong&gt; look at speed of execution there is very little difference between professional and consumer GPUs if you compare like for like. An RTX 4090 is near as makes no difference the same speed as an RTX 6000 Ada.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An RTX 4090 is near as makes no difference the same speed as an RTX 6000 Ada.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All this little experiment has illustrated so far is that speed is very important, as industry standard models are progressing in complexity quite quickly. Older generation graphics cards are noticeably slower already. To keep up requires &lt;strong&gt;at least&lt;/strong&gt; staying on the cutting edge of hardware.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…scale matters a great deal when answering this question.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;…but with the speed of progression (just look at the rapid accent of GTP-3 and GTP-4) it also appears that if you want to stay at the cutting edge, one GPU, even at the level of the RTX 4090 or RTX 6000 Ada, is unlikely to be enough. If that is the case, then the superior cooling, less power draw and more compact size of the professional level graphics cards are a significant advantage when building a system.&lt;/p&gt;
&lt;p&gt;Essentially, scale matters a great deal when answering this question.&lt;/p&gt;
&lt;p&gt;However, speed is only one facet. Now let’s move on to the GPU RAM, where things get a little more interesting…&lt;/p&gt;
&lt;h1 id=&quot;discussion-%E2%80%94-gpu-ram&quot; tabindex=&quot;-1&quot;&gt;Discussion — GPU RAM &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#discussion-%E2%80%94-gpu-ram&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;GPU RAM is a significant consideration in some situations, and can be a literal limiting factor as to whether certain models, or datasets, can be utilised at all.&lt;/p&gt;
&lt;p&gt;Let’s see the pair of RTX 6000 Ada in full flow:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/6000-ada-x2-running.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/6000-ada-x2-running.jpg&quot; alt=&quot;Two GPUs running statistics&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The two RTX 6000 Ada GPUs running a deep learning model. Image by Author&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You may notice in the image above that the GPU RAM is at 100% for both GPUs. However, the this is not the real usage:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, TensorFlow maps nearly all of the GPU memory of all GPUs (subject to &lt;code&gt;*CUDA_VISIBLE_DEVICES*&lt;/code&gt;) visible to the process. This is done to more efficiently use the relatively precious GPU memory resources on the devices by reducing memory fragmentation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tensorflow.org/guide/gpu&quot;&gt;-tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-limits&quot; tabindex=&quot;-1&quot;&gt;The limits &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-limits&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The absolute limit is brought home quite starkly by the fact that the GTX 1070 (which has 8GB of GPU RAM) is only capable of running EfficientNet B7 with a batch size of 1 (i.e. it can process 1 image at a time before having to update the model parameters and load the next image into the GPU RAM).&lt;/p&gt;
&lt;p&gt;This causes two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You lose speed of execution due to frequent parameter updates in addition to loading in fresh data to the GPU RAM more regularly (i.e. larger batch sizes are inherently quicker.)&lt;/li&gt;
&lt;li&gt;If the input image size gets any larger, the model will not be able to run at all, as it won’t fit one single image into the GPU RAM&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Even the Tesla T4 which has a not too shabby 16GB of GPU memory only manages a batch size of 2 on EfficientNet B7.&lt;/p&gt;
&lt;p&gt;As detailed earlier, 16GB of GPU RAM is a good representation of the majority of current generation consumer GPUs, with only the RTX 4090 having more at 24GB. So this is a fairly significant downfall for consumer GPUs if you are dealing with memory heavy raw data.&lt;/p&gt;
&lt;p&gt;At this point it suddenly becomes clear why all the professional GPUs are so RAM heavy when compared to their consumer equivalents. As mentioned in the discussion for the speed of execution, EfficientNet is no longer at the bleeding edge, so the reality today is probably even more demanding than outlined in the tests for this article.&lt;/p&gt;
&lt;h2 id=&quot;system-density&quot; tabindex=&quot;-1&quot;&gt;System density &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#system-density&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another consideration in regard to GPU RAM is system density.&lt;/p&gt;
&lt;p&gt;For example, the system I have been given access to has a motherboard that can take 4 double height GPUs (I have also seen systems with up to 8 GPUs). This means that if GPU RAM is a priority in your system, then professional GPUs are a no brainer:&lt;/p&gt;
&lt;p&gt;4 x RTX 6000 Ada = 192GB GPU RAM and 1200W of power draw&lt;/p&gt;
&lt;p&gt;4 x RTX 4090 = 96GB GPU RAM and 1800W of power draw&lt;/p&gt;
&lt;p&gt;(…and as I have already mentioned earlier in the article the RTX 4090 is a triple slot GPU so this isn’t even realistic. In reality only two RTX 4090 graphics cards would actually fit, but for the sake of easy comparison let’s assume it would work.)&lt;/p&gt;
&lt;p&gt;That is no small difference. To match the RTX 6000 Ada system in terms of GPU RAM you would need two separate systems drawing at least &lt;strong&gt;three times the power&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To match the RTX 6000 Ada system in terms of RAM you would need two separate systems drawing at least three times the power.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Don’t forget that as you would need two separate systems, you would have to fork out for additional CPUs, power supplies, motherboards, cooling, cases etc.&lt;/p&gt;
&lt;h2 id=&quot;a-side-note-on-system-ram%E2%80%A6&quot; tabindex=&quot;-1&quot;&gt;A side note on system RAM… &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#a-side-note-on-system-ram%E2%80%A6&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-blue.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-blue.jpg&quot; alt=&quot;Side view of the professional workstation with blue internal lights&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Did you notice 8 sticks of 64GB system RAM above and below the CPU in the professional system? Image via&lt;/em&gt; &lt;a href=&quot;https://www.exxactcorp.com/category/Deep-Learning-Solutions?page=1&amp;amp;utm_source=web+referral&amp;amp;utm_medium=backlink&amp;amp;utm_campaign=Michael+Clayton&amp;amp;utm_term=Medium+Towards+Data+Science&quot;&gt;&lt;em&gt;Exxact Corporation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under license to Michael Clayton&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is also worth pointing out, that it is not just the GPU RAM that matters. As the GPU RAM scales up you need to increase the system RAM in parallel.&lt;/p&gt;
&lt;p&gt;You may note in the Jupyter notebooks for the Tesla T4 that I have commented out the following optimisations:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;train_data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; train_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prefetch&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AUTOTUNE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
val_data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prefetch&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;tf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AUTOTUNE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because, for EfficientNet B7, the training will crash if they are enabled.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;Because the “.cache()” optimisation keeps the data in system memory to feed it efficiently to the GPU, and the Colab instance only has 12GB of system memory. Which is not enough, even though the GPU RAM peaks at 9.9GB:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This [.cache()] will save some operations (like file opening and data reading) from being executed during each epoch.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://www.tensorflow.org/guide/data_performance&quot;&gt;tensorflow.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, the professional system has 8 sticks of 64GB system RAM, for a total of 512GB of system RAM. So even though the two RTX 6000 Ada GPUs combined have 96GB of GPU RAM, there is still plenty of overhead in the system RAM to deal with heavy caching.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-side-light-nolight.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/pro-vs-consumer-gpu/WS-side-light-nolight.jpg&quot; alt=&quot;Side view of the professional workstation with and without blue internal  lights&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image via&lt;/em&gt; &lt;a href=&quot;https://www.exxactcorp.com/category/Deep-Learning-Solutions?page=1&amp;amp;utm_source=web+referral&amp;amp;utm_medium=backlink&amp;amp;utm_campaign=Michael+Clayton&amp;amp;utm_term=Medium+Towards+Data+Science&quot;&gt;&lt;em&gt;Exxact Corporation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;under license to Michael Clayton&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, are professional level graphics cards better than consumer cards for deep learning?&lt;/p&gt;
&lt;p&gt;Money no object. Yes, they are.&lt;/p&gt;
&lt;p&gt;Does that mean that you should discard considering consumer level graphics cards for deep learning?&lt;/p&gt;
&lt;p&gt;No, it doesn’t.&lt;/p&gt;
&lt;p&gt;It all comes down to specific requirements, and more often than not scale.&lt;/p&gt;
&lt;h2 id=&quot;large-datasets&quot; tabindex=&quot;-1&quot;&gt;Large datasets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#large-datasets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you know that your workload is going to be RAM intensive (large language models, image, or video based analysis for example) then professional graphics cards of the same generation and processing speed tend to have roughly double the GPU RAM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It all comes down to specific requirements, and scale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a significant advantage, especially considering there is no elevation in energy requirements to achieve this compared to a consumer graphics card.&lt;/p&gt;
&lt;h2 id=&quot;smaller-datasets&quot; tabindex=&quot;-1&quot;&gt;Smaller datasets &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#smaller-datasets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you don’t have high RAM requirements, then the question is more nuanced and relies on whether reliability, compatibility, support, energy consumption, and that additional 10% in terms of speed are worth the quite significant hike in price.&lt;/p&gt;
&lt;h2 id=&quot;scale-1&quot; tabindex=&quot;-1&quot;&gt;Scale &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#scale-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are about to invest in significant infrastructure, then reliability, energy consumption and system density may move from low priority to quite significant considerations. Areas that professional GPUs excel at.&lt;/p&gt;
&lt;p&gt;Conversely, if you need a smaller system, and high GPU RAM requirements aren’t important, then considering consumer level graphics cards may turn out to be beneficial. Factors associated with large scale, such as reliability and energy consumption will become less of an issue, and system density won’t matter at all.&lt;/p&gt;
&lt;h2 id=&quot;the-final-word&quot; tabindex=&quot;-1&quot;&gt;The final word &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/consumer-vs-pro-gpu/#the-final-word&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all it is a balancing act, but if I had to pick two items to summarise the most important factors in choosing between a consumer GPU and professional GPU it would be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GPU RAM&lt;/li&gt;
&lt;li&gt;System scale&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have &lt;strong&gt;either&lt;/strong&gt; high GPU RAM requirements, or will need larger systems with multiple GPUs, then you need a professional level GPU/GPUs.&lt;/p&gt;
&lt;p&gt;Otherwise, most likely, consumer level will be a better deal.&lt;/p&gt;

		</content>
	</entry>
	
	<entry>
		<title>Encrypted Arch Linux Installation Guide</title>
		<link href="https://www.thetestspecimen.com/posts/arch-install/"/>
		<updated>Thu, 30 May 2024 01:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/arch-install/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Arch Linux is probably avoided by many due to the initial hurdle of actually getting it installed, which is understandable. This is unfortunate, because once it is installed it is probably the most sorted operating system I have ever used, and not unstable at all in my experience.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It has excellent documentation with the Arch Wiki, something I had come across time and again, even before using Arch. It also has a knowledgable and active community, reflected by the enormity of the AUR. And to round things of, you are always bang up to date with the latest kernel and packages.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hopefully, this guide will help you overcome that initial hurdle so you can see for yourself.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best of luck!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article was last updated on 7th January 2026&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide provides information on how to setup an Arch Linux installation from scratch with the following features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Encrypted root, swapfile and boot (only the EFI partition is unencrypted)&lt;/li&gt;
&lt;li&gt;Btrfs file system and subvolumes setup&lt;/li&gt;
&lt;li&gt;Encrytped swapfile (rather than swap partition), including the necessary settings for hibernation&lt;/li&gt;
&lt;li&gt;Gnome desktop installation&lt;/li&gt;
&lt;li&gt;NVIDIA proprietary driver setup&lt;/li&gt;
&lt;li&gt;Wayland/Gnome(gdm) configuration for NVIDIA&lt;/li&gt;
&lt;li&gt;Snapper snapshot installation and configuration, including btrfs-assistant GUI&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To put this guide together I have referenced various blog posts, and of course the &lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;Arch Wiki&lt;/a&gt;. Specific sources are detailed in the references section at the end.&lt;/p&gt;
&lt;p&gt;This guide should produce a complete and functional system, with GUI and snapshot capability.&lt;/p&gt;
&lt;p&gt;This article is also available as a &lt;a href=&quot;https://github.com/thetestspecimen/linux-notes/blob/master/arch-install.md&quot;&gt;GitHub repo&lt;/a&gt;. Therefore, if you have any suggestions for improvements to any of the methods used in this guide, please feel free to put in a bug report (or pull request) on GitHub.&lt;/p&gt;
&lt;p&gt;I am aware that preferred / recommended methods change regularly, so I have tried to stick closely to the Arch Wiki where possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note: &lt;em&gt;this guide at some point may become outdated, the &lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;arch wiki&lt;/a&gt; should always be considered the main and trusted source for any information.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;pre-requisites&quot; tabindex=&quot;-1&quot;&gt;Pre-requisites &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#pre-requisites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is assumed that you have already downloaded Arch Linux, burned it to a USB drive, and booted into the live environment.&lt;/p&gt;
&lt;p&gt;If you are now sitting looking at the Arch live environment commandline then you are ready to go, otherwise please get setup first.&lt;/p&gt;
&lt;p&gt;You may also need buckets of patience...best of luck!&lt;/p&gt;
&lt;h1 id=&quot;set-the-console-keyboard-layout-and-font&quot; tabindex=&quot;-1&quot;&gt;Set the console keyboard layout and font &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-the-console-keyboard-layout-and-font&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The default console keymap is &amp;quot;US&amp;quot;. Available layouts can be listed with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;localectl list-keymaps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To set the keyboard layout, pass the keyboard layout name to loadkeys. For example, to set a UK keyboard layout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;loadkeys uk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Console fonts are located in &lt;code&gt;/usr/share/kbd/consolefonts/&lt;/code&gt; and can be set with &lt;code&gt;setfont&lt;/code&gt;, omitting the path and file extension. For example, to use one of the largest fonts suitable for HiDPI screens, run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;setfont ter-132b&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;check-if-the-system-is-uefi&quot; tabindex=&quot;-1&quot;&gt;Check if the system is UEFI &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#check-if-the-system-is-uefi&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If the following command returns 64, then the system is booted in UEFI mode, and has a 64-bit x64 UEFI. If the command returns 32, then system is booted in UEFI mode and has a 32-bit IA32 UEFI. Either of which is fine to proceed with this guide, as we will be using GRUB.&lt;/p&gt;
&lt;p&gt;If the file doesn&#39;t exist then the system isn&#39;t UEFI, so you won&#39;t be able to proceed.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /sys/firmware/efi/fw_platform_size&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;connect-to-wifi&quot; tabindex=&quot;-1&quot;&gt;Connect to Wifi &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#connect-to-wifi&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If your device is plugged in via Ethernet cable then you should be good to go. Otherwise, connect to a Wi-Fi network using &lt;code&gt;iwctl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Enter the iwctl interface&lt;/span&gt;
iwctl
&lt;span class=&quot;token comment&quot;&gt;# Find the name of your wireless device:&lt;/span&gt;
device list
&lt;span class=&quot;token comment&quot;&gt;# Scan for networks:&lt;/span&gt;
station &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;device name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; scan
&lt;span class=&quot;token comment&quot;&gt;# List network SSID:&lt;/span&gt;
station &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;device name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; get-networks
&lt;span class=&quot;token comment&quot;&gt;# Connect to network:&lt;/span&gt;
station &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;device-name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; connect &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SSID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leave iwctl by pressing &lt;strong&gt;Ctrl+C&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Test the connection:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ping&lt;/span&gt; archlinux.org&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the ping responds, then stop the process using &lt;strong&gt;Ctrl+C&lt;/strong&gt;.&lt;/p&gt;
&lt;h1 id=&quot;update-the-system-clock&quot; tabindex=&quot;-1&quot;&gt;Update the system clock &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#update-the-system-clock&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Enable and start network time synchronisation:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# check current settings&lt;/span&gt;
timedatectl
&lt;span class=&quot;token comment&quot;&gt;# list timezones (change &quot;Europe/&quot; as appropriate)&lt;/span&gt;
timedatectl list-timezones &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Europe/&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# or if you want to list everything omit the &#39;grep&#39;&lt;/span&gt;
timedatectl list-timezones
&lt;span class=&quot;token comment&quot;&gt;# set timezone (change &quot;Europe/London&quot; to your timezone)&lt;/span&gt;
timedatectl set-timezone &lt;span class=&quot;token string&quot;&gt;&quot;Europe/London&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# turn on ntp&lt;/span&gt;
timedatectl set-ntp &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# check the settings have updated&lt;/span&gt;
timedatectl&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;prepare-the-drive&quot; tabindex=&quot;-1&quot;&gt;Prepare the drive &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#prepare-the-drive&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Disks are assigned to a block device such as &lt;code&gt;/dev/sda&lt;/code&gt;, &lt;code&gt;dev/nvme0n1&lt;/code&gt; or &lt;code&gt;/dev/mmcblk0&lt;/code&gt;. Let&#39;s list out the devices:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;wipe-the-disk&quot; tabindex=&quot;-1&quot;&gt;Wipe the disk &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#wipe-the-disk&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is a good idea to wipe the disk before proceeding any further.&lt;/p&gt;
&lt;p&gt;Create a container called &amp;quot;wipe_me&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;the &amp;quot;block-device&amp;quot; should be the main device not one of the device partitions. For example, it could be &lt;code&gt;/dev/sdf&lt;/code&gt; , but not &lt;code&gt;/dev/sdf1&lt;/code&gt; , or &lt;code&gt;/dev/nvme0n1&lt;/code&gt; but not &lt;code&gt;/dev/nvmen0n1p1&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: YOU ARE ABOUT TO WIPE THE DISK! BE SURE YOU DON&#39;T NEED THE DATA ON THE DISK AS IT IS NOT RECOVERABLE!&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cryptsetup &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--type&lt;/span&gt; plain &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; /dev/urandom /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; wipe_me&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Zero out the container. This may take a while depending on the size and type of drive:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;1M &lt;span class=&quot;token assign-left variable&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;token assign-left variable&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/mapper/wipe_me &lt;span class=&quot;token assign-left variable&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;progress&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then close the container:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cryptsetup close wipe_me&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;partition-the-disk&quot; tabindex=&quot;-1&quot;&gt;Partition the disk &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#partition-the-disk&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the drive erased, use fdisk to partition the disk.&lt;/p&gt;
&lt;p&gt;Using fdisk is an interactive process. Start the interactive process by telling fdisk the drive to setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;until you give the write command &#39;w&#39; (write table to disk and exit), nothing will be changed on the disk. So if you make a mistake, just type &#39;q&#39; (quit without saving changes), and start again.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# As per the pervious section the &quot;block-device&quot; should be the main device not one of the device partitions.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is now the interactive part of the process with fdisk.&lt;/p&gt;
&lt;p&gt;Enter &#39;m&#39; to see the available commands:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;m&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;  GPT
   M   enter protective/hybrid MBR

  Generic
   d   delete a partition
   F   list free unpartitioned space
   l   list known partition types
   n   add a new partition
   p   print the partition table
   t   change a partition type
   v   verify the partition table
   i   print information about a partition

  Misc
   m   print this menu
   x   extra functionality (experts only)

  Script
   I   load disk layout from sfdisk script file
   O   dump disk layout to sfdisk script file

  Save &amp; Exit
   w   write table to disk and exit
   q   quit without saving changes

  Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty MBR (DOS) partition table
   s   create a new empty Sun partition table&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;start-the-partitioning&quot; tabindex=&quot;-1&quot;&gt;Start the partitioning &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#start-the-partitioning&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Two partitions will be created:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The EFI partition - this will be ONLY the EFI, and will not contain boot.&lt;/li&gt;
&lt;li&gt;The root partition, which will contain everything else, including boot and swap (in our case a swapfile), and will be encrypted.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# CREATE A NEW PARTITION TABLE&lt;/span&gt;
g &lt;span class=&quot;token comment&quot;&gt;# create a new empty GPT partition table&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# CREATE THE EFI PARTITION&lt;/span&gt;
n &lt;span class=&quot;token comment&quot;&gt;# add a new partition&lt;/span&gt;
*enter* &lt;span class=&quot;token comment&quot;&gt;# Partition number (1-128, default 1)&lt;/span&gt;
*enter* &lt;span class=&quot;token comment&quot;&gt;# First sector (2048-250069646, default 2048)&lt;/span&gt;
+512M &lt;span class=&quot;token comment&quot;&gt;# Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-250069646, default 250068991)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Created a new partition 1 of type &#39;Linux filesystem&#39; and of size 512 MiB.&lt;/span&gt;

t &lt;span class=&quot;token comment&quot;&gt;# change the partition type, as we need an EFI partition, not &#39;Linux filesystem&#39;&lt;/span&gt;
uefi &lt;span class=&quot;token comment&quot;&gt;# &#39;uefi&#39; is an alias for &#39;1&#39;, so you can use either &#39;1&#39; or &#39;uefi&#39; here&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Changed type of partition &#39;Linux filesystem&#39; to &#39;EFI System&#39;.&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# CREATE THE ROOT PARTITION&lt;/span&gt;
n &lt;span class=&quot;token comment&quot;&gt;# add a new partition&lt;/span&gt;
*enter* &lt;span class=&quot;token comment&quot;&gt;# Partition number (2-128, default 2)&lt;/span&gt;
*enter* &lt;span class=&quot;token comment&quot;&gt;# First sector (1050624-250069646, default 3147776)&lt;/span&gt;
*enter* &lt;span class=&quot;token comment&quot;&gt;# Last sector, +/-sectors or +/-size{K,M,G,T,P} (1050624-250069646, default 250068991)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Created a new partition 2 of type &#39;Linux filesystem&#39; and of size 118.7 GiB.&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# PRINT THE PARTITION TABLE&lt;/span&gt;
p &lt;span class=&quot;token comment&quot;&gt;# print the partition table&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Disk /dev/sdf: 119.24 GiB, 128035676160 bytes, 250069680 sectors&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Disk model: SSD 850 PRO 128G&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Units: sectors of 1 * 512 = 512 bytes&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Sector size (logical/physical): 512 bytes / 512 bytes&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# I/O size (minimum/optimal): 512 bytes / 33553920 bytes&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Disklabel type: gpt&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Disk identifier: 63A0B976-C21F-47B8-B9FB-DD16BA279098&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Device       Start       End   Sectors   Size Type&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# /dev/sdf1     2048   1050623   1048576   512M EFI System&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# /dev/sdf2  1050624 250068991 249018368 118.7G Linux filesystem&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# WRITE THE TABLE TO DISK&lt;/span&gt;
w &lt;span class=&quot;token comment&quot;&gt;# write table to disk and exit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;From now on I will use the partition names above as examples ( i.e.  &lt;code&gt;/dev/sdf1&lt;/code&gt; and &lt;code&gt;/dev/sdf2&lt;/code&gt;) , but they need to be changed as appropriate for your actual setup. For example with an nvme device the partition names will likely be in the format &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt; and &lt;code&gt;/dev/nvme0n1p2&lt;/code&gt;. &lt;strong&gt;Use whatever is in the &amp;quot;Device&amp;quot; column when you printed the partition table above.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;create-the-filesystems&quot; tabindex=&quot;-1&quot;&gt;Create the filesystems &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-the-filesystems&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are two partitions, and each will have it&#39;s own filesystem. The root partition will use btrfs, but the EFI partition cannot use btrfs, and so will be set as FAT.&lt;/p&gt;
&lt;h2 id=&quot;create-the-efi-filesystems&quot; tabindex=&quot;-1&quot;&gt;Create the EFI filesystems &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-the-efi-filesystems&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.vfat &lt;span class=&quot;token parameter variable&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt; /dev/sdf1&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;encrypt-and-open-the-root-partition&quot; tabindex=&quot;-1&quot;&gt;Encrypt and open the root partition &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#encrypt-and-open-the-root-partition&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;You must use luks1 here&lt;/strong&gt; - Currently, the latest grub does support opening a luks2 partition, &lt;strong&gt;but&lt;/strong&gt; it does not support the argon2id encryption algorithm yet. So to have an encrypted boot requires luks1 for the moment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I have upped the iteration parameter to 5000 from the default 3000. This will result in the unlocking of encrypted partition taking a little longer at boot (nothing excessive, but it depends on hardware). If this is a problem (i.e. you have a slow processor), please change the 5000 in the command below back to 3000. I would not recommend going any lower than the default of 3000.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# You will be asked to create a password. Make sure it is a strong password&lt;/span&gt;
cryptsetup &lt;span class=&quot;token parameter variable&quot;&gt;--type&lt;/span&gt; luks1 &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; aes-xts-plain64 &lt;span class=&quot;token parameter variable&quot;&gt;-h&lt;/span&gt; sha512 &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; luksFormat /dev/sdf2
&lt;span class=&quot;token comment&quot;&gt;# Now open the new encrypted partition. You will be prompted to enter the password you created in the previous step.&lt;/span&gt;
cryptsetup luksOpen /dev/sdf2 cryptroot&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;create-the-root-filesystem&quot; tabindex=&quot;-1&quot;&gt;Create the root filesystem &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-the-root-filesystem&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.btrfs &lt;span class=&quot;token parameter variable&quot;&gt;-L&lt;/span&gt; archlinux /dev/mapper/cryptroot&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;mount-the-root-device&quot; tabindex=&quot;-1&quot;&gt;Mount the root device &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#mount-the-root-device&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/mapper/cryptroot /mnt&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;configuring-btrfs&quot; tabindex=&quot;-1&quot;&gt;Configuring btrfs &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#configuring-btrfs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As btrfs is being used, then subvolumes should be created.&lt;/p&gt;
&lt;h2 id=&quot;create-btrfs-subvolumes&quot; tabindex=&quot;-1&quot;&gt;Create btrfs subvolumes &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-btrfs-subvolumes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Various subvolumes will be created, this is mainly to help with snapshots later in the process.&lt;/p&gt;
&lt;p&gt;When taking a snapshot of root, the other subvolumes will not be included in the snapshot. (This is useful, for example, if you want to access logs after restoring a previous snapshot, as @log stops the logs from being rolled back along with root).&lt;/p&gt;
&lt;p&gt;If you don&#39;t want so many, then you must at least keep the first four below (@cache, @log and @tmp are not strictly necessary).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@swap
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
btrfs subvolume create /mnt/@cache
btrfs subvolume create /mnt/@log
btrfs subvolume create /mnt/@tmp&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;unmount-the-root-partition&quot; tabindex=&quot;-1&quot;&gt;Unmount the root partition &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#unmount-the-root-partition&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;umount&lt;/span&gt; /mnt&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-the-options-for-subvolume-mounting&quot; tabindex=&quot;-1&quot;&gt;Set the options for subvolume mounting &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-the-options-for-subvolume-mounting&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# set subvolume options for main btrfs subvolumes&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ssd,noatime,compress=zstd:1,space_cache=v2,discard=async&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ssd&lt;/strong&gt; - specification of the allocation scheme suitable for SSD drives (rather than rotational drives).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;noatime&lt;/strong&gt; - significantly improves read intensive workload performance, and also reduces writes in some circumstances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;compress=zstd:1&lt;/strong&gt; - zstd level 1 compression is optimal for NVME devices, while gaining some compression. If compression is increased too much with rapid NVME drives, the compression can become a bottleneck. Omit the &lt;code&gt;:1&lt;/code&gt; to use the default compression level of 3. zstd accepts a value range of 1-15, with higher levels trading speed and memory for higher compression ratios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;space_cache=v2&lt;/strong&gt; - creates cache in memory for greatly improved performance. Be sure to use v2 and not v1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;discard=async&lt;/strong&gt; - keeps the disk tidy by enabling the discarding of freed file blocks. Specifically, the asynchronous mode (async) gathers extents in larger chunks before sending them to the devices for TRIM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please take a look at the &lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/ch-mount-options.html&quot;&gt;official documentation&lt;/a&gt; for further details.&lt;/p&gt;
&lt;h2 id=&quot;mount-the-root-btrfs-subvolume&quot; tabindex=&quot;-1&quot;&gt;Mount the root BTRFS subvolume &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#mount-the-root-btrfs-subvolume&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@ /dev/mapper/cryptroot /mnt&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;create-mountpoints-for-other-btrfs-subvolumes&quot; tabindex=&quot;-1&quot;&gt;Create mountpoints for other BTRFS subvolumes &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-mountpoints-for-other-btrfs-subvolumes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently the root partition doesn&#39;t contain any subfolders to mount the other partitions to, so they need to be created.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /mnt/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;swap,home,.snapshots,var/cache,var/log,var/tmp&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;mount-the-other-subvolumes-(except-swap)&quot; tabindex=&quot;-1&quot;&gt;Mount the other subvolumes (except swap) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#mount-the-other-subvolumes-(except-swap)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mount the previously created btrfs subvolumes to the folders created in the previous section.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@home /dev/mapper/cryptroot /mnt/home
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@snapshots /dev/mapper/cryptroot /mnt/.snapshots
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@cache /dev/mapper/cryptroot /mnt/var/cache
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@log /dev/mapper/cryptroot /mnt/var/log
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${opts}&lt;/span&gt;,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@tmp /dev/mapper/cryptroot /mnt/var/tmp&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;mount-swap&quot; tabindex=&quot;-1&quot;&gt;Mount swap &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#mount-swap&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The swap subvolume needs different mounting options as it cannot use COW (Copy-On-Write), and hence cannot use compression:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; noatime,ssd,subvol&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;@swap /dev/mapper/cryptroot /mnt/swap&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;setup-swap&quot; tabindex=&quot;-1&quot;&gt;Setup swap &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#setup-swap&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The two lines below are sufficient to create a swapfile with all the necessary correct settings (such as nocow). See the &lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/Swapfile.html&quot;&gt;official guidance&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;If you want to use hybernation you must assign a swap file that is at least as large as your RAM.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# create swapfile - change the 62g to your required swap filesize (62g = 62 Gigabytes)&lt;/span&gt;
btrfs filesystem mkswapfile &lt;span class=&quot;token parameter variable&quot;&gt;--size&lt;/span&gt; 62g &lt;span class=&quot;token parameter variable&quot;&gt;--uuid&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clear&lt;/span&gt; /mnt/swap/swapfile
&lt;span class=&quot;token comment&quot;&gt;# activate swapfile&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;swapon&lt;/span&gt; /mnt/swap/swapfile&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;mount-efi-and-boot&quot; tabindex=&quot;-1&quot;&gt;Mount EFI and boot &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#mount-efi-and-boot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The EFI is mounted on the first partition, which is formated with FAT. This guide uses &lt;code&gt;/efi&lt;/code&gt; rather than the quite common &lt;code&gt;/boot/efi&lt;/code&gt;. This follows the recommendation of the &lt;a href=&quot;https://wiki.archlinux.org/title/EFI_system_partition#Typical_mount_points&quot;&gt;Arch wiki&lt;/a&gt;, and also makes sense since in this instance the UEFI info is on a completely separate partition to boot.&lt;/p&gt;
&lt;p&gt;The boot directory just needs creating, not mounting, as the root directory is already mounted, which is where boot will reside.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /mnt/efi
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /mnt/boot
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdf1 /mnt/efi&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;syncronise-the-package-database&quot; tabindex=&quot;-1&quot;&gt;Syncronise the Package Database &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#syncronise-the-package-database&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pacman &lt;span class=&quot;token parameter variable&quot;&gt;-Syy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;update-the-mirror-list&quot; tabindex=&quot;-1&quot;&gt;Update the Mirror List &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#update-the-mirror-list&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Below, swap out the countries for those of your choice.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;reflector &lt;span class=&quot;token parameter variable&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; https &lt;span class=&quot;token parameter variable&quot;&gt;--latest&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--sort&lt;/span&gt; rate &lt;span class=&quot;token parameter variable&quot;&gt;--country&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Sweden,Monaco,Switzerland,Germany&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; /etc/pacman.d/mirrorlist&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;install-the-arch-base-system&quot; tabindex=&quot;-1&quot;&gt;Install the Arch Base System &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-the-arch-base-system&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Add to, or change, the listed programs as you wish. However, this is a good starting point.&lt;/p&gt;
&lt;p&gt;Be sure that if you remove anything you know what you are doing, as some packages are required later on in the install process.&lt;/p&gt;
&lt;p&gt;For example, you may wish to switch out &lt;code&gt;intel-ucode&lt;/code&gt; for &lt;code&gt;amd-ucode&lt;/code&gt; if you have an AMD CPU. Also you could add an alternative text editor such as &lt;code&gt;nano&lt;/code&gt;. However, even if you add an alternative text editor please don&#39;t remove &lt;code&gt;vim&lt;/code&gt; as it is required later for using &lt;code&gt;visudo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can install other packages later, so you don&#39;t need to go crazy here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;  &lt;em&gt;an &lt;code&gt;lts&lt;/code&gt; kernel will be installed as an option later, so there is no need to do it here.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pacstrap /mnt base base-devel linux linux-headers linux-firmware intel-ucode btrfs-progs grub efibootmgr &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; networkmanager gvfs exfatprogs dosfstools e2fsprogs man-db man-pages texinfo openssh &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; reflector &lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; cryptsetup wpa_supplicant terminus-font&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;generate-fstab&quot; tabindex=&quot;-1&quot;&gt;Generate fstab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#generate-fstab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This will autogenerate the fstab based on the subvolumes that have been created so far.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;genfstab &lt;span class=&quot;token parameter variable&quot;&gt;-U&lt;/span&gt; /mnt &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /mnt/etc/fstab&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check result with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /mnt/etc/fstab&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;remove-subvolid&quot; tabindex=&quot;-1&quot;&gt;Remove subvolid &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#remove-subvolid&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As per the &lt;a href=&quot;https://wiki.archlinux.org/title/Btrfs#Mounting_subvolumes&quot;&gt;Arch wiki&lt;/a&gt; for btrfs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One can mimic traditional file system partitions by creating various subvolumes under the top level of the file system and then mounting them at the appropriate mount points. It is preferable to mount using &lt;code&gt;subvol=/path/to/subvolume&lt;/code&gt;, rather than the &lt;code&gt;subvolid&lt;/code&gt;, as the &lt;code&gt;subvolid&lt;/code&gt; may change when restoring #Snapshots, requiring a change of mount configuration.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://wiki.archlinux.org/title/Btrfs#Mounting_subvolumes&quot;&gt;Arch wiki&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Therefore if you want to use something like &lt;a href=&quot;https://github.com/linuxmint/timeshift&quot;&gt;timeshift&lt;/a&gt; or &lt;a href=&quot;https://github.com/openSUSE/snapper&quot;&gt;snapper&lt;/a&gt; later, then you should make this adjustment.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# completely remove the &quot;subvolid&quot; entries from fstab&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt;  /mnt/etc/fstab&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;enter-the-new-system&quot; tabindex=&quot;-1&quot;&gt;Enter the new system &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#enter-the-new-system&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We will now &#39;chroot&#39; into the newely installed system.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;basic-settings&quot; tabindex=&quot;-1&quot;&gt;Basic Settings &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#basic-settings&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now we are operating in the new install, so let&#39;s start by setting some basics.&lt;/p&gt;
&lt;h2 id=&quot;set-system-clock&quot; tabindex=&quot;-1&quot;&gt;Set system clock &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-system-clock&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Change the &#39;Europe/London&#39; as appropriate for your timezone.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; /usr/share/zoneinfo/Europe/London /etc/localtime
hwclock &lt;span class=&quot;token parameter variable&quot;&gt;--systohc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-hostname&quot; tabindex=&quot;-1&quot;&gt;Set hostname &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-hostname&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Change &#39;your_hostname&#39; to your actual hostname. (This can be anything you want, it is essentially what you want your computer to be named.)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; your_hostname &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /etc/hostname&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-hosts&quot; tabindex=&quot;-1&quot;&gt;Set hosts &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-hosts&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Again, change &#39;your_hostname&#39; to be the same as the hostname you set in the previous step.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /etc/hosts &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;EOF
127.0.0.1   localhost
::1         localhost
127.0.1.1   your_hostname.localdomain your_hostname
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-locale&quot; tabindex=&quot;-1&quot;&gt;Set Locale &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-locale&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Remember to change the relevant parts to your specific locale.&lt;/p&gt;
&lt;h3 id=&quot;option-1&quot; tabindex=&quot;-1&quot;&gt;Option 1 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en_GB.UTF-8&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s/^#&#92;(&lt;span class=&quot;token variable&quot;&gt;${locale}&lt;/span&gt;&#92;)/&lt;span class=&quot;token entity&quot; title=&quot;&#92;1&quot;&gt;&#92;1&lt;/span&gt;/&quot;&lt;/span&gt; /etc/locale.gen
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LANG=&lt;span class=&quot;token variable&quot;&gt;${locale}&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /etc/locale.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;option-2&quot; tabindex=&quot;-1&quot;&gt;Option 2 &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Alternatively, go in and edit the files directly.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;/etc/locale.gen&lt;/code&gt; uncomment  &lt;code&gt;en_GB.UTF-8 UTF-8&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;en_GB.UTF-8 UTF-8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following line to &lt;code&gt;/etc/locale.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;&lt;span class=&quot;token environment constant&quot;&gt;LANG&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;en_GB.UTF-8&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;generate-the-locales&quot; tabindex=&quot;-1&quot;&gt;Generate the locales &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#generate-the-locales&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The locales you just created need to be generated. To do this run the below:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;locale-gen&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-keyboard-layout-and-terminal-font&quot; tabindex=&quot;-1&quot;&gt;Set keyboard layout and terminal font &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-keyboard-layout-and-terminal-font&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Change &amp;quot;uk&amp;quot; to whatever your keyboard layout is.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;KEYMAP=uk&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/vconsole.conf
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FONT=ter-v28n&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/vconsole.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other font sizes if 28 is too small or large for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ter-v20n&lt;/li&gt;
&lt;li&gt;ter-v24n&lt;/li&gt;
&lt;li&gt;ter-v32n&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(also change the &#39;n&#39; to &#39;b&#39; if you want &#39;bold&#39; rather than &#39;normal&#39;)&lt;/p&gt;
&lt;h2 id=&quot;set-default-editor&quot; tabindex=&quot;-1&quot;&gt;Set default editor &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-default-editor&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Swap in your favourite editor here (e.g. &lt;code&gt;nano&lt;/code&gt;  rather than &lt;code&gt;vim&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EDITOR=vim&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/environment
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;VISUAL=vim&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/environment&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;set-accounts-and-passwords&quot; tabindex=&quot;-1&quot;&gt;Set accounts and passwords &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-accounts-and-passwords&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Some accounts and associated passwords should now be created&lt;/p&gt;
&lt;h2 id=&quot;set-the-root-password&quot; tabindex=&quot;-1&quot;&gt;Set the root password &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-the-root-password&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The root account will already exist, but it doesn&#39;t have a password yet.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;passwd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;create-a-user-and-user-password&quot; tabindex=&quot;-1&quot;&gt;Create a user and user password &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-a-user-and-user-password&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This will be your user account, so swap in your username where it says &lt;code&gt;user_name&lt;/code&gt; and set your account password.&lt;/p&gt;
&lt;p&gt;The below will also add your user to the &lt;code&gt;wheel&lt;/code&gt; group, which will allow the user to use sudo commands in conjunction with their password.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# add user&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;useradd&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-G&lt;/span&gt; wheel &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; /bin/bash user_name
&lt;span class=&quot;token comment&quot;&gt;# set password&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;passwd&lt;/span&gt; user_name&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;activate-wheel&quot; tabindex=&quot;-1&quot;&gt;Activate wheel &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#activate-wheel&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is recommended to never adust &lt;code&gt;/etc/sudoers&lt;/code&gt; directly, as any mistakes can permanently bork your system. &lt;code&gt;visudo&lt;/code&gt; is a command designed specifically to edit this file, and has checks in place to ensure that any mistakes are caught.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# issuing this command will open /etc/sudoers with vim&lt;/span&gt;
visudo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now uncomment this line:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;## Uncomment to allow members of group wheel to execute any command&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# %wheel ALL=(ALL:ALL) ALL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so it becomes:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;## Uncomment to allow members of group wheel to execute any command&lt;/span&gt;
%wheel &lt;span class=&quot;token assign-left variable&quot;&gt;ALL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ALL:ALL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ALL&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;create-the-crypto-keyfile&quot; tabindex=&quot;-1&quot;&gt;Create the crypto keyfile &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#create-the-crypto-keyfile&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This section will create an encrypted keyfile. The reason this is necessary is to remove the requirement to supply the encryption unlock password twice at boot.&lt;/p&gt;
&lt;p&gt;With the keyfile, the password is supplied once, and the system will be completely decrypted.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /
&lt;span class=&quot;token function&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/random &lt;span class=&quot;token assign-left variable&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;crypto_keyfile.bin &lt;span class=&quot;token assign-left variable&quot;&gt;iflag&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;fullblock
&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; 000 /crypto_keyfile.bin
&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt; /boot/initramfs-linux*
cryptsetup luksAddKey /dev/sdf2 /crypto_keyfile.bin
&lt;span class=&quot;token comment&quot;&gt;# enter your encryption password when prompted&lt;/span&gt;
cryptsetup luksDump /dev/sdf2
&lt;span class=&quot;token comment&quot;&gt;# You should now see that LUKS Key Slots 0 and 1 are both occupied&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;configure-mkinitcpio&quot; tabindex=&quot;-1&quot;&gt;Configure mkinitcpio &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#configure-mkinitcpio&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Mkinitcpio&quot;&gt;mkinitcpio&lt;/a&gt; is a script that creates the initial ramdisk. It basically sets up various kernel modules, and performs initialisation steps.&lt;/p&gt;
&lt;p&gt;Open the conf file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/mkinitcpio.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edit the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# load the keyfile we created&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;FILES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/crypto_keyfile.bin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Remove &quot;kms&quot; from hooks if you use a NVIDIA card so that you can use proprietary drivers later&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Add &quot;resume&quot; if you want to use hibernation later&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Add &quot;encrypt&quot; before &quot;filesystem&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# the below is my suggested ordering, but it could be adjusted if you know what you are doing&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;HOOKS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base udev keyboard autodetect keymap modconf microcode consolefont block encrypt resume filesystems &lt;span class=&quot;token function&quot;&gt;fsck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Add &quot;crc32c&quot;. Note: there used to be an option for &quot;crc32c-intel&quot; if you have an intel CPU which supports SSE4.2, but this is now deprecated.&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;MODULES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;btrfs crc32c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recompile initcpio:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkinitcpio &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; linux&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;configure-grub&quot; tabindex=&quot;-1&quot;&gt;Configure Grub &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#configure-grub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now we will go through a few steps to setup grub so the system can boot.&lt;/p&gt;
&lt;h2 id=&quot;get-uuid-of-encrypted-partition&quot; tabindex=&quot;-1&quot;&gt;Get UUID of encrypted partition &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#get-uuid-of-encrypted-partition&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;blkid &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; UUID &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; value /dev/sdf2
&lt;span class=&quot;token comment&quot;&gt;# output:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 180901b5-151a-45e3-ba87-28f02b124666&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;get-uuid-of-root&quot; tabindex=&quot;-1&quot;&gt;Get UUID of root &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#get-uuid-of-root&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;blkid &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; UUID &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; value /dev/mapper/cryptroot
&lt;span class=&quot;token comment&quot;&gt;# output:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# aba2d556-2891-4f79-a78e-4f9a6e439b02&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;get-swapfile-offset-for-resume&quot; tabindex=&quot;-1&quot;&gt;Get swapfile offset for resume &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#get-swapfile-offset-for-resume&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This &lt;a href=&quot;https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Acquire_swap_file_offset&quot;&gt;must be done&lt;/a&gt; as per the below for btrfs (using the &#39;filefrag&#39; method will be inaccurate):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;btrfs inspect-internal map-swapfile &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; /swap/swapfile
&lt;span class=&quot;token comment&quot;&gt;# output:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 533760&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;update-the-grub-file-settings&quot; tabindex=&quot;-1&quot;&gt;Update the grub file settings &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#update-the-grub-file-settings&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open the grub setting file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/default/grub&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following to what already exists. Note that the UUID for the encrypted partition is used for the &amp;quot;cryptdevice&amp;quot; and the UUID for root is used for &amp;quot;resume&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you don&#39;t need hibernation you can remove &amp;quot;resume&amp;quot; and &amp;quot;resume_offset&amp;quot;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cryptdevice=UUID=180901b5-151a-45e3-ba87-28f02b124666:cryptroot resume=UUID=aba2d556-2891-4f79-a78e-4f9a6e439b02 resume_offset=533760&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;GRUB_PRELOAD_MODULES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;luks&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# This exists, but needs turning on (i.e. remove the initial #)&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;GRUB_ENABLE_CRYPTODISK&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;y&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;install-grub&quot; tabindex=&quot;-1&quot;&gt;Install grub &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-grub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two options for running grub install. My recommendation is to use option 2 below, but it depends on your preference.&lt;/p&gt;
&lt;p&gt;If you want some more information on why you might want to use one over the other then there is some useful information &lt;a href=&quot;https://www.rodsbooks.com/efi-bootloaders/principles.html&quot;&gt;here&lt;/a&gt;. Specifically take a look at the last paragraph of the section &amp;quot;The EFI Boot Process&amp;quot;.&lt;/p&gt;
&lt;h3 id=&quot;option-1%3A-standard-install-method&quot; tabindex=&quot;-1&quot;&gt;Option 1: Standard install method &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-1%3A-standard-install-method&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This method is the standard way to install grub. This will produce an entry in your UEFI (efi) directory, and will be loaded into NVRAM by your BIOS when the system boots.&lt;/p&gt;
&lt;p&gt;I have had issues with this method in the past, as in some circumstances (for example swapping out hard drives, or moving a drive to a new system), it can cause the boot entries in the BIOS to disappear, making the drive unbootable until this setup is re-run.&lt;/p&gt;
&lt;p&gt;There are also instances of some (probably older) motherboards not recognising this method, so the drive doesn&#39;t appear in BIOS.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;grub-install &lt;span class=&quot;token parameter variable&quot;&gt;--target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;x86_64-efi --efi-directory&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/efi --bootloader-id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Arch&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the &lt;code&gt;--bootloader-id&lt;/code&gt; can be whatever you want. This is the name that will be shown in bios/grub so you can identify the install.&lt;/p&gt;
&lt;p&gt;Verify that a GRUB entry has been added to the UEFI bootloader by running:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;efibootmgr&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(It will be the one with the name specified by &amp;quot;--bootloader-id&amp;quot; from grub-install).&lt;/p&gt;
&lt;h3 id=&quot;option-2%3A-removable-install-method&quot; tabindex=&quot;-1&quot;&gt;Option 2: Removable install method &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-2%3A-removable-install-method&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is my preferred method, as it avoids the issues of the first method by installing the bootloader info in a specific standard location: &lt;code&gt;EFI/BOOT/bootx64.efi&lt;/code&gt;. This means you are not relying on NVRAM, and so the entry will never get &amp;quot;lost&amp;quot; or removed by the BIOS.&lt;/p&gt;
&lt;p&gt;Typically this is the method used by bootable USB drives, but is perfectly fine for normal drives that you have no intention of removing.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;grub-install &lt;span class=&quot;token parameter variable&quot;&gt;--target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;x86_64-efi --efi-directory&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/efi &lt;span class=&quot;token parameter variable&quot;&gt;--removable&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;generate-the-grub-configuration-file&quot; tabindex=&quot;-1&quot;&gt;Generate the GRUB configuration file &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#generate-the-grub-configuration-file&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;grub-mkconfig&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify that grub.cfg has entries for &lt;code&gt;insmod cryptodisk&lt;/code&gt; and &lt;code&gt;insmod luks&lt;/code&gt; by running:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;cryptodisk&#92;|luks&#39;&lt;/span&gt; /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;exit-and-reboot&quot; tabindex=&quot;-1&quot;&gt;Exit and reboot &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#exit-and-reboot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;exit&lt;/span&gt;
swapoff &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;umount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; /mnt
&lt;span class=&quot;token function&quot;&gt;reboot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After reboot you should end up at the arch commandline login screen (fingers crossed!).&lt;/p&gt;
&lt;h1 id=&quot;after-reboot-checks&quot; tabindex=&quot;-1&quot;&gt;After reboot checks &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#after-reboot-checks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Failed systemd services&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token parameter variable&quot;&gt;--failed&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# High priority errors in the systemd journal&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# There may be items here, it doesn&#39;t mean the install failed&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# For example I had broadcom bluetooth fails, which is normal for my system&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; journalctl &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-xb&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Check swap is active (various methods):&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;swapon&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--show&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /proc/swaps&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;connect-to-wifi-(if-required)&quot; tabindex=&quot;-1&quot;&gt;Connect to wifi (if required) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#connect-to-wifi-(if-required)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Start NetworkManager&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; NetworkManager.service
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl start NetworkManager.service

&lt;span class=&quot;token comment&quot;&gt;# Connect to WIFI&lt;/span&gt;
nmcli device wifi list
nmcli device wifi connect SSID_or_BSSID password your_password

&lt;span class=&quot;token comment&quot;&gt;# Check WIFI Connection&lt;/span&gt;
nmcli connection show&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;pacman-config-(optional)&quot; tabindex=&quot;-1&quot;&gt;Pacman config (optional) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#pacman-config-(optional)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/pacman.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uncomment (or add) the following if you wish. &amp;quot;Color&amp;quot; will provide color in the terminal, and &amp;quot;ILoveCandy&amp;quot; will make the loading bar into a &amp;quot;pacman&amp;quot; like animation.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Misc options&lt;/span&gt;
Color
ILoveCandy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uncomment the following to allow parallel downloads:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ParallelDownloads &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can change the number 5 to whatever you like depending on your connection speed.&lt;/p&gt;
&lt;h1 id=&quot;update-system&quot; tabindex=&quot;-1&quot;&gt;Update system &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#update-system&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-Syyu&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;install-lts-kernal-(recommended%2C-but-optional)&quot; tabindex=&quot;-1&quot;&gt;Install LTS kernal (recommended, but optional) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-lts-kernal-(recommended%2C-but-optional)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Install the Long-Term Support (LTS) Linux kernel as a fallback option to Arch&#39;s default kernel.&lt;/p&gt;
&lt;p&gt;As arch is generally at the bleeding edge, it can mean that there is more chance of conflicts arising with a specific new kernel. One way to mitigate this is to have an &lt;code&gt;lts&lt;/code&gt; kernel to fall back to. Hence, the recommendation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; this will not replace the &#39;normal&#39; kernel, you will have a choice between &#39;normal&#39; and &#39;lts&#39; at boot.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; linux-lts linux-lts-headers
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grub-mkconfig&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reboot and select LTS kernel to test.&lt;/p&gt;
&lt;p&gt;After reboot using the LTS kernel, confirm that the running kernel is indeed &lt;code&gt;lts&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;change-the-kernel-menu-order-in-grub&quot; tabindex=&quot;-1&quot;&gt;Change the kernel menu order in grub &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#change-the-kernel-menu-order-in-grub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may find that the LTS kernel is now the first in the boot order. This will result in the LTS kernel being automatically loaded every time you boot, rather than the normal kernel, unless you intervene at the boot menu.&lt;/p&gt;
&lt;p&gt;This is inconvenient and can get quite annoying.&lt;/p&gt;
&lt;p&gt;Until quite recently there was no good option to remedy this situation, although there were a few slightly &#39;hacky&#39; ways to get around it. However, with a recent update of grub there is now a much better solution as described in the &lt;a href=&quot;https://wiki.archlinux.org/title/GRUB#Setting_the_top-level_menu_entry&quot;&gt;Arch wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First open up the following file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/default/grub&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you have the file &lt;code&gt;grub&lt;/code&gt; open as per the above, the following line should be added as the top entry in the file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;GRUB_TOP_LEVEL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/boot/vmlinuz-linux&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will change the order of the kernels in the selection menu on boot, essentially putting the normal kernel above the LTS kernel.&lt;/p&gt;
&lt;p&gt;Then regenerate grub:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grub-mkconfig&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;install-pipewire-for-sound&quot; tabindex=&quot;-1&quot;&gt;Install pipewire for sound &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-pipewire-for-sound&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; pipewire pipewire-alsa pipewire-pulse pipewire-jack wireplumber alsa-utils&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then reboot.&lt;/p&gt;
&lt;h1 id=&quot;install-yay-for-access-to-the-aur&quot; tabindex=&quot;-1&quot;&gt;Install yay for access to the AUR &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-yay-for-access-to-the-aur&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://aur.archlinux.org/yay-git.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; yay-git
makepkg &lt;span class=&quot;token parameter variable&quot;&gt;-si&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;install-gnome&quot; tabindex=&quot;-1&quot;&gt;Install GNOME &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-gnome&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I&#39;m aware that a desktop environment is a personal thing, so you can of course install whatever you want here if you don&#39;t like GNOME. However, just bear in mind that I have not tested this guide with any other desktop environment, so if you hit problems you will need to get creative!&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; gnome gnome-extra
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; gdm.service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then reboot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: &lt;em&gt;on initial reboot I was met with a black screen immediately after providing my user password at the Gnome login screen, and was unable to proceed to the Gnome desktop. A simple reboot alleviated this. Whether you will experience the same I am not sure.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After reboot you should have a fully functional Gnome desktop environment using wayland. However, there are various other items that can be setup as well, which the next few sections will go through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Setup a NVIDIA graphics card with proprietary drivers from NVIDIA&lt;/li&gt;
&lt;li&gt;Disable root account for additional security&lt;/li&gt;
&lt;li&gt;Setup snapper to allow snapshots to be taken (including GUI)&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;nvidia-setup-(optional)&quot; tabindex=&quot;-1&quot;&gt;NVIDIA Setup (Optional) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#nvidia-setup-(optional)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you have a NVIDIA graphics card then this section is recommended.&lt;/p&gt;
&lt;h2 id=&quot;enable-the-multilib-repository&quot; tabindex=&quot;-1&quot;&gt;Enable the multilib repository &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#enable-the-multilib-repository&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open pacman conf:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/pacman.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uncomment the following lines by removing the # character at the start of them&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;multilib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
Include &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; /etc/pacman.d/mirrorlist&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update the package list, and install packages with yay.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: As of January 2026 NVIDIA has deprecated all cards from the 10xx series and lower (e.g. 1070, 1080 etc.). If you own one of these cards you will need to use packages from the AUR. See &lt;a href=&quot;https://archlinux.org/news/nvidia-590-driver-drops-pascal-support-main-packages-switch-to-open-kernel-modules/&quot;&gt;this post&lt;/a&gt; on &lt;a href=&quot;http://archlinux.org/&quot;&gt;archlinux.org&lt;/a&gt; for more details.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;nvidia-20xx-and-1650-series-and-higher%3A&quot; tabindex=&quot;-1&quot;&gt;NVIDIA 20xx and 1650 series and higher: &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#nvidia-20xx-and-1650-series-and-higher%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yay &lt;span class=&quot;token parameter variable&quot;&gt;-Syu&lt;/span&gt;
yay &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; nvidia nvidia-lts nvidia-utils libxnvctrl opencl-nvidia lib32-nvidia-utils nvidia-settings&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;nvidia-10xx-series-and-lower%3A&quot; tabindex=&quot;-1&quot;&gt;NVIDIA 10xx series and lower: &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#nvidia-10xx-series-and-lower%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yay &lt;span class=&quot;token parameter variable&quot;&gt;-Syu&lt;/span&gt;
yay &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; nvidia-580xx-dkms nvidia-580xx-utils nvidia-580xx-settings opencl-nvidia-580xx lib32-nvidia-580xx-utils libxnvctrl-580xx&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;set-enviromental-variables&quot; tabindex=&quot;-1&quot;&gt;Set enviromental variables &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#set-enviromental-variables&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Force the GBM (Generic Buffer Management) backend.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/environment
&lt;span class=&quot;token comment&quot;&gt;# Append&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;GBM_BACKEND&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;nvidia-drm
&lt;span class=&quot;token assign-left variable&quot;&gt;__GLX_VENDOR_LIBRARY_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;nvidia&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;drm-settings&quot; tabindex=&quot;-1&quot;&gt;DRM Settings &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#drm-settings&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Enable DRM (Direct Rendering Manager)&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA#DRM_kernel_mode_setting&quot;&gt;Arch Wiki&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since NVIDIA does not support automatic KMS late loading, enabling DRM (Direct Rendering Manager) kernel mode setting is required to make Wayland compositors function properly.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA#DRM_kernel_mode_setting&quot;&gt;Arch Wiki&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;option-1---add-parameters-using-modprobe-(recommended-method)&quot; tabindex=&quot;-1&quot;&gt;Option 1 - Add parameters using modprobe (recommended method) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-1---add-parameters-using-modprobe-(recommended-method)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the preferred method, as per the &lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA#DRM_kernel_mode_setting&quot;&gt;Arch Wiki&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To enable DRM (Direct Rendering Manager), set the &lt;code&gt;modeset=1&lt;/code&gt; kernel module parameter for the &lt;code&gt;nvidia_drm&lt;/code&gt; module...&lt;/p&gt;
&lt;p&gt;...Additionally, with driver version 545 and above, you can also set the experimental &lt;code&gt;nvidia_drm.fbdev=1&lt;/code&gt; parameter, which is required to tell the NVIDIA driver to provide its own framebuffer device instead of relying on efifb or vesafb, which do not work under simpledrm...&lt;/p&gt;
&lt;p&gt;...&lt;code&gt;nvidia_drm.fbdev=1&lt;/code&gt; has known issues that are only possibly fixed in the driver version 550 and above.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;options nvidia_drm modeset=1 fbdev=1&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; /etc/modprobe.d/nvidia.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;other-parameters&quot; tabindex=&quot;-1&quot;&gt;Other parameters &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#other-parameters&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are also other (non-essential) parameters that can be set at the same time. There is a great rundown of potential parameter settings on the &lt;a href=&quot;https://wiki.gentoo.org/wiki/NVIDIA/nvidia-drivers&quot;&gt;Gentoo Wiki&lt;/a&gt;, but I have selected a relevant few to apply here (the bullet point explanation text below is quoted from the Gentoo Wiki):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NVreg_UsePageAttributeTable --&amp;gt; Default:0&lt;/strong&gt; - This is one of the latest and newest additions to the NVIDIA driver modules option. It allows the driver to take full advantage of the PAT technology - a newer way of allocating memory, replacing the older Memory Type Range Register (MTRR) method. The PAT method creates a partition type table at a specific address mapped inside the register and utilizes the memory architecture and instruction set more efficiently and faster. If the computer supports PAT and the feature is enabled in the kernel then this flag can be enabled. Without PAT support, users may experience unstable performance and even crashes if this is enabled. So be careful with these options.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NVreg_InitializeSystemMemoryAllocations --&amp;gt; Default:1&lt;/strong&gt; - Tell the NVIDIA driver to clear system memory allocations prior to using it for the GPUs. Disabling can give a slight performance boost but at the cost of increased security risks. By default the driver will wipe the allocated by zeroing out its content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NVreg_PreserveVideoMemoryAllocations --&amp;gt; Default:0&lt;/strong&gt; - By default the NVIDIA Linux drivers save and restore only essential video memory allocations on system suspend and resume. Quoting NVIDIA &amp;quot;The resulting loss of video memory contents is partially compensated for by the user-space NVIDIA drivers, and by some applications, but can lead to failures such as rendering corruption and application crashes upon exit from power management cycles.&amp;quot;. The &amp;quot;still experimental&amp;quot; interface enables saving all video memory (given enough space on disk or RAM).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to apply these parameters, do the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0 NVreg_PreserveVideoMemoryAllocations=1&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; /etc/modprobe.d/nvidia.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;option-2---update-grub-(alternate-method---not-recommended)&quot; tabindex=&quot;-1&quot;&gt;Option 2 - update grub (alternate method - NOT recommended) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#option-2---update-grub-(alternate-method---not-recommended)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As an alternative to the previous modprobe method parameters can also be passed to the Linux kernel during its initial boot, through the GRUB bootloader.&lt;/p&gt;
&lt;p&gt;Open the grub settngs file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/default/grub&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the &lt;code&gt;nvidia-drm.modeset=1&lt;/code&gt;&#39; to &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nvidia_drm.fbdev=1 nvidia_drm.modeset=1 loglevel=3 quiet...&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Regenerate the grub config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grub-mkconfig&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;update-mkinitcpio&quot; tabindex=&quot;-1&quot;&gt;Update mkinitcpio &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#update-mkinitcpio&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/mkinitcpio.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Append the following to what is already there:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;MODULES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nvidia nvidia_modeset nvidia_uvm nvidia_drm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Add this if you used the recommended method (option 1) from the previous section&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;FILES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/etc/modprobe.d/nvidia.conf&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# If you haven&#39;t already, please also remove &quot;kms&quot; from &quot;HOOKS=()&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Removing &lt;code&gt;kms&lt;/code&gt;  from &lt;code&gt;HOOKS=()&lt;/code&gt; ensures that the initramfs will avoid including the open-source “nouveau” driver, which may conflict with the proprietary NVIDIA drivers.&lt;/p&gt;
&lt;p&gt;Recompile:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; mkinitcpio &lt;span class=&quot;token parameter variable&quot;&gt;-P&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;preserve-video-memory-after-suspend&quot; tabindex=&quot;-1&quot;&gt;Preserve video memory after suspend &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#preserve-video-memory-after-suspend&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default the NVIDIA Linux drivers save and restore only essential video memory allocations on system suspend and resume. Quoting NVIDIA:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The resulting loss of video memory contents is partially compensated for by the user-space NVIDIA drivers, and by some applications, but can lead to failures such as rendering corruption and application crashes upon exit from power management cycles.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://download.nvidia.com/XFree86/Linux-x86_64/460.67/README/powermanagement.html&quot;&gt;nvidia.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &amp;quot;still experimental&amp;quot; interface enables saving all video memory (given enough space on disk or RAM).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; nvidia-suspend.service nvidia-hibernate.service nvidia-resume.service&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;add-pacman-hook&quot; tabindex=&quot;-1&quot;&gt;Add Pacman Hook &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#add-pacman-hook&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This will automatically update initramfs after a NVIDIA upgrade.&lt;br /&gt;
&lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA#pacman_hook&quot;&gt;Arch wiki source&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /etc/pacman.d/hooks
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/pacman.d/hooks/nvidia.hook&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following to the file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Trigger&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Install
&lt;span class=&quot;token assign-left variable&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Upgrade
&lt;span class=&quot;token assign-left variable&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Remove
&lt;span class=&quot;token assign-left variable&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Package
&lt;span class=&quot;token assign-left variable&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;nvidia
&lt;span class=&quot;token assign-left variable&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;nvidia-lts
&lt;span class=&quot;token assign-left variable&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;linux
&lt;span class=&quot;token assign-left variable&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;linux-lts

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Action&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Updating NVIDIA module &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; initcpio
&lt;span class=&quot;token assign-left variable&quot;&gt;Depends&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;mkinitcpio
&lt;span class=&quot;token assign-left variable&quot;&gt;When&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;PostTransaction
NeedsTargets
&lt;span class=&quot;token assign-left variable&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/bin/sh &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;while read -r trg; do case $trg in linux*) exit 0; esac; done; /usr/bin/mkinitcpio -P&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;force-enable-wayland&quot; tabindex=&quot;-1&quot;&gt;Force enable wayland &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#force-enable-wayland&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The udev rules contained in &lt;code&gt;61-gdm.rules&lt;/code&gt; need to be turned off to force wayland to work with NVIDIA graphics.&lt;/p&gt;
&lt;p&gt;You will likely find that &lt;code&gt;61-gdm.rules&lt;/code&gt; does not exist in &lt;code&gt;/etc/udev/rules.d/&lt;/code&gt;, which is normal, and what you want.&lt;/p&gt;
&lt;p&gt;The following command creates a &amp;quot;symbolic link&amp;quot; to &amp;quot;no information&amp;quot; (i.e. &lt;code&gt;/dev/null&lt;/code&gt;). This effectively overrides &lt;code&gt;/usr/lib/udev/rules.d/61-gdm.rules&lt;/code&gt; (which does exist), as &lt;code&gt;/etc/udev&lt;/code&gt; takes precedence over &lt;code&gt;/usr/lib/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;em&gt;it is not a good idea to adjust the file in &lt;code&gt;/usr/lib&lt;/code&gt; as it will be overwritten automatically on updates.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; /dev/null /etc/udev/rules.d/61-gdm.rules&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reboot-and-check&quot; tabindex=&quot;-1&quot;&gt;Reboot and check &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#reboot-and-check&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Regenerate initramfs:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; mkinitcpio &lt;span class=&quot;token parameter variable&quot;&gt;-P&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Reboot&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;reboot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;NOTE: &lt;em&gt;as with the reboot after installing Gnome, on initial reboot I was met with a black screen immediately after providing my user password at the Gnome login screen, and was unable to proceed to the Gnome desktop. A simple reboot alleviated this. Whether you will experience the same I am not sure.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After reboot you can check if NVIDIA drm settings were applied with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /sys/module/nvidia_drm/parameters/modeset&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should return &lt;code&gt;Y&lt;/code&gt;&lt;/p&gt;
&lt;h1 id=&quot;disable-the-root-account-(optional)&quot; tabindex=&quot;-1&quot;&gt;Disable the root account (Optional) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#disable-the-root-account-(optional)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As per the &lt;a href=&quot;https://wiki.archlinux.org/title/Sudo#Disable_root_login&quot;&gt;Arch Wiki&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Users may wish to disable the root login. Without root, attackers must first guess a user name configured as a sudoer as well as the user password.&lt;/p&gt;
&lt;p&gt;-&lt;a href=&quot;https://wiki.archlinux.org/title/Sudo#Disable_root_login&quot;&gt;Arch Wiki&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;passwd&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt; root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;be careful here, as you could lock yourself out! Make sure you added your user to the wheel group, and activated wheel using visudo (all of this was covered earlier in this install guide).&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;enable-snapshots-with-snapper&quot; tabindex=&quot;-1&quot;&gt;Enable snapshots with snapper &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#enable-snapshots-with-snapper&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are basically two options when it comes to making snapshots with a Btrfs filesystem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Timeshift&lt;/li&gt;
&lt;li&gt;Snapper&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have used timeshift for many years, and it has saved my skin quite a few times. It just works. However, it is not as flexible / configurable as snapper, so in this instance snapper will be installed.&lt;/p&gt;
&lt;h2 id=&quot;basic-setup&quot; tabindex=&quot;-1&quot;&gt;Basic setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#basic-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section comes across as a mess of deleting and recreating things, but unfortunately this is necessary because of the way the snapper &#39;create_config&#39; currently works.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# install snapper&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; snapper snap-pac

&lt;span class=&quot;token comment&quot;&gt;# remove the original snapshots folder as the snapper script will want to create it&#39;s own&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;umount&lt;/span&gt; /.snapshots
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; /.snapshots

&lt;span class=&quot;token comment&quot;&gt;# run config creation for the root filesystem&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; snapper &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; root create-config /

&lt;span class=&quot;token comment&quot;&gt;# list the btrfs subvolumes after config&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; btrfs subvolume list /

&lt;span class=&quot;token comment&quot;&gt;# in the subvolumes list you will note that snapper has created &quot;.snapshots&quot;, but also that our original &quot;@snapshots&quot; still exists. We don&#39;t need both.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# remove the subvolume created by snapper, so we can use &quot;@snapshots&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; btrfs subvolume delete /.snapshots
&lt;span class=&quot;token comment&quot;&gt;# re-make the directory we deleted earlier and mount it&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /.snapshots
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# update the permissions for the new folder&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt; /.snapshots&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;manual-snapshot&quot; tabindex=&quot;-1&quot;&gt;Manual Snapshot &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#manual-snapshot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snapper is essentially setup, so an initial snapshot can be taken here if you wish.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# example syntax for creating a manual snapshot&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; snapper &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; root create &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;First snapshot&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;automatic-timeline-snapshots&quot; tabindex=&quot;-1&quot;&gt;Automatic Timeline Snapshots &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#automatic-timeline-snapshots&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open the config for &amp;quot;root&amp;quot;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/snapper/configs/root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# required&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;ALLOW_USERS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;your_username&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;ALLOW_GROUPS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;wheel&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# the below can be changed as you please&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_MIN_AGE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;3600&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_HOURLY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_DAILY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;7&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_WEEKLY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_MONTHLY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_QUARTERLY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;TIMELINE_LIMIT_YEARLY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enable services:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--now&lt;/span&gt; snapper-timeline.timer
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--now&lt;/span&gt; snapper-cleanup.timer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;how-to-list-configs-and-snapshots&quot; tabindex=&quot;-1&quot;&gt;How to list configs and snapshots &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#how-to-list-configs-and-snapshots&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;snapper list-configs
snapper &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; root list&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;skip-indexing-on-.snapshots&quot; tabindex=&quot;-1&quot;&gt;Skip indexing on .snapshots &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#skip-indexing-on-.snapshots&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It doesn&#39;t make sense to have indexing on the snapshots, so it may as well be disabled.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; plocate
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/updatedb.conf
&lt;span class=&quot;token comment&quot;&gt;# add the following&lt;/span&gt;
PRUNENAMES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.snapshots&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;auto-update-grub&quot; tabindex=&quot;-1&quot;&gt;Auto update Grub &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#auto-update-grub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This will allow the snapshots to appear, and be accessible from the GRUB menu on boot.&lt;/p&gt;
&lt;p&gt;Install the grub-btrfs package:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; grub-btrfs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have followed this guide then you don&#39;t need to change anything in the grub-btrfs config. However, if you have a different location for boot/grub then you may need to edit the following parameters in the config file:&lt;br /&gt;
&lt;code&gt;GRUB_BTRFS_GRUB_DIRNAME=&amp;quot;/boot/grub&amp;quot;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;GRUB_BTRFS_BOOT_DIRNAME=&amp;quot;/boot&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/default/grub-btrfs/config&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;automatically-update-grub-upon-snapshot-creation-or-deletion&quot; tabindex=&quot;-1&quot;&gt;Automatically update grub upon snapshot creation or deletion &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#automatically-update-grub-upon-snapshot-creation-or-deletion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; pacman &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; inotify-tools
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; grub-btrfsd
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl start grub-btrfsd&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;read-only-snapshots-and-overlayfs&quot; tabindex=&quot;-1&quot;&gt;Read-only snapshots and overlayfs &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#read-only-snapshots-and-overlayfs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Typically, if you boot into a snapshot it will be readonly. This can cause problems (crashing/freezing) as some parts of the root directory need write access to funciton properly.&lt;/p&gt;
&lt;p&gt;To get around this, &#39;overlayfs&#39; can be used. Overlayfs allows any changes made to be temporarily saved in RAM.&lt;/p&gt;
&lt;p&gt;This effectively gets around the write access issue, so no crashing/freezing. However, because it doesn&#39;t change the snapshot at all (the changes are in RAM), it also retains the integrity of the snapshot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;all changes made are lost on reboot.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/mkinitcpio.conf
&lt;span class=&quot;token comment&quot;&gt;# add &#39;grub-btrfs-overlayfs&#39; as the last item in HOOKS&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;HOOKS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;. &lt;span class=&quot;token function&quot;&gt;fsck&lt;/span&gt; grub-btrfs-overlayfs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Regenerate initramfs&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; mkinitcpio &lt;span class=&quot;token parameter variable&quot;&gt;-P&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;install-btrfs-assistant-(gui)&quot; tabindex=&quot;-1&quot;&gt;Install btrfs-assistant (GUI) &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#install-btrfs-assistant-(gui)&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;btrfs-assistant provides an intuitive GUI interface for managing snapshots and settings for snapper. It makes restoring, creating and monitoring snapshots a breeze.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yay &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; btrfs-assistant&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;the-end&quot; tabindex=&quot;-1&quot;&gt;The End &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#the-end&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are many more things that could be added to this guide, but I think here is a good place to stop.&lt;/p&gt;
&lt;p&gt;You should now have a fully working Arch Linux install with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Encrypted root, swapfile and boot&lt;/li&gt;
&lt;li&gt;A btrfs filesystem with compression and snapshot capabilities&lt;/li&gt;
&lt;li&gt;Gnome desktop using Wayland&lt;/li&gt;
&lt;li&gt;NVIDIA proprietary drivers&lt;/li&gt;
&lt;li&gt;Snapper snapshots including GUI&lt;/li&gt;
&lt;li&gt;The license to say &amp;quot;I use Arch BTW!&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#references&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Below are links to some of the general references and  blog post used to create this guide.&lt;/p&gt;
&lt;h2 id=&quot;arch-install-guidance&quot; tabindex=&quot;-1&quot;&gt;Arch install guidance &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#arch-install-guidance&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These two were absolutely essential for this guide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide&quot;&gt;The official Arch guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/HardenedArray/ee3041c04165926fca02deca675effe1&quot;&gt;HardenedArray -  Arch install guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also plenty of other guides that helped fill in the blanks here and there, but be careful as things can be outdated. &lt;strong&gt;If you are unsure, the Arch wiki should always be your main reference&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dwarmstrong.org/archlinux-install/&quot;&gt;Daniel Wayne Armstrong - Arch install guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/tassavarat/installing-arch-linux-with-btrfs-and-encryption-48na&quot;&gt;dev.to (Tim Assavarat) - Arch install guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codyhou.com/arch-encrypt-swap/&quot;&gt;Cody Hou - Arch install guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/User:ZachHilman/Installation_-_Btrfs_%2B_LUKS2_%2B_Secure_Boot&quot;&gt;Zach Hilman - Arch install guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/raven2cz/geek-room/tree/main/arch-install-luks-btrfs&quot;&gt;Raven2cz - Arch install&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;nvidia-settings-guidance&quot; tabindex=&quot;-1&quot;&gt;NVIDIA settings guidance &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#nvidia-settings-guidance&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Kernel_module#Setting_module_options&quot;&gt;Arch wiki - Kernel module settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.gentoo.org/wiki/NVIDIA/nvidia-drivers&quot;&gt;Gentoo wiki - NVIDIA driver guidance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/korvahannu/arch-nvidia-drivers-installation-guide&quot;&gt;Korvahannu Github - driver installation guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxiac.com/nvidia-with-wayland-on-arch-setup-guide/&quot;&gt;linuxiac.com - nvidia-wayland-arch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;btrfs&quot; tabindex=&quot;-1&quot;&gt;Btrfs &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#btrfs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some good guidance and comparisons are made here to help with a decision on what is appropriate for you in terms of Btrfs compression:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://thelinuxcode.com/enable-btrfs-filesystem-compression/&quot;&gt;thelinuxcode - btrfs compression&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Swapfile info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/Swapfile.html&quot;&gt;Btrfs official docs -  swapfile info&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;snapper-setup&quot; tabindex=&quot;-1&quot;&gt;Snapper setup &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/arch-install/#snapper-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dwarmstrong.org/btrfs-snapshots-rollbacks/&quot;&gt;Daniel Wayne Armstrong - Snapper guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lorenzobettini.it/2023/03/snapper-and-grub-btrfs-in-arch-linux/&quot;&gt;Lorenzo Bettini - Snapper guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

		</content>
	</entry>
	
	<entry>
		<title>How To Encrypt a Disk Using LUKS and Automount on Boot</title>
		<link href="https://www.thetestspecimen.com/posts/encrypt-hdd/"/>
		<updated>Tue, 30 Dec 2025 00:00:00 GMT</updated>
		<id>https://www.thetestspecimen.com/posts/encrypt-hdd/</id>
		<content type="html">
		  &lt;p&gt;&lt;strong&gt;Encryption should really be used wherever possible. There is no reason to have your data easily accessible to anybody that might be snooping around, whether you think the data is sensitive or not.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem is encryption can be a pain, with the constant requirement for password input to access your data. However, that doesn&#39;t need to be the case.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will guide you through the process of encrypting a secondary disk with LUKS (i.e. not the boot disk with your operating system installed).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Furthermore, it will detail how you can implement auto-decryption along with auto-mount, so that on system boot your data is already freely accessible. No password input!&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#introduction&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide provides information on how to encrypt a disk with LUKS, and then auto-decrypt and auto-mount the disk on boot. The following features will be included:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;LUKS2 whole disk encryption&lt;/li&gt;
&lt;li&gt;BTRFS file system, and associated settings&lt;/li&gt;
&lt;li&gt;Auto-decryption using a keyfile and crypttab&lt;/li&gt;
&lt;li&gt;Auto-mount using fstab&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To put this guide together I have mainly referenced the &lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;Arch Wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;the auto-decryption / auto-mounting only makes sense if the operating system is encrypted, as otherwise the keyfile used for auto-decryption would be accessible, which defeats the object of encrypting the drive in the first place.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;find-target-drive-name&quot; tabindex=&quot;-1&quot;&gt;Find target drive name &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#find-target-drive-name&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Firstly, it is necessary to find the correct hard drive. For this use the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;lsblk &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example output:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;NAME          FSTYPE      FSVER LABEL         UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
sdf
└─sdf1        btrfs             DriveName     4177e516-e532-45e3-8ad8-81c0ec8c1696 &lt;span class=&quot;token number&quot;&gt;117&lt;/span&gt;.2G  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;%     /mnt/mount-point&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the drive is already in use, and has been previously partitioned.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Drive name:&lt;/em&gt; sdf&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partition 1 name:&lt;/em&gt; sdf1&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partition 1 UUID:&lt;/em&gt; 4177e516-e532-45e3-8ad8-81c0ec8c1696&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partition 1 Label:&lt;/em&gt; DriveName&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partition 1 Mountpoint:&lt;/em&gt; /mnt/mount-point&lt;/p&gt;
&lt;p&gt;It may be the case that there is no partition on the disk, which is fine. The above is just for illustration.&lt;/p&gt;
&lt;h1 id=&quot;dismount-drive-if-required&quot; tabindex=&quot;-1&quot;&gt;Dismount drive if required &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#dismount-drive-if-required&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If necessary dismount the drive.&lt;/p&gt;
&lt;p&gt;This can either be done in file explorer or on the commandline if the mountpoint is known:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;umount&lt;/span&gt; /mnt/mount-point&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;securely-wipe-the-drive&quot; tabindex=&quot;-1&quot;&gt;Securely wipe the drive &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#securely-wipe-the-drive&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/hdd.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/hdd.jpg&quot; alt=&quot;a picture of an open hard disk drive&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://pixabay.com/users/rohitdarbari-16904916/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=7880077&quot;&gt;Rohit Gupta&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=7880077&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is a good idea to wipe the disk before proceeding any further.&lt;/p&gt;
&lt;p&gt;Create a container called &lt;code&gt;wipe_me&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;the &amp;quot;block-device&amp;quot; should be the main device not one of the device partitions. For example, it could be &lt;code&gt;/dev/sdf&lt;/code&gt; , but not &lt;code&gt;/dev/sdf1&lt;/code&gt; , or &lt;code&gt;/dev/nvme0n1&lt;/code&gt; but not &lt;code&gt;/dev/nvmen0n1p1&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: YOU ARE ABOUT TO WIPE THE DISK! BE SURE YOU DON&#39;T NEED THE DATA ON THE DISK AS IT IS NOT RECOVERABLE!&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; cryptsetup &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--type&lt;/span&gt; plain &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; /dev/urandom /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; wipe_me&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Zero out the container. This may take a while depending on the size and type of drive:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;1M &lt;span class=&quot;token assign-left variable&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;token assign-left variable&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/mapper/wipe_me &lt;span class=&quot;token assign-left variable&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;progress&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then close the container&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; cryptsetup close wipe_me&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;create-luks-encryption&quot; tabindex=&quot;-1&quot;&gt;Create LUKS encryption &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#create-luks-encryption&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/encrypt.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/encrypt.jpg&quot; alt=&quot;coded text viewed through a magnifying glass&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/photo-of-cryptic-character-codes-7319085/&quot;&gt;cottonbro studio&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;if you want to setup any partitions on the disk, this is the point at which you would do it. It is not necessary if you intend to use the whole disk as one single space, but it is completely up to you.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that the drive has been wiped the drive can be formatted with a LUKS container.&lt;/p&gt;
&lt;p&gt;After running the below you will be prompted to input a password. This password is the encryption/decryption password and should be as strong as possible. &lt;strong&gt;You must remember this password as without it you will not be able to decrypt the drive in the future&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; cryptsetup luksFormat &lt;span class=&quot;token parameter variable&quot;&gt;-h&lt;/span&gt; sha512 &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt; /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I have upped the iteration parameter to  5000 from the default 3000. This will result in the unlocking of the encrypted partition taking a little longer (nothing excessive,  but it depends on hardware). If this is a problem (i.e. you have a slow  processor), please change the 5000 in the command above back to 3000. I  would not recommend going any lower than the default of 3000.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;add-keyfile&quot; tabindex=&quot;-1&quot;&gt;Add Keyfile &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#add-keyfile&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In the previous section a password was created for the encryption. To allow the drive to be mounted on boot, without the requirement for a password every time, a keyfile will be created that will auto-decrypt the LUKS partition on boot:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;you can change &amp;quot;keyfile.key&amp;quot; to whatever you like, just make sure you are consistent moving forward.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/random &lt;span class=&quot;token assign-left variable&quot;&gt;iflag&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;fullblock &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; 0600 /dev/stdin /etc/cryptsetup-keys.d/keyfile.key&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the keyfile to the LUKS partition (after running the command below you will be prompted to input the encryption password you created earlier):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; cryptsetup luksAddKey /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /etc/cryptsetup-keys.d/keyfile.key&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;create-filesystem&quot; tabindex=&quot;-1&quot;&gt;Create filesystem &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#create-filesystem&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/file-system.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/file-system.jpg&quot; alt=&quot;a monitor screen with the computer file system listed in green and blue text&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;https://pixabay.com/users/joffi-1229850/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1685092&quot;&gt;joffi&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com//?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1685092&quot;&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, open the encrypted partition (you will be prompted for the password):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;  &lt;em&gt;the word &lt;code&gt;crypt&lt;/code&gt; is arbitrary, you can use whatever you like, just be consistent.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; cryptsetup luksOpen /dev/&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;block-device&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; crypt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now create the drive file system. In this case I will use BTRFS, but it can be swapped out for whichever file system you prefer:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;&amp;quot;MyDriveName&amp;quot; is the drive &amp;quot;Label&amp;quot;, and can be whatever you like. This is the name that will appear in your file explorer as the name of the drive.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; mkfs.btrfs &lt;span class=&quot;token parameter variable&quot;&gt;-L&lt;/span&gt; MyDriveName /dev/mapper/crypt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An example output after running this command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Label:              MyDriveName
UUID:               9f4f484c-6f5f-493f-a2a2-7c136e193e8d
Node size:          &lt;span class=&quot;token number&quot;&gt;16384&lt;/span&gt;
Sector size:        &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;	&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CPU page size: &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Filesystem size:    &lt;span class=&quot;token number&quot;&gt;119&lt;/span&gt;.23GiB
Block group profiles:
  Data:             single            &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;.00MiB
  Metadata:         DUP               &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.00GiB
  System:           DUP               &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;.00MiB
SSD detected:       &lt;span class=&quot;token function&quot;&gt;yes&lt;/span&gt;
Zoned device:       no
Features:           extref, skinny-metadata, no-holes, free-space-tree
Checksum:           crc32c
Number of devices:  &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
Devices:
   ID        SIZE  &lt;span class=&quot;token environment constant&quot;&gt;PATH&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;119&lt;/span&gt;.23GiB  /dev/mapper/crypt&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;setup-auto-decrypt-and-auto-mount&quot; tabindex=&quot;-1&quot;&gt;Setup auto-decrypt and auto-mount &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#setup-auto-decrypt-and-auto-mount&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/decrypt.jpg&quot;&gt;&lt;img src=&quot;https://www.thetestspecimen.com/img/encrypt-hdd/decrypt.jpg&quot; alt=&quot;a man holding a magnifying glass over encrypted text on paper and writing in a notebook&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://www.pexels.com/photo/photo-of-person-taking-down-notes-7319070/&quot;&gt;cottonbro studio&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Essentially the drive is setup at this point, all that is left to do is setup the auto-decryption followed by auto-mounting the drive.&lt;/p&gt;
&lt;h2 id=&quot;auto-decryption&quot; tabindex=&quot;-1&quot;&gt;Auto-decryption &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#auto-decryption&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For auto-decryption &lt;code&gt;crypttab&lt;/code&gt; will be used.&lt;/p&gt;
&lt;p&gt;First, the UUID of the encrypted LUKS container is needed:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;lsblk &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result (something like this), be sure to find the correct device as we did earlier:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;NAME           FSTYPE         FSVER LABEL    UUID
sdf            crypto_LUKS &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;                 3618e759-b3c7-4cf8-9753-5571ce38bc22
└─crypt btrfs                 MyDriveName    9f4f484c-6f5f-493f-a2a2-7c136e193e8d&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now add the following line to &lt;code&gt; /etc/crypttab&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;&amp;quot;drive-name-crypt&amp;quot; is arbitrary, and use the UUID from the &lt;code&gt;&amp;lt;block-device&amp;gt;&lt;/code&gt; line (i.e. sdf above, remember your device may not be called sdf! Pick the correct block device)&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;drive-name-crypt  &lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;3618e759-b3c7-4cf8-9753-5571ce38bc22  /etc/cryptsetup-keys.d/keyfile.key nofail&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;in the above the last item is &lt;code&gt;nofail&lt;/code&gt;. This is not essential to include, but is advisable. &lt;code&gt;nofail&lt;/code&gt; ensures that if the decryption fails it will not cause boot to fail. You will know it has failed as the drive won&#39;t appear later on, but at least your operating system will boot!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;auto-mount-with-fstab&quot; tabindex=&quot;-1&quot;&gt;Auto-mount with fstab &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#auto-mount-with-fstab&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, create the mount point if it doesn&#39;t already exist:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /mnt/my-drive-mount-point&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the following to &lt;code&gt;/etc/fstab&lt;/code&gt;. The UUID is from the &amp;quot;btrfs&amp;quot; line from the output of &lt;code&gt;lsblk -f&lt;/code&gt;. I have provided two options, one for SSDs and one for hard drives (rotational drives):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSD:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;9f4f484c-6f5f-493f-a2a2-7c136e193e8d  /mnt/my-drive-mount-point btrfs rw,nofail,noatime,compress&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;zstd:1,ssd,discard&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;async,space_cache&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;v2,x-gvfs-show &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;HDD:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;9f4f484c-6f5f-493f-a2a2-7c136e193e8d  /mnt/my-drive-mount-point btrfs rw,nofail,noatime,compress&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;zstd:1,nossd,space_cache&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;v2,autodefrag,x-gvfs-show &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the options after &amp;quot;btrfs&amp;quot; can in theory be changed, some explanations are given below.&lt;/p&gt;
&lt;p&gt;Options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ssd&lt;/strong&gt; - specification of the allocation scheme suitable for SSD drives (rather than rotational drives). Change this to &lt;code&gt;nossd&lt;/code&gt; for rotational drives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;noatime&lt;/strong&gt; - significantly improves read intensive workload performance, and also reduces writes in some circumstances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;compress=zstd:1&lt;/strong&gt; - zstd level 1 is the minimum level of compression. zstd accepts a value range from 1-15, with higher levels trading speed and memory for higher compression ratios. The default compression level is zstd level 3. zstd level 1 already gives a quite decent level of compression, increasing the compression level has a much larger impact on compression speed than it does on reducing file size, so only increase the level if you are not concerned at all with time to write files. Decompression speed is largely unchanged regardless of compression level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;space_cache=v2&lt;/strong&gt; - creates cache in memory for greatly improved performance. Be sure to use v2 and not v1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;discard=async&lt;/strong&gt; - keeps the disk tidy by enabling the discarding of freed file blocks.  Specifically, the asynchronous mode (async) gathers extents in larger  chunks before sending them to the devices for TRIM. (only required for  SSDs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please take a look at the &lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/ch-mount-options.html&quot;&gt;official documentation&lt;/a&gt; for further details.&lt;/p&gt;
&lt;h1 id=&quot;reboot&quot; tabindex=&quot;-1&quot;&gt;Reboot &lt;a class=&quot;direct-link&quot; href=&quot;https://www.thetestspecimen.com/posts/encrypt-hdd/#reboot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now reboot and if all has gone well you should see the drive appear after boot ready for use.&lt;/p&gt;
&lt;p&gt;The only final step you may need to perform is to change ownership of the drive to your user account the first time you use it. It will likely be assigned to root the first time you boot (replace &amp;quot;username&amp;quot; with your actual username.)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; username:username /mnt/my-drive-mount-point&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the above is done, it will not be required again.&lt;/p&gt;

		</content>
	</entry>
</feed>
