乐闻世界logo
搜索文章和话题

面试题手册

VS Code 终端集成功能有哪些?

VS Code 内置强大的终端集成功能,允许在编辑器内直接使用命令行工具,无需切换窗口,极大提升开发效率。终端基础打开终端快捷键: Ctrl+` (反引号)菜单: View > Terminal命令面板: Terminal: Create New Terminal多终端管理创建新终端: 终端面板右上角的 + 按钮切换终端: 点击终端标签或使用快捷键拆分终端: 终端面板右上角的拆分按钮终端配置终端类型配置{ "terminal.integrated.defaultProfile.windows": "PowerShell", "terminal.integrated.defaultProfile.osx": "zsh", "terminal.integrated.defaultProfile.linux": "bash"}终端外观配置{ "terminal.integrated.fontSize": 13, "terminal.integrated.fontFamily": "Menlo, Monaco, 'Courier New'", "terminal.integrated.lineHeight": 1.2, "terminal.integrated.cursorBlinking": true, "terminal.integrated.cursorStyle": "block"}终端颜色配置{ "workbench.colorCustomizations": { "terminal.ansiBlack": "#000000", "terminal.ansiRed": "#cd3131", "terminal.ansiGreen": "#0dbc79", "terminal.ansiYellow": "#e5e510", "terminal.ansiBlue": "#2472c8", "terminal.ansiMagenta": "#bc3fbc", "terminal.ansiCyan": "#11a8cd", "terminal.ansiWhite": "#e5e5e5" }}终端操作常用快捷键Ctrl+`: 切换终端显示/隐藏Ctrl+Shift+`: 创建新终端Ctrl+1/2/3…: 切换到指定终端Ctrl+Shift+1/2/3…: 聚焦到指定终端Ctrl+C: 终止当前命令Ctrl+Shift+C: 复制终端内容Ctrl+Shift+V: 粘贴到终端终端命令历史上/下箭头: 浏览命令历史Ctrl+R: 搜索命令历史Ctrl+G: 退出搜索模式终端滚动Shift+PageUp/PageDown: 快速滚动Ctrl+Home/End: 跳转到开始/结束终端集成功能从终端打开文件# 在终端中执行code filename.jscode .从终端选择文本使用鼠标选择文本自动复制到剪贴板支持多行选择终端链接终端中的文件路径可点击自动打开对应文件支持行号跳转任务集成从任务运行命令{ "version": "2.0.0", "tasks": [ { "label": "Run Tests", "type": "shell", "command": "npm test", "presentation": { "reveal": "always", "panel": "new" } } ]}任务配置选项reveal: 何时显示终端(always, silent, never)panel: 使用哪个终端(shared, new, dedicated)focus: 是否聚焦终端clear: 是否清除终端内容终端环境环境变量配置{ "terminal.integrated.env.windows": { "PATH": "${env:PATH};C:\\myapp\\bin" }, "terminal.integrated.env.osx": { "PATH": "${env:PATH}:/usr/local/myapp/bin" }}工作目录配置{ "terminal.integrated.cwd": "${workspaceFolder}"}高级功能终端 Shell 集成自动检测 Shell 类型支持自定义 Shell 脚本提供智能提示终端配置文件创建自定义终端配置:{ "terminal.integrated.profiles.windows": { "PowerShell": { "source": "PowerShell", "icon": "terminal-powershell" }, "Git Bash": { "path": "C:\\Program Files\\Git\\bin\\bash.exe", "args": ["--login"] } }}终端 API在扩展中操作终端:const terminal = vscode.window.createTerminal('My Terminal');terminal.sendText('echo Hello World');terminal.show();常见 Shell 配置PowerShell{ "terminal.integrated.defaultProfile.windows": "PowerShell", "powershell.integrated.consoleTitleTemplate": "PowerShell: ${cwd}"}Git Bash{ "terminal.integrated.profiles.windows": { "Git Bash": { "path": "C:\\Program Files\\Git\\bin\\bash.exe", "args": ["--login", "-i"] } }}WSL{ "terminal.integrated.profiles.windows": { "WSL": { "path": "wsl.exe", "args": ["-d", "Ubuntu"] } }}注意事项终端会话在关闭 VS Code 时结束长时间运行的命令可能影响性能注意终端命令的安全性合理使用终端历史记录考虑使用终端扩展增强功能
阅读 0·2月18日 18:15

i18next-http-backend 如何实现翻译资源的远程加载?

i18next-http-backend 简介i18next-http-backend 是 i18next 的一个插件,用于从远程服务器加载翻译资源。它支持 HTTP 请求、缓存和延迟加载等功能。安装npm install i18next-http-backend# 或yarn add i18next-http-backend基本配置简单配置import i18next from 'i18next';import Backend from 'i18next-http-backend';i18next .use(Backend) .init({ lng: 'en', fallbackLng: 'en', backend: { loadPath: '/locales/{{lng}}/{{ns}}.json' } });完整配置i18next .use(Backend) .init({ lng: 'en', fallbackLng: 'en', ns: ['translation', 'common', 'errors'], defaultNS: 'translation', backend: { loadPath: '/locales/{{lng}}/{{ns}}.json', addPath: '/locales/add/{{lng}}/{{ns}}', parse: (data, lng, ns) => { return JSON.parse(data); }, stringify: (data, lng, ns) => { return JSON.stringify(data); }, request: (options, url, payload, callback) => { // 自定义请求逻辑 fetch(url, options) .then(response => response.json()) .then(data => callback(null, { data, status: 200 })) .catch(error => callback(error, null)); }, reloadInterval: false, // 重新加载间隔(毫秒) queryStringParams: { v: '1.0.0' } // 添加查询参数 } });路径配置动态路径变量{{lng}}: 当前语言代码{{ns}}: 当前命名空间{{projectId}}: 自定义项目 IDbackend: { loadPath: '/api/translations/{{lng}}/{{ns}}?projectId={{projectId}}', queryStringParams: { projectId: 'my-project-123' }}多路径配置backend: { loadPath: (lngs, namespaces) => { return namespaces.map(ns => `/locales/${lngs[0]}/${ns}.json`); }}延迟加载按需加载命名空间// 初始化时只加载默认命名空间i18next .use(Backend) .init({ ns: ['translation'], defaultNS: 'translation' });// 需要时加载其他命名空间i18next.loadNamespaces(['admin', 'settings'], () => { console.log('命名空间加载完成');});React 中的延迟加载import { useTranslation } from 'react-i18next';function AdminPanel() { const { t, ready } = useTranslation('admin', { useSuspense: false }); if (!ready) { return <div>Loading translations...</div>; } return <h1>{t('dashboard.title')}</h1>;}缓存机制使用本地存储缓存import LocalStorageBackend from 'i18next-localstorage-backend';import Backend from 'i18next-http-backend';i18next .use(Backend) .use(LocalStorageBackend) .init({ backend: { backends: [ LocalStorageBackend, // 主后端 Backend // 回退后端 ], backendOptions: [ { expirationTime: 7 * 24 * 60 * 60 * 1000, // 7天 defaultVersion: 'v1.0.0' }, { loadPath: '/locales/{{lng}}/{{ns}}.json' } ] } });自定义缓存逻辑backend: { loadPath: '/locales/{{lng}}/{{ns}}.json', request: (options, url, payload, callback) => { const cacheKey = `i18n_${url}`; const cached = localStorage.getItem(cacheKey); if (cached) { const { data, timestamp } = JSON.parse(cached); const isExpired = Date.now() - timestamp > 3600000; // 1小时 if (!isExpired) { return callback(null, { data, status: 200 }); } } fetch(url, options) .then(response => response.json()) .then(data => { localStorage.setItem(cacheKey, JSON.stringify({ data, timestamp: Date.now() })); callback(null, { data, status: 200 }); }) .catch(callback); }}错误处理加载失败处理i18next .use(Backend) .init({ backend: { loadPath: '/locales/{{lng}}/{{ns}}.json' } }) .catch(err => { console.error('翻译资源加载失败:', err); // 使用回退翻译 i18next.addResourceBundle('en', 'translation', { welcome: 'Welcome', error: 'An error occurred' }); });重试机制backend: { loadPath: '/locales/{{lng}}/{{ns}}.json', request: (options, url, payload, callback) => { let retries = 3; const attemptFetch = (attempt) => { fetch(url, options) .then(response => response.json()) .then(data => callback(null, { data, status: 200 })) .catch(error => { if (attempt < retries) { setTimeout(() => attemptFetch(attempt + 1), 1000 * attempt); } else { callback(error, null); } }); }; attemptFetch(0); }}性能优化预加载关键翻译i18next .use(Backend) .init({ preload: ['en', 'zh'], // 预加载的语言 ns: ['translation', 'common'] // 预加载的命名空间 });批量加载// 一次性加载多个命名空间Promise.all([ i18next.loadNamespaces(['admin', 'settings', 'reports']), i18next.loadLanguages(['en', 'zh', 'fr'])]).then(() => { console.log('所有翻译资源加载完成');});最佳实践版本控制: 在 URL 中添加版本参数,避免缓存问题错误处理: 实现完善的错误处理和回退机制性能优化: 使用缓存和延迟加载减少网络请求监控: 监控翻译资源加载性能和错误率CDN: 使用 CDN 加速翻译资源加载
阅读 0·2月18日 18:14

i18next 如何实现语言检测和切换?

语言检测使用 i18next-browser-languagedetectorimport LanguageDetector from 'i18next-browser-languagedetector';i18next .use(LanguageDetector) .init({ detection: { order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag'], caches: ['localStorage', 'cookie'], lookupQuerystring: 'lng', lookupCookie: 'i18next', lookupLocalStorage: 'i18nextLng', lookupSessionStorage: 'i18nextLng', lookupFromPathIndex: 0, checkWhitelist: true } });检测优先级querystring: 从 URL 查询参数中获取(如 ?lng=en)cookie: 从 cookie 中获取localStorage: 从本地存储中获取navigator: 从浏览器的语言设置中获取htmlTag: 从 HTML 标签的 lang 属性中获取语言切换基本切换import { useTranslation } from 'react-i18next';function LanguageSwitcher() { const { i18n } = useTranslation(); const changeLanguage = (lng) => { i18n.changeLanguage(lng); }; return ( <div> <button onClick={() => changeLanguage('en')}>English</button> <button onClick={() => changeLanguage('zh')}>中文</button> <button onClick={() => changeLanguage('fr')}>Français</button> </div> );}异步切换async function changeLanguageAsync(lng) { try { await i18n.changeLanguage(lng); console.log('语言切换成功'); } catch (error) { console.error('语言切换失败:', error); }}带加载状态的切换function LanguageSwitcher() { const { i18n } = useTranslation(); const [loading, setLoading] = useState(false); const changeLanguage = async (lng) => { setLoading(true); try { await i18n.changeLanguage(lng); } finally { setLoading(false); } }; return ( <div> {loading && <div>Loading...</div>} <button onClick={() => changeLanguage('en')} disabled={loading}> English </button> <button onClick={() => changeLanguage('zh')} disabled={loading}> 中文 </button> </div> );}监听语言变化使用事件监听function MyComponent() { const { i18n } = useTranslation(); const [currentLanguage, setCurrentLanguage] = useState(i18n.language); useEffect(() => { const handleLanguageChange = (lng) => { setCurrentLanguage(lng); console.log('语言已切换到:', lng); }; i18n.on('languageChanged', handleLanguageChange); return () => { i18n.off('languageChanged', handleLanguageChange); }; }, [i18n]); return <p>当前语言: {currentLanguage}</p>;}使用 useTranslation 的 ready 状态function MyComponent() { const { t, ready } = useTranslation(); if (!ready) { return <div>Loading translations...</div>; } return <h1>{t('welcome')}</h1>;}持久化语言设置使用 localStoragefunction LanguageSwitcher() { const { i18n } = useTranslation(); const changeLanguage = (lng) => { i18n.changeLanguage(lng); localStorage.setItem('preferredLanguage', lng); }; useEffect(() => { const savedLanguage = localStorage.getItem('preferredLanguage'); if (savedLanguage && savedLanguage !== i18n.language) { i18n.changeLanguage(savedLanguage); } }, [i18n]); return ( <div> <button onClick={() => changeLanguage('en')}>English</button> <button onClick={() => changeLanguage('zh')}>中文</button> </div> );}使用 URL 参数// 从 URL 参数获取语言function getLanguageFromURL() { const params = new URLSearchParams(window.location.search); return params.get('lng') || 'en';}// 更新 URL 参数function updateLanguageInURL(lng) { const url = new URL(window.location); url.searchParams.set('lng', lng); window.history.pushState({}, '', url);}function LanguageSwitcher() { const { i18n } = useTranslation(); const changeLanguage = (lng) => { i18n.changeLanguage(lng); updateLanguageInURL(lng); }; return ( <div> <button onClick={() => changeLanguage('en')}>English</button> <button onClick={() => changeLanguage('zh')}>中文</button> </div> );}服务端语言检测Express.js 示例const express = require('express');const i18next = require('i18next');const i18nextMiddleware = require('i18next-http-middleware');const LanguageDetector = require('i18next-browser-languagedetector');i18next .use(LanguageDetector) .use(i18nextMiddleware.LanguageDetector) .init({ detection: { order: ['header', 'querystring', 'cookie'], caches: ['cookie'] } });const app = express();app.use(i18nextMiddleware.handle(i18next));app.get('/', (req, res) => { const language = req.language; res.send(`Current language: ${language}`);});Next.js 示例// pages/_app.jsimport { appWithTranslation } from 'next-i18next';function MyApp({ Component, pageProps }) { return <Component {...pageProps} />;}export default appWithTranslation(MyApp);// pages/index.jsimport { useTranslation } from 'next-i18next';export default function Home() { const { t, i18n } = useTranslation(); const changeLanguage = (lng) => { i18n.changeLanguage(lng); }; return ( <div> <h1>{t('welcome')}</h1> <button onClick={() => changeLanguage('en')}>English</button> <button onClick={() => changeLanguage('zh')}>中文</button> </div> );}最佳实践用户偏好优先: 尊重用户的语言选择偏好持久化设置: 使用 localStorage 或 cookie 保存用户选择优雅降级: 当检测失败时使用默认语言加载状态: 显示加载状态提升用户体验URL 同步: 将语言设置同步到 URL,便于分享服务端支持: 在服务端也支持语言检测和切换白名单过滤: 只允许支持的语言切换
阅读 0·2月18日 18:14

VS Code 设置优先级是如何工作的?

VS Code 提供了多层次的设置系统,允许在不同级别配置编辑器行为。理解设置优先级对于正确配置开发环境至关重要。设置级别VS Code 支持以下设置级别,按优先级从高到低:工作区设置 - .vscode/settings.json远程设置 - 远程开发环境中的设置用户设置 - 用户全局设置默认设置 - VS Code 默认值设置文件位置用户设置macOS: ~/Library/Application Support/Code/User/settings.jsonWindows: %APPDATA%\Code\User\settings.jsonLinux: ~/.config/Code/User/settings.json工作区设置项目根目录下的 .vscode/settings.json远程设置远程服务器上的 ~/.vscode/data/Machine/settings.json设置优先级示例假设有以下设置:用户设置:{ "editor.fontSize": 14, "editor.tabSize": 2}工作区设置:{ "editor.fontSize": 16}最终生效:editor.fontSize: 16(工作区设置覆盖用户设置)editor.tabSize: 2(使用用户设置)语言特定设置可以为特定语言配置设置:{ "editor.fontSize": 14, "[javascript]": { "editor.fontSize": 16, "editor.tabSize": 2 }, "[python]": { "editor.tabSize": 4 }}常用设置项编辑器设置{ "editor.fontSize": 14, "editor.tabSize": 2, "editor.insertSpaces": true, "editor.wordWrap": "on", "editor.minimap.enabled": false}文件关联{ "files.associations": { "*.js": "javascript", "*.jsx": "javascriptreact" }}终端设置{ "terminal.integrated.fontSize": 13, "terminal.integrated.shell.osx": "/bin/zsh"}设置同步VS Code 提供设置同步功能,可以在不同设备间同步:用户设置键盘快捷键扩展用户片段UI 状态启用方法:Settings > Turn on Settings Sync动态配置在扩展中读取和修改设置:// 读取设置const config = vscode.workspace.getConfiguration('editor');const fontSize = config.get('fontSize', 14);// 监听设置变化vscode.workspace.onDidChangeConfiguration(event => { if (event.affectsConfiguration('editor.fontSize')) { console.log('Font size changed'); }});// 修改设置await config.update('fontSize', 16, vscode.ConfigurationTarget.Global);注意事项工作区设置应提交到版本控制用户设置包含个人偏好,不应提交敏感信息(如 API 密钥)不应存储在设置中使用 Settings Sync 时注意隐私和安全团队协作时,建议在 .vscode/settings.json 中共享项目配置
阅读 0·2月18日 18:09

VS Code 调试器如何配置和使用?

VS Code 内置了强大的调试功能,支持多种编程语言和运行时环境。通过配置 launch.json 文件,可以自定义调试行为。调试配置文件调试配置存储在 .vscode/launch.json 文件中:{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Program", "program": "${workspaceFolder}/app.js" } ]}常用配置属性基本属性type: 调试器类型(node, python, java 等)request: 请求类型(launch 启动程序,attach 附加到运行中的进程)name: 配置名称program: 要调试的程序路径变量替换${workspaceFolder}: 工作区根目录${file}: 当前打开的文件${fileBasename}: 当前文件名(不含路径)${fileDirname}: 当前文件所在目录${env:Name}: 环境变量常见语言配置示例Node.js{ "type": "node", "request": "launch", "name": "Launch Node.js", "program": "${workspaceFolder}/index.js", "console": "integratedTerminal"}Python{ "type": "python", "request": "launch", "name": "Python: Current File", "program": "${file}", "console": "integratedTerminal"}Chrome/Edge{ "type": "chrome", "request": "launch", "name": "Launch Chrome", "url": "http://localhost:3000", "webRoot": "${workspaceFolder}"}调试功能断点行断点:点击行号左侧条件断点:右键 > Add Conditional Breakpoint日志点:右键 > Add Logpoint调试操作F5: 开始调试F10: 单步跳过F11: 单步进入Shift+F11: 单步跳出Shift+F5: 停止调试调试控制台在调试过程中,可以在调试控制台中执行代码和检查变量。高级功能多配置调试{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Server", "program": "${workspaceFolder}/server.js" }, { "type": "chrome", "request": "launch", "name": "Client", "url": "http://localhost:3000" } ], "compounds": [ { "name": "Server/Client", "configurations": ["Server", "Client"] } ]}任务与调试集成在调试前自动运行构建任务:{ "preLaunchTask": "npm: build", "type": "node", "request": "launch", "name": "Launch"}注意事项确保安装了对应语言的调试扩展源码映射(Source Maps)对于 TypeScript/编译语言很重要远程调试需要正确配置端口和网络调试配置可以针对特定环境进行优化(开发、测试、生产)
阅读 0·2月18日 18:09

VS Code 调试适配器协议(DAP)是什么?

调试适配器协议(Debug Adapter Protocol,DAP)是 VS Code 提出的一种协议,用于将调试功能与调试器实现分离,使编辑器能够支持多种调试器。DAP 架构协议层次客户端: VS Code 编辑器,负责调试 UI 和用户交互适配器: 调试适配器,将 DAP 请求转换为调试器特定命令调试器: 实际的调试器实现(如 GDB、LLDB、Chrome DevTools)通信方式使用 JSON-RPC 协议通过标准输入/输出或 WebSocket 通信支持异步消息传递核心概念会话(Session)调试会话表示一次完整的调试过程,从启动到结束。线程(Thread)调试器中的执行线程,可以包含多个栈帧。栈帧(Stack Frame)函数调用栈中的一个帧,包含局部变量和执行位置。作用域(Scope)变量的逻辑分组,如局部变量、全局变量等。变量(Variable)调试器中的变量,可以查看和修改其值。DAP 请求类型初始化请求{ "seq": 1, "type": "request", "command": "initialize", "arguments": { "adapterID": "my-debugger", "pathFormat": "path", "linesStartAt1": true, "columnsStartAt1": true }}启动/附加请求{ "seq": 2, "type": "request", "command": "launch", "arguments": { "program": "/path/to/program", "stopOnEntry": false }}设置断点请求{ "seq": 3, "type": "request", "command": "setBreakpoints", "arguments": { "source": { "path": "/path/to/file.js" }, "breakpoints": [ { "line": 10 } ] }}继续执行请求{ "seq": 4, "type": "request", "command": "continue", "arguments": { "threadId": 1 }}DAP 事件类型初始化完成事件{ "seq": 1, "type": "event", "event": "initialized"}停止事件{ "seq": 2, "type": "event", "event": "stopped", "body": { "reason": "breakpoint", "threadId": 1, "allThreadsStopped": false }}输出事件{ "seq": 3, "type": "event", "event": "output", "body": { "category": "console", "output": "Hello World\n" }}实现调试适配器创建适配器项目npm init -ynpm install @vscode/debugadapter基本适配器结构import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent } from '@vscode/debugadapter';class MyDebugSession extends DebugSession { constructor() { super(); } protected initializeRequest(response: DebugProtocol.InitializeResponse): void { response.body = { supportsConfigurationDoneRequest: true, supportsEvaluateForHovers: true, supportsStepBack: false }; this.sendResponse(response); } protected launchRequest(response: DebugProtocol.LaunchResponse, args: any): void { // 启动调试器 this.sendResponse(response); } protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void { // 设置断点 response.body = { breakpoints: args.breakpoints.map(bp => ({ verified: true, line: bp.line })) }; this.sendResponse(response); }}配置调试适配器package.json 配置{ "contributes": { "debuggers": [ { "type": "my-debugger", "label": "My Debugger", "program": "./out/debugAdapter.js", "runtime": "node", "configurationAttributes": { "launch": { "required": ["program"], "properties": { "program": { "type": "string", "description": "Program to debug" } } } } } ] }}launch.json 配置{ "version": "0.2.0", "configurations": [ { "type": "my-debugger", "request": "launch", "name": "Debug with My Debugger", "program": "${workspaceFolder}/app.js" } ]}调试适配器测试调试适配器按 F5 启动扩展开发宿主打开包含调试配置的项目启动调试会话测试各种调试功能测试清单断点设置和触发单步执行变量查看和修改调用栈查看表达式求值高级功能自定义求值protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { const result = this.evaluateExpression(args.expression); response.body = { result: String(result), variablesReference: 0 }; this.sendResponse(response);}自定义变量protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void { const variables = this.getVariables(args.variablesReference); response.body = { variables: variables.map(v => ({ name: v.name, value: String(v.value), variablesReference: v.children ? 1 : 0 })) }; this.sendResponse(response);}注意事项正确处理异步操作提供清晰的错误信息支持取消操作考虑性能优化遵循 DAP 规范
阅读 0·2月18日 18:08

TensorFlow 中的分布式训练策略有哪些,如何实现多 GPU 训练

TensorFlow 提供了强大的分布式训练能力,支持在单机多 GPU、多机多 GPU 以及 TPU 上进行训练。了解这些策略对于加速大规模模型训练至关重要。分布式训练策略概览TensorFlow 2.x 提供了统一的 tf.distribute.Strategy API,支持以下策略:MirroredStrategy:单机多 GPU 同步训练MultiWorkerMirroredStrategy:多机多 GPU 同步训练TPUStrategy:TPU 训练ParameterServerStrategy:参数服务器架构CentralStorageStrategy:单机多 GPU,参数集中存储MirroredStrategy(单机多 GPU)基本用法import tensorflow as tf# 检查可用的 GPUprint("GPU 数量:", len(tf.config.list_physical_devices('GPU')))# 创建 MirroredStrategystrategy = tf.distribute.MirroredStrategy()print("副本数量:", strategy.num_replicas_in_sync)完整训练示例import tensorflow as tffrom tensorflow.keras import layers, models# 创建策略strategy = tf.distribute.MirroredStrategy()# 在策略作用域内创建和编译模型with strategy.scope(): # 构建模型 model = models.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(10, activation='softmax') ]) # 编译模型 model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'] )# 加载数据(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()x_train = x_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0x_test = x_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0# 创建分布式数据集batch_size_per_replica = 64global_batch_size = batch_size_per_replica * strategy.num_replicas_in_synctrain_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))train_dataset = train_dataset.shuffle(10000).batch(global_batch_size).prefetch(tf.data.AUTOTUNE)test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))test_dataset = test_dataset.batch(global_batch_size).prefetch(tf.data.AUTOTUNE)# 训练模型model.fit(train_dataset, epochs=10, validation_data=test_dataset)自定义训练循环import tensorflow as tffrom tensorflow.keras import optimizers, lossesstrategy = tf.distribute.MirroredStrategy()with strategy.scope(): model = models.Sequential([ layers.Dense(128, activation='relu', input_shape=(784,)), layers.Dense(10, activation='softmax') ]) optimizer = optimizers.Adam(learning_rate=0.001) loss_fn = losses.SparseCategoricalCrossentropy()# 训练步骤@tf.functiondef train_step(inputs, targets): with tf.GradientTape() as tape: predictions = model(inputs, training=True) per_replica_loss = loss_fn(targets, predictions) loss = tf.reduce_mean(per_replica_loss) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) return loss# 分布式训练步骤@tf.functiondef distributed_train_step(dataset_inputs): per_replica_losses = strategy.run(train_step, args=(dataset_inputs,)) return strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses, axis=None)# 训练循环epochs = 10for epoch in range(epochs): total_loss = 0 num_batches = 0 for inputs, targets in train_dataset: loss = distributed_train_step((inputs, targets)) total_loss += loss num_batches += 1 avg_loss = total_loss / num_batches print(f'Epoch {epoch + 1}, Loss: {avg_loss:.4f}')MultiWorkerMirroredStrategy(多机多 GPU)基本配置import tensorflow as tfimport os# 设置环境变量os.environ['TF_CONFIG'] = json.dumps({ 'cluster': { 'worker': ["host1:port", "host2:port", "host3:port"] }, 'task': {'type': 'worker', 'index': 0}})# 创建策略strategy = tf.distribute.MultiWorkerMirroredStrategy()print("副本数量:", strategy.num_replicas_in_sync)使用 TF_CONFIG 配置import jsonimport os# Worker 1 的配置tf_config_worker1 = { 'cluster': { 'worker': ["worker1.example.com:12345", "worker2.example.com:12345"] }, 'task': {'type': 'worker', 'index': 0}}# Worker 2 的配置tf_config_worker2 = { 'cluster': { 'worker': ["worker1.example.com:12345", "worker2.example.com:12345"] }, 'task': {'type': 'worker', 'index': 1}}# 设置环境变量os.environ['TF_CONFIG'] = json.dumps(tf_config_worker1)训练代码(与 MirroredStrategy 相同)with strategy.scope(): model = create_model() model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')model.fit(train_dataset, epochs=10)TPUStrategy(TPU 训练)基本用法import tensorflow as tf# 创建 TPU 策略resolver = tf.distribute.cluster_resolver.TPUClusterResolver()tf.config.experimental_connect_to_cluster(resolver)tf.tpu.experimental.initialize_tpu_system(resolver)strategy = tf.distribute.TPUStrategy(resolver)print("TPU 副本数量:", strategy.num_replicas_in_sync)TPU 训练示例with strategy.scope(): model = models.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(10, activation='softmax') ]) model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'] )# 调整批次大小以适应 TPUbatch_size = 1024 # TPU 支持更大的批次大小train_dataset = train_dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)model.fit(train_dataset, epochs=10)ParameterServerStrategy(参数服务器)基本配置import tensorflow as tfimport jsonimport os# 参数服务器配置tf_config = { 'cluster': { 'worker': ["worker1.example.com:12345", "worker2.example.com:12345"], 'ps': ["ps1.example.com:12345", "ps2.example.com:12345"] }, 'task': {'type': 'worker', 'index': 0}}os.environ['TF_CONFIG'] = json.dumps(tf_config)# 创建策略strategy = tf.distribute.ParameterServerStrategy()使用 ParameterServerStrategywith strategy.scope(): model = create_model() optimizer = tf.keras.optimizers.Adam() # 自定义训练循环 @tf.function def train_step(inputs, targets): with tf.GradientTape() as tape: predictions = model(inputs) loss = loss_fn(targets, predictions) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) return lossCentralStorageStrategy(集中存储)基本用法import tensorflow as tf# 创建策略strategy = tf.distribute.CentralStorageStrategy()print("副本数量:", strategy.num_replicas_in_sync)# 使用方式与 MirroredStrategy 相同with strategy.scope(): model = create_model() model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')model.fit(train_dataset, epochs=10)数据分布策略自动分片# 使用 strategy.experimental_distribute_dataset 自动分片distributed_dataset = strategy.experimental_distribute_dataset(dataset)# 或者使用 strategy.distribute_datasets_from_functiondef dataset_fn(input_context): batch_per_replica = 64 global_batch_size = batch_per_replica * input_context.num_replicas_in_sync dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) dataset = dataset.shuffle(10000).batch(global_batch_size) return dataset.shard(input_context.num_input_pipelines, input_context.input_pipeline_id)distributed_dataset = strategy.distribute_datasets_from_function(dataset_fn)性能优化技巧1. 混合精度训练from tensorflow.keras import mixed_precision# 启用混合精度policy = mixed_precision.Policy('mixed_float16')mixed_precision.set_global_policy(policy)with strategy.scope(): model = create_model() # 需要使用损失缩放 optimizer = mixed_precision.LossScaleOptimizer(optimizer) model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy')2. 同步批量归一化# 使用 SyncBatchNormalizationwith strategy.scope(): model = models.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.BatchNormalization(), # 自动转换为 SyncBatchNormalization layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(10, activation='softmax') ])3. XLA 编译# 启用 XLA 编译tf.config.optimizer.set_jit(True)with strategy.scope(): model = create_model() model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')4. 优化数据加载# 使用 AUTOTUNE 自动优化train_dataset = train_dataset.cache()train_dataset = train_dataset.shuffle(10000)train_dataset = train_dataset.batch(global_batch_size)train_dataset = train_dataset.prefetch(tf.data.AUTOTUNE)监控和调试使用 TensorBoardimport datetime# 创建日志目录log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")tensorboard_callback = tf.keras.callbacks.TensorBoard( log_dir=log_dir, histogram_freq=1)# 训练时使用回调model.fit( train_dataset, epochs=10, callbacks=[tensorboard_callback])监控 GPU 使用情况# 查看设备分配print("设备列表:", tf.config.list_physical_devices())# 查看当前设备print("当前设备:", tf.test.gpu_device_name())常见问题和解决方案1. 内存不足# 减小批次大小batch_size_per_replica = 32 # 从 64 减小到 32# 使用梯度累积# 或者使用模型并行2. 通信开销# 增大批次大小以减少通信频率global_batch_size = 256 * strategy.num_replicas_in_sync# 使用梯度压缩# 或者使用异步更新3. 数据加载瓶颈# 使用缓存train_dataset = train_dataset.cache()# 使用预取train_dataset = train_dataset.prefetch(tf.data.AUTOTUNE)# 使用并行加载train_dataset = train_dataset.map( preprocess, num_parallel_calls=tf.data.AUTOTUNE)策略选择指南| 策略 | 适用场景 | 优点 | 缺点 || --------------------------- | ------------- | -------- | ---------- || MirroredStrategy | 单机多 GPU | 简单易用,性能好 | 受限于单机资源 || MultiWorkerMirroredStrategy | 多机多 GPU | 可扩展性强 | 配置复杂,网络开销 || TPUStrategy | TPU 环境 | 极高性能 | 仅限 TPU || ParameterServerStrategy | 大规模异步训练 | 支持超大规模模型 | 实现复杂,收敛慢 || CentralStorageStrategy | 单机多 GPU(参数集中) | 简单,内存效率高 | 参数更新可能成为瓶颈 |完整的多 GPU 训练示例import tensorflow as tffrom tensorflow.keras import layers, models# 1. 创建策略strategy = tf.distribute.MirroredStrategy()# 2. 在策略作用域内构建模型with strategy.scope(): model = models.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dropout(0.5), layers.Dense(10, activation='softmax') ]) model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'] )# 3. 准备数据(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()x_train = x_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0x_test = x_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0# 4. 创建分布式数据集batch_size_per_replica = 64global_batch_size = batch_size_per_replica * strategy.num_replicas_in_synctrain_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))train_dataset = train_dataset.shuffle(10000).batch(global_batch_size).prefetch(tf.data.AUTOTUNE)test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))test_dataset = test_dataset.batch(global_batch_size).prefetch(tf.data.AUTOTUNE)# 5. 训练模型history = model.fit( train_dataset, epochs=10, validation_data=test_dataset, callbacks=[ tf.keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True), tf.keras.callbacks.ModelCheckpoint('best_model.h5', save_best_only=True) ])# 6. 评估模型test_loss, test_acc = model.evaluate(test_dataset)print(f'Test Accuracy: {test_acc:.4f}')总结TensorFlow 的分布式训练策略提供了灵活且强大的多 GPU 训练能力:MirroredStrategy:最适合单机多 GPU 场景MultiWorkerMirroredStrategy:适用于多机多 GPU 场景TPUStrategy:在 TPU 上获得最佳性能ParameterServerStrategy:支持超大规模异步训练CentralStorageStrategy:单机多 GPU 的替代方案掌握这些策略将帮助你充分利用硬件资源,加速模型训练。
阅读 0·2月18日 18:07

VS Code 键盘快捷键如何自定义?

VS Code 提供丰富的键盘快捷键,可以大幅提高开发效率。通过自定义快捷键配置,可以根据个人习惯优化工作流程。常用快捷键编辑操作Ctrl+X: 剪切行Ctrl+C: 复制行Alt+上/下箭头: 移动行Shift+Alt+上/下箭头: 复制行Ctrl+Enter: 在下方插入新行Ctrl+Shift+Enter: 在上方插入新行导航操作Ctrl+P: 快速打开文件Ctrl+Shift+P: 命令面板Ctrl+G: 跳转到行Ctrl+T: 跳转到符号Ctrl+Shift+O: 跳转到文件中的符号Ctrl+Tab: 切换编辑器标签选择操作Ctrl+D: 选择下一个相同的词Ctrl+Shift+L: 选择所有相同的词Alt+点击: 添加光标Shift+Alt+拖动: 列选择搜索替换Ctrl+F: 查找Ctrl+H: 替换Ctrl+Shift+F: 在文件中查找Ctrl+Shift+H: 在文件中替换自定义快捷键快捷键配置文件快捷键配置存储在 keybindings.json 文件中。打开快捷键编辑器按 Ctrl+K, Ctrl+S或通过菜单:File > Preferences > Keyboard Shortcuts自定义快捷键示例[ { "key": "ctrl+shift+;", "command": "editor.action.insertCursorAtEndOfEachLineSelected", "when": "editorTextFocus" }, { "key": "ctrl+alt+/", "command": "editor.action.commentLine", "when": "editorTextFocus" }]条件快捷键when 子句使用 when 子句控制快捷键的触发条件:[ { "key": "ctrl+shift+f", "command": "editor.action.formatDocument", "when": "editorHasDocumentFormattingProvider && editorTextFocus && !editorReadonly" }]常用 when 条件editorTextFocus: 编辑器有焦点editorHasSelection: 有选中文本editorReadonly: 编辑器只读resourceExtname == .js: 文件扩展名为 .js多键快捷键定义多键序列[ { "key": "ctrl+k ctrl+s", "command": "workbench.action.showAllSymbols" }]使用多键快捷键按下第一个键组合在状态栏提示后按下第二个键组合平台特定快捷键不同平台配置[ { "key": "ctrl+shift+f", "mac": "cmd+shift+f", "command": "workbench.action.findInFiles" }]平台标识符mac: macOSlinux: Linuxwindows: Windows快捷键冲突解决查看快捷键冲突打开快捷键编辑器输入快捷键组合查看冲突的命令禁用默认快捷键[ { "key": "ctrl+shift+f", "command": "-workbench.action.findInFiles" }]覆盖扩展快捷键[ { "key": "ctrl+shift+f", "command": "myExtension.customCommand", "when": "editorTextFocus" }]快捷键最佳实践命名规范使用有意义的快捷键组合避免与常用快捷键冲突考虑跨平台兼容性组织快捷键按功能分组使用一致的命名模式添加注释说明示例配置[ { "key": "ctrl+shift+1", "command": "workbench.action.terminal.new", "when": "!terminalFocus" }, { "key": "ctrl+shift+2", "command": "workbench.action.splitEditor", "when": "!terminalFocus" }, { "key": "ctrl+shift+3", "command": "workbench.action.toggleSidebarVisibility", "when": "!terminalFocus" }]注意事项定期备份快捷键配置测试自定义快捷键是否正常工作考虑团队协作时的快捷键一致性避免过度自定义导致学习成本增加使用快捷键提示功能(Ctrl+K Ctrl+R)
阅读 0·2月18日 18:05

TensorFlow 中的回调函数(Callbacks)有哪些,如何自定义回调函数

回调函数是 TensorFlow 中用于在训练过程中执行自定义操作的强大工具。它们允许你在训练的不同阶段监控、控制和修改训练过程。内置回调函数1. ModelCheckpoint - 保存模型检查点from tensorflow.keras.callbacks import ModelCheckpoint# 保存最佳模型checkpoint = ModelCheckpoint( filepath='best_model.h5', monitor='val_loss', save_best_only=True, mode='min', verbose=1)# 保存每个 epoch 的模型checkpoint_epoch = ModelCheckpoint( filepath='model_{epoch:02d}.h5', save_freq='epoch', verbose=1)# 只保存模型权重checkpoint_weights = ModelCheckpoint( filepath='weights_{epoch:02d}.h5', save_weights_only=True, verbose=1)2. EarlyStopping - 早停from tensorflow.keras.callbacks import EarlyStopping# 基于验证损失早停early_stop = EarlyStopping( monitor='val_loss', patience=5, mode='min', restore_best_weights=True, verbose=1)# 基于验证准确率早停early_stop_acc = EarlyStopping( monitor='val_accuracy', patience=3, mode='max', verbose=1)3. ReduceLROnPlateau - 学习率衰减from tensorflow.keras.callbacks import ReduceLROnPlateau# 当验证损失不再下降时降低学习率reduce_lr = ReduceLROnPlateau( monitor='val_loss', factor=0.1, # 学习率乘以 0.1 patience=3, mode='min', min_lr=1e-7, verbose=1)# 基于准确率调整学习率reduce_lr_acc = ReduceLROnPlateau( monitor='val_accuracy', factor=0.5, patience=2, mode='max', verbose=1)4. TensorBoard - TensorBoard 日志from tensorflow.keras.callbacks import TensorBoardimport datetime# 创建带时间戳的日志目录log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")tensorboard = TensorBoard( log_dir=log_dir, histogram_freq=1, write_graph=True, write_images=True, update_freq='epoch')5. LearningRateScheduler - 学习率调度from tensorflow.keras.callbacks import LearningRateSchedulerimport math# 定义学习率调度函数def lr_scheduler(epoch, lr): if epoch < 10: return lr else: return lr * math.exp(-0.1)lr_schedule = LearningRateScheduler(lr_scheduler, verbose=1)# 使用预定义的学习率衰减def step_decay(epoch): initial_lr = 0.001 drop = 0.5 epochs_drop = 10.0 lrate = initial_lr * math.pow(drop, math.floor((1+epoch)/epochs_drop)) return lratelr_step = LearningRateScheduler(step_decay, verbose=1)6. CSVLogger - CSV 日志记录from tensorflow.keras.callbacks import CSVLoggercsv_logger = CSVLogger( 'training.log', separator=',', append=False)7. ProgbarLogger - 进度条日志from tensorflow.keras.callbacks import ProgbarLoggerprogbar = ProgbarLogger( count_mode='steps', stateful_metrics=['loss', 'accuracy'])8. LambdaCallback - 自定义回调from tensorflow.keras.callbacks import LambdaCallback# 简单的自定义回调lambda_callback = LambdaCallback( on_epoch_begin=lambda epoch, logs: print(f"Epoch {epoch} 开始"), on_epoch_end=lambda epoch, logs: print(f"Epoch {epoch} 结束, Loss: {logs['loss']:.4f}"), on_batch_begin=lambda batch, logs: None, on_batch_end=lambda batch, logs: None, on_train_begin=lambda logs: print("训练开始"), on_train_end=lambda logs: print("训练结束"))9. RemoteMonitor - 远程监控from tensorflow.keras.callbacks import RemoteMonitorremote_monitor = RemoteMonitor( root='http://localhost:9000', path='/publish/epoch/end/', field='data', headers=None, send_as_json=False)10. BackupAndRestore - 备份和恢复from tensorflow.keras.callbacks import BackupAndRestorebackup_restore = BackupAndRestore( backup_dir='backup', save_freq='epoch', delete_checkpoint=True)自定义回调函数基本自定义回调from tensorflow.keras.callbacks import Callbackclass CustomCallback(Callback): def on_train_begin(self, logs=None): print("训练开始") def on_train_end(self, logs=None): print("训练结束") def on_epoch_begin(self, epoch, logs=None): print(f"Epoch {epoch} 开始") def on_epoch_end(self, epoch, logs=None): print(f"Epoch {epoch} 结束") print(f"Loss: {logs['loss']:.4f}") print(f"Accuracy: {logs['accuracy']:.4f}") def on_batch_begin(self, batch, logs=None): pass def on_batch_end(self, batch, logs=None): if batch % 100 == 0: print(f"Batch {batch}, Loss: {logs['loss']:.4f}")使用自定义回调# 创建自定义回调实例custom_callback = CustomCallback()# 在训练时使用model.fit( x_train, y_train, epochs=10, validation_data=(x_val, y_val), callbacks=[custom_callback])高级自定义回调示例1. 学习率记录回调class LearningRateRecorder(Callback): def __init__(self): super(LearningRateRecorder, self).__init__() self.lr_history = [] def on_epoch_end(self, epoch, logs=None): # 获取当前学习率 lr = self.model.optimizer.learning_rate if isinstance(lr, tf.keras.optimizers.schedules.LearningRateSchedule): lr = lr(self.model.optimizer.iterations) self.lr_history.append(float(lr)) print(f"Epoch {epoch}: Learning Rate = {lr:.6f}") def get_lr_history(self): return self.lr_history2. 梯度监控回调class GradientMonitor(Callback): def __init__(self, log_dir='logs/gradients'): super(GradientMonitor, self).__init__() self.log_dir = log_dir self.writer = tf.summary.create_file_writer(log_dir) def on_epoch_end(self, epoch, logs=None): # 计算梯度 with tf.GradientTape() as tape: predictions = self.model(x_train[:1]) loss = self.model.compiled_loss(y_train[:1], predictions) gradients = tape.gradient(loss, self.model.trainable_variables) # 记录梯度范数 with self.writer.as_default(): for i, grad in enumerate(gradients): if grad is not None: grad_norm = tf.norm(grad) tf.summary.scalar(f'gradient_norm_{i}', grad_norm, step=epoch)3. 模型权重监控回调class WeightMonitor(Callback): def __init__(self, log_dir='logs/weights'): super(WeightMonitor, self).__init__() self.log_dir = log_dir self.writer = tf.summary.create_file_writer(log_dir) def on_epoch_end(self, epoch, logs=None): with self.writer.as_default(): for i, layer in enumerate(self.model.layers): if hasattr(layer, 'get_weights'): weights = layer.get_weights() for j, w in enumerate(weights): w_mean = tf.reduce_mean(w) w_std = tf.math.reduce_std(w) tf.summary.scalar(f'layer_{i}_weight_{j}_mean', w_mean, step=epoch) tf.summary.scalar(f'layer_{i}_weight_{j}_std', w_std, step=epoch)4. 自定义早停回调class CustomEarlyStopping(Callback): def __init__(self, monitor='val_loss', patience=5, min_delta=0): super(CustomEarlyStopping, self).__init__() self.monitor = monitor self.patience = patience self.min_delta = min_delta self.wait = 0 self.best = None self.stopped_epoch = 0 def on_train_begin(self, logs=None): self.wait = 0 self.best = float('inf') if 'loss' in self.monitor else -float('inf') def on_epoch_end(self, epoch, logs=None): current = logs.get(self.monitor) if current is None: return if self.monitor == 'val_loss': if current < self.best - self.min_delta: self.best = current self.wait = 0 else: self.wait += 1 if self.wait >= self.patience: self.stopped_epoch = epoch self.model.stop_training = True print(f"Early stopping at epoch {epoch}") else: if current > self.best + self.min_delta: self.best = current self.wait = 0 else: self.wait += 1 if self.wait >= self.patience: self.stopped_epoch = epoch self.model.stop_training = True print(f"Early stopping at epoch {epoch}")5. 混合精度训练回调class MixedPrecisionCallback(Callback): def __init__(self): super(MixedPrecisionCallback, self).__init__() self.loss_scale = 1.0 def on_batch_end(self, batch, logs=None): # 检查损失是否为 NaN 或 Inf if logs is not None and 'loss' in logs: if tf.math.is_nan(logs['loss']) or tf.math.is_inf(logs['loss']): print(f"NaN/Inf detected at batch {batch}, reducing loss scale") self.loss_scale /= 2.0 # 重置优化器状态 self.model.optimizer.set_weights([ w / 2.0 if w is not None else None for w in self.model.optimizer.get_weights() ])6. 数据增强回调class DataAugmentationCallback(Callback): def __init__(self, augmentation_fn): super(DataAugmentationCallback, self).__init__() self.augmentation_fn = augmentation_fn def on_batch_begin(self, batch, logs=None): # 在训练时应用数据增强 if self.model.trainable: # 这里可以访问当前批次的数据 # 实际应用中需要更复杂的实现 pass7. 模型集成回调class ModelEnsembleCallback(Callback): def __init__(self, ensemble_size=5): super(ModelEnsembleCallback, self).__init__() self.ensemble_size = ensemble_size self.models = [] def on_epoch_end(self, epoch, logs=None): # 保存模型快照 if epoch % 5 == 0 and len(self.models) < self.ensemble_size: model_copy = tf.keras.models.clone_model(self.model) model_copy.set_weights(self.model.get_weights()) self.models.append(model_copy) print(f"Saved model snapshot at epoch {epoch}") def predict_ensemble(self, x): # 集成预测 predictions = [model.predict(x) for model in self.models] return np.mean(predictions, axis=0)回调函数组合使用# 组合多个回调函数callbacks = [ # 模型检查点 ModelCheckpoint( 'best_model.h5', monitor='val_loss', save_best_only=True, verbose=1 ), # 早停 EarlyStopping( monitor='val_loss', patience=5, restore_best_weights=True, verbose=1 ), # 学习率衰减 ReduceLROnPlateau( monitor='val_loss', factor=0.1, patience=3, verbose=1 ), # TensorBoard TensorBoard(log_dir='logs/fit'), # 自定义回调 CustomCallback()]# 训练模型model.fit( x_train, y_train, epochs=100, validation_data=(x_val, y_val), callbacks=callbacks)回调函数执行顺序回调函数的执行顺序如下:on_train_beginon_epoch_beginon_batch_beginon_batch_endon_epoch_endon_train_end回调函数最佳实践1. 合理设置监控指标# 根据任务选择合适的监控指标early_stop = EarlyStopping( monitor='val_accuracy' if classification else 'val_loss', patience=5, verbose=1)2. 保存最佳模型# 始终保存最佳模型checkpoint = ModelCheckpoint( 'best_model.h5', monitor='val_loss', save_best_only=True, mode='min')3. 使用学习率调度# 结合学习率调度和早停callbacks = [ ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3), EarlyStopping(monitor='val_loss', patience=10)]4. 监控训练过程# 使用 TensorBoard 监控训练tensorboard = TensorBoard( log_dir='logs/fit', histogram_freq=1, write_graph=True)5. 避免过度记录# 不要过于频繁地记录信息class EfficientCallback(Callback): def on_epoch_end(self, epoch, logs=None): if epoch % 5 == 0: # 每 5 个 epoch 记录一次 print(f"Epoch {epoch}: Loss = {logs['loss']:.4f}")6. 处理异常情况class RobustCallback(Callback): def on_batch_end(self, batch, logs=None): try: # 处理逻辑 pass except Exception as e: print(f"Error in callback: {e}") # 不要中断训练回调函数应用场景1. 长时间训练# 使用检查点和备份恢复callbacks = [ ModelCheckpoint('checkpoint.h5', save_freq='epoch'), BackupAndRestore(backup_dir='backup')]2. 超参数调优# 使用早停和学习率调度callbacks = [ EarlyStopping(monitor='val_loss', patience=5), ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=2)]3. 实验跟踪# 使用 TensorBoard 和 CSVLoggercallbacks = [ TensorBoard(log_dir='logs/experiment_1'), CSVLogger('experiment_1.csv')]4. 生产部署# 保存最佳模型并监控性能callbacks = [ ModelCheckpoint('production_model.h5', save_best_only=True), CustomMonitoringCallback()]总结TensorFlow 的回调函数提供了强大的训练控制能力:内置回调:提供常用的训练控制功能自定义回调:实现特定的训练逻辑灵活组合:可以组合多个回调函数执行顺序:了解回调函数的执行时机最佳实践:合理使用回调函数提高训练效率掌握回调函数将帮助你更好地控制和监控模型训练过程。
阅读 0·2月18日 18:03

TensorFlow 中的张量是什么,如何创建和操作张量

张量(Tensor)是 TensorFlow 中的核心数据结构,理解张量的概念和操作对于使用 TensorFlow 至关重要。张量的基本概念定义张量是一个多维数组,可以表示标量、向量、矩阵或更高维度的数据。在 TensorFlow 中,张量是数据流动的基本单位。张量的属性每个张量都有以下关键属性:阶(Rank):张量的维度数形状(Shape):每个维度的大小数据类型(Dtype):张量中元素的数据类型设备(Device):张量存储的设备(CPU/GPU/TPU)张量的阶(维度)import tensorflow as tf# 0 阶张量(标量)scalar = tf.constant(42)print(f"标量: {scalar}, 阶: {tf.rank(scalar).numpy()}, 形状: {scalar.shape}")# 1 阶张量(向量)vector = tf.constant([1, 2, 3, 4, 5])print(f"向量: {vector}, 阶: {tf.rank(vector).numpy()}, 形状: {vector.shape}")# 2 阶张量(矩阵)matrix = tf.constant([[1, 2], [3, 4]])print(f"矩阵:\n{matrix}, 阶: {tf.rank(matrix).numpy()}, 形状: {matrix.shape}")# 3 阶张量tensor_3d = tf.constant([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])print(f"3阶张量:\n{tensor_3d}, 阶: {tf.rank(tensor_3d).numpy()}, 形状: {tensor_3d.shape}")创建张量1. 使用 tf.constant 创建常量张量import tensorflow as tf# 从 Python 列表创建a = tf.constant([1, 2, 3, 4])print(a)# 指定数据类型b = tf.constant([1.0, 2.0, 3.0], dtype=tf.float32)print(b)# 创建多维张量c = tf.constant([[1, 2, 3], [4, 5, 6]])print(c)# 创建标量d = tf.constant(42)print(d)2. 使用 tf.zeros 和 tf.ones 创建# 创建全零张量zeros = tf.zeros([3, 4])print(f"全零张量:\n{zeros}")# 创建全一张量ones = tf.ones([2, 3])print(f"全一张量:\n{ones}")# 创建与给定张量形状相同的全零张量zeros_like = tf.zeros_like(a)print(f"与 a 形状相同的全零张量: {zeros_like}")3. 使用 tf.fill 创建填充张量filled = tf.fill([2, 3], 7)print(f"填充张量:\n{filled}")4. 使用随机数创建# 正态分布随机数normal = tf.random.normal([3, 3], mean=0.0, stddev=1.0)print(f"正态分布随机数:\n{normal}")# 均匀分布随机数uniform = tf.random.uniform([2, 4], minval=0, maxval=1)print(f"均匀分布随机数:\n{uniform}")# 随机打乱shuffled = tf.random.shuffle([1, 2, 3, 4, 5])print(f"随机打乱: {shuffled}")5. 使用序列创建# 创建等差数列range_tensor = tf.range(0, 10, 2)print(f"等差数列: {range_tensor}")# 创建线性空间linspace = tf.linspace(0.0, 10.0, 5)print(f"线性空间: {linspace}")6. 从 NumPy 数组创建import numpy as npnumpy_array = np.array([[1, 2], [3, 4]])tensor_from_numpy = tf.convert_to_tensor(numpy_array)print(f"从 NumPy 创建的张量:\n{tensor_from_numpy}")7. 使用 tf.Variable 创建可变张量variable = tf.Variable([1, 2, 3, 4])print(f"可变张量: {variable}")# 修改值variable.assign([5, 6, 7, 8])print(f"修改后的可变张量: {variable}")# 部分修改variable.assign_add([1, 1, 1, 1])print(f"相加后的可变张量: {variable}")张量操作1. 数学运算a = tf.constant([1, 2, 3])b = tf.constant([4, 5, 6])# 基本运算print(f"加法: {a + b}")print(f"减法: {a - b}")print(f"乘法: {a * b}")print(f"除法: {a / b}")print(f"幂运算: {a ** 2}")# TensorFlow 函数print(f"平方: {tf.square(a)}")print(f"平方根: {tf.sqrt(tf.cast(a, tf.float32))}")print(f"指数: {tf.exp(tf.cast(a, tf.float32))}")print(f"对数: {tf.math.log(tf.cast(a, tf.float32))}")2. 矩阵运算A = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)B = tf.constant([[5, 6], [7, 8]], dtype=tf.float32)# 矩阵乘法print(f"矩阵乘法:\n{tf.matmul(A, B)}")# 矩阵转置print(f"矩阵转置:\n{tf.transpose(A)}")# 矩阵求逆print(f"矩阵求逆:\n{tf.linalg.inv(A)}")# 矩阵行列式print(f"矩阵行列式: {tf.linalg.det(A).numpy()}")# 矩阵迹print(f"矩阵迹: {tf.linalg.trace(A).numpy()}")3. 形状操作tensor = tf.constant([[1, 2, 3], [4, 5, 6]])# 获取形状print(f"形状: {tensor.shape}")# 重塑形状reshaped = tf.reshape(tensor, [3, 2])print(f"重塑后的张量:\n{reshaped}")# 展平flattened = tf.reshape(tensor, [-1])print(f"展平后的张量: {flattened}")# 增加维度expanded = tf.expand_dims(tensor, axis=0)print(f"增加维度后的形状: {expanded.shape}")# 减少维度squeezed = tf.squeeze(expanded)print(f"减少维度后的形状: {squeezed.shape}")4. 索引和切片tensor = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 基本索引print(f"第 0 行: {tensor[0]}")print(f"第 0 行第 1 列: {tensor[0, 1]}")# 切片print(f"前 2 行: {tensor[:2]}")print(f"第 1 列: {tensor[:, 1]}")print(f"子矩阵:\n{tensor[1:, 1:]}")# 高级索引indices = tf.constant([[0, 0], [1, 1], [2, 2]])gathered = tf.gather_nd(tensor, indices)print(f"高级索引结果: {gathered}")5. 拼接和分割a = tf.constant([[1, 2], [3, 4]])b = tf.constant([[5, 6], [7, 8]])# 拼接concat_0 = tf.concat([a, b], axis=0)print(f"沿 axis=0 拼接:\n{concat_0}")concat_1 = tf.concat([a, b], axis=1)print(f"沿 axis=1 拼接:\n{concat_1}")# 堆叠stacked = tf.stack([a, b], axis=0)print(f"堆叠后的形状: {stacked.shape}")# 分割split = tf.split(concat_0, 2, axis=0)print(f"分割结果: {split}")6. 聚合操作tensor = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.float32)# 求和print(f"所有元素求和: {tf.reduce_sum(tensor).numpy()}")print(f"沿 axis=0 求和: {tf.reduce_sum(tensor, axis=0).numpy()}")print(f"沿 axis=1 求和: {tf.reduce_sum(tensor, axis=1).numpy()}")# 平均值print(f"所有元素平均值: {tf.reduce_mean(tensor).numpy()}")# 最大值和最小值print(f"最大值: {tf.reduce_max(tensor).numpy()}")print(f"最小值: {tf.reduce_min(tensor).numpy()}")# 乘积print(f"所有元素乘积: {tf.reduce_prod(tensor).numpy()}")# 标准差和方差print(f"标准差: {tf.math.reduce_std(tensor).numpy()}")print(f"方差: {tf.math.reduce_variance(tensor).numpy()}")7. 比较操作a = tf.constant([1, 2, 3, 4])b = tf.constant([2, 2, 2, 2])print(f"相等: {a == b}")print(f"不等: {a != b}")print(f"大于: {a > b}")print(f"小于: {a < b}")print(f"大于等于: {a >= b}")print(f"小于等于: {a <= b}")# 找到最大值和最小值的索引tensor = tf.constant([1, 3, 2, 4, 0])print(f"最大值索引: {tf.argmax(tensor).numpy()}")print(f"最小值索引: {tf.argmin(tensor).numpy()}")8. 数据类型转换tensor = tf.constant([1, 2, 3], dtype=tf.int32)# 转换为 float32float_tensor = tf.cast(tensor, tf.float32)print(f"转换为 float32: {float_tensor}")# 转换为 boolbool_tensor = tf.cast(tensor, tf.bool)print(f"转换为 bool: {bool_tensor}")广播机制TensorFlow 支持广播机制,允许不同形状的张量进行运算:a = tf.constant([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)b = tf.constant([1, 2, 3]) # 形状: (3,)# 广播后进行运算result = a + bprint(f"广播结果:\n{result}")c = tf.constant([[1], [2]]) # 形状: (2, 1)result2 = a + cprint(f"广播结果 2:\n{result2}")设备管理# 检查可用的 GPUprint(f"GPU 可用: {tf.config.list_physical_devices('GPU')}")# 在特定设备上创建张量with tf.device('/CPU:0'): cpu_tensor = tf.constant([1, 2, 3])# 在 GPU 上创建张量(如果可用)if tf.config.list_physical_devices('GPU'): with tf.device('/GPU:0'): gpu_tensor = tf.constant([1, 2, 3])性能优化建议使用合适的数据类型:根据需要选择 float32、float16 等避免频繁的数据类型转换:减少 tf.cast 调用利用向量化操作:使用 TensorFlow 内置函数而非 Python 循环使用 GPU 加速:将计算密集型操作放在 GPU 上预分配内存:使用 tf.TensorArray 或预分配张量总结张量是 TensorFlow 的基础数据结构,掌握张量的创建和操作是使用 TensorFlow 的关键:创建张量:使用 tf.constant、tf.zeros、tf.ones、tf.random 等操作张量:数学运算、矩阵运算、形状操作、索引切片等理解广播:利用广播机制简化代码性能优化:选择合适的数据类型和设备熟练掌握张量操作将帮助你更高效地构建和训练深度学习模型。
阅读 0·2月18日 18:02