This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-07-22
Channels
- # announcements (7)
- # babashka (17)
- # beginners (45)
- # biff (2)
- # cider (16)
- # clj-on-windows (3)
- # cljs-dev (12)
- # clojure (27)
- # clojure-austin (1)
- # clojure-europe (18)
- # clojure-norway (5)
- # clojurescript (36)
- # conjure (35)
- # core-async (2)
- # datascript (4)
- # datomic (4)
- # emacs (15)
- # fulcro (23)
- # holy-lambda (12)
- # hyperfiddle (1)
- # introduce-yourself (5)
- # nbb (11)
- # off-topic (37)
- # pathom (34)
- # pedestal (9)
- # reitit (4)
- # releases (1)
- # remote-jobs (1)
- # sci (5)
- # scittle (3)
- # shadow-cljs (88)
- # tools-build (4)
I installed Neanderthal yesterday so I can do GPU computations from Clojure. It would be really nice if I could use 16-bit floats since neural nets don't usually require 32-bit precision. Does anyone know if Neanderthal allows that? Hardware is Intel + Nvidia in case it matters.
Yes and no. Neanderthal allows that, but since Nvidia's cuBLAS (and any other) library only supports 32-bit and 64-bit matrix calculations, 16-bit matrix operations are usually not implemented. Additionally, most consumer GPUs don't have general half precision support (AFAIK). Since you are interested in neural networks, maybe the right library for that feature is Deep Diamond. It generally supports half precision, when and where the underlying backend support it. Both Intel and Nvidia DO support 16 bit precision, but only for some operations where that makes sense, and usually only for inference. YMMV, but if you're just starting, I'd recommend not to worry about half precision and use 32bit floats until you reach the point where you absolutely know what you want and why.
There are 3 reasons, any of which is enough to justify the use of 16-bit floats: 1. Half precision floats require half the RAM, 2. Half as much time to transfer from CPU to GPU, 3. Doubling the precision requires 4x as many cores. Therefore halving the precision should increase throughput by 4x.
(#(get % :c (get % :b :not-found)) {:a 1 :b 2})
is there any better way to do this?
if some get does not work, do other get, else return something
If you don't expect any key to have false or nil value then try ((some-fn :c :b (constantly :nothfound)) {})
(let [{:keys [a b]} ...] (or a b))
this one
(def nested-map {:top {:middle {:bottom "hello"}}})
(get-in nested-map [:top :middle :bottom])
(-> nested-map :top :middle :bottom)
Why would I choose one over the other?
Purely stylistic?I would say that get-in
is more descriptive as it indicates that you are targeting an associative structure. It also follows the pattern that you would use to manipulate the structure (ref: https://clojuredocs.org/clojure.core/update-in)
If the structure is static, the thread macro performs slightly better. However, sometimes you construct a path to get data, in which case a vector may be more useful.
But I try to avoid nested data structures. Often the nesting is about grouping, in which case namespaced keywords are a better fit.
get/get-in is slower then threading but you can pass it a value to return if the key doesn't exist. e.g
(get {} :a "hi")
;; => "hi"
(or (-> {} :a) "hi")
;; => "hi"
i think both are equally readable without the default, with it, slight edge to get-inuh, that's not immediately intuitive to me. here is how that expands:
(let [or__5533__auto__ (-> {} :a)]
(if or__5533__auto__ or__5533__auto__ (or "hi")))
err i guess keywords have a not-found argument as well. odd, i don't often use that.
Am I thinking about this incorrectly or is a binding of this form
(loop [[thing1 thing2 & more] thing] ...)
calling first thing
second thing
and then rest thing
and then when it hits a recursion point doing so againyes except for the last statement, those bindings are only for the initial trip through the loop
but if I call recur
with more
does it not then follow the same pattern and take the first two items out?
have you tried it?
(loop [[f s & remain] (range 5)]
(println "first" f "second " s)
(when (seq remain)
(recur remain)))
first 0 second 1
first 2 second 3
first 4 second nil
nil
ah so I should use a when
yea that makes sense bc I got a NullPtrException
trying to do without
on a slightly different block of code but similar concept
is there a requirement to call seq
on remain inside the body like that
I thought range
was a seq already
in words, it is “if there are any more remaining items, continue looping with those items”
is it more common/idiomatic to use seq
like that than something like empty?
(source empty?)
(defn empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
{:added "1.0"
:static true}
[coll] (not (seq coll)))
the "rest" part of that (after the &) is done with a call to clojure.core/next
, which you can think of as rest+seq
i always forget whether its destructuring with next or rest so i just play it safe with seq all the time.
when i’m confused I’m not sure where I’d go to confirm that that is the actual behavior
enumerate=> (doc destructure)
-------------------------
clojure.core/destructure
([bindings])
nil
I could try it i suppose but I would be worried if that was implementation detail (although it likely would never change)and if not, how might I achieve something like that