OSCR

Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation.

Code ↔ Paper

5 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 5 matches · 1 of them tie a paragraph to a whole file, not to given lines: a weak match, whose lines are not tinted
  1. [1] § Methods › CycleGAN Framework and Network Architecture ↔ models/residual_transformers.py, lines 285–348 · score 0.90 · residual CNN, channel compression, Residual Transformer, ART blocks, ResNet blocks, reshaped
  2. [2] § Methods › CycleGAN Model Training › Input Augmentations ↔ utils/NiftiDataset.py, lines 928–977 · score 0.90 · recursive Gaussian filtering, random Gaussian noise, spline deformation, augmentation, flipping, brightness
  3. [3] § Methods › CycleGAN Model Training › CycleGAN Pre‐Training ↔ models/cycle_gan_model.py, lines 83–109 · score 0.61 · L1 loss, GAN loss, cycle, PyTorch, GPU, trained
  4. [4] § Methods › CycleGAN Model Training › CycleGAN Model Training ↔ options/train_options.py, the whole file · a weak match · score 0.54 · adamW, lr, decay, epochs, training, T1w
  5. [5] § Methods › CycleGAN Framework and Network Architecture ↔ models/networks3D.py, lines 83–105 · score 0.53 · ResViT, generator models, residual, ResNet, layers, transformers

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 671 lines · 29 KB · MIT · 1 match

  1. # coding=utf-8
  2. from __future__ import absolute_import
  3. from __future__ import division
  4. from __future__ import print_function
  5. import copy
  6. import logging
  7. import math
  8. from os.path import join as pjoin
  9. import torch
  10. import torch.nn as nn
  11. import numpy as np
  12. from torch.nn import CrossEntropyLoss, Dropout, Softmax, Linear, Conv3d, LayerNorm
  13. from torch.nn.modules.utils import _pair
  14. import torch.nn.functional as F
  15. import torch.utils.checkpoint as checkpoint
  16. from scipy import ndimage
  17. from . import transformer_configs as configs
  18. logger = logging.getLogger(__name__)
  19. ATTENTION_Q = "MultiHeadDotProductAttention_1/query"
  20. ATTENTION_K = "MultiHeadDotProductAttention_1/key"
  21. ATTENTION_V = "MultiHeadDotProductAttention_1/value"
  22. ATTENTION_OUT = "MultiHeadDotProductAttention_1/out"
  23. FC_0 = "MlpBlock_3/Dense_0"
  24. FC_1 = "MlpBlock_3/Dense_1"
  25. ATTENTION_NORM = "LayerNorm_0"
  26. MLP_NORM = "LayerNorm_2"
  27. def np2th(weights, conv=False):
  28. """Possibly convert HWIO to OIHW. - Used for Loading Weights"""
  29. if conv:
  30. weights = weights.transpose([3, 2, 0, 1])
  31. return torch.from_numpy(weights)
  32. class Attention(nn.Module):
  33. def __init__(self, config, vis):
  34. super(Attention, self).__init__()
  35. self.vis = vis
  36. self.num_attention_heads = config.transformer["num_heads"]
  37. self.attention_head_size = int(config.hidden_size / self.num_attention_heads)
  38. self.all_head_size = self.num_attention_heads * self.attention_head_size##paraphrase
  39. self.query = Linear(config.hidden_size, self.all_head_size)
  40. self.key = Linear(config.hidden_size, self.all_head_size)
  41. self.value = Linear(config.hidden_size, self.all_head_size)
  42. self.out = Linear(config.hidden_size, config.hidden_size)
  43. self.attn_dropout = Dropout(config.transformer["attention_dropout_rate"])
  44. self.proj_dropout = Dropout(config.transformer["attention_dropout_rate"])
  45. self.softmax = Softmax(dim=-1)
  46. def transpose_for_scores(self, x):
  47. new_x_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size)
  48. x = x.view(*new_x_shape)
  49. return x.permute(0, 2, 1, 3)
  50. def forward(self, hidden_states):
  51. mixed_query_layer = self.query(hidden_states)
  52. mixed_key_layer = self.key(hidden_states)
  53. mixed_value_layer = self.value(hidden_states)
  54. query_layer = self.transpose_for_scores(mixed_query_layer)
  55. key_layer = self.transpose_for_scores(mixed_key_layer)
  56. value_layer = self.transpose_for_scores(mixed_value_layer)
  57. attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))
  58. attention_scores = attention_scores / math.sqrt(self.attention_head_size)
  59. attention_probs = self.softmax(attention_scores)
  60. weights = attention_probs if self.vis else None
  61. attention_probs = self.attn_dropout(attention_probs)
  62. context_layer = torch.matmul(attention_probs, value_layer)
  63. context_layer = context_layer.permute(0, 2, 1, 3).contiguous()
  64. new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
  65. context_layer = context_layer.view(*new_context_layer_shape)
  66. attention_output = self.out(context_layer)
  67. attention_output = self.proj_dropout(attention_output)
  68. return attention_output, weights
  69. class Mlp(nn.Module):
  70. def __init__(self, config):
  71. super(Mlp, self).__init__()
  72. self.fc1 = Linear(config.hidden_size, config.transformer["mlp_dim"])
  73. self.fc2 = Linear(config.transformer["mlp_dim"], config.hidden_size)
  74. self.act_fn = torch.nn.functional.gelu
  75. self.dropout = Dropout(config.transformer["dropout_rate"])
  76. self._init_weights()
  77. def _init_weights(self):
  78. nn.init.xavier_uniform_(self.fc1.weight)
  79. nn.init.xavier_uniform_(self.fc2.weight)
  80. nn.init.normal_(self.fc1.bias, std=1e-6)
  81. nn.init.normal_(self.fc2.bias, std=1e-6)
  82. def forward(self, x):
  83. x = self.fc1(x)
  84. x = self.act_fn(x)
  85. x = self.dropout(x)
  86. x = self.fc2(x)
  87. x = self.dropout(x)
  88. return x
  89. class Embeddings(nn.Module):
  90. """Construct the embeddings from patch, position embeddings.
  91. """
  92. def __init__(self, config, img_size, in_channels=3, input_dim=3, old=1):
  93. super(Embeddings, self).__init__()
  94. self.config = config
  95. img_size = _pair(img_size)
  96. grid_size = config.patches["grid"]
  97. patch_size = (img_size[0] // 16 // grid_size[0],
  98. img_size[1] // 16 // grid_size[1],
  99. img_size[2] // 16 // grid_size[2])
  100. patch_size_real = (patch_size[0] * 16,
  101. patch_size[1] * 16,
  102. patch_size[2] * 16)
  103. n_patches = (img_size[0] // patch_size_real[0]) * \
  104. (img_size[1] // patch_size_real[1]) * \
  105. (img_size[2] // patch_size_real[2])
  106. in_channels = 1024
  107. #Learnable patch embeddings
  108. self.patch_embeddings = Conv3d(in_channels=in_channels,
  109. out_channels=config.hidden_size,
  110. kernel_size=patch_size,
  111. stride=patch_size)
  112. #learnable positional encodings
  113. self.positional_encoding = nn.Parameter(torch.zeros(1, n_patches, config.hidden_size))
  114. self.dropout = Dropout(config.transformer["dropout_rate"])
  115. def forward(self, x):
  116. x = self.patch_embeddings(x)
  117. x = x.flatten(2)
  118. x = x.transpose(-1, -2)
  119. embeddings = x + self.positional_encoding
  120. embeddings = self.dropout(embeddings)
  121. return embeddings
  122. class Block(nn.Module):
  123. def __init__(self, config, vis):
  124. super(Block, self).__init__()
  125. self.hidden_size = config.hidden_size
  126. self.attention_norm = LayerNorm(config.hidden_size, eps=1e-6)
  127. self.ffn_norm = LayerNorm(config.hidden_size, eps=1e-6)
  128. self.ffn = Mlp(config)
  129. self.attn = Attention(config, vis)
  130. def forward(self, x):
  131. h = x
  132. x = self.attention_norm(x)
  133. x, weights = self.attn(x)
  134. x = x + h
  135. h = x
  136. x = self.ffn_norm(x)
  137. x = self.ffn(x)
  138. x = x + h
  139. return x, weights
  140. def load_from(self, weights, n_block):
  141. ROOT = f"Transformer/encoderblock_{n_block}"
  142. with torch.no_grad():
  143. query_weight = np2th(weights[pjoin(ROOT, ATTENTION_Q, "kernel")]).view(self.hidden_size, self.hidden_size).t()
  144. key_weight = np2th(weights[pjoin(ROOT, ATTENTION_K, "kernel")]).view(self.hidden_size, self.hidden_size).t()
  145. value_weight = np2th(weights[pjoin(ROOT, ATTENTION_V, "kernel")]).view(self.hidden_size, self.hidden_size).t()
  146. out_weight = np2th(weights[pjoin(ROOT, ATTENTION_OUT, "kernel")]).view(self.hidden_size, self.hidden_size).t()
  147. query_bias = np2th(weights[pjoin(ROOT, ATTENTION_Q, "bias")]).view(-1)
  148. key_bias = np2th(weights[pjoin(ROOT, ATTENTION_K, "bias")]).view(-1)
  149. value_bias = np2th(weights[pjoin(ROOT, ATTENTION_V, "bias")]).view(-1)
  150. out_bias = np2th(weights[pjoin(ROOT, ATTENTION_OUT, "bias")]).view(-1)
  151. self.attn.query.weight.copy_(query_weight)
  152. self.attn.key.weight.copy_(key_weight)
  153. self.attn.value.weight.copy_(value_weight)
  154. self.attn.out.weight.copy_(out_weight)
  155. self.attn.query.bias.copy_(query_bias)
  156. self.attn.key.bias.copy_(key_bias)
  157. self.attn.value.bias.copy_(value_bias)
  158. self.attn.out.bias.copy_(out_bias)
  159. mlp_weight_0 = np2th(weights[pjoin(ROOT, FC_0, "kernel")]).t()
  160. mlp_weight_1 = np2th(weights[pjoin(ROOT, FC_1, "kernel")]).t()
  161. mlp_bias_0 = np2th(weights[pjoin(ROOT, FC_0, "bias")]).t()
  162. mlp_bias_1 = np2th(weights[pjoin(ROOT, FC_1, "bias")]).t()
  163. self.ffn.fc1.weight.copy_(mlp_weight_0)
  164. self.ffn.fc2.weight.copy_(mlp_weight_1)
  165. self.ffn.fc1.bias.copy_(mlp_bias_0)
  166. self.ffn.fc2.bias.copy_(mlp_bias_1)
  167. self.attention_norm.weight.copy_(np2th(weights[pjoin(ROOT, ATTENTION_NORM, "scale")]))
  168. self.attention_norm.bias.copy_(np2th(weights[pjoin(ROOT, ATTENTION_NORM, "bias")]))
  169. self.ffn_norm.weight.copy_(np2th(weights[pjoin(ROOT, MLP_NORM, "scale")]))
  170. self.ffn_norm.bias.copy_(np2th(weights[pjoin(ROOT, MLP_NORM, "bias")]))
  171. class Encoder(nn.Module):
  172. def __init__(self, config, vis):
  173. super(Encoder, self).__init__()
  174. self.vis = vis
  175. self.layer = nn.ModuleList()
  176. self.encoder_norm = LayerNorm(config.hidden_size, eps=1e-6)
  177. for _ in range(config.transformer["num_layers"]):
  178. layer = Block(config, vis)
  179. self.layer.append(copy.deepcopy(layer))
  180. def forward(self, hidden_states):
  181. attn_weights = []
  182. for layer_block in self.layer:
  183. hidden_states, weights = layer_block(hidden_states)
  184. if self.vis:
  185. attn_weights.append(weights)
  186. encoded = self.encoder_norm(hidden_states)
  187. return encoded, attn_weights
  188. class Transformer(nn.Module):
  189. def __init__(self,config, img_size, vis,in_channels=3, old=1):
  190. super(Transformer, self).__init__()
  191. self.embeddings = Embeddings(config, img_size=img_size, input_dim=in_channels, old=old)
  192. self.encoder = Encoder(config, vis)
  193. def forward(self, input_ids):
  194. embedding_output, features = self.embeddings(input_ids)
  195. encoded, attn_weights = self.encoder(embedding_output) # (B, n_patch, hidden)
  196. return encoded, features
  197. # Define a resnet block
  198. class ResnetBlock(nn.Module):
  199. def __init__(self, dim, padding_type, norm_layer, use_dropout, use_bias, dim2=None):
  200. super(ResnetBlock, self).__init__()
  201. self.conv_block = self.build_conv_block(dim, padding_type, norm_layer, use_dropout, use_bias)
  202. def build_conv_block(self, dim, padding_type, norm_layer, use_dropout, use_bias):
  203. conv_block = []
  204. p = 0
  205. #use_dropout= use_dropo
  206. if padding_type == 'reflect':
  207. conv_block += [nn.ReflectionPad3d(1)]
  208. elif padding_type == 'replicate':
  209. conv_block += [nn.ReplicationPad3d(1)]
  210. elif padding_type == 'zero':
  211. p = 1
  212. else:
  213. raise NotImplementedError('padding [%s] is not implemented' % padding_type)
  214. conv_block += [nn.Conv3d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
  215. norm_layer(dim), nn.ReLU(True)]
  216. if use_dropout:
  217. conv_block += [nn.Dropout(0.5)]
  218. p = 0
  219. if padding_type == 'reflect':
  220. conv_block += [nn.ReflectionPad3d(1)]
  221. elif padding_type == 'replicate':
  222. conv_block += [nn.ReplicationPad3d(1)]
  223. elif padding_type == 'zero':
  224. p = 1
  225. else:
  226. raise NotImplementedError('padding [%s] is not implemented' % padding_type)
  227. conv_block += [nn.Conv3d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
  228. norm_layer(dim)]
  229. return nn.Sequential(*conv_block)
  230. def forward(self, x):
  231. out = x + self.conv_block(x)
  232. return out
  233. class ART_block(nn.Module):
  234. def __init__(self,config, input_dim, img_size=224, transformer=None):
  235. super(ART_block, self).__init__()
  236. self.transformer = transformer
  237. self.config = config
  238. ngf = 64
  239. mult = 4
  240. use_bias = False
  241. norm_layer = nn.BatchNorm3d
  242. padding_type = 'reflect'
  243. if self.transformer:
  244. # Downsample
  245. model = [nn.Conv3d(ngf * 4, ngf * 8, kernel_size=3, stride=2, padding=1, bias=use_bias),
  246. norm_layer(ngf * 8), nn.ReLU(True)]
  247. model += [nn.Conv3d(ngf * 8, 1024, kernel_size=3, stride=2, padding=1, bias=use_bias),
  248. norm_layer(1024), nn.ReLU(True)]
  249. setattr(self, 'downsample', nn.Sequential(*model))
  250. #Patch embedings
  251. self.embeddings = Embeddings(config, img_size=img_size, input_dim=input_dim)
  252. # Upsampling block
  253. model = [nn.ConvTranspose3d(self.config.hidden_size, ngf * 8,
  254. kernel_size=3, stride=2,
  255. padding=1, output_padding=1,
  256. bias=use_bias),
  257. norm_layer(ngf * 8),
  258. nn.ReLU(True)]
  259. model += [nn.ConvTranspose3d(ngf * 8, ngf * 4,
  260. kernel_size=3, stride=2,
  261. padding=1, output_padding=1,
  262. bias=use_bias),
  263. norm_layer(ngf * 4),
  264. nn.ReLU(True)]
  265. setattr(self, 'upsample', nn.Sequential(*model))
  266. #Channel compression
  267. self.cc = channel_compression(ngf * 8, ngf * 4)
  268. # Residual CNN
  269. model = [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer,
  270. use_dropout=False, use_bias=use_bias)]
  271. setattr(self, 'residual_cnn', nn.Sequential(*model))
  272. def forward(self, x):
  273. if self.transformer:
  274. # downsample
  275. down_sampled = self.downsample(x)
  276. # embed
  277. embedding_output = self.embeddings(down_sampled)
  278. # feed to transformer
  279. transformer_out, attn_weights = self.transformer(embedding_output)
  280. # reshape from (B, n_patch, hidden) to (B, h, w, hidden)
  281. B, n_patch, hidden = transformer_out.size()
  282. h, w, d = int(np.cbrt(n_patch)), int(np.cbrt(n_patch)), int(np.cbrt(n_patch))
  283. transformer_out = transformer_out.permute(0, 2, 1)
  284. transformer_out = transformer_out.contiguous().view(B, hidden, h, w, d)
  285. # upsample transformer output
  286. transformer_out = self.upsample(transformer_out)
  287. # concat transformer output and resnet output
  288. x = torch.cat([transformer_out, x], dim=1)
  289. # channel compression
  290. x = self.cc(x)
  291. # residual CNN
  292. x = self.residual_cnn(x)
  293. return x
  294. ########Generator############
  295. class ResViT(nn.Module):
  296. def __init__(self, config, input_dim, img_size=224, output_dim=3, vis=False):
  297. super(ResViT, self).__init__()
  298. self.transformer_encoder = Encoder(config, vis)
  299. self.config = config
  300. output_nc = output_dim
  301. ngf = 64
  302. use_bias = False
  303. norm_layer = nn.BatchNorm3d
  304. padding_type = 'reflect'
  305. mult = 4
  306. ############################################################################################
  307. # Layer1-Encoder1
  308. model = [nn.ReflectionPad3d(3),
  309. nn.Conv3d(input_dim, ngf, kernel_size=7, padding=0,
  310. bias=use_bias),
  311. norm_layer(ngf),
  312. nn.ReLU(True)]
  313. setattr(self, 'encoder_1', nn.Sequential(*model))
  314. ############################################################################################
  315. # Layer2-Encoder2
  316. n_downsampling = 2
  317. model = []
  318. i = 0
  319. mult = 2 ** i
  320. model = [nn.Conv3d(ngf * mult, ngf * mult * 2, kernel_size=3,
  321. stride=2, padding=1, bias=use_bias),
  322. norm_layer(ngf * mult * 2),
  323. nn.ReLU(True)]
  324. setattr(self, 'encoder_2', nn.Sequential(*model))
  325. ############################################################################################
  326. # Layer3-Encoder3
  327. model = []
  328. i = 1
  329. mult = 2 ** i
  330. model = [nn.Conv3d(ngf * mult, ngf * mult * 2, kernel_size=3,
  331. stride=2, padding=1, bias=use_bias),
  332. norm_layer(ngf * mult * 2),
  333. nn.ReLU(True)]
  334. setattr(self, 'encoder_3', nn.Sequential(*model))
  335. ####################################ART Blocks##############################################
  336. self.art_1 = ART_block(self.config, input_dim, img_size, transformer=self.transformer_encoder)
  337. self.art_2 = ART_block(self.config, input_dim, img_size, transformer=None)
  338. self.art_3 = ART_block(self.config, input_dim, img_size, transformer=None)
  339. self.art_4 = ART_block(self.config, input_dim, img_size, transformer=None)
  340. self.art_5 = ART_block(self.config, input_dim, img_size, transformer=None)
  341. self.art_6 = ART_block(self.config, input_dim, img_size, transformer=self.transformer_encoder)
  342. self.art_7 = ART_block(self.config, input_dim, img_size, transformer=None)
  343. self.art_8 = ART_block(self.config, input_dim, img_size, transformer=None)
  344. self.art_9 = ART_block(self.config, input_dim, img_size, transformer=None)
  345. ############################################################################################
  346. # Layer13-Decoder1
  347. n_downsampling = 2
  348. i = 0
  349. mult = 2 ** (n_downsampling - i)
  350. model = []
  351. model = [nn.ConvTranspose3d(ngf * mult, int(ngf * mult / 2),
  352. kernel_size=3, stride=2,
  353. padding=1, output_padding=1,
  354. bias=use_bias),
  355. norm_layer(int(ngf * mult / 2)),
  356. nn.ReLU(True)]
  357. setattr(self, 'decoder_1', nn.Sequential(*model))
  358. ############################################################################################
  359. # Layer14-Decoder2
  360. i = 1
  361. mult = 2 ** (n_downsampling - i)
  362. model = []
  363. model = [nn.ConvTranspose3d(ngf * mult, int(ngf * mult / 2),
  364. kernel_size=3, stride=2,
  365. padding=1, output_padding=1,
  366. bias=use_bias),
  367. norm_layer(int(ngf * mult / 2)),
  368. nn.ReLU(True)]
  369. setattr(self, 'decoder_2', nn.Sequential(*model))
  370. ############################################################################################
  371. # Layer15-Decoder3
  372. model = []
  373. model = [nn.ReflectionPad3d(3)]
  374. model += [nn.Conv3d(ngf, output_dim, kernel_size=7, padding=0)]
  375. model += [nn.Tanh()]
  376. setattr(self, 'decoder_3', nn.Sequential(*model))
  377. ############################################################################################
  378. def forward(self, x):
  379. # encoder
  380. x = checkpoint.checkpoint(self.encoder_1, x)
  381. x = checkpoint.checkpoint(self.encoder_2, x)
  382. x = checkpoint.checkpoint(self.encoder_3, x)
  383. # Information Bottleneck
  384. x = checkpoint.checkpoint(self.art_1, x)
  385. x = checkpoint.checkpoint(self.art_2, x)
  386. x = checkpoint.checkpoint(self.art_3, x)
  387. x = checkpoint.checkpoint(self.art_4, x)
  388. x = checkpoint.checkpoint(self.art_5, x)
  389. x = checkpoint.checkpoint(self.art_6, x)
  390. x = checkpoint.checkpoint(self.art_7, x)
  391. x = checkpoint.checkpoint(self.art_8, x)
  392. x = checkpoint.checkpoint(self.art_9, x)
  393. # decoder
  394. x = checkpoint.checkpoint(self.decoder_1, x)
  395. x = checkpoint.checkpoint(self.decoder_2, x)
  396. x = checkpoint.checkpoint(self.decoder_3, x)
  397. return x
  398. def load_from(self, weights):
  399. with torch.no_grad():
  400. res_weight = weights
  401. if self.config.name == 'b16':
  402. self.art_1.embeddings.patch_embeddings.weight.copy_(np2th(weights["embedding/kernel"], conv=True))
  403. self.art_1.embeddings.patch_embeddings.bias.copy_(np2th(weights["embedding/bias"]))
  404. self.art_6.embeddings.patch_embeddings.weight.copy_(np2th(weights["embedding/kernel"], conv=True))
  405. self.art_6.embeddings.patch_embeddings.bias.copy_(np2th(weights["embedding/bias"]))
  406. self.transformer_encoder.encoder_norm.weight.copy_(np2th(weights["Transformer/encoder_norm/scale"]))
  407. self.transformer_encoder.encoder_norm.bias.copy_(np2th(weights["Transformer/encoder_norm/bias"]))
  408. posemb = np2th(weights["Transformer/posembed_input/pos_embedding"])
  409. posemb_new = self.art_1.embeddings.positional_encoding
  410. if posemb.size() == posemb_new.size():
  411. self.art_1.embeddings.positional_encoding.copy_(posemb)
  412. elif posemb.size()[1] - 1 == posemb_new.size()[1]:
  413. posemb = posemb[:, 1:]
  414. self.art_1.embeddings.positional_encoding1.copy_(posemb)
  415. else:
  416. logger.info("load_pretrained: resized variant: %s to %s" % (posemb.size(), posemb_new.size()))
  417. ntok_new = posemb_new.size(1)
  418. _, posemb_grid = posemb[:, :1], posemb[0, 1:]
  419. gs_old = int(np.sqrt(len(posemb_grid)))
  420. gs_new = int(np.sqrt(ntok_new))
  421. print('load_pretrained: grid-size from %s to %s' % (gs_old, gs_new))
  422. posemb_grid = posemb_grid.reshape(gs_old, gs_old, -1)
  423. zoom = (gs_new / gs_old, gs_new / gs_old, 1)
  424. posemb_grid = ndimage.zoom(posemb_grid, zoom, order=1) # th2np
  425. posemb_grid = posemb_grid.reshape(1, gs_new * gs_new, -1)
  426. posemb = posemb_grid
  427. self.art_1.embeddings.positional_encoding.copy_(np2th(posemb))
  428. #############
  429. posemb = np2th(weights["Transformer/posembed_input/pos_embedding"])
  430. posemb_new = self.art_6.embeddings.positional_encoding
  431. if posemb.size() == posemb_new.size():
  432. self.art_6.embeddings.positional_encoding.copy_(posemb)
  433. elif posemb.size()[1] - 1 == posemb_new.size()[1]:
  434. posemb = posemb[:, 1:]
  435. self.art_6.embeddings.positional_encoding.copy_(posemb)
  436. else:
  437. logger.info("load_pretrained: resized variant: %s to %s" % (posemb.size(), posemb_new.size()))
  438. ntok_new = posemb_new.size(1)
  439. _, posemb_grid = posemb[:, :1], posemb[0, 1:]
  440. gs_old = int(np.sqrt(len(posemb_grid)))
  441. gs_new = int(np.sqrt(ntok_new))
  442. print('load_pretrained: grid-size from %s to %s' % (gs_old, gs_new))
  443. posemb_grid = posemb_grid.reshape(gs_old, gs_old, -1)
  444. zoom = (gs_new / gs_old, gs_new / gs_old, 1)
  445. posemb_grid = ndimage.zoom(posemb_grid, zoom, order=1) # th2np
  446. posemb_grid = posemb_grid.reshape(1, gs_new * gs_new, -1)
  447. posemb = posemb_grid
  448. self.art_6.embeddings.positional_encoding.copy_(np2th(posemb))
  449. # Encoder whole
  450. for bname, block in self.transformer_encoder.named_children():
  451. for uname, unit in block.named_children():
  452. unit.load_from(weights, n_block=uname)
  453. class Res_CNN(nn.Module):
  454. def __init__(self, config, input_dim, img_size=224, output_dim=3, vis=False):
  455. super(Res_CNN, self).__init__()
  456. self.config = config
  457. output_nc = output_dim
  458. ngf = 64
  459. use_bias = False
  460. norm_layer = nn.BatchNorm3d
  461. padding_type = 'reflect'
  462. mult = 4
  463. ############################################################################################
  464. # Layer1-Encoder1
  465. model = [nn.ReflectionPad3d(3),
  466. nn.Conv3d(input_dim, ngf, kernel_size=7, padding=0,
  467. bias=use_bias),
  468. norm_layer(ngf),
  469. nn.ReLU(True)]
  470. setattr(self, 'encoder_1', nn.Sequential(*model))
  471. ############################################################################################
  472. # Layer2-Encoder2
  473. n_downsampling = 2
  474. model = []
  475. i = 0
  476. mult = 2 ** i
  477. model = [nn.Conv3d(ngf * mult, ngf * mult * 2, kernel_size=3,
  478. stride=2, padding=1, bias=use_bias),
  479. norm_layer(ngf * mult * 2),
  480. nn.ReLU(True)]
  481. setattr(self, 'encoder_2', nn.Sequential(*model))
  482. ############################################################################################
  483. # Layer3-Encoder3
  484. model = []
  485. i = 1
  486. mult = 2 ** i
  487. model = [nn.Conv3d(ngf * mult, ngf * mult * 2, kernel_size=3,
  488. stride=2, padding=1, bias=use_bias),
  489. norm_layer(ngf * mult * 2),
  490. nn.ReLU(True)]
  491. setattr(self, 'encoder_3', nn.Sequential(*model))
  492. ####################################ART Blocks##############################################
  493. mult = 4
  494. self.art_1 = ART_block(self.config, input_dim, img_size, transformer=None)
  495. self.art_2 = ART_block(self.config, input_dim, img_size, transformer=None)
  496. self.art_3 = ART_block(self.config, input_dim, img_size, transformer=None)
  497. self.art_4 = ART_block(self.config, input_dim, img_size, transformer=None)
  498. self.art_5 = ART_block(self.config, input_dim, img_size, transformer=None)
  499. self.art_6 = ART_block(self.config, input_dim, img_size, transformer=None)
  500. self.art_7 = ART_block(self.config, input_dim, img_size, transformer=None)
  501. self.art_8 = ART_block(self.config, input_dim, img_size, transformer=None)
  502. self.art_9 = ART_block(self.config, input_dim, img_size, transformer=None)
  503. ############################################################################################
  504. # Layer13-Decoder1
  505. n_downsampling = 2
  506. i = 0
  507. mult = 2 ** (n_downsampling - i)
  508. model = []
  509. model = [nn.ConvTranspose3d(ngf * mult, int(ngf * mult / 2),
  510. kernel_size=3, stride=2,
  511. padding=1, output_padding=1,
  512. bias=use_bias),
  513. norm_layer(int(ngf * mult / 2)),
  514. nn.ReLU(True)]
  515. setattr(self, 'decoder_1', nn.Sequential(*model))
  516. ############################################################################################
  517. # Layer14-Decoder2
  518. i = 1
  519. mult = 2 ** (n_downsampling - i)
  520. model = []
  521. model = [nn.ConvTranspose3d(ngf * mult, int(ngf * mult / 2),
  522. kernel_size=3, stride=2,
  523. padding=1, output_padding=1,
  524. bias=use_bias),
  525. norm_layer(int(ngf * mult / 2)),
  526. nn.ReLU(True)]
  527. setattr(self, 'decoder_2', nn.Sequential(*model))
  528. ############################################################################################
  529. # Layer15-Decoder3
  530. model = []
  531. model = [nn.ReflectionPad3d(3)]
  532. model += [nn.Conv3d(ngf, output_dim, kernel_size=7, padding=0)]
  533. model += [nn.Tanh()]
  534. setattr(self, 'decoder_3', nn.Sequential(*model))
  535. ############################################################################################
  536. def forward(self, x):
  537. # Encoder
  538. x = self.encoder_1(x)
  539. x = self.encoder_2(x)
  540. x = self.encoder_3(x)
  541. # Information bottleneck
  542. x = self.art_1(x)
  543. x = self.art_2(x)
  544. x = self.art_3(x)
  545. x = self.art_4(x)
  546. x = self.art_5(x)
  547. x = self.art_6(x)
  548. x = self.art_7(x)
  549. x = self.art_8(x)
  550. x = self.art_9(x)
  551. # Decoder
  552. x = self.decoder_1(x)
  553. x = self.decoder_2(x)
  554. x = self.decoder_3(x)
  555. return x
  556. class channel_compression(nn.Module):
  557. def __init__(self, in_channels, out_channels, stride=1):
  558. """
  559. Args:
  560. in_channels (int): Number of input channels.
  561. out_channels (int): Number of output channels.
  562. stride (int): Controls the stride.
  563. """
  564. super(channel_compression, self).__init__()
  565. self.skip = nn.Sequential()
  566. if stride != 1 or in_channels != out_channels:
  567. self.skip = nn.Sequential(
  568. nn.Conv3d(in_channels=in_channels, out_channels=out_channels,
  569. kernel_size=1, stride=stride, bias=False),
  570. nn.BatchNorm3d(out_channels))
  571. else:
  572. self.skip = None
  573. self.block = nn.Sequential(
  574. nn.Conv3d(in_channels=in_channels, out_channels=out_channels,
  575. kernel_size=3, padding=1, stride=1, bias=False),
  576. nn.BatchNorm3d(out_channels),
  577. nn.ReLU(),
  578. nn.Conv3d(in_channels=out_channels, out_channels=out_channels,
  579. kernel_size=3, padding=1, stride=1, bias=False),
  580. nn.BatchNorm3d(out_channels))
  581. def forward(self, x):
  582. out = self.block(x)
  583. out += (x if self.skip is None else self.skip(x))
  584. out = F.relu(out)
  585. return out
  586. CONFIGS = {
  587. 'ViT-B_16': configs.get_b16_config(),
  588. 'ViT-L_16': configs.get_l16_config(),
  589. 'Res-ViT-B_16': configs.get_resvit_b16_config(),
  590. 'Res-ViT-L_16': configs.get_resvit_l16_config()
  591. }

residual_transformers.py at commit 0a8fd15, under MIT · at the source

Overview

Authors: Peter Hsu1,2, Elisa Marchetto1, Patricia M. Johnson1,2,3, Jelle Veraart1,3
  1. Bernard and Irene Schwartz Center for Biomedical Imaging, Department of Radiology New York University Grossman School of Medicine New York New York USA
  2. Vilcek Institute of Graduate Biomedical Sciences, New York University Grossman School of Medicine New York New York USA
  3. Center for Advanced Imaging Innovation and Research (CAI2R), Department of Radiology New York University Grossman School of Medicine New York New York USA
Institutions: New York University (United States); Center for Advanced Imaging Innovation and Research (United States)
Journal: Magnetic resonance in medicine, volume 96, issue 5, pages 2458-2473
Dates: received 28 January 2026; accepted 16 June 2026; published online 22 July 2026; in print November 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1002/mrm.70488 · PMID 42487246 · PMCID PMC13527236 · OpenAlex W7170138008
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), methods / tools (subfield)
Methods: Connectivity, Statistics, Machine learning
Keywords: accessible neuroimaging, brain segmentation, brain volume analysis, deep learning, image‐to‐image translation, ultra‐low‐field MRI
MeSH: Brain*, Image Processing, Computer-Assisted*, Magnetic Resonance Imaging*, Neuroimaging*, Algorithms, Deep Learning, Generative Adversarial Networks, Humans, Image Interpretation, Computer-Assisted, Reproducibility of Results, Signal-To-Noise Ratio (* major topic)
Journal subjects: Computer Processing and Modeling
Topic: Advanced MRI Techniques and Applications (Radiology, Nuclear Medicine and Imaging, Medicine), according to OpenAlex
Funding: NIH (P41 EB017183); NYU‐KAIST Global Innovation and Research Institute
Citations: not cited yet (Europe PMC); 103 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repository

Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.

peterjhsu/CycleGAN-3D-ULF

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 0a8fd1521c455ae2a0ac30c6e0ffe3f78c54927e, 23 July 2026
Languages: Python (14), Shell (3)
Size: 21 files, 17 scripts
Software Heritage: not archived
Found in: “Data Availability Statement”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: PyTorch (7 files), NumPy (3 files), SciPy (2 files), Matplotlib (1 file), MONAI (1 file), SimpleITK (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
19 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 17 scripts, each with its path and the digest of its content;
  • 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1002/mrm.70488.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 2, 28 September 2026

  • Publisher: n/a → Wiley

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 6 keywords, 11 MeSH terms, 2 funders, 90 references.

Cite

This paper

Hsu, P., Marchetto, E., Johnson, P. M., & Veraart, J. (2026). Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation. Magnetic resonance in medicine, 96(5), 2458-2473. https://doi.org/10.1002/mrm.70488

BibTeX

@article{hsu2026advancing,
author = {Hsu, Peter and Marchetto, Elisa and Johnson, Patricia M. and Veraart, Jelle},
title = {{Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation}},
journal = {Magnetic resonance in medicine},
year = {2026},
month = jul,
volume = {96},
number = {5},
pages = {2458--2473},
publisher = {Wiley},
issn = {0740-3194},
doi = {10.1002/mrm.70488},
url = {https://doi.org/10.1002/mrm.70488},
pmid = {42487246},
pmcid = {PMC13527236}
}

RIS

TY - JOUR
AU - Hsu, Peter
AU - Marchetto, Elisa
AU - Johnson, Patricia M.
AU - Veraart, Jelle
TI - Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation
T2 - Magnetic resonance in medicine
J2 - Magn Reson Med
PY - 2026
DA - 2026/07/22
VL - 96
IS - 5
SP - 2458
EP - 2473
SN - 0740-3194
PB - Wiley
DO - 10.1002/mrm.70488
UR - https://doi.org/10.1002/mrm.70488
LA - en
ER -

CSL-JSON

{
"id": "10.1002/mrm.70488",
"type": "article-journal",
"title": "Advancing the Volumetric Analysis of Ultra-Low-Field Brain MRI Using Image-to-Image Translation",
"container-title": "Magnetic resonance in medicine",
"author": [
{
"family": "Hsu",
"given": "Peter"
},
{
"family": "Marchetto",
"given": "Elisa"
},
{
"family": "Johnson",
"given": "Patricia M."
},
{
"family": "Veraart",
"given": "Jelle"
}
],
"container-title-short": "Magn Reson Med",
"volume": "96",
"issue": "5",
"page": "2458-2473",
"DOI": "10.1002/mrm.70488",
"PMID": "42487246",
"PMCID": "PMC13527236",
"ISSN": "0740-3194",
"publisher": "Wiley",
"URL": "https://doi.org/10.1002/mrm.70488",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
22
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1162/imag.a.1352 [code]
Brain-age in ultra-low-field MRI: How well does it work?
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MONAI, PyTorch, SciPy, 1 other tool, methods / tools, structural MRI / diffusion, 11 references
[2] doi:10.1016/j.jmro.2026.100225 [code]
Feasibility, image quality, and analytic usability of mobile 64 mT ultra-low-field MRI for infant brain imaging at 3 and 12 months in southern Malawi.
Journal: Journal of magnetic resonance open
In common: structural MRI / diffusion, 11 references
[3] doi:10.1002/mrm.70407 [code]
Time-Conditioned Zero-Shot Self-Supervised Reconstruction for Accelerated 3D Ultra-Low-Field MRI.
Journal: Magnetic resonance in medicine
In common: PyTorch, SciPy, Matplotlib, 1 other tool, structural MRI / diffusion, 6 references
[4] doi:10.1016/j.patter.2026.101538 [code]
A multi-modal foundation model for brain disease diagnosis and medical imaging.
Journal: Patterns (New York, N.Y.)
In common: MONAI, PyTorch, SciPy, 2 other tools, 4 references
[5] doi:10.1002/hbm.70547 [code]
miniMORPH: A Morphometry Pipeline for Low-Field MRI in Infants.
Journal: Human brain mapping
In common: Matplotlib, NumPy, structural MRI / diffusion, 7 references
[6] doi:10.64898/2026.07.15.26357954 [code]
Portable Ultra-Low Field MRI Deep-Learning Algorithms for White Matter Lesion Segmentation Improve Accuracy and Reflect Clinical Disability in Multiple Sclerosis
Journal: medRxiv (preprint)
In common: SimpleITK, PyTorch, SciPy, 2 other tools, structural MRI / diffusion, 4 references
[7] doi:10.1002/advs.76596 [code]
DDSurfer: A Weakly-Supervised Dual-Stream Deep Learning Framework for Cortical Surface Reconstruction From Diffusion MRI.
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)
In common: SimpleITK, PyTorch, SciPy, 1 other tool, methods / tools, structural MRI / diffusion, 5 references
[8] doi:10.1080/01652176.2026.2696026
Canine brain imaging with a new low-field portable (0.05 T) MRI scanner: a pilot <i>in vivo</i> comparison to conventional 1.5 T.
Journal: The veterinary quarterly
In common: structural MRI / diffusion, 6 references
[9] doi:10.1162/imag.a.1183 [code]
Learning-based segmentation of diffusion-weighted MR images with arbitrary <i>q</i>-space samplings.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: PyTorch, SciPy, Matplotlib, 1 other tool, methods / tools, structural MRI / diffusion, 6 references
[10] doi:10.1016/j.crmeth.2026.101473 [code]
AmygdalaGo-BOLT for boundary-aware segmentation of the human amygdala.
Journal: Cell reports methods
In common: MONAI, SimpleITK, PyTorch, 3 other tools, methods / tools, structural MRI / diffusion, 1 reference

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.