当前位置: 首页 > news >正文

贪心算法在联邦学习客户端选择问题中的应用

在这里插入图片描述

Java中的贪心算法在联邦学习客户端选择问题中的应用

1. 联邦学习与客户端选择问题概述

联邦学习(Federated Learning)是一种分布式机器学习方法,允许多个客户端(如移动设备)在本地数据上训练模型,而不需要将原始数据上传到中央服务器。在这种框架下,客户端选择是一个关键问题,它决定了哪些客户端参与每一轮的模型训练。

1.1 客户端选择的重要性

  1. 资源效率:避免选择过多客户端导致通信和计算资源浪费
  2. 模型质量:选择具有代表性数据的客户端提高模型性能
  3. 公平性:确保所有客户端都有机会参与训练
  4. 隐私保护:合理轮换客户端减少隐私泄露风险

1.2 客户端选择面临的挑战

  • 客户端资源异构性(计算能力、网络条件)
  • 数据分布非独立同分布(Non-IID)
  • 客户端可用性动态变化
  • 隐私和安全约束

2. 贪心算法基本原理

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优的选择,从而希望导致结果是全局最优的算法策略。

2.1 贪心算法的特点

  1. 局部最优选择:每一步都做出在当前看来最佳的选择
  2. 不可回溯:一旦做出选择就不再改变
  3. 高效性:通常比其他全局优化算法更快
  4. 近似解:不一定能得到全局最优解,但往往能得到不错的近似解

2.2 贪心算法的适用条件

贪心算法适用于问题具有以下性质:

  • 贪心选择性质:局部最优解能导致全局最优解
  • 最优子结构:问题的最优解包含其子问题的最优解

3. 联邦学习客户端选择问题的贪心解法

3.1 问题建模

假设我们有:

  • N个客户端:C = {c₁, c₂, …, c_N}
  • 每轮需要选择K个客户端参与训练
  • 每个客户端cᵢ有以下属性:
    • 数据量dᵢ
    • 计算资源rᵢ
    • 网络带宽bᵢ
    • 数据质量qᵢ
    • 上次参与时间tᵢ

目标:选择K个客户端,最大化某种效用函数U(S),其中S是选择的客户端集合,|S|=K

3.2 效用函数设计

常见的效用函数可以设计为:

U(S) = α·D(S) + β·R(S) + γ·Q(S) - δ·T(S)

其中:

  • D(S): 选择客户端的总数据量
  • R(S): 选择客户端的平均计算资源
  • Q(S): 选择客户端的数据质量
  • T(S): 选择客户端的上次参与时间的总和(鼓励轮换)
  • α, β, γ, δ: 权重参数

3.3 贪心选择策略

基本思路:每一步选择能使当前效用增加最多的客户端

算法步骤:

  1. 初始化S = ∅
  2. while |S| < K:
    • 对于每个不在S中的客户端c,计算ΔU = U(S ∪ {c}) - U(S)
    • 选择使ΔU最大的客户端c*
    • S = S ∪ {c*}
  3. 返回S

4. Java实现详细代码

下面是一个完整的Java实现,包含多个客户端选择策略。

4.1 客户端模型类

public class Client {private String id;private int dataSize;          // 数据量(MB)private double computePower;   // 计算能力(FLOPs)private double bandwidth;      // 网络带宽(Mbps)private double dataQuality;    // 数据质量(0-1)private long lastSelectedTime; // 上次被选择的时间戳public Client(String id, int dataSize, double computePower, double bandwidth, double dataQuality) {this.id = id;this.dataSize = dataSize;this.computePower = computePower;this.bandwidth = bandwidth;this.dataQuality = dataQuality;this.lastSelectedTime = -1; // 初始化为-1表示从未被选择}// Getters and Setterspublic String getId() { return id; }public int getDataSize() { return dataSize; }public double getComputePower() { return computePower; }public double getBandwidth() { return bandwidth; }public double getDataQuality() { return dataQuality; }public long getLastSelectedTime() { return lastSelectedTime; }public void setLastSelectedTime(long time) { this.lastSelectedTime = time; }@Overridepublic String toString() {return String.format("Client[%s]: data=%.1fMB, compute=%.1fGFLOPS, bw=%.1fMbps, quality=%.2f, last=%d",id, (float)dataSize, computePower/1e9, bandwidth, dataQuality, lastSelectedTime);}
}

4.2 客户端选择器接口

import java.util.List;
import java.util.Set;public interface ClientSelector {/*** 选择客户端参与联邦学习* @param allClients 所有可用客户端* @param numToSelect 需要选择的客户端数量* @param currentRound 当前轮次* @return 被选中的客户端集合*/Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound);
}

4.3 基于贪心算法的客户端选择实现

import java.util.*;
import java.util.stream.Collectors;public class GreedyClientSelector implements ClientSelector {// 权重参数private final double alpha;   // 数据量权重private final double beta;    // 计算资源权重private final double gamma;   // 数据质量权重private final double delta;   // 公平性权重public GreedyClientSelector(double alpha, double beta, double gamma, double delta) {this.alpha = alpha;this.beta = beta;this.gamma = gamma;this.delta = delta;}@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {if (allClients == null || allClients.isEmpty() || numToSelect <= 0) {return Collections.emptySet();}// 如果可选客户端不足,返回所有if (allClients.size() <= numToSelect) {return new HashSet<>(allClients);}Set<Client> selected = new HashSet<>();List<Client> candidates = new ArrayList<>(allClients);while (selected.size() < numToSelect && !candidates.isEmpty()) {Client bestClient = null;double maxUtility = Double.NEGATIVE_INFINITY;// 评估每个候选客户端的边际效用for (Client client : candidates) {// 计算添加此客户端后的效用增量double utilityGain = calculateUtilityGain(selected, client, currentRound);if (utilityGain > maxUtility) {maxUtility = utilityGain;bestClient = client;}}if (bestClient != null) {selected.add(bestClient);candidates.remove(bestClient);bestClient.setLastSelectedTime(currentRound);} else {break; // 没有客户端能提供正效用增益}}return selected;}/*** 计算添加指定客户端后的效用增量*/private double calculateUtilityGain(Set<Client> selected, Client candidate, int currentRound) {// 计算当前效用double currentUtility = calculateUtility(selected);// 计算添加候选后的效用Set<Client> newSet = new HashSet<>(selected);newSet.add(candidate);double newUtility = calculateUtility(newSet);return newUtility - currentUtility;}/*** 计算选定客户端集合的总效用*/private double calculateUtility(Set<Client> clients) {if (clients.isEmpty()) return 0;double totalData = 0;double totalCompute = 0;double totalQuality = 0;double totalRecency = 0;for (Client c : clients) {totalData += c.getDataSize();totalCompute += c.getComputePower();totalQuality += c.getDataQuality();totalRecency += (c.getLastSelectedTime() < 0) ? 1 : 0; // 从未被选择的客户端}double avgCompute = totalCompute / clients.size();double avgQuality = totalQuality / clients.size();return alpha * totalData + beta * avgCompute + gamma * avgQuality + delta * totalRecency;}// 其他可能的效用函数变体private double calculateAlternativeUtility(Set<Client> clients) {// 这里可以实现不同的效用计算方式// 例如考虑资源平衡、数据多样性等return 0;}
}

4.4 测试用例

import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class FederatedLearningClientSelectionDemo {public static void main(String[] args) {// 创建模拟客户端List<Client> clients = new ArrayList<>();clients.add(new Client("Client1", 100, 2.5e9, 10, 0.9));clients.add(new Client("Client2", 150, 1.8e9, 5, 0.85));clients.add(new Client("Client3", 80, 3.2e9, 15, 0.92));clients.add(new Client("Client4", 200, 2.0e9, 8, 0.8));clients.add(new Client("Client5", 120, 2.8e9, 12, 0.88));clients.add(new Client("Client6", 90, 1.5e9, 6, 0.75));clients.add(new Client("Client7", 180, 2.2e9, 9, 0.82));// 创建贪心选择器 (权重参数可以根据需求调整)ClientSelector selector = new GreedyClientSelector(0.4, 0.3, 0.2, 0.1);// 模拟多轮选择for (int round = 1; round <= 5; round++) {System.out.println("\n=== Round " + round + " ===");// 选择3个客户端Set<Client> selected = selector.selectClients(clients, 3, round);// 打印结果System.out.println("Selected Clients:");selected.forEach(client -> {System.out.println(client);client.setLastSelectedTime(round); // 更新最后选择时间});// 打印未选择的客户端System.out.println("\nUnselected Clients:");clients.stream().filter(c -> !selected.contains(c)).forEach(System.out::println);}}
}

4.5 更高级的贪心策略实现

import java.util.*;public class AdvancedGreedyClientSelector implements ClientSelector {private final double dataWeight;private final double computeWeight;private final double bandwidthWeight;private final double qualityWeight;private final double fairnessWeight;private final double diversityWeight;public AdvancedGreedyClientSelector(double dataWeight, double computeWeight, double bandwidthWeight, double qualityWeight,double fairnessWeight, double diversityWeight) {this.dataWeight = dataWeight;this.computeWeight = computeWeight;this.bandwidthWeight = bandwidthWeight;this.qualityWeight = qualityWeight;this.fairnessWeight = fairnessWeight;this.diversityWeight = diversityWeight;}@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {// 1. 预处理:计算每个客户端的得分Map<Client, Double> clientScores = new HashMap<>();for (Client client : allClients) {clientScores.put(client, calculateClientScore(client, currentRound));}// 2. 按得分排序List<Client> sortedClients = new ArrayList<>(allClients);sortedClients.sort((c1, c2) -> Double.compare(clientScores.get(c2), clientScores.get(c1)));// 3. 贪心选择,考虑多样性约束Set<Client> selected = new HashSet<>();List<Client> remaining = new ArrayList<>(sortedClients);while (selected.size() < numToSelect && !remaining.isEmpty()) {// 找到剩余客户端中得分最高的Client best = remaining.get(0);// 检查多样性约束if (meetsDiversityConstraint(selected, best)) {selected.add(best);best.setLastSelectedTime(currentRound);}remaining.remove(0);}// 如果因为多样性约束无法选够,补充选择次优的if (selected.size() < numToSelect) {for (Client client : sortedClients) {if (!selected.contains(client)) {selected.add(client);client.setLastSelectedTime(currentRound);if (selected.size() >= numToSelect) break;}}}return selected;}private double calculateClientScore(Client client, int currentRound) {// 计算各个维度的归一化值double dataNorm = client.getDataSize() / 1024.0; // 假设最大1GBdouble computeNorm = client.getComputePower() / 5e9; // 假设最大5GFLOPSdouble bandwidthNorm = client.getBandwidth() / 100.0; // 假设最大100Mbpsdouble qualityNorm = client.getDataQuality(); // 已经是0-1// 公平性:距离上次选择的轮次,越大越好long lastRound = client.getLastSelectedTime();double fairness = (lastRound < 0) ? 1.0 : 1.0 / (1.0 + (currentRound - lastRound));return dataWeight * dataNorm +computeWeight * computeNorm +bandwidthWeight * bandwidthNorm +qualityWeight * qualityNorm +fairnessWeight * fairness;}private boolean meetsDiversityConstraint(Set<Client> selected, Client candidate) {if (selected.isEmpty()) return true;// 简单的多样性检查:确保不所有客户端都有相似的资源特性// 这里可以实现更复杂的多样性度量double avgCompute = selected.stream().mapToDouble(Client::getComputePower).average().orElse(0);// 如果候选客户端的计算能力与已选客户端的平均值相差不大,可能降低多样性double diff = Math.abs(candidate.getComputePower() - avgCompute) / avgCompute;// 差异小于30%则认为不够多样if (diff < 0.3) {// 检查是否已经有足够多样的选择long diverseCount = selected.stream().filter(c -> Math.abs(c.getComputePower() - avgCompute) / avgCompute >= 0.5).count();return diverseCount >= selected.size() / 2;}return true;}
}

5. 贪心算法的优化与变体

5.1 带约束的贪心算法

在实际联邦学习中,客户端选择可能需要考虑各种约束条件:

public class ConstrainedGreedySelector extends GreedyClientSelector {private final double minComputePower; // 最小计算能力要求private final double minBandwidth;    // 最小带宽要求private final double minDataQuality;  // 最小数据质量要求public ConstrainedGreedySelector(double alpha, double beta, double gamma, double delta,double minComputePower, double minBandwidth, double minDataQuality) {super(alpha, beta, gamma, delta);this.minComputePower = minComputePower;this.minBandwidth = minBandwidth;this.minDataQuality = minDataQuality;}@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {// 先过滤掉不符合约束的客户端List<Client> filtered = allClients.stream().filter(c -> c.getComputePower() >= minComputePower).filter(c -> c.getBandwidth() >= minBandwidth).filter(c -> c.getDataQuality() >= minDataQuality).collect(Collectors.toList());// 调用父类的贪心选择return super.selectClients(filtered, numToSelect, currentRound);}
}

5.2 随机化贪心算法

为了避免贪心算法陷入局部最优,可以引入随机性:

public class RandomizedGreedySelector extends GreedyClientSelector {private final double explorationProb; // 探索概率public RandomizedGreedySelector(double alpha, double beta, double gamma, double delta,double explorationProb) {super(alpha, beta, gamma, delta);this.explorationProb = explorationProb;}@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {if (Math.random() < explorationProb) {// 探索:随机选择Collections.shuffle(allClients);return allClients.stream().limit(numToSelect).collect(Collectors.toSet());} else {// 利用:正常贪心选择return super.selectClients(allClients, numToSelect, currentRound);}}
}

5.3 基于子模函数的贪心算法

当效用函数满足子模性时,贪心算法可以提供理论保证:

public class SubmodularGreedySelector implements ClientSelector {// 子模函数要求效用函数满足边际效用递减的性质@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {Set<Client> selected = new HashSet<>();for (int i = 0; i < numToSelect; i++) {Client best = null;double bestMarginalGain = Double.NEGATIVE_INFINITY;for (Client client : allClients) {if (!selected.contains(client)) {double gain = marginalGain(selected, client, currentRound);if (gain > bestMarginalGain) {bestMarginalGain = gain;best = client;}}}if (best != null) {selected.add(best);best.setLastSelectedTime(currentRound);} else {break; // 没有更多客户端可选}}return selected;}private double marginalGain(Set<Client> selected, Client client, int currentRound) {// 实现满足子模性的效用函数double base = utility(selected);Set<Client> extended = new HashSet<>(selected);extended.add(client);double extendedUtil = utility(extended);return extendedUtil - base;}private double utility(Set<Client> clients) {// 实现满足子模性的效用函数// 例如: U(S) = ∑_{i∈S} w_i - λ·∑_{i,j∈S} similarity(i,j)return 0;}
}

6. 性能分析与优化

6.1 时间复杂度分析

基本贪心算法的时间复杂度:

  • 每轮选择需要评估所有剩余客户端的边际效用
  • 选择K个客户端,每轮评估N, N-1, …, N-K+1次
  • 总时间复杂度:O(K*N)

优化策略:

  1. 预排序:先按某种指标排序,减少评估次数
  2. 懒惰评估:利用边际效用递减性质,避免重复计算
  3. 并行计算:并行评估多个客户端的边际效用

6.2 空间复杂度分析

  • 需要存储所有客户端信息:O(N)
  • 选择过程中需要临时存储效用计算:O(1)
  • 总体空间复杂度:O(N)

6.3 Java特定优化

  1. 使用高效集合:根据场景选择HashSet或TreeSet
  2. 对象池:重用Client对象减少GC压力
  3. 并行流:利用多核并行计算效用
  4. 缓存计算结果:对于不变的数据缓存计算结果

优化后的贪心选择示例:

public Set<Client> optimizedSelect(List<Client> allClients, int numToSelect, int currentRound) {// 使用并行流加速评估PriorityQueue<ClientUtility> topCandidates = allClients.parallelStream().map(client -> new ClientUtility(client, calculateUtilityGain(Collections.emptySet(), client, currentRound))).sorted(Comparator.comparingDouble(ClientUtility::getUtility).reversed()).limit(numToSelect * 3L) // 保留前3K个候选,增加多样性.collect(Collectors.toCollection(() -> new PriorityQueue<>(Comparator.comparingDouble(ClientUtility::getUtility))));Set<Client> selected = new HashSet<>();Set<Client> candidates = new HashSet<>();// 填充候选集while (candidates.size() < numToSelect * 2 && !topCandidates.isEmpty()) {candidates.add(topCandidates.poll().getClient());}// 二次贪心选择while (selected.size() < numToSelect && !candidates.isEmpty()) {Client best = null;double maxGain = Double.NEGATIVE_INFINITY;for (Client client : candidates) {double gain = calculateUtilityGain(selected, client, currentRound);if (gain > maxGain) {maxGain = gain;best = client;}}if (best != null) {selected.add(best);candidates.remove(best);best.setLastSelectedTime(currentRound);}}return selected;
}private static class ClientUtility {private final Client client;private final double utility;public ClientUtility(Client client, double utility) {this.client = client;this.utility = utility;}public Client getClient() { return client; }public double getUtility() { return utility; }
}

7. 实际应用中的考虑因素

7.1 动态环境适应

联邦学习环境是动态变化的,需要考虑:

  • 客户端可用性变化:设备可能随时加入或离开
  • 资源波动:网络条件和计算资源可能变化
  • 数据分布漂移:客户端数据可能随时间变化

解决方案:

public class AdaptiveGreedySelector extends GreedyClientSelector {private Map<Client, Double> historicalUtility = new HashMap<>();private double learningRate; // 用于更新历史效用public AdaptiveGreedySelector(double alpha, double beta, double gamma, double delta,double learningRate) {super(alpha, beta, gamma, delta);this.learningRate = learningRate;}@Overrideprotected double calculateUtilityGain(Set<Client> selected, Client candidate, int currentRound) {double instantGain = super.calculateUtilityGain(selected, candidate, currentRound);double historicalGain = historicalUtility.getOrDefault(candidate, instantGain);// 结合即时效用和历史效用return learningRate * instantGain + (1 - learningRate) * historicalGain;}public void updateHistoricalUtility(Client client, double actualUtility) {double current = historicalUtility.getOrDefault(client, actualUtility);historicalUtility.put(client, learningRate * actualUtility + (1 - learningRate) * current);}
}

7.2 隐私保护考虑

客户端选择可能泄露信息,需要考虑:

  • 选择模式隐私:避免通过选择模式推断客户端数据
  • 差分隐私:在效用计算中加入噪声

差分隐私贪心选择示例:

public class DifferentiallyPrivateGreedySelector extends GreedyClientSelector {private final double privacyBudget;private final Random random = new Random();public DifferentiallyPrivateGreedySelector(double alpha, double beta, double gamma, double delta,double privacyBudget) {super(alpha, beta, gamma, delta);this.privacyBudget = privacyBudget;}@Overrideprotected double calculateUtilityGain(Set<Client> selected, Client candidate, int currentRound) {double realGain = super.calculateUtilityGain(selected, candidate, currentRound);// 添加拉普拉斯噪声double sensitivity = calculateSensitivity(selected, candidate);double noise = laplaceNoise(sensitivity / privacyBudget);return realGain + noise;}private double calculateSensitivity(Set<Client> selected, Client candidate) {// 计算效用函数的敏感度// 这取决于具体的效用函数设计return 1.0; // 简化示例}private double laplaceNoise(double scale) {// 生成拉普拉斯分布的随机数double u = random.nextDouble() - 0.5;return -scale * Math.signum(u) * Math.log(1 - 2 * Math.abs(u));}
}

7.3 多目标优化

客户端选择通常需要平衡多个目标:

  • 模型准确性
  • 训练速度
  • 资源消耗
  • 公平性

多目标贪心选择示例:

public class MultiObjectiveGreedySelector implements ClientSelector {private final List<ClientSelector> selectors;private final List<Double> weights;public MultiObjectiveGreedySelector(List<ClientSelector> selectors, List<Double> weights) {this.selectors = selectors;this.weights = weights;}@Overridepublic Set<Client> selectClients(List<Client> allClients, int numToSelect, int currentRound) {// 收集各选择器的评分Map<Client, Double> combinedScores = new HashMap<>();for (int i = 0; i < selectors.size(); i++) {ClientSelector selector = selectors.get(i);double weight = weights.get(i);// 获取该选择器的选择结果Set<Client> selected = selector.selectClients(allClients, allClients.size(), currentRound);// 为每个客户端分配分数int rank = 1;for (Client client : allClients) {if (selected.contains(client)) {combinedScores.merge(client, weight * (1.0 / rank), Double::sum);rank++;}}}// 按综合得分排序List<Client> sorted = new ArrayList<>(allClients);sorted.sort((c1, c2) -> Double.compare(combinedScores.getOrDefault(c2, 0.0), combinedScores.getOrDefault(c1, 0.0)));// 返回前K个return sorted.stream().limit(numToSelect).collect(Collectors.toSet());}
}

8. 评估与验证

8.1 评估指标

  1. 模型准确性:选择客户端训练后的模型测试准确率
  2. 收敛速度:达到目标准确率所需的轮次
  3. 资源利用率:计算和网络资源的使用效率
  4. 公平性:客户端被选择的频率分布
  5. 隐私保护度:信息泄露风险

8.2 验证框架示例

public class ClientSelectionEvaluator {public void evaluate(ClientSelector selector, List<Client> clients, int rounds, int clientsPerRound) {// 记录统计数据Map<Client, Integer> selectionCounts = new HashMap<>();clients.forEach(c -> selectionCounts.put(c, 0));double totalUtility = 0;long totalTime = 0;// 模拟多轮训练for (int round = 1; round <= rounds; round++) {long startTime = System.currentTimeMillis();// 选择客户端Set<Client> selected = selector.selectClients(clients, clientsPerRound, round);long endTime = System.currentTimeMillis();// 更新统计数据selected.forEach(c -> selectionCounts.put(c, selectionCounts.get(c) + 1));// 计算本轮效用double roundUtility = calculateRoundUtility(selected);totalUtility += roundUtility;// 记录时间totalTime += (endTime - startTime);// 可以在这里添加模型训练和评估的逻辑}// 计算公平性 (基尼系数)double gini = calculateGiniCoefficient(selectionCounts.values());// 打印评估结果System.out.println("Evaluation Results:");System.out.printf("Total Utility: %.2f\n", totalUtility);System.out.printf("Average Utility per Round: %.2f\n", totalUtility / rounds);System.out.printf("Average Selection Time: %.2f ms\n", (double)totalTime / rounds);System.out.printf("Gini Coefficient (Fairness): %.3f\n", gini);System.out.println("Selection Counts:");selectionCounts.forEach((client, count) -> System.out.printf("%s: %d times (%.1f%%)\n", client.getId(), count, 100.0 * count / rounds));}private double calculateRoundUtility(Set<Client> clients) {// 简化的效用计算return clients.stream().mapToDouble(c -> c.getDataSize() * c.getDataQuality()).average().orElse(0);}private double calculateGiniCoefficient(Collection<Integer> values) {// 计算基尼系数评估公平性List<Integer> sorted = new ArrayList<>(values);Collections.sort(sorted);double sum = 0;for (int i = 0; i < sorted.size(); i++) {sum += (2 * (i + 1) - sorted.size() - 1) * sorted.get(i);}double mean = sorted.stream().mapToInt(Integer::intValue).average().orElse(0);return sum / (sorted.size() * sorted.size() * mean);}
}

9. 总结与展望

贪心算法在联邦学习客户端选择问题中具有以下优势:

  1. 高效性:计算复杂度相对较低,适合大规模客户端场景
  2. 灵活性:可以灵活调整效用函数适应不同需求
  3. 可解释性:选择标准明确,便于分析和调试

开发方向:

  1. 深度强化学习:用DRL学习最优选择策略
  2. 联邦元学习:在联邦框架下学习选择算法
  3. 自适应权重调整:根据训练动态调整效用函数权重
  4. 跨轮次优化:考虑多轮选择的长期影响

贪心算法虽然简单,但在联邦学习客户端选择问题上通过精心设计的效用函数和各种优化策略,能够实现高效、公平且保护隐私的客户端选择,是实际系统中常用的解决方案。


文章转载自:

http://WZg2qKZM.zcfsq.cn
http://LBwLmtZ1.zcfsq.cn
http://V1qk90KA.zcfsq.cn
http://lIEmhSln.zcfsq.cn
http://fPaQ88ZU.zcfsq.cn
http://cPnhz3ZD.zcfsq.cn
http://pi9E8vKn.zcfsq.cn
http://GNufg9bl.zcfsq.cn
http://g5uV4doq.zcfsq.cn
http://TfOwOtgp.zcfsq.cn
http://a3PYZYKm.zcfsq.cn
http://n4m20how.zcfsq.cn
http://tIoOYUp4.zcfsq.cn
http://4B71lYy2.zcfsq.cn
http://JixCsPyS.zcfsq.cn
http://kelNFDPV.zcfsq.cn
http://OsAuLbBp.zcfsq.cn
http://9iuoCIaG.zcfsq.cn
http://71AldsPJ.zcfsq.cn
http://NP6xkGnF.zcfsq.cn
http://ss69j7QQ.zcfsq.cn
http://67t96IT0.zcfsq.cn
http://hrrrZfLQ.zcfsq.cn
http://OdxwVaXk.zcfsq.cn
http://KviaS8ia.zcfsq.cn
http://6BUxsnEG.zcfsq.cn
http://pqzI8h9Q.zcfsq.cn
http://JEtmXMFh.zcfsq.cn
http://0sl7dxrY.zcfsq.cn
http://KLJpx93d.zcfsq.cn
http://www.dtcms.com/a/382064.html

相关文章:

  • 自增主键为何需要返回?
  • JDBC从入门到面试:全面掌握Java数据库连接技术
  • java本机电脑跳过2层网络连到客户内网远程调试方案
  • 基于多元线性回归、随机森林与神经网络的农作物元素含量预测及SHAP贡献量分析
  • MySQL数据库 -- 6.事务
  • CSS :has() 选择器详解:为什么它是“父选择器”?如何实现真正的容器查询?
  • 6-1ASPNETCoreWeb入门
  • 【文献笔记】PointWeb
  • Rupert Baines加入CSA Catapult董事会
  • 解密进程管理:从创建到回收全解析(基于Liunx操作系统)
  • 深度神经网络2——优化器选择、学习率消毒、正则化选择
  • 核心利润获现率
  • Nginx 502 网关错误:upstream 超时配置的踩坑与优化
  • (综述)视觉任务的视觉语言模型
  • 【C语言选择排序算法详解】+ 算法性能优化 + 动态演示实现
  • 基于Matlab硬币圆形检测的实现
  • go使用反射获取http.Request参数到结构体
  • vscode使用tmux技巧
  • 【Block总结】ConverseNet:神经网络中的反向卷积算子
  • C++学习记录(8)list
  • 【C++】STL·List
  • 网络安全与iptables防火墙配置
  • Django + Vue3 前后端分离技术实现自动化测试平台从零到有系列 <第一章> 之 注册登录实现
  • Flink面试题及详细答案100道(41-60)- 状态管理与容错
  • 从基础到高级:一文快速认识MySQL UPDATE 语句
  • 基于KAZE算法的织物图像拼接matlab仿真,对比SIFT和SURF
  • 知识输出零散没有体系怎么办
  • 【LeetCode】37. 解数独
  • Redis常见性能问题
  • 数据帮助我们理解未知世界