tf.cond()函数

部署运行你感兴趣的模型镜像

tf.cond()函数
tf.add_to_collection与tf.get_collection函数
tf.train.ExponentialMovingAverage
tf.identity()与tf.control_dependencies()
tf.assign(ref, value, validate_shape=None, use_locking=None, name=None)

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.15

TensorFlow-v2.15

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

“from flask import Flask, render_template, request, jsonify, send_file import tensorflow as tf import cv2 import math import numpy as np import os import tempfile from typing import Tuple, Dict, List from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas import matplotlib.pyplot as plt # ----------------------------------------------------------------------------- # 1. 基础配置(设备自动检测、临时文件路径) # ----------------------------------------------------------------------------- app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 最大上传大小50MB UPLOAD_FOLDER = tempfile.mkdtemp() # 临时文件存储目录(自动清理) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER # 自动检测GPU/CPU def get_available_device() -> str: return "/GPU:0" if tf.config.list_physical_devices("GPU") else "/CPU:0" DEVICE = get_available_device() print(f"使用计算设备: {DEVICE}") # ----------------------------------------------------------------------------- # 2. FSIM配置类(参数集中管理) # ----------------------------------------------------------------------------- class FSIMConfig: def __init__( self, win_size: int = 11, sigma: float = 1.5, alpha: float = 0.84, beta: float = 0.16, target_size: Tuple[int, int] = (512, 512), nscale: int = 4, norient: int = 4, min_wave_length: int = 6, mult: float = 2.0, sigma_onf: float = 0.55, d_theta_on_sigma: float = 1.2 ): if win_size % 2 == 0: raise ValueError("窗口大小必须为奇数") self.win_size = win_size self.sigma = sigma self.alpha = alpha self.beta = beta self.target_size = target_size self.nscale = nscale self.norient = norient self.min_wave_length = min_wave_length self.mult = mult self.sigma_onf = sigma_onf self.d_theta_on_sigma = d_theta_on_sigma self.half_win = win_size // 2 self.epsilon = tf.constant(1e-8, dtype=tf.float32) # 全局配置实例 config = FSIMConfig() # ----------------------------------------------------------------------------- # 3. 核心工具函数(图像预处理、特征提取、FSIM计算) # ----------------------------------------------------------------------------- def preprocess_image(img_path: str) -> tf.Tensor: """单张图像预处理:读取→RGB→Resize→归一化""" img = cv2.imread(img_path) if img is None: raise ValueError(f"图像读取失败: {img_path}") img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) target_h, target_w = config.target_size h, w = img.shape[:2] # 保持比例Resize scale = min(target_w / w, target_h / h) new_w, new_h = int(w * scale), int(h * scale) img_resized = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_CUBIC) # 补黑边 pad_left = (target_w - new_w) // 2 pad_right = target_w - new_w - pad_left pad_top = (target_h - new_h) // 2 pad_bottom = target_h - new_h - pad_top img_padded = cv2.copyMakeBorder( img_resized, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=(0, 0, 0) ) return tf.cast(img_padded, tf.float32) / 255.0 def lowpassfilter(sze: Tuple[int, int], cutoff: float, n: int) -> tf.Tensor: """生成频域低通滤波器""" rows, cols = sze x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols) y_range = tf.range(-(rows-1)//2, (rows//2)+1, dtype=tf.float32) / (rows-1 if rows%2 else rows) x_grid, y_grid = tf.meshgrid(x_range, y_range) radius = tf.sqrt(x_grid**2 + y_grid**2) filter_val = 1.0 / (1.0 + (radius / cutoff) ** (2 * n)) return tf.signal.ifftshift(filter_val) def phasecong2(img: tf.Tensor) -> tf.Tensor: """单张图像相位一致性计算""" H, W = tf.shape(img)[0], tf.shape(img)[1] img_fft = tf.signal.fft2d(tf.cast(img, tf.complex128)) # 频域网格 x_range = tf.range(-(W-1)//2, (W//2)+1, dtype=tf.float32) / (W-1 if W%2 else W) y_range = tf.range(-(H-1)//2, (H//2)+1, dtype=tf.float32) / (H-1 if H%2 else H) x_grid, y_grid = tf.meshgrid(x_range, y_range) radius = tf.sqrt(x_grid**2 + y_grid**2) theta = tf.math.atan2(-y_grid, x_grid) radius = tf.signal.ifftshift(radius) theta = tf.signal.ifftshift(theta) radius = tf.where(radius == 0, 1.0, radius) sintheta = tf.math.sin(theta) costheta = tf.math.cos(theta) # 全局低通滤波 lp = lowpassfilter((H, W), 0.45, 15) lp = tf.cast(lp, tf.float32) # 多尺度对数Gabor log_gabor_list = [] for s in range(config.nscale): wavelength = config.min_wave_length * (config.mult ** s) fo = 1.0 / wavelength log_gabor = tf.exp(-(tf.math.log(radius / fo)) ** 2 / (2 * (tf.math.log(config.sigma_onf)) ** 2)) log_gabor *= lp log_gabor = tf.where(radius == 1, 0.0, log_gabor) log_gabor_list.append(log_gabor) # 多方向扩散 theta_sigma = math.pi / config.norient / config.d_theta_on_sigma spread_list = [] for o in range(config.norient): angl = tf.cast(o * math.pi / config.norient, tf.float32) ds = sintheta * tf.math.cos(angl) - costheta * tf.math.sin(angl) dc = costheta * tf.math.cos(angl) + sintheta * tf.math.sin(angl) dtheta = tf.abs(tf.math.atan2(ds, dc)) spread = tf.exp(-dtheta ** 2 / (2 * theta_sigma ** 2)) spread_list.append(spread) # 相位一致性计算 energy_all = tf.zeros((H, W), dtype=tf.float32) an_all = tf.zeros((H, W), dtype=tf.float32) for o in range(config.norient): spread = spread_list[o] sum_e = tf.zeros((H, W), dtype=tf.float32) sum_o = tf.zeros((H, W), dtype=tf.float32) sum_an = tf.zeros((H, W), dtype=tf.float32) energy = tf.zeros((H, W), dtype=tf.float32) ifft_filters = [] for s in range(config.nscale): log_gabor = log_gabor_list[s] filter_freq = log_gabor * spread ifft_filt = tf.math.real(tf.signal.ifft2d(tf.cast(filter_freq, tf.complex128))) ifft_filt *= tf.math.sqrt(tf.cast(H * W, tf.float32)) ifft_filters.append(ifft_filt) eo = tf.signal.ifft2d(img_fft * tf.cast(filter_freq, tf.complex128)) an = tf.abs(eo) sum_an += an sum_e += tf.math.real(eo) sum_o += tf.math.imag(eo) # 主相位归一化 x_energy = tf.sqrt(sum_e ** 2 + sum_o ** 2 + config.epsilon) mean_e = sum_e / x_energy mean_o = sum_o / x_energy # 能量计算 for s in range(config.nscale): log_gabor = log_gabor_list[s] filter_freq = log_gabor * spread eo = tf.signal.ifft2d(img_fft * tf.cast(filter_freq, tf.complex128)) e = tf.math.real(eo) o = tf.math.imag(eo) energy += e * mean_e + o * mean_o - tf.abs(e * mean_o - o * mean_e) # 噪声过滤 log_gabor0 = log_gabor_list[0] filter0_freq = log_gabor0 * spread eo0 = tf.signal.ifft2d(img_fft * tf.cast(filter0_freq, tf.complex128)) an0 = tf.abs(eo0) median_e2n = tf.math.reduce_median(tf.reshape(an0**2, (-1,))) mean_e2n = -median_e2n / math.log(0.5) em_n = tf.reduce_sum((log_gabor0 * spread) ** 2) noise_power = mean_e2n / em_n est_sum_an2 = tf.reduce_sum(tf.stack([f**2 for f in ifft_filters], axis=0), axis=0) est_sum_ai_aj = tf.zeros((H, W), dtype=tf.float32) for si in range(config.nscale): for sj in range(si+1, config.nscale): est_sum_ai_aj += ifft_filters[si] * ifft_filters[sj] est_noise_energy2 = 2 * noise_power * est_sum_an2 + 4 * noise_power * est_sum_ai_aj tau = tf.math.sqrt(est_noise_energy2 / 2) est_noise_energy = tau * tf.math.sqrt(tf.cast(math.pi / 2, tf.float32)) t = est_noise_energy + 2.0 * tf.math.sqrt((2 - math.pi/2) * tau ** 2) t /= 1.7 energy = tf.maximum(energy - t, 0.0) energy_all += energy an_all += sum_an pc = energy_all / (an_all + config.epsilon) return tf.clip_by_value(pc, 0.0, 1.0) def extract_features(img: tf.Tensor) -> Dict[str, tf.Tensor]: """提取单张图像特征(PC+梯度+色度)""" H, W = tf.shape(img)[0], tf.shape(img)[1] r, g, b = img[..., 0], img[..., 1], img[..., 2] # RGB→YIQ y = 0.299 * r + 0.587 * g + 0.114 * b i = 0.596 * r - 0.274 * g - 0.322 * b q = 0.211 * r - 0.523 * g + 0.312 * b # 下采样参数 min_dim = tf.minimum(H, W) f = tf.maximum(1, tf.cast(tf.round(min_dim / 256), tf.int32)) win_size = f ave_kernel = tf.ones((win_size, win_size, 1, 1), dtype=tf.float32) / (win_size ** 2) # 下采样函数 def downsample(channel: tf.Tensor) -> tf.Tensor: channel = tf.expand_dims(channel, axis=-1) filtered = tf.nn.conv2d(channel, ave_kernel, strides=[1,1,1,1], padding='SAME') return filtered[:, ::f, ::f, 0] y_down = downsample(y) i_down = downsample(i) q_down = downsample(q) # 相位一致性 pc_y = phasecong2(y_down) # 梯度计算 dx = tf.constant([[3, 0, -3], [10, 0, -10], [3, 0, -3]], dtype=tf.float32) / 16 dy = tf.constant([[3, 10, 3], [0, 0, 0], [-3, -10, -3]], dtype=tf.float32) / 16 dx_kernel = tf.reshape(dx, (3, 3, 1, 1)) dy_kernel = tf.reshape(dy, (3, 3, 1, 1)) y_down_exp = tf.expand_dims(y_down, axis=-1) ix = tf.nn.conv2d(y_down_exp, dx_kernel, strides=[1,1,1,1], padding='SAME')[..., 0] iy = tf.nn.conv2d(y_down_exp, dy_kernel, strides=[1,1,1,1], padding='SAME')[..., 0] g_y = tf.sqrt(ix**2 + iy**2 + config.epsilon) return { "pc_y": pc_y, "g_y": g_y, "i": i_down, "q": q_down, "y_down": y_down, "img_original": img # 保留原始图像用于可视化 } def calculate_fsim(ref_feats: Dict[str, tf.Tensor], dis_feats: Dict[str, tf.Tensor]) -> float: """计算单组FSIM分数""" pc_ref, g_ref = ref_feats["pc_y"], ref_feats["g_y"] pc_dis, g_dis = dis_feats["pc_y"], dis_feats["g_y"] H, W = tf.shape(pc_ref)[0], tf.shape(pc_ref)[1] # 高斯窗口 half_win = config.half_win x = tf.range(-half_win, half_win + 1, dtype=tf.float32) x_grid, y_grid = tf.meshgrid(x, x) gaussian = tf.exp(-(x_grid**2 + y_grid**2) / (2 * config.sigma**2)) gaussian /= tf.reduce_sum(gaussian) gaussian = tf.reshape(gaussian, (config.win_size, config.win_size, 1)) # 滑动窗口提取 def extract_patches(channel: tf.Tensor) -> tf.Tensor: channel = tf.expand_dims(tf.expand_dims(channel, axis=0), axis=-1) patches = tf.image.extract_patches( images=channel, sizes=[1, config.win_size, config.win_size, 1], strides=[1, 1, 1, 1], rates=[1, 1, 1, 1], padding="SAME" ) return tf.reshape(patches, (H * W, config.win_size, config.win_size, 1)) # 窗口加权 pc_ref_patches = extract_patches(pc_ref) * gaussian pc_dis_patches = extract_patches(pc_dis) * gaussian g_ref_patches = extract_patches(g_ref) * gaussian g_dis_patches = extract_patches(g_dis) * gaussian # 相似度计算 def window_sim(x_patches: tf.Tensor, y_patches: tf.Tensor) -> tf.Tensor: x_mean = tf.reduce_mean(x_patches, axis=[1,2,3], keepdims=True) y_mean = tf.reduce_mean(y_patches, axis=[1,2,3], keepdims=True) cov = tf.reduce_mean((x_patches - x_mean) * (y_patches - y_mean), axis=[1,2,3]) var_x = tf.reduce_mean((x_patches - x_mean) ** 2, axis=[1,2,3]) var_y = tf.reduce_mean((y_patches - y_mean) ** 2, axis=[1,2,3]) sim = cov / (tf.sqrt(var_x * var_y) + config.epsilon) return tf.maximum(sim, 0.0) pc_sim = window_sim(pc_ref_patches, pc_dis_patches) g_sim = window_sim(g_ref_patches, g_dis_patches) # 加权平均 local_weight = (tf.reduce_mean(g_ref_patches, axis=[1,2,3]) + tf.reduce_mean(g_dis_patches, axis=[1,2,3])) / 2 total_sim = tf.reduce_sum(pc_sim * g_sim * local_weight) total_weight = tf.reduce_sum(local_weight) return tf.clip_by_value(total_sim / (total_weight + config.epsilon), 0.0, 1.0).numpy() def calculate_fsimc(ref_feats: Dict[str, tf.Tensor], dis_feats: Dict[str, tf.Tensor]) -> float: """计算单组FSIMc分数""" # FSIM分数 fsim = calculate_fsim(ref_feats, dis_feats) # 色度相似度 i_ref, q_ref = ref_feats["i"], ref_feats["q"] i_dis, q_dis = dis_feats["i"], dis_feats["q"] H, W = tf.shape(i_ref)[0], tf.shape(i_ref)[1] # 高斯窗口 half_win = config.half_win x = tf.range(-half_win, half_win + 1, dtype=tf.float32) x_grid, y_grid = tf.meshgrid(x, x) gaussian = tf.exp(-(x_grid**2 + y_grid**2) / (2 * config.sigma**2)) gaussian /= tf.reduce_sum(gaussian) gaussian = tf.reshape(gaussian, (config.win_size, config.win_size, 1)) # 窗口提取与加权 def chroma_sim(chroma_ref: tf.Tensor, chroma_dis: tf.Tensor) -> float: def extract_patches(channel: tf.Tensor) -> tf.Tensor: channel = tf.expand_dims(tf.expand_dims(channel, axis=0), axis=-1) patches = tf.image.extract_patches( images=channel, sizes=[1, config.win_size, config.win_size, 1], strides=[1, 1, 1, 1], rates=[1, 1, 1, 1], padding="SAME" ) return tf.reshape(patches, (H * W, config.win_size, config.win_size, 1)) ref_patches = extract_patches(chroma_ref) * gaussian dis_patches = extract_patches(chroma_dis) * gaussian # SSIM色度公式 c2 = (0.08) ** 2 ref_mean = tf.reduce_mean(ref_patches, axis=[1,2,3]) dis_mean = tf.reduce_mean(dis_patches, axis=[1,2,3]) cov = tf.reduce_mean((ref_patches - tf.expand_dims(ref_mean, axis=[1,2,3])) * (dis_patches - tf.expand_dims(dis_mean, axis=[1,2,3])), axis=[1,2,3]) var_ref = tf.reduce_mean((ref_patches - tf.expand_dims(ref_mean, axis=[1,2,3])) ** 2, axis=[1,2,3]) var_dis = tf.reduce_mean((dis_patches - tf.expand_dims(dis_mean, axis=[1,2,3])) ** 2, axis=[1,2,3]) numerator = (2 * ref_mean * dis_mean + c2) * (2 * cov + c2) denominator = (ref_mean**2 + dis_mean**2 + c2) * (var_ref + var_dis + c2) sim = numerator / (denominator + config.epsilon) sim = tf.maximum(sim, 0.0) return tf.reduce_mean(sim).numpy() sc_i = chroma_sim(i_ref, i_dis) sc_q = chroma_sim(q_ref, q_dis) sc = (sc_i + sc_q) / 2 # FSIMc分数 fsimc = (fsim ** config.alpha) * (sc ** config.beta) return np.clip(fsimc, 0.0, 1.0) def generate_visualization(ref_feats: Dict[str, tf.Tensor], dis_feats: Dict[str, tf.Tensor], fsim: float, fsimc: float) -> str: """生成可视化图片,返回临时文件路径""" # 转换为NumPy数组 ref_img = tf.cast(ref_feats["img_original"] * 255, tf.uint8).numpy() dis_img = tf.cast(dis_feats["img_original"] * 255, tf.uint8).numpy() pc_ref = ref_feats["pc_y"].numpy() pc_dis = dis_feats["pc_y"].numpy() g_ref = ref_feats["g_y"].numpy() g_dis = dis_feats["g_y"].numpy() # 梯度图归一化 g_ref_norm = (g_ref - g_ref.min()) / (g_ref.max() - g_ref.min() + 1e-8) g_dis_norm = (g_dis - g_dis.min()) / (g_dis.max() - g_dis.min() + 1e-8) grad_diff = g_ref_norm - g_dis_norm # 创建画布 fig, axes = plt.subplots(2, 3, figsize=(18, 12)) fig.suptitle(f"FSIM: {fsim:.4f} | FSIMc: {fsimc:.4f}", fontsize=16, fontweight="bold") # 填充子图 axes[0,0].imshow(ref_img) axes[0,0].set_title("参考图像", fontsize=12) axes[0,0].axis("off") axes[0,1].imshow(dis_img) axes[0,1].set_title("比较图像", fontsize=12) axes[0,1].axis("off") axes[0,2].text(0.5, 0.5, f"FSIM: {fsim:.4f}\nFSIMc: {fsimc:.4f}", ha="center", va="center", fontsize=14, fontweight="bold") axes[0,2].set_title("相似度分数", fontsize=12) axes[0,2].axis("off") im1 = axes[1,0].imshow(pc_ref, cmap="jet") axes[1,0].set_title("参考图相位一致性", fontsize=12) axes[1,0].axis("off") plt.colorbar(im1, ax=axes[1,0], fraction=0.046, pad=0.04) im2 = axes[1,1].imshow(pc_dis, cmap="jet") axes[1,1].set_title("比较图相位一致性", fontsize=12) axes[1,1].axis("off") plt.colorbar(im2, ax=axes[1,1], fraction=0.046, pad=0.04) im3 = axes[1,2].imshow(grad_diff, cmap="coolwarm", vmin=-1, vmax=1) axes[1,2].set_title("梯度差异(参考-比较)", fontsize=12) axes[1,2].axis("off") plt.colorbar(im3, ax=axes[1,2], fraction=0.046, pad=0.04) # 保存到临时文件 temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=app.config['UPLOAD_FOLDER']) canvas = FigureCanvas(fig) canvas.print_png(temp_file) temp_file.close() return temp_file.name # ----------------------------------------------------------------------------- # 4. Flask路由(前端页面+API接口) # ----------------------------------------------------------------------------- @app.route('/') def index(): """主页面:图像上传与结果展示""" return render_template('index.html') @app.route('/upload', methods=['POST']) def upload(): """图像上传与计算接口""" try: # 1. 获取上传文件 if 'reference' not in request.files: return jsonify({"status": "error", "msg": "未上传参考图像"}) ref_file = request.files['reference'] comp_files = request.files.getlist('comparison[]') if not ref_file.filename: return jsonify({"status": "error", "msg": "参考图像文件名不能为空"}) if not comp_files: return jsonify({"status": "error", "msg": "未上传比较图像"}) # 2. 保存临时文件 ref_path = os.path.join(app.config['UPLOAD_FOLDER'], ref_file.filename) ref_file.save(ref_path) comp_paths = [] for file in comp_files: if file.filename: comp_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename) file.save(comp_path) comp_paths.append(comp_path) # 3. 预处理与特征提取 with tf.device(DEVICE): # 参考图处理 ref_img = preprocess_image(ref_path) ref_feats = extract_features(ref_img) # 比较图批量处理 results = [] for comp_path in comp_paths: comp_img = preprocess_image(comp_path) comp_feats = extract_features(comp_img) # 计算分数 fsim = calculate_fsim(ref_feats, comp_feats) fsimc = calculate_fsimc(ref_feats, comp_feats) # 生成可视化图片 vis_path = generate_visualization(ref_feats, comp_feats, fsim, fsimc) vis_filename = os.path.basename(vis_path) results.append({ "filename": os.path.basename(comp_path), "fsim": round(fsim, 4), "fsimc": round(fsimc, 4), "vis_filename": vis_filename }) # 4. 返回结果 return jsonify({ "status": "success", "ref_filename": os.path.basename(ref_path), "results": results }) except Exception as e: return jsonify({"status": "error", "msg": str(e)}) @app.route('/visualization/<filename>') def get_visualization(filename): """获取可视化图片""" vis_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) if os.path.exists(vis_path): return send_file(vis_path, mimetype='image/png') return "图片不存在", 404 # ----------------------------------------------------------------------------- # 5. 启动服务 # ----------------------------------------------------------------------------- if __name__ == '__main__': # 确保临时文件夹存在 if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) # 启动Flask服务(debug=False用于生产环境,True用于开发) app.run(host='0.0.0.0', port=5000, debug=False)” 这段代码使用过程中,提示“`x` and `y` must have the same dtype, got tf.float32 != tf.int32.
最新发布
10-25
<think>我们遇到了一个错误提示:“`x` and `y` must have the same dtype, got tf.float32 != tf.int32.”。这个错误通常发生在TensorFlow操作中,当两个张量的数据类型不一致时。 我们需要检查代码中涉及张量操作的地方,特别是那些需要相同数据类型的操作(比如数学运算、矩阵运算等)。根据错误信息,其中一个张量是tf.float32,另一个是tf.int32。 观察错误发生的位置:由于错误信息比较泛,我们无法直接定位到具体行,但我们可以通过堆栈跟踪来定位。不过,由于我们这里没有堆栈信息,我们可以根据代码中的可疑点进行排查。 在提供的代码中,我们注意到在函数`phasecong2`中有一些操作可能涉及数据类型转换问题。例如: 1. 在生成频域网格时,我们使用了`tf.range`生成整数序列,然后转换为float32,但后续可能会有类型不一致的操作。 2. 在计算`radius`时,我们使用了`tf.sqrt(x_grid**2 + y_grid**2)`,这里都是float32,应该没问题。 3. 在`log_gabor = tf.exp(-(tf.math.log(radius / fo)) ** 2 / ...)`中,我们使用了`radius`和`fo`(float),应该没问题。 另一个可疑点是:在`extract_features`函数中,下采样操作使用的`f`(下采样因子)是整数,但在构造卷积核时,我们使用了`win_size = f`(整数)来创建卷积核,而卷积核的数据类型是`tf.float32`。这应该不会直接导致错误,因为卷积操作会处理类型转换。 但是,错误信息明确指出了`tf.float32`和`tf.int32`不匹配。因此,我们需要检查所有显式或隐式的类型转换。 另外,在`phasecong2`函数中,有一个操作可能存在问题: `radius = tf.where(radius == 0, 1.0, radius)` 这里,`1.0`是浮点数,而`radius`在之前是`tf.float32`,所以没有问题。 另一个可能的点是:在`lowpassfilter`函数中,我们生成了`filter_val`,然后返回。在`phasecong2`中使用时,我们将其转换为`tf.float32`(`lp = tf.cast(lp, tf.float32)`),所以也没有问题。 我们注意到在`phasecong2`函数中,我们使用了`img_fft = tf.signal.fft2d(tf.cast(img, tf.complex128))`,所以输入的`img`应该是浮点类型。在调用`phasecong2`时,传入的是`y_down`,它来自经过下采样的`y`(`y`是`tf.float32`),所以没有问题。 然而,在`phasecong2`函数中,我们使用`x_range`和`y_range`时,是通过`tf.range`生成整数,然后除以整数(或浮点数?)得到浮点数。但是,在除以整数时,如果整数是`tf.int32`,那么除法结果可能仍然是`tf.int32`?但实际上,由于我们指定了`dtype=tf.float32`,所以结果应该是`tf.float32`。 因此,我们需要检查每一个`tf.range`的调用,确保我们指定了`dtype=tf.float32`,并且后续操作不会改变数据类型。 在代码中,我们在`phasecong2`函数中生成`x_range`和`y_range`时,确实指定了`dtype=tf.float32`。所以问题可能不在这里。 重新审视错误信息,它提到了两个张量`x`和`y`,所以可能是二元操作(如加减乘除、矩阵运算等)中的两个张量类型不一致。 我们注意到在`phasecong2`函数中,有一个操作: `dtheta = tf.abs(tf.math.atan2(ds, dc))` 这里`ds`和`dc`都是通过浮点数运算得到的,应该没有问题。 另一个可能的地方是:在计算`spread`时,我们使用了`theta_sigma`(浮点数)和`dtheta`(浮点数),也没有问题。 由于错误信息没有给出具体位置,我们可以尝试在代码中显式地转换数据类型,避免隐式转换。另外,我们可以使用`tf.debugging`来检查张量的数据类型。 但是,我们也可以使用另一种方法:在代码中所有可能的地方强制使用相同的数据类型。由于大部分计算都是`tf.float32`,我们可以将整数张量显式转换为浮点张量。 在`extract_features`函数中,下采样因子`f`是通过`tf.cast(tf.round(...), tf.int32)`得到的整数。然后我们用这个整数创建卷积核: `ave_kernel = tf.ones((win_size, win_size, 1, 1), dtype=tf.float32) / (win_size ** 2)` 这里`win_size`是整数,所以`win_size ** 2`也是整数。然后我们除以整数,得到一个浮点数?在TensorFlow中,常数除法会得到浮点数吗?实际上,在TensorFlow中,整数除法会得到整数,但这里我们除以的是整数,而`ave_kernel`被赋值为浮点类型,所以TensorFlow应该会进行类型转换。但是,为了确保安全,我们可以将除数改为浮点数:`tf.cast(win_size**2, tf.float32)`。 不过,这不会导致`x`和`y`数据类型不一致的错误。 我们再来看看`generate_visualization`函数,这里我们使用了`matplotlib`,不应该有TensorFlow数据类型错误。 所以,问题可能出现在我们之前没有注意到的地方。 另一个可疑点是:在`phasecong2`函数中,我们有一个循环: for s in range(config.nscale): wavelength = config.min_wave_length * (config.mult ** s) fo = 1.0 / wavelength 这里,`config.mult`是浮点数,`config.min_wave_length`是整数,所以`wavelength`和`fo`都是浮点数。 排除这些,剩下的一个可能是:在`lowpassfilter`函数中,我们使用`tf.range`生成整数序列,但除以整数(当`cols`或`rows`为偶数时,我们除以`cols`,它是整数)。但是,我们指定了`dtype=tf.float32`,所以结果应该是浮点数。 我们注意到在`lowpassfilter`函数中,我们计算: `x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols)` 这里,分母可能是整数,但除以整数不会改变浮点数的类型(因为分子已经是浮点数)。 但是,当`cols`为偶数时,分母是`cols`(整数),当`cols`为奇数时,分母是`cols-1`(整数)。虽然除法操作会保持浮点数,但分母是整数,而分子是浮点数,结果还是浮点数。 因此,我们需要更仔细地检查。 由于错误信息没有给出具体位置,我建议在运行代码时启用TensorFlow的eager执行,并打印每一步的数据类型,或者使用`tf.debugging.assert_same_float_dtype`来检查。 但是,在缺少具体错误位置的情况下,我们可以尝试一个常见的修复:在`phasecong2`函数中,将整数常量显式转换为浮点数。 例如,在计算`log_gabor`时: `log_gabor = tf.exp(-(tf.math.log(radius / fo)) ** 2 / (2 * (tf.math.log(config.sigma_onf)) ** 2))` 这里,`2`是整数,我们可以改成`2.0`。 另外,在`spread = tf.exp(-dtheta ** 2 / (2 * theta_sigma ** 2))`中,将`2`改为`2.0`。 但这可能不是根本原因。 我们重新阅读错误信息,它可能是由`tf.image.extract_patches`引起的?因为在滑动窗口提取函数中,我们使用了`tf.image.extract_patches`,这个函数要求输入图像是浮点类型吗?实际上,我们的输入图像(在`extract_patches`调用中)是经过`gaussian`加权的,而`gaussian`是`tf.float32`,所以没有问题。 然而,在`calculate_fsim`函数中,我们调用了`extract_patches`,传入的图像是`pc_ref`等,它们是`tf.float32`。 因此,问题可能出现在其他地方。 考虑到错误信息中提到的两个张量分别是`tf.float32`和`tf.int32`,我们可以全局搜索代码中哪些地方使用了`tf.int32`,并检查是否与`tf.float32`进行了混合运算。 在代码中,我们使用了许多整数变量,比如`H, W`,它们是通过`tf.shape`得到的,而`tf.shape`返回的是`tf.int32`。当我们使用这些整数变量参与运算时,如果与浮点数混合,可能会出现问题。 例如,在`phasecong2`函数中,我们有以下代码: `img_fft = tf.signal.fft2d(tf.cast(img, tf.complex128))` `H, W = tf.shape(img)[0], tf.shape(img)[1]` 这里的`H`和`W`是`tf.int32`。 然后,在计算`x_range`和`y_range`时: `x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols)` 这里`cols`是`tf.int32`,但是我们在除法中使用了整数除法(//)和整数除法分母。但是,由于我们指定了`dtype=tf.float32`,所以`tf.range`生成的是浮点数,然后除以一个整数(cols-1或cols),得到浮点数。 但是,在`tf.range`的参数中,我们使用了`(cols-1)//2`,这是整数除法,结果还是整数。然后我们用浮点数的除法(`/`)除以整数,所以整体结果应该是浮点数。 但是,有一个潜在问题:在计算`x_range`时,我们使用了整数除法`//`,而`cols`是`tf.int32`,所以`(cols-1)//2`也是`tf.int32`。然后我们将其作为`tf.range`的起点,但是`tf.range`要求参数与`dtype`匹配吗?实际上,`tf.range`要求参数与`dtype`相同,否则会报错。我们这里指定了`dtype=tf.float32`,但是起点和终点都是整数(`tf.int32`),这会导致类型不匹配。 因此,这里可能是问题所在:`tf.range`的起点和终点应该是浮点数,但我们传入了整数(`tf.int32`)。我们需要将起点和终点转换为浮点数。 修改方法:将`-(cols-1)//2`和`(cols//2)+1`转换为浮点数,或者使用`tf.cast`。 所以,修改`phasecong2`函数中的两行为: `x_range = tf.range(tf.cast(-(cols-1)//2, tf.float32), tf.cast((cols//2)+1, tf.float32), dtype=tf.float32) / (cols-1 if cols%2 else cols)` 但是,请注意,`cols`是`tf.int32`,所以我们需要先进行整数运算,然后转换为浮点数。 但是,`tf.range`的起点和终点参数必须是标量,并且与`dtype`一致。所以更好的做法是: `start = tf.cast(-(cols-1)//2, tf.float32)` `end = tf.cast((cols//2)+1, tf.float32)` `x_range = tf.range(start, end, dtype=tf.float32) / ...` 但是,这里除法分母还是整数,我们需要将其转换为浮点数吗?没关系,因为除以整数会得到浮点数(在TensorFlow中,浮点数除以整数会得到浮点数)。 但是,分母表达式`(cols-1 if cols%2 else cols)`的结果是`tf.int32`,所以除法操作会得到一个`tf.float32`(因为`tf.range`的结果是`tf.float32`),所以没问题。 但是,我们注意到在`phasecong2`函数中,我们有两个`tf.range`调用(分别用于x和y),所以我们需要修改这两处。 具体修改如下: 原代码: x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols) y_range = tf.range(-(rows-1)//2, (rows//2)+1, dtype=tf.float32) / (rows-1 if rows%2 else rows) 修改为: # 先将起点和终点转换为浮点数 start_x = tf.cast(-(cols-1)//2, tf.float32) end_x = tf.cast((cols//2)+1, tf.float32) x_range = tf.range(start_x, end_x, dtype=tf.float32) / tf.cast((cols-1 if cols%2 else cols), tf.float32) start_y = tf.cast(-(rows-1)//2, tf.float32) end_y = tf.cast((rows//2)+1, tf.float32) y_range = tf.range(start_y, end_y, dtype=tf.float32) / tf.cast((rows-1 if rows%2 else rows), tf.float32) 这样,我们确保`tf.range`的参数与`dtype`一致,并且分母也是浮点数。 另外,同样的问题可能出现在`lowpassfilter`函数中。在该函数中,我们也有类似的代码: x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols) y_range = tf.range(-(rows-1)//2, (rows//2)+1, dtype=tf.float32) / (rows-1 if rows%2 else rows) 所以,我们也需要修改这个函数中的这两行,方法同上。 修改后,我们重新运行代码,看是否解决了问题。 如果问题仍然存在,我们可能需要继续检查其他地方。但根据错误信息,这个数据类型不匹配的问题很可能就是由`tf.range`的参数类型与指定的`dtype`不一致引起的。 因此,我们进行上述修改。 由于我们无法直接运行整个代码,因此建议先修改这两处,然后再测试。 此外,在`phasecong2`函数中,还有一个地方使用了整数除法:`angl = tf.cast(o * math.pi / config.norient, tf.float32)`,这里`o`是整数,`config.norient`也是整数,但`math.pi`是浮点数,所以结果是浮点数,没有问题。 我们按照上述思路修改代码。 </think>你的代码中出现的错误 `"x and y must have the same dtype, got tf.float32 != tf.int32."` 通常发生在 TensorFlow 操作中两个张量数据类型不一致时。让我们分析原因并解决: ### 问题原因分析 在 `phasecong2` 函数中,以下代码段存在问题: ```python x_range = tf.range(-(cols-1)//2, (cols//2)+1, dtype=tf.float32) / (cols-1 if cols%2 else cols) y_range = tf.range(-(rows-1)//2, (rows//2)+1, dtype=tf.float32) / (rows-1 if rows%2 else rows) ``` 这里的问题根源是: 1. `cols` 和 `rows` 是通过 `tf.shape` 获取的,返回的是 `tf.int32` 类型 2. 当执行 `(cols-1)//2` 等整数除法运算时,结果仍是 `tf.int32` 3. 但 `tf.range()` 的 `start` 和 `limit` 参数需要与 `dtype=tf.float32` 匹配 4. 导致 TensorFlow 无法将 `int32` 值应用于要求 `float32` 的操作 ### 解决方案 修改 `phasecong2` 函数中的坐标生成代码,确保数据类型一致: ```python def phasecong2(img: tf.Tensor) -> tf.Tensor: """单张图像相位一致性计算""" H, W = tf.shape(img)[0], tf.shape(img)[1] # 将尺寸转换为浮点数 cols_f = tf.cast(W, tf.float32) rows_f = tf.cast(H, tf.float32) # 修改后的坐标计算 x_start = tf.cast(-(W-1)//2, tf.float32) x_end = tf.cast(W//2, tf.float32) + 1 x_range = tf.range(x_start, x_end, dtype=tf.float32) / tf.cond( W % 2 == 1, lambda: tf.cast(W-1, tf.float32), lambda: tf.cast(W, tf.float32) ) y_start = tf.cast(-(H-1)//2, tf.float32) y_end = tf.cast(H//2, tf.float32) + 1 y_range = tf.range(y_start, y_end, dtype=tf.float32) / tf.cond( H % 2 == 1, lambda: tf.cast(H-1, tf.float32), lambda: tf.cast(H, tf.float32) ) # 其余代码保持不变... x_grid, y_grid = tf.meshgrid(x_range, y_range) # ...后续代码不变 ``` ### 关键修改说明: 1. **显式类型转换**: ```python cols_f = tf.cast(W, tf.float32) rows_f = tf.cast(H, tf.float32) ``` 先将尺寸转换为浮点数类型 2. **确保边界值为 float32**: ```python x_start = tf.cast(-(W-1)//2, tf.float32) x_end = tf.cast(W//2, tf.float32) + 1 ``` 3. **使用 tf.cond 处理条件分支**: ```python tf.cond(W % 2 == 1, lambda: tf.cast(W-1, tf.float32), lambda: tf.cast(W, tf.float32)) ``` 确保分母也是 float32 类型 ### 其他潜在问题预防 在 `lowpassfilter` 函数中也存在类似操作,建议同步修改: ```python def lowpassfilter(sze: Tuple[int, int], cutoff: float, n: int) -> tf.Tensor: rows, cols = sze # 转换尺寸为浮点类型 cols_f = tf.cast(cols, tf.float32) rows_f = tf.cast(rows, tf.float32) # 修改后的坐标计算(同上) # ... ``` ### 为什么会出现这个问题? TensorFlow 对数据类型要求严格,特别是在涉及数学运算时: - `tf.shape()` 返回的是 `int32` 张量 - 整数除法 (`//`) 会保持 `int32` 类型 - 但当这些值用于 `tf.range(start, limit, dtype=float)` 时 - 需要 `start` 和 `limit` 与指定的 `dtype` 完全匹配
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值