The octree vs. kd-tree debate seems ancient; as I recall I've seen both sides argued well. I can't speak about KD-trees with much experience, so I can only provide half the answer. That said, I know many optimizations that can be made to the Octree data structure, these could help you in your research, and are probably relevant:
Parametric Traversal (An Efficient Parametric Algorithm for Octree Traversal by J Revelles): I hear that similar optimizations exist for kd-trees, not sure how well they work. But for octrees the method described in this paper is fast even on the CPU, and I happen to know it's trivial to rewrite as optimized SIMD code. So be on the lookout for a similar thing. On that note,
SSE/NEON/Altivec: When looking into implementing both raycast and simple top-down traversal methods, see how well they vectorize. I wouldn't rely on the compiler for this, since it's such a specific and critical problem domain with so many nuances; in fact, I tend to lean towards writing at least my top-down routine in inline assembly for good measure. Beware of dodgy code-gen around intrinsics; spitting out "movups" everywhere is not unheard of.
Cache Coherence: KD-tree nodes are points with two subnodes each. Octree nodes have 8 or more; the result is that, while KD-Trees as implemented naively are easier, octrees are trivial to rewrite for better cache coherence. A cursory glance at google reveals some variety of methods described or advocated for cache-aware KD-tree optimization, only a few being pointer-less. With octrees, the way to go seems to be to store an integer offset in each node and use it to index a "node pool", which stores each group of 8 children in their own block. This, I've found, is fastest by at least an order of magnitude, and I don't see an equivalent boost coming from blocks of 2 subnodes. But you're welcome to try :D.
Since you're doing volume rendering, you may also want to check out Jon Olick's SIGGRAPH 2008 presentation on SVOs, from the "Beyond Programmable Shading" talk. Just find the link on his youtube demonstration. Aside from describing a structure similar to what I've outlined, it has a nifty optimization in it called "depth advance". The idea is to start the raycast close to the z-buffer of the previous frame, taking advantage of temporal coherence. Again, I don't know if this is possible with KD-trees, particularly since they don't subdivide along the z-axis and parametric traversal is likely harder, but you're welcome to try :D.
I don't mean to advocate one method or another, just pointing out that the basic algorithm is only as good as its implementation, and there are a lot of subtleties at play here.