前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >tensorflow 0.10 word2vec 源码解析

tensorflow 0.10 word2vec 源码解析

作者头像
ke1th
发布于 2019-05-27 04:19:02
发布于 2019-05-27 04:19:02
84100
代码可运行
举报
运行总次数:0
代码可运行

版权声明:本文为博主原创文章,转载请注明出处。 https://cloud.tencent.com/developer/article/1436566

关于word2vec 的解释见word2vec的数学原理

本代码主要是实现了skip-gram模型,通过神经网络,对概率进行建模(概率模型中的最大似然,其实就是神经网络中的最小损失)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections
import math
import os
import random
import zipfile
import numpy as np    #在引用包方面,对源码进行了一些修改,因为源码应该是基于python3的 
import urllib         #而我使用的python2
import tensorflow as tf

# Step 1: Download the data.
url = 'http://mattmahoney.net/dc/'

def maybe_download(filename, expected_bytes):
  """Download a file if not present, and make sure it's the right size."""
  if not os.path.exists(filename):
    filename, _ = urllib.urlretrieve(url + filename, filename)
  statinfo = os.stat(filename)
  if statinfo.st_size == expected_bytes:
    print('Found and verified', filename)
  else:
    print(statinfo.st_size)
    raise Exception(
        'Failed to verify ' + filename + '. Can you get to it with a browser?')
  return filename

filename = maybe_download('text8.zip', 31344016)


# Read the data into a list of strings.
def read_data(filename):
  """Extract the first file enclosed in a zip file as a list of words"""
  with zipfile.ZipFile(filename) as f:
    data = tf.compat.as_str(f.read(f.namelist()[0])).split()
  return data

words = read_data(filename)
print('Data size', len(words))

# Step 2: Build the dictionary and replace rare words with UNK token.
vocabulary_size = 50000

def build_dataset(words): #words in corpus , list
  count = [['UNK', -1]]
  count.extend(collections.Counter(words).most_common(vocabulary_size - 1)) 
  # 因为使用了most_common,所以count中的word,是按照word在文本中出现的次数从大到小排列的
  dictionary = dict()
  for word, _ in count:
    dictionary[word] = len(dictionary)   # assign id to word
  data = list()
  unk_count = 0
  for word in words:
    if word in dictionary:
      index = dictionary[word]
    else:
      index = 0  # dictionary['UNK'] UNK:unknown
      unk_count += 1
    data.append(index) #translate word to id
  count[0][1] = unk_count
  reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
  return data, count, dictionary, reverse_dictionary #data:ids count:list of [word,num] dictionary:word->id ,

data, count, dictionary, reverse_dictionary = build_dataset(words)
del words  # Hint to reduce memory.
print('Most common words (+UNK)', count[:5])
print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])

data_index = 0


# Step 3: Function to generate a training batch for the skip-gram model.
#skip_skip:从span里面取出多少个word, skip_window:|contex(w)| / 2
#span: w上下文的word, 只能从span这个范围中获取
def generate_batch(batch_size, num_skips, skip_window):
  global data_index
  assert batch_size % num_skips == 0
  assert num_skips <= 2 * skip_window   # num_skip? skip_window? skip-gram
  batch = np.ndarray(shape=(batch_size), dtype=np.int32) #batch_size: the number of words in one batch
  labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
  span = 2 * skip_window + 1 # [ skip_window target skip_window ]
  buffer = collections.deque(maxlen=span) #buffer用来存取w上下文word的id
  for _ in range(span):
    buffer.append(data[data_index]) # data:ids
    data_index = (data_index + 1) % len(data)
  for i in range(batch_size // num_skips): #how many num_skips in a batch
    target = skip_window  # target label at the center of the buffer
    targets_to_avoid = [ skip_window ] # extract the middle word
    for j in range(num_skips):
      while target in targets_to_avoid:#context中的word,一个只取一次
        target = random.randint(0, span - 1)
      targets_to_avoid.append(target) #
      batch[i * num_skips + j] = buffer[skip_window]
      labels[i * num_skips + j, 0] = buffer[target]
    buffer.append(data[data_index]) #update the buffer, append the next word to buffer
    data_index = (data_index + 1) % len(data)
  return batch, labels #batch: ids [batch_size] lebels:ids [batch_size*1]

batch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1)
for i in range(8):
  print(batch[i], reverse_dictionary[batch[i]],
      '->', labels[i, 0], reverse_dictionary[labels[i, 0]])
#========================================================
#上面的操作会形成一个这样的输出 batch中存储的是id, 假设我们去skip_size = 4, skip_window = 2
#那么,单词 as 所对应的context的word个数就是4个,所以batch中有4as, 所对应的就是context中的word
# 12 as -> 195 term
# 12 as -> 5239 anarchism
# 12 as -> 6 a
# 12 as -> 3084 originated
# 6 a -> 12 as
# 6 a -> 3084 originated
# 6 a -> 2 of
# 6 a -> 195 term
#=======================================================
# Step 4: Build and train a skip-gram model.

#在本代码中,batch_size代表的是一个batch中,word的个数,而不是sentense的个数。
batch_size = 128
embedding_size = 128  # Dimension of the embedding vector.
skip_window = 1       # How many words to consider left and right.
num_skips = 2         # How many times to reuse an input(buffer) to generate a label.

# We pick a random validation set to sample nearest neighbors. Here we limit the
# validation samples to the words that have a low numeric ID, which by
# construction are also the most frequent.
valid_size = 16     # Random set of words to evaluate similarity on.
valid_window = 100  # Only pick dev samples in the head of the distribution.
valid_examples = np.random.choice(valid_window, valid_size, replace=False)
num_sampled = 64    # Number of negative examples to sample.

graph = tf.Graph()

with graph.as_default():

  # Input data.
  #在这里,我们只输入word对应的id,假设batch_size是128,那么我们第一次就输入文本前128个word所对应的id
  train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
  #labels和inputs是一样的, 只不过一个是行向量(tensor),一个是列向量(tensor)
  train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
  valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

  # Ops and variables pinned to the CPU because of missing GPU implementation
  with tf.device('/cpu:0'):
    # Look up embeddings for inputs.
    embeddings = tf.Variable(
        tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
    # embedding_look 返回值的shape 是 shape(train_inputs)+shape(embeddings)[1:]
    embed = tf.nn.embedding_lookup(embeddings, train_inputs)

    # Construct the variables for the NCE loss
    nce_weights = tf.Variable(   #every word has a corresponding nce_weight ad nce_biase
        tf.truncated_normal([vocabulary_size, embedding_size],
                            stddev=1.0 / math.sqrt(embedding_size)))
    nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

word2vec的数学原理中的skip-gram模型解释中,作者提到了一个公式

σ(xTwθu+bu)σ(xwTθu+bu)\sigma(x_w^T\theta^u+b^u) 其中 xTw_xwTx_w^T 是输入的word_vector ,θu_θu\theta^u 和 _bu_bub^u 就是上面的nce_weights nce_bias 其中nce_weightsu_id nce_biasu_id 对应与单词u

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  # Compute the average NCE loss for the batch.
  # tf.nce_loss automatically draws a new sample of the negative labels each
  # time we evaluate the loss.
  loss = tf.reduce_mean(
      tf.nn.nce_loss(nce_weights, nce_biases, embed, train_labels,
                     num_sampled, vocabulary_size))#关于nce_loss的介绍在文章最后

  # Construct the SGD optimizer using a learning rate of 1.0.
  optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)

  # Compute the cosine similarity between minibatch examples and all embeddings.
  norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
  normalized_embeddings = embeddings / norm
  valid_embeddings = tf.nn.embedding_lookup(
      normalized_embeddings, valid_dataset)
  similarity = tf.matmul(
      valid_embeddings, normalized_embeddings, transpose_b=True)

  # Add variable initializer.
  init = tf.initialize_all_variables()

# Step 5: Begin training.
num_steps = 10001

with tf.Session(graph=graph) as session:
  # We must initialize all variables before we use them.
  init.run()
  print("Initialized")

  average_loss = 0
  for step in xrange(num_steps):
    batch_inputs, batch_labels = generate_batch(
        batch_size, num_skips, skip_window)
    feed_dict = {train_inputs : batch_inputs, train_labels : batch_labels}

    # We perform one update step by evaluating the optimizer op (including it
    # in the list of returned values for session.run()
    _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)
    average_loss += loss_val

    if step % 2000 == 0:
      if step > 0:
        average_loss /= 2000
      # The average loss is an estimate of the loss over the last 2000 batches.
      print("Average loss at step ", step, ": ", average_loss)
      average_loss = 0

    # Note that this is expensive (~20% slowdown if computed every 500 steps)
    if step % 10000 == 0:
      sim = similarity.eval()
      for i in xrange(valid_size):
        valid_word = reverse_dictionary[valid_examples[i]]
        top_k = 8 # number of nearest neighbors
        nearest = (-sim[i, :]).argsort()[1:top_k+1]
        log_str = "Nearest to %s:" % valid_word
        for k in xrange(top_k):
          close_word = reverse_dictionary[nearest[k]]
          log_str = "%s %s," % (log_str, close_word)
        print(log_str)
  final_embeddings = normalized_embeddings.eval()

# Step 6: Visualize the embeddings.

def plot_with_labels(low_dim_embs, labels, filename='tsne.png'):
  assert low_dim_embs.shape[0] >= len(labels), "More labels than embeddings"
  plt.figure(figsize=(18, 18))  #in inches
  for i, label in enumerate(labels):
    x, y = low_dim_embs[i,:]
    plt.scatter(x, y)
    plt.annotate(label,
                 xy=(x, y),
                 xytext=(5, 2),
                 textcoords='offset points',
                 ha='right',
                 va='bottom')

  plt.savefig(filename)

try:
  from sklearn.manifold import TSNE
  import matplotlib.pyplot as plt

  tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000)
  plot_only = 500
  low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only,:])
  labels = [reverse_dictionary[i] for i in xrange(plot_only)]
  plot_with_labels(low_dim_embs, labels)

except ImportError:
  print("Please install sklearn, matplotlib, and scipy to visualize embeddings.")

细说nce_loss

nce_loss函数提供了,取negtive sample,计算loss一条龙服务,相当方便。源码中的注释是这么写的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def nce_loss(weights, #[num_classes, dim] dim就是emdedding_size
             biases,  #[num_classes] num_classes就是word的个数(不包括重复的)
             inputs, #[batch_size, dim]
             labels,  #[batch_size, num_true] 这里,我们的num_true设置为1,就是一个输入对应一个输出
             num_sampled,#要取的负样本的个数(per batch)
             num_classes,#类别的个数(在这里就是word的个数(不包含重复的))
             num_true=1,
             sampled_values=None,
             remove_accidental_hits=False,
             partition_strategy="mod",
             name="nce_loss"):
      logits, labels = _compute_sampled_logits(
      weights,
      biases,
      inputs,
      labels,
      num_sampled,
      num_classes,
      num_true=num_true,
      sampled_values=sampled_values,
      subtract_log_q=True,
      remove_accidental_hits=remove_accidental_hits,
      partition_strategy=partition_strategy,
      name=name)
  sampled_losses = sigmoid_cross_entropy_with_logits(
      logits, labels, name="sampled_losses") 
      #此函数返回的tensor与输入logits同维度。 _sum_rows之后,就得到了每个样本的corss entropy。
  # sampled_losses is batch_size x {true_loss, sampled_losses...}
  # We sum out true and sampled losses.
  return _sum_rows(sampled_losses)
  #在word2vec中对此函数的返回调用了reduce_mean() 就获得了平均 cross entropy

nce_loss调用了_compute_sammpled_logits, 这个函数是搞什么的呢?

看源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 def _compute_sampled_logits(weights,
                            biases,
                            inputs,
                            labels,
                            num_sampled,
                            num_classes,
                            num_true=1,
                            sampled_values=None,
                            subtract_log_q=True,
                            remove_accidental_hits=False,
                            partition_strategy="mod",
                            name=None):
  if not isinstance(weights, list):
    weights = [weights]

  with ops.op_scope(weights + [biases, inputs, labels], name,
                    "compute_sampled_logits"):
    if labels.dtype != dtypes.int64:
      labels = math_ops.cast(labels, dtypes.int64)
    labels_flat = array_ops.reshape(labels, [-1])

    # Sample the negative labels.
    #   sampled shape: [num_sampled] tensor
    #   true_expected_count shape = [batch_size, 1] tensor
    #   sampled_expected_count shape = [num_sampled] tensor
    if sampled_values is None:
      sampled_values = candidate_sampling_ops.log_uniform_candidate_sampler(
          true_classes=labels,
          num_true=num_true,
          num_sampled=num_sampled,
          unique=True,
          range_max=num_classes)

NOTE:这个函数是通过log-uniform进行取样的P(class)=(log(class+2)−log(class+1))/log(rangmax+1)P(class)=(log⁡(class+2)−log⁡(class+1))/log⁡(rangmax+1)P(class)=(\log(class+2)-\log(class+1))/\log(rang_max+1),取样范围是0, range_max ,用这种方法取样就要求我们的word是按照频率从高到低排列的。之前对word的处理的确是这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # NOTE: pylint cannot tell that 'sampled_values' is a sequence
    # pylint: disable=unpacking-non-sequence
    sampled, true_expected_count, sampled_expected_count = sampled_values
    # pylint: enable=unpacking-non-sequence

    # labels_flat is a [batch_size * num_true] tensor
    # sampled is a [num_sampled] int tensor
    all_ids = array_ops.concat(0, [labels_flat, sampled])

    # weights shape is [num_classes, dim]
    all_w = embedding_ops.embedding_lookup(
        weights, all_ids, partition_strategy=partition_strategy)
    all_b = embedding_ops.embedding_lookup(biases, all_ids)
    # true_w shape is [batch_size * num_true, dim]
    # true_b is a [batch_size * num_true] tensor
    true_w = array_ops.slice(
        all_w, [0, 0], array_ops.pack([array_ops.shape(labels_flat)[0], -1]))
    true_b = array_ops.slice(all_b, [0], array_ops.shape(labels_flat))

    # inputs shape is [batch_size, dim]
    # true_w shape is [batch_size * num_true, dim]
    # row_wise_dots is [batch_size, num_true, dim]
    dim = array_ops.shape(true_w)[1:2]
    new_true_w_shape = array_ops.concat(0, [[-1, num_true], dim])
    row_wise_dots = math_ops.mul(
        array_ops.expand_dims(inputs, 1),
        array_ops.reshape(true_w, new_true_w_shape))
    # We want the row-wise dot plus biases which yields a
    # [batch_size, num_true] tensor of true_logits.
    dots_as_matrix = array_ops.reshape(row_wise_dots,
                                       array_ops.concat(0, [[-1], dim]))
    true_logits = array_ops.reshape(_sum_rows(dots_as_matrix), [-1, num_true])
    true_b = array_ops.reshape(true_b, [-1, num_true])
    true_logits += true_b

    # Lookup weights and biases for sampled labels.
    #   sampled_w shape is [num_sampled, dim]
    #   sampled_b is a [num_sampled] float tensor
    sampled_w = array_ops.slice(
        all_w, array_ops.pack([array_ops.shape(labels_flat)[0], 0]), [-1, -1])
    sampled_b = array_ops.slice(all_b, array_ops.shape(labels_flat), [-1])

    # inputs has shape [batch_size, dim]
    # sampled_w has shape [num_sampled, dim]
    # sampled_b has shape [num_sampled]
    # Apply X*W'+B, which yields [batch_size, num_sampled]
    sampled_logits = math_ops.matmul(
        inputs, sampled_w, transpose_b=True) + sampled_b

    if remove_accidental_hits:
      acc_hits = candidate_sampling_ops.compute_accidental_hits(
          labels, sampled, num_true=num_true)
      acc_indices, acc_ids, acc_weights = acc_hits

      # This is how SparseToDense expects the indices.
      acc_indices_2d = array_ops.reshape(acc_indices, [-1, 1])
      acc_ids_2d_int32 = array_ops.reshape(
          math_ops.cast(acc_ids, dtypes.int32), [-1, 1])
      sparse_indices = array_ops.concat(1, [acc_indices_2d, acc_ids_2d_int32],
                                        "sparse_indices")
      # Create sampled_logits_shape = [batch_size, num_sampled]
      sampled_logits_shape = array_ops.concat(
          0,
          [array_ops.shape(labels)[:1], array_ops.expand_dims(num_sampled, 0)])
      if sampled_logits.dtype != acc_weights.dtype:
        acc_weights = math_ops.cast(acc_weights, sampled_logits.dtype)
      sampled_logits += sparse_ops.sparse_to_dense(
          sparse_indices,
          sampled_logits_shape,
          acc_weights,
          default_value=0.0,
          validate_indices=False)

    if subtract_log_q:
      # Subtract log of Q(l), prior probability that l appears in sampled.
      true_logits -= math_ops.log(true_expected_count)
      sampled_logits -= math_ops.log(sampled_expected_count)

    # Construct output logits and labels. The true labels/logits start at col 0.
    out_logits = array_ops.concat(1, [true_logits, sampled_logits])
    # true_logits is a float tensor, ones_like(true_logits) is a float tensor
    # of ones. We then divide by num_true to ensure the per-example labels sum
    # to 1.0, i.e. form a proper probability distribution.
    out_labels = array_ops.concat(1,
                                  [array_ops.ones_like(true_logits) / num_true,
                                   array_ops.zeros_like(sampled_logits)])

  return out_logits, out_labels
  """
  代码很长,但是我们主要关心的是返回的out_logits和out_labels是什么样子的,想搞清楚到底是怎么样用神经网络对概率分布进行建模。
  """

最终输出的logits是这样的,假设(uicontext(w)ui∈context(w)u_i \in context(w), nicontext(w)ni∉context(w)n_i \notin context(w)) batch_size, 1+num_sampled

|_xTwθu_0xwTθu0x_w^T\theta^{u_0}| _xTwθn_0xwTθn0x_w^T\theta^{n_0}|_xTwθn_1xwTθn1x_w^T\theta^{n_1}|_xTwθn_2xwTθn2x_w^T\theta^{n_2}|_xTwθn_3xwTθn3x_w^T\theta^{n_3}|…|

|_xTwθu_1xwTθu1x_w^T\theta^{u_1}| _xTwθn_0xwTθn0x_w^T\theta^{n_0}|_xTwθn_1xwTθn1x_w^T\theta^{n_1}|_xTwθn_2xwTθn2x_w^T\theta^{n_2}|_xTwθn_3xwTθn3x_w^T\theta^{n_3}|…|

|_xTwθu_2xwTθu2x_w^T\theta^{u_2}| _xTwθn_0xwTθn0x_w^T\theta^{n_0}|_xTwθn_1xwTθn1x_w^T\theta^{n_1}|_xTwθn_2xwTθn2x_w^T\theta^{n_2}|_xTwθn_3xwTθn3x_w^T\theta^{n_3}|…|

是输出的out_labels是这样的 batch_size, 1+num_sampled

|1 |0 |0 |0 |0 |…|

|1 |0 |0 |0 |0 |…|

|1 |0 |0 |0 |0 |…|

word2vec的数学原理中告诉我们的是,要求logits的最大似然。就相当与最小化out_labels与logits的损失函数。

之后将输出的logits和out_labels输入到sampled_losses = sigmoid_cross_entropy_with_logits(

代码语言:txt
AI代码解释
复制
   logits, labels, name=”sampled\_losses”)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def sigmoid_cross_entropy_with_logits(logits, targets, name=None):
  with ops.name_scope(name, "logistic_loss", [logits, targets]) as name:
    logits = ops.convert_to_tensor(logits, name="logits")
    targets = ops.convert_to_tensor(targets, name="targets")
    try:
      targets.get_shape().merge_with(logits.get_shape())
    except ValueError:
      raise ValueError("logits and targets must have the same shape (%s vs %s)"
                       % (logits.get_shape(), targets.get_shape()))

    # The logistic loss formula from above is
    #   x - x * z + log(1 + exp(-x))
    # For x < 0, a more numerically stable formula is
    #   -x * z + log(1 + exp(x))
    # Note that these two expressions can be combined into the following:
    #   max(x, 0) - x * z + log(1 + exp(-abs(x)))
    # To allow computing gradients at zero, we define custom versions of max and
    # abs functions.
    zeros = array_ops.zeros_like(logits, dtype=logits.dtype)
    cond = (logits >= zeros)
    relu_logits = math_ops.select(cond, logits, zeros)
    neg_abs_logits = math_ops.select(cond, -logits, logits)
    return math_ops.add(relu_logits - logits * targets,
                        math_ops.log(1 + math_ops.exp(neg_abs_logits)),
                        name=name)

此函数返回的tensor与输入logits同维度。 _sum_rows之后,就得到了每个样本的corss entropy。

水平有限,如有问题,请指正

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年10月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
谷歌医疗AI又有新进展:转移性乳腺癌检测准确率达99%
在最新公布的进展中,Google深度学习算法在转移性乳腺癌的检测精度测试中,准确率达到了99.3%。
量子位
2018/10/26
6590
ANHIR2019——自动非刚性组织学图像配准之AI形变场配准方法
在数字病理学中,最简单但最有用的功能之一是直观地比较连续的组织切片(切片),这需要将图像对齐。需要图像对齐的其他相关应用包括3D重建、图像融合等。图像对齐使病理学家能够评估患者在单个区域中的多个标记物的组织学和表达。此外,由于组织处理和预分析步骤,切片可能会遭受非线性变形。也就是说,它们会在各个部分之间拉伸并改变形状。目前,只有少数自动对齐工具能够以足够的精度和合理的处理时间处理大图像。
医学处理分析专家
2024/04/02
3220
ANHIR2019——自动非刚性组织学图像配准之AI形变场配准方法
SICAP2020——组织学前列腺自动格里森分级
今天将分享组织学前列腺自动格里森分级完整实现版本,为了方便大家学习理解整个流程,将整个流程步骤进行了整理,并给出详细的步骤结果。感兴趣的朋友赶紧动手试一试吧。
医学处理分析专家
2024/03/21
2320
SICAP2020——组织学前列腺自动格里森分级
ANHIR2019——自动非刚性组织学图像配准之传统非刚性配准方法
在数字病理学中,最简单但最有用的功能之一是直观地比较连续的组织切片(切片),这需要将图像对齐。需要图像对齐的其他相关应用包括3D重建、图像融合等。图像对齐使病理学家能够评估患者在单个区域中的多个标记物的组织学和表达。此外,由于组织处理和预分析步骤,切片可能会遭受非线性变形。也就是说,它们会在各个部分之间拉伸并改变形状。目前,只有少数自动对齐工具能够以足够的精度和合理的处理时间处理大图像。
医学处理分析专家
2024/04/02
3170
ANHIR2019——自动非刚性组织学图像配准之传统非刚性配准方法
Nat. Commun. | 无需人工标注,自动识别结肠癌预后的组织学特征
今天为大家介绍的是来自纽约大学Aristotelis Tsirigos团队的一篇论文。自监督学习(SSL)可以自动从未标注的苏木精-伊红染色的全扫描切片(WSIs)中提取和解释病理组织学特征。我们在来自癌症基因组图谱的435个结肠腺癌WSI上训练了一个SSL Barlow Twins编码器,用于从小型图像块中提取特征。利用Leiden社区检测方法将这些特征分组为组织形态学表型簇(histomorphological phenotype clusters,HPCs)。一项独立的临床试验(N = 1213 WSIs)确认了HPC的可重复性和对总体生存率的预测能力。这种无偏的图谱有47个HPCs,展示出独特且共享的临床显著组织形态学特征,突出了组织类型、数量和结构,特别是在肿瘤基质的背景下。通过对这些HPCs的深入分析,包括免疫景观和基因集富集分析,以及与临床结果的关联,作者阐明了影响生存和对标准辅助化疗和实验治疗反应的因素。对HPCs的进一步探索可能会揭示额外的见解,并有助于结肠癌患者的决策和个性化治疗。
DrugAI
2025/04/26
1080
Nat. Commun. | 无需人工标注,自动识别结肠癌预后的组织学特征
Nature Medicine | 基于群体学习的分散式人工智能在癌症组织病理学中的应用
本文介绍由英国利兹大学圣詹姆斯医学研究所、德国国家肿瘤疾病中心的Jakob Nikolas Kather住院医师团队发表在Nature Medicine的研究成果。作者展示了群体学习(SL)在5000多名患者的千兆像素组织病理学图像的大型多中心数据集中上的成功应用。作者表明,使用SL训练的人工智能(AI)模型可以直接从结直肠癌H&E染色的病理切片上预测BRAF突变状态和微卫星不稳定性。作者在北爱尔兰、德国和美国三类患者人群中训练AI模型,并在来自英国的两个独立数据集中验证了预测性能。数据显示,经过SL训练的AI模型优于大多数本地训练的模型,并与在合并数据集上训练的模型表现相同。此外,作者展示了基于SL的AI模型是数据高效的。未来,SL可用于训练分布式AI模型,用于任何组织病理学图像分析任务,从而无需数据传输。
DrugAI
2022/06/10
7940
Nature Medicine | 基于群体学习的分散式人工智能在癌症组织病理学中的应用
AI Lab医疗AI又一成功探索——深度学习助力靶向疗法相关基因预测
| 导语   近期腾讯AI Lab医疗AI中心和南方医院合作发表一项基于病理图片预测微卫星不稳定性的可解释深度学习模型研究成果,助力分子病理和精准医疗的研究。 微卫星不稳定性(Microsatellite instability,MSI)是一种基因组不稳定的表型,发生在DNA错配修复缺陷(dMMR)的肿瘤中,据报道是遗传性林奇综合征(LS)相关癌症的标志。MSI已被确定为II期结直肠癌(CRC)辅助化疗的有利预后因素。更重要的是,最近的研究表明,MSI或dMMR与增加的新生抗原(Neoantigen)
腾讯大讲堂
2020/10/14
1.3K0
Nat. Biomed. Eng. | 多模态人工智能系统助力乳腺癌精准诊断
今天为大家介绍的是来自上海科技大学,上海联影智能,安徽医科大学附属第一医院的一篇论文。乳腺癌机器学习诊断模型可以帮助预测癌症风险并指导后续的患者管理等临床任务。为了使这些模型能够对临床实践产生影响,它们需要遵循标准工作流程,协助解读乳腺X光和超声数据,评估临床上下文信息,处理不完整数据,并在前瞻性环境中得到验证。本文报告了一个多模态模型的开发和测试,该模型利用乳腺X光和超声模块,基于来自多个医疗中心和不同扫描仪制造商的5,025名患者(5,216个乳房的19,360张图像,包括临床元数据、乳腺X线摄影和三模态超声)的手术病理确诊数据,对乳腺癌风险进行分层。与经验丰富的放射科医生相比,该模型在良恶性肿瘤分类方面表现相当,在病理水平的鉴别诊断方面表现更优。在一个前瞻性收集的187名患者191个乳房的数据集中,多模态模型与病理学家对活检乳房标本的初步评估的总体准确率相近(分别为90.1%和92.7%)。多模态模型可能有助于肿瘤学诊断。
DrugAI
2024/12/30
3460
Nat. Biomed. Eng. | 多模态人工智能系统助力乳腺癌精准诊断
LEOPARD2024——从组织病理学切片中学习前列腺癌生化复发 (LEOPARD) 挑战赛
前列腺癌是一种常见的恶性肿瘤,每年影响 140 万男性。这些患者中有相当一部分接受前列腺切除术作为主要治愈性治疗。该手术的疗效部分通过监测血液中的前列腺特异性抗原 (PSA) 浓度来评估。虽然 PSA 在前列腺癌筛查中的作用尚有争议,但它是患者前列腺切除术后随访的宝贵生物标志物。手术成功后,PSA 浓度通常在 4-6 周内检测不到(<0.1 ng/mL)。然而,大约 30% 的患者会出现生化复发,这意味着前列腺癌细胞复发。这种复发可作为临床转移进展和最终前列腺癌相关死亡的预后指标。
医学处理分析专家
2024/06/05
1910
LEOPARD2024——从组织病理学切片中学习前列腺癌生化复发 (LEOPARD) 挑战赛
9+!通过深度学习从结直肠癌的组织学中预测淋巴结状态
近几年深度学习一直是研究热点,今天小编为大家带来的这篇文章,研究了通过深度学习模型从常规组织学切片和临床数据中提取的图像特征是否可用于预测 CRC 淋巴结转移 (LNM)。文章发表在《European Journal of Cancer》上,影响因子为9.162,文章题目为Deep learning can predict lymph node status directly from histology in colorectal cancer。
作图丫
2022/06/24
3180
9+!通过深度学习从结直肠癌的组织学中预测淋巴结状态
Nat Rev Cancer|人工智能在癌症研究、诊断和治疗中的应用
2021年9月17日,Nature Reviews Cancer杂志发表文章,介绍了4位专家对于AI在癌症的研究、诊断和治疗中使用的相关问题的观点。
智药邦
2021/11/26
7080
人工智能 | Nature | 针对精准肿瘤学的视觉-语言基础模型
◉ 我们开发了一个基于多模态变压器架构的视觉-语言基础模型作为网络主干。◉ 模型预训练包括两个连续阶段。◉ 首先,MUSK 在来自 11,577 名患者的近 33,000 张全切片组织病理学扫描图像和一亿个与病理相关的文本标记上进行了预训练。◉ 这些图像是代表 33 种肿瘤类型的图像。◉ MUSK 模型改编自 BEiT3(参考文献 21)架构,包含共享的自注意力块和用于视觉和语言输入的两个独立专家;使用掩码建模实现了预训练。◉ 其次,MUSK 使用对比学习对来自模型 QUILT-1M 的一百万张图像-文本对进行了多模态对齐预训练。◉ 通用临床应用。◉ 一旦预训练完成,MUSK 可以用于各种下游任务,并且只需要少量或不需要进一步的训练。◉ 重要的是,我们使用全切片图像和临床报告评估了 MUSK 的预测能力,包括复发、预后和免疫治疗反应预测。◉ MUSK 在视觉-语言基础模型方面显著优于最先进的模型,包括 PLIP15、QUILT-1M46、BiomedCLIP47 和 CONCH16。◉ b 图中的插图、黑色素瘤、预后、肺癌和胃食管癌是使用 BioRender 制作的(https://biorender.com)。
生信菜鸟团
2025/02/27
2330
人工智能 | Nature | 针对精准肿瘤学的视觉-语言基础模型
癌症免疫研究的技术进步:从免疫基因组学到单细胞分析和人工智能
肿瘤细胞与附近的细胞一起存在于复杂的细胞群落中,这强烈影响肿瘤细胞的生长、行为和与其他细胞的交流。在这些细胞中,免疫细胞是关键的参与者,许多研究证明肿瘤细胞和免疫细胞之间的交流是双向的。事实上,免疫细胞既能促进也能抑制癌变、肿瘤进展、转移和复发。因此,文章主要关注肿瘤免疫微环境(TIME)。
生信技能树jimmy
2022/03/14
1.2K0
癌症免疫研究的技术进步:从免疫基因组学到单细胞分析和人工智能
放射学中基于影像组学和人工智能预测癌症预后
人工智能(AI)在医学影像诊断中的成功应用使得基于人工智能的癌症成像分析技术开始应用于解决其他更复杂的临床需求。从这个角度出发,我们讨论了基于人工智能利用影像图像解决临床问题的新挑战,如预测多种癌症的预后、预测对各种治疗方式的反应、区分良性治疗混杂因素与进展,肿瘤异常反应的识别以及突变和分子特征的预测等。我们综述了人工智能技术在肿瘤成像中的发展和机遇,重点介绍了基于人工的影像组学方法和基于深度学习的方法,并举例说明了它们在决策支持中的应用。我们还解决了临床应用过程中面临的挑战,包括数据整理和标注、可解释性以及市场监管和报销问题。我们希望通过帮助临床医生理解人工智能的局限性和挑战,以及它作为癌症临床决策支持工具所能提供的机会,为他们揭开影像组学人工智能的神秘面纱。
用户1279583
2022/02/28
1.5K0
放射学中基于影像组学和人工智能预测癌症预后
Nature子刊:用于阿尔茨海默病痴呆评估的多模态深度学习模型
在全球范围内,每年有近1000万新发痴呆病例,其中阿尔茨海默病(AD)最为常见。需要新的措施来改善对各种病因导致认知障碍的个体的诊断。作者报告了一个深度学习框架,该框架以连续方式完成多个诊断步骤,以识别具有正常认知(NC)、轻度认知障碍(MCI)、AD和非AD痴呆(nADD)的人。作者展示了一系列能够接受常规收集的临床信息的灵活组合的模型,包括人口统计、病史、神经心理学测试、神经影像学和功能评估。然后,作者表明这些框架与执业神经科医生和神经放射科医生的诊断准确性相比具有优势。最后,作者在计算机视觉中应用可解释性方法,以表明模型检测到的疾病特异性模式可以跟踪整个大脑的退行性变化的不同模式,并与尸检时神经病理学病变的存在密切相关。作者的工作证明了使用既定的医学诊断标准验证计算预测的方法。
悦影科技
2022/11/07
2.5K0
热点综述 | Nature Methods:利用空间组学和多路成像技术探索癌症生物学
了解肿瘤异质性——肿瘤内细胞间的分子变异——有望解决癌症生物学中的突出问题,并改善特定癌症亚型的诊断和治疗。近日,来自澳大利亚的科研团队在《Nature Methods》发表综述文章,总结了空间技术在肿瘤研究中的应用,并讨论了目前的方法和未来的机会,以计算整合这些模式实现对肿瘤生物学的综合评估。
尐尐呅
2021/08/31
1.5K0
热点综述 | Nature Methods:利用空间组学和多路成像技术探索癌症生物学
npj | digital medicine:可解释性人工智能构建AD患者结构性脑畸变的个性化特征
摘要:基于磁共振成像(MRI)数据的深度学习在神经系统疾病诊断与预后中潜力巨大,但临床应用受限,因其模型不透明。本研究通过训练卷积神经网络(CNN)区分痴呆患者与健康对照,并利用分层相关性传播(LRP)提供个体层面的解释,克服了这一挑战。验证表明,模型识别与痴呆结构性脑畸变知识相符。在轻度认知障碍(MCI)数据集中,可解释的痴呆分类器预测向痴呆过渡,其空间丰富的解释补充了模型预测,并表征了个体大脑疾病表现。我们构建了形态学记录,可视化痴呆病理学数量和位置,跟踪疾病进展。形态学记录不仅验证了相关性图的有效性,还揭示了其在患者分层和疾病进展预测中的临床效用,为精准医学提供了有力支持。
悦影科技
2024/11/12
1970
BRAIN:用于阿尔茨海默病分类的可解释深度学习框架的开发和验证
阿尔茨海默症是全世界痴呆症的主要病因,随着人口老龄化,患病负担不断增加,在未来可能会超出社会的诊断和管理能力。目前的诊断方法结合患者病史、神经心理学检测和MRI来识别可能的病例,然而有效的做法仍然应用不一,缺乏敏感性和特异性。在这里,本文报告了一种可解释的深度学习策略,该策略从MRI、年龄、性别和简易智力状况检查量表(mini-mental state examination ,MMSE) 得分等多模式输入中描绘出独特的阿尔茨海默病特征(signatures)。该框架连接了一个完全卷积网络,该网络从局部大脑结构到多层感知器构建了疾病概率的高分辨率图,并对个体阿尔茨海默病风险进行了精确、直观的可视化,以达到准确诊断的目的。该模型使用临床诊断的阿尔茨海默病患者和认知正常的受试者进行训练,这些受试者来自阿尔茨海默病神经影像学倡议(ADNI)数据集(n = 417),并在三个独立的数据集上进行验证:澳大利亚老龄化影像、生物标志物和生活方式研究(AIBL)(n = 382)、弗雷明汉心脏研究(FHS)(n = 102)和国家阿尔茨海默病协调中心(NACC)(n = 582)。使用多模态输入的模型的性能在各数据集中是一致的,ADNI研究、AIBL、FHS研究和NACC数据集的平均曲线下面积值分别为0.996、0.974、0.876和0.954。此外,本文的方法超过了多机构执业神经科医生团队(n = 11)的诊断性能,通过密切跟踪死后组织病理学的损伤脑组织验证了模型和医生团队的预测结果。该框架提供了一种可适应临床的策略,用于使用常规可用的成像技术(如MRI)来生成用于阿尔茨海默病诊断的细微神经成像特征;以及将深度学习与人类疾病的病理生理过程联系起来的通用方法。本研究发表在BRAIN杂志。
用户1279583
2020/07/15
2K0
BRAIN:用于阿尔茨海默病分类的可解释深度学习框架的开发和验证
【他山之石】CVPR 2024 | 知识感知注意力!用于组织病理学全幻灯片图像分析!
“他山之石,可以攻玉”,站在巨人的肩膀才能看得更高,走得更远。在科研的道路上,更需借助东风才能更快前行。为此,我们特别搜集整理了一些实用的代码链接,数据集,软件,编程技巧等,开辟“他山之石”专栏,助你乘风破浪,一路奋勇向前,敬请关注!
马上科普尚尚
2024/05/14
5730
【他山之石】CVPR 2024 | 知识感知注意力!用于组织病理学全幻灯片图像分析!
提供超全面代码,看看顶刊 Nat Med 是如何用单细胞和空间转录组研究癌症的
生信菜鸟团
2024/11/28
1730
提供超全面代码,看看顶刊 Nat Med 是如何用单细胞和空间转录组研究癌症的
推荐阅读
谷歌医疗AI又有新进展:转移性乳腺癌检测准确率达99%
6590
ANHIR2019——自动非刚性组织学图像配准之AI形变场配准方法
3220
SICAP2020——组织学前列腺自动格里森分级
2320
ANHIR2019——自动非刚性组织学图像配准之传统非刚性配准方法
3170
Nat. Commun. | 无需人工标注,自动识别结肠癌预后的组织学特征
1080
Nature Medicine | 基于群体学习的分散式人工智能在癌症组织病理学中的应用
7940
AI Lab医疗AI又一成功探索——深度学习助力靶向疗法相关基因预测
1.3K0
Nat. Biomed. Eng. | 多模态人工智能系统助力乳腺癌精准诊断
3460
LEOPARD2024——从组织病理学切片中学习前列腺癌生化复发 (LEOPARD) 挑战赛
1910
9+!通过深度学习从结直肠癌的组织学中预测淋巴结状态
3180
Nat Rev Cancer|人工智能在癌症研究、诊断和治疗中的应用
7080
人工智能 | Nature | 针对精准肿瘤学的视觉-语言基础模型
2330
癌症免疫研究的技术进步:从免疫基因组学到单细胞分析和人工智能
1.2K0
放射学中基于影像组学和人工智能预测癌症预后
1.5K0
Nature子刊:用于阿尔茨海默病痴呆评估的多模态深度学习模型
2.5K0
热点综述 | Nature Methods:利用空间组学和多路成像技术探索癌症生物学
1.5K0
npj | digital medicine:可解释性人工智能构建AD患者结构性脑畸变的个性化特征
1970
BRAIN:用于阿尔茨海默病分类的可解释深度学习框架的开发和验证
2K0
【他山之石】CVPR 2024 | 知识感知注意力!用于组织病理学全幻灯片图像分析!
5730
提供超全面代码,看看顶刊 Nat Med 是如何用单细胞和空间转录组研究癌症的
1730
相关推荐
谷歌医疗AI又有新进展:转移性乳腺癌检测准确率达99%
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验